Spring_MVC

SpringMVC

1. 概述:

MVC是一个表现层框架,通过注解让POJO【简单的Java对象】成为请求处理的控制器,且无需实现任何接口。支持REST风格的URL请求

优略分析:

SpringMVC与Struts2的优略分析

1.1 B/S基本流程

[外链图片转存在这里插入图片描述
在这里插入图片描述

  1. 客propagation户端请求提交到DispatcherServlet

  2. 由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller

  3. DispatcherServlet将请求提交到Controller(也称为Handler)

  4. Controller调用业务逻辑处理后,返回ModelAndView

  5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

  6. 视图负责将结果显示到客户端

SpringMVC中的主要组件:

  • ​ DispatcherServlet :前端控制器
    • 根据自定义的拦截规则,将拦截下的请求,根据相应规则分发到目标Coltroller处理
      (简单来说,就时将拦截下的请求路径交给不同的servlet处理)
  • ​ Controller :页面控制器
    • 做MVC中C的事情,(可能相当于上面前端控制器交予的Servlet)用于对请求进行处理
  • ​ HandlerMapping :请求映射到处理器
    • 请求映射到处理器,找谁来处理,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器对象)
  • ​ HandlerAdaptor :处理转换器
  • ​ View Resolver :视图解析器
    • 把逻辑视图解析为具体的VIew,
      • 如InternalResourceViewResolver将逻辑视图名映射为JSP视图
  • ​ MultipartResolver :文件上传解析器
  • ​ HandlerExceptionResolver :异常处理器

1.2SpringMVC简单入门

  1. 创建Web环境,导入jar包(Spring核心包和web包)

    1. spring-beans-5.3.1.jar
    2. spring-context-5.3.1.jar
    3. spring-core-5.3.1.jar
    4. spring-expression-5.3.1.jar
    5. spring-jcl-5.3.1.jar
    6. spring-aop-5.3.1.jar
    7. spring-web-5.3.1.jar
    8. spring-webmvc-5.3.1.jar
  2. 在web.xml文件中配置前端控制器DispatcheServlet

    1. 需要在标签中通过子标签设置SpringMVC的配置路径
    2. 如果不配置,就会默认寻找【/WEB-INF/标签里配置的值-servlet.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>
            <!--配置 DispatcherServlet 的初始化参数:设置springMVC文件的路径和文件抿成-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
            <!--设置为服务器启动时创建-->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <!--设置访问所有非jsp路径的-->
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <!--此处设置 【/】 是为了替换tomcat中的默认行为 -->
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  3. 在src目录下配置Springmvc.xml

    1. 配置自动扫描的包

    2. 视图解析器【InternalResourceViewResolver】
      到时候转发的路径网页为:前缀 + 转发过来的数据+.jsp

      1. 配置前缀:prefix

      2. 配置后缀:suffix

        <?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: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/context https://www.springframework.org/schema/context/spring-context.xsd">
            <!--    配置自动扫描的包-->
            <context:component-scan base-package="com.atguigu.springmvc"></context:component-scan>
            <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <!--        配置前缀-->
                <property name="prefix" value="/WEB-INF/views/"></property>
                <!--        配置后缀-->
                <property name="suffix" value=".jsp"></property>
            </bean>
        </beans>
        
  4. 在首页添加一个超链接

    <a href="${pageContext.request.contextPath}/helloworld">Hello SpringMVC</a>
    
  5. 创建控制器/处理器(Controller)

    1. 在类上添加注解@Contorller

    2. 在方法上添加注解@RequsetMapping

      1. value属性为超链接中传过来的请求路径

        package com.atguigu.springmvc;
        
        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.RequestMapping;
        
        @Controller
        public class HelloWorld {
        
            @RequestMapping(value = "/helloworld")
            public String helloWorld(){
                System.out.println("Hello SpringMVC!");
                return "success";
            }
        }
        
        
  6. 在前缀定义的相应位置创建success.jsp页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>成功页面</title>
    </head>
    <body>
        <h1>请求成功!</h1>
    </body>
    
  7. 部署tomcat测试
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrW3VWiG-1617632806119)(C:\Users\罗先生\AppData\Roaming\Typora\typora-user-images\1615206892128.png)]

