首页/新闻资讯/正文详情

filter 和 intercepter(结合苍穹外卖分析)

发布时间:2026/9/24 19:15:08 来源:云帆数科 栏目:资讯中心
filter 和 intercepter(结合苍穹外卖分析)
全局视角浏览器请求 →Filter过滤器Servlet 层→ DispatcherServlet →Interceptor拦截器SpringMVC 层→ Controller返回Controller → Interceptor → Filter → 浏览器Filter:属于 Servlet 规范由 Tomcat 容器创建管理不属于 Spring因为不属于 Spring所以不方便直接使用Autowired 注入 SpringBean以下代码演示了如何创建一个过滤器来拦截所有请求并打印日志import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; WebFilter(/*) // 匹配所有请求注意Spring Boot 内置 Tomcat 还要在启动类加 ServletComponentScan否则这个注解会被忽略、过滤器不生效 public class LoggingFilter implements Filter { Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println(过滤器初始化); } Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println(请求被拦截 - 处理前); chain.doFilter(request, response); // 放行请求刚需不然所有请求都断在这里 System.out.println(响应被拦截 - 处理后); } Override public void destroy() { System.out.println(过滤器销毁); } }Filter 的注解方式通过 WebFilter 注解/*表示匹配所有请求。Filter 匹配/*时所有请求都会进来包括 CSS、js 和静态页面等。Interceptor 会不会被拦到取决于请求路径有没有命中 addPathPatterns命中就会进来静态资源命中了也一样会进来。之所以静态资源没有被拦住是因为 preHandle 里手动放行了if (!(handler instanceof HandlerMethod)) { // 不是 Controller 的方法静态资源的 handler 是 ResourceHttpRequestHandler直接放行 return true; }也就是说不是拦截器不拦静态资源而是代码里判断后把非 Controller 的请求放行了。Interceptor属于 SpringMVC 框架执行位于 DispatcherServlet 之后Controller 之前。会拦截命中 addPathPatterns 的请求静态资源不是自动不拦而是靠上面那行判断放行支持Autowired 注入 Bean在苍穹外卖中使用 Interceptor 进行登录校验操作因为它属于 Spring 组件可以直接注入 JwtProperties 这类配置 Bean。注意JwtUtil 是纯静态工具类方法全是 static不在 Spring 容器里注入不了也不需要注入直接JwtUtil.parseJWT(...)用类名调即可。苍穹外卖中的 Interceptor结合 JWT文件角色sky-server/.../interceptor/JwtTokenAdminInterceptor.java管理端拦截器拦/admin/**sky-server/.../interceptor/JwtTokenUserInterceptor.java用户端拦截器拦/user/**sky-server/.../config/WebMvcConfiguration.java注册两个拦截器 配置放行名单sky-common/.../utils/JwtUtil.java签发 / 解析 JWTsky-common/.../properties/JwtProperties.java读sky.jwt.*配置两套密钥/过期时间/请求头名sky-common/.../constant/JwtClaimsConstant.java载荷 key 常量empId、userIdsky-common/.../context/BaseContext.javaThreadLocalLong在拦截器里存、在 Service 里取sky-server/.../controller/admin/EmployeeController.java管理端登录签发 tokensky-server/.../controller/user/UserController.java用户端微信登录签发 tokensky-server/src/main/resources/application.ymlsky.jwt两套配置JwtTokenAdminInterceptor.java/** * jwt令牌校验的拦截器 */ Component Slf4j public class JwtTokenAdminInterceptor implements HandlerInterceptor { Autowired private JwtProperties jwtProperties; public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判断当前拦截到的是Controller的方法还是其他资源 if (!(handler instanceof HandlerMethod)) { //当前拦截到的不是动态方法直接放行 return true; } //1、从请求头中获取令牌 String token request.getHeader(jwtProperties.getAdminTokenName()); //2、校验令牌 try { log.info(jwt校验:{}, token); Claims claims JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token); Long empId Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString()); log.info(当前员工id, empId); BaseContext.setCurrentId(empId); //3、通过放行 return true; } catch (Exception ex) { //4、不通过响应401状态码 response.setStatus(401); return false; } } }这是 JWT 令牌校验的拦截器上面是管理端拦截器拦/admin/**拿到 token -- 校验 token 中的载荷claims其中包含存储的信息这里是员工 id-- 校验通过拿到 empId -- 放入 BaseContext是自定义 SpringMVC 拦截器专门用来校验管理员端请求的 JWT 令牌。在请求进入 Controller 之前执行校验 token 合法性解析出管理员 id 存入BaseContext校验失败直接拦截请求返回 401。JwtUtil.parseJWT()方法的调用是校验的核心是定义在JwtUtil.java中的public static Claims parseJWT(String secretKey, String token) { // 得到DefaultJwtParser Claims claims Jwts.parser() // 设置签名的秘钥 .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8)) // 设置需要解析的jwt .parseClaimsJws(token).getBody(); return claims; }Jwts.parser()获取 JWT 解析器.setSigningKey()告诉解析器验证签名要用哪个密钥.parseClaimsJws(token)拆分 token 三段使用 secretKey 校验签名校验 exp 过期时间✅ 全部通过返回 Jws 对象调用.getBody()拿到载荷 Claims❌ 任意失败直接抛出异常SignatureException/ExpiredJwtException等拦截器外层的try-catch捕获这个异常返回 401WebMvcConfiguration.java关键代码截取Configuration Slf4j public class WebMvcConfiguration extends WebMvcConfigurationSupport { Autowired private JwtTokenAdminInterceptor jwtTokenAdminInterceptor; Autowired private JwtTokenUserInterceptor jwtTokenUserInterceptor; Override protected void addInterceptors(InterceptorRegistry registry) { log.info(开始注册自定义拦截器...); // 1、管理员端拦截器jwtTokenAdminInterceptor registry.addInterceptor(jwtTokenAdminInterceptor) .addPathPatterns(/admin/**)// 拦截匹配 /admin/** 的所有路径 .excludePathPatterns(/admin/employee/login); // 排除登录接口不拦截 // 2、用户端拦截器jwtTokenUserInterceptor registry.addInterceptor(jwtTokenUserInterceptor) .addPathPatterns(/user/**)// 拦截匹配 /user/** 的所有路径 .excludePathPatterns(/user/user/login)// 排除用户登录接口 .excludePathPatterns(/user/shop/status);// 排除店铺状态查询接口 }单纯是上述的管理端和用户端拦截器的注册JwtUtil.javapublic class JwtUtil { /** * 生成jwt * 使用Hs256算法, 私匙使用固定秘钥 * * param secretKey jwt秘钥 * param ttlMillis jwt过期时间(毫秒) * param claims 设置的信息 * return */ public static String createJWT(String secretKey, long ttlMillis, MapString, Object claims) { // 指定签名的时候使用的签名算法也就是header那部分 SignatureAlgorithm signatureAlgorithm SignatureAlgorithm.HS256; // 生成JWT的时间 long expMillis System.currentTimeMillis() ttlMillis; Date exp new Date(expMillis); // 设置jwt的body JwtBuilder builder Jwts.builder() // 如果有私有声明一定要先设置这个自己创建的私有的声明这个是给builder的claim赋值一旦写在标准的声明赋值之后就是覆盖了那些标准的声明的 .setClaims(claims) // 设置签名使用的签名算法和签名使用的秘钥 .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8)) // 设置过期时间 .setExpiration(exp); return builder.compact(); } /** * Token解密 * * param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个 * param token 加密后的token * return */ public static Claims parseJWT(String secretKey, String token) { // 得到DefaultJwtParser Claims claims Jwts.parser() // 设置签名的秘钥 .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8)) // 设置需要解析的jwt .parseClaimsJws(token).getBody(); return claims; } }JwtUtil 是一个JWT 工具类封装了 JWT 令牌的生成、解析、校验方法专门用来创建 token 和解析 token 中的用户信息在 JWT 拦截器中调用。什么时候该用 Filter 而不是 InterceptorFilter 更底层、更通用跨域处理、字符编码、请求体包装比如 XSS 过滤、Body 重复读、全局访问日志——这些要在进入 Spring MVC 之前做就用 Filter。而要拿到 Controller 方法/注解信息的比如AutoFill、登录校验要知道 handler就用 Interceptor 或 AOP。Intercepter 与 JWT 拦截器校验1第一次请求登录POST /admin/employee/login前端提交账号密码访问登录接口请求进入 Tomcat经过 Filter到达 DispatcherServlet匹配拦截器配置excludePathPatterns(/admin/employee/login)→跳过 JwtTokenAdminInterceptor进入 EmployeeController 的 login 方法Controller 校验账号密码是否正确如果账号密码正确调用JwtUtil.generateToken()生成 JWT 令牌把 JWT 字符串返回给前端前端拿到 token保存在浏览器本地存储localStorage这一步只生成 JWT没有 JWT 校验。还没 token自然不需要校验。2第二次请求登录之后访问业务接口例如 /admin/dish/list前端发请求请求头带上token: JWT字符串这个时候拦截器才会触发 JWT 校验浏览器发起请求GET /admin/dish/listheader 携带 token请求经过 Filter到达 DispatcherServlet匹配拦截器规则/admin/**进入 JwtTokenAdminInterceptor 的 preHandle ()preHandle 里面获取请求头的 token调用JwtUtil.parseJWT(密钥, token)jjwt 底层校验签名、过期时间校验成功取出 empId 放入 BaseContextreturn true 放行进入 DishController校验失败catch 捕获异常设置 401 状态码 return false请求终止不会进到 ControllerController 执行业务可从 BaseContext 拿到当前登录员工 id用于公共字段自动填充 createUser/updateUser请求结束执行拦截器afterCompletion()清理 BaseContext 中的 ThreadLocal

相关推荐

数据清洗实战指南:从脏数据到高质量数据的完整流程与工具选型
数据清洗实战指南:从脏数据到高质量数据的完整流程与工具选型

做数据这行久了,会发现一个特别扎心的现象:很多团队把精力全花在搭建集群、训练模型、做可视化大屏上,结果模型上线效果稀烂,业务方一句"你们的数是不是有问题"就把整个项目打回原形。我见过太多这样的案例,… · 2026/9/24 19:15:02

Spring Boot+Vue慈善捐赠平台实战:从数据库设计到部署避坑全解析
Spring Boot+Vue慈善捐赠平台实战:从数据库设计到部署避坑全解析

做慈善捐赠平台这件事,我一开始其实是有点低估的。接这个项目的时候,客户说“就是个捐赠管理系统,后端管数据,前端管展示”,听着挺简单,真拆开做才发现,它既要处理复杂的角色权限(普… · 2026/9/24 19:15:02

垃圾处理厂建设:CDE与数字孪生的落地实践指南
垃圾处理厂建设:CDE与数字孪生的落地实践指南

1. 从图纸到数据:为什么垃圾处理厂建设需要CDE与数字孪生这几年我在垃圾处理、固废焚烧这类市政基础设施项目上跑了不少现场,最大的感受是:垃圾处理厂的建设难度,一点都不比商业综合体低。它涉及焚烧炉、余热锅炉、烟气净化、渗滤… · 2026/9/24 19:15:02

工业监控界面搭建实战:用2D组态平台快速搞定数据绑定与画面交付
工业监控界面搭建实战:用2D组态平台快速搞定数据绑定与画面交付

接到一个空压站集中监控的项目时,甲方只丢过来一张工艺流程图和一份Excel点位表,交货周期压到一周。第一次接触智捷云2D组态工具,说实话我心里也没底,毕竟之前也经历过从零手写前端做工业监控界面的痛苦——项目拖了两个月&#x… · 2026/9/24 19:54:34

OpenCut开源剪辑工具实测:免费无水印+AI剪片,替代剪映?
OpenCut开源剪辑工具实测:免费无水印+AI剪片,替代剪映?

视频剪辑这件事,过去几年一直被几款商业软件牢牢把持着。想剪个片子,要么忍受导出时硕大的水印,要么就得为几个基础功能掏订阅费。我身边不少做自媒体的朋友,每个月在剪辑工具上的开销加起来够吃好几顿火锅了。直到最近&#xff0… · 2026/9/24 19:54:34

Python实现MinHash海量文本去重:从原理到代码实战
Python实现MinHash海量文本去重:从原理到代码实战

做爬虫采集、新闻聚合或者语料库清洗的朋友,大概率都遇到过同一个问题:抓下来的文本重复率能到30%甚至更高。同一篇新闻被不同网站转载,改个标题、换一下首段、插入几条广告,内容主体几乎一模一样。这个时候拿MD5做精确去重根本没… · 2026/9/24 19:54:34

麒麟V10 ARM部署K8S 1.26.15:外部etcd与containerd实战
麒麟V10 ARM部署K8S 1.26.15:外部etcd与containerd实战

简介:这份资源面向需要在国产化信创环境中落地容器编排的运维与云原生工程师,聚焦Kylin V10操作系统搭配ARM架构服务器、采用外部etcd与containerd运行时部署Kubernetes 1.26.15一主多从集群的完整离线安装包。压缩包共41个文件,约645.74MB&a… · 2026/9/24 19:54:34

Claude Code深度解析:AI编程代理如何重塑终端工作流
Claude Code深度解析:AI编程代理如何重塑终端工作流

1. 先聊清楚:Claude Code 到底是什么,以及它凭什么值得关注我第一次注意到Claude Code这个关键词,是在一个技术社群里。有人贴了一段终端截图,里面是一个交互式命令行界面,AI 在逐行分析和修改代码,评论区全… · 2026/9/24 19:54:34

数据库课程设计入门:从四张空表理解表结构与约束设计
数据库课程设计入门:从四张空表理解表结构与约束设计

刚接手数据库课程设计时,任务书写得很简短:SchoolDB数据库,设计四张表,无数据。说实话,第一次看到“无数据”三个字,很多人是愣住的——不让我填数据,那我交什么?后来我才明白&#… · 2026/9/24 19:54:26

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码