SpringMVC学习笔记

SpringMVC概述

1.1SpringMVC基本说明

SpringMVC是基于spring的,是spring中的一个模块,做web开发使用的,SpringMVC又叫做spring web mvc 说明他是spring的核心技术,做web开发,SpringMVC内部使用的是mvc架构模式。

SpringMVC是一个容器,管理对象的,使用IoC核心技术。SpringMVC管理界面层中的控制器对象。

SpringMVC底层也是Servlet。以Servlet为核心,接受请求,处理请求,显示处理结果给用户。

处理用户的请求:

用户发起请求-----SpringMVC-----Spring----MyBatis----mysql数据库

什么是MVC

MVC是模型(Model),视图(View),控制器(COntroller)的简写,是一种软件设计规范,是将业务逻辑,数据,显示分离的方法来组织代码,其主要作用是降低视图与业务逻辑间的双耦合,MVC不是一种设计模式,而是一种架构模式

1.2SpringMVC中的核心Servlet---DispatchServlet

DispatcherServlet是框架的一个Servlet对象,负责接收请求,响应处理结果

DispatcherServlet的父类是HttpServlet

DispatcherServlet也叫作前端控制器(front controller)

SpringMVC是管理控制器对象,原来没有SpringMVC之前使用Servlet作为控制器对象使用,现在通过SpringMVC容器创建一种叫做控制器的对象,代替Servlet行使控制器的角色,功能。

1.3第一个SpringMVC

步骤:

1.maven中新建web应用

2.加入web依赖

spring-webmvc依赖(springmvc框架依赖),servlet依赖。

<dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.11</version>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>javax.servlet-api</artifactId>
     <version>4.0.1</version>
   </dependency>
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>5.3.12</version>
   </dependency>

3.声明SpringMVC核心对象DispatcherServlet

1)DispatcherServlet是一个Servlet对象

2)DispatcherServlet叫做前端控制器(front controller)

3)DispatcherServlet作用:

1.在servlet的init()方法中,创建SpringMVC中的容器对象。

2.作为servlet,接受请求。

<!--在web.xml中声明-->
 <servlet>
   <servlet-name>myweb</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>
   <servlet-name>myweb</servlet-name>
   <url-pattern>*.do</url-pattern>
 </servlet-mapping>

<load-on-startup>标签的作用:标记是否在web服务器(这里用的是Tomcat)启动时是否创建这个Servlet实例,即是否在Web服务器启动时调用执行该Servlet的init()方法,而不是在真正访问时才创建。

其中它里面的数值必须是一个整数

当其中的值大于0时,表示容器在启动时就加载并初始化这个servlet,数值越小,该Servlet的优先级越高,其被创建的也就越早

当值小于0时或者没有被指定时,则表示该Servlet在真正被使用的时候才会被创建。

当两个值相同时,容器会自己选择创建顺序

4.创建一个jsp,发起请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Title</title>
</head>
<body>
<a href="/some.do">somedo</a>
</body>
</html>

5.创建一个普通的类,作为控制器使用(代替之前的Servlet)

1)在类的上面加入@Controller注解

@Controller:创建控制器(处理器)对象

控制器:叫做后端控制器(back controller),自定义的类处理请求的。

使用位置:在类的上面,表示创建此类的对象,对象放在SpringMVC容器中

2)在类中定义方法,方法的上面加入@RequestMapping注解

方法处理请求的,相当于servlet的doGet,doPost

@RequestMapping:(当在类上面使用时)

属性value:表示所欲请求地址的公共前缀,相当于是模块名称。

使用位置:在类的上面。

@RequestMapping:(当在方法上面使用时)

属性value:表示把指定的请求交给方法处理。

@Controller
public class MyController {
   @RequestMapping(value = "/some.do")
   public ModelAndView dosome(){
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("msg","测试");
       modelAndView.setViewName("show");
       return modelAndView;
  }
}

@RequestMapping:表示当前方法为处理器方法。该方法要对 value 属性所指定的 URI 进行处理与响应。被注解的方法的方法名可以随意。

若有多个请求路径均可匹配该处理器方法的执行,则@RequestMapping 的 value 属性中 可以写上一个数组。

    ModelAndView 类中的 addObject()方法用于向其 Model 中添加数据。Model 的底层为一 个 HashMap。

