Spring <mvc:resources ... /> 请求路由

Spring <mvc:resources ... /> request routing

TL;DR:我正在编写一个简单的 Tomcat/Spring/Freemarker webapp,但似乎很难让 Spring 的 DispatcherServlet 支持 <mvc:resources...> 配置。

请注意:AFAICT 这不是其他问题的重复,因为我已经尝试过其他答案中给出的解决方案。如果有人发现现有问题并且该问题提供了我遗漏的解决方案,我很乐意将 VTC 作为副本(或根据需要删除此问题)。

我有一个非常简单的基于 Freemarker 的网络应用程序。那部分工作正常。我有一个请求处理程序方法来处理所有请求 (@RequestMapping("/**")),但希望使用 <mvc:resources.../> 工具提供静态资源 /${contextPath}/static/...。资源位于顶级 webapp 目录的子目录中。

基于阅读关于 SO 的其他问题,我添加了

<mvc:resources mapping="/static/**" location="/" /> 

到我的 Spring 配置。

无论我做什么,我希望作为静态资源文件解析的请求都被发送到我的控制器的请求处理程序方法。我唯一能想到的是 @RequestMapping 注释优先于 mvc:resources,但这没有多大意义。

我已验证资源 URL 生成正确,即模板行

<link rel="stylesheet" href="${contextPath}/static/css/gallery.css">

生成

<link rel="stylesheet" href="/gallery/static/css/gallery.css">

Tomcat 服务器正在接收请求,只是路由到了错误的地方。

我已经阅读了关于这个主题的大部分问题,我相信我做对了(例如 Trying to get mvc resources to serve my static resources),但显然我遗漏了一些明显的东西。

环境

已部署布局

标准JavaEE Tomcat目录结构

webapps
 |- gallery
     |- css
     |- images
     |- js
     |- META-INF
     |- WEB-INF
         |- classes
         |- lib
         |- views

Tomcat 上下文定义

<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="D:\dev\tools\apache-tomcat-8.0.24\wtpwebapps\gallery" 
         path="/gallery" reloadable="true" 
         source="org.eclipse.jst.j2ee.server:gallery"/>

Spring Servlet 配置

WEB-INF/main-servlet.xml

...
<mvc:resources mapping="/static/**" location="/" />
<mvc:annotation-driven/>
<context:component-scan base-package="com.mysite.gallery"/>
...

我已经尝试了这些语句的所有可能顺序,但似乎没有效果。我也尝试添加

<mvc:default-servlet-handler/>

没有效果。

WEB-INF/web.xml

标准 Spring MVC DispatcherServlet 配置

  ...
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
      <servlet-name>main</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
      <servlet-name>main</servlet-name>
      <url-pattern>/*</url-pattern>
  </servlet-mapping>
  ...

请求映射方法

...
@RequestMapping("/**")
public String gallery(ModelMap modelMap, HttpServletRequest req, HttpServletResponse resp)
{
    etc...

Freemarker 模板

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="${contextPath}/static/css/photoswipe.css">
    <link rel="stylesheet" href="${contextPath}/static/css/default-skin/default-skin.css">
    <link rel="stylesheet" href="${contextPath}/static/css/gallery.css">
    <script src="${contextPath}/static/js/photoswipe.min.js"></script>
    <script src="${contextPath}/static/js/photoswipe-ui-default.min.js"></script>
  </head>
  <body>
    <div>
...

你在问题中给出了答案:我唯一能想到的是@RequestMapping注解优先于mvc:resources,但这没有多大意义.

你可能认为它没有意义,但 Spring 伙计们认为它应该是这样的,至少在默认情况下是这样...

但是你有不同的方法让静态资源在 @RequestMapping 注释控制器上具有优先权。

最简单的方法是在 <mvc:resources.../> 标签中添加一个 "order=0" 属性:

<mvc:resources mapping="/static/**" location="/" order="0"/>

并写在WEB-INF/main-servlet.xml之前<mvc:annotation-driven/>

我在 Spring 3.2.4 中进行了测试,它可以正常工作。但它看起来像是驱动 spring 框架,它不是为它设计的,所以我不能保证它能在其他版本上工作。


您还可以将调度程序 servlet 映射到 / 而不是 /*。这样所有可以由 servlet 容器直接提供的静态资源(以及 JSP)都将是。该映射的主要警告是 Spring dispatcher servlet 将不再为 root 提供服务。一种可能的解决方法是对根控制器使用 /home URL,并在网络中放置一个欢迎文件 xml :

<servlet>
  <servlet-name>main</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

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

<welcome-file-list>
    <welcome-file>/home</welcome-file>
</welcome-file-list>

这样,你甚至不需要使用 /mappings/images/img.gif,只需使用 /images/img.gif/.

但是我一直接受另一个警告(因为我找不到任何解决方法):如果 /url 由一个控制器提供服务,则 /url.jsp/url.jpeg 将给出 404 错误。由于容器默认 servlet 知道 .jpeg.jsp 文件,它将捕获请求并失败。