ChatGPT解决这个技术问题 Extra ChatGPT

如何处理 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/ 等,我想从 DispatcherServlet 中排除 /static/*。

现在,当我这样做时,我可以让静态资源正常工作:

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

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

我也不想要与 tomcat 或任何其他 servlet 容器耦合的解决方案,因为这是(相对)低流量,我不需要前端的网络服务器(如 apache httpd)。

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


N
Nimantha

由于我在这个问题上花了很多时间,我想我会分享我的解决方案。从 spring 3.0.4 开始,有一个名为 <mvc:resources/> 的配置参数(有关 reference documentation website 的更多信息)可用于提供静态资源,同时仍使用站点根目录上的 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";
 }
}

网页内容/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>

网页内容/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>

网页内容/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" />" />

这个例子应该在 Spring 用户指南中——这是我在这个主题上看到的最好的。谢谢乔里斯!
这对我来说确实有用——只是 rozky 的建议是我开始做的,但由于某种原因,除了我的主页之外,任何页面都在渲染相对于页面的资源 URL——遵循这个建议会使它们相对改为我的应用程序的上下文根 - 并且完美运行!谢谢!
谢谢!我一直在拔头发,直到我改变了这一行:
正如@Bane 指出的那样, 是该解决方案的关键部分。你(或任何人)介意告诉我为什么吗?谢谢!
您也可以使用 并将其映射到根目录。 (即:根将包含资源和 jsps)。这可以节省您在任何地方使用 c:url
r
rozky

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

检查Spring Documentation


虽然实际上并不是“错误”,但这个答案太简短了,因为 Spring 自己的文档(您将其引用为您的答案)似乎遗漏了一些东西。检查 Joris 的答案以获得更完整的答案......不是它很长的事实,而是他提到使用 的事实,你的答案和 Spring 的 dox 都没有提到 - 事实证明成为解决方案的关键部分。
N
Nimantha

在 Spring 3.0.x 中,将以下内容添加到您的 servlet-config.xml(在 web.xml 中配置为 contextConfigLocation 的文件。您还需要添加 mvc 命名空间,但如果您不知道如何添加,只需 Google 即可!

这对我行得通

<mvc:default-servlet-handler/>

当我添加这一行时,我得到: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:来自类路径资源 [META-INF/spring/application-context.xml] 的 XML 文档中的第 31 行无效;嵌套异常是 org.xml.sax.SAXParseException;行号:31;列号:35; cvc-complex-type.2.4.c:匹配通配符是严格的,但找不到元素“mvc:default-servlet-handler”的声明。
当您还有其他一些视图解析器时,请务必处理处理程序的顺序。
u
user243397

如果我正确理解您的问题,我想我已经找到了解决您问题的方法:

我遇到了同样的问题,原始输出显示没有找到 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 文件请求。

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


我实际上不想使用默认的 servlet——它将我与 jboss/tomcat 结合起来
@hamo 为什么这是个问题? (这是一个真正的问题,而不是一个有争议的反驳)。无论如何,您都需要运行服务器(jboss/tomcat/jetty)才能运行spring,对吗?
您可以在同一个 <servlet-mapping> 中添加所有 <url-pattern> 标签
C
Community

还有另一个具有 excellent solution 的堆栈溢出帖子。

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

简而言之,它说添加一个像这样的 servlet 映射:

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

h
hamo

我使用 tukey 的 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 )不会被重写。


正如@Joris 所展示的,更好的答案是 Spring 3 的 <mvc:resources/>
n
nickdos

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

所以我想出了一个与上面的“Unknown (Google)”类似的解决方案,但是借用了从 /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 所做的唯一更改是将 /static/ 路径添加到 CSS、JS 和图像的 URL。例如“${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>

不错的解决方案 nickdos - 谢谢!我仍然不“明白”为什么核心 spring mvc 中没有资源 servlet(而不是必须使用 web 流添加另一个依赖项)或其他一些开箱即用的解决方案。 Urlrewrite 对我来说很好,所以我会暂时坚持下去!干杯,哈莫
回顾 Spring Pet Clinic 应用程序的标准(非 Roo)版本,我注意到“默认”的 servlet 定义被注释掉并带有附加注释:“在未声明的容器 (GlassFish) 中取消注释开箱即用的隐含定义”。默认的显式包声明是 org.apache.catalina.servlets.DefaultServlet。所以这可能是您的“开箱即用”资源 servlet(?)。我使用 Jetty 进行开发工作,但似乎 Jetty 不提供隐式默认 servlet(如 Glassfish)。
N
Nimantha

我自己对这个问题的经验如下。大多数与 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("/")

这是唯一对我有用的解决方案。我注意到的一件有趣的事情是,在我启动 webapp 之后添加的新资源直到重新启动才被发现。从用户的角度来看没有意义,但大多数时候不应该是一个主要问题。
你用 Tomcat 的视角说的,太棒了:)
我尝试了此页面上的每个答案。谢天谢地,当我到达这个时,我不必再尝试了。
N
Nimantha

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

<mvc:annotation-driven /> 

到 servlet 配置文件。没有该资源映射将无法工作,所有处理程序都将停止工作。


B
BreakerOfStones

如果您想这样称呼它,则 URLRewrite 有点像“黑客”。归根结底,您是在重新发明轮子;因为已经有现有的解决方案。要记住的另一件事是 Http 服务器 = 静态内容 & 应用服务器 = 动态内容(这就是它们的设计方式)。通过将适当的职责委派给每台服务器,您可以最大限度地提高效率......但现在这可能只是性能关键环境中的一个问题,并且像 Tomcat 这样的东西很可能在大部分时间都可以很好地工作;但仍然需要牢记这一点。


C
Chepech

我是这样解决的:

<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 所述)。


R
Ruju

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

<annotation-driven />

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

在 urlrewrite 的情况下,必须定义大量规则,并且有时还会为 UrlRewriteFilter 获取类未找到异常,因为已经为其提供了依赖项。我发现这是由于传递依赖的存在而发生的,因此将再次增加一步,并且必须使用从 pom.xml 中排除该依赖

<exclusion></exclusion> tags.

因此,基于注释的方法将是不错的选择。


B
Balasubramanian Jayaraman

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

例子 :

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

通过这样做,您可以指示调度程序 servlet 查看目录资源以查找静态内容。


T
Teja Kantamneni

我解决这个问题的方法是把你的所有动作都加上一个特定的前缀,比如“web”或“service”,并配置所有带有该前缀的 url 都将被 DispatcherServlet 拦截。


P
Pablo Cantero

我只是在tukey的urlrewritefilter(urlrewrite.xml)的spring默认规则(/**)前添加三个规则来解决问题

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

0
0DayHack

我知道有一些配置可以使用静态内容,但我的解决方案是我只是在你的 tomcat 中创建一个批量 web-application 文件夹。这个“批量网络应用程序”只提供所有静态内容而不提供应用程序。这是为您的实际 spring webapp 提供静态内容的轻松且简单的解决方案。

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

springapp:它只运行 spring web 应用程序,没有像 imgs、js 或 css 这样的静态内容。 (专用于 spring 应用程序。)资源:它只提供静态内容,没有 JSP、servlet 或任何类型的 java web 应用程序。 (专用于静态内容)

如果我想使用 javascript,我只需为我的 javascript 文件添加 URI。

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

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

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

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

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


J
Jorge Sanchez

在我的情况下,这做了真正的工作

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

...


V
Vipul Panth

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

使用 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");

    }

n
ngeek

在遇到并经历了这里描述的相同决策过程之后,我决定采用效果很好的 ResourceServlet 提案。

请注意,您可以在此处获得有关如何在 maven 构建过程中使用 webflow 的更多信息: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> 

C
Community

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

解决方案:

将 html 公开为资源文件

指示 JspServlet 也处理 *.html 请求

编写您自己的 servlet(或将请求传递给另一个现有的 servlet 到 *.html)。

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


A
Asif Malek

问题在于 URLPattern

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


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

b
barbsan

将 css 、js 等静态内容放在以下路径中

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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