Model 中的数据存储在 request 作用域中,SringMVC 默认采用转发的方式跳转到视图, 本次请求结束,模型中的数据被销毁。

6.创建作为结果的jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

7.创建SpringMVC的配置文件(和spring的配置文件一样)

1)声明组件扫描器,指定@Controller注解所在的包名

2)声明视图解析器对象。

<?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.hao"/>
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <!--前缀:表示视图所在的路径-->
       <property name="prefix" value="/WEB-INF/view/"/>
       <!--后缀:表示视图文件的拓展名-->
       <property name="suffix" value=".jsp"/>
   </bean>
</beans>

8.使用逻辑视图名称。

1.4web开发中配置文件的说明

1.web.xml部署描述文件,给服务器(tomcat)

作用:服务器在启动的时候,读取web.xml,根据文件中的声明创建各种对象,根据文件中的声明,知道请求和servlet等对象的关系。

2.框架的配置文件,SpringMVC的配置文件

作用:声明框架创建项目中的各种对象,主要是创建Controller对象的,

配置文件的加载顺序和功能:

1.tomcat服务器启动,读取web.xml,根据web.xml文件中的说明,创建对象。

<servlet>
   <servlet-name>myweb</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>
   <servlet-name>myweb</servlet-name>
   <url-pattern>*.do</url-pattern>
 </servlet-mapping>

创建DispatcherServlet对象,会执行init()方法,在init()方法中会执行SpringMVC容器对象创建WebApplicationContext ctx=new ClassPathXMLApplicationContext(“classpath:springmvc.xml”)

2.springmvc框架,new ClassPathXMLApplicationContext()读取SpringMVC的配置文件。

    <context:component-scan base-package="com.hao"/>
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <property name="prefix" value="/WEB-INF/view/"/>
       <property name="suffix" value=".jsp"/>
   </bean>

使用组件扫描器base-package="com.hao.controller",遍历Controller包中的所有类,找到相关类中的@Controller,@RequestMapping注解,就能创建其对象。并执行相关方法。

1,2两步都是项目启动的过程,没有执行任何的用户请求

3.用户发起请求some.do----DispatcherServlet

DispatcherServlet里面有WebApplicationContext,WebApplicationContext里面有MyController对象,请求相关方法,DispatcherServlet就知道是MyController处理的。

其中MyController是自己创建的类,里面有@controller,@RequestMapping注解。

SpringMVC注解式开发

2.1RequestMapping注解的使用

属性:value 请求的uri地址

属性:1)在方法上面,必须的。2)在类的上面作为模板名称

@RequestMapping(value="/some.do")
public ModelAndView doSome(){}

属性method请求的方式,使用RequestMethod类的枚举,表示请求方式。

@RequestMapping(value="/some.do",method=RequestMethod.POST)
public ModelAndView doSome(){}

2.2接收请求中的参数

对于HttpServletRequest,HttpServletResponse,HttpSession只需要在控制器方法的形参列表中定义就可以了,框架会给参数赋值,在控制器方法内部可以直接使用request,response,session参数。

接收请求中的参数:逐个接收,对象接收

2.2.1 逐个接收

逐个接收:请求中的参数名和控制器方法的形参名一样,按照名称对象接收参数。

参数接收:

1.框架使用request对象,接收参数

String name=request.getParameter(“name”);

2.在中央调度器的内部调用相关方法时候,按名称对象传递参数。

<form action="/some.do" method="post">
  姓名:<input type="text" name="name"/><br>
  年龄:<input type="text" name="age"/><br>
   <input type="submit" value="提交"/>
