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
файлы он поймает запрос и потерпит неудачу.