2. @RequestMapping注解

2.1 映射普通请求地址

  • 可以添加的位置

    • 类上:添加到类上的信息,相当于标记类中的根目录
    • 方法上:提供进一步细分的映射信息
  • 可以配置的属性

    • value/path:用来设置要映射URL的【String数组】

      • 花括号可以省略 {“/fingOne”,“/findTwo”}
      • 如果只有value属性,则属性名可以省略
    • method:用来设置映射URL可以处理的请求方式

      • 如果该属性没有指定,那么将只考虑请求地址,不考虑请求方式
      • 可以这只GET、POST等
    • params:过滤指定参数的请求

      • 设置URL必须包含的请求参数

      • 值为String类型数组,

        • 如果某一元素中只有名称,则必须包含
        • 如果某一元素为一个简单表达式(age=18)那么请求参数必须有18的一个age才可以
      • 可以使用【= 、!=、!xxx=xx】

      • 使用案例:

        @RequestMapping(value = "/testParams",params ={"name=zs","age"} )
        public String testParams() {
            System.out.println("参数必须有age,且name属性为zs");
            return "success";
        }
        
    • header:过滤指定请求的header参数

      • 设置处理包含请求头信息的请求

      • 或者请求头中某个参数的值为XXX时,才会处理请求,

        • 这里的处理请求,指得是这个方法是否会执行,但是想要获取到header中的参数值,仅仅这样是不够的,还需要再方法的声明参数中,用@RequestHeader注解来获取
      • 使用案例:请求头中的Accept-Language属性值必须为zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7时,才会进行处理,

        @RequestMapping(value = "/testHeaders",headers = "Accept-Language=zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7")
        public String testHeaders(){
        	System.out.println("测试@RequestMapping的headers属性");
        	return SUCCESS;
        }
        
        

2.2 通配符与占位符

2.2.1 通配符如何使用
  • ?:代表一个任意字符

  • * :代表多个任意字符

  • **:代表多层路径

    在接受请求路径时,?可以兼容任意一个字符,一个与两个【*】同理比如下:
    <a href="/testTPF/1" >/testTPF
    <a href="/testTPF/d" >/testTPF

  • 使用案例:

    @RequestMapping(value = "/testTPF/?/{id}")
    public String testTPF(@PathVariable("id") Integer id) {
        System.out.println("参数为:" + id);
        return "success";
    }
    
2.2 映射带占位符的URL

@PathVariable:获取Rest风格中的占位符参数。

注意:RequestMapping中的占位符必须与方法声明中的参数名称相同,如果名称不相同,那么方法声明中的参数值为空,也可以通过required属性来指定该参数为非必须参数

  • 该注解用到参数中

    • value/name:用来指定占位符的名称
    • required:用来设置value属性指定的占位符是否必须,默认true
  • 使用案例:{id}即为占位符

    @RequestMapping(value = "/hello/{id}")//此处的【id】应该与方法参数中的【id】相匹配,不然获取不到该参数的值
    public String testRuest(@PathVariable(value = "id",required = false) Integer id) {
        return "success";
    }
    
    

2.3 REST风格

简单来说就是请求中没有参数名称,直接跟相应的参数值,通过不同的提交方法,来指明为不同的操作,举例: /getBookById/1 GET请求 == /getBookById?id=1 GET请求

  • 将四种请求方式对应四种操作方式

    • GET:获取资源
    • POST:新建资源
    • PUT:更新资源
    • DELETE:删除资源
  • 如何发送PUT与DELETE方式的请求

    • 在web.xml中通过HiddenHttpMethodFilter过滤器,解析响应的方法

    • 配置过滤器

          <filter>
              <filter-name>hiddenHttpMethodFilter</filter-name>
              <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
          </filter>
          <filter-mapping>
              <filter-name>hiddenHttpMethodFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
      
    • 发送格式

      <form action="${pageContext.request.contextPath}/testMethod" method="post">
        <input type="hidden" name="_method" value="put">
        <input type="submit" value="Test REST_Put">
      </form>
      <form action="${pageContext.request.contextPath}/testMethod/8" method="post">
          <input type="hidden" name="_method" value="delete">
          <input type="submit" value="Test REST_Delete">
      </form>
      