</form>
@Controller
public class MyController {
   @RequestMapping(value = "/some.do")
   public ModelAndView dosome(String name,int age){

但是当请求中参数名和形参名不一样时,则得不到自己想要的值

这时候要加注解:@RequestParam,

属性值:value 请求中的参数名称

requierd:boolean类型的,

默认是true,请求中必须由此参数,否则会报错。

当时false时,表示请求中可以没有参数。

位置:在形参定义的前面

2.2.2请求参数中文乱码问题

如果获取参数的方法为post的话,如果参数中有中文,则会出现中文乱码问题,Spring对于请求参数中的中文乱码问题,给出了专门的字符集过滤器。

解决方案:

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

相关代码:

<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>
       <!--强制请求(request)对象使用encoding的编码方式-->
     <param-name>forceRequestEncoding</param-name>
     <param-value>true</param-value>
   </init-param>
   <init-param>
       <!--强制应答(response)对象使用的encoding的编码方式-->
     <param-name>forceResponseEncoding</param-name>
     <param-value>true</param-value>
   </init-param>
 </filter>
 <filter-mapping>
   <filter-name>characterEncodingFilter</filter-name>
   <url-pattern>/*</url-pattern>
 </filter-mapping>

接收参数的问题:

1.参数最好使用包装类型,例如Integer,能接收空值情况,接收的是null

2.框架可以使用String到int,long,float,double等类型装换

3.post请求中有乱码的问题,使用字符集过滤器。

2.2.3对象接收

对象接收:在控制器方法的形参是java对象,使用java对象的属性接收请求中的参数值

要求:java对象的属性名和请求中参数名一样。

框架的处理步骤:

1.调用Student的无参数构造方法,创建对象

2.调用对象set方法,同名的参数,调用对应的set方法,参数是name,则调用setName(参数值)。

例子:

//实体类
package com.hao.entity;

public class Student {
   private String name;
   private int age;

   public String getName() {
       return name;
  }

   public void setName(String name) {
       this.name = name;
  }

   public int getAge() {
       return age;
  }

   public void setAge(int age) {
       this.age = age;
  }
}
//Controller
   @RequestMapping(value = "/some2.do")
   public ModelAndView dosome2(Student student){
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("myname",student.getName());
       modelAndView.addObject("myage",student.getAge());
       modelAndView.setViewName("show");
       return modelAndView;
  }
<!--首页-->
<form action="/some2.do" method="post">
  姓名:<input type="text" name="name"/><br>
  年龄:<input type="text" name="age"/><br>
   <input type="submit" value="提交"/>
</form>

2.3控制器方法的返回值

控制器方法的返回值表示本次请求的处理结果,返回值有ModelAndView,String,void,Object

请求的处理结果包含:数据和视图

2.3.1ModelAndView数据和视图

请求的结果有数据和视图,使用ModelAndView最方便

数据:存放request作用域

视图:执行forward转发操作。

2.3.2 String视图

框架的返回值是String,执行的是forward转发操作,视图可以表示为完整试图路径,或者视图的逻辑名称。

    @RequestMapping(value = "/some3.do")
   public String dosome3(HttpServletRequest request,String name, int age){
    <!--返回值为路径的逻辑名称,需要配置视图解析器-->
       <!--如果返回值为完整视图路径,则不需要使用视图解析器-->
       return "show";
  }

视图解析器:

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <property name="prefix" value="/WEB-INF/view/"/>
       <property name="suffix" value=".jsp"/>
   </bean>

2.3.3void 没有数据和视图

void:没有数据和视图,可以使用HttpServletResponse对象输出数据,响应ajax请求

<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
   <script type="text/javascript">
       $(function (){
           $("#btnAjax").on("click",function(){
              $.ajax({
                  url:"return-void-ajax.do",
                  data:{
                      name:"张三",
                      age:11
                  },
                  dataType:"json",
                  success:function (resp){
                      alert("rest===="+resp.name+resp.age);
                  }

              })
          })
      })
   </script>
   @RequestMapping(value="/return-void-ajax.do")
   public void dosome4(HttpServletResponse response,String name, Integer age) throws IOException {
       System.out.println("姓名为"+name+"年龄为"+age);
       Student student = new Student();
       student.setName(name);
       student.setAge(age);
       ObjectMapper om=new ObjectMapper();
       String json=om.writeValueAsString(student);
       response.setContentType("application/json;charset=utf-8");
       PrintWriter pw=response.getWriter();
       pw.println(json);
       pw.flush();
       pw.close();
  }

2.3.4Object

控制器方法返回对象Object,用来响应ajax请求。返回对象Object,可以使List,Student,Map,String,Integer....这些都是数据,而ajax请求需要的就是数据,在ajax请求中,一般需要从服务器返回的是json格式的数据,经常要处理java对象到json的转换,而且还需要输出数据响应ajax请求,框架提供了处理java对象到json转换,和数据输出工作。

2.3.4.1HttpMessageConverter消息转换器

HttpMessageConverter接口,

作用

1)实现请求的数据转为java对象,

2)把控制器方法返回的对象转为json,xml,text,二进制等不同格式的数据。

2.3.4.2@ResponseBody

@ResponseBody注解的作用,就是把student转换后的json通过HttpServletResponse对象输出给浏览器

//输出json,响应ajax
response.setContentType("application/json;charset=utf-8");
       PrintWriter pw=response.getWriter();
       pw.println(json);
       pw.flush();
       pw.close();
@ResponseBody注解作用就是这一段代码的实现。

2.3.4.3控制器方法返回对象转为json的步骤

1)pom.xml加入jackson依赖,springmvc框架,默认处理json就是使用jackson

<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>4.0.1</version>
</dependency>
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <version>2.13.0</version>
</dependency>

2)在springmvc的配置文件中,加入注解驱动的标签mvc:annotation-driven

<mvc:annotation-driven/>
<!--注意此注解属于: xmlns:mvc="http://www.springframework.org/schema/mvc"-->

3)在控制器方法的上面加入@ResponseBody注解,表示返回值数据,输出到浏览器。

@RequestMapping(value="/doStudentJson.do")
@ResponseBody
public Student doAjaxJson(String name, Integer age) {

   Student student = new Student();
   student.setName(name);
   student.setAge(age);
   return student;
}

4)首页

<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
   <script type="text/javascript">
       $(function (){
           $("#btnAjax").on("click",function(){
              $.ajax({
                  //url:"return-void-ajax.do",
                  url:"doStudentJson.do",
                  data:{
                      name:"张三",
                      age:11
                  },
                  dataType:"json",
                 success:function (resp){
                      alert("rest===="+resp.name+resp.age);
                  }
              })
          })
      })
   </script>
<button id="btnAjax">发起Ajax请求</button>

框架的处理模式:

1.框架根据控制其方法的返回值类型,找到HttpMessageConverter接口的实现类,最后找到的是MappingJackson2HttpMessageConverter,

2.使用实现类MappingJackson2HttpMessageConverter,执行他的write()方法,把student对象转为了json格式的数据

3.框架使用@ResponseBody注解,把2中的json输出给浏览器。

2.3.4.4控制器方法返回list对象转为json的步骤

1)pom.xml加入jackson依赖,springmvc框架,默认处理json就是使用jackson

<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>4.0.1</version>
</dependency>
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <version>2.13.0</version>
</dependency>

2)在springmvc的配置文件中,加入注解驱动的标签mvc:annotation-driven

<mvc:annotation-driven/>
<!--注意此注解属于: xmlns:mvc="http://www.springframework.org/schema/mvc"-->

3)在控制器方法的上面加入@ResponseBody注解,表示返回值数据,输出到浏览器。

    @RequestMapping(value="/doStudentArray.do")
   @ResponseBody
   public List<Student> doAjaxList(){
       Student student1 = new Student();
       student1.setName("张三");
       student1.setAge(18);
       Student student2 = new Student();
       student2.setName("李四");
       student2.setAge(12);
       List<Student> list=new ArrayList<>();
       list.add(student1);
       list.add(student2);
       return list;
  }

4)首页

<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
   <script type="text/javascript">
       $(function (){
           $("#btnAjax").on("click",function(){
              $.ajax({
                  //url:"return-void-ajax.do",
                  //url:"doStudentJson.do",
                  url:"doStudentArray.do",
                  data:{
                      name:"张三",
                      age:11
                  },
                  dataType:"json",
                /* success:function (resp){
                      alert("rest===="+resp.name+resp.age);
                  }*/

                  success:function (resp){
                      $.each(resp,function (i,n){
                          alert("n name:"+n.name+"age:"+n.age);
                      })
                  }
              })
          })
      })
   </script>
