public or static包下的 html 丢了(404)? 你快回来! 我一人承受不来

没想到吧,我把html还是放到了jar包中~

环境:

  • Spring Boot 版本 2.X
  • Java 版本 1.8.0 及以上

问题:

public or static包下的 html 丢了(404)?
话不多说先上图
public or static包下的 html 丢了(404)? 你快回来! 我一人承受不来_第1张图片

public or static包下的 html 丢了(404)? 你快回来! 我一人承受不来_第2张图片

我的目录结构是这样的

src
└── main
    └── java
        └── com
            └── example
                └── demo
                    └── DemoApplication.java
    └── resources
        └── public
            ├── css
            │   └── main.css
            ├── js
            │   └── script.js
            └── index.html

Spring Boot 默认会自动配置 /public 目录下的静态资源文件,使其可以通过 / 根路径访问。这是通过 WebMvcAutoConfiguration 类来实现的。
那么找不到文件??? 这是什么原因?

排查

1、 先检查最基础的!! 依赖项 (理论上一定有依赖)


    org.springframework.boot
    spring-boot-starter-web

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 {

    @Override
    protected 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 {

    @Override
    public 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

去掉这个注解后 发现可用了
public or static包下的 html 丢了(404)? 你快回来! 我一人承受不来_第3张图片

学习

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();

        @Override
        public 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 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[] toArray(Collection collection, Class 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 Setters

    public 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

你可能感兴趣的:(html,前端,java,学习,spring)