多个Filter过滤顺序
当存在两个Filter:filter1和filter2,两个filter过滤URL相同,此时的过滤顺序为:
在web.xml中,的配置顺序则为两个过滤器的过滤顺序。
filter1--->filter2--->doFilter---->filter2---->filter1
这种情况下,如果第二个过滤器需要得到第一个过滤器过滤之后的一些数据,则会出现空指针异常。
此时我们可以先让第一个过滤器返回,因为当存在几个过滤器只有遇到doFilter时,才会放行,也就是说才会完整的运行一次。doFilter这个方法就是一个阀值。
如果要使第一个filter先完整执行,则在第二个过滤器中,当第一个过滤进入之后,若我们并没有获取需要的数据,即直接调用doFilter()方法。此时就将返回到第一个过滤器之中。
以下通过实际代码说明两个filter的执行顺序:
第一个过滤器,为过滤登录地址,和是否登录。
`public class RestAuthenticationFilter implements Filter {
public void destroy() {
}
public void init(FilterConfig arg0) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
logAccessAPI(request);
String requestURI = request.getRequestURI();
if (requestURI.endsWith("/filter/login")) {
**system.out.println( login before);**
**chain.doFilter(request, response);**
**System.out.println( login after);**
return;
}
Object personId = request.getSession().getAttribute("personid");
if (null != personId && StringUtils.isNotBlank((String) personId.toString())) {
**system.out.println( login before);**
**chain.doFilter(request, response);**
**System.out.println( login after);**
return;
} else {
response.setContentType("application/json;");
ServletOutputStream sos = response.getOutputStream();
sos.write("{\"flag\":false,\"msg\":\"session timeout, need login\",\"data\":[{}]}".getBytes());
}
}
第二个过滤器:过滤请求的参数是否正常,是否符合自己要求。
public class DataAuthenticationFilter implements Filter{
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
long start = System.currentTimeMillis();
Enumeration<String> paramter = req.getParameterNames();
if (paramter == null || !(FindEnum(paramter))) {
**system.out.println( DataAuth before);**
chain.doFilter(req, res);
**system.out.println( DataAuth after);
long end = System.currentTimeMillis();
System.out.println( end - start );
return;
}
String[] site_id = ((String) req.getSession().getAttribute("siteId")).split("\|");
List<String> site = Arrays.asList(site_id);
String site_id_check = req.getParameter("site_id");
if (site_id_check != null){
List<String> site_check = Arrays.asList(site_id_check.split(","));
if (site.containsAll(site_check) && site_check != null){
chain.doFilter(req, res);
long end = System.currentTimeMillis();
System.out.println( end - start );
return;
}
}
response.setContentType("application/json;");
ServletOutputStream sos = response.getOutputStream();
sos.write("{\"flag\":false,\"msg\":\"site_id invalid \",\"data\":[{}]}".getBytes());
long end = System.currentTimeMillis();
System.out.println( end - start );
return;
}
private boolean FindEnum(Enumeration<String> paramter){
for(Enumeration<String> e=paramter;e.hasMoreElements();){
if(e.nextElement().toString().equals("site_id"))
return true;
}
return false;
}
}
Web.xml
在web.xml中我们的配置为:<filter>
<filter-name>restAuthenticationFilter</filter-name>
<filter-class>com.envision.envservice.filter.RestAuthenticationFilter</filter-class>
</filter>
<filter>
<filter-name>dataAuthenticationFilter</filter-name>
<filter-class>com.envision.envservice.filter.DataAuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>restAuthenticationFilter</filter-name>
<url-pattern>/services/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>dataAuthenticationFilter</filter-name>
<url-pattern>/services/*</url-pattern>
</filter-mapping>
如果第一次我们请求的资源地址为:http://127.0.0.1:8080/filter/services/login
此时打印输出的信息为:
login before
DataAuth before
doFilter
DataAuth after
login after
过滤顺序即可以看出是什么顺序,也我们必要的时候,也可以控制他先将某些过滤器“跳过”