<button id="btnAjax">发起Ajax请求</button>

2.3.4.3控制器方法返回对象为string文本数据解决乱码

在@RequestMapping中加入produces属性即可解决乱码问题:

@RequestMapping(value="/doStringData.do",procuces="text/plain;charset=utf-8")

第三章

相对路径

在页面中,有路径的问题,访问路径有“/"开头的,还有没有”/“开头的。

<a href="test/some.do">没有斜杠开头的</a>
<a href="/test/some.do">有斜杠开头的</a>
<a href="http://www.baidu.com">有协议开头的地址</a>

地址的区别:

1)有协议开头的例如http://www.baidu.com,称为绝对地址,地址是唯一的,可以直接访问的

2)没有协议开头的,例如test/some.do , /test/some.do称为相对地址,相对地址单独使用不能表示某个资源,不能访问。相对地址必须和参考地址在一起,才能表示一个资源的完整地址,才可以访问。

没有“/”开头的,多次点击可能出现页面未找到的现象,解决方法为在路径前面加上${pageContext.request.contextPath}/

<a href="test/some.do">没有斜杠开头的</a>
解决方式:
第一种:<a href="${pageContext.request.contextPath}/test/some.do">没有斜杠开头的</a>
优点:好理解
缺点:每个链接地址,都需要加el表达式
第二种:固定当前页面中没有“/”开头地址的参考地址,使用html中的base标签。
<%
String basePath=request.getScheme()+"://" + request.getServerName()+":" +request.getServerPort()+request.getContextPath()+"/";
  %>
