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

у меня есть /static/ папка, которая включает/ 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.

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

22 ответов


поскольку я потратил много времени на эту проблему, я подумал, что поделюсь своим решением. С весны 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/web / 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-сервлет.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" />" />

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


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

Регистрация Весна Документации


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

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

<mvc:default-servlet-handler/>

в отношении

Аюб Малик


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

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

Я просто добавил сопоставления в сервлет" по умолчанию". В Сеть было добавлено следующее.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. Не слишком уверен, что это для других серверов.


есть еще одна запись переполнения стека, которая имеет отличное решение.

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

вкратце, он говорит добавить сопоставление сервлетов, как это:

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

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

поэтому я придумал аналогичное решение для "неизвестного (Google)" выше, но позаимствовал идею того, что все статическое содержимое обслуживается из /static/ (взято из версии Spring Roo Pet Store app). Сервлет "по умолчанию" не работал для меня, но 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>

единственное изменение, которое я сделал в JSPs, - это добавить /static / path к URL-адресам для CSS, JS и изображений. Е. Г. "${pagecontext, который.запрос.contextPath} / static / css / screen.стиль CSS."

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

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

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

в интернете.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/</to>
</rule>
<outbound-rule>
    <from>/app/**</from>
    <to>/</to>
</outbound-rule>    

это означает, что любой uri с a '.'in it (like style.css, например) не будет переписан.


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

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

приведенный выше синтаксис предполагает, что вы можете разместить свои статические ресурсы (CSS, JavaScript, изображения) в папке с именем "ресурсы" в корне вашего приложения, т. е. /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>

излишне упоминать, что весь вопрос возник только потому, что я хотел, чтобы мой весенний диспетчерский сервлет (передний контроллер) перехватывал все, все динамическое, то есть. Итак, у меня есть следующее В моей паутине.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>

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

<mvc:annotation-driven/>

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

@RequestMapping("/")

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


Я получил ту же проблему и нашел ответ Джориса очень полезным. Но дополнительно мне нужно добавить

<mvc:annotation-driven /> 

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


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


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

<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. Однако в конце концов я решил использовать решение пружина обеспечивает (как упоминалось rozky), который является гораздо более портативным.


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

пример :

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

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


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


Я просто добавляю три правила перед весенним правилом по умолчанию ( / * * ) к urlrewritefilter tuckey (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/</to>
     </rule>
     <rule>
      <from>/styles/**</from>
      <to>/styles/</to>
     </rule>
     <rule>
      <from>/images/**</from>
      <to>/images/</to>
     </rule>
     <rule>
      <from>/**</from>
      <to>/app/</to>
     </rule>
     <outbound-rule>
      <from>/app/**</from>
      <to>/</to>
     </outbound-rule> 
    </urlrewrite>

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

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

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

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

EX> / ресурсы / путь/к/js / myjavascript.js

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

EX> / ресурсы / путь/к / img / myimg.формат JPG

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

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


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

<annotation-driven />

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

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

<exclusion></exclusion> tags.

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


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

в интернете.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>

...


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

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

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

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

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

решений:

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

для полных примеров кода, как достичь этого, пожалуйста, ответьте на мой ответ в другом посте:как сопоставить запросы в HTML-файл весной В MVC?


проблема с URLPattern

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


<?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>

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

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

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

С помощью 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");

    }