Как обрабатывать статический контент в Spring MVC?

Я разрабатываю webapp используя Spring MVC 3 и DispatcherServlet ловут все запросы к '/', как это (web.xml):

  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>

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

Теперь это работает как реклама, однако как я могу обрабатывать статический контент? Раньше, прежде чем использовать URL RESTful, я бы, например, поймал все *.html и отправил его в DispatcherServlet, но теперь это другая игра с мячом.

У меня есть/статическая/папка, которая включает /styles/,/js/,/images/etc и я хотел бы исключить /static/ * из DispatcherServlet.

Теперь я могу заставить статические ресурсы работать, когда я это сделал:

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

Но я хочу, чтобы у него были хорошие URL-адреса (точка меня с использованием Spring MVC 3), а не на целевой странице www.domain.com/app/

Я также не хочу, чтобы решение было связано с tomcat или любым другим контейнером сервлетов, и поскольку это (относительно) низкий трафик, мне не нужен веб-сервер (например, apache httpd) infront.

Есть ли для этого чистое решение?

Ответ 1

Поскольку я потратил много времени на эту проблему, я решил поделиться своим решением. Поскольку spring 3.0.4, есть параметр конфигурации, который называется <mvc:resources/> (подробнее об этом на сайте справочной документации), который может используется для обслуживания статических ресурсов, при этом все еще используется DispatchServlet для вашего сайта.

Чтобы использовать это, используйте структуру каталогов, которая выглядит следующим образом:

src/
 springmvc/
  web/
   MyController.java
WebContent/
  resources/
   img/
    image.jpg
  WEB-INF/
    jsp/
      index.jsp
    web.xml
    springmvc-servlet.xml

Содержимое файлов должно выглядеть следующим образом:

SRC/SpringMVC/веб/HelloWorldController.java:

package springmvc.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloWorldController {

 @RequestMapping(value="/")
 public String index() {
  return "index";
 }
}

WebContent/WEB-INF/web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

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

 <servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>
</web-app>

WebContent/WEB-INF/SpringMVC-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 http://www.springframework.org/schema/mvc
 http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- not strictly necessary for this example, but still useful, see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-controller for more information -->
 <context:component-scan base-package="springmvc.web" />

    <!-- the mvc resources tag does the magic -->
 <mvc:resources mapping="/resources/**" location="/resources/" />

    <!-- also add the following beans to get rid of some exceptions -->
 <bean      class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
 <bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
 </bean>

    <!-- JSTL resolver -->
 <bean id="viewResolver"
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass"
   value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
 </bean>

</beans>

WebContent/JSP/index.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h1>Page with image</h1>
<!-- use c:url to get the correct absolute path -->
<img src="<c:url value="/resources/img/image.jpg" />" />

Надеюсь, что это поможет: -)

Ответ 2

Эта проблема решена в spring 3.0.4.RELEASE, где вы можете использовать <mvc:resources mapping="..." location="..."/> конфигурационного элемента в конфигурационном файле диспетчера spring.

Отметьте Spring Документация

Ответ 3

В Spring 3.0.x добавьте следующее в ваш servlet-config.xml(файл, который настроен в web.xml как contextConfigLocation. Вам также нужно добавить пространство имен mvc, но просто Google для этого, если вы не знаю, как!;)

Это работает для меня

<mvc:default-servlet-handler/>

Привет

Аюб Малик

Ответ 4

Если я правильно понимаю вашу проблему, я думаю, что нашел решение вашей проблемы:

У меня была такая же проблема, когда был показан необработанный вывод без каких-либо CSS-стилей, javascripts или jquery файлов.

Я просто добавил сопоставления к сервлету по умолчанию. В файл web.xml добавлено следующее:

 <servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>*.css</url-pattern>
 </servlet-mapping>

 <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
 </servlet-mapping>

Это должно отфильтровывать запросы файла javascript и css из объекта DispatcherRequest.

Опять же, не уверен, что это то, что вам нужно, но это сработало для меня. Я думаю, что "default" - это имя сервлета по умолчанию в JBoss. Не слишком уверен, что это для других серверов.

Ответ 5

Там есть другой столбец переполнения, который имеет отличное решение.

Это не похоже на Tomcat, просто, и отлично работает. Я пробовал пару решений в этом сообщении с помощью spring mvc 3.1, но затем возникли проблемы с получением моего динамического содержимого.

