没想到吧,我把html还是放到了jar包中~
环境:
- Spring Boot 版本 2.X
- Java 版本 1.8.0 及以上
问题:
public or static包下的 html 丢了(404)?
话不多说先上图
我的目录结构是这样的
src
└── main└── java└── com└── example└── demo└── DemoApplication.java└── resources└── public├── css│ └── main.css├── js│ └── script.js└── index.html
Spring Boot 默认会自动配置 /public 目录下的静态资源文件,使其可以通过 / 根路径访问。这是通过 WebMvcAutoConfiguration 类来实现的。
那么找不到文件??? 这是什么原因?
排查
1、 先检查最基础的!! 依赖项 (理论上一定有依赖)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、 是不是有使用 Spring Security 是否开启了静态资源 允许访问
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/css/**", "/js/**", "/public/**").permitAll() // 允许访问静态资源.anyRequest().authenticated(); // 其他请求需要认证}
}
3、 是不是有自主配置 WebMvcConfig 比如
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/");}
}
4、 是不是配置了yml? 自定义资源文件
spring:resources:static-locations: classpath:/public/
5、 是不是开启了 @EnableWebMvc !!! (我是这个原因)
使用这个注解后 会使用 WebMvcConfigurationSupport 资源加载 所以就不识别 /public /static 这些了 spring-boot 默认使用的是 WebMvcAutoConfigurationAdapter
去掉这个注解后 发现可用了
学习
Spring Boot 的自动配置机制
Spring Boot 使用自动配置机制来简化开发者的配置工作。对于静态资源的处理,Spring Boot 会在启动时自动配置一个 ResourceHandler 来处理这些资源。
关键类和方法
1、 WebMvcAutoConfiguration 类:
这个类是Spring Boot自动配置的一部分,负责配置Spring MVC的相关设置,包括静态资源的处理。
2、 WebMvcAutoConfiguration.AddResourceHandlers 类:
这个内部类实现了 WebMvcConfigurer 接口,并提供了 addResourceHandlers 方法来添加资源处理器。
WebMvcAutoConfiguration 类
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {@Configuration@ConditionalOnClass({ Servlet.class, RequestMappingHandlerMapping.class })@ConditionalOnMissingBean({ WebMvcRegistrations.class, WebMvcConfigurationSupport.class })@ConditionalOnBean(DispatcherServlet.class)@ConditionalOnWebApplication(type = Type.SERVLET)public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {private final ResourceProperties resourceProperties = new ResourceProperties();@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");return;}Duration cachePeriod = this.resourceProperties.getCache().getPeriod();CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toBuilder();if (!registry.hasMappingForPattern("/webjars/**")) {customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));}String staticPathPattern = this.resourceProperties.getStatic().getPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern).addResourceLocations(getResourceLocations(this.resourceProperties.getStatic().getResourceLocations())).setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));}}private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {// Customization can be added here if needed}private long getSeconds(Duration duration) {return duration.isNegativeOrZero() ? -1 : duration.getSeconds();}private String[] getResourceLocations(String[] locations) {Assert.notNull(locations, "Locations must not be null");ArrayList<String> resolved = new ArrayList<>(locations.length);Arrays.stream(locations).forEach(location -> {if (location.startsWith(CLASSPATH_PREFIX)) {File file = getFileFromResourceLocation(location);if (file != null && file.exists() && file.isDirectory()) {String path = file.toURI().toString();if (!path.endsWith("/")) {path = path + "/";}resolved.add(path);} else {resolved.add(location);}} else {resolved.add(location);}});return toArray(resolved, String.class);}private File getFileFromResourceLocation(String location) {try {URL url = new UrlResource(location).getURL();if ("file".equals(url.getProtocol())) {return new File(url.toURI());}} catch (Exception ex) {// Ignore}return null;}private <T> T[] toArray(Collection<T> collection, Class<T> clazz) {return collection.toArray((T[]) Array.newInstance(clazz, collection.size()));}}
}
ResourceProperties 类
ResourceProperties 类用于配置静态资源的路径和其他相关属性
@ConfigurationProperties(prefix = "spring.resources")
public class ResourceProperties {private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/" };private boolean addMappings = true;private Static static = new Static();// Getters and Setterspublic static class Static {private String pathPattern = "/**";private String[] resourceLocations = CLASSPATH_RESOURCE_LOCATIONS;// Getters and Setters}
}
ResourceProperties 类中的 CLASSPATH_RESOURCE_LOCATIONS 数组定义了默认的静态资源路径
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/"
};
在 WebMvcAutoConfiguration.AddResourceHandlers 类的 addResourceHandlers 方法中,Spring Boot 会自动添加一个资源处理器来处理这些默认路径下的静态资源:
if (!registry.hasMappingForPattern(staticPathPattern)) {customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern).addResourceLocations(getResourceLocations(this.resourceProperties.getStatic().getResourceLocations())).setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
总结
Spring Boot 默认会自动配置 /public 目录下的静态资源文件,使其可以通过 / 根路径访问。这是通过 WebMvcAutoConfiguration 类中的 addResourceHandlers 方法实现的。该方法会注册一个资源处理器,处理默认路径下的静态资源文件,包括 classpath:/public/。
如果你在 src/main/resources/public 目录下放置了静态资源文件,Spring Boot 会自动配置一个资源处理器来处理这些文件的请求。你可以通过以下路径访问这些文件:
http://localhost:8080/index.html 访问 src/main/resources/public/index.html
http://localhost:8080/css/main.css 访问 src/main/resources/public/css/main.css
http://localhost:8080/js/script.js 访问 src/main/resources/public/js/script.js