SpringMVC 是不是可以配置为处理所有请求,但排除静态内容目录?
Posted
技术标签:
【中文标题】SpringMVC 是不是可以配置为处理所有请求,但排除静态内容目录?【英文标题】:Can SpringMVC be configured to process all requests, but exclude static content directories?SpringMVC 是否可以配置为处理所有请求,但排除静态内容目录? 【发布时间】:2010-11-17 02:02:08 【问题描述】:如果我将 Spring 应用程序映射为处理所有传入请求 ('/*'),则静态内容请求会返回 404。例如,对“myhost.com/css/global.css”的请求将返回 404,即使在 Spring 拦截请求时资源存在。
替代方法是将 SpringMVC 映射到子目录(例如 '/home/'),但在这种情况下,您必须在应用程序的所有链接中传递此目录。有没有办法将 SpringMVC 映射到“/”并从处理中排除一组目录?
我当前的 web.xml 配置是:
<servlet>
<servlet-name>springApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springApp</servlet-name>
<url-pattern>/home/*</url-pattern>
</servlet-mapping>
理想情况下,我希望映射如下所示:
<servlet-mapping>
<servlet-name>springApp</servlet-name>
<url-pattern>/*</url-pattern>
<exclude>/css/*,/js/*</exclude>
</servlet-mapping>
这种事情可能吗?
【问题讨论】:
【参考方案1】:您使用什么来提供静态图片? 如果是 Apache,那么您可以将 Apache 配置为不将 css/js 请求传递给您的应用服务器。
如果你使用的是 Tomcat,你会在你的 httpd.conf 中加入这样的内容:
JkUnMount /*.css webapp
“webapp”是您的workers.properties 中的条目。
对不起,我不能给你一个纯 Spring 的解决方案,但我就是这样做的。
【讨论】:
这是一个很好的提示,但我正在寻找便携的东西;因此,当组装好的 WAR 放入 servlet 容器中时,无需外部配置即可工作。【参考方案2】:一种方法是使用过滤器。您必须编写一些自定义代码,但这还不错。如果您不想将 *.css 或 *.js 文件传递给 Spring servlet,这是一个示例:
web.xml:
<filter-mapping>
<filter-name>fileTypeFilter</filter-name>
<filter-class>foo.FileTypeFilter</filter-class>
<url-pattern>/*</url-pattern>
</filter-mapping>
Java 类:
public class FileTypeFilter implements Filter
public void init(FilterConfig conf)
// init logic here
public void destroy()
// release resources here
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException
if(shouldExclude(req))
chain.doFilter(req, res);
//some logic so the request doesnt go to the servlet
//maybe you could just forward
//the request directly to the file getting accessed. not sure if that would work
//file should be passed to the servlet; you can do some logic here
//if you want
private boolean shouldExclude(ServletRequest req)
if(req instanceof HttpServletRequest)
HttpServletRequest hreq = (HttpServletRequest) req;
return (hreq.getRequestURI().endsWith(".css") ||
hreq.getRequestURI().endsWith(".js"));
return false;
我没有对此进行测试,但我认为它会起作用。
编辑:servlet 规范中没有任何排除功能。我认为在 Spring 中没有很好的方法来做到这一点,但它在你的帖子中基本上实现了同样的事情。
编辑 2:如果您希望能够轻松更改过滤的内容,您可以使用 Spring 在运行时向过滤器中注入一些内容。
编辑 3:我刚刚意识到,如果您直接转发到文件,它会再次进行过滤,您将陷入无限循环。使用过滤器可能还有另一种方法,但老实说我不确定它是什么。
【讨论】:
【参考方案3】:对于希望由 Spring 调度程序处理的请求,您是否有一致的扩展(我相信大多数 Spring 示例都使用 *.htm)?在这种情况下,您可以映射到您希望处理的扩展,从而绕过您的 css 和 js 文件。
否则我会同意 Nalandial,过滤器方法可能是目前最好的解决方法。
【讨论】:
我使用的是restful url,所以应用程序中没有任何扩展名,所以后缀映射对我不起作用。【参考方案4】:如果你只想用 Spring 做这件事,有可能但有点混乱:
-
您要么需要使用SimpleUrlHandlerMapping,您可以明确指定应该映射到控制器的 URL 模式,或者扩展它以支持“忽略”URL,如“css/**”。
您需要编写自己的 HttpRequestHandler 实现,该实现基本上由“getServletContext().getRequestDsipatcher().include()”调用组成,以按原样返回请求的资源。
您必须将该处理程序注册为上述 SimpleUrlHandlerMapping 的 defaultHandler。
完成所有操作后,所有无法映射到您的控制器的请求都将转发到您的 HttpRequestHandler
并“按原样”提供服务。
【讨论】:
我目前正在使用 DefaultAnnotationHandlerMapping 进行基于注释的控制器映射。根据您的建议,我将对其进行扩展并添加对基于路径的排除的支持。感谢您为我指明正确的方向。 如果有人错过了它,请注意 Spring 3.x 存在更好的解决方案。看看下面的答案!【参考方案5】:我通过“默认”servlet 提供静态内容来解决问题,该 servlet 只是将内容提供给客户端。所以我的 web.xml 看起来像这样:
<servlet>
<servlet-name>MyApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyApp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <!-- The 'dynamic' content -->
<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>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping> <!-- The 'static' content -->
希望这会有所帮助。
【讨论】:
我也遇到了这个解决方案——我唯一的问题是:我不相信它是可移植的,b:我无法通过注释映射“/”路径。如果能解决这两个问题,这对我来说将是完美的解决方案。 对不起,如果我迟到了,我不在城里。是的,关于可移植性问题,您可能是对的。我没有这个问题,因为我被困在tomcat上。可能你可以在战争中包含 DefaultServlet。关于通过注释的“/”路径,在我的配置(方法级注释的IndexController)中,它与@RequestMapping(value =“/”)一起使用。使用类级注释控制器,有时我需要以这种方式注释 @RequestMapping(value = "") 如果您正在运行开发人员实例并且不想为为静态媒体设置 Web 服务器而烦恼。 对于它的价值,我已经尝试过了,这适用于 Tomcat 7 和 Jetty 6。 这似乎不适用于 Glassfish 3.1.2.2(构建 5)。我在部署期间收到以下错误:“这里没有默认名称的 Web 组件。”有什么想法吗?【参考方案6】:使用UrlRewriteFilter 将请求重定向到您的servlet 更简洁,这里是urlrewrite.xml
的示例
<urlrewrite>
<rule>
<from>^/img/(.*)$</from>
<to>/img/$1</to>
</rule>
<rule>
<from>^/js/(.*)$</from>
<to>/js/$1</to>
</rule>
<rule>
<from>^/css/(.*)$</from>
<to>/css/$1</to>
</rule>
<rule>
<from>^/(.*)$</from>
<to>/app/$1</to>
</rule>
<outbound-rule>
<from>/app/(.*)$</from>
<to>/$1</to>
</outbound-rule>
</urlrewrite>
注意事项:
重要的是最后一个<rule>
在底部,所以img、js、css 将首先被捕获
<outbound-rule>
是可选的,只是为了使现有的<c:url value="/app/some" />
呈现 /some
而不是 /app/some
【讨论】:
【参考方案7】:注意:此答案仅适用于 Spring 3.0.4+
(顺便说一句,这里也处理过这个问题:Spring serving static content with mvc:resources, invalid xsd)
查看 Spring subversion samples repository 中的 Spring mvc-showcase 项目。它准确地显示了您想要做什么,即您可以描述 DisapatcherServlet 不会处理的静态资源。见文件/mvc-showcase/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
。这是我如何处理这些排除的 sn-p,其中 JS、CSS 和图像位于应用程序上下文根中(MVC 命名空间映射到 mvc
:
<!-- resources exclusions from servlet mapping -->
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/js/**" location="/js/" />
【讨论】:
注意:Spring MVC Showcase 项目已移至 github。在此处访问:github.com/SpringSource/spring-mvc-showcase 你如何在配置中使用注解做同样的事情? nm ***.com/questions/14299149/…【参考方案8】:通常,大型网站更喜欢仅使用另一台服务器来处理静态内容。 静态内容的请求发送到一台服务器,动态发送到另一台服务器(在这种情况下使用 spring)。
在很多情况下,nginx 服务器 (http://nginx.com/) 是一个最新且非常快的服务器。
但这并非易事。很多配置。
【讨论】:
【参考方案9】:对我来说最简单的方法(如果使用足够晚的 Spring 版本)是
<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
...
【讨论】:
我喜欢这个解决方案,因为我将 spring 添加到一个非常古老的站点,该站点到处都是静态内容。我遇到的所有其他示例都没有考虑到这一点。谢谢!【参考方案10】:我使用虚拟 URL 路径来检索我需要的资源。通常我使用 Spring MVC,所以 /WEB-INF/views 文件夹下不能有 javascripts 和 css。我想出了这个自定义 servlet,只允许访问 /WEB-INF/views 文件夹中的 .js 和 .css 文件。在您的情况下,如果您将 /css 文件夹和 /js 文件夹移动到 /resource 等父文件夹,那么我的解决方案将适用于您。
您可以更改字符串 url = "YOUR_RESOURCE_FOLDER"
例如,虚拟路径可以是 http://www.mysite.com/resources/path/path/app.js
这将映射到我的 /WEB-INF/views/path/path/app.js
web.xml
<servlet>
<servlet-name>ResourceDispatcherServlet</servlet-name>
<servlet-class>mywebapp.web.ResourceDispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ResourceDispatcherServlet</servlet-name>
<url-pattern>/resource/*</url-pattern>
</servlet-mapping>
小服务程序
public class ResourceDispatcherServlet extends HttpServlet
public void init() throws ServletException
public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException
String servletPath = req.getServletPath(); // /resource
String pathInfo = req.getPathInfo(); // /path/path/app.js
String url = "/WEB-INF/views" + pathInfo;
String lastPath = StringUtil.substringAfterLast(pathInfo, "/");
String extension = StringUtil.substringAfterLast(lastPath, ".");
try
RequestDispatcher dispatcher = null;
if (!StringUtil.isEmpty(extension) && ("js".equals(extension) || "css".equals(extension)))
dispatcher = req.getRequestDispatcher(url);
if (dispatcher != null)
dispatcher.include(req, rsp);
else
rsp.sendError(404);
catch (Exception e)
if (!rsp.isCommitted())
rsp.sendError(500);
【讨论】:
【参考方案11】:如果您使用的是 Spring 3.0.4 及更高版本,则应使用solution provided by atrain
否则,您可以这样做简单:
也许您有以下要服务的静态目录结构:
WebContent
|
WEB-INF
|
public
|
css
|
js
|
img
Eclipse
动态 Web 项目默认生成以下结构:WebContent/WEB-INF
。将public
文件夹从您的WEB-INF 目录中移出到WebContent
目录中。
在客户端
通过以下方式引用您的静态文件:
<link rel="stylesheet" type="text/css" href="public/css/mystyles.css">
这是我的reference.
【讨论】:
【参考方案12】:我遇到了同样的问题,我是这样解决的:
以下内容已添加到 web.xml 文件中:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.ico</url-pattern>
<url-pattern>*.png</url-pattern>
<url-pattern>*.jpg</url-pattern>
<url-pattern>*.htc</url-pattern>
<url-pattern>*.gif</url-pattern>
<url-pattern>*.html</url-pattern>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
spring3 MVC servlet bean定义文件(如applicationContext.xml,web.xml中配置为contextConfigLocation的文件)添加了以下内容:
<mvc:annotation-driven />
<mvc:default-servlet-handler />
【讨论】:
【参考方案13】:就我而言,一切都很好。但是我的控制器有问题
那是我的问题 @RequestMapping(method = RequestMethod.GET)
为此改变:
@RequestMapping(value = "/usuario", method = RequestMethod.GET)
它可以工作
查找具有错误@RequestMappgin 的控制器并进行更改。
【讨论】:
以上是关于SpringMVC 是不是可以配置为处理所有请求,但排除静态内容目录?的主要内容,如果未能解决你的问题,请参考以下文章