14SpringMVC的拦截器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了14SpringMVC的拦截器相关的知识,希望对你有一定的参考价值。


文章目录

  • ​​一、拦截器​​
  • ​​1.1 拦截器与过滤器​​
  • ​​1.2 拦截器的应用​​
  • ​​1.2.1 HandlerInterceptor接口​​
  • ​​1.2.2 拦截器的拦截规则​​
  • ​​1.3 搭建工程测试拦截器​​
  • ​​1.3.1 测试SpringMVC拦截器​​
  • ​​1.3.2 SprinMVC拦截器注意事项​​
  • ​​1.4 HandlerMethod类​​
  • ​​1.5 多个拦截器的执行顺序​​

一、拦截器

1.1 拦截器与过滤器

  • 过滤器

依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。

  • 拦截器:

依赖于web框架。在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。

1.2 拦截器的应用

1.2.1 HandlerInterceptor接口

在SpringMVC中,定义一个拦截器需要实现HandlerInterceptor接口;在该接口下有三个功能方法:

public interface HandlerInterceptor 

// 进入handler之前的处理(选择是否将该请求拦截下来),返回true:放行,返回false:拦截
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
return true;


// handler方法执行完毕后执行
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception


// 页面(JSP等)渲染后执行
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception

  • ​preHandle()​​​:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;
    当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
  • ​postHandle()​​:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
  • ​afterCompletion()​​:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。

1.2.2 拦截器的拦截规则

定义好拦截器后,需要设置拦截器的拦截规则(说明资源该拦截,什么资源不拦截)

符号

说明

?

匹配任何一个字符

*

匹配任何长度的字符

**

匹配多级目录的路径

1.3 搭建工程测试拦截器

1.3.1 测试SpringMVC拦截器

  • pom.xml:
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dfbz</groupId>
<artifactId>SpringMVC_01_Interceptor</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>

<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-api</artifactId>
<version>8.5.71</version>
</dependency>
</dependencies>
</project>
  • web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!--配置springmvc配置文件的位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

</web-app>
  • 编写拦截器:
package com.dfbz.interceptor;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.invoke.MethodHandle;

public class MyInterceptor implements HandlerInterceptor
/**
* 请求执行前执行(handle执行前执行)
*
* @param request
* @param response
* @param handler: 要执行的handler(目标方法)
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception

System.out.println("preHandle...");

return true;


/**
* handle执行后执行
*
* @param request
* @param response
* @param handler :要执行的handler(目标方法)
* @param modelAndView :handler返回的ModelAndView对象,如果目标方法没有返回ModelAndView则为null
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception
System.out.println("postHandle...");


/**
* 页面渲染后执行
*
* @param request
* @param response
* @param handler :要执行的handler(目标方法)
* @param ex :解析JSP页面出现异常时的异常对象
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception
System.out.println("afterCompletion...");

  • 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">

<!--包扫描-->
<context:component-scan base-package="com.dfbz"/>

<!--开启注解驱动-->
<mvc:annotation-driven />

<!--静态资源放行-->
<mvc:default-servlet-handler/>

<!--拦截器配置:将我们编写的拦截器加入到SpringMVC管理的拦截器中-->
<mvc:interceptors>

<!--配置单个拦截器-->
<mvc:interceptor>
<!--
path:拦截规则
?:匹配单个字符
*:代表匹配任意长度的字符(只能匹配单机目录)
**:代表匹配任意长度的多级目录
-->
<!-- <mvc:mapping path="/**"/>-->

<!--代表拦截/user下的所有请求-->
<mvc:mapping path="/user/**"/>

<!--代表放行/user/register请求-->
<mvc:exclude-mapping path="/user/register"/>

<!--配置拦截器-->
<bean class="com.dfbz.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
  • Controller:
package com.dfbz.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

/**
* @author lscl
* @version 1.0
* @intro:
*/
@RequestMapping("/user")
@RestController
public class UserController

@GetMapping("/login")
public String login() // 进入拦截器
System.out.println("login");
return "login";


@GetMapping("/register")
public String register() // 不进入拦截器
System.out.println("register");
return "register";


@GetMapping("id") // 进入拦截器
public String findById(@PathVariable Integer id)
System.out.println("findById");
return "findById: " + id;


@GetMapping
public String findAll() // 进入拦截器
System.out.println("findAll");
return "findAll";


