2011-08-25 91 views
29

我希望能够以不同于web.xml的方式修改/配置过滤器。这是2个过滤器的静态配置。我希望能够静态配置一个过滤器并允许该过滤器加载额外的过滤器。我只是想知道是否有人知道lib已经有这个。如何在不修改web.xml的情况下向servlet添加过滤器

使用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> 

我已经看到了这个吉斯做与GuiceFilter当过滤器在运行时配置。

+0

这将取决于servlet容器的,所以您在使用 – SJuan76

+0

哪一个必须依赖你应该告诉我们什么? GuiceFilter是否依赖于容器? – TJR

+0

Guice为自己的映射机制创建了一个类似于web.xml映射的映射机制 - 对于web容器,所有请求都以'GuiceFilter'结束。如果你想要Guice,只需使用它:) –

回答

35

只要做容器已经做的相同的工作。即在servlet过滤器所使用的覆盖范围内重新设计了chain of responsibility设计模式。

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(); 
     } 
    } 

} 

与那些小助手类(可以根据需要进行private static嵌套类以上GodFilter的):

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配置文件,以便最终配置更简单。您可以使用反射在您的GodFilterinit()中创建滤镜。

哦没关系,那是什么web.xml,并已经容器是做...

+0

Should not GodFilterChain.doFilter()loop over所有添加的过滤器比只使用第一个? – MRalwasser

+0

@MRalwasser:呃,没有。也许你错过了“责任链”设计模式的工作原理?过滤器实现中的'chain.doFilter()'调用会再次调用'GodFilterChain#doFilter()'(因为它是作为'FilterChain'参数传递的),然后迭代器会前进到下一个元素,等等。 – BalusC

+0

啊,我完全错过了后面的iterator.next()调用将在更深的“链级”内完成。感谢您指出了这一点。 – MRalwasser

15

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

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

+2

删除我的回答,击败我30秒>:| – Dave

+2

@JB Nizet:TJR没有要求版本servlet 3.0,他是特定的servlet 2.5 – developer

+0

@JB,我已经添加到我使用2.5的问题。 3.0功能确实让我开心。 – TJR

4

它可以简单的步骤来实现,即使是前3.0 Servlet规范:

  1. 添加包含类的静态&有序集合(链)的过滤器。
  2. 映射过滤器以拦截每个流量。
  3. 操纵订单&存在您的帮助类(在拦截流量时由您的过滤器私下调用这些类)。

Ref:Xstream使用相同类型的串行器模式,尽管没有使用Servlet/Filter。 :)

相关问题