博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring MVC拦截器
阅读量:4090 次
发布时间:2019-05-25

本文共 4006 字,大约阅读时间需要 13 分钟。

拦截器 由发表在

框架中的Interceptor,与Servlet API中的Filter十分类似,用于对Web请求进行预处理/后处理。通常情况下这些预处理/后处理逻辑是通用的,可以被应用于所有或多个Web请求,例如:

  • 记录Web请求相关日志,可以用于做一些信息监控、统计、分析
  • 检查Web请求访问权限,例如发现用户没有登录后,重定向到登录页面
  • 打开/关闭数据库连接——预处理时打开,后处理关闭,可以避免在所有业务方法中都编写类似代码,也不会忘记关闭数据库连接

Spring MVC请求处理流程

上图是Spring MVC框架处理Web请求的基本流程,请求会经过DispatcherServlet的分发后,会按顺序经过一系列的Interceptor并执行其中的预处理方法,在请求返回时同样会执行其中的后处理方法。

HandlerInterceptor接口

中拦截器是实现了HandlerInterceptor接口的Bean:

public interface HandlerInterceptor {    boolean preHandle(HttpServletRequest request,                       HttpServletResponse response,                       Object handler) throws Exception;    void postHandle(HttpServletRequest request,                     HttpServletResponse response,                     Object handler, ModelAndView modelAndView) throws Exception;    void afterCompletion(HttpServletRequest request,                          HttpServletResponse response,                          Object handler, Exception ex) throws Exception;}
  • preHandle():预处理回调方法,若方法返回值为true,请求继续(调用下一个拦截器或处理器方法);若方法返回值为false,请求处理流程中断,不会继续调用其他的拦截器或处理器方法,此时需要通过response产生响应;
  • postHandle():后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时可以通过modelAndView对模型数据进行处理或对视图进行处理
  • afterCompletion():整个请求处理完毕回调方法,即在视图渲染完毕时调用

HandlerInterceptor有三个方法需要实现,但大部分时候可能只需要实现其中的一个方法,HandlerInterceptorAdapter是一个实现了HandlerInterceptor的抽象类,它的三个实现方法都为空实现(或者返回true),继承该抽象类后可以仅仅实现其中的一个方法:

public class Interceptor extends HandlerInterceptorAdapter {    public boolean preHandle(HttpServletRequest request,                             HttpServletResponse response,                             Object handler) throws Exception {        System.out.println("This is interceptor.");        return true;    }}

配置Interceptor

定义HandlerInterceptor后,需要在MVC配置中将它们应用于特定的URL中,下面是一个配置的例子:

@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurerAdapter {    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new LocaleInterceptor());        registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");    }}

对应的XML配置是:

实例:用户登录检查

根据前面几个小节的学习,现在需要实现用户登录检查——如果发现用户没有登录,跳转到登录页面,登录成功后跳转回之前访问的页面。

Interceptor实现检查逻辑

public class LoginInterceptor extends HandlerInterceptorAdapter {    @Override    public boolean preHandle(HttpServletRequest request,                             HttpServletResponse response,                             Object handler) throws Exception {        if (request.getSession().getAttribute(Constants.USER_SESSION_ATTR) != null) {            return true;        }        response.sendRedirect("/login?next=".concat(request.getRequestURI()));        return false;    }}

为了实现跳转登录页面登录成功后能够返回当前页面,在Interceptor中将当前URL作为/login的参数next

LoginController

@Controller@RequestMapping("/login")public class LoginController {    public static final Logger logger = LoggerFactory.getLogger(LoginController.class);    @RequestMapping(method = RequestMethod.GET)    public String loginPage(@RequestParam("next") Optional
next) { logger.info("next = {}", next); return "login"; } @RequestMapping(method = RequestMethod.POST) public String login(@RequestParam("next") Optional
next, HttpSession session) { logger.info("next = {}", next); session.setAttribute(Constants.USER_SESSION_ATTR, "username"); return "redirect:".concat(next.orElse("/")); }}

在登录的POST方法中,除了将Session中放入user对象外,跳转到next以便回到登录前的页面。

配置Interceptor

需要注意的是,登录页面本身(包括POST请求)不能应用Interceptor来拦截,否则会陷入无限循环中:

@Configurationpublic class WebMvcConfig extends WebMvcConfigurerAdapter {    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new LoginInterceptor())                .addPathPatterns("/**")                .excludePathPatterns("/login");    }}

更多文章请访问

你可能感兴趣的文章
前端开发必知:组件封装的原则
查看>>
微信小程序采坑记录:http:XXX 不在以下request合法域名列表中的解决方法
查看>>
js数组去重小结
查看>>
javascript defer与async 的差异
查看>>
flex实现等宽布局且间隔相等的小技巧
查看>>
JS冷知识:label 语句记录循环语句中断的值
查看>>
软件架构必知-康威定律
查看>>
JS基础夯实——垃圾回收机制
查看>>
js基础夯实——基本类型与引用类型
查看>>
ubuntu19 安装python虚拟环境
查看>>
我的ubuntu19.04在执行一次全面升级后,导致不能进入桌面
查看>>
我在ubuntu19.01中 使用pip3安装 pgadmin4
查看>>
我在unbutu19.01中使用阿里云的容器服务搭建fusionpbx
查看>>
我在ubuntu19.01中安装docker-composer
查看>>
我在ubuntu19.01中,使用docker-compose启动docker
查看>>
fusionpbx在換了服务器主机后,或换了ip地址后,必须改的设置
查看>>
使用python-ESL开发呼叫系统
查看>>
我在djiango的单页文件中,使用邮件发送接口与功能
查看>>
在vue页面中,使用audio标签 播放音频和视频
查看>>
我的后台规范
查看>>