29

What I'm trying to do is map requests to the servlet root (correct terminology?). I'm at the point where URLs are mapped to correct view but all the static content - css, javascript, images - that is part of the page cannot be found.

So in my web.xml my servlet tag looks like this

<servlet-mapping>
    <servlet-name>springapp</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

My controller looks something like this:

@RequestMapping("/shop")
public class TheShopController extends MyBaseController {

    public static String VIEW = "Tile.Shop";

    @Override
    @RequestMapping(method = RequestMethod.GET)
    protected ModelAndView processRequest(HttpServletRequest req, HttpServletResponse resp) {
        ModelAndView mav = new ModelAndView(VIEW);
        return mav;
    }

}

MyBaseController is very simple. It looks like this:

public abstract class MyBaseController extends AbstractController {

    protected Logger log = Logger.getLogger(getClass());

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse resp) 
        throws Exception {

        ModelAndView mav = processRequest(req, resp);
        return mav;
    }

    protected abstract ModelAndView processRequest(HttpServletRequest req, HttpServletResponse resp);
}

I'm using Tiles in my view layer. My configuration is as follows:

/WEB-INF/tiles-defs.xml

As I mentioned, the views are found but the static resources that are a port of the page can't be found. Here is some typical logging out put:

2010-01-24 17:25:01,777 DEBUG [http-8080-7] servlet.DispatcherServlet (DispatcherServlet.java:690) - DispatcherServlet with name 'springapp' processing GET request for [/springapp/static/css/account.css] 2010-01-24 17:25:01,778 WARN [http-8080-4] servlet.DispatcherServlet (DispatcherServlet.java:962) - No mapping found for HTTP request with URI [/springapp/static/css/shop.css] in DispatcherServlet with name 'springapp' 2010-01-24 17:25:01,778 DEBUG [http-8080-6] servlet.FrameworkServlet (FrameworkServlet.java:677) - Successfully completed request 2010-01-24 17:25:01,778 WARN [http-8080-5] servlet.DispatcherServlet (DispatcherServlet.java:962) - No mapping found for HTTP request with URI [/springapp/static/css/offers.css] in DispatcherServlet with name 'springapp' 2010-01-24 17:25:01,778 WARN [http-8080-3] servlet.DispatcherServlet (DispatcherServlet.java:962) - No mapping found for HTTP request with URI [/springapp/static/css/scrollable-buttons.css] in DispatcherServlet with name 'springapp'

Going to http://localhost:8080/springapp/shop works fine but the css and images are missing.

I think that using Tiles is somehow complicating things but I"m reluctant to get rid of it. I'm wondering if I need to adjust my view resolution configuration needs to be tweeked somehow? Chaining view resolvers maybe? I'm just not that experienced in doing that.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Rich Everhart
  • 1,043
  • 4
  • 19
  • 29

4 Answers4

61

The problem is that requests for the static content go to the dispatcherServlet, because it's mapped as <url-pattern>/</url-pattern>. It's a very common problem in applications with "RESTful" URLs (that is, without any prefix in the DispatcherServlet mapping).

There are several possible ways to solve this problem:


Since Spring 3.x the preferred way to access static resources is to use <mvc:resources>: web.xml:

<servlet-mapping> 
    <servlet-name>springapp</servlet-name> 
    <url-pattern>/</url-pattern> 
</servlet-mapping>

Spring config:

<!-- Handles GET requests for /resources/** by efficiently serving static content 
    in the ${webappRoot}/resources dir --> 
<mvc:resources mapping="/resources/**" location="/resources/" /> 

See also MVC Simplifications in Spring 3


1. Use URL rewrite filter
See mvc-basic example here

2. Set a prefix for the default servlet:

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

That is, request for /static/images/image.png will return the file named /images/image.png However, this way is incompatible across different servlet containers (doesn't work in Jetty), see workarounds here

3. Set static content extensions for the default servlet:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
    <url-pattern>*.js</url-pattern>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>

4. Do not use RESTful URLs, use URLs with prefix:

<servlet-mapping> 
    <servlet-name>springapp</servlet-name> 
    <url-pattern>/app</url-pattern> 
</servlet-mapping>

5. Do not use RESTful URLs, use URLs with extension:

<servlet-mapping> 
    <servlet-name>springapp</servlet-name> 
    <url-pattern>*.do</url-pattern> 
</servlet-mapping>
Community
  • 1
  • 1
axtavt
  • 239,438
  • 41
  • 511
  • 482
  • What I really want to do is use the @RequestMapping annotation with the @PathVariable annotation to achieve the use of RESTful urls. Eventually all static resources will be served by apache but that will be in a production environment. I need static resources served by tomcat when running locally, like in development. I've used urlrewrite filter before, and I liked it, but I'd like to find another way. – Rich Everhart Jan 27 '10 at 04:07
  • I went with a combination of org.tuckey.urlrewrite filter and #4 from above. Thanks! – Rich Everhart Mar 05 '10 at 06:46
  • You rock. FYI I tried #2 and it worked in my local environment, which was running under the root website in tomcat. As soon as I deployed it to a test server, under a non-root site called "test", it stopped working. For some reason the /test/ before /static/ was throwing off the default servlet mapping. Just switched to #3 and it's working like a charm. I've been struggling with this for too long. Thank you! +1 – kmehta Apr 21 '11 at 13:20
  • @axtavt : I have similar issue while accessing REST, not sure if its because of wrong mapping. Could you help me by having a look at : http://stackoverflow.com/questions/25285805/getting-404-not-found-while-accessing-valid-rest-service-with-jersey-extjs Thanks! – Snehal Masne Aug 14 '14 at 07:04
5

Did any one consider using this:

<!-- Allows for mapping the DispatcherServlet to "/" by forwarding static resource requests to the container's default Servlet -->
<mvc:default-servlet-handler/>

Here is the latest spring docs on it: http://static.springsource.org/spring/docs/3.1.2.RELEASE/spring-framework-reference/htmlsingle/spring-framework-reference.html#mvc-default-servlet-handler

Solubris
  • 3,603
  • 2
  • 22
  • 37
4

As an alternative to the proposed solution number (2, default servlet which behaves differently from servlet container to servlet container), I would recommend taking a look into the Resource Servlet (org.springframework.js.resource.ResourceServlet) from the Spring Webflow project.

For more details please have a look at How to handle static content in Spring MVC?

Community
  • 1
  • 1
ngeek
  • 7,733
  • 11
  • 36
  • 42
1

I have the same problem but instead of using spring, I do mysefl a small filter that redirect root to my start page like that:

    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;

    String pageName = req.getServletPath();

    if(pageName.equals("/")) {
        res.sendRedirect( req.getContextPath() + "/start" );
    } else {
        chain.doFilter(request, response);
    }

It's maybe a trick but it look like working fine with a small code. Go here for more filter information http://www.oracle.com/technetwork/java/filters-137243.html

Nereis
  • 486
  • 1
  • 4
  • 21