自定义拦截器实现

简介: 自定义拦截器实现

在 Spring MVC 框架中, 拦截器作为一种机制, 用于对请求进行拦截. 拦截器可以在请求进入处理器之前、处理器返回处理之后、视图渲染之前等各个环节进行拦截.

拦截器通常用于实现一下功能 :


  • 鉴权和身份认证
  • 日志记录和统计
  • 请求参数和校验和过滤
  • 缓存和性能优化
  • 路径重定向和错误处理


也就是说, 当需要对多个请求进行相同或者类似处理时, 可以使用拦截器来统一处理, 从而避免冗余的代码和低效的维护.


一. 自定义拦截器实现



1. 创建一个 Spring Boot 项目, 添加 Spring Web、 Lombok 起步依赖.


正常创建一个 Spring Boot 的 Maven 项目即可.


2. 创建一个公共包 common 实现登录拦截器类


在 Spring MVC 中, 拦截器是通过实现 HandlerInterceptor 接口实现的.

在实现 HandlerInterceptor 接口时, 重写里面的拦截器方法.


3ba764edad47ceb91fa7adc97a3f782b.png


a. preHandle


该方法用于在请求处理之前进行拦截和处理. 该方法在 DispatcherServlet ( 调度器 ) 将请求对象封装为 HandlerExecutionChain 对象后、但在调用处理器( Controller ) 之前被调用在 preHandle 方法中, 我们可以对请求进行检查、验证、修改等操作, 例如 :

  • 身份认证和权限控制
  • 请求参数校验和过滤
  • 缓存和性能优化


b. postHandle


该方法用于在请求处理完成之后, 试图渲染之前进行拦截和处理. 该方法在 HandlerAdapter 将处理器执行并将其结果返回给 DispatcherServlet 之后调用.在 postHandle 方法中, 我们可以做一些与请求处理有关的操作, 例如 :

  • 修改 Model 数据
  • 添加一些公共的 Model 属性
  • 对视图进行渲染前的处理


c. afterCompletion


该方法用于请求处理完毕后进行回收和清理工作, 该方法在视图渲染完毕之后被调用, 用于释放资源和进行日志记录等操作在 afterCompletion 方法中, 我们可以进行一些与请求处理过程相关的清理工作, 例如 :

  • 清理 ThreadLocal 变量
  • 关闭打开的文件或数据库连接
  • 记录请求处理时间和结果


3. 重写方法


由于我们是一个登陆拦截器, 可以想象在各个功能使用之前就需要进行权限的鉴定和登陆的检验. 因此应该重写 preHandle 方法, 在请求处理之前进行拦截和处理

@Component
    public class LoginInterceptor implements HandlerInterceptor {
        /**
* 拦截器为调用方法执行之前执行的方法
*
* @param request  请求
* @param response 响应
* @param handler  表示要执行的处理器, 即处理请求的 Controller 对象或者是拦截器的对象
* @return true 拦截器验证成功, 继续执行后续操作
* false 拦截器验证失败, 验证未通过后续流程不执行
* @throws Exception 异常
*/
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 用户登录判断
            HttpSession session = request.getSession(false);
            if (session != null && session.getAttribute("session_userinfo") != null) {
                // 该用户已经登陆
                return true;
            }
            // 请求无权限, 返回状态码提示
            response.setStatus(401);
            return false;
        }
    }


4. 添加拦截器配置


有了拦截器, 但还没有实现拦截规则, 并且这个拦截的规则是要随着 Web 项目的启动而启动的, 否则在进行页面访问时, 就无法提前拦截了. 因此还需要将自定义的拦截器添加到我们的系统配置当中.而在 Spring MVC 中提供了一个 WebMvcConfigurer 接口, 因为我们配置的是拦截器, 因此重写里面的 addInterceptors 方法即可.

image.png


在重写的方法中, 将我们实现的登陆拦截器添加进去, 然后配置拦截的规则即可

@Configuration
    public class MyInterceptorConfig implements WebMvcConfigurer {
        // 将自定义的拦截器注入
        @Autowired
        private LoginInterceptor interceptor;
        /**
* @param registry 注册对象
*/
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 注册对象将拦截器添加进框架中
            registry.addInterceptor(interceptor)
                // 配置拦截规则
                .addPathPatterns("/**") // 拦截所有的 url
                .excludePathPatterns("/user/reg") // 排除用户注册 url
                .excludePathPatterns("/user/login") // 排除用户登陆 url
                .excludePathPatterns("/image/**"); // 排除 image 文件夹底下的所有文件
        }
    }


一般对于拦截规则的设置, 我们都是先拦截所有, 然后放行部分. 并且里面的路径写法和我们之前学习的相同.


5. 验证拦截器


当写好拦截器后, 我们创建一个用户操作类

@RestController
    @RequestMapping("/user")
    public class UserController {
        @RequestMapping("/reg")
        public String register() {
            return "注册成功";
        }
        @RequestMapping("/login")
        public String login() {
            return "登陆成功";
        }
        @RequestMapping("article")
        public String writer() {
            return "写文章鉴权";
        }
    }


根据我们的拦截规则, 我们排除了 url 为 /user/reg 和 user/login 以及 image 文件底下的所有文件. 因此这三个都是可以访问的, 其他的 ulr 都是不可以访问的, 也就是我们上面写的 /user/article 是无法访问的, 会被拦截并返回 401


可以看到, 我们放行的方法都能够正确经过拦截器的处理

