繁体   English   中英

如何在不修改 web.xml 的情况下向 servlet 添加过滤器

[英]How to add filters to servlet without modifying web.xml

我希望能够以不同于 web.xml 的方式修改/配置过滤器。 这是 2 个过滤器的静态配置。 我希望能够静态配置一个过滤器并允许该过滤器加载其他过滤器。 我只是想知道是否有人知道已经拥有这个的 lib。

使用 Servlet API 2.5

<web-app>
  ...
  <filter>
    <filter-name>MyFilter1</filter-name>
    <filter-class>com.me.MyFilter1</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>MyFilter1</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  ...
  <filter>
    <filter-name>MyFilter2</filter-name>
    <filter-class>com.me.MyFilter2</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>MyFilter2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  ...
</web-app>

我已经看到在 Guice 中使用 GuiceFilter 完成此操作,其中过滤器在运行时配置。

只需做与容器已经做的相同的工作。 即重新发明责任链设计模式的轮子,正如 servlet 过滤器所使用的那样。

public class GodFilter implements Filter {

    private Map<Pattern, Filter> filters = new LinkedHashMap<Pattern, Filter>();

    @Override
    public void init(FilterConfig config) throws ServletException {
        Filter1 filter1 = new Filter1();
        filter1.init(config);
        filters.put(new Pattern("/foo/*"), filter1);

        Filter2 filter2 = new Filter2();
        filter2.init(config);
        filters.put(new Pattern("*.bar"), filter2);

        // ...
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest hsr = (HttpServletRequest) request;
        String path = hsr.getRequestURI().substring(hsr.getContextPath().length());
        GodFilterChain godChain = new GodFilterChain(chain);

        for (Entry<Pattern, Filter> entry : filters.entrySet()) {
            if (entry.getKey().matches(path)) {
                godChain.addFilter(entry.getValue());
            }
        }

        godChain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        for (Filter filter : filters.values()) {
            filter.destroy();
        }
    }

}

使用那些小助手类(如有必要,可以将其GodFilter上述GodFilter private static嵌套类):

public class Pattern {

    private int position;
    private String url;

    public Pattern(String url) {
        this.position = url.startsWith("*") ? 1
                      : url.endsWith("*") ? -1
                      : 0;
        this.url = url.replaceAll("/?\\*", "");
    }

    public boolean matches(String path) {
        return (position == -1) ? path.startsWith(url)
             : (position == 1) ? path.endsWith(url)
             : path.equals(url);
    }

}

public class GodFilterChain implements FilterChain {

    private FilterChain chain;
    private List<Filter> filters = new ArrayList<Filter>();
    private Iterator<Filter> iterator;

    public GodFilterChain(FilterChain chain) {
        this.chain = chain;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (iterator == null) {
            iterator = filters.iterator();
        }

        if (iterator.hasNext()) {
            iterator.next().doFilter(request, response, this);
        } else {
            chain.doFilter(request, response);
        }
    }

    public void addFilter(Filter filter) {
        if (iterator != null) {
            throw new IllegalStateException();
        }

        filters.add(filter);
    }

}

如有必要,您还可以提供包含所有可能过滤器的 XML 配置文件,以便您最终获得更简单的配置。 您可以使用反射在GodFilter init()中创建过滤器。

哦,没关系,这就是web.xml和容器已经在做的......

Servlet 3.0 有@WebFilter注释来定义过滤器。 不再需要在 web.xml 中声明它。

但不支持从过滤器加载过滤器。 你可以自己实现它:它“只是”责任链模式,但你为什么要这样做?

它可以通过简单的步骤实现,即使对于 3.0 之前的 Servlet 规范:

  1. 添加一个包含静态和有序类(链)集合的过滤器。
  2. 映射过滤器以拦截每个流量。
  3. 在链中操纵您的助手类(它们将在拦截流量时由您的过滤器私下调用)的顺序和存在。

参考:Xstream 对 Serializer 使用相同类型的模式,但不与 Servlet/Filter 一起使用。 :)

我个人喜欢@WebFilter注释来注册 servlet 过滤器。
但另一个解决方案是在运行时使用ServletContext's addFilter函数添加过滤器。

实现ServletContextListener 就像是:

public class MyContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent ce) {
        ServletContext servletContext = ce.getServletContext();
    
        // you can even conditionally add this
        servletContext.addFilter("My filter 1", MyFilter1.class)
                .addMappingForUrlPatterns(allOf(DispatcherType.class), false, "/*");
    }
}

注册监听器:

<listener>
    <listener-class>com.me.MyContextListener</listener-class>
</listener>   

当然,您需要实现一个Filter 但是在您的问题中,您已经参考了示例过滤器“MyFilter1”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM