How to add filters to servlet without modifying web.xml

后端 未结 3 425
醉话见心
醉话见心 2020-12-07 15:24

I\'d like the ability to modify/configure filters in a different way than web.xml. Here is a static configuration of 2 filters. I\'d like the ability to have one filter stat

3条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-07 15:45

    Just do the same job as the container already does. I.e. reinvent the wheel of the chain of responsibility design pattern as is under the covers been used by servlet filters.

    public class GodFilter implements Filter {
    
        private Map filters = new LinkedHashMap();
    
        @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 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();
            }
        }
    
    }
    

    with those little helper classes (which can if necessary be made private static nested classes of the above 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);
        }
    
    }
    

    and

    public class GodFilterChain implements FilterChain {
    
        private FilterChain chain;
        private List filters = new ArrayList();
        private Iterator 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);
        }
    
    }
    

    You could if necessary also feed a XML config file with all possible filters so that you end up with easier configuration. You could use reflection to create filters in init() of your GodFilter.

    Oh nevermind, that's what the web.xml and the container already is doing...

提交回复
热议问题