【问题标题】:How to use second DispatcherServlet for resources如何使用第二个 DispatcherServlet 获取资源
【发布时间】:2015-01-08 12:19:39
【问题描述】:

配置

Tomcat 7.0.47 上的 Servlet 3.0
春季 3.1

问题

我有一个特殊的情况,我需要两个DispatcherServlets:一个处理资源请求,一个处理普通的@RequestMapping-type 请求。出于某种原因,我在日志中得到了这个:

在名称为“resources”的 DispatcherServlet 中找不到具有 URI [/my-app/images/someimage.png] 的 HTTP 请求的映射

这是我的web.xml 文件的样子:

<servlet>
  <servlet-name>resources</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>resources</servlet-name>
  <url-pattern>/css/*</url-pattern>
  <url-pattern>/images/*</url-pattern>
  <url-pattern>/js/*</url-pattern>
</servlet-mapping>

<servlet>
  <servlet-name>springmvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

resources-servlet.xml 我有这个:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"
  default-autowire="byName">

  <context:annotation-config />
  <context:property-placeholder />

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

  <context:component-scan base-package="lesscss" />
  <mvc:annotation-driven />
</beans>

如您所见,我没有用于 CSS 文件的 &lt;mvc:resources&gt;,因为该映射是通过 @Controller 即时构建 LESS 文件完成的。 &lt;context:component-scan base-package="lesscss" /&gt; 负责处理这一点,它似乎正在工作。

我以前在我的springmvc-servlet.xml 文件中有那些&lt;mvc:resources&gt; 标签,但我删除了它们。我还能错过什么?

更新

我尝试将我的web.xml 文件更改为使用*.ext url-patterns 而不是/dir/* 类型,并且成功了。不过,我宁愿不必列出所有扩展,所以我仍然希望有更好的解决方案来解决这个问题。

更新

我将&lt;mvc:resources mapping="/images/**" location="/images/"/&gt; 更改为&lt;mvc:resources mapping="/**" location="/images/"/&gt; 并删除了js 文件的那个,图像开始工作。在 Spring 中映射事物时,* 之前的 servlet-mapping url-pattern 似乎被忽略了。有没有办法解决这个问题?

解释为什么我“需要”两个 Servlet

我想我会添加这个只是为了帮助以前没有意识到这一点的其他人(比如我),并让某人有机会提出更好的解决方案(如果有的话)。

使用&lt;mvc:resources&gt; 标记时,创建的处理程序是常规DispatcherServlet 请求处理的一部分。这意味着,如果您没有明确说明所有 &lt;mvc:resources&gt; 使用 &lt;mvc:mapping&gt; 处理的资源路径(我仍在使用 Spring 3.1 并且不能使用 &lt;mvc:exclude-mapping&gt;),每个对图像、JavaScript 文件和样式表的请求会运行您在 &lt;mvc:interceptors&gt; 中列出的所有 HandlerInterceptors。我的应用程序中有很多拦截器,由于应用程序的结构和性质,列出所有路径非常容易出错。不仅仅是性能下降,所有这些HandlerInterceptors 的执行实际上会破坏手写的POST-redirect-GET 组件。

另一种方法是检查每个 HandlerInterceptor 方法中正在使用哪个处理程序,但这几乎不是 DRY,也容易出错,如果不扩展它们,我无法对 OpenSessionInViewInterceptor 等类进行此调整。我想出的避免所有这些混乱的解决方案是使用一个单独的 servlet 专门用于静态(ish)资源。

【问题讨论】:

  • 你为什么坚持把它分成两个DispatcherServlets
  • 顺便说一句。要解决您的问题,只需将您的 servlet 映射到 /resources 路径。
  • 解释需要两个DispatcherServlets 的时间太长了;只知道它必须是那样的。此外,/resources 不能在此处使用,因为资源位于应用根目录中。
  • 它们在哪里都没有关系......映射中使用的路径将在Spring查找资源时被剥离。您只需在 HTML / JSP 中将它们称为/resources/js/foo.js
  • 有太多的位置需要改变。我的 HTML 中的路径是 /my-app/css/foo.css 等。

标签: spring spring-mvc tomcat servlets


【解决方案1】:

简单的解决方案

首先,我觉得我必须写一些显而易见的东西(如果不是为了 OP,那么对于将来可能会阅读此答案的其他人):

  • 简单的解决方案是只使用单个DispatcherServlet。如果没有很强的理由,不要使用两个 servlet。

  • 或者,您可以将资源映射到 /resources/* 路径。将所有资源置于明确定义的路径下是一种常见(最​​佳?)做法。

复杂的解决方案

现在&lt;mvc:resources&gt;ResourcesBeanDefinitionParser 处理。该组件注册了两个关键组件:SimpleUrlHandlerMappingResourceHttpRequestHandler

第一个组件负责将请求映射到处理程序。如果不希望该组件为strip servlet mapping path,则需要设置alwaysUseFullPath flag。这可以通过自己进行&lt;mvc:resources&gt; 配置来完成,或者通过对注册的实例进行后处理来完成。

对于使用问题中的示例进行手动配置,请设置映射和处理程序:

<context:component-scan base-package="lesscss" />

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
  <property name="alwaysUseFullPath" value="true" />
</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="alwaysUseFullPath" value="true"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="alwaysUseFullPath" value="true"/>
  <property name="mappings">
    <props>
      <prop key="/images/**">imagesResources</prop>
      <prop key="/js/**">jsResources</prop>
    </props>
  </property>
</bean>

<bean id="imagesResources" class="org.springframework.web.servlet.resource.ResourceHttpRequestHandler">
  <property name="locations">
    <list>
      <value>/images/</value>
    </list>
  </property>
</bean>

<bean id="jsResources" class="org.springframework.web.servlet.resource.ResourceHttpRequestHandler">
  <property name="locations">
    <list>
      <value>/js/</value>
    </list>
  </property>
</bean>

对于后处理方法,创建并注册 bean:

public class SimpleUrlMappingConfigurer implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof SimpleUrlHandlerMapping) {
            ((SimpleUrlHandlerMapping) bean).setAlwaysUseFullPath(true);
        }
        return bean;
    }

}

【讨论】:

  • 为了清晰和透视添加了我的两个 servlet 解释。
猜你喜欢
  • 2020-03-01
  • 2021-06-08
  • 1970-01-01
  • 2014-10-05
  • 1970-01-01
  • 1970-01-01
  • 2013-02-10
  • 2013-04-18
  • 2014-02-02
相关资源
最近更新 更多