• SpringMVC——基于MVC架构的Spring框架


    活动地址:CSDN21天学习挑战赛

    文章目录

    第1章 SpringMVC概述

    1.1 SpringMVC简介

    MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

    MModel,模型层,指工程中的JavaBean,作用是处理数据

    JavaBean分为两类:

    一类称为实体类Bean:专门存储业务数据的,如 Student、User 等

    一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

    V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

    C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

    MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller

    调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果

    找到相应的View视图,渲染数据后最终响应给浏览器

    SpringMVC是Spring的一个后续产品,是Spring的一个子项目

    SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、

    WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目

    表述层开发的首选方案

    注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台

    servlet

    1.2 SpringMVC的优点

    1.2.1 基于MVC架构

    基于 MVC 架构,功能分工明确。解耦合。

    1.2.2 容易理解,上手快,使用简单

    就可以开发一个注解的 SpringMVC 项目,SpringMVC 也是轻量级的,jar 很小。不依赖的特定的接口和类。

    1.2.3作为Spring框架一部分,能够使用Spring的IOC和AOP

    方便整合Strtus,MyBatis,Hiberate,JPA 等其他框架。

    1.2.4 SpringMVC 强化注解的使用

    在Controller, Service, Dao 都可以使用注解。方便灵活。使用@Controller 创建处理器对象,@Service 创建业务对象,@Autowired 或者@Resource 在控制器类中注入 Service,在Service 类中注入 Dao。

    1.3SpringMVC优化的方向

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aFRDDzL8-1659882586537)(../../../../Pictures/Spring/wps1-16588394965531.jpg)]

    1.4 SpringMVC执行的流程

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2wNF0cJR-1659882586539)(../../../../Pictures/Spring/wps2-16588394965532.jpg)]

    执行流程说明:

    1. 向服务器发送HTTP请求,请求被前端控制器 DispatcherServlet 捕获。
    2. DispatcherServlet 根据中的配置对请求的URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用 HandlerMapping 获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回。
    3. DispatcherServlet 根据获得的Handler,选择一个合适的 HandlerAdapter。
    4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息。
      • 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等。
      • 数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。
      • 数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中。
    5. Handler(Controller)执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象。
    6. 根据返回的ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet。
    7. ViewResolver 结合Model和View,来渲染视图。
    8. 视图负责将渲染结果返回给客户端

    1.5基于注解的SpringMVC程序

    所谓 SpringMVC 的注解式开发是指:
    在代码中通过对类与方法的注解,便可完成处理器在 springmvc 容器的注册。注解式开发是重点。

    项目案例功能:用户提交一个请求,服务端处理器在接收到这个请求后,给出一条欢迎信息,在响应页面中显示该信息。

    创建步骤:

    1. 新建maven_web项目

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H8RtMTPx-1659882586539)(../../../../Pictures/Spring/wps3-16588394965533.jpg)]

    1. 添加依赖
    <dependency> 
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-webmvcartifactId>
        <version>5.2.5.RELEASEversion>
    dependency> 
    <dependency> 
        <groupId>javax.servletgroupId>
        <artifactId>javax.servlet-apiartifactId>
        <version>3.1.0version> 
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 删除web.xml文件重新添加,因为自动生成的web.xml文件版本太低了。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Om4L7gwY-1659882586539)(../../../../Pictures/Spring/wps4.jpg)]

    1. 在web.xml文件中注册SpringMvc框架。

    ​ 因为web的请求都是由Servlet来进行处理的,而SpringMVC的核心处理器就是一个DispatcherServlet,它负责接收客户端的请求,并根据请求的路径分派给对应的action(控制器)进行处理,处理结束后依然由核心处理器DispatcherServlet进行响应返回。

    中央调度器的全限定性类名在导入的 Jar 文件 spring-webmvc-5.2.5.RELEASE.jar 的第一个包org.springframework.web.servlet下可找到。

    <servlet> 
        <servlet-name>springmvcservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param> 
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:springmvc.xmlparam-value>
        init-param>
        
        
    servlet>
    <servlet-mapping> 
        <servlet-name>springmvcservlet-name> 
        <url-pattern>*.actionurl-pattern>
    servlet-mapping>
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    classpath:springmvc.xml

    表示从类路径下加载SpringMVC的配置文件。

    指定拦截以.action结尾的请求,交给核心处理器DispatcherServlet处理。

    1. 删除index.jsp页面,重新建index.jsp页面,因为自动生成的页面缺失指令设置。

    2. 开发页面,发出请求。

    <a href="${pageContext.request.contextPath}/zar/hello.action">访问actiona>
    
    • 1
    • 其中:
      • /zar 是类上的注解路径
      • /hello 是方法上的注解路径
    1. 在webapp目录上新添目录/admin。

    2. 在/admin目录下新建main.jsp页面。用来进行服务器处理完毕后数据的回显。

    3. 开发HelloSpringMvc.java–>控制器(相当于以前的servlet)。这是一个普通的类,不用继承和实现接口。类中的每个方法就是一个具体的action控制器。

    • 类中的方法定义有规范:
      • A. 访问权限是public。
      • B. 方法名自定义。
      • C. 方法的参数可以有多个,任意类型,用来接收客户端提交上来的数据。
      • D. 方法的返回值任意。以返回String居多。
    @Controller
    @RequestMapping("/zar")
    public class HelloSpringMvc { 
        @RequestMapping("/hello") 
        public String one(){ 
            return "main";
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    @Controller:表示当前类为处理器,交给Spring容器去创建对象。

    @RequestMapping:表示路径映射。该注解可以加在类上相当于包名,还可以加在方法上相当于action的名称,都是来指定映射路径的。

    1. 完成springmvc.xml文件的配置。在工程的类路径即resources目录下创建 SpringMVC 的配置文件 springmvc.xml。该文件名可以任意命名。推荐使用springmvc.xml.
    <context:component-scan base-package="com.bjpowernode.controller">context:component-scan> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
        <property name="prefix" value="/WEB-INF/jsp/">property>
        <property name="suffix" value=".jsp">property>
    bean> 
    
    • 1
    • 2
    • 3
    • 4

    SpringMVC框架为了避免对于请求资源路径与扩展名上的冗余,在视图解析器

    InternalResouceViewResolver 中引入了请求的前辍与后辍。而action中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,视图解析器会自动完成拼接。

    context:component-scan:用来进行包扫描,这里用于指定@Controller注解所在的包路径。

    1.6总结

    浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面

    第2章 SpringMVC注解式开发

    2.1@RequestMapping定义请求规则

    2.1.1 指定模块名称

    • 通过@RequestMapping 注解可以定义处理器对于请求的映射规则。

    • 该注解可以注解在方法上,也可以注解在类上,但意义是不同的。

    • value 属性值常以“/”开始。

    • @RequestMapping 的 value 属性用于定义所匹配请求的 URI。

    • 一个@Controller 所注解的类中,可以定义多个处理器方法。

    • 不同的处理器方法所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的value 属性中。但若这些请求具有相同的 URI 部分,则这些相同的 URI部分可以被抽取到注解在类之上的@RequestMapping 的 value 属性中。此时的这个 URI 表示模块(相当于包)的名称。URI 的请求是相对于 Web 的根目录。

    • 换个角度说,要访问处理器的指定方法,必须要在方法指定 URI 之前加上处理器类前定义的模块名称。

    示例:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KWL7Bojb-1659882586540)(../../../../Pictures/Spring/wps5.jpg)]

    提取后

    @Controller 
    @RequestMapping("/zar")
    public class HelloSpringMvc { 
        //相当于一个控制器处理的方法
        @RequestMapping("/hello") 
        public String one() {
            return "main";
        }
        @RequestMapping("/two")
        public String two() { 
            return "main"; 
        } 
        //客户端的请求:
        // 
    // }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.1.2对请求提交方式的定义

    • 对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。
    • Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与 RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。
    @RequestMapping(value = "/hello", method = RequestMethod.POST)
    public String one() { 
        return "main";
    }
    
    • 1
    • 2
    • 3
    • 4

    以上处理器方法只能处理 POST 方式提交的请求。

    客户端浏览器常用的请求方式,及其提交方式有以下几种:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hxf9HhLs-1659882586540)(../../../../Pictures/Spring/wps6.jpg)]

    也就是说,只要指定了处理器方法匹配的请求提交方式为 POST,则相当于指定了请求发送的方式:要么使用表单请求,要么使用 AJAX 请求。其它请求方式被禁用。

    当然,若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配。即对于请求的提交方式无要求。

    (1)post提交方式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V0nyOO7b-1659882586540)(../../../../Pictures/Spring/wps7.jpg)]

    (2)get提交方式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-akls4X3U-1659882586540)(../../../../Pictures/Spring/wps8.jpg)]

    对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解

    • 处理get请求的映射–>@GetMapping
    • 处理post请求的映射–>@PostMapping
    • 处理put请求的映射–>@PutMapping
    • 处理delete请求的映射–>@DeleteMapping

    2.1.3@RequestMapping注解的params属性(了解)

    @RequestMapping注解的params属性通过请求的请求参数匹配请求映射

    @RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数

    和请求映射的匹配关系

    • “param”:要求请求映射所匹配的请求必须携带param请求参数

      <a th:href="@{/test(username='admin',password=123456)">测试@RequestMapping的 
      params属性-->/testa><br>
      
      • 1
      • 2
      @RequestMapping( 
      	value = {"/testRequestMapping", "/test"} 
      	,method = {RequestMethod.GET, RequestMethod.POST} 
      	,params = {"username","password!=123456"} 
      )
      public String testRequestMapping(){ 
      	return "success"; 
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • “param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value

    • “param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value

    注:

    若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面回报错400:Parameter conditions “username, password!=123456” not met for actual
    request parameters: username={admin}, password={123456}

    2.1.4@RequestMapping注解的headers属性(了解)

    @RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射,来源页面

    @RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信

    息和请求映射的匹配关系

    • “header”:要求请求映射所匹配的请求必须携带header请求头信息
    • “!header”:要求请求映射所匹配的请求必须不能携带header请求头信息
    • “header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value
    • “header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value

    若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面

    显示404错误,即资源未找到

    2.2 五种数据提交的方式

    前四种数据注入的方式,会自动进行类型转换。但无法自动转换日期类型。

    (1)单个数据注入

    在方法中声明一个和表单提交的参数名称相同的参数,由框架按照名称直接注入。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5uJbNAc1-1659882586541)(../../../../Pictures/Spring/wps9.jpg)]

    (2)对象封装注入

    在方法中声明一个自定义的实体类参数,框架调用实体类中相应的setter方法注入属性值,只要保证实体类中成员变量的名称与提交请求的name属性值一致即可。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i4lJM74t-1659882586541)(../../../../Pictures/Spring/wps10.jpg)]

    (3)动态占位符提交(仅用于超链接)

    使用框架提供的一个注解@PathVariable,将请求url中的值作为参数进行提取,只能是超链接。restful风格下的数据提取方式。restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J8WYedCV-1659882586541)(../../../../Pictures/Spring/wps11.jpg)]

    (4)请求参数名称与形参名称不一致

    请求与形参中的名字不对应,可以使用

    @RequestParam(value="name1",required=true)String namea
    
    • 1

    来进行参数名称绑定。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7yElb5Xi-1659882586541)(../../../../Pictures/Spring/wps12.jpg)]

    (5)使用HttpServletRequest对象提取

    在方法参数中声明一个request对象,使用request的getParameter()获取表单提交的数据,这样得到的数据还要手工进行数据类型的转换。

    public String five(HttpServletRequest request){ 
        int age=new Integer(request.getParameter("stuage")); 
        String name=request.getParameter("stuname"); 
        System.out.println(age+"*********"+name);
        return "main";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (6)获取请求头信息@RequestHeader

    @RequestHeader是将请求头信息和控制器方法的形参创建映射关系

    @RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

    (7)获取Cookie值@CookieValue

    @CookieValue是将cookie数据和控制器方法的形参创建映射关系

    @CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

    2.3请求参数中文乱码解决

    对于前面所接收的请求参数,若含有中文,则会出现中文乱码问题。Spring 对于请求参数中的中文乱码问题,给出了专门的字符集过滤器: spring-web-5.2.5.RELEASE.jar 的org.springframework.web.filter 包下的 CharacterEncodingFilter 类。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ytHsoltC-1659882586542)(../../../../Pictures/Spring/wps13.jpg)]

    (1)解决方案

    • 在 web.xml 中注册字符集过滤器,即可解决 Spring 的请求参数的中文乱码问题。
    • 不过,最好将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dvp61iiK-1659882586542)(../../../../Pictures/Spring/wps14.jpg)]

    (2)源码分析

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I2YGXSv6-1659882586542)(…/…/…/…/Pictures/Spring/wps15.jpg)]

    2.4处理器方法的返回值(处理AJAX请求)

    使用@Controller 注解的处理器的方法,其返回值常用的有四种类型:

    • 第一种:ModelAndView

    • 第二种:String

    • 第三种:无返回值void

    • 第四种:返回对象类型

    2.4.1返回 ModelAndView

    • 若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。
    • 当然,若要返回 ModelAndView,则处理器方法中需要定义 ModelAndView 对象。
    • 在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将总是有一部分多余:要么 Model 多余,要么 View 多余。即此时返回 ModelAndView 将不合适。较少使用。

    2.4.2返回 String

    处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址。

    ![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S1gMsHVb-1659882586543)(…/…/…/…/Pictures/Spring/wps16.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ojn4atP-1659882586543)(…/…/…/…/Pictures/Spring/wps17.jpg)](https://img-blog.csdnimg.cn/15a94715b6594994994f09713df9ff6f.jpeg)
    在这里插入图片描述

    当然,也可以直接返回资源的物理视图名。不过,此时就不需要再在视图解析器中再配置前辍与后辍了。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9yccpzlQ-1659882586543)(../../../../Pictures/Spring/wps18.jpg)]

    2.4.1无返回值void

    对于处理器方法返回 void 的应用场景,应用在AJAX 响应处理。若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。我们SSM整合案例中的分页使用的就是无返回值。

    2.4.2返回对象Object

    • 处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,自定义对象,Map,List 等。
    • 但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。
    • 返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
    • Ajax请求多用于Object返回值类型。
    • 由于转换器底层使用了Jackson 转换方式将对象转换为JSON 数据,所以需要添加Jackson的相关依赖。

    项目案例:使用ajax请求返回一个JSON结构的学生.

    实现步骤:

    A.在pom.xml文件中添加依赖

      <dependency>
    
       <groupId>com.fasterxml.jackson.coregroupId>
    
       <artifactId>jackson-databindartifactId>
    
       <version>2.9.8version>
    
      dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    B.添加jQuery的函数库,在webapp目录下,新建js目录,拷贝jquery-3.3.1.js到目录下

    C.在页面添加jQuery的函数库的引用

       <script src="js/jquery-3.3.1.js"></script>
    
    • 1

    D.发送ajax请求

    function show() {
    
         $.ajax({
           url:"${pageContext.request.contextPath}/ajax.action",
           type:"post",
           dataType:"json",
           success:function (stu) {
             $("#oneStu").html(stu.name+"------"+stu.age);
           }
         });
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    E.开发action

    @Controller
    public class AjaxDemo {
        @RequestMapping("/ajax")
        @ResponseBody  //此注解用来解析ajax请求
        public Object ajax(){
            Student stu = new Student("张三",22);
            return stu;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    F.在springmvc.xml文件中添加注解驱动

     <mvc:annotation-driven>mvc:annotation-driven>
    
    • 1

    G.index.jsp页面

      ajax访问服务器,返回一个学生
       
    • 1
    • 2

    2.5SpringMVC的四种跳转方式

    2.5.1 转发与重定向

    • 默认的跳转是请求转发,直接跳转到jsp页面展示
    • 使用框架提供的关键字redirect:,进行一个重定向操作,包括重定向页面和重定向action,
    • 使用框架提供的关键字forward:,进行服务器内部转发操作,包括转发页面和转发action。
    • 当使用redirect:和forward:关键字时,视图解析器中前缀后缀的拼接就无效了。

    页面部分:

     
    请求转发页面(默认)
    请求转发action
    重定向页面
    重定向action
    • 1
    • 2
    • 3
    • 4
    • 5

    Controller部分:

    @Controller
    public class JumpAction {  
        @RequestMapping("/one")   
        public String one(){    
            System.out.println("请求转发页面(默认)"); 
            //以前的访问方式     //request.getRequestDispatcher("/admin/main.jsp").forward(request,response);  
            //观察地址栏的变化: http://localhost:8080/one.action    
            //return "main"; //默认的访问方式是自动拼接前缀和后缀进行跳转   
            return "forward:/fore/user.jsp";//只要使用了forward:就可以屏蔽前缀和后缀的拼接,自己手工构建返回的全部路径+.jsp   
        }  
        @RequestMapping("/two") 
        public String two(){   
            System.out.println("请求转发action");  
            //观察地址栏的变化:  http://localhost:8080/two.action
            return "forward:/other.action"; 
            //不使用forward:,就会是这样的路径 /admin/other.action/.jsp
        } 
        @RequestMapping("/three")  
        public String three(){  
            System.out.println("重定向页面");   
            //观察地址栏的变化 http://localhost:8080/admin/main.jsp 
            return "redirect:/admin/main.jsp";
            //只要使用了redirect:就可以屏蔽前缀和后缀的拼接  
        }  
        @RequestMapping("/four")
        public String four(){ 
            System.out.println("重定向action"); 
            //观察地址栏的变化 http://localhost:8080/other.action    
            return "redirect:/other.action";
            //只要使用了redirect:就可以屏蔽前缀和后缀的拼接
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2.5.2 视图控制器view-controller

    当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view

    controller标签进行表示

     
    <mvc:view-controller path="/testView" view-name="success">mvc:view-controller>
    
    • 1
    • 2

    注:

    当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需

    要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:

    2.6SpringMVC支持的默认参数类型

    JSP中内置对象

    • pagecontext JSP页面的范围
    • HttpServletRequest 一次请求的范围
    • HttpSession 一次会话的范围
    • ServletContext(application) 整个应用的范围

    这些类型只要写在方法参数中就可以使用了。

    1)HttpServletRequest 对象

    2)HttpServletResponse 对象

    3)HttpSession 对象

    4)Model/ModelMap 对象

    5)Map对象

    示例:

    @Controller
    public class ParamAction {
        @RequestMapping("/param") 
        public String param(HttpServletRequest request,    
                            HttpServletResponse response,  
                            HttpSession session,     
                            Model model,    
                            ModelMap modelMap,    
                            Map map){   
            //Map ,Model,ModelMap,request都使用请求作用域进行传值, 
            //所以必须使用请求转发的方式进行跳转,否则丢失数据
            Student stu = new Student("张三",22);  
            request.setAttribute("requestStu",stu); 
            session.setAttribute("sessionStu",stu);    
            modelMap.addAttribute("modelMapStu",stu); 
            model.addAttribute("modelStu",stu);  
            map.put("mapStu",stu);   
            return "main"; //切记请求转发跳转  
            // return "redirect:/admin/main.jsp";//会丢失数据 
        } 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    注意Model,Map,ModelMap都使用的是request请求作用域,意味着只能是请求转发后,页面才可以得到值

    2.6.1 使用ServletAPI向request域对象共享数据

    @RequestMapping("/testServletAPI") 
    public String testServletAPI(HttpServletRequest request){
        request.setAttribute("testScope", "hello,servletAPI"); 
        return "success";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.6.2 使用ModelAndView向request域对象共享数据

    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){ 
        /**
        * ModelAndView有Model和View的功能 
        * Model主要用于向请求域共享数据
        * View主要用于设置视图,实现页面跳转
        */
        ModelAndView mav = new ModelAndView();
        //向请求域共享数据
        mav.addObject("testScope", "hello,ModelAndView");
        //设置视图,实现页面跳转
        mav.setViewName("success");
        return mav;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.6.3 使用Model向request域对象共享数据

    @RequestMapping("/testModel")
    public String testModel(Model model){
        model.addAttribute("testScope", "hello,Model"); 
        return "success"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.6.4 使用map向request域对象共享数据

    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map){ 
        map.put("testScope", "hello,Map");
        return "success"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.6.5 使用ModelMap向request域对象共享数据

    @RequestMapping("/testModelMap")
    public String testModelMap(ModelMap modelMap){
        modelMap.addAttribute("testScope", "hello,ModelMap");
        return "success";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.5.6 Model、ModelMap、Map的关系

    Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的

    public interface Model{} 
    public class ModelMap extends LinkedHashMap<String, Object> {} 
    public class ExtendedModelMap extends ModelMap implements Model {} 
    public class BindingAwareModelMap extends ExtendedModelMap {}
    
    • 1
    • 2
    • 3
    • 4

    2.5.7、向session域共享数据

    @RequestMapping("/testSession")
    public String testSession(HttpSession session){
        session.setAttribute("testSessionScope", "hello,session"); 
        return "success"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.5.8、向application域共享数据

    @RequestMapping("/testApplication")
    public String testApplication(HttpSession session){
        ServletContext application = session.getServletContext(); 
        application.setAttribute("testApplicationScope", "hello,application"); 
        return "success"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.7日期处理

    2.7.1 日期注入

    日期类型不能自动注入到方法的参数中。需要单独做转换处理。

    使用@DateTimeFormat注解,需要在springmvc.xml文件中添加 标签。

    (1)在方法的参数上使用@DateTimeFormat注解

    @RequestMapping("/submitone")
    public String submitdateone(
        @DateTimeFormat(pattern="yyyy-MM-dd")  
        Date mydate){  
        System.out.println(mydate);   
        return "dateShow"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (2)在类的成员setXXX()方法上使用@DateTimeFormat注解

    @DateTimeFormat(pattern="yyyy-MM-dd")
    public void setDate(Date date) { 
        this.date = date;
    }
    
    • 1
    • 2
    • 3
    • 4

    但这种解决方案要在每个使用日期类型的地方都去添加使用@DateTimeFormat注解,比较麻烦,我们可以使用@InitBinder注解来进行类中统一日期类型的处理。

    (3)@InitBinder注解解决类中日期问题

    @InitBinder 
    public void initBinder(WebDataBinder dataBinder) { 
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd"); 
        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(sf, true));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样在类中出现的所有日期都可以进行转换了。

    2.7.2 日期显示

    (1)JSON中的日期显示

    需要在类中的成员变量的getXXX方法上加注解.

    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
    public Date getDate() { 
        return date; 
    }
    
    • 1
    • 2
    • 3
    • 4

    (2)JSP页面的日期显示

    需要使用国际化标签,先添加依赖

    <dependency> 
        <groupId>jstlgroupId> 
        <artifactId>jstlartifactId>
        <version>1.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    导入国际化的标签库

    <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    
    • 1

    再使用标签显示日期

    <c:forEach items="${list}" var="stu"> ${stu.name}-------${stu.age}-------
        <fmt:formatDate value="${stu.date}" pattern="yyyy-MM-dd">
    
    • 1
    • 2

    2.8 标签的使用

    • 会自动注册两个bean,分别为**DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter。**是springmvc为@controller分发请求所必须的。
    • 除了注册了这两个bean,还提供了很多支持。

    1)支持使用ConversionService 实例对表单参数进行类型转换;

    2)支持使用 @NumberFormat 、@DateTimeFormat;

    3)注解完成数据类型的格式化;

    4)支持使用 @RequestBody 和 @ResponseBody 注解;

    5)静态资源的分流也使用这个标签;

    2.9资源在WEB-INF目录下

    • 很多企业会将动态资源放在WEB-INF目录下,这样可以保证资源的安全性。
    • 在WEB-INF目录下的动态资源不可以直接访问,必须要通过请求转发的方式进行访问。
    • 这样避免了通过地址栏直接对资源的访问。重定向也无法访问动态资源。

    项目案例:

    页面结构图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-owcokdyh-1659882586543)(../../../../Pictures/Spring/wps19.jpg)]

    action:

    @Controller
    public class ShowAction { 
        @RequestMapping("/showIndex")  
        public String showIndex(){ 
            System.out.println("index............."); 
            return "index"; 
        }  
        @RequestMapping("/showMain") 
        public String showMain(){   
            System.out.println("main.............");
            return "main";
        }  
        @RequestMapping("/showLogin") 
        public String showLogin(){    
            System.out.println("login............."); 
            return "login"; 
        }
        @RequestMapping("/login")  
        public String login(String name, String pwd, HttpServletRequest request){ 
            if("admin".equals(name) && "123".equals(pwd)){  
                return "main"; 
            }    
            request.setAttribute("msg","用户名或密码不正确!"); 
            return "login"; 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    运行结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GQyL7qla-1659882586544)(../../../../Pictures/Spring/wps20.jpg)]

    2.10SpringMVC支持ant风格的路径

    • ?:表示任意的单个字符(不包括**?**)
    • :表示任意的0个或多个字符(不包括*?**和 /
    • **:表示任意层数的任意目录

    注意:在使用 ** 时,只能使用/**/xxx的方式, * *前后不能有任何字符,只能有//

    2.11@RestController注解

    @RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解

    第3章 拦截器与异常处理器

    • SpringMVC 中的 Interceptor 拦截器,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。
    • 其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。
    • 当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。

    3.1 拦截器介绍

    3.1.1拦截器的应用场景

    1、日志记录:记录请求信息的日志

    2、权限检查,如登录检查

    3、性能检测:检测方法的执行时间

    3.1.2 拦截器的执行原理

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WeMv4JEm-1659882586544)(../../../../Pictures/Spring/wps21.jpg)]

    3.1.3拦截器执行的时机

    1)preHandle():在请求被处理之前进行操作

    2)postHandle():在请求被处理之后,但结果还没有渲染前进行操作,可以改变响应结果

    3)afterCompletion:所有的请求响应结束后(渲染视图完毕)执行善后工作,清理对象,关闭资源

    3.1.4 拦截器实现的两种方式

    1)继承HandlerInterceptorAdapter的父类

    2)实现HandlerInterceptor接口,实现的接口,推荐使用实现接口的方式

    3.2 HandlerInterceptor接口分析

    自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:

    (1) preHandle

    该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。

    (2) postHandle

    该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。

    (3)afterCompletion

    当preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据等。

    3.3 自定义拦截器实现权限验证

    实现一个权限验证拦截器。

    1. 修改web.xml文件中请求路径

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gh3cYNVZ-1659882586544)(../../../../Pictures/Spring/wps22.jpg)]

    1. 将所有的页面放入WEB-INF目录下

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ewmLGMo-1659882586544)(../../../../Pictures/Spring/wps23.jpg)]

    1. 开发登录action

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fk8sETep-1659882586545)(../../../../Pictures/Spring/wps24.jpg)]

    1. 开发拦截器

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f1LmF4yy-1659882586545)(../../../../Pictures/Spring/wps25.jpg)]

    1. 配置springmvc.xml文件
     
    <mvc:interceptors>  
        <mvc:interceptor> 
             
            
            
            <mvc:mapping path="/**"/> 
                
            <mvc:exclude-mapping path="/login">mvc:exclude-mapping>  
            <mvc:exclude-mapping path="/showLogin">mvc:exclude-mapping>    
              
            <bean class="com.bjpowernode.interceptor.LoginInterceptor">bean> 
            
        mvc:interceptor> 
    mvc:interceptors> 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.4 过滤器和拦截器的区别

    1、实现原理不同

    过滤器和拦截器 底层实现方式大不相同,过滤器 是基于函数回调的,拦截器 则是基于Java的反射机制(动态代理)实现的。

    2、使用范围不同

    • 过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。
    • 拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IeAmsDTN-1659882586545)(../../../../Pictures/Spring/image-20220807201506264.png)]

    3、触发时机不同

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SladAgzy-1659882586545)(../../../../Pictures/Spring/image-20220805113721158.png)]

    • 过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。
    • 拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

    4、拦截的请求范围不同

    Filter 处理中
    Interceptor 前置
    Interceptor 处理中
    Interceptor 后置
    Filter 处理中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 过滤器Filter执行了两次,拦截器Interceptor只执行了一次。
    • 这是因为过滤器几乎可以对所有进入容器的请求起作用,
    • 而拦截器只会对Controller中请求或访问static目录下的资源请求起作用。

    5、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

    • ​ ①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
    • ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
    • ③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
    • ④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
    • ⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
    • ⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JYKH8wpf-1659882586546)(../../../../Pictures/Spring/image-20220805113828880.png)]

    3.5 多个拦截器的执行顺序

    ①若每个拦截器的preHandle()都返回true

    此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:

    preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行

    ②若某个拦截器的preHandle()返回了false

    preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false

    的拦截器之前的拦截器的afterCompletion()会执行

    3.6 异常处理器

    3.6.1 基于配置的异常处理

    SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver

    HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver

    SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    	<property name="exceptionMappings">
    		<props>
                
    			<prop key="java.lang.ArithmeticException">errorprop>
    		props>	
    	property>
        
    	<property name="exceptionAttribute" value="ex">property>
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.6.2 基于注解的异常处理

    //@ControllerAdvice将当前类标识为异常处理的组件
    @ControllerAdvice
    public class ExceptionController {
    	//@ExceptionHandler用于设置所标识方法处理的异常	
        @ExceptionHandler(ArithmeticException.class)
    	//ex表示当前请求处理中出现的异常对象
    	public String handleArithmeticException(Exception ex, Model model){ 
            model.addAttribute("ex", ex);
            return "error";
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    第4章RESTful

    4.1RESTful简介

    REST:Representational State Transfer,表现层资源状态转移。

    ①资源

    • 资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。
    • 每个资源是服务器上一个 可命名的抽象概念。
    • 因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、 数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端 应用开发者能够理解。
    • 与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。
    • 一个 资源可以由一个或多个URI来标识。
    • URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴 趣的客户端应用,可以通过资源的URI与其进行交互。

    ②资源的表述

    • 资源的表述是一段对于资源在某个特定时刻的状态的描述。
    • 可以在客户端-服务器端之间转移(交换)。
    • 资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。
    • 资源的表述格式可以通过协商机制来确定。
    • 请求-响应方向的表述通常使用不同的格式。

    ③状态转移

    • 状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。
    • 通过转移和操作资 源的表述,来间接实现操作资源的目的。

    4.2RESTful的实现

    具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。

    它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。

    REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。

    操作传统方式REST风格
    查询操作getUserById?id=1user/1–>get请求方式
    保存操作saveUseruser–>post请求方式
    删除操作deleteUser?id=1user/1–>delete请求方式
    更新操作updateUseruser–>put请求方式

    4.3HiddenHttpMethodFilter

    • 由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?
      • SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们 POST 请求转换为 DELETE PUT 请求
    • HiddenHttpMethodFilter 处理put和delete请求的条件:
      • a>当前请求的请求方式必须为post
      • b>当前请求必须传输请求参数_method
      • 满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数
        _ method的值,因此请求参数 _ method的值才是最终的请求方式

    在web.xml中注册HiddenHttpMethodFilter

    <filter>
    	<filter-name>HiddenHttpMethodFilterfilter-name>
    	<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter
            filter- class>
    filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilterfilter-name>
    	<url-pattern>/*url-pattern>
    filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和

    HiddenHttpMethodFilter

    在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter 原因:

    • 在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的

    • request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:

    • String paramValue = request.getParameter(this.methodParam);
      
      • 1

    第5章 注解配置SpringMVC及执行流程

    使用配置类和注解代替web.xml和SpringMVC配置文件的功能

    5.1创建初始化类,代替web.xml

    • 在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类, 如果找到的话就用它来配置Servlet容器。
    • Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。
    • Spring3.2引入了一个便利的WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatcherServletInitializer,当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候,容器会自 动发现它,并用它来配置Servlet上下文。
    public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        /**
        *指定spring的配置类
        *@return
        */ @Override
        protected Class<?>[] getRootConfigClasses() { 
            return new Class[]{SpringConfig.class};
        }
    
        /**
        *指定SpringMVC的配置类
        *@return
        */ @Override
        protected Class<?>[] getServletConfigClasses() { 
            return new Class[]{WebConfig.class};
        }
    
    
        /**
        *指定DispatcherServlet的映射规则,即url-pattern
        *@return
        */ @Override
        protected String[] getServletMappings() {
            	return new String[]{"/"};
        }
    
    
        /**
        *添加过滤器
        *@return
        */ 
        @Override
        protected Filter[] getServletFilters() {
        	CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); 
            encodingFilter.setEncoding("UTF-8"); encodingFilter.setForceRequestEncoding(true);
        	HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        	return new Filter[]{encodingFilter, hiddenHttpMethodFilter};
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    5.2 创建SpringConfig配置类,代替spring的配置文件

    @Configuration
    public class SpringConfig {
        //ssm整合之后,spring的配置信息写在此类中
    }
    
    • 1
    • 2
    • 3
    • 4

    5.3 创建WebConfig配置类,代替SpringMVC的配置文件

    @Configuration
    //扫描组件@ComponentScan("com.atguigu.mvc.controller")
    //开启MVC注解驱动@EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
    
        //使用默认的servlet处理静态资源@Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
        	configurer.enable();
        }
    
        //配置文件上传解析器@Bean
        public CommonsMultipartResolver multipartResolver(){
            return new CommonsMultipartResolver();
        }
    
        //配置拦截器@Override
        public void addInterceptors(InterceptorRegistry registry) {
            FirstInterceptor firstInterceptor = new FirstInterceptor(); 
            registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
        }
    
        //配置视图控制
    
        /*@Override
        public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index");
        }*/
    
        //配置异常映射
        /*@Override public void
        configureHandlerExceptionResolvers(List resolvers) { SimpleMappingExceptionResolver exceptionResolver = new
        SimpleMappingExceptionResolver(); Properties prop = new Properties();
        prop.setProperty("java.lang.ArithmeticException", "error");
        //设置异常映射exceptionResolver.setExceptionMappings(prop);
        //设置共享异常信息的键exceptionResolver.setExceptionAttribute("ex"); resolvers.add(exceptionResolver);
    
        }*/
    
        //配置生成模板解析器@Bean
        public ITemplateResolver templateResolver() { 
            WebApplicationContext webApplicationContext =
        ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
        webApplicationContext.getServletContext()); 
            templateResolver.setPrefix("/WEB-INF/templates/"); 
            templateResolver.setSuffix(".html"); templateResolver.setCharacterEncoding("UTF-8"); 
            templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver;
        }
    
        //生成模板引擎并为模板引擎注入模板解析器@Bean
        public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
            SpringTemplateEngine templateEngine = new SpringTemplateEngine(); 			
            templateEngine.setTemplateResolver(templateResolver);
            return templateEngine;
        }
    
        //生成视图解析器并未解析器注入模板引擎@Bean
        public ViewResolver viewResolver(SpringTemplateEngine templateEngine) { 
            ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); 
            viewResolver.setCharacterEncoding("UTF-8"); 
            viewResolver.setTemplateEngine(templateEngine);
            return viewResolver;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    5.4测试功能

    @RequestMapping("/")
    public String index(){
    	return "index";
    }
    
    • 1
    • 2
    • 3
    • 4

    5.5 SpringMVC常用组件

    • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供

      ​ 作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

    • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供

      ​ 作用:根据请求的url、method等信息查找Handler,即控制器方法

    • Handler:处理器,需要工程师开发

      ​ 作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理

    • HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供

      ​ 作用:通过HandlerAdapter对处理器(控制器方法)进行执行

    • ViewResolver:视图解析器,不需要工程师开发,由框架提供

      ​ 作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView

    • View:视图

      ​ 作用:将模型数据通过页面展示给用户

    5.6 SpringMVC的执行流程

    1. 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。

    2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:

    a) 不存在

    i. 再判断是否配置了mvc:default-servlet-handler

    ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXk9ebEH-1659882586546)(../../../../Pictures/Spring/image-20220807222630291.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V5hS3SGC-1659882586546)(../../../../Pictures/Spring/wps19-16598823188431.jpg)]

    iii. 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404 错误

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MsbrDHAw-1659882586546)(../../../../Pictures/Spring/image-20220807222657996.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sQulx2oE-1659882586547)(../../../../Pictures/Spring/wps21-16598823188433.jpg)]

    b) 存在则执行下面的流程

    1. 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。

    2. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。

    3. 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】

    4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

    • HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
    • 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
    • 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
    • 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
    1. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。

    2. 此时将开始执行拦截器的postHandle(…)方法【逆向】。

    3. 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。

    4. 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。

    5. 将渲染结果返回给客户端。

  • 相关阅读:
    JVisualVM 中线程状态(运行/休眠/等待/驻留/监视)解析
    机器学习与深度学习
    Linux SocketCAN 编程(C++,启用多线程接收)
    Java方法调用动态绑定(多态性)详解
    Feign服务调用
    Windows10 安装 Ubuntu(WSL2)
    入门力扣自学笔记147 C++ (题目编号1598)
    layui几种加载方式
    C语言实现冒泡排序
    SpringBoot实战案例:图书管理系统
  • 原文地址:https://blog.csdn.net/m0_61163395/article/details/126218787