可以将SpringMVC配置为处理所有请求,但排除静态内容目录吗?

时间:2009-08-05 16:24:06

标签: spring configuration spring-mvc

如果我映射我的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>

Idealy我希望映射类似于以下内容:

 <servlet-mapping>
    <servlet-name>springApp</servlet-name>
    <url-pattern>/*</url-pattern>
    <exclude>/css/*,/js/*</exclude>
 </servlet-mapping>

这类事可能吗?

13 个答案:

答案 0 :(得分:56)

注意:此答案仅适用于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。以下是我如何处理这些排除的片段,其中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/" />

答案 1 :(得分:27)

我通过“默认”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 -->

希望这有帮助。

答案 2 :(得分:7)

如果你只想用Spring做这个,那可能会有点麻烦:

  1. 您需要使用SimpleUrlHandlerMapping,您可以明确指定应映射到控制器的URL模式或扩展它以支持“忽略”URL,例如“css /**”。
  2. 您需要编写自己的HttpRequestHandler实现,该实现基本上由“getServletContext()。getRequestDsipatcher()。include()”调用以按原样返回所请求的资源。
  3. 您必须将该处理程序注册为上述SimpleUrlHandlerMapping的defaultHandler。
  4. 完成所有操作后,所有无法映射到您的控制器的请求都会转发到您的HttpRequestHandler并按“原样”提供。

答案 3 :(得分:4)

对我来说最简单的方法(如果使用足够晚的Spring版本)是

<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
...

答案 4 :(得分:3)

一种方法是使用过滤器。你必须写一些自定义代码,但它并不坏。如果您不想将* .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 :我刚刚意识到如果你直接转发到文件,它会再次进行过滤,你会陷入无限循环。可能还有另一种方法可以使用过滤器,但我真的不确定它是什么。

答案 5 :(得分:2)

您使用什么来提供静态图像? 如果是Apache,那么您可以将Apache配置为不将css / js请求传递给您的应用服务器。

如果你使用的是Tomcat,你可以在httpd.conf中输入这样的东西:

JkUnMount /*.css  webapp

'webapp'是您的workers.properties的条目。

抱歉,我不能给你一个纯粹的Spring解决方案,但这就是我的方法。

答案 6 :(得分:2)

我遇到了同样的问题,这就是我解决的问题:

以下内容已添加到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 />

答案 7 :(得分:0)

对于您希望由Spring调度程序处理的请求,您是否有一致的扩展(我相信大多数Spring示例都使用* .htm)?在这种情况下,您可以映射到您希望处理的扩展名,这些扩展名将绕过您的css和js文件。

否则我同意Nalandial,过滤方法可能是目前最好的工作方式。

答案 8 :(得分:0)

我使用虚拟URL路径来检索我需要的资源。通常我使用Spring MVC,所以我不能在/ WEB-INF / views文件夹下有javascripts和css。我想出了这个自定义servlet,只允许访问.js&amp; / WEB-INF / views文件夹中的.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>

的servlet

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

答案 9 :(得分:0)

如果您使用的是Spring 3.0.4及更高版本,则应使用solution provided by atrain

否则,您可以执行 简单 事情:

也许您有以下要提供的静态目录结构:

WebContent
   |
   WEB-INF
     |
    public
        |
       css
        |
       js
        |
       img

Eclipse默认情况下,动态网络项目会生成以下结构:WebContent/WEB-INF。将public文件夹移出WEB-INF目录到WebContent目录。

在客户端

以下列方式引用您的静态文件:

<link rel="stylesheet" type="text/css" href="public/css/mystyles.css">

这是我的reference.

答案 10 :(得分:-1)

使用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

答案 11 :(得分:-1)

通常,大型网站更喜欢使用其他服务器来处理静态内容。 静态内容的请求转到一个服务器,动态转到另一个服务器(在这种情况下使用spring)。

在许多情况下,Nginx服务器(http://nginx.com/),一个最新且速度非常快的服务器。

但这并非易事。很多配置。

答案 12 :(得分:-1)

在我的情况下一切都很好。但我在控制器中遇到了问题

那是我的问题     @RequestMapping(method = RequestMethod.GET)

为此改变:

@RequestMapping(value = "/usuario", method = RequestMethod.GET)

并且有效

查找具有错误@RequestMappgin并更改的控制器。