Cómo añadir filtros a servlet sin modificar web.XML


Me gustaría la capacidad de modificar/configurar filtros de una manera diferente a web.XML. Aquí hay una configuración estática de 2 filtros. Me gustaría tener la capacidad de tener un filtro configurado estáticamente y permitir que ese filtro cargue filtros adicionales. Sólo quería saber si alguien sabe de Lib que ya tiene esto.

Usando 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>

He visto esto hecho en Guice con GuiceFilter donde los Filtros se configuran en tiempo de ejecución.

Author: BalusC, 2011-08-25

3 answers

Simplemente haga el mismo trabajo que ya hace el contenedor. Es decir, reinventar la rueda de la cadena de responsabilidad patrón de diseño como está debajo de las cubiertas utilizadas por los filtros 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();
        }
    }

}

Con esas pequeñas clases auxiliares (que si es necesario se pueden hacer private static clases anidadas de lo anterior 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);
    }

}

Y

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

}

Si es necesario, también podría alimentar un archivo de configuración XML con todos los filtros posibles para que termine con una configuración más fácil. Podrías usar reflexión para crear filtros en init() de su GodFilter.

Oh no importa, eso es lo que el web.xml y el contenedor ya están haciendo...

 36
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-10 22:09:47

Servlet 3.0 tiene la anotación @WebFilter para definir un filtro. No hay necesidad de declararlo en la web.xml más.

Pero no se admite la carga de un filtro desde un filtro. Podrías implementarlo tú mismo: es "solo" el patrón de la cadena de responsabilidad, pero ¿por qué lo harías?

 15
Author: JB Nizet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-03 19:51:55

Se puede lograr en sencillos pasos, incluso para especificaciones de Servlet pre-3.0:

  1. Agregue un filtro que contenga una colección estática y ordenada de Clases (cadena).
  2. Asigna el filtro para interceptar cada tráfico.
  3. Manipula el orden y la existencia de tus clases de ayuda (que serán llamadas de forma privada por tu filtro al interceptar el tráfico) en la cadena.

Ref: Xstream usa el mismo tipo de patrón para Serializer, aunque no con Servlet/Filter. :)

 4
Author: Puspendu Banerjee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-25 14:22:50