SpringBoot中应用Web Filter

最近要给自己的项目里面加个filter,结果折腾了好几天终于弄好了,记录一下。

web的逻辑是这样的,首先给前台控件写好click或者change方法,点击控件的时候,用ajax向后台请求数据,然后封装请求的数据成json返回前台,ajax拿到json数据进行更新操作。
Filter过程中遇到过无限请求,无限过滤,死循环等等一系列的问题,目前只是把Filter这一种方案做成了,Springboot自带的Interceptor仍然没有调试成功。
总结如下:
1.如果遇到控件不生效的问题:

  • 检查id选择器应该用#id,class选择器应该用.Class,且没有重名。
  • 是否使用的是a标签中的onclick方法,不知道为啥笔者用的时候Filter死活不生效,因此在外面直接用jquery写click方法就可以了,如果有谁知道原因,还请不吝赐教。

2.如果遇到无限循环的问题请依此检查:

  • 检查是不是没有设置跳出白名单。
  • 是否所有例外请求都被加入过滤白名单了,如果有一个少加死循环的概率会很大
  • 是否每一个condition都有处理逻辑,该放过的用chain.doFilter(request, response)放过,该重定向的用res.sendRedirect(REDIRECT_URL)重定向。
  • 是否有额外的chain.doFilter(request, response)语句导致了无限请求。

贴代码

package com.lenovo.integration.filter;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Component;

@Component
@WebFilter(urlPatterns = "/**", filterName = "loginFilter")
public class LoginFilter implements Filter {

	private static final String[] excludePathPatterns = { "/login", "/login/loginPost", "/login/accountCheck","/login/logout",
			"/ex/register", "/consultant/addConsultant", "/teams/getTeams", "/company/getCompanies" };/*设置循环跳出的例外请求(白名单)*/
	private static String REDIRECT_URL = "/login";

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//System.out.println("开始拦截了................");
		HttpServletRequest req = (HttpServletRequest) request;  /*拿到请求*/
		HttpServletResponse res = (HttpServletResponse) response; /*拿到回复*/
		String requestUri = req.getRequestURI();   /*获取当前的request uri*/
		String goURL = req.getServletPath();       /*获取当前的servlet路径,也包含文件名,可以用这种办法放过静态资源,用"/static/**"这样的写法不太好用*/
		if (Arrays.asList(excludePathPatterns).contains(requestUri)) {
		//碰见白名单放过
			chain.doFilter(request, response);
		} else if (goURL.endsWith(".js") || goURL.endsWith(".css") || goURL.endsWith(".svg") || goURL.endsWith(".png")
				|| goURL.endsWith(".map") || goURL.endsWith(".ico")) {
				//碰见静态资源放过
			chain.doFilter(request, response);
		} else {
		//其他,开始执行拦截逻辑
			HttpSession session = req.getSession();
			if (null == session.getAttribute("sessionAccount")) {
				res.sendRedirect(REDIRECT_URL);
			} else {
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String date=df.format(new Date());
				System.out.println("["+date+"]");
				System.out.println("session is NOT null:" + req.getContextPath() + requestUri);
				chain.doFilter(request, response);
			}
		}
	}
	//chain.doFilter(request, response); 笔者测试的时候这里写了一个放过语句结果忘了删了,于是陷入了无限请求和无限过滤的尴尬境地
}

工作流

Filter的工作流如下:

  1. 开始第一次拦截,判断是否是白名单?是:放过,开始下一次请求;
  2. 否:是否是静态资源?是:放过,开始下一次请求;
  3. 否:获取session,判断是否session有合法的信息?是:放过,执行程序逻辑发给前台显示。
  4. 否:发给重定向的请求,并对这个重定向进行拦截。

从这里就能看出来,如果跳出条件没有设置好,很容易陷入死循环,无限重定向直到最大值,浏览器报错网页无法响应。


Created with Raphaël 2.2.0 开始 Request URI 拦截(filter) 白名单? static ? session存在? 放过(chain.doFilter(req,res)) 前台显示,结束循环 重定向 yes no yes no yes no