springboot-MVC 过滤器使用
一、前言
一下代码以SSO用户登录列子代码。完整代码https://gitee.com/xuxueli0323/xxl-sso
二、使用
2.1 创建过滤器
创建一个过滤器,实现Filter 接口
public class XxlSsoTokenFilter extends HttpServlet implements Filter {
private static Logger logger = LoggerFactory.getLogger(XxlSsoTokenFilter.class); private static final AntPathMatcher antPathMatcher = new AntPathMatcher(); private String ssoServer;
private String logoutPath;
private String excludedPaths; @Override
public void init(FilterConfig filterConfig) throws ServletException { ssoServer = filterConfig.getInitParameter(Conf.SSO_SERVER);
logoutPath = filterConfig.getInitParameter(Conf.SSO_LOGOUT_PATH);
excludedPaths = filterConfig.getInitParameter(Conf.SSO_EXCLUDED_PATHS); logger.info("XxlSsoTokenFilter init.");
} @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response; // make url
String servletPath = req.getServletPath(); // excluded path check
if (excludedPaths!=null && excludedPaths.trim().length()>0) {
for (String excludedPath:excludedPaths.split(",")) {
String uriPattern = excludedPath.trim(); // 支持ANT表达式
if (antPathMatcher.match(uriPattern, servletPath)) {
// excluded path, allow
chain.doFilter(request, response);
return;
} }
} // logout filter
if (logoutPath!=null
&& logoutPath.trim().length()>0
&& logoutPath.equals(servletPath)) { // logout
SsoTokenLoginHelper.logout(req); // response
res.setStatus(HttpServletResponse.SC_OK);
res.setContentType("application/json;charset=UTF-8");
res.getWriter().println("{\"code\":"+ReturnT.SUCCESS_CODE+", \"msg\":\"\"}"); return;
} // login filter
XxlSsoUser xxlUser = SsoTokenLoginHelper.loginCheck(req);
if (xxlUser == null) { // response
res.setStatus(HttpServletResponse.SC_OK);
res.setContentType("application/json;charset=UTF-8");
res.getWriter().println("{\"code\":"+Conf.SSO_LOGIN_FAIL_RESULT.getCode()+", \"msg\":\""+ Conf.SSO_LOGIN_FAIL_RESULT.getMsg() +"\"}");
return;
} // ser sso user
request.setAttribute(Conf.SSO_USER, xxlUser); // already login, allow
chain.doFilter(request, response);
return;
} }
2.2 注册filter
使用java 配置 @Configuration 注解配置 ,通过FilterRegistrationBean ,向spring容器中注入 过滤器。
@Configuration
public class XxlSsoConfig implements DisposableBean { @Value("${xxl.sso.server}")
private String xxlSsoServer; @Value("${xxl.sso.logout.path}")
private String xxlSsoLogoutPath; @Value("${xxl.sso.redis.address}")
private String xxlSsoRedisAddress; @Value("${xxl-sso.excluded.paths}")
private String xxlSsoExcludedPaths; @Bean
public FilterRegistrationBean xxlSsoFilterRegistration() { // xxl-sso, redis init
JedisUtil.init(xxlSsoRedisAddress); // xxl-sso, filter init
FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setName("XxlSsoWebFilter");
registration.setOrder(1);
registration.addUrlPatterns("/*");
registration.setFilter(new XxlSsoTokenFilter());
registration.addInitParameter(Conf.SSO_SERVER, xxlSsoServer);
registration.addInitParameter(Conf.SSO_LOGOUT_PATH, xxlSsoLogoutPath);
registration.addInitParameter(Conf.SSO_EXCLUDED_PATHS, xxlSsoExcludedPaths); return registration;
} @Override
public void destroy() throws Exception { // xxl-sso, redis close
JedisUtil.close();
} }
三、执行流程
以springboot 为列子,看filter 是如何工作的
3.1 bean的注入
因为filter 以 FilterRegistrationBean 的形式 注入到spring 的容器,首先来看看这个类的结构 ,可以看到这个类实现 ServletContextInitializer 接口
3.2 断点跟踪
在FilterRegistrationBean 类中有个方法getFilter 获取的过滤器,在这里打个断点,看看spring在什么时候会来获取过滤器。
启动容器,进入断点 ,观察栈信息,可以看到是在创建spring容器后创建tomcat 服务进入的断点
然后拿到所有接口实现,调用
看下 FilterRegistrationBean 调用 onStartup 把filter获取注册到servletContext 容器中
最后 封装成 FilterMap放进org.apache.catalina.core.StandardContext#filterMaps
3.3 前端断点
在过滤器中打上断点,前端发起请求,进入断点
找到 ApplicationFilterChain 看到过滤器在 org.apache.catalina.core.ApplicationFilterChain#filters 中 ,分析发现添加过滤器的方法 ,在此方法设置断点,前端再次发请求
过滤器链创建完了之后 会调用 过滤器链,用里面的过滤器循环过滤
最新文章
- 记一次SQLServer的分页优化兼谈谈使用Row_Number()分页存在的问题
- Objective-C_基本数据类型详解
- Whole life
- OpenCV学习笔记——OpenCV安装
- 看stackoverflow大牛如何回答何时在ASP.NET中使用异步控制器?
- VPS拨号主机自动拨号脚本(centos7)
- Workaround for Markdown blogging platform that to use LaTeX
- Different ways to invoke a shared object/share library(.so)
- 解决nginx负载均衡的session共享问题
- curl要注意的几点
- ACCESS-关于DELPHI中操作ACCESS数据库中单精度数据的问题
- 又一家自适应学习平台上线,大讲台主攻IT在线教育
- HDU 4604 Deque 二分最长上升子序列
- [转载]起动service保存android系统log( logcat服务)
- PL/SQL程序中调用Java代码(转)
- Keil C 里面Lib库文件的生成与调用
- mysql主键,外键,索引
- PHP之cookies小练习
- 把旧系统迁移到.Net Core 2.0 日记 (20) --使用MiniProfiler for .NET
- jq 绑定事件和解绑事件