SpringMVC-- 14 拦截器
Posted Moon&&Dragon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC-- 14 拦截器相关的知识,希望对你有一定的参考价值。
文章目录
17 拦截器
在Servlet阶段学习过过滤器,那么这里的拦截器其实是和Servlet中的过滤器性质差不多,但是底层的实现是完全的不一样。
17.1 SpringMVC的拦截器
拦截器
是SpringMVC框架中的一部分,它天然的在SpringIOC容器中运行着,它的底层其实和SpringAOP一样通过代理模式实现的,是SpringAOP的一个具体实现。而过滤器
是J2EE的标准,是由不同的第三方容器厂商实现的,基于函数回调
作用:
- 日志记录
- 权限认证
- 性能监控
- 用户画像
17.1.1 拦截器和过滤器区别
需要注意的是拦截器是SpringMVC框架中的一部分,而过滤器是服务器中的,一个请求最先到达就是过滤器,然后就进入了SpringMVC的请求分发处理中心,在进行处理控制器前调用了前置方法,这就是属于拦截器的方法。
17.1.2 单个拦截器流程
在单个拦截器中,其实是有三个方法的,他们分别在不同的时间执行
拦截器方法 | 说明 | 执行时间 |
---|---|---|
preHandle | 这个方法是拦截器中使用比较多,是前置拦截器,该拦截方法在执行在控制器之前,可以对整个的访问进行处理,如果返回false,则不会去继续寻找handler,直接返回空白。 | 控制器之前 |
postHandle | 这个方法是属于后置拦截器,该方法无法对访问进行处理,不管如何都会继续。 | 在控制器之后,目标资源已经被SpringMVC框架处理,也就是在HandlerAdapter之后,但是在渲染页面之前 |
afterCompletion | 这个方法也是属于后置拦截器,和上面的方法一样,但是执行的时间不一样 | 在渲染页面之后(或者没有页面就是在json字符串被Jackson处理完之后) |
流程图:
17.1.3 多个拦截器流程
如果我们去使用多个拦截器的话,那么多个拦截器之间的流程也是有有规律的,那么拦截器的执行顺序就是我们配置注册的顺序。
步骤:
- 执行拦截器1的前置方法
- 执行拦截器2的前置方法
- 执行控制层
- 处理后执行拦截器2的后置方法
- 处理后执行拦截器1的后置方法
- 渲染后执行拦截器2的后置完成方法
- 渲染后执行拦截器1的后置完成方法
执行顺序:1–>2–>2–>1–>2–>1
流程图:
17.2 实现拦截器类
我们如果想要使用SpringMVC中拦截器,我们只需要新建一个类,然后去实现Spring为我们提供的接口即可,我们需要去实现HandlerInterceptor接口
Tips:
- 我们实现完该接口后,可以选择实现全部三个方法,也可以选择实现其中一个,或者不实现,也没啥意义了
public class MyInterceptor implements HandlerInterceptor
/**
* 前置处理器,拦截的是请求
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
// 在这里我们可以操作请求和响应,不过现在响应啥也没有
System.out.println("用户访问的uri:"+request.getRequestURI());
System.out.println("用户的上网环境:"+request.getHeader("User-Agent"));
System.out.println("用户的IP:"+request.getRemoteHost());
// 这里如果返回了false,那么拦截到的请求不会继续往下执行,直接返回空白
return true;
/**
* 在目标资源已经被SpringMVC框架处理之后(在HandlerAdapter之后,在渲染前)
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
// 在这里也可以操作请求和响应,而且还可以操作控制器返回的ModelAndView对象
System.out.println(request.getRequestURI()+"被POST拦截了");
/**
* 在渲染完视图层后,产生响应文本之后(渲染页面之后或者json数据被Jackson处理之后)
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
// 这里的拦截方法已经执行完了渲染
System.out.println(request.getRequestURI()+"被after拦截了");
17.3 配置拦截器
在SpringMVC中配置拦截器,我们同样可以使用俩种方式进行配置
Tips:
- 过滤器的配置我们是在
web.xml
或者Java初始化类
,而拦截器的配置我们是在SpringMCV的配置文件
或者SpringMVC配置类
17.3.1 基于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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.moon"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<!--配置mvc拦截器-->
<!--配置多个拦截器标签-->
<mvc:interceptors>
<!--配置单个拦截器-->
<mvc:interceptor>
<!--拦截所有-->
<mvc:mapping path="/**"/>
<!--使用内部bean的方式声明我们写的拦截器-->
<bean class="com.moon.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
17.3.2 基于JavaConfig
@EnableWebMvc
@Configurable
@ComponentScan("com.moon")
public class WebMvcConfig implements WebMvcConfigurer
/**
* 处理静态资源
* @param configurer 配置
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer)
configurer.enable();
/**
* 添加拦截器
* @param registry 配置
*/
@Override
public void addInterceptors(InterceptorRegistry registry)
// 添加一个拦截器,拦截全部的请求,如果添加做个,继续在registry中添加
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
17.4 资源过滤问题
在上面的配置中,我们拦截了所有的请求,那么js这些静态文件也是会被拦截的。这时候我们可能会想,上面不是配置静态资源处理了吗,怎么还会拦截,答案是会的
为什么会出现静态资源的拦截:
- 在我们前面配置的静态资源放行,只是在DispatcherServlet寻找执行链时生效的
- 而我们的拦截器是在我们执行链已经找到,准备执行执行链的时候,所以之前的静态资源放行是无效的
解决方案:
- 这种请求显然Spring也是会想到的,在我们配置拦截器的时候,Spring为我们提供了不包括的资源方法
Tips:
- 在配置拦截放行时,我们可以使用通配符来放行对应的后缀的文件,比如==*.js==
- 如果有多个后缀的文件,那也不是很方便,所以我们一般选择放行对应文件夹下的所有,比如static/**
XML配置:
<mvc:interceptors>
<mvc:interceptor>
<!--拦截所有-->
<mvc:mapping path="/**"/>
<!--去除不需要拦截的url-->
<!--放行js-->
<mvc:exclude-mapping path="/**.js"/>
<!--放行css-->
<mvc:exclude-mapping path="/**.css"/>
<!--放行图标-->
<mvc:exclude-mapping path="/**.ico"/>
<!--放行static下的全部文件-->
<mvc:exclude-mapping path="/static/**"/>
<bean class="com.moon.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
Java类配置:
@Override
public void addInterceptors(InterceptorRegistry registry)
// 资源放行文件集合
ArrayList<String> list = new ArrayList<>();
list.add("/**.js");
list.add("/**.css");
list.add("/**.jpg");
// 资源放行
registry.addInterceptor(new FirstInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/static/**")
.excludePathPatterns(list);
以上是关于SpringMVC-- 14 拦截器的主要内容,如果未能解决你的问题,请参考以下文章
学习笔记——SpringMVC拦截器的两种装配方式;SpringMVC拦截器工作原理;SpringMVC中的异常处理器;SpringMVC工作原理