2.4 如何获取传统请求中参数

  • @RequestParam

    • 该注解使用在参数中,用来获取传统请求中携带的参数
    • 属性有几下几点
      • value/name:用来接受请求参数的参数名
      • required:设置该参数是否为必须。默认为ture
      • defaultvalue属性:给当前请求参数设置默认值,如果没有请求参数的传入,则使用默认值
  • @RequestHeader:获取请求中携带的请求头信息【与上方所拥有的属性一致】

  • @CookieValue:获取请求中携带的Cookie信息【与上方所拥有的属性一致】

  • 直接封装为POJO【简单对象】

    • 使用要求:必须保证请求参数名与POJO的属性名保持一致
      • form中的name必须与bean中的属性名一致
      • bean中的属性最好使用自动生成的getter与setter
      • 处理该请求的方法申明参数的类型必须与类名称一致
    请求页面
    <form method="post" action="${pageContext.request.contextPath}/testPOJO">
    
        图书数量: <input type="text" name="totalAccount"><br>
        图书名称: <input type="text" name="book.title"><br>
        图书作者: <input type="text" name="book.author"><br>
        <input type="submit" value="testPOJO">
    </form>
    处理页面
    @RequestMapping(value = "/testPOJO", method = RequestMethod.POST)
    public String testPOJO(CartItem cartItem) {
        System.out.println(cartItem);
        return "success";
    }
    bean
    public class CartItem {
        private Book book;
        private Integer totalAccount;
        ......
    }
    public class Book {
        private String title;
        private String author;
    	......
    }
    
  • 如果不使用@RequestParam注解和POJO,也可以使用原生的Servlet API作为声明参数进行操作

  • Springmvc处理器方法中接受原生的Servlet API有以下9个

    1. HttpServletRequest
    2. HttpServletResponse
    3. HttpSession
    4. java.security.Principal
    5. Locale
    6. InputStream
    7. OutputStream
    8. Reader
    9. Writer

3. 解决springmvc中request的post请求中文乱码问题

  1. 在Java web工程中的配置文件web.xml中配置一个filter
  2. 具体配置的类文件为:org.springframework.web.filter.CharacterEncodingFilter
  3. 需要初始化其中两个参数
    1. encoding:初始化该属性为UTF-8
    2. forceRequestEncoding:初始化该属性为true
<!--  配置过滤器,用来配置POST格式的请求编码为UTF-8   -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!--            设置encoding属性为 UTF-8 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
<!--        设置 forceRequestEncoding 属性为true-->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

可以查看源码如下:

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    String encoding = this.getEncoding();
    if (encoding != null) {//当encoding不为空,就是只有初始化之后,才可以进入此判断
        if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
            //isForceRequestEncoding属性含义为:是否强制请求编码
            //如果,在初始化时,将上述属性设置为true或者检测到客户端已经设置过编码,
            //那么此时过滤器将不会再帮助我们重新设置编码
            //getCharacterEncoding==null 即为客户端没有设置过编码
            request.setCharacterEncoding(encoding);
        }

        if (this.isForceResponseEncoding()) {
            response.setCharacterEncoding(encoding);
        }
    }

    filterChain.doFilter(request, response);
}

4. 处理响应参数

