1、拦截器简介
拦截器采用AOP的设计思想, 它跟过滤器类似, 用来拦截处理方法在之前和之后执行一些跟主业务没有关系的一些公共功能,可以实现:权限控制、日志、异常记录、记录方法执行时间.....
SpringMVC提供了拦截器机制,允许运行目标方法之前进行一些拦截工作或者目标方法运行之后进行一下其他相关的处理。自定义的拦截器必须实现HandlerInterceptor接口。
拦截器一个有3个回调方法,而一般的过滤器Filter才两个:
(1)preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
(2)postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
(3)afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于trycatchfinally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器才会执行
顺序:执行拦截器的preHandle方法》执行目标方法》执行拦截器的postHandle方法》执行页面跳转》执行拦截器的afterCompletion方法
在配置拦截器的时候有两个需要注意的点:
1、如果prehandle方法返回值 为false,那么意味着不放行,那么就会造成后续的所有操作都中断
2、如果执行到方法中出现异常,那么后续流程不会处理但是afterCompletion方法会执行
2、自定义拦截器与过滤器
(1)MyInterceptor.java
package cn.qqa.interceptors;
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.util.Arrays;
public class MyInterceptor implements HandlerInterceptor {
/**
* 处理方法之前执行 日志、权限控制、记录调用时间
* @param request 可以再请求处理之前更改requset中的属性值
* @param response
* @param handler 封装了处理方法的相关信息
* @return true代表后续拦截器调用链继续执行 false代表后续拦截器调用链终止执行
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//只有在请求能映射到对应的处理方法时,实现类才是HandlerMethod
//如果是view-controller视图控制器配置的映射,实现类是ParameterizableViewController
//所以不能随便强转
if(handler instanceof HandlerMethod){
HandlerMethod handler1 = (HandlerMethod) handler;
}
System.out.println("----处理方法前执行----preHandle");
/* System.out.println("----类:["+handler1.getBean().getClass().getName()+
"]方法名:["+ handler1.getMethod()+
"]参数名:["+ Arrays.toString(handler1.getMethod().getParameters())+"]");*/
return true;
//return false;
//false :拦截器与过滤器类似,也是一层层的,false就代表到这一层就终止了
}
/**
* 如果preHandle返回false,则不会执行该方法
* 处理方法之后执行,在视图渲染之前执行,当处理方法出现了异常则不会执行方法
* 记录异常的日志不能写在这儿
* @param request
* @param response 可以更改response中的信息
* @param handler
* @param modelAndView 封装了model和view,处理方法结束后可以修改/新增model中的数据,也可以修改view视图
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("----方法后执行,在视图渲染之前----postHandle");
}
/**
* 如果preHandle返回false,则不会执行该方法
* 在视图渲染之后执行 相当于try-catch-finally中的finally,出现异常也会执行该方法
* @param request
* @param response
* @param handler
* @param ex Exception对象,在该方法中做一些记录异常日志的功能或者清除资源(例如需要关闭close的对象)
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("----在视图渲染之后----afterCompletion");
}
}
(2)MyFilter.java
package cn.qqa.Filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("==========过滤器前==========");
filterChain.doFilter(servletRequest,servletResponse );
System.out.println("==========过滤器后==========");
}
@Override
public void destroy() {
}
}
(3)配置自定义拦截器
<mvc:interceptors>
<bean class="cn.qqa.interceptors.MyInterceptor"></bean>
<!--如果不是所有的请求都要拦截,可以加一个<mvc:interceptor>进行配置-->
<mvc:interceptor>
<!--需要拦截的请求-->
<mvc:mapping path="/**"/>
<!--不需要拦截的请求-->
<mvc:exclude-mapping path="/login"/>
<!--拦截器-->
<bean class="cn.qqa.interceptors.CheckLoginInterceptor"></bean>
</mvc:interceptor>
<bean class="cn.qqa.interceptors.InvokeTimeInterceptor"></bean>
</mvc:interceptors>
(4)拦截器与过滤器的区别
1、过滤器是基于函数回调的,而拦截器是基于java反射的
2、过滤器依赖于servlet容器,而拦截器不依赖与Servlet容器,拦截器依赖SpringMVC
3、过滤器几乎对所有的请求都可以起作用,而拦截器只能对SpringMVC请求起作用
4、拦截器可以访问处理方法的上下文,而过滤器不可以
3、使用拦截器实现登录权限拦截
(1)CheckLoginInterceptor.java
package cn.qqa.interceptors;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
*
* 验证用户登录拦截器
*/
@Controller
public class CheckLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
if(StringUtils.isEmpty(session.getAttribute("username"))){
response.sendRedirect(request.getContextPath()+"/login");
return false;
}else{
return true;
}
}
}
(2)配置需要拦截映射以及排除拦截映射spring-mvc.xml
<mvc:interceptors>
<bean class="cn.qqa.interceptors.MyInterceptor"></bean>
<!--如果不是所有的请求都要拦截,可以加一个<mvc:interceptor>进行配置-->
<mvc:interceptor>
<!--需要拦截的请求-->
<mvc:mapping path="/**"/>
<!--不需要拦截的请求-->
<mvc:exclude-mapping path="/login"/>
<!--拦截器-->
<bean class="cn.qqa.interceptors.CheckLoginInterceptor"></bean>
</mvc:interceptor>
<bean class="cn.qqa.interceptors.InvokeTimeInterceptor"></bean>
</mvc:interceptors>
<mvc:view-controller path="/admin" view-name="admin"></mvc:view-controller>
(3)login.jsp
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2021/3/13
Time: 11:06
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录界面</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/login" method="post">
<input type="submit" value="登录">
</form>
</body>
</html>
(4)admin.jsp
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2021/3/13
Time: 9:56
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
管理员后台页面!您好:${username}
</body>
</html>