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

Rah*_*arg 58 java resources servlets

我将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>
Run Code Online (Sandbox Code Playgroud)

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

我怎么能访问它们?

Bal*_*usC 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>
Run Code Online (Sandbox Code Playgroud)

过滤器中有以下内容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);
}
Run Code Online (Sandbox Code Playgroud)

不,这不会/pages在浏览器地址栏中结束.它是完全透明的.如有必要,可以补充"/static"和/或"/pages"一个init-param过滤器.

  • @MStodd:只是不要转发回控制器,它已经完成了它的工作.将视图隐藏在`/ WEB-INF`中的某个地方,例如`/ WEB-INF/pages/default.jsp`.有关更多提示,请参阅[this](http://stackoverflow.com/questions/2523430/hidden-features-of-jsp-servlet/2525995#2525995)和[this](http://stackoverflow.com/questions/3541077/design-patterns-web-based-applications/3542297#3542297)回答. (2认同)

Joa*_*les 43

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

<mvc:resources mapping="/resources/**" location="/public-resources/"/>
Run Code Online (Sandbox Code Playgroud)

Spring Reference中所示.


cas*_*sey 19

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

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>
Run Code Online (Sandbox Code Playgroud)

然后将其添加到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>
Run Code Online (Sandbox Code Playgroud)

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

得到它?因此,您的应用仍然位于子网址,但在用户访问您网站的根目录时会自动显示.这允许你让/images/bob.img仍然去常规地方,但'/'是你的应用程序.


小智 17

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

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这是Tomcat中的一个安全漏洞(WEB-INF和META-INF内容可以通过这种方式访问​​),它已在7.0.4中修复(并将被移植到5.x和6.x). (7认同)

GO'*_*GO' 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>
Run Code Online (Sandbox Code Playgroud)

  • 您可以将其添加到应用程序的web.xml中.您不必编辑$ {TOMCAT_HOME} /conf/web.xml中的全局web.xml. (2认同)
  • 是的取决于您的需求.我没有提到全局或应用程序配置.所以你的评论无关紧要. (2认同)

Gan*_*alf 12

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

<servlet-mapping>       
  <servlet-name>home</servlet-name>             
  <url-pattern>/app/*</url-pattern>     
</servlet-mapping>
Run Code Online (Sandbox Code Playgroud)

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

  • 我真的希望看到一个更好的解决方案.到处都是/ app /前缀很糟糕. (17认同)

dig*_*oel 9

从3.0.4开始,您应该能够mvc:resourcesmvc:default-servlet-handler弹簧文档中描述的组合使用来实现此目的.

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,那就是您的静态资源.

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

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