SpringMVC提供两种途径输出模型数据:两种方法最后都会将数据添加到Request域中

  • ModelAndView:
    处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据,最终会添加到request域中。
  • Map或Model或ModelMap:
    入参为java.uti.Map、 org.springframework.ui.Model或org.springframework.ui.ModelMap 时,处理方法返回时,Map 中的数据会自动添加到模型中,并最终添加到request域中。

4.1 ModelAndView

当返回值为ModelAndView 时,其中包含视图信息,也包括模型数据信息

  • 核心属性
    • private Object view; 视图信息
    • private ModelMap model; 模型数据
  • 添加模型数据的方法
    • ModelAndView addObject(String attributeName,Object attributeValue)
    • ModelAndView addAllObject(Map<String, ?> modelMap)
  • 获取模型数据的方法
    • protected Map<String, Object> getModelInternal()
    • public ModelMap getModelMap()
    • public Map<String, Object> getModel()
  • 设置视图的方法
    • void setView(View view) 设置视图对象
    • void setViewName(String viewName) 通过视图名字设置跳转视图

4.2 Map或Model或ModelMap:

Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据,具体使用步骤

  • Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。

  • 如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。

  • 在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据

  • Map、Model、ModelMap 三者的关系

    • ​ ModelMap继承了LinkedHashMap
    • ​ ExtendedModelMap继承了ModelMap实现了Model接口

当使用隐含对象模型作为数据的存储容器时,在处理器处理完成之后,会将该该隐含对象模型【Map、Model、ModelMap】放入到Ruquest域中,

5. 视图解析

  • 不论处理器方法返回一个String,ModelAndView还是View,Spring MVC 都会在内部将它们转换成一个 ModelAndView 对象,由视图解析器解析视图,然后,进行页面的跳转。
  • Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart等各种表现形式的视图。

在这里插入图片描述

5.1 视图解析器:

视图解析器的功能:

  1. 视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。
  2. 所有的视图解析器都必须实现 ViewResolver 接口
  3. 可以在 SpringMVC 上下文中配置一种或多种解析器,每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
  4. SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常。
  5. JSP 是最常见的视图技术,可以使用 InternalResourceViewResolve作为视图解析器。

5.2 指定请求页面直接跳转

5.2.1 spring配置__mvc:view-controller标签之后

通过配置该标签,让指定的访问请求不经过调度员直接跳转到指定页面

设置标签属性:

  • path属性:请求的路径
  • view-name属性:跳转资源的视图名称

注意:

  • 不经过处理器方法,直接转发到指定页面,
  • 但会使所有的@RequestMapping标签失效,所以我们要配置如下标签
  • <mvc:annotation-driven/>
5.2.2 配置静态资源处理器

在配置了DispatcherServlet后,网页中的js路径请求将会找不到处理该请求对应的处理器,想要使网页中的js路径请求与css路径请求可以使用,需要配置静态资源处理器,也就是在springxml中配置

<!--    配置静态资源处理器-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
  • 但是配置该标签之后,同样会使自定义的内部资源视图解析器【InternalResourceViewResolver】失去作用,所以,我们要想上面一样,同样才配置一个注解驱动支持【<mvc:annotation-driven/>】

5.3 转发与重定向:

​ 一般情况下,处理器方法返回字符串类型的值会被当成逻辑视图名处理。如果返回的字符串中带 【forward: 】或【 redirect: 】前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理:

处理方法返回时添加如下前缀:

  • forward:转发

  • redirect:重定向

    • 注意:在添加前缀之后,系统不会自动添加后缀,所以需要我们手动配置,

    • 该处的解析又服务器进行完成

    • 案例如下:

      return "forward:/XXX.jsp";
      

6. SpringMVC的form表单

使 编辑更加快捷、方便表单回显

导入标签库即可使用。<%@ taglib prefix=“form” uri=“http://www.springframework.org/tags/form” %>

  1. form:form标签
    1. 使用RESTFul时,get请求为获取表单页面,post请求为提交表单页面
    2. 如果获取表单和提交表单的URL相同,<form:form> 标签就无需通过 action 属性指定表单提交的 URL,默认提交方法为 method= post
    3. 默认会回显,以command为Key从request域中的查找数据
      1. 可以在form中使用modelAttribut属性修改command
  2. 表单项form:input、form:password、form:radiobutton、form:select对应 HTML input表单项的 text、password、radio和select 标签
  3. form:input标签中的属性
    1. path:表单字段,对应 html 元素的 name 属性,支持级联属性。
    2. htmlEscape:是否对表单值的 HTML 特殊字符进行转换,默认值为 true。
    3. cssClass:表单组件对应的 CSS 样式类名。
    4. cssErrorClass:表单组件的数据存在错误时,采取的样式
  4. form:radiobutton:单选框组件标签,当表单POJO对象对应的属性值和 value 值相等时,单选框被选中
    1. path:bean中对应的字段
    2. value:提交到bean中的属性值
    3. label:显示的名称
  5. form:radiobuttons:单选框组标签,用于构造多个单选框
    1. items:可以是一个 List、String[] 或 Map。
    2. itemValue:指定 radio 的 value 值。可以是集合中 bean 的一个属性值。
    3. itemLabel:指定 radio 的 label 值。
    4. delimiter:指定多个单选框的分隔符。
  6. form:checkbox:复选框组件,用于构造单个复选框。
  7. form:checkboxs:用于构造多个复选框。使用方式同 form:radiobuttons 标签。
  8. form:select:用于构造下拉框组件。使用方式同 form:radiobuttons 标签。
  9. form:option:下拉框选项组件标签。使用方式同 form:radiobuttons 标签。
  10. form:errors:显示表单组件或数据校验所对应的错误
    1. <form:errors path= “”/> :显示表单所有的错误。
    2. <form:errors path= “user*” /> :显示所有以 user 为前缀的属性对应的错误。
    3. <form:errors path= “username” /> :显示特定表单对象属性的错误。

7. 请求数据转换

HttpMessageConverter 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息。

注意:SpringMVC的配置文件中一定要配置mvc:annotation-driven标签。如果不配置将只装四个转换器。

6.1 使用方法:

  • @ResponseBody:对处理方法进行注解
    • 加到方法签名上
      • 会直接将内容响应到浏览器中,不会经过视图处理器
  • @RequestBody:对处理方法进行注解
    • 加在方法参数值中
      • 可以获取请求体的内容,且将内容转化为指定类型,如:String
      • 可以将请求体中的信息转化为指定类行的java对象
  • 不需要称对出现

示例代码:

加载参数声明中
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String info) {
    System.out.println(info);
    return "success";//跳转到success界面
}
加载方法上
@ResponseBody
@RequestMapping("/testJson")
public Employee testJson()  {
    Employee employee = new Employee(1001, "zhangsan", "zhangsan@163.com", new Department(0001, "销售"));
    return employee;//如果配置json时,就会返回json
}
  • HttpEntity :作为返回值或参数
    • 可以获取请求头信息
    • 也可以获取请求体信息
  • ResponseEntity :作为返回值或参数
    • 可以将请求体中的信息转化为指定类型的java对象
    • 也可以将请求头中的信息转化为指定类型的java对象

示例代码:

HttpEntity
@RequestMapping("/testHttpEntity")
public String testHttpEntity(HttpEntity<String> info) {
    System.out.println("info.getBody() = " + info.getBody());
    System.out.println("info.getHeaders() = " + info.getHeaders());
    return "success";
}
使用ResponseEntity,进行文件下载
@ResponseBody
@RequestMapping("/testResponseBody")
public ResponseEntity testResponseBody(HttpServletRequest request) throws IOException {
    String realPath = request.getServletContext().getRealPath("/download/jxs.png");
    InputStream is = new FileInputStream(realPath);
    byte[] bytes = new byte[is.available()];
    is.read(bytes);
    MultiValueMap<String, String> map = new HttpHeaders();
    map.set("content-disposition", "attachment;filename=机械师.png");
    HttpStatus httpStatus = HttpStatus.OK;
    ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, map, httpStatus);
    is.close();
    return responseEntity;
}

6.2 返回JSON数据

有了HttpMessageConverter之后,使用json更加方便了

使用方法:

  1. 导入相关jar包
    1. jackson-annotations-2.10.0.jar
    2. jackson-core-2.10.0.jar
    3. jackson-databind-2.10.0.jar
    4. Spring 5 不能使用 jackson 2.2.3版本的jar包,不然会出现bean初始化异常
    5. 必须要配置【<mvc:annotation-driver>】标签
  2. 设置对应的实体类
  3. 给处理方法添加@ResponseBody注解
  4. 返回bean对象即可

示例代码:

@ResponseBody
@RequestMapping("/testJSON")
public Employee testJson(){
    //创建Employee对象
    Employee employee = new Employee(1, "zhangsan", "zhangsan@atguigu.com", 1, new Department(1001, "Teacher"));
    return employee;//此处返回的就是json对象,可以在jsp页面中直接【点】
}

6.3 【<mvc:annotation-driver>】标签

在配置了静态资源处理器或指定页面跳转的标签之后,会使一些功能失效,比如 :DispatcherServlet中装配的handlerAdapters变少等等,所以我们要配置<mvc:annotation-driver>该标签。建议每个工程都有

  • <mvc:view-controller/>:指定页面跳转标签
  • <mvc:default-servlet-handler/>:静态资源处理器

8. 拦截器

如何自定义拦截器

创建自定义拦截器类

  • 通过实现接口【HandlerInterceptor】
  • 通过集成类【HandlerInterceptorAdapter】

重写拦截器中的三个方法

  • 请求前调用【preHandle】

    • 返回为ture:放行,但还是会被其他指定的拦截器拦截

    • 返回为false:直接拦截,不会继续进行

  • 处理器处理完成后,渲染视图前【postHandle】

  • 请求后调用,也就是视图渲染后【afterCompletion】

package com.atguigu.springmvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor.preHandle()......");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor.postHandle()......");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor.afterCompletion()......");
    }
}

拦截器的拦截顺序为springmvc.xml中的配置顺序

<mvc:annotation-driven></mvc:annotation-driven>
<!--    配置拦截器们-->
<mvc:interceptors>
    <!--        该拦截器可以拦截所有请求-->
    <bean id="interceptor" class="com.atguigu.springmvc.interceptor.FirstInterceptor"></bean>
    <!--        配置单个路径拦截器-->
    <mvc:interceptor>
        <mvc:mapping path="/testInterceptor2"/>
        <!--配置不拦截的路径-->
<!--    <mvc:exclude-mapping path="/testInterceptor"/>-->
        <bean class="com.atguigu.springmvc.interceptor.SecondInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

多个拦截器执行流程图

在这里插入图片描述

9. 异常处理

默认异常处理器 HandlerExceptionResolver 中有三个对象

通过在spring.xml种配置【SimpleMappingExceptionResolver】bean

使用步骤:

  1. 在SpringMVC的配置文件中配置SimpleMappingExceptionResolver
<!--    配置异常跳转至指定页面-->
    <bean id="simpleMappingExceptionResolver"
          class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
				<!--该种错误,渲染到error视图页面种-->
                <prop key="ArithmeticException">error</prop>
            </props>
        </property>
        <!--设置向request域中存放异常信息的key,默认是exception-->
        <property name="exceptionAttribute" value="e"></property>
    </bean>

  1. 创建处理器方法
@RequestMapping("/testSimple")
public String testSimpleMappingExceptionResolver(@RequestParam("i") Integer i){
    System.out.println("测试SimpleMappingExceptionResolver");
    int result = 10 / i;
    System.out.println(result);
    return "success";
}

  1. 测试路径

    <a href="${pageContext.request.contextPath}/testSimple?i=0">测试异常</a>
    
  2. 创建视图页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>错误页面</title>
    </head>
    <body>
        <h1>异常信息是:${requestScope.e}</h1>
    </body>
    </html>
    
    
  3. 页面信息

