SpringBoot中静态资源映射处理

本文介绍了SpringBoot中静态资源文件的映射规则,包括默认欢迎页和浏览器图标映射的实现方式。通过源码解析,详细展示了如何配置静态资源路径,以及SpringBoot如何处理这些资源请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇博文说明了SpringBoot对WebJars的支持,那么项目中还有其他静态资源文件,如自定义CSS、JS、image等,SpringBoot同样提供了映射支持。

【1】静态资源文件映射规则


同样查看WebMvcAutoConfiguration源码如下:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
	if (!this.resourceProperties.isAddMappings()) {
		logger.debug("Default resource handling disabled");
		return;
	}
	//对webjars做映射处理
	Integer cachePeriod = this.resourceProperties.getCachePeriod();
	if (!registry.hasMappingForPattern("/webjars/**")) {
		customizeResourceHandlerRegistration(
				registry.addResourceHandler("/webjars/**")
						.addResourceLocations(
								"classpath:/META-INF/resources/webjars/")
				.setCachePeriod(cachePeriod));
	}
	// 对静态资源文件映射支持
	String staticPathPattern = this.mvcProperties.getStaticPathPattern();
	if (!registry.hasMappingForPattern(staticPathPattern)) {
		customizeResourceHandlerRegistration(
				registry.addResourceHandler(staticPathPattern)
						.addResourceLocations(
								this.resourceProperties.getStaticLocations())
				.setCachePeriod(cachePeriod));
	}
}


@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**").addResourceLocations("file:"+"D://javasoftinstall/upload/");
registry.addResourceHandler("/**")
    .addResourceLocations("classpath:/resources/")
    .addResourceLocations("classpath:/static/")
super.addResourceHandlers(registry);
}

这里可以看到对静态资源处理的具体支持代码如下:

String staticPathPattern = this.mvcProperties.getStaticPathPattern();
	if (!registry.hasMappingForPattern(staticPathPattern)) {
		customizeResourceHandlerRegistration(
				registry.addResourceHandler(staticPathPattern)
						.addResourceLocations(
								this.resourceProperties.getStaticLocations())
				.setCachePeriod(cachePeriod));
	}

第一步拿到staticPathPattern;

/**
 * Path pattern used for static resources.
 */
private String staticPathPattern = "/**";

第二步,如果资源请求没有对应映射,就添加资源处理器及资源找寻位置并设置缓存

if (!registry.hasMappingForPattern(staticPathPattern)) {
		customizeResourceHandlerRegistration(
				registry.addResourceHandler(staticPathPattern)
						.addResourceLocations(
								this.resourceProperties.getStaticLocations())
				.setCachePeriod(cachePeriod));
	}

其中 staticLocations在ResourceProperties类中,源码如下:

/**
 * Properties used to configure resource handling.
 */
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {

	private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" };
//静态资源映射路径
	private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
			"classpath:/META-INF/resources/", "classpath:/resources/",
			"classpath:/static/", "classpath:/public/" };

	private static final String[] RESOURCE_LOCATIONS;

	static {
		RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
				+ SERVLET_RESOURCE_LOCATIONS.length];
		System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
				SERVLET_RESOURCE_LOCATIONS.length);
		System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
				SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
	}

	/**
	 * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
	 * /resources/, /static/, /public/] plus context:/ (the root of the servlet context).
	 */
	private String[] staticLocations = RESOURCE_LOCATIONS;

即:"/**" 访问当前项目的任何资源,只要没有匹配的处理映射,则都去静态资源的文件夹找映射

"classpath:/META‐INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":当前项目的根路径

这里写图片描述


如下图,访问static/asserts/img/bootstrap-solid.svg:

这里写图片描述

URL : http://localhost:8083/asserts/img/bootstrap-solid.svg;

这里注意URL上面不要添加静态资源文件夹(路径)的名字,如static、public等等。


【2】默认欢迎页的映射

代码如下:

		@Bean
		public WelcomePageHandlerMapping welcomePageHandlerMapping(
				ResourceProperties resourceProperties) {
			return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
					this.mvcProperties.getStaticPathPattern());
		}

