如何在Spring MVC中处理静态内容?

时间:2009-09-27 07:54:09

标签: spring-mvc

我正在使用Spring MVC 3开发一个webapp并让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>

现在这可以像宣传的那样工作,但是我如何处理静态内容呢?以前,在使用RESTful URL之前,我会抓住所有* .html并将其发送到DispatcherServlet,但现在它是一个不同的球赛。

我有一个/ static /文件夹,其中包含/ styles /,/ js /,/ images / etc,我想从DispatcherServlet中排除/ static / *。

现在,当我这样做时,我可以获得静态资源:

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

但是我希望它有很好的网址(我使用Spring MVC 3)而不是登陆页面www.domain.com/app /

我也不希望解决方案耦合到tomcat或任何其他servlet容器,并且因为这是(相对)低流量我不需要网络服务器(如apache httpd)infront。

这有一个干净的解决方案吗?

23 个答案:

答案 0 :(得分:259)

由于我花了很多时间在这个问题上,我以为我会分享我的解决方案。从Spring 3.0.4开始,有一个名为<mvc:resources/>的配置参数(更多关于reference documentation website的配置参数),可用于提供静态资源,同时仍然使用站点根目录上的DispatchServlet。 / p>

要使用此功能,请使用如下所示的目录结构:

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" />" />

希望这会有所帮助: - )

答案 1 :(得分:47)

这个问题在Spring 3.0.4.RELEASE中可以解决 <mvc:resources mapping="..." location="..."/> spring调度程序配置文件中的配置元素。

检查Spring Documentation

答案 2 :(得分:38)

在Spring 3.0.x中,将以下内容添加到您的servlet-config.xml(在web.xml中配置为contextConfigLocation的文件。您还需要添加mvc名称空间,但只要谷歌,如果你不这样做我知道怎么做!;)

这对我有用

<mvc:default-servlet-handler/>

此致

Ayub Malik

答案 3 :(得分:19)

如果我理解你的问题,我认为我找到了解决问题的方法:

我遇到了同样的问题,其中显示的原始输出没有找到css样式,javascripts或jquery文件。

我刚刚将映射添加到“默认”servlet中。以下内容已添加到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>

这应该过滤掉DispatcherRequest对象的javascript和css文件请求。

再次,不确定这是否是你所追求的,但它对我有用。我认为“default”是JBoss中默认servlet的名称。不太清楚其他服务器是什么。

答案 4 :(得分:15)

另一个堆栈溢出帖子有excellent solution

它似乎没有特定的Tomcat,简单,效果很好。我已经使用spring mvc 3.1在这篇文章中尝试了几个解决方案但是在提供我的动态内容方面遇到了问题。

简而言之,它表示添加这样的servlet映射:

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

答案 5 :(得分:12)

我刚刚在Spring MVC 3.0中解决了这个问题,我最初选择了UrlRewriteFilter选项。但是我对这个解决方案并不满意,因为它“感觉不对”(我不是唯一一个 - 请参阅弹簧论坛上面的链接,其中“hack”一词出现几次)。

所以我想出了一个类似于上面“未知(谷歌)”的解决方案,但借用了从/ static /(取自Pet Store应用程序的Spring Roo版本)提供的所有静态内容的想法。 “默认”servlet对我来说不起作用,但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所做的唯一改变是为CSS,JS和图像的URL添加/ static / path。例如。 “$ {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>

答案 6 :(得分:11)

我找到了一种方法,使用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)将不会被重写。

答案 7 :(得分: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调度程序servlet(前端控制器)拦截所有内容,一切都是动态的,即。所以我的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>

最后,因为我正在使用当前的最佳实践,所以我的前端控制器servlet xml中有以下内容(见上文)。

<mvc:annotation-driven/>

我在实际的控制器实现中有以下内容,以确保我有一个默认方法来处理所有传入的请求。

@RequestMapping("/")

我希望这会有所帮助。

答案 8 :(得分:6)

我遇到了同样的问题,发现Joris的回答很有帮助。但另外我需要添加

<mvc:annotation-driven /> 

到servlet配置文件。如果没有该资源映射将无法工作,所有处理程序将停止工作。希望这会对某人有所帮助。

答案 9 :(得分:2)

如果要调用它,URLRewrite就是一种“黑客”。它归结为,你正在重新发明轮子;因为已有解决方案。要记住的另一件事是Http Server = Static content&amp; App server =动态内容(这就是它们的设计方式)。通过将适当的职责委派给每个服务器,您可以最大限度地提高效率......但是现在这一天可能只是性能关键环境中的一个问题,而Tomcat在大多数情况下最有可能在这两个角色中都能正常工作。但是仍然要记住这一点。

答案 10 :(得分:2)

从Spring 3开始,所有资源都需要以不同的方式进行映射。您需要使用标记来指定资源的位置。

示例:

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

通过这种方式,您将指示调度程序servlet查看目录资源以查找静态内容。

答案 11 :(得分:2)

我这样解决了:

<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 provides(如rozky所述)。

答案 12 :(得分:1)

我解决此问题的方法是将所有操作都放在特定前缀(如“web”或“service”)上,并配置所有带有该前缀的URL将被DispatcherServlet截获。

答案 13 :(得分:1)

对于基于java的弹簧配置,您可以使用以下

使用ResourceHandlerRegistry存储资源处理程序的注册以提供静态资源。

更多信息@ WebMvcConfigurerAdapter定义了回调方法,以通过@EnableWebMvc自定义Spring MVC的基于Java的配置。

@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");

    }

答案 14 :(得分:1)

在我的案例中,这确实起了作用

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>

...

答案 15 :(得分:1)

我使用了两种方式,即基于spring mvc 3.0.x的urlrewrite和annotation,并发现基于注释的方法最适合

<annotation-driven />

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

在urlrewrite的情况下,必须定义大量的规则,并且有时也会为UrlRewriteFilter获取类找不到异常,因为已经为它提供了依赖性。   我发现由于存在传递依赖性而发生这种情况,因此再一步将增加并且必须使用

从pom.xml中排除该依赖性
<exclusion></exclusion> tags.

因此,基于注释的方法将是一个很好的协议。

答案 16 :(得分:1)

我知道有一些配置可以使用静态内容,但我的解决方案是我只是在tomcat中创建一个批量Web应用程序文件夹。此“批量网络应用程序”仅在不提供应用程序的情况下提供所有静态内容。这是为您的实际弹簧webapp提供静态内容的无痛且简单的解决方案。

例如,我在tomcat上使用了两个webapp文件夹。

  1. springapp :它只运行没有像imgs,js或css这样的静态内容的spring web应用程序。 (专用于春季应用程序。)
  2. 资源:它只提供没有JSP,servlet或任何类型的Java Web应用程序的静态内容。 (专用于静态内容)
  3. 如果我想使用javascript,我只需添加我的javascript文件的URI。

    EX&GT;的 /resources/path/to/js/myjavascript.js

    对于静态图像,我使用相同的方法。

    EX&GT; /resources/path/to/img/myimg.jpg

    最后,我在tomcat上添加了“ security-constraint ”来阻止访问实际目录。 我将“nobody”用户滚动到约束,以便当人们尝试访问静态内容路径时页面生成“403禁止错误”。

    到目前为止,它对我来说非常有效。我还注意到许多流行的网站,如亚马逊,Twitter和Facebook,他们使用不同的URI来提供静态内容。要找到这一点,只需右键单击任何静态内容并检查其URI。

答案 17 :(得分:1)

我只需在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>

答案 18 :(得分:0)

这可以通过至少三种方式实现。

<强>解决方案

  • 将html公开为资源文件
  • 指示JspServlet也处理* .html请求
  • 编写自己的servlet(或传递给另一个现有的servlet请求* .html)。

有关完整的代码示例如何实现此目的,请在另一篇文章中回答我的回答:How to map requests to HTML file in Spring MVC?

答案 19 :(得分:0)

问题在于URLPattern

将servlet映射上的URL模式从“/”更改为“/ *”

答案 20 :(得分:0)

<?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();
    }

答案 21 :(得分:0)

在遇到并经历了此处描述的相同决策制定过程后,我决定采用ResourceServlet提案,该提案非常有效。

请注意,您可以在此处获取有关如何在maven构建过程中使用webflow的更多信息:http://static.springsource.org/spring-webflow/docs/2.0.x/reference/html/ch01s05.html

如果使用标准Maven中央存储库,则工件(与上面提到的泉源包相反):

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

答案 22 :(得分:0)

将静态内容(如css,js)放在以下路径中

resources 
        ->static
               ->css
               ->js
(or) 
resources 
        ->public
               ->css
               ->js