2022-08-20

本文介绍Spring MVC的三大组件,它们分别是处理器映射器(HandlerMapper),处理器适配器(HandlerAdapter),视图解析器(ViewResolver)。

1 处理器映射器

1.1 处理器映射器作用

通过处理器映射,你可以将Web 请求映射到正确的处理器 Controller 上。当接收到请求时,DispactherServlet 将请求交给 HandlerMapping 处理器映射,让他检查请求并找到一个合适的HandlerExecutionChain,这个HandlerExecutionChain 包含一个能处理该请求的处理器 Controller。然后,DispactherServlet 执行在HandlerExecutionChain 中的处理器 Controller。

Spring内置了许多处理器映射策略,目前主要由三个实现。SimpleUrlHandlerMapping、``BeanNameUrlHandlerMappingRequestMappingHandlerMapping

202202131334234141.png

注意:Spring MVC3.1之前使用DefaultAnnotationHandlerMapping,Spring MVC3.1之后改为RequestMappingHandlerMapping。

1)SimpleUrlHandlerMapping

SimpleUrlHandlerMapping 在应用上下文中可以进行配置,并且有Ant 风格的路径匹配功能。例如我们在springmvc.xml 中配置一个SimpleUrlHandlerMapping 处理器映射。

springmvc.xml配置:

            
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
                <!--1.创建SimpleUrlHandlerMapping-->
                <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
                    <property name="mappings">
                        <props>
                            <prop key="/hello.do">helloController</prop>
                        </props>
                    </property>
                </bean>
            
                <!--2.创建Controller对象-->
                <bean id="helloController" class="com.yiidian.controller.HelloController"/>
            
                <!--3.视图解析器-->
                <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/pages/"/>
                    <property name="suffix" value=".jsp" />
                </bean>
            </beans>

对应的HelloController类:

            
            package com.yiidian.controller;
            import org.springframework.web.bind.annotation.RequestMapping;
            import org.springframework.web.servlet.ModelAndView;
            import org.springframework.web.servlet.mvc.Controller;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            /**
             * 控制器
             * 一点教程网 - www.yiidian.com
             */
            public class HelloController implements Controller {
            
                @Override
                public ModelAndView handleRequest(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception {
                    ModelAndView mv = new ModelAndView("success");
                    return mv;
                }
            }

源码下载:https://pan.baidu.com/s/1iKKlM5zyxVxvMyXHj2a0UQ

2)BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping 将收到的Http请求映射到bean的名字上。如:我们用如下方式将包含http://localhost:8080/hello.do的访问请求映射到指定的HelloController上。

springmvc.xml配置

            
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
                <!--1.创建BeanNameUrlHandlerMapping-->
                <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
            
                <!--2.创建Controller对象,这里的id必须页面访问的路径(以斜杠开头)-->
                <bean id="/hello.do" class="com.yiidian.controller.HelloController"/>
            
                <!--3.视图解析器-->
                <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/pages/"/>
                    <property name="suffix" value=".jsp" />
                </bean>
            </beans>

Controller类

            
            package com.yiidian.controller;
            import org.springframework.web.bind.annotation.RequestMapping;
            import org.springframework.web.servlet.ModelAndView;
            import org.springframework.web.servlet.mvc.Controller;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            /**
             * 控制器
             * 一点教程网 - www.yiidian.com
             */
            public class HelloController implements Controller {
            
                @Override
                public ModelAndView handleRequest(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception {
                    ModelAndView mv = new ModelAndView("success");
                    return mv;
                }
            }

注意:在bean的id中要加上斜杆,Controller的代码跟前面的SimpleUrlHandlerMapping一样,实现Controller,重写handlerRequest()方法即可。

在默认情况下,如果没有在上下文中没有找到处理器映射,DispactherServlet 会为你创建一个BeanNameUrlHandlerMapping。

源码下载:https://pan.baidu.com/s/1DX6Ekg51WOSRn1ByVkJV5Q

3)RequestMappingHandlerMapping

