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

StackOverflow https://stackoverflow.com/questions/14539076

Question

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>  
Was it helpful?

Solution

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.

OTHER TIPS

For me, this works in Tomcat 8.5 (I don't even have a web.xml anymore):

@WebServlet(urlPatterns = "/*")
public class MainServlet {}

@WebServlet(urlPatterns = { "/static/*", "/gwt/*" })
public class StaticServlet extends org.apache.catalina.servlets.DefaultServlet {}

The more specific url patterns seem to get precedence automatically. To extend the catalina default servlet, add org.apache.tomcat > tomcat-catalina maven dependency with scope provided to your project.

You might (like me) run immediately into the issue that a request for just the app context has problems resolving relative paths in your html (e.g. for stylesheets and javascripts).

I solved that with a redirect in the main servlet:

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    if(request.getPathInfo() == null) {
      // redirect http://localhost:8080/test -> http://localhost:8080/test/ (add trailing slash)
      // because only then are the relative paths to the gwt scripts correctly resolved
      getResponse().sendRedirect(getRequest().getContextPath() + "/");
      return;
    }

    //...
  }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top