我希望能够以与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>
我已经在使用GuiceFilter的Guice中看到了这一点,其中过滤器是在运行时配置的。
答案 0 :(得分:38)
完成与容器相同的工作。即重新设计chain of responsibility设计模式的轮子,就像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();
}
}
}
使用那些小帮助程序类(如果需要,可以使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配置文件,以便最终更轻松地进行配置。您可以使用反射在init()
的{{1}}中创建过滤器。
哦,没关系,这就是GodFilter
和容器已经在做什么......
答案 1 :(得分:15)
Servlet 3.0具有@WebFilter
注释来定义过滤器。无需再在web.xml中声明它。
但不支持从过滤器加载过滤器。你可以自己实现它:它只是“责任链模式”,但你为什么要这样做?
答案 2 :(得分:4)
即使对于3.0之前的Servlet规范,也可以通过简单的步骤实现:
参考:Xstream对Serializer使用相同的模式,但不使用Servlet / Filter。 :)
答案 3 :(得分:0)
我个人喜欢 @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”。