@GetMapping("/hello") // 进入拦截器
public ModelAndView hello()
ModelAndView mv = new ModelAndView();
System.out.println("handler...");
mv.setViewName("/hello.jsp");
return mv;

  • JSP页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>我是JSP页面哦!</h1>
<%
System.out.println("页面渲染!");
%>
</body>
</html>

启动服务器,访问:

​http://localhost:8080/user/register(放行)​

​http://localhost:8080/user/login(拦截)​

​http://localhost:8080/user/hello(拦截)​

​http://localhost:8080/user(拦截)​

14【SpringMVC的拦截器】_springmvc

Tips:我们说的拦截指的是发送的请求会进入SpringMVC的拦截器,具体是否能访问到目标资源要看拦截器是否放行;

1.3.2 SprinMVC拦截器注意事项

1)即使访问的资源不存在,只要符合SpringMVC的拦截器规则,都会进入SpringMVC

  • 如:http://localhost:8080/user/abc 这样的请求也是会经过SpringMVC拦截器的

14【SpringMVC的拦截器】_java_02

Tips:由于请求没有找到对应的资源,因此不会经过拦截器的postHandler方法

2)只要是符合SpringMVC的拦截器规则都会进入SpringMVC,静态资源也不例外!

在webapp目录下新建​​/js/test.js​

14【SpringMVC的拦截器】_拦截器_03

在springmvc.xml中添加配置:

<mvc:interceptor>
<mvc:mapping path="/js/**"/>
</mvc:interceptor>

访问:http://localhost:8080/js/test.js

14【SpringMVC的拦截器】_spring_04

同理,缺省servlet放行方式,资源连SpringMVC都没有进入,更加不会进入SpringMVC的拦截器了;

缺省servlet依赖:

<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.5.41</version>
<scope>provided</scope>
</dependency>
  • 相关配置:
<!--代表以js后缀结尾的任何请求进入Tomcat默认的Servlet处理(放行)-->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>

再次访问:http://localhost:8080/js/test.js,发现资源能够直接访问,并且没有经过SpringMVC拦截器;

1.4 HandlerMethod类

HandlerMethod类是SpringMVC用于封装目标方法的类,可以通过该类获取目标方法的一系列参数,如目标方法对象、目标方法所在的类、目标方法参数、目标方法返回值等;

package com.dfbz.interceptor;

import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Method;

public class MyInterceptor implements HandlerInterceptor
/**
* 请求执行前执行(handle执行前执行)
*
* @param request
* @param response
* @param handler: 要执行的handler(目标方法)
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
System.out.println("preHandle...");

// 转换为Handler对象
HandlerMethod handlerMethod = (HandlerMethod) handler;

// 获取目标方法
Method method = handlerMethod.getMethod();

// 获取Controller
Object bean = handlerMethod.getBean();

// 获取目标方法上的形参
MethodParameter[] methodParameters = handlerMethod.getMethodParameters();

// 获取目标方法的返回值
MethodParameter returnType = handlerMethod.getReturnType();

return true;

访问:http://localhost:8080/user/login

14【SpringMVC的拦截器】_java_05

1.5 多个拦截器的执行顺序

SpringMVC多个拦截器执行流程如下:

14【SpringMVC的拦截器】_servlet_06

编写另一个拦截器:

package com.dfbz.interceptor;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor2 implements HandlerInterceptor
/**
* 请求执行前执行(handle执行前执行)
*
* @param request
* @param response
* @param handler: 要执行的handler(目标方法)
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception

System.out.println("preHandle2...");
return true;


/**
* handle执行后执行
*
* @param request
* @param response
* @param handler :要执行的handler(目标方法)
* @param modelAndView :handler返回的ModelAndView对象,如果目标方法没有返回ModelAndView则为null
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception
System.out.println("postHandle2...");


/**
* 页面渲染后执行
*
* @param request
* @param response
* @param handler :要执行的handler(目标方法)
* @param ex :解析JSP页面出现异常时的异常对象
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception
System.out.println("afterCompletion2...");

添加到SpringMVC中:

<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.dfbz.interceptor.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.dfbz.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>

访问:http://localhost:8080/user/login


以上是关于14SpringMVC的拦截器的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC-- 14 拦截器

SpringMVC-- 14 拦截器

springMVC拦截器简单配置

SpringMVC拦截器

css拦截器,SpringMVC 拦截器(interceptors)对样式(css),JavaScript(js),图片(images)链接的拦截...

SpringMVC配置了拦截器(interceptors)却显示不出cssjs样式的解决办法