Webjars-locator 不适用于基于 XML 的 Spring MVC 4.2.x 配置?



我有一个Spring MVC 4.2.x项目。我正在通过基于XML的配置文件对其进行配置:

<servlet>
<servlet-name>foo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

context.xml文件中,我配置了资源和annotation-driven模式:

<mvc:resources mapping="/webjars/**" location="/webjars/"/>
<mvc:annotation-driven/>

一切都很好,除了一件事:webjars-locator-Webjars 定位器根本不起作用


我已经开始研究Spring MVC源代码以了解出了什么问题,并发现webjars-locator通过WebJarsResourceResolver类工作,该类的对象被添加到ResourceChainRegistration.getResourceResolvers()类方法中。

完整序列如下所示:

WebMvcConfigurationSupport.resourceHandlerMapping()>>ResourceHandlerRegistration.getHandlerMapping()>>ResourceHandlerRegistration.getRequestHandler()>>ResourceChainRegistration.getResourceResolvers(),其中添加为:

if (isWebJarsAssetLocatorPresent) {
result.add(new WebJarsResourceResolver());
}

问题是,在上述基于 XML 的配置的情况下,不会调用此序列,也不会使用WebMvcConfigurationSupport类。

此外,如果我添加

@EnableWebMvc
@Configuration
public class WebConfig {
}

进入项目,WebMvcConfigurationSupport显然有效,但在ResourceHandlerRegistration.getHandlerMapping()

protected AbstractHandlerMapping getHandlerMapping() {
if (registrations.isEmpty()) {
return null;
}
...
}

registrations是空的!


毕竟,如何强制使 Spring 将WebJarsResourceResolver添加到解析器链中的唯一方法是:

1) 从context.xml上取下<mvc:resources mapping="/webjars/**" location="/webjars/"/>,然后

2) 将addResourceHandlers添加到WebConfig

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/webjars/**")
.addResourceLocations("/webjars/")
.setCachePeriod(3600)
.resourceChain(true)  // !!! very important
;
}

我的问题是:我做错了什么?为什么 XML 基本配置不会导致注册WebJarsResourceResolver

假设上下文根路径是/ctx。使用您的配置,作为/webjars/RESOURCE的资源路径实际上映射到/ctx/webjars/RESOURCE;与通常期望相反,它应该映射到/webjars/RESOURCE.

根据 Spring 4.2.x 文档和类似问题的示例,您需要将/webjars/**映射到默认调度程序 servlet,如下所示:

这允许将 DispatcherServlet 映射到 "/"(从而覆盖容器默认 Servlet 的映射),同时仍然允许静态资源请求由容器的默认 Servlet 处理。它配置了一个 DefaultServletHttpRequestHandler,其 URL 映射为 "/**",并且相对于其他 URL 映射的优先级最低。

这意味着添加以下内容应该可以解决问题:

<mvc:resources mapping="/webjars/**" location="/webjars/">
<mvc:resource-chain>
<mvc:resource-cache />
</mvc:resource-chain>
</mvc:resources>
<mvc:annotation-driven />
<mvc:default-servlet-handler />

另一个注意事项是petclinic使用location="classpath:/META-INF/resources/webjars/"用于webjar的示例,我不确定这是否与此相关。

希望这有帮助。


由@Andremoniy添加:

对于Spring 4,它的标记略有不同:

<mvc:resources mapping="/webjars/**" location="/webjars/">
<mvc:resource-chain resource-cache="true"/>
</mvc:resources>

要回答您剩下的问题"为什么它没有在 webjar 文档中描述":

这是 2016 年 5 月 3 日报告的问题:

https://github.com/webjars/webjars/issues/1395

如本页所述,本期还提到Spring MVC需要resourceChain()方法。我今天创建了一个 PR 来解决这个问题:

https://github.com/webjars/webjars/pull/1946

仅供参考:我试图让与版本无关的 url 按照文档中描述的方式工作,但没有成功。在此过程中,我还发现了以下问题,其中提到"必须为与版本无关的WebJars调用resourceChain()方法":

https://github.com/spring-projects/spring-framework/issues/25410

最新更新