Spring Boot+Docker环境下Thymeleaf引入CSS/JS报404求助
1. 确认静态资源目录结构
Spring Boot默认从classpath:/static/、classpath:/public/等目录加载静态资源,你的文件目录必须符合规则,正确结构应为:
src/ └── main/ └── resources/ ├── static/ │ ├── css/ │ │ └── scalata.css │ └── js/ │ └── scalata.js └── templates/ └── scalata.html
若将静态资源放在templates/目录下,Thymeleaf不会将其识别为静态资源,必然返回404。
2. 检查Thymeleaf资源引用语法
必须使用Thymeleaf的@{...}表达式生成正确路径,禁止使用相对路径或硬编码绝对路径,正确写法:
<!-- CSS 引用 --> <link rel="stylesheet" th:href="@{/css/scalata.css}"> <!-- JS 引用 --> <script th:src="@{/js/scalata.js}"></script>
@{/xxx}会自动适配Spring Boot的上下文路径(如配置了server.servlet.context-path),避免路径错误。
3. 排查Spring Boot配置是否修改了静态资源路径
查看application.properties或application.yml,若存在spring.web.resources.static-locations配置,需确认它包含默认静态资源目录:
# 示例:自定义路径时需保留默认目录 spring.web.resources.static-locations=classpath:/static/,classpath:/assets/
若配置仅包含自定义路径,而静态资源仍放在默认static/下,会导致资源无法被加载。
4. 确认Maven打包是否包含静态资源
执行mvn clean package后,用以下命令检查生成的jar包是否包含目标文件:
jar tf your-app.jar | grep scalata
若输出中没有css/scalata.css和js/scalata.js,说明Maven打包时排除了这些文件。检查pom.xml的<resources>配置,是否存在排除static/目录的规则:
<!-- 错误示例:需删除该exclude规则 --> <resources> <resource> <directory>src/main/resources</directory> <excludes> <exclude>static/**</exclude> </excludes> </resource> </resources>
5. 检查Docker构建与运行环节
- 确认Dockerfile正确复制了打包后的jar包:
COPY target/your-app.jar /app/app.jar CMD ["java", "-jar", "/app/app.jar"] - 启动容器后,进入容器验证jar包内的静态资源是否存在:
docker exec -it <容器ID> bash jar tf /app/app.jar | grep scalata
若通过挂载目录部署静态资源,需确认宿主机目录中确实存在scalata.css和scalata.js,且挂载路径与Spring Boot配置的静态资源路径对应。
6. 查看浏览器请求的实际URL
打开浏览器开发者工具(F12)的Network面板,查看请求静态资源的完整URL:
- 若URL为
http://xxx/css/scalata.css但返回404,说明资源确实不在该路径下; - 若URL包含上下文路径(如
http://xxx/scalata/css/scalata.css),需确保使用了Thymeleaf的@{...}语法适配路径。
7. 排查Spring Security拦截(若使用)
若项目引入了spring-boot-starter-security,默认会拦截所有请求,需在Security配置类中允许静态资源匿名访问:
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; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/css/**", "/js/**").permitAll() // 放行静态资源 .anyRequest().authenticated(); } }
内容的提问来源于stack exchange,提问作者Caterina Acce

