2011-08-25 14 views
29

Tôi muốn có khả năng sửa đổi/cấu hình bộ lọc theo cách khác với web.xml. Đây là cấu hình tĩnh của 2 bộ lọc. Tôi muốn khả năng có một bộ lọc được định cấu hình tĩnh và cho phép bộ lọc đó tải các bộ lọc bổ sung. Tôi chỉ muốn biết nếu có ai biết về lib đã có điều này chưa.Cách thêm bộ lọc vào servlet mà không sửa đổi web.xml

Sử dụng 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> 

Tôi đã thấy điều này được thực hiện trong Guice với GuiceFilter nơi Các bộ lọc được cấu hình khi chạy.

+0

Nó sẽ phụ thuộc vào các container servlet, vì vậy bạn nên cho chúng tôi biết cái nào bạn đang sử dụng – SJuan76

+0

nó Phải phụ thuộc? GuiceFilter có phụ thuộc vào container không? – TJR

+0

Guice sẽ cuộn cơ chế ánh xạ của riêng nó hoạt động giống như ánh xạ 'web.xml' - cho vùng chứa web, tất cả các yêu cầu kết thúc tại' GuiceFilter'. Nếu bạn muốn Guice, chỉ cần sử dụng nó :) –

Trả lời

35

Chỉ cần thực hiện công việc tương tự như vùng chứa đã có. I E. phát minh lại bánh xe của mẫu thiết kế chain of responsibility dưới nắp được sử dụng bởi bộ lọc 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(); 
     } 
    } 

} 

với những lớp helper ít (có thể nếu cần được thực hiện private static lớp lồng nhau của các bên trên 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); 
    } 

} 

Bạn có thể nếu cần thiết cũng nuôi một Tệp cấu hình XML với tất cả các bộ lọc có thể để bạn kết thúc với cấu hình dễ dàng hơn. Bạn có thể sử dụng phản chiếu để tạo bộ lọc trong init() trong số GodFilter của mình.

Oh nevermind, đó là những gì các web.xml và container đã được làm ...

+0

Không nên GodFilterChain.doFilter() lặp lại tất cả các bộ lọc được thêm vào chỉ sử dụng bộ lọc đầu tiên? – MRalwasser

+0

@MRalwasser: Uh, no. Có lẽ bạn đang thiếu mẫu thiết kế "Chuỗi trách nhiệm" hoạt động như thế nào? Lệnh 'chain.doFilter()' trong việc thực hiện của bộ lọc sẽ gọi lại 'GodFilterChain # doFilter()' (vì nó là 'this' được truyền vào như đối số' FilterChain') và sau đó trình vòng lặp sẽ chuyển sang phần tử tiếp theo, v.v. – BalusC

+0

ah, tôi hoàn toàn bỏ lỡ rằng lặp đi lặp lại iterator.next() invocations sẽ được thực hiện bên trong sâu hơn "chuỗi cấp". Cảm ơn, vì đã chỉ ra điều này. – MRalwasser

15

Servlet 3.0 có chú thích @WebFilter để xác định bộ lọc. Không cần khai báo nó trong web.xml nữa.

Nhưng việc tải bộ lọc từ bộ lọc không được hỗ trợ. Bạn có thể tự mình thực hiện: đó là "chỉ" chuỗi mô hình trách nhiệm, nhưng tại sao bạn?

+2

Đã xóa câu trả lời của tôi, đánh bại tôi với nó bằng 30 giây>: | – Dave

+2

@JB Nizet: TJR không yêu cầu phiên bản servlet 3.0, anh ta cụ thể với servlet 2.5 – developer

+0

@JB, tôi đã thêm vào câu hỏi mà tôi đang sử dụng 2.5. Đó là tính năng 3.0 không làm cho tôi hạnh phúc mặc dù. – TJR

4

Nó có thể đạt được trong bước dễ dàng, ngay cả đối với pre-3.0 Servlet spec:

  1. Thêm một bộ lọc có chứa một tĩnh & bộ sưu tập lệnh của lớp (chuỗi).
  2. Lập bản đồ bộ lọc để chặn mọi lưu lượng truy cập.
  3. Thao tác theo thứ tự & sự tồn tại của các lớp trợ giúp của bạn (chúng sẽ được gọi riêng bởi bộ lọc của bạn khi chặn lưu lượng truy cập) trong chuỗi.

Tham khảo: Xstream sử dụng cùng loại mẫu cho Trình nối tiếp, cũng không phải với Servlet/Bộ lọc. :)