在这里插入图片描述

10. SpringMVC运行流程

  1. 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。也就是被mvc的调度员所劫持,等待调度员的派遣。
  2. DispatcherServlet对请求URL进行解析,得到请求资源标识符,判断该URI是否存在
    1. 如果不存在,
      1. 查看是否配置静态资源处理器【mvc:default-servlet-handler】
      2. 如果没有配置,控制台报映射查不到,客户端404
      3. 如果有配置,会去直接访问该资源,如果没有找到依旧会报404,但是这时的404会告诉你找不到的路径
    2. 如果存在,
      1. 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回
      2. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter【处理器】。
      3. 成功获得HandlerAdapter,将开始执行拦截器中的preHandler(…)方法,如果有多个拦截器对该请求生效,则按顺序依次进行拦截
      4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
        1. HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
        2. 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
        3. 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
        4. 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
      5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。
      6. 此时将开始执行拦截器的postHandle(…)方法【倒叙】。
      7. 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet,根据Model和View,来渲染视图。
      8. 在返回给客户端时需要执行拦截器的afterCompletion(…)方法【倒叙】。
      9. 将渲染结果返回给客户端。

执行流程图:
在这里插入图片描述
在这里插入图片描述

11. Spring整合Springmvc

两种解决方法,

第一种:

  • 不整合:
    • 将所有的配置都配置到Springmvc的配置文件中
    • 也可以创建多个配置文件,将配置文件放入到Springmvc的配置文件中

第二种:

  • 整合:

    • Spring负责管理Dao、Service、数据源及其他的第三方框架等。
    • Springmvc负责controller、视图解析器、静态资源等。
  • 但是依旧存在两个问题:

    1. 问题一:Spring的配置文件如何初始化
      • 解决:
        • 在Java工程中,ioc容器为手动创建
          • ApplicationContext ioc = new ClassPathXmlApplicationContext(“XXX.xml“)
        • 在Web工程中,可以在web.xml中配置一个监听器【ContextLoaderListener】,用来加载Spring的配置文件
    2. 问题二:Controller与Service层的Bean被创建了两次
      • 解决:
        • 让Springmvc只扫描controller
        • 让Spring不扫描controller

在Spring与Springmvc整合当中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">
<!--    配置 CharacterEncodingFilter 用来处理post请求乱码问题-->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--    配置前端控制器-->
    <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:springmvc.xml</param-value>
        </init-param>
        <!--        服务器启动时,创建-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <!--        过滤所有非jsp路径请求-->
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!--配置上下文的初始化参数,用来注入spring-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring.xml</param-value>
    </context-param>
    <!--    配置 ContextLoaderListener 监听器用来加载Spring配置文件-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

</web-app>

在Spring与Springmvc整合当中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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!--设置扫描的controller-->
    <context:component-scan base-package="com.atguigu.springmvc.ss" use-default-filters="false">
        <!--让Springmvc只扫描controller-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    <!--配置静态文件解析器-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
    <!--配置注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

在Spring与Springmvc整合当中spring.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: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/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!--不扫描Controller东西-->
    <context:component-scan base-package="com.atguigu.springmvc.ss">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--引入druid配置文件-->
    <context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>
    <!--配置数据源-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="${jdbc.initialSize}"/>
        <property name="minIdle" value="${jdbc.minIdle}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>
        <property name="maxWait" value="${jdbc.maxWait}"/>
    </bean>
    <!--    配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>
</beans>

DuridDataSource配置文件内容

#MySQL  8.0
#key=value
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bookstore1214?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true
#url=jdbc:mysql://localhost:3306/mysqldb
jdbc.username=root
jdbc.password=root
jdbc.initialSize=10
jdbc.minIdle=5
jdbc.maxActive=20
jdbc.maxWait=5000
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值