SpringMVC-02-什么是SpringMVC

1、概述

Spring MVC是Spring Framework的Web开发部分,是基于Java实现MVC的轻量级Web框架。

为什么要学习SpringMVC ?

Spring MVC的特点:

  1. 轻量级,简单易学
  2. 高效 , 基于请求响应的MVC框架
  3. 与Spring兼容性好,无缝结合
  4. 约定优于配置
  5. 功能强大:RESTful、数据验证、格式化、本地化、主题等
  6. 简洁灵活

Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。

DispatcherServlet的作用是将请求分发到不同的Handler。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;

正因为SpringMVC好 , 简单 , 便捷 , 易学 , 天生和Spring无缝集成(可以使用IOC和AOP) , 使用约定优于配置 ,能够进行简单的junit测试 ,支持Restful风格 ,异常处理 ,本地化 ,国际化 ,数据验证 ,类型转换 ,拦截器 等等......所以我们要学习。

最重要的一点还是用的人多 , 使用的公司多 。

2、SpringMVC 核心组件

  • 前端控制器:DispactherServlet
  • 处理器映射器:HandlerMapping
  • 处理器适配器:HandlerAdapter
  • 处理器:Handler
  • 视图解析器:ViewResolver

组件介绍:

  • DispactherServlet:用于接收所有的客户端请求并将请求分发给合适的Handler(Controller)进行处理。在原生JavaWeb中,分发请求是由 Tomcat 根据 web.xml 来做的,SpringMVC使用 DispactherServlet 替代了这个功能。(不需要程序员开发)
  • HandlerMapping:解析每个请求的URL,找到对应的 Handler。(不需要程序员开发)
  • HandlerAdapter:适配器模式,适配调用具体的 Handler。(不需要程序员开发)
  • Handler:Controller层组件,对客户端请求进行逻辑处理,替代了原生JavaWeb中的 Servlet 所做的功能。(需要程序员手动开发)
  • ViewResolver:将 SpringMVC 中的 逻辑视图名 拼接成具体的视图地址,简化了视图地址的编写。(不需要程序员开发)

Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)

3、SpringMVC 执行原理

简要分析执行流程

  1. 当用户通过浏览器发起一个HTTP请求,请求直接到前端控制器 DispatcherServlet;
  2. 前端控制器接收到请求以后调用处理器映射器HandlerMapping,处理器映射器根据请求的URL解析出URI,找到具体的Handler,并将它返回给前端控制器;
  3. 前端控制器调用处理器适配器HandlerAdapter去适配调用Handler;
  4. 处理器适配器会根据Handler去调用真正的处理器去处理请求,并且处理对应的业务逻辑;
  5. 当处理器处理完业务之后,会返回一个ModelAndView对象给处理器适配器,HandlerAdapter再将该对象返回给前端控制器;ModelAndView 中的 Model 是指 被Model层执行业务处理后返回的数据对象,View 是指 将要转向的视图信息。
  6. 前端控制器DispatcherServlet将返回的ModelAndView对象传给视图解析器ViewResolver进行解析,解析完成之后就会返回一个具体的视图地址给前端控制器;(ViewResolver根据逻辑的View查找具体的View)
  7. 前端控制器DispatcherServlet转向具体的视图,并进行渲染;
  8. 渲染完成之后响应给用户(浏览器显示);

4、HelloSpringMVC(举个实例)

4.1、配置版

  1. 新建一个Moudle , SpringMVC-02-HelloMVC , 添加web的支持!

  2. 确定导入了SpringMVC 的依赖!

  3. 配置web.xml , 注册DispatcherServlet

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
        <!--注册DispatcherServlet-->
        <servlet>
            <servlet-name>DispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!--关联一个springmvc的配置文件-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:spring-mvc.xml</param-value>
            </init-param>
            <!--启动级别-1-->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>DispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>
    

    配置说明:

    • init-param:当请求进入此servlet时,会携带的初始参数
    • classpath:classpath*::前者指的是 当前项目的编译路径,后者代表的是 当前项目及其依赖jar包的所有编译路径
    • load-on-startup:启动级别,当值为0或者大于0时,表示容器在应用启动时就加载这个servlet,值越小,优先级越高,当值是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。
    • url-pattern 为 ‘/’:默认匹配,详见 关于tomcat中servlet的url-pattern匹配规则
  4. 编写SpringMVC 的 配置文件!名称:spring-mvc.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- Handler映射器 -->
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    
        <!-- Handler适配器 -->
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    
        <!-- 视图解析器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    
    </beans>
    
  5. 编写处理器 Handler ,实现Controller接口 或者 增加注解;需要返回一个ModelAndView,装数据,封视图

    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class HelloController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            ModelAndView mv = new ModelAndView();
    
            mv.addObject("msg","HelloMVC");
            mv.setViewName("hello");
    
            return mv;
        }
    }
    
  6. 将编写的 Handler 交给SpringIOC容器,注册bean,添加到spring-mvc.xml中。

    <!-- Handler -->
    <bean id="/hello" class="controller.HelloController"/>
    
  7. 编写要跳转的jsp页面,显示ModelandView存放的数据,以及正常页面;

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>hello</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  8. 配置Tomcat,启动测试!

