The principle underneath Spring MVC

Abstract

Spring MVC(Model-View-Controller) is widely used in current Java web development, even in the "frontend backend separation" era. It not only implements all the crucial Spring features like the inversion of control and the dependency injection but combines the service of the frontend and backend. Therefore, it is vital for us to look deep into the principle of Spring MVC, to understand its logic and code. This tutorial will introduce the principle of Spring MVC by using simply examples and images. Let's start it!

The DispatcherServlet

The most critical component of Spring MVC is the DispathcerServlet. All the framework and logic of the Spring MVC are built around the DispatcherServlet. Here we created a simple POJO java type DispatherServlet.

public class DispatcherServlet extends ViewBaseServlet{

    private Map<String,Object> beanMap = new HashMap<>();

    public DispatcherServlet(){
    }

    public void init() throws ServletException {
        super.init();
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            //1.Create DocumentBuilderFactory
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //2. Create DocumentBuilder Object
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
            Document document = documentBuilder.parse(inputStream);

            //3. Obtain all the bean nodes from applicationContext.xml
            NodeList beanNodeList = document.getElementsByTagName("bean");
            for(int i = 0 ; i<beanNodeList.getLength() ; i++){
                Node beanNode = beanNodeList.item(i);
                if(beanNode.getNodeType() == Node.ELEMENT_NODE){
                    Element beanElement = (Element)beanNode ;
                    String beanId =  beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class controllerBeanClass = Class.forName(className);
                    Object beanObj = controllerBeanClass.newInstance() ;
                    beanMap.put(beanId , beanObj) ;
                }

    }
...catch exceptions

The basic logic of the Dispatcher Servlet is first to initialize a hashmap to store all the nodes and responded controller classes. The information of each controller's name and class are edited in the applicationContext.xml.

<?xml version="1.0" encoding="utf-8"?>

<beans>
    <!-- For example, the  information of this controller will be key(fruit) and 
value(FruitController)-->
    <bean id="fruit" class="com.banana.fruit.controllers.FruitController"/>
</beans>

We created a sample controller bean called "fruit" for this tutorial.I hide the details of the repository layer since it is not crucial in this tutorial.

public class FruitController {
    private FruitDAO fruitDAO = new FruitDAOImpl();

    private String update(Integer fid , String fname , Integer price , Integer fcount , String remark ){
        
        fruitDAO.updateFruit(new Fruit(fid,fname, price ,fcount ,remark ));
        
        return "redirect:fruit.do";
    }

Most Crucial Part

Some readers may wonder what the function of the hashmap we created above is. In this section, we will discuss the service method of DispactherServlet.

@Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //set character encoding 
        request.setCharacterEncoding("UTF-8");
        //if URL is:  http://localhost:8080/pro15/hello.do
        //servletPath is:    /hello.do
      
        //so the first part is to get the servletPath string
        String servletPath = request.getServletPath();
        servletPath = servletPath.substring(1);
        int lastDotIndex = servletPath.lastIndexOf(".do") ;
        servletPath = servletPath.substring(0,lastDotIndex);
        
        //use the right controller to deal with this request
        Object controllerBeanObj = beanMap.get(servletPath);

        String operate = request.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index" ;
        }
        
           //this part is to use the method including parameters
        try {
            Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
            for(Method method : methods){
                if(operate.equals(method.getName())){


                    Parameter[] parameters = method.getParameters();

                    Object[] parameterValues = new Object[parameters.length];
                    for (int i = 0; i < parameters.length; i++) {
                        Parameter parameter = parameters[i];
                        String parameterName = parameter.getName() ;
                     
                        if("request".equals(parameterName)){
                            parameterValues[i] = request ;
                        }else if("response".equals(parameterName)){
                            parameterValues[i] = response ;
                        }else if("session".equals(parameterName)){
                            parameterValues[i] = request.getSession() ;
                        }else{
                       
                            String parameterValue = request.getParameter(parameterName);
                            String typeName = parameter.getType().getName();

                            Object parameterObj = parameterValue ;

                            if(parameterObj!=null) {
                                if ("java.lang.Integer".equals(typeName)) {
                                    parameterObj = Integer.parseInt(parameterValue);
                                }
                            }

                            parameterValues[i] = parameterObj ;
                        }
                    }
                    //2.controller method invoking
                    method.setAccessible(true);
                    Object returnObj = method.invoke(controllerBeanObj,parameterValues);

                    //3. deal with the String return
                    String methodReturnStr = (String)returnObj ;
                    if(methodReturnStr.startsWith("redirect:")){       
                        String redirectStr = methodReturnStr.substring("redirect:".length());
                        response.sendRedirect(redirectStr);
                    }else{
                        super.processTemplate(methodReturnStr,request,response);    
                    }
                }
            }

Here is the result of the service example. Once a request is coming to the dispatcher servlet, the service method will first obtain the type of method that will be invoked. Then, the DispatcherServlet will configure it and get the right controller from the hashmap. Besides, the service method will also choose to create a servlet instance by using reflection and invoke the method according to the request. Finally, there is also a method at the end of the service section to configure the string result.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值