9206dc285059eb2c037e5b546e642515.png

064a7f3ebdcf2be0042a50382bfce96a.png

而我们的 /user/article 被拦截器拦截在外无法执行

e567fb21e305d12cad15e3d96cf2eefd.png


6. 调整返回错误信息


对于我们刚刚的做法中, 当被拦截以后, 说明这个方法是不符合要求的请求, 直接返回了 401 拒绝访问, 但在开发中, 无论是否被拦截, 都应该将信息返回给前端, 而并非返回页面而是要一个数据, 前端根据我们返回的数据进行判断后再执行下一步操作.


因此, 我们可以封装一个统一的返回对象 ResultAjax

即使后端拦截了这个方法, 它没有进行登录, 我们也不能帮前端进行重定向让给用户去登录, 这是要越权行为. 我们只需要返回约定的错误代码 code 告诉前端, 并把错误信息返回给前端即可.

@Data
    public class ResultAjax {
        private int code;
        private String msg;
        private String date;
    }


当被拦截时, 说明为经过登陆鉴权, 返回约定的对象即可

@Component
    public class LoginInterceptor implements HandlerInterceptor {
        /**
* 拦截器为调用方法执行之前执行的方法
*
* @param request  请求
* @param response 响应
* @param handler  表示要执行的处理器对象, 即处理请求的 Controller 对象或者是拦截器的对象
* @return true 拦截器验证成功, 继续执行后续操作
* false 拦截器验证失败, 验证未通过后续流程不执行
* @throws Exception 异常
*/
        @Autowired
        private ResultAjax resultAjax;
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 用户登录判断
            HttpSession session = request.getSession(false);
            if (session != null && session.getAttribute("session_userinfo") != null) {
                // 该用户已经登陆
                return true;
            }
            ObjectMapper objectMapper = new ObjectMapper();
            // 设置数据返回格式, 防止乱码解析
            response.setContentType("application/json; charset = utf8");
            // 当前方法未通过登陆鉴权, 返回约定的结果
            resultAjax.setCode(-1); // 约定错误都为 -1 状态码, 成功都为 200
            resultAjax.setMsg("用户未登录, 请登录后再操作 !");
            resultAjax.setDate(""); // 为登陆没有数据返回
            // 将返回的数据对象转为 JSON 格式字符串
            String respJson = objectMapper.writeValueAsString(resultAjax);
            // 返回统一的处理对象给前端
            response.getWriter().write(respJson);
            return false;
        }
    }


1aa52b2316220a1655d3d722cb52589c.png


这是一般我们的处理情况, 最好的还是进行一个统一的格式的错误信息返回. 关于统一的数据处理和错误处理, 在后续文章中会讲解到.

相关文章
|
API Python Windows
python2.7 win32com 避坑指南
python2.7 win32com 避坑指南
1042 0
|
NoSQL 数据可视化 JavaScript
漂亮又好用的Redis可视化客户端汇总
漂亮又好用的Redis可视化客户端汇总
9961 0
漂亮又好用的Redis可视化客户端汇总
|
资源调度 监控 JavaScript
3倍+提升,高德地图极致性能优化之路
伴随着高德地图APP近几年的高速发展,也面临到这些问题,从2019年开始,我们开启了一系列性能优化专项,对高德地图APP进行了深入性能分析和极致优化,取得比较显著的效果。在这个过程中总结了一系列优化思路和技术方案,希望对同样面临超级应用性能问题的你有所帮助。
|
存储 JSON 运维
直击痛点,详解 K8s 日志采集最佳实践
在 Kubernetes 中,日志采集和普通虚拟机的方式有很大不同,相对实现难度和部署代价也略大,但若使用恰当则比传统方式自动化程度更高、运维代价更低。
直击痛点,详解 K8s 日志采集最佳实践
|
XML Java 数据库连接
MyBatis入门——MyBatis XML配置文件(3)
MyBatis入门——MyBatis XML配置文件(3)
644 6
|
域名解析 算法 安全
免费申请https加密全攻略
访问JoySSL官网注册账号,申请免费SSL证书。选择证书类型,填写域名信息,生成CSR文件,验证域名所有权。下载并部署证书至服务器,测试HTTPS连接。注意定期续期,确保兼容性和安全性。如有问题,可联系JoySSL客服。
|
TensorFlow 算法框架/工具 iOS开发
手把手教你-MAC虚拟环境搭建TensorFlow开发环境
手把手教你-MAC虚拟环境搭建TensorFlow开发环境
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
474 1
|
存储
二维数组在物理上以及逻辑上的数组维度理解
C 语言中,二维数组在物理上按行优先连续存储,可视为一维数组的数组;逻辑上呈现行和列的结构,支持通过双下标访问元素,适用于矩阵和表格等数据结构的表示与操作。
GitHub爆赞的Web安全防护指南,网络安全零基础入门必备教程!
web安全现在占据了企业信息安全的很大一部分比重,每个企业都有对外发布的很多业务系统,如何保障web业务安全也是一项信息安全的重要内容。 然而Web 安全是一个实践性很强的领域,需要通过大量的练习来建立对漏洞的直观认识,并积累解决问题的经验。 Web安全与防护技术是当前安全界关注的热点,今天给小伙伴们分享的这份手册尝试针对各类漏洞的攻防技术进行体系化整理,从漏洞的原理到整体攻防技术演进过程进行详细讲解,从而形成对漏洞和web安全的体系化的认识。