可能遇到的问题:访问出现404,排查步骤:

  1. 查看控制台输出,看一下是不是缺少了什么jar包。

  2. 如果缺少jar包,就在项目结构中添加相应的lib依赖!

  3. 重启Tomcat 即可解决!

4.2、注解版

  1. 新建一个Moudle,SpringMVC-03-Annotation ,添加web支持!

  2. 在pom.xml文件引入相关的依赖:主要有Spring框架核心库、Spring MVC、Servlet、 JSTL等。在父项目中已经引入了

  3. 配置web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
        <servlet>
            <servlet-name>DispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:spring-mvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>DispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        
    </web-app>
    

    配置说明:在上面的配置版讲过了,这里一样,就不说了。

  4. 添加Spring MVC配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
    ">
    
        <!-- 组件扫描 -->
        <context:component-scan base-package="com.moondream.controller"/>
        <!-- 使用 default-servlet 处理静态资源 -->
        <mvc:default-servlet-handler/>
        <!-- 使用mvc注解驱动 -->
        <mvc:annotation-driven/>
    
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    
    </beans>
    

    配置说明:

    1. 加入了两个Xml命名空间 contextmvc

    2. <context:component-scan/>:组件扫描

      命名空间 context 下的标签,扫描指定包下所有被模板注解标注了的类,将其bean化并注册到IOC中。

      模板注解 即 @component 及其 组合注解(@Controller、@Configuration……),它们大都位于 org.springframework.stereotype 包下,抽象定义为 项目的某个模块,比如 @Controller 代表 项目的 控制层,@Service 代表 项目的 服务层,@Configuration 代表 项目的 配置,@Component 代表 项目的 组件。

      不想使用组件扫描,也可以将其手动一个个注册成bean

      <bean class="com.moondream.controller.HelloController"/>
      
    3. <mvc:default-servlet-handler/>:使用 default-servlet 来处理请求

      命名空间 mvc 下的标签,将 匹配到的请求 转发到 Tomcat 内建的 default servlet 中处理。

      一般用来处理 静态资源请求(.html、.css、.mp3、.jpg……),使用此标签要注意 配置中多个HandlerMapping的优先级问题,免得 非静态资源请求 被匹配上 default servlet ,那样会报 404 错误。

      其本质是

          <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
              <!-- SimpleUrlHandlerMapping 通过urlMap来找相应的Handler -->
              <property name="urlMap">
                  <map>
                      <entry key="/**" value="org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0"/>
                  </map>
              </property>
          </bean>
          <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
          <bean class="org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler"/>
      
    4. <mvc:annotation-driven/>:使用 mvc 注解驱动

      命名空间 mvc 下的标签,使用注解的方式来处理请求。

      其本质是

      <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
          <!-- 使用高优先级 -->
          <property name="order" value="0"/>
      </bean>
      <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
      

      (spring3.1之前使用的是 DefaultAnnotationHandlerMapping 与 AnnotationMethodHandlerAdapter )

      (spring3.1之后替换成如上述所示)

      注解方式处理请求的简要流程:

      1)Spring容器启动,RequestMappingHandlerMapping在bean加载完成后,扫描出所有带有@Controller注解的bean,进而遍历出其中所有带有@RequestMapping注解 的方法,将方法上@RequestMapping注解信息封装成RequestMappingInfo对象,其包含了请求路径、请求方法、请求参数、请求头等信息,将方法本身封装成HandlerMethod对象,并以RequestMappingInfo为键,HandlerMethod为值,存储在一个Map结构中,以便于后续查找。

      2)当一个HTTP请求到达DispatcherServlet时,DispatcherServlet会调用RequestMappingHandlerMappinggetHandler()方法来查找到相应的 Handler,这里就是HandlerMethod

      3)如果找到了匹配的HandlerMethodDispatcherServlet就会根据其类型选择合适的HandlerAdapter(即RequestMappingHandlerAdapter)来执行它,并返回结果;如果没有找到匹配的HandlerMethodDispatcherServlet就会抛出异常并使用下一个 HandlerMapping 来查找 Handler 或者返回404错误页面。

      4)如果被封装成HandlerMethod的方法 或者 其上的类 被@ResponseBody注解 标注,那么HandlerMethod的返回结果就是一个单纯的数据字符串,会被当成响应体直接返回给客户端浏览器,否则就是逻辑视图名,会被视图解析器解析后转向具体视图。

      详见这篇文章的 RequestMappingHandlerMapping 部分:Spring MVC源码解析——HandlerMapping(处理器映射器)

  5. 编写Controller层,创建一个Java类:com.moondream.controller.HelloController , 注意编码规范

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/HelloController")
    public class HelloController {
    
       //真实访问地址 : 项目名/HelloController/hello
       @RequestMapping("/hello")
       public String sayHello(Model model){
           //向模型中添加属性msg与值,可以在JSP页面中取出并渲染
           model.addAttribute("msg","hello,SpringMVC");
           
           // /WEB-INF/jsp/hello.jsp
           return "hello";
      }
    }
    

    注意:

    • 标注在类上的 @RequestMapping,相当于前置要求,每个RequestMappingInfo在被封装时,都会将类和对应方法上的 @RequestMapping 注解信息 整合注入自己。
    • 被封装成HandlerMethod的方法,返回值必须是String类型,方法参数会被框架进行数据绑定。如果想在访问的请求上加数据,可以设置一个Model类型的参数,这个参数对象将由框架传入,它会把自身被加入的数据封装到访问的请求上。不要设置ModelAndView类型的参数,它在HandlerMethod中无效。
    • 一个RequestMappingInfo匹配的请求范围不能被另一个RequestMappingInfo完全覆盖,不然程序会报错。简单来说,你要保证一个RequestMappingInfo至少有一类请求能匹配上。
  6. 创建视图层

    在WEB-INF/jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息;

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Hello</title>
    </head>
    <body>
    ${msg}
    <br/>
    <%out.print(request.getRequestURI());%>
    </body>
    </html>
    
  7. 配置Tomcat运行,开启服务器,访问对应的请求路径!

    http://localhost:8080/spring03/HelloController/hello

    运行成功!!!