<head>
   <base href="<%=basePath%>"/>
</head>

有“/”开头的地址,参考地址是服务器地址,也就是从协议开始到端口号的位置,地址缺少访问路径。

解决方式:在路径的前面加el表达式${pageContext.request.contextPath}

SpringMVC核心技术

请求重定向和转发

转发(forward)

控制器方法返回时ModelAndView实现转发forward

语法:mv.setViewName("forward:视图完整路径")

forward特点:不和视图解析器一同工作,就当项目中没有视图解析器

@Controller
public class MyController {
   @RequestMapping("/some.do")
   public ModelAndView dosome(){
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("msg","msg信息");
       modelAndView.setViewName("forward:/WEB-INF/view/show.jsp");
       //modelAndView.setViewName("show");和上面一样意思
       return modelAndView;
  }
}

forward语句可以用在需要访问视图解析器以外的前端页面时。

重定向redirect

控制器方法返回时ModelAndView实现重定向redirect

语法:modelAanView.setViewName("redirect:视图完整路径")

redirect特点:不和视图解析器一同工作,就当项目中没有视图解析器。

框架提供的重定向的功能:

1.框架可以事项两次请求之间的数据传递,把第一个请求中的Model里面简单类型的数据,转为字符串,附加到目标页面的后面,做get参数传递,可以在目标页面中获取参数值的使用。

2.在目标页面中,可以使用${param.参数名},获取参数的值。

重定向redirect不能访问受保护的目录(即/WEB-INF),而forward可以。

异常处理

框架使用的是集中地异常处理,把各个Controller中抛出的异常集中到一个地方处理,处理异常的叫做异常处理器

框架中使用两个注解完成异常的集中处理,这样每个Controller就不用单独处理异常了,这两个注解分别是:

1)@ExceptionHandler:放在方法的上面,表示此方法可以处理某个类型的异常,当异常发生时,执行这个方法。

2)@ControllerAdvice:放在类的上面,表示这个类中有异常的处理方法,相当于aop中的@Aspect。@ControllerAdvice看作是控制器增强,就是给Conroller类增加异常(切面)的处理功能。

拦截器

拦截器:是SpringMVC框架中的一种对象,需要实现接口HandlerInterceptor,拦截用户的请求,拦截到controller的请求。

作用:拦截用户的请求,可以预先对请求做处理,根据处理结果,决定是否执行controller,也可以把多个controller中共用的功能定义到拦截器

特点:

1.拦截器可以分为系统拦截器和自定义拦截器

2.一个项目可以有多个拦截器,0个或者多个自定义拦截器

3.拦截器侧重拦截用户的请求

4.拦截器是在请求处理之前先执行的。

一个拦截器

拦截器的定义:

1)创建类实现拦截器接口HandlerInterceptor,实现接口中的方法(3个)

