在/ *上映射全局前端控制器servlet时如何访问静态资源

问题描述 投票:57回答:18

我已将Spring MVC调度程序映射为/*上的全局前端控制器servlet。

<servlet>       
  <servlet-name>home</servlet-name>         
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>     
</servlet>  
<servlet-mapping>       
  <servlet-name>home</servlet-name>         
  <url-pattern>/*</url-pattern>     
</servlet-mapping>

但是,此映射会停止访问CSS,JS,图像等静态文件,这些文件都位于/res/文件夹中。

我怎么能访问它们?

java servlets resources
18个回答
12
投票

我也遇到过这种情况,从未找到过很好的解决方案。我最终将我的servlet映射到URL层次结构中的更高级别:

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

现在,您的容器可以提供基本上下文(以及您的/ res目录中)的所有内容。


2
投票

处理此问题的最佳方法是使用某种URL重写。通过这种方式,您可以拥有干净的restful URL,而不是任何扩展名,即abc.com/welcom/register,而不是abc.com/welcome/resister.html

我使用非常酷的Tuckey URL

它有关于如何设置您的Web应用程序的说明。我已经使用我的Spring MVC Web应用程序进行了设置。当然,一切都很好,直到我想对@Email@Null这样的Spring 3验证使用注释作为域对象。

当我添加Spring mvc指令时:

< mvc:annotation-driven  /> 
< mvc:default-servlet-handler />

..它打破了好的ol Tuckey代码。显然,< mvc:default-servlet-handler />取代了Tuckey,我仍然试图解决这个问题。


1
投票

将您不想触发servlet处理的文件夹添加到appengine-web.xml文件的<static-files>部分。

我只是这样做,看起来事情开始正常。这是我的结构:

/

/pages/<.jsp文件>

/ CSS

我将“/ pages / **”和“/ css / **”添加到<static-files>部分,现在我可以从servlet doGet中转发到.jsp文件,而不会导致无限循环。


1
投票

尝试过滤器方法后没有成功(由于某些原因没有进入doFilter()函数)我改变了我的设置并找到了一个非常简单的解决根服务问题的方法:

我现在只收听专用语言前缀“EN”,“EN / *”,“DE”,“DE / *”,而不是在主Servlet中提供“/ *”。

静态内容由默认的Servlet提供,空的根请求转到index.jsp,它使用默认语言调用我的主Servlet:

<jsp:include page =“/ EN /”/>(索引页面上没有其他内容。)


1
投票

我发现使用了

<mvc:default-servlet-handler />

在Spring中,MVC servlet bean定义文件适合我。它将未注册的MVC控制器处理的任何请求传递给容器的原始默认处理程序,该处理程序应将其作为静态内容提供。只要确保没有注册的控制器可以处理所有内容,它应该可以正常工作。不确定为什么@logixplayer会建议重写URL;你可以单独使用Spring MVC来实现他正在寻找的效果。


0
投票

我建议尽可能尝试使用Filter而不是默认的servlet。

其他两种可能性:

自己编写FileServlet。你会发现很多例子,它应该只是通过URL打开文件并将其内容写入输出流。然后,使用它来提供静态文件请求。

当您需要在给定URL上提供静态文件时,实例化Google App Engine使用的FileServlet类并在该FileServlet上调用服务(请求,响应)。

您可以将/ res / *映射到YourFileServlet或从DispatcherServlets处理中将其排除,或直接从DispatcherServlet调用它。

而且,我不得不问,Spring文档对这次碰撞有什么看法?我从来没用过它。


0
投票

我发现了一个带有虚拟索引文件的简单解决方案。

创建一个Servlet(或使用你想要响应的“/”),它映射到“/index.html”(这里提到的解决方案使用XML映射,我使用带有注释@WebServlet的3.0版本)然后创建一个静态(空)文件名为“index.html”的静态内容的根目录

我使用Jetty,发生的事情是服务器识别文件而不是列出目录,但是当被要求提供资源时,我的Servlet取而代之。所有其他静态内容不受影响。


0
投票

在Embedded Jetty中,我设法通过在web.xml中为“css”目录添加映射来实现类似的功能。明确告诉它使用DefaultServlet:

<servlet>
  <servlet-name>DefaultServlet</servlet-name>
  <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>DefaultServlet</servlet-name>
  <url-pattern>/css/*</url-pattern>
</servlet-mapping>

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

0
投票

关于Tomcat,很大程度上取决于特定的版本。有一个错误修复https://bz.apache.org/bugzilla/show_bug.cgi?id=50026,这意味着默认servlet的servlet映射(除了'/'除外)在Tomcat 6.0.29(及更早版本)中与后续版本相比表现不同。


71
投票

将控制器servlet映射到更具体的url-pattern,如/pages/*,将静态内容放在/static等特定文件夹中,并创建一个Filter监听/*,它透明地继续链接任何静态内容,并将请求发送到控制器servlet以获取其他内容。

简而言之:

<filter>
    <filter-name>filter</filter-name>
    <filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>controller</servlet-name>
    <servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>controller</servlet-name>
    <url-pattern>/pages/*</url-pattern>
</servlet-mapping>

在过滤器的doFilter()中有以下内容:

HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/static")) {
    chain.doFilter(request, response); // Goes to default servlet.
} else {
    request.getRequestDispatcher("/pages" + path).forward(request, response);
}

不,这不会以浏览器地址栏中的/pages结束。它是完全透明的。你可以根据需要使"/static"和/或"/pages"成为过滤器的init-param


43
投票

使用Spring 3.0.4.RELEASE和更高版本,您可以使用

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

正如Spring Reference所见。


19
投票

您要做的是在web.xml中添加一个欢迎文件

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

然后将其添加到servlet映射中,以便当有人转到应用程序的根目录时,它们会在内部发送到index.html,然后映射将在内部将它们发送到您将其映射到的servlet

<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/main</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/index.html</url-pattern>
</servlet-mapping>

最终结果:您访问/应用程序,但在不中断任何其他根请求的情况下,您将看到/ Application / MainActions servlet。

得到它?因此,您的应用仍然位于子网址,但在用户访问您网站的根目录时会自动显示。这允许您将/images/bob.img仍然转到常规位置,但“/”是您的应用。


17
投票

如果使用Tomcat,则可以将资源映射到缺省servlet:

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

并使用url http:// {context path} / static / res / ...访问您的资源

也适用于Jetty,不确定其他servlet容器。


16
投票

在多个servlet映射定义中使用适当的后缀提供静态内容解决了其中一个答案中的一个注释中提到的安全问题。引用如下:

这是Tomcat中的一个安全漏洞(WEB-INF和META-INF内容可以通过这种方式访问​​),它已在7.0.4中修复(并将被移植到5.x和6.x)。 - BalusC 2010年11月2日22:44

这对我帮助很大。以下是我如何解决它:

<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>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>

9
投票

从3.0.4开始,您应该能够将mvc:resourcesmvc:default-servlet-handler结合使用,如Spring文档中所述,以实现此目的。

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources


5
投票

发生冲突的原因似乎是因为,默认情况下,上下文根“/”将由org.apache.catalina.servlets.DefaultServlet处理。此servlet旨在处理对静态资源的请求。

如果你决定用你自己的servlet来阻止它,为了处理动态请求,那个顶级servlet也必须执行catalina最初的“DefaultServlet”处理程序完成的任何任务。

如果您阅读tomcat文档,他们会提到True Apache(httpd)比Apache Tomcat更好地处理静态内容,因为它是专门为此而构建的。我的猜测是因为Tomcat默认使用org.apache.catalina.servlets.DefaultServlet来处理静态请求。由于它全部包含在JVM中,并且Tomcat旨在作为Servlet / JSP容器,因此它们可能不会将该类编写为超级优化的静态内容处理程序。在那。它完成了工作。够好了。

但这是处理静态内容的东西,它生活在“/”。因此,如果您在那里放置任何其他东西,并且该东西不处理静态请求,WHOOPS,那就是您的静态资源。

我一直在寻找相同答案的高低,我到处得到的答案是“如果你不想这样做,就不要那样做”。

总而言之,您的配置正在取代默认的静态资源处理程序,而不是静态资源处理程序。您需要尝试不同的配置来获得您正在寻找的结果(我也一样)。


3
投票

您的应用无法直接访问App Engine中的“静态”文件。您需要上传两次,或者自己提供静态文件,而不是使用静态处理程序。

© www.soinside.com 2019 - 2024. All rights reserved.