1

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

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

我有一个非常简单的基于 Freemarker 的 webapp。那部分工作正常。我有一个请求处理程序方法来处理所有请求(@RequestMapping("/**"))但希望/${contextPath}/static/...使用该<mvc:resources.../>工具提供静态资源。这些资源位于顶级 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服务器接收,只是路由到了错误的地方。

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

环境

  • 日食月神
  • 爪哇 8
  • 雄猫 8
  • 自由标记 2.3.23
  • 春天 4.2.0
  • 视窗 7 SP1

部署布局

标准 Java EE 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...

自由标记模板

<!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>
...
4

1 回答 1

3

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

您可能认为这没有意义,但 Spring 的同胞认为它应该是这样的,至少在默认情况下......

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

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

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

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

我使用 Spring 3.2.4 进行了测试,它可以按照您的意愿工作。但它看起来像是在驱动不是为它设计的 spring 框架,所以我不能保证它可以在其他版本上运行。


您还可以将调度程序 servlet 映射到/而不是/*. 这样,可以由 servlet 容器直接提供的所有静态资源(以及 JSP)都将如此。该映射的主要警告是,根将不再由 Spring 调度程序 servlet 提供服务。一种可能的解决方法是使用/home根控制器的 URL,并将欢迎文件放在 web 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文件,它将捕获请求并失败。

于 2015-08-12T11:53:12.080 回答