Вкратце, он говорит, добавляет отображение сервлета, как это:

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/images/*</url-pattern>
</servlet-mapping>

Ответ 6

Я только что справился с этой проблемой в Spring MVC 3.0, и я сначала пошел с параметром UrlRewriteFilter. Однако я не был доволен этим решением, так как он "не чувствовал себя хорошо" (я не единственный), см. Ссылку выше на Spring Форумы, где слово "взломать" появляется несколько раз).

Итак, я придумал аналогичное решение для "Неизвестного (Google)", но заимствовал идею наличия всего статического контента из/static/(взятого из Spring Roo версии приложения Pet Store). Сервлет "default" не работал у меня, но Spring Webflow ResourceServlet сделал (также взятый из Spring созданного Roo-приложения).

web.xml:

<servlet>
    <servlet-name>mainDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

<servlet>
    <servlet-name>Resource Servlet</servlet-name>
    <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

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

<servlet-mapping>
    <servlet-name>Resource Servlet</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

Единственное изменение, которое я сделал для JSP, заключалось в том, чтобы добавить/static/путь к URL-адресам для CSS, JS и изображений. Например. "$ {} PageContext.request.contextPath/static/css/screen.css".

для пользователей Maven зависимость для "org.springframework.js.resource.ResourceServlet":

<dependency>
    <groupId>org.springframework.webflow</groupId>
    <artifactId>org.springframework.js</artifactId>
    <version>2.0.8.RELEASE</version>
</dependency>

Ответ 7

Я нашел способ обойти это, используя tuckey urlrewritefilter. Пожалуйста, не стесняйтесь дать лучший ответ, если он у вас есть!

В web.xml:

<filter>
    <filter-name>UrlRewriteFilter</filter-name>
    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>

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

В urlrewrite.xml:

<urlrewrite default-match-type="wildcard">
<rule>
    <from>/</from>
    <to>/app/</to>
</rule>
<rule match-type="regex">
    <from>^([^\.]+)$</from>
    <to>/app/$1</to>
</rule>
<outbound-rule>
    <from>/app/**</from>
    <to>/$1</to>
</outbound-rule>    

Это означает, что любой uri с '.' в нем (например, style.css) не будет переписываться.

Ответ 8

Мой собственный опыт с этой проблемой заключается в следующем. Большинство Spring связанных веб-страниц и книг, похоже, предполагают, что наиболее подходящий синтаксис следующий.

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

В приведенном выше синтаксисе вы можете разместить свои статические ресурсы (CSS, JavaScript, изображения) в папке с именем "resources" в корне вашего приложения, то есть /webapp/resources/.

Однако, по моему опыту (я использую Eclipse и плагин Tomcat), единственный подход, который работает, заключается в том, что вы размещаете свою папку ресурсов внутри WEB_INF (или META-INF). Итак, рекомендуемый синтаксис следующий.

    <mvc:resources mapping="/resources/**" location="/WEB-INF/resources/" />

В вашем JSP (или аналогичном) ссылайтесь на ресурс следующим образом.

<script type="text/javascript"
        src="resources/my-javascript.js">
</script>

Излишне говорить, что весь вопрос возник только потому, что я хотел, чтобы мой диспетчер серфинга Spring (фронт-контроллер) перехватил все, все динамическое. Поэтому в моем web.xml есть следующее.

<servlet>
    <servlet-name>front-controller</servlet-name>
    <servlet-class>
                org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    <!-- spring automatically discovers /WEB-INF/<servlet-name>-servlet.xml -->
</servlet>

<servlet-mapping>
    <servlet-name>front-controller</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Наконец, поскольку я использую текущие лучшие практики, у меня есть следующее в моем сервлет-контроллере xml (см. выше).

<mvc:annotation-driven/>

И у меня есть следующая в моей фактической реализации контроллера, чтобы убедиться, что у меня есть метод по умолчанию для обработки всех входящих запросов.

@RequestMapping("/")

Надеюсь, это поможет.

Ответ 9

У меня такая же проблема, и я нашел ответ Йориса очень полезным. Но дополнительно мне нужно добавить

<mvc:annotation-driven /> 

в конфигурационный файл сервлета. Без этого сопоставление ресурсов не будет работать, и все обработчики перестанут работать. Надеюсь, это поможет кому-то.

Ответ 10

URLRewrite - это своего рода "хак", если вы хотите его назвать. Что это значит, вы изобретаете колесо; так как есть уже существующие решения. Еще одна вещь, которую следует помнить, - Http Server = Статический контент и сервер приложений = динамический контент (так они были разработаны). Делегируя соответствующие обязанности каждому серверу, вы максимизируете эффективность... но сейчас это, вероятно, всего лишь проблема в критически важных средах, и что-то вроде Tomcat, скорее всего, будет хорошо работать в обеих ролях большую часть времени; но это все равно что-то иметь в виду, тем не менее.

Ответ 11

Я решил это так:

<servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>

Это работает на Tomcat и, конечно же, на Jboss. Однако в конце я решил использовать решение Spring предоставляет (как упоминалось rozky), который гораздо более портативен.

Ответ 12

Из Spring 3 все ресурсы должны отображаться по-другому. Вы должны использовать тег, чтобы указать расположение ресурсов.

Пример:

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

Таким образом, вы направляете сервлет диспетчера для поиска в ресурсах каталога для поиска статического содержимого.

Ответ 13

Мой способ решения этой проблемы заключается в размещении всех ваших действий с определенным префиксом, таким как "web" или "service", и настроить, чтобы весь URL-адрес с этим префиксом был перехвачен DispatcherServlet.

Ответ 14

Я просто добавлю три правила до spring правила по умолчанию (/**), чтобы tuckey urlrewritefilter (urlrewrite.xml) решить проблему

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN" "http://tuckey.org/res/dtds/urlrewrite3.0.dtd">
    <urlrewrite default-match-type="wildcard">
     <rule>
      <from>/</from>
      <to>/app/welcome</to>
     </rule>
     <rule>
      <from>/scripts/**</from>
      <to>/scripts/$1</to>
     </rule>
     <rule>
      <from>/styles/**</from>
      <to>/styles/$1</to>
     </rule>
     <rule>
      <from>/images/**</from>
      <to>/images/$1</to>
     </rule>
     <rule>
      <from>/**</from>
      <to>/app/$1</to>
     </rule>
     <outbound-rule>
      <from>/app/**</from>
      <to>/$1</to>
     </outbound-rule> 
    </urlrewrite>

Ответ 15

Я знаю, что есть несколько конфигураций для использования статического содержимого, но мое решение заключается в том, что я просто создаю папку большого веб-приложения в вашем tomcat. Этот "bulk webapp" обслуживает только статическое содержимое без обслуживания приложений. Это безболезненное и простое решение для обслуживания статического содержимого вашего фактического веб-приложения spring.

Например, я использую две папки webapp на моем tomcat.

  • springapp: он работает только с веб-приложением spring без статического содержимого, такого как imgs, js или css. (выделено для приложений spring.)
  • ресурсы: он обслуживает только статическое содержимое без JSP, сервлета или любого вида веб-приложения java. (посвященный статическому содержимому)

Если я хочу использовать javascript, я просто добавляю URI для своего javascript файла.

EX > /resources/path/to/js/myjavascript.js

Для статических изображений, я использую тот же метод.

EX > /resources/path/to/img/myimg.jpg

Наконец, я поставил " security-constraint" на моем tomcat, чтобы заблокировать доступ к фактическому каталогу. Я помещал "никто" в список ограничений, чтобы страница генерировала "запрещенную ошибку 403", когда люди пытались получить доступ к пути статического содержимого.

Пока это работает очень хорошо для меня. Я также заметил, что многие популярные сайты, такие как Amazon, Twitter и Facebook, используют разные URI для обслуживания статического содержимого. Чтобы узнать это, просто щелкните правой кнопкой мыши на любом статическом содержимом и проверьте их URI.

Ответ 16

Я использовал оба способа - urlrewrite и аннотацию, основанную на spring mvc 3.0.x, и нашел, что подход на основе аннотации наиболее подходит, который

<annotation-driven />

<resources mapping="/resources/**" location="/resources/" />

В случае urlrewrite, нужно определить множество правил и некоторое время также получить исключение класса, не найденное для UrlRewriteFilter, поскольку уже предоставило ему зависимость. Я обнаружил, что это происходит из-за наличия транзитивной зависимости, поэтому снова один шаг будет увеличен и должен исключить эту зависимость от pom.xml с помощью

<exclusion></exclusion> tags.

Такой подход, основанный на аннотации, будет хорошим делом.

Ответ 17

Это сделало реальную работу в моем случае

в web.xml:

...
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/images/*</url-pattern>
    <url-pattern>/css/*</url-pattern>
    <url-pattern>/javascripts/*</url-pattern>
</servlet-mapping>


<servlet-mapping>
    <servlet-name>spring-mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

...

Ответ 18

После того, как вы столкнулись с одним и тем же процессом принятия решений, описанным здесь, я решил пойти с предложением ResourceServlet, которое работает очень хорошо.

Обратите внимание, что вы получаете больше информации о том, как использовать веб-поток в процессе сборки maven здесь: http://static.springsource.org/spring-webflow/docs/2.0.x/reference/html/ch01s05.html

Если вы используете стандартный центральный репозиторий Maven, артефакт (в противоположность вышеупомянутому расслоению springsource):

<dependency>
    <groupId>org.springframework.webflow</groupId>
    <artifactId>spring-js</artifactId>
    <version>2.0.9.RELEASE</version>
</dependency> 

Ответ 19

Это может быть достигнуто, по крайней мере, тремя способами.

Решения

  • выставить html в качестве файла ресурсов
  • поручить JspServlet также обрабатывать запросы *.html
  • напишите свой собственный сервлет (или перейдите к другим существующим запросам сервлетов в *.html).

Для получения полного кода примера, как это сделать, пожалуйста, обратитесь к моему ответу в другом сообщении: Как сопоставить запросы к HTML файлу в Spring MVC?

Ответ 20

Проблема связана с URLPattern

Измените свой шаблон URL-адреса на вашем сервлет-сопоставлении с "/" на "/*"

Ответ 21

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:default-servlet-handler/>
</beans>

и если вы хотите использовать настройку на основе аннотации, используйте код ниже

@Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

Ответ 22

Для java-конфигурации spring вы можете использовать следующие

Используя ResourceHandlerRegistry, который хранит регистрацию обработчиков ресурсов для обслуживания статических ресурсов.

Дополнительная информация @WebMvcConfigurerAdapter, которая определяет методы обратного вызова для настройки конфигурации на Java для spring MVC с помощью @EnableWebMvc.

@EnableWebMvc
@Configurable
@ComponentScan("package.to.scan")
public class WebConfigurer extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static_resource_path/*.jpg").addResourceLocations("server_destination_path");

    }