RequestMappingHandlerMapping是三个中最常用的HandlerMapping,因为注解方式比较通俗易懂,代码界面清晰,只需要在代码前加上@RequestMapping()的相关注释就可以了。代码示例如下:

            
            package com.yiidian.controller;
            import org.springframework.stereotype.Controller;
            import org.springframework.web.bind.annotation.RequestMapping;
            /**
             * 控制器
             * 一点教程网 - www.yiidian.com
             */
            @Controller
            public class HelloController {
            
                @RequestMapping("/hello.do")
                public String hello(){
                    System.out.println("进入控制器的方法");
            
                    //注意:这里返回的只是页面名称,不是完整的页面访问路径
                    return "success";
                }
            }

springmvc.xml配置:

            
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
                <!-- 1.扫描Controller的包-->
                <context:component-scan base-package="com.yiidian.controller"/>
            
                <!-- 2.配置视图解析器 -->
                <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <!-- 2.1 页面前缀 -->
                    <property name="prefix" value="/pages/"/>
                    <!-- 2.2 页面后缀 -->
                    <property name="suffix" value=".jsp"/>
                </bean>
            
                <!-- 3.创建RequestMappingHandlerMapping对象-->
                <mvc:annotation-driven/>
            </beans>

注意:重点是添加<mvc:annotation-driven/>标签!

2 处理器适配器

2.1 处理器适配器作用

HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理。当HandlerMapping获取到执行请求的Controller时,DispatcherServlte会根据Controller对应的Controller类型来调用相应的HandlerAdapter来进行处理。

HandlerAdapter的实现有HttpRequestHandlerAdapterSimpleServletHandlerAdapterSimpleControllerHandlerAdapterAnnotationMethodHandlerAdapter(Spring MVC 3.1后已废弃)和RequestMappingHandlerAdapter。

202202131334240752.png

1)HttpRequestHandlerAdapter

HttpRequestHandlerAdapter可以处理类型为HttpRequestHandler的handler,对handler的处理是调用HttpRequestHandler的handleRequest()方法。

Controller类

            
            package com.yiidian.controller;
            import org.springframework.web.HttpRequestHandler;
            import org.springframework.web.bind.annotation.RequestMapping;
            import org.springframework.web.servlet.ModelAndView;
            import org.springframework.web.servlet.mvc.Controller;
            
            import javax.servlet.ServletException;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import java.io.IOException;
            /**
             * 控制器
             * 一点教程网 - www.yiidian.com
             */
            public class HelloController implements HttpRequestHandler {
                @Override
                public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                    response.getWriter().write("Hello-www.yiidian.com");
                }
            }

springmvc.xml配置,创建HttpRequestHandlerAdapter对象

            
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
                <!--1.创建BeanNameUrlHandlerMapping-->
                <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
            
                <!--2.创建HttpRequestHandlerAdapter-->
                <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
            
                <!--3.创建Controller对象,这里的id必须页面访问的路径(以斜杠开头)-->
                <bean id="/hello.do" class="com.yiidian.controller.HelloController"/>
            
            </beans>

结果为

202202131334246893.png

源码下载:https://pan.baidu.com/s/1sIUcZ1UcmG4CNDObG18zSw

2)SimpleServletHandlerAdapter

SimpleServletHandlerAdapter可以处理类型为Servlet,就是把Servlet当做Controller来处理,使用Servlet的service方法处理用户请求。

springmvc.xml配置

            
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
                <!--1.创建BeanNameUrlHandlerMapping-->
                <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
            
                <!--2.创建SimpleServletHandlerAdapter-->
                <bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>
            
                <!--3.创建Controller对象,这里的id必须页面访问的路径(以斜杠开头)-->
                <bean id="/hello.do" class="com.yiidian.controller.HelloServlet"/>
            
            </beans>

Controller类

            
            package com.yiidian.controller;
            import javax.servlet.ServletException;
            import javax.servlet.http.HttpServlet;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import java.io.IOException;
            /**
             * 把Servlet作为控制器
             * 一点教程网 - www.yiidian.com
             */
            public class HelloServlet extends HttpServlet{
            
                @Override
                protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                    resp.getWriter().write("Hello-www.yiidian.com");
                }
            
                @Override
                protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                    super.doGet(req,resp);
                }
            }

源码下载:https://pan.baidu.com/s/1Ra4Dm1HmHrKeKKTi8-CPFA

3)SimpleControllerHandlerAdapter

