Merge pull request #31769 from vpavic

* pr/31769:
  Add support for customizing WebJars resource handler path pattern

Closes gh-31769
This commit is contained in:
Stephane Nicoll 2022-09-07 11:51:16 +02:00
commit d546ea515a
8 changed files with 63 additions and 6 deletions

View File

@ -189,8 +189,9 @@ public class WebFluxAutoConfiguration {
logger.debug("Default resource handling disabled"); logger.debug("Default resource handling disabled");
return; return;
} }
if (!registry.hasMappingForPattern("/webjars/**")) { String webjarsPathPattern = this.webFluxProperties.getWebjarsPathPattern();
ResourceHandlerRegistration registration = registry.addResourceHandler("/webjars/**") if (!registry.hasMappingForPattern(webjarsPathPattern)) {
ResourceHandlerRegistration registration = registry.addResourceHandler(webjarsPathPattern)
.addResourceLocations("classpath:/META-INF/resources/webjars/"); .addResourceLocations("classpath:/META-INF/resources/webjars/");
configureResourceCaching(registration); configureResourceCaching(registration);
customizeResourceHandlerRegistration(registration); customizeResourceHandlerRegistration(registration);

View File

@ -23,6 +23,7 @@ import org.springframework.util.StringUtils;
* {@link ConfigurationProperties properties} for Spring WebFlux. * {@link ConfigurationProperties properties} for Spring WebFlux.
* *
* @author Brian Clozel * @author Brian Clozel
* @author Vedran Pavic
* @since 2.0.0 * @since 2.0.0
*/ */
@ConfigurationProperties(prefix = "spring.webflux") @ConfigurationProperties(prefix = "spring.webflux")
@ -40,6 +41,11 @@ public class WebFluxProperties {
*/ */
private String staticPathPattern = "/**"; private String staticPathPattern = "/**";
/**
* Path pattern used for WebJar assets.
*/
private String webjarsPathPattern = "/webjars/**";
public String getBasePath() { public String getBasePath() {
return this.basePath; return this.basePath;
} }
@ -76,6 +82,14 @@ public class WebFluxProperties {
this.staticPathPattern = staticPathPattern; this.staticPathPattern = staticPathPattern;
} }
public String getWebjarsPathPattern() {
return this.webjarsPathPattern;
}
public void setWebjarsPathPattern(String webjarsPathPattern) {
this.webjarsPathPattern = webjarsPathPattern;
}
public static class Format { public static class Format {
/** /**

View File

@ -329,7 +329,8 @@ public class WebMvcAutoConfiguration {
logger.debug("Default resource handling disabled"); logger.debug("Default resource handling disabled");
return; return;
} }
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/"); addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(),
"classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations()); registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) { if (this.servletContext != null) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,6 +35,7 @@ import org.springframework.validation.DefaultMessageCodesResolver;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Brian Clozel * @author Brian Clozel
* @author Vedran Pavic
* @since 2.0.0 * @since 2.0.0
*/ */
@ConfigurationProperties(prefix = "spring.mvc") @ConfigurationProperties(prefix = "spring.mvc")
@ -91,6 +92,11 @@ public class WebMvcProperties {
*/ */
private String staticPathPattern = "/**"; private String staticPathPattern = "/**";
/**
* Path pattern used for WebJar assets.
*/
private String webjarsPathPattern = "/webjars/**";
private final Async async = new Async(); private final Async async = new Async();
private final Servlet servlet = new Servlet(); private final Servlet servlet = new Servlet();
@ -188,6 +194,14 @@ public class WebMvcProperties {
this.staticPathPattern = staticPathPattern; this.staticPathPattern = staticPathPattern;
} }
public String getWebjarsPathPattern() {
return this.webjarsPathPattern;
}
public void setWebjarsPathPattern(String webjarsPathPattern) {
this.webjarsPathPattern = webjarsPathPattern;
}
public Async getAsync() { public Async getAsync() {
return this.async; return this.async;
} }

View File

@ -109,6 +109,7 @@ import static org.mockito.Mockito.mock;
* @author Brian Clozel * @author Brian Clozel
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Vedran Pavic
*/ */
class WebFluxAutoConfigurationTests { class WebFluxAutoConfigurationTests {
@ -186,6 +187,18 @@ class WebFluxAutoConfigurationTests {
}); });
} }
@Test
void shouldMapWebjarsToCustomPath() {
this.contextRunner.withPropertyValues("spring.webflux.webjars-path-pattern:/assets/**").run((context) -> {
SimpleUrlHandlerMapping hm = context.getBean("resourceHandlerMapping", SimpleUrlHandlerMapping.class);
assertThat(hm.getUrlMap().get("/assets/**")).isInstanceOf(ResourceWebHandler.class);
ResourceWebHandler webjarsHandler = (ResourceWebHandler) hm.getUrlMap().get("/assets/**");
assertThat(webjarsHandler.getLocations()).hasSize(1);
assertThat(webjarsHandler.getLocations().get(0))
.isEqualTo(new ClassPathResource("/META-INF/resources/webjars/"));
});
}
@Test @Test
void shouldNotMapResourcesWhenDisabled() { void shouldNotMapResourcesWhenDisabled() {
this.contextRunner.withPropertyValues("spring.web.resources.add-mappings:false") this.contextRunner.withPropertyValues("spring.web.resources.add-mappings:false")

View File

@ -146,6 +146,7 @@ import static org.mockito.Mockito.mock;
* @author Kristine Jetzke * @author Kristine Jetzke
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Scott Frederick * @author Scott Frederick
* @author Vedran Pavic
*/ */
class WebMvcAutoConfigurationTests { class WebMvcAutoConfigurationTests {
@ -195,6 +196,17 @@ class WebMvcAutoConfigurationTests {
}); });
} }
@Test
void customWebjarsHandlerMapping() {
this.contextRunner.withPropertyValues("spring.mvc.webjars-path-pattern:/assets/**").run((context) -> {
Map<String, List<Resource>> locations = getResourceMappingLocations(context);
assertThat(locations.get("/assets/**")).hasSize(1);
assertThat(locations.get("/assets/**").get(0))
.isEqualTo(new ClassPathResource("/META-INF/resources/webjars/"));
assertThat(getResourceResolvers(context, "/assets/**")).hasSize(1);
});
}
@Test @Test
void resourceHandlerMappingOverrideWebjars() { void resourceHandlerMappingOverrideWebjars() {
this.contextRunner.withUserConfiguration(WebJars.class).run((context) -> { this.contextRunner.withUserConfiguration(WebJars.class).run((context) -> {

View File

@ -84,7 +84,8 @@ If you do so, the default welcome page detection switches to your custom locatio
So, if there is an `index.html` in any of your locations on startup, it is the home page of the application. So, if there is an `index.html` in any of your locations on startup, it is the home page of the application.
In addition to the "`standard`" static resource locations listed earlier, a special case is made for https://www.webjars.org/[Webjars content]. In addition to the "`standard`" static resource locations listed earlier, a special case is made for https://www.webjars.org/[Webjars content].
Any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format. By default, any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format.
The path can be customized with the configprop:spring.webflux.webjars-path-pattern[] property.
TIP: Spring WebFlux applications do not strictly depend on the servlet API, so they cannot be deployed as war files and do not use the `src/main/webapp` directory. TIP: Spring WebFlux applications do not strictly depend on the servlet API, so they cannot be deployed as war files and do not use the `src/main/webapp` directory.

View File

@ -107,7 +107,8 @@ You can also customize the static resource locations by using the configprop:spr
The root servlet context path, `"/"`, is automatically added as a location as well. The root servlet context path, `"/"`, is automatically added as a location as well.
In addition to the "`standard`" static resource locations mentioned earlier, a special case is made for https://www.webjars.org/[Webjars content]. In addition to the "`standard`" static resource locations mentioned earlier, a special case is made for https://www.webjars.org/[Webjars content].
Any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format. By default, any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format.
The path can be customized with the configprop:spring.mvc.webjars-path-pattern[] property.
TIP: Do not use the `src/main/webapp` directory if your application is packaged as a jar. TIP: Do not use the `src/main/webapp` directory if your application is packaged as a jar.
Although this directory is a common standard, it works *only* with war packaging, and it is silently ignored by most build tools if you generate a jar. Although this directory is a common standard, it works *only* with war packaging, and it is silently ignored by most build tools if you generate a jar.