Spring <mvc: resources... /> маршрутизация запросов

TL;DR: я пишу простое веб-приложение Tomcat/Spring/Freemarker и, похоже, у меня много проблем с получением Spring DispatcherServlet в честь <mvc:resources...> конфигурации.

ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ: AFAICT, это не дубликат других вопросов, поскольку я попробовал решения, приведенные в других ответах. Если кто-то найдет существующий вопрос, и этот вопрос предоставит решение, которое я пропустил, я с радостью добавлю VTC в качестве дуплика (или, при желании, удалю этот вопрос).

У меня очень простое веб-приложение, основанное на Freemarker. Эта часть работает нормально. У меня есть один метод обработчика запросов для обработки всех запросов (@RequestMapping("/**")) но хочу обслуживать статические ресурсы /${contextPath}/static/... с использованием <mvc:resources.../> объект. Ресурсы расположены в подкаталогах каталога веб-приложения верхнего уровня.

Основываясь на прочтении других вопросов по SO, я добавил

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

к моей весенней конфигурации.

Независимо от того, что я делаю, запросы, которые я ожидаю разрешить как статический файл ресурсов, вместо этого отправляются методу обработчика запросов моего контроллера. Единственное, о чем я могу думать, это то, что @RequestMapping аннотация имеет приоритет над mvc:resources, но это не имеет большого смысла.

Я проверил, что URL ресурса генерируются правильно, т.е. строка шаблона

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

генерирует

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

и запрос принимается сервером Tomcat, просто направленным в неправильное место.

Я прочитал большинство вопросов по этой теме на SO и считаю, что все делаю правильно (см., Например, Попытка получить ресурсы mvc для обслуживания моих статических ресурсов), но, очевидно, я упускаю что-то очевидное.

Среда

  • Затмение Луны
  • Java 8
  • Tomcat 8
  • Freemarker 2.3.23
  • Весна 4.2.0
  • Windows 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"/>

Весенний сервлет Конфиг

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

...
@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>
...

1 ответ

Решение

Вы дали ответ на свой вопрос: единственное, о чем я могу думать, это то, что аннотация @RequestMapping имеет приоритет над mvc:resources, но это не имеет большого смысла.

Вы можете подумать, что это не имеет смысла, но именно так Spring 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, и он работает так, как вы хотите. Но это похоже на каркас пружины, для которой он не был разработан, поэтому я не могу гарантировать, что он будет работать на других версиях.


Вы также можете сопоставить диспетчерский сервлет с / вместо /*, Таким образом будут все статические ресурсы (а также JSP), которые могут обслуживаться непосредственно контейнером сервлета. Основное предостережение, связанное с этим сопоставлением, заключается в том, что root больше не будет обслуживаться сервлетом-диспетчером Spring. Один из возможных способов это использовать /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. Как сервлет по умолчанию контейнер знает .jpeg или же .jsp файлы он поймает запрос и потерпит неудачу.

Другие вопросы по тегам