【问题标题】: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>

这种事情可能吗?

【问题讨论】:

    标签: spring configuration spring-mvc


    【解决方案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 做这件事,有可能但有点混乱:

      1. 您要么需要使用SimpleUrlHandlerMapping,您可以明确指定应该映射到控制器的 URL 模式,或者扩展它以支持“忽略”URL,如“css/**”。
      2. 您需要编写自己的 HttpRequestHandler 实现,该实现基本上由“getServletContext().getRequestDsipatcher().include()”调用组成,以按原样返回请求的资源。
      3. 您必须将该处理程序注册为上述 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>
      

      注意事项:

      • 重要的是最后一个&lt;rule&gt; 在底部,所以img、js、css 将首先被捕获
      • &lt;outbound-rule&gt; 是可选的,只是为了使现有的
        &lt;c:url value="/app/some" /&gt; 呈现 /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/" />
        

        【讨论】:

        【解决方案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 的控制器并进行更改。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-08-09
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-06-16
                  相关资源
                  最近更新 更多