Serving static resources at /static/* context while keeping my servlet handling /* context

Archer picture Archer · Jan 26, 2013 · Viewed 12.6k times · Source

My problem is simple. I want to have my static resources served at /static/* context, but my specific servlet serving /* context. Since /static/* is a subset of /* it does not work. My web.xml looks like this:

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <display-name>template-guice-jersey-tomcat</display-name>
 <session-config>
     <session-timeout>30</session-timeout>
 </session-config>
 <welcome-file-list>
     <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

 <!-- set up Google Guice Servlet integration -->
 <filter>
    <filter-name>guiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>guiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

 <servlet-mapping>                                                                                                                               
   <servlet-name>default</servlet-name>                                                                                                          
   <url-pattern>/static/*</url-pattern>                                                                                                          
 </servlet-mapping>                                                                                                                              


 <listener>                                                                                                                                      
     <listener-class>de.danbim.templateguicejerseytomcat.GuiceServletConfig</listener-class>                                                     
 </listener>                                                                                                                                     
</web-app>  

Answer

Archer picture Archer · Jan 27, 2013

Here's very clean solution to this problem: http://www.kuligowski.pl/java/rest-style-urls-and-url-mapping-for-static-content-apache-tomcat,5:

Unfortunately after looking into DefaultServlet source I found that DefaultServlet takes only pathInfo part of requested URL, so if your request is /static/styles.css, container translates it into /styles.css. Servlet part is omitted by the DefaultServlet. If you want to access such css file you should use /static/static/styles.css request url.

The simple solution of our problem is to write DefaultFilter class and place it at the beginning of web.xml file. This filter will forward all static content calls to DefaultServlet.

Define a filter which will dispatch the request to the default servlet:

public class DefaultFilter implements Filter {  
  
    private RequestDispatcher defaultRequestDispatcher;  
  
    @Override  
    public void destroy() {}  

    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)   
          throws IOException, ServletException {  
        defaultRequestDispatcher.forward(request, response);  
    }  

    @Override  
    public void init(FilterConfig filterConfig) throws ServletException {  
        this.defaultRequestDispatcher =   
            filterConfig.getServletContext().getNamedDispatcher("default");  
    }  
}

Add the filter (ahead of the other filters) to web.xml:

<filter>  
    <filter-name>default</filter-name>  
    <servlet-name>default</servlet-name>  
    <filter-class>pl.kuligowski.example.DefaultFilter</filter-class>  
</filter>  
<filter-mapping>  
    <filter-name>default</filter-name>  
    <url-pattern>/static/*</url-pattern>  
    <url-pattern>*.ico</url-pattern>  
</filter-mapping>

Only static content calls are matched to DefaultFilter, which simply breaks the filter chain and forwards the request to the DefaultServlet.