拦截器模式
目录
背景
拦截器模式是一种行为设计模式,允许在不修改原有对象的情况下,在其前后插入额外的逻辑。Filter 在 Servlet 中的应用正是这一模式的典型体现:
前置处理:在请求到达目标资源(如 Servlet、JSP)之前,对请求进行预处理(如字符编码、权限校验)。
后置处理:在响应返回客户端之前,对响应进行加工(如压缩、日志记录)。
Servlet Filter 使用的设计模式:拦截器模式(Interceptor Pattern)
1. 拦截器模式的核心思想
拦截器模式是一种行为设计模式,允许在不修改原有对象的情况下,在其前后插入额外的逻辑。Filter 在 Servlet 中的应用正是这一模式的典型体现:
- 前置处理:在请求到达目标资源(如 Servlet、JSP)之前,对请求进行预处理(如字符编码、权限校验)。
- 后置处理:在响应返回客户端之前,对响应进行加工(如压缩、日志记录)。
2. Filter 的典型应用场景
(1) 全局字符编码过滤
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
req.setCharacterEncoding("UTF-8");
res.setCharacterEncoding("UTF-8");
chain.doFilter(req, res);
}
}
(2) 登录校验过滤
@WebFilter("/secure/*")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (request.getSession().getAttribute("user") == null) {
response.sendRedirect(request.getContextPath() + "/login");
} else {
chain.doFilter(req, res);
}
}
}
(3) 日志记录过滤
@WebFilter("/*")
public class LogFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(LogFilter.class);
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
String uri = ((HttpServletRequest) req).getRequestURI();
logger.info("Request: {} - {}", LocalDateTime.now(), uri);
chain.doFilter(req, res);
logger.info("Response: {} - {}", LocalDateTime.now(), uri);
}
}
3. 用好 Filter 的最佳实践
(1) 单一职责原则
- 每个 Filter 专注一个功能(如编码、鉴权、日志),避免功能混杂。
- 示例:拆分
EncodingFilter
和SecurityFilter
。
(2) 控制执行顺序
- 通过
@WebFilter
的order
属性或 web.xml 的<filter-mapping>
顺序定义优先级。 - 关键场景:字符编码过滤器应放在最前端。
(3) 异步支持
- 对耗时操作(如数据库查询)使用
AsyncContext
,避免阻塞主线程:
chain.doFilter(req, res); // 同步调用
// 或
AsyncContext asyncContext = req.startAsync();
asyncContext.start(() -> {
// 异步处理逻辑
});
(4) 资源管理
- 在
init()
中加载配置,在destroy()
中释放资源(如数据库连接池):
@Override
public void init(FilterConfig config) throws ServletException {
// 初始化配置
}
@Override
public void destroy() {
// 释放资源
}
(5) 异常处理
- 捕获 Filter 链中的异常并统一处理:
try {
chain.doFilter(req, res);
} catch (Exception e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error occurred");
}
4. 进阶技巧
(1) 动态过滤路径
- 通过注解参数动态匹配路径:
@WebFilter(urlPatterns = {"${config.loginPath}"})
public class DynamicFilter implements Filter { /* ... */ }
(2) CORS 处理
@WebFilter("/*")
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
chain.doFilter(req, res);
}
}
(3) 请求/响应修改
- 修改请求参数(需谨慎):
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(req) {
@Override
public String getParameter(String name) {
return super.getParameter(name).toUpperCase();
}
};
chain.doFilter(requestWrapper, res);
5. 注意事项
- 性能影响:避免在 Filter 中进行 IO 操作或复杂计算。
- 安全风险:敏感操作(如密码验证)应在 Filter 之后由业务层处理。
- 依赖注入:可通过
@Inject
注入 Spring Bean(需启用@WebFilter
+@Component
)。
通过合理设计 Filter 链,可以显著提升代码的可维护性和扩展性,同时保持核心业务逻辑的简洁性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!