注册了WelcomePageHandlerMappingBean来处理项目的默认欢迎页面,构造器有两个参数,第一个是项目中存在的欢迎页资源,第二个是静态资源路径映射规则。


① 获取欢迎页资源

其中跟踪resourceProperties.getWelcomePage()源码:

	public Resource getWelcomePage() {
		for (String location : getStaticWelcomePageLocations()) {
			Resource resource = this.resourceLoader.getResource(location);
			try {
				if (resource.exists()) {
					resource.getURL();
					return resource;
				}
			}
			catch (Exception ex) {
				// Ignore
			}
		}
		return null;
	}

即找到存在的欢迎页的资源,继续跟getStaticWelcomePageLocations()源码:

private String[] getStaticWelcomePageLocations() {
		String[] result = new String[this.staticLocations.length];
		for (int i = 0; i < result.length; i++) {
			String location = this.staticLocations[i];
			if (!location.endsWith("/")) {
				location = location + "/";
			}
			result[i] = location + "index.html";
		}
		return result;
	}

即 欢迎页的位置为第【1】部分中静态资源文件路径下的index.html。

如下所示:

"classpath:/META‐INF/resources/index.html",
"classpath:/resources/index.html",
"classpath:/static/index.html",
"classpath:/public/index.html"
"/":/index.html

② 静态路径映射规则


	/**
	 * Path pattern used for static resources.
	 */
	private String staticPathPattern = "/**";

③ WelcomePageHandlerMapping类

static final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {

		private static final Log logger = LogFactory
				.getLog(WelcomePageHandlerMapping.class);

		private WelcomePageHandlerMapping(Resource welcomePage,
				String staticPathPattern) {
			if (welcomePage != null && "/**".equals(staticPathPattern)) {
				logger.info("Adding welcome page: " + welcomePage);
				ParameterizableViewController controller = new ParameterizableViewController();
				controller.setViewName("forward:index.html");
				setRootHandler(controller);
				setOrder(0);
			}
		}

		@Override
		public Object getHandlerInternal(HttpServletRequest request) throws Exception {
			for (MediaType mediaType : getAcceptedMediaTypes(request)) {
				if (mediaType.includes(MediaType.TEXT_HTML)) {
					return super.getHandlerInternal(request);
				}
			}
			return null;
		}

		private List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) {
			String acceptHeader = request.getHeader(HttpHeaders.ACCEPT);
			return MediaType.parseMediaTypes(
					StringUtils.hasText(acceptHeader) ? acceptHeader : "*/*");
		}

	}

总结:项目访问时,请求如http://localhost:8083/,则SpringBoot会从静态资源文件路径下找index.html,如果存在一个这样的资源,就转发请求到该页面。


【3】项目浏览器图标的映射

SpringBoot同样对项目浏览器图标请求映射做了默认配置。浏览器图片即项目访问时,浏览器页面上呈现的图标,如优快云图标如下

这里写图片描述


代码如下:

		@Configuration
		@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
		public static class FaviconConfiguration {

			private final ResourceProperties resourceProperties;

			public FaviconConfiguration(ResourceProperties resourceProperties) {
				this.resourceProperties = resourceProperties;
			}

			@Bean
			public SimpleUrlHandlerMapping faviconHandlerMapping() {
				SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
				mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
				mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
						faviconRequestHandler()));
				return mapping;
			}

			@Bean
			public ResourceHttpRequestHandler faviconRequestHandler() {
				ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
				requestHandler
						.setLocations(this.resourceProperties.getFaviconLocations());
				return requestHandler;
			}

		}

跟踪源码this.resourceProperties.getFaviconLocations()如下:

List<Resource> getFaviconLocations() {
		List<Resource> locations = new ArrayList<Resource>(
				this.staticLocations.length + 1);
		if (this.resourceLoader != null) {
			for (String location : this.staticLocations) {
				locations.add(this.resourceLoader.getResource(location));
			}
		}
		locations.add(new ClassPathResource("/"));
		return Collections.unmodifiableList(locations);
	}

即在静态资源文件下找所有的favicon.ico !

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值