public class MyInterceptor implements HandlerInterceptor {
   /*
  preHandle:预先处理请求的方法。
  参数:Object handler:被拦截的控制器对象(MyController)
  返回值:Boolean
  true:表示请求是正确的,可以被controller处理
  false:请求不能被处理,控制器方法不会执行。只执行preHandle方法,请求到此截止。
  特点:
  1.执行时间:在控制器方法之前先执行的
  2.可以对请求做处理,可以做登录的检查,权限的判断,统计数据等等。
  3.决定请求是否执行。
   */
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       System.out.println("preHandle执行了");
       return true;
  }

   /*
  postHandle:后处理方法
  参数:
  Object handler:被拦截的控制器对象(MyController)
  ModelAndView modelAndView:控制器方法的返回值(请求的执行结果)
  特点:
  1.在控制器方法之后执行的
  2.能获取到控制器方法的执行结果,可以修改原来的执行结果,可以修改数据,也可以修改视图
  3.可以做对请求的二次处理
   */
   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle执行了");
  }

   /*
  afterCompletion:最后执行的方法
  参数:
  Object handler:被拦截的控制器对象(MyController)
  Exception ex:异常对象
  特点:
  1.在请求处理完成后执行的
  请求处理完成的标志是:视图处理完成,对视图执行forward操作后
  2.可以做程序最后要做的工作,释放内存,清理临时变量
  3.方法的执行条件:
  1)当前拦截器的preHandle()方法必须执行。
  2)preHandle()必须返回true
   */
   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion执行了");
  }
}

2)在SpringMVC配置文件中,声明拦截器对象,并指定拦截的url地址。

<!--声明拦截器-->
<mvc:interceptors>
   <!--声明第一个拦截器-->
   <mvc:interceptor>
       <!--指定拦截器的拦截地址
           /**代表拦截所有地址
       -->
       <mvc:mapping path="/**"/>
       <!--指定要使用的拦截器-->
       <bean class="com.hao.handler.MyInterceptor"/>
   </mvc:interceptor>
</mvc:interceptors>

控制器相关的代码为:

@Controller
public class MyController {

   @RequestMapping("/some.do")
   public ModelAndView dosome(String name,Integer age){
       System.out.println("执行了MyController中的doSome方法");
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("myname",name);
       modelAndView.addObject("myage",age);

       modelAndView.setViewName("show");
       return modelAndView;
  }

}

当preHandle的返回值为true时候,其执行结果为:

preHandle执行了 执行了MyController中的doSome方法 postHandle执行了 afterCompletion执行了

请求的执行顺序为:用户发起请求---preHandle---控制器中的方法---postHandle---afterCompletion

当preHandle的返回值为false时候,其执行结果为:

preHandle执行了

多个拦截器

使用两个拦截器,主要看拦截器的执行顺序,以及哪个方法控制请求的执行。

使用多个拦截器的作用:

1.把验证功能分散到独立的拦截器,每个拦截器做单一的验证处理

2.组合多个拦截器

总结:多个拦截器,串在一个链条上,多个拦截器和一个控制对象在一个链条上,框架中使用HandlerExecutionChain(处理器执行链)表示这个执行链条。

当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再 次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专 门的方法栈中放入该拦截器的 afterCompletion()方法。即无论执行链执行情况怎样,只要 方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,并被执行到时候,就会执行方法栈中的 afterCompletion()方法。最终都会给出响应。

 

 

拦截器和过滤器的对比

  1. 拦截器是SpringMVC框架中的对象,过滤器是servlet中的对象

  2. 拦截器对象是框架容器创建的,过滤器对象是tomcat创建的对象

  3. 拦截器是侧重对请求做判断的,处理的,可以截断请求,过滤器是侧重对request,response对象的属性,参数设置值的,例如request.setCharacterEncoding(“utf-8”)

  4. 拦截器的执行时间有三个,分别是控制器方法之前,之后,请求完成后,过滤器的执行时间都是在请求之前。

  5. 拦截器是拦截对controller,动态资源请求的,过滤器可以过滤所有请求,包括动态的和静态的

  6. 拦截器和过滤器一起执行的话,先执行过滤器,然后执行中央调度器,然后是拦截器,最后面是控制器方法。

posted @ 2021-11-25 12:17  AMHAO  阅读(110)  评论(0编辑  收藏  举报