4.3、小结

实现步骤:

  1. 新建一个web项目
  2. 导入相关jar包
  3. 编写web.xml , 注册DispatcherServlet
  4. 编写springmvc配置文件
  5. 接下来就是去创建对应的控制类 , controller
  6. 最后完善前端视图和controller之间的对应
  7. 测试运行调试.

使用springMVC必须配置的三大件:

  • 处理器映射器、处理器适配器、视图解析器

通常,我们只需要手动配置视图解析器,而处理器映射器处理器适配器只需要开启注解驱动即可,省去了大段的xml配置。

不知道有没有小伙伴注意到一个问题:

在上述注解版的案例中,我们通过命名空间mvc下的两个标签default-servlet-handlerannotation-driven,在SpringIOC中配置了多个HandlerMapping和HandlerAdapter,

那么,当请求到达时,DispatcherServlet该使用哪个HandlerMapping和HandlerAdapter呢?

当IOC中有多个HandlerMapping时:

  1. DispatcherServlet会优先使用优先级高的HandlerMapping(所有HandlerMapping中,都有一个order属性,代表优先级)
  2. 如果HandlerMapping优先级一样,DispatcherServlet会使用先注册的
  3. 如果使用的HandlerMapping根据请求找不到Handler,DispatcherServlet会继续使用下一优先级的HandlerMapping继续找,直到找到Handler

当IOC中有多个HandlerAdapter时:

  1. DispatcherServlet会遍历所有注册的HandlerAdapter,根据请求的Handler类型来选择对应的HandlerAdapter
  2. 如果有多个HandlerAdapter都能够支持当前请求的Handler类型,选择第一个适配成功的HandlerAdapter来执行Handler,即选择先注册的HandlerAdapter

热门相关:重生后我成了权臣的掌中娇   许你盛世安宁   纨绔毒医   永恒王权   赠我深爱如长风