拦截器 【编程|拦截器和过滤器】对action请求起作用,动态拦截action调用的对象。主要是拦截客户请求并作出相应的处理。
实现原理
基于Java反射机制(动态代理)来实现的。
不依赖servlet容器
触发时机:请求进入servlet后,在进入Controller之前
文章图片
拦截器的方法
方法名 |
说明 |
preHandle() |
此方法将在请求处理之前调用,返回值是Boolean类型。如果返回false,标识请求结束,之后的拦截器和controller都不会执行;如果返回true,则会继续调用下一个拦截器的preHandle()方法。 |
postHandle() |
该方法是在请求处理之后被调用,前提是preHandle()方法的返回值全部为true才能被调用,并且会在Dispatcher Servlet进行视图返回 渲染之前被调用,所以可以在这个方法中对controller处理之后的ModelAndView对象进行操作。 |
afterCompletion() |
该方法是在整个请求结束之后,即在Dispatcher Servlet渲染了对应的视图之后执行,前提是preHandle()方法的返回值全部为true才能被调用。 |
文章图片
1.根据当前请求,找到HandlerExecutionChain执行链,执行链可以处理当前请求的handler方法以及handler方法的所有拦截器;
2.按顺序执行所有拦截器的preHandle方法;
(1)如果当前拦截器preHandle返回为true,说明放行,则执行下一个拦截器的preHandle方法(2)如果当前拦截器preHandle返回为false,说明不放行,则倒序执行所有已经执行了的拦截器的afterCompletion方法(不执行当前返回false拦截器的afterCompletion方法);
3.所有拦截器都返回true才会执行目标方法;
4.倒序执行所有拦截器的postHandle方法;
5.之前的所有步骤如果有任何异常就不会继续向下执行,但都会直接倒序触发afterCompletion;
6.如何没有任何异常,页面成功渲染完成以后,也会倒序触发afterCompletion方法。
使用拦截器(多个拦截器)
1.创建拦截器类实现HandlerInterceptor接口
(两个拦截器)
public class OneInterceptor implements HandlerInterceptor {// 处理请求之前执行,controller处理之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
String url =String.valueOf(request.getRequestURL()) ;
System.out.println("1、url=="+url);
// 放开拦截
return true;
}// 处理请求之后执行,(controller处理之后,DispatcherServlet进行视图渲染之前)
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) {
System.out.println("1、postHandle");
}// 响应之后执行(DispatcherServlet进行视图渲染之后,返回前端)
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, Exception e) {
System.out.println("1、afterCompletion");
}
}
public class TwoInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object o) throws Exception {
String url =String.valueOf(request.getRequestURL()) ;
System.out.println("2、url=="+url);
// 放开拦截
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
System.out.println("2、postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
System.out.println("2、afterCompletion");
}
}
2.注入拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有路径
// 注册自定义两个拦截器
registry.addInterceptor(new OneInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new TwoInterceptor()).addPathPatterns("/**");
}}
3.测试,访问路径
@RequestMapping("/reqUrl")
public void reqUrl () {
System.out.println("目标方法执行....");
}
文章图片
Filter过滤器 实现原理
基于函数回调
依赖servlet容器,在进入tomcat容器之后,进入servlet之前执行
方法
init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。
doFilter() :容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。
destroy(): 当容器销毁过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {System.out.println("Filter 前置");
}@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("Filter 处理中");
filterChain.doFilter(servletRequest, servletResponse);
}@Override
public void destroy() {System.out.println("Filter 后置");
}
}
使用
Filter流程图:
用户登录
文章图片
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
Object user = session.getAttribute("user");
// 如果 user = null;
说明 user 还没有登陆
if (user == null) {
httpServletRequest.getRequestDispatcher("/xxxx").forward(httpServletRequest,servletResponse);
return;
} else {
// 让程序继续往下访问用户的目标资源
filterChain.doFilter(servletRequest,servletResponse);
}
}
FilterChain过滤器链
执行流程:
文章图片
多个Filter执行顺序
1.在web.xml中,filter执行顺序跟
2.使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
3.如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter