如何在Java中跳过过滤器链中的过滤器

28

我的应用程序中有两个过滤器。根据某些条件,我想选择是否执行第二个过滤器。有没有办法做到这一点?

我进行了一些搜索,但没有成功。我希望请求在不执行第二个过滤器的情况下继续。这可能吗?

任何帮助将不胜感激。

2个回答

70
除了Colin的答案,还有另一种方法:不要调用FilterChain#doFilter(),而是使用RequestDispatcher#forward()
if (condition) {
    request.getRequestDispatcher(((HttpServletRequest) request).getServletPath()).forward(request, response);
} else {
    chain.doFilter(request, response);
}

但这将跳过当前所有的过滤器,除了那些监听<dispatcher>FORWARD</dispatcher>的过滤器。


1
好的解决方案。但是,我们认为我们会采用属性方式,因为它更简单一些。 - Vanchinathan Chandrasekaran
11
不客气。当另一个过滤器的源代码完全不受您控制(例如来自第三方)时,这可能是唯一的解决方案。 - BalusC
9
以上示例忽略了基本servlet路径后面的URL部分。以下修复此问题:request.getRequestDispatcher(((HttpServletRequest)request).getServletPath() + StringUtils.defaultString(((HttpServletRequest)request).getPathInfo())).forward(request, response); - Cojones
1
Cojones 提出了一个好问题。根据您的应用程序,您可能需要请求中除了 servlet 路径之外的更多部分。这个 StackOverflow 的回答有一个很好的表格展示了请求的哪些部分是哪些:https://dev59.com/aW445IYBdhLWcg3wTIjm#21046620 - Nick Knowlson
非常感谢这个解决方案! - Jurica Krizanic
显示剩余4条评论

13

您可以在请求中设置一个属性,并在第二个过滤器中进行检查。

public class FirstFilter implements Filter {
    //...

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setAttribute("executeSecondFilter", true);
        //...
        if(someReason)
            servletRequest.setAttribute("executeSecondFilter", false);
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

public class SecondFilter implements Filter {
    //..

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest.getAttribute("executeSecondFilter") == null || !((Boolean) servletRequest.getAttribute("executeSecondFilter"))) {
            filterChain.doFilter(servletRequest, servletResponse);
        }
        //...
    }
}
你可以像这样简化上面的代码:
public class FirstFilter implements Filter {
    //...

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //...
        if(someReason)
            servletRequest.setAttribute("executeSecondFilter", false);
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

public class SecondFilter implements Filter {
    //..

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest.getAttribute("executeSecondFilter") != null) {
            filterChain.doFilter(servletRequest, servletResponse);
        }
        //...
    }
}

通过这种方式,您只需检查属性“executeSecondFilter”的存在即可。


1
好主意,但是如果未设置属性,此示例将抛出NPE。 - BalusC
1
@BalusC,这就是为什么我加了一个!= true,但自动拆箱胜过对象比较,现在已经纠正 :) - Colin Hebert
1
你也可以使用 Boolean.TRUE。然而,我个人觉得它看起来很丑陋 ;) - BalusC
我已经对在条件中写入true感到非常糟糕,而以Boolean.TRUE的方式会让我感觉更糟。 :P - Colin Hebert
@ColinHebert。你好!你有没有解决这个问题的办法:https://stackoverflow.com/questions/53774909/how-to-bypass-or-skip-customfilter-in-mockito-with-springboot-applicaiton? - MrSham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接