Serving static resources in / static / * context while keeping my servlet handling / * context
My problem is simple. I want my static resources to serve in context /static/*
, but my specific servlet serving the context /*
. Since it /static/*
is a subset /*
, this will 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>
source to share
Here's a 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 searching the source for the DefaultServlet, I found that the DefaultServlet only accepts the url portion of the requested url, so if your request is /static/styles.css, the container translates it to /styles.css. Servlet function is not listed in DefaultServlet. If you want to access this css file you have to use the url / static / static / styles.css request.
A simple solution to our problem is to write a DefaultFilter class and place it at the beginning of the web.xml file. This filter will redirect all static content calls to the DefaultServlet.
Define a filter that will send a 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 filter (before 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 mapped to the DefaultFilter, which simply breaks up the filter chain and redirects the request to the DefaultServlet.
source to share
For me this works in Tomcat 8.5 (I no longer have web.xml):
@WebServlet(urlPatterns = "/*")
public class MainServlet {}
@WebServlet(urlPatterns = { "/static/*", "/gwt/*" })
public class StaticServlet extends org.apache.catalina.servlets.DefaultServlet {}
More specific url patterns seem to take priority automatically. To extend the default catalina servlet add a scoped org.apache.tomcat > tomcat-catalina
maven to your project provided
.
You can (like me) immediately run into the problem that the application context-only request has problems resolving relative paths in your html (for stylesheets and javascripts, for example).
I figured 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;
}
//...
}
source to share