SimpleControllerHandlerAdapter可以处理类为Controller的控制器,使用Controller的handlerRequest方法处理用户请求。

springmvc.xml配置

            
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
                <!--1.创建BeanNameUrlHandlerMapping-->
                <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
            
                <!--2.创建SimpleControllerHandlerAdapter-->
                <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
            
                <!--3.创建Controller对象,这里的id必须页面访问的路径(以斜杠开头)-->
                <bean id="/hello.do" class="com.yiidian.controller.HelloController"/>
            
            </beans>

Controller类

            
            package com.yiidian.controller;
            
            import org.springframework.web.servlet.ModelAndView;
            import org.springframework.web.servlet.mvc.Controller;
            
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            
            /**
             * 控制器
             * 一点教程网 - www.yiidian.com
             */
            public class HelloController implements Controller {
            
                @Override
                public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
                    response.getWriter().write("Hello-www.yiidian.com");
                    return null;
                }
            }

源码下载:https://pan.baidu.com/s/1hOwI1tBALDuf7WiGJ0HmoQ

4)RequestMappingHandlerAdapter

RequestMappingHandlerAdapter可以处理类型为HandlerMethod的控制器,通过Java反射调用HandlerMethod的方法来处理用户请求。

springmvc.xml配置

            
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
                <!--1.扫描Controller,创建Controller对象 -->
                <context:component-scan base-package="com.yiidian.controller"/>
            
                <!--2.创建RequestMappingHandlerMapping-->
                <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
            
                <!--3.创建RequestMappingHandlerAdapter-->
                <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
            
            </beans>

Controller类

            
            package com.yiidian.controller;
            import org.springframework.stereotype.Controller;
            import org.springframework.web.bind.annotation.RequestMapping;
            import org.springframework.web.servlet.ModelAndView;
            
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import java.io.IOException;
            /**
             * 控制器
             * 一点教程网 - www.yiidian.com
             */
            @Controller
            public class HelloController{
                @RequestMapping("/hello.do")
                public void hello(HttpServletRequest request,HttpServletResponse response) throws IOException {
                    response.getWriter().write("Hello-www.yiidian.com");
                }
            }

源码下载:https://pan.baidu.com/s/1m9nOeCUfzV6Myj9SkYwROQ

3 视图解析器

3.1 视图解析器作用

Spring MVC中的视图解析器的主要作用就是将逻辑视图转换成用户可以看到的物理视图。

当用户对SpringMVC应用程序发起请求时,这些请求都会被Spring MVC的DispatcherServlet处理,通过处理器找到最为合适的HandlerMapping定义的请求映射中最为合适的映射,然后通过HandlerMapping找到相对应的Handler,然后再通过相对应的HandlerAdapter处理该Handler。返回结果是一个ModelAndView对象,当该ModelAndView对象中不包含真正的视图,而是一个逻辑视图路径的时候,ViewResolver就会把该逻辑视图路径解析为真正的View视图对象,然后通过View的渲染,将最终结果返回给用户。

SpringMVC中处理视图最终要的两个接口就是ViewResolverView,ViewResolver的作用是将逻辑视图解析成物理视图,View的主要作用是调用其render()方法将物理视图进行渲染。

3.2 常见的视图解析器

以下为Spring MVC提供常见视图解析器:

视图类型 说明
BeanNameViewResolver 将逻辑视图名称解析为一个Bean,Bean的Id等于逻辑视图名
InternalResourceViewResolver 将视图名解析为一个URL文件,一般使用该解析器将视图名映射为一个保存在WEB-INF目录下的程序文件,如JSP
JaperReportsViewResolver JapserReports是基于Java的开源报表工具,该解析器解析为报表文件对应的URL
FreeMarkerViewResolver 解析为基于FreeMarker模板的模板文件
VelocityViewResolver 解析为Velocity模板技术的模板文件
VelocityLayoutViewResolver 解析为Velocity模板技术的模板文件

其中,最常用的是InternalResourceViewResolver,配置如下:

            
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
               <!-- 页面前缀 -->
               <property name="prefix" value="/pages/"/>
                <!--页面后缀 -->
               <property name="suffix" value=".jsp"/>
            </bean>
阅读全文