spring – 如何使用第二个DispatcherServlet获取资源

组态

Tomcat 7.0.47上的Servlet 3.0
春季3.1

我有一个特殊情况,我需要两个DispatcherServlet:一个用于处理资源请求,另一个用于处理正常的@RequestMapping类型请求.出于某种原因,我在日志中得到这个:

No mapping found for HTTP request with URI [/my-app/images/someimage.png] in DispatcherServlet with name ‘resources’

这是我的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>

如你所见,我没有< mvc:resources>对于CSS文件,因为该映射是使用@Controller动态构建LESS文件完成的. < context:component-scan base-package =“lesscss”/>照顾那一点,它似乎工作.

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

UPDATE

我尝试将我的web.xml文件更改为使用* .ext url-patterns而不是/ dir / * kind,并且它有效.不过,我宁愿不必列出所有扩展,所以我仍然希望更好地解决这个问题.

UPDATE

我更改了< mvc:resources mapping =“/ images / **”location =“/ images /”/>到< mvc:resources mapping =“/ **”location =“/ images /”/>并删除了一个js文件,图像开始工作.在Spring中映射事物时,似乎忽略了*之前的servlet-mapping url-pattern.有没有解决的办法?

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

我想我会添加这个只是为了帮助那些之前没有意识到这一点的人(比如我),并给某人一个机会,如果有的话,想出更好的解决方案.

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

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

最佳答案 简单的解决方案

首先,我觉得我必须写明显(如果不是OP,那么对于其他可能会在未来阅读此答案的人):

>简单的解决方案是使用单个DispatcherServlet.如果没有很强的理由,请不要使用两个servlet.
>或者,您可以将资源映射到/ resources / *路径.将所有资源置于明确定义的路径下是一种常见的(最好的)实践.

复杂的解决方案

现在< mvc:resources>由ResourcesBeanDefinitionParser处理.该组件注册两个关键组件:SimpleUrlHandlerMapping和ResourceHttpRequestHandler.

第一个组件负责将请求映射到处理程序.如果您不希望此组件为strip servlet mapping path,则需要设置alwaysUseFullPath flag.这可以通过执行< mvc:resources>来完成.自己配置,或通过后处理已注册的实例.

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

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

}
点赞