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

时间:2009-05-15 18:23:40

标签: java servlets resources

我已将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/文件夹中。

我怎样才能访问它们?

19 个答案:

答案 0 :(得分:70)

将控制器servlet映射到更具体的url-pattern /pages/*上,将静态内容放在/static等特定文件夹中,并在{{1}上创建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"

答案 1 :(得分:43)

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

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

Spring Reference中所示。

答案 2 :(得分: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仍然去常规地方,但'/'是你的应用程序。

答案 3 :(得分:17)

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

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

并使用网址http:// {context path} / static / res /...

访问您的资源

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

答案 4 :(得分: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>

答案 5 :(得分:12)

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

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

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

答案 6 :(得分: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

答案 7 :(得分: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,那就是您的静态资源。

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

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

答案 8 :(得分:3)

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

答案 9 :(得分: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 />

..它打破了好的Tuckey代码。显然,< mvc:default-servlet-handler />取代了Tuckey,我仍在努力解决。

答案 10 :(得分:1)

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

我刚刚做了这件事,看起来事情开始好起来了。这是我的结构:

/

/pages/<.jsp文件&gt;

/ CSS

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

答案 11 :(得分:1)

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

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

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

  

&LT; jsp:include page =“/ EN /”/&gt;   (索引页面上没有其他内容。)

答案 12 :(得分:1)

我发现使用

<mvc:default-servlet-handler />
春天MVC servlet bean定义文件中的

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

答案 13 :(得分:0)

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

其他两种可能性:

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

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

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

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

答案 14 :(得分:0)

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

创建一个Servlet(或使用你想要响应的那个“/​​”),它映射到“/index.html” (这里提到的解决方案使用XML映射,我使用带有注释@WebServlet的3.0版本) 然后在名为“index.html”

的静态内容的根目录下创建一个静态(空)文件

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

答案 15 :(得分:0)

在嵌入式Jetty中,我设法通过为&#34; css&#34;添加映射来实现类似的功能。 web.xml中的目录。明确告诉它使用DefaultServlet:

(function(angular) {
  'use strict';
  angular.module('docsTemplateUrlDirective', [])
    .controller('Controller', ['$scope', '$compile',
      function($scope, $compile) {
        $scope.names = [{
          'name': '1',
          'tmpl': 'my-tmpl1'
        }, {
          'name': '2',
          'tmpl': 'my-tmpl2'
        }, {
          'name': '3',
          'tmpl': 'my-tmpl3'
        }];
        $scope.showdiv = function(tmpl) {
          $scope.templateURL = tmpl;

        };
      }
    ]);
})(window.angular);

答案 16 :(得分: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();
    }

答案 17 :(得分:0)

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

答案 18 :(得分:-1)

在Servlet规范的“ 12.2映射规范”部分中,内容为:

仅包含“ /”字符的字符串表示该服务器的“默认” servlet 应用。

因此,从理论上讲,您可以将Servlet映射到declare %private function local:get-path( $path as xs:string?, $book ) { xquery:eval( $path, map{'':$book} ) }; let $doc := fn:doc('test/content/9781501342226/9781501342226_9781501342226/content/latest/9781501342226_txt_xml.xml') let $xpath := '/*:book/*:info/*:authorgroup/*:author/*:personname' for $value in local:get-path($xpath,$doc) return <item name="author" value="{$value}"></item> 来做到:

/*

...如果您不想自己处理。

但是,实际上,这是行不通的。

在Tomcat和Jetty中,如果有映射到getServletContext().getNamedDispatcher("/").forward(req,res); 的servlet,则对getServletContext().getNamedDispatcher('/')的调用将返回null