且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用Spring,在web.xml中映射到root,找不到静态资源

更新时间:2023-11-22 14:16:34

问题是对静态内容的请求到了 dispatcherServlet,因为它被映射为 <url-pattern>/</url-模式>.这是具有RESTful"URL 的应用程序(即 DispatcherServlet 映射中没有任何前缀)中的一个非常常见的问题.

有几种可能的方法可以解决这个问题:

从 Spring 3.x 开始,访问静态资源的首选方式是使用 :web.xml:

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

弹簧配置:

<!-- 通过有效地提供静态内容来处理对/resources/** 的 GET 请求在 ${webappRoot}/resources 目录中 --><mvc:resources mapping="/resources/**" location="/resources/"/>

另见 Spring 中的 MVC 简化3

1.使用 URL 重写过滤器
参见 mvc-basic 示例 这里

2.为 default servlet 设置前缀:

<servlet-name>默认</servlet-name><url-pattern>/static/*</url-pattern></servlet-mapping>

也就是说,请求/static/images/image.png 将返回名为/images/image.png 的文件但是,这种方式在不同的 servlet 容器之间不兼容(在 Jetty 中不起作用),请参阅解决方法 这里

3.为 default servlet 设置静态内容扩展:

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

4.不要使用 RESTful URL,使用带有前缀的 URL:

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

5.不要使用 RESTful URL,使用带有扩展名的 URL:

<servlet-name>springapp</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping>

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.

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>