servletsservlet-filtersservlet-mapping

Servlet URL mapping and filter mapping -- can't get both to work together


In my web.xml I have a servlet mapping:

<servlet>
  <servlet-name>My Servlet</servlet-name>
  <servlet-class>servlets.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>My Servlet</servlet-name>
  <url-pattern>/dir/*</url-pattern>
</servlet-mapping>

and I also have a filter:

<filter>
  <filter-name>My Filter</filter-name>
  <filter-class>filters.MyFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>My Filter</filter-name>
  <url-pattern>*.data</url-pattern>
</filter-mapping>

If I access /dir or /dir/foo, the servlet responds. If I access /somewhere/file.data, the filter filters the response. If I access /dir/foo.data, I just get a 404 error.

I have tried reversing the order of the servlet and the filter in my web.xml file, but it makes no difference. It seems that I can either get the servlet to respond, or the filter to filter the response, but not both.

Can anyone tell me what to do to get the servlet to respond and also have the filter process the servlet response?


Solution

  • There is no easy way to solve this, since filter mappings always seem to take precedence over servlet mappings. (I can't see anything in the servlet spec which mandates this, but this is how it appears to work.) The only solution I've found is to get rid of the filter altogether and merge its functionality into the servlet.

    I now have a servlet which responds to /dir/* and also to *.data. It inspects the request URI, and if it starts with /dir/ it generates the response dynamically, otherwise it just processes the corresponding file. Then, if the URI ends with .data, it preprocesses the response in the same way as the filter used to do.

    The disadvantage is that this causes a maintenance problem, as the servlet needs to know which patterns it is configured to respond to in the web.xml file. To minimise the problem, the servlet mapping now looks like this:

    <servlet>
      <servlet-name>My Servlet</servlet-name>
      <servlet-class>servlets.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>My Servlet</servlet-name>
    <!--
      If the patterns below are changed, the "prefixes" and
      "suffixes" list in the servlet source code need to be
      updated to match, and the servlet needs to be recompiled.
    -->
      <url-pattern>/dir/*</url-pattern>
      <url-pattern>*.data</url-pattern>
    </servlet-mapping>
    

    In the servlet I have this:

    public static final String[] prefixes = new String[] {
      "/dir/"
    };
    public static final String[] suffixes = new String[] {
      ".data"
    };
    

    so the servlet can match the URI against the contents of each array. It's a bit messy, but it's the best I can do.