package cn.lihu.jh.server.ecg; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * 前端静态资源映射(配合"前端打进 jar"的合并部署方案)。 * *

作用

* 把 jar 内 {@code META-INF/resources/frontend/} 下的前端构建产物映射到站点根路径。 * *
 *   URL                         来源
 *   /assets/index-xxx.js   ->   classpath:/META-INF/resources/frontend/assets/index-xxx.js
 *   /logo.gif              ->   classpath:/META-INF/resources/frontend/logo.gif
 *   /favicon.ico           ->   classpath:/META-INF/resources/frontend/favicon.ico
 *   /static/jquery.min.js  ->   classpath:/META-INF/resources/frontend/static/jquery.min.js
 * 
* *

⚠ 为什么【不能】用 {@code /**} 通配(重要)

* 初版曾写成 {@code registry.addResourceHandler("/**")},这是**错误**的: * 一旦把 {@code /**} 指向前端目录,以下后端自带的路径会被静态资源处理器 * 抢先匹配,导致静态文件找不到而**直接 404**,控制器不再有机会处理: * * 因此这里改为**显式枚举前端真实存在的资源前缀**,把根路径留给后端自己。 * *

前端产物实际包含哪些顶层条目

* 依据 {@code dist-prod} 的实际构建结果: *
 *   index.html, favicon.ico, logo.gif          ← 文件
 *   bigCall.html, smallCall.html               ← kiosk 页(建议删除,见部署指南)
 *   assets/                                    ← 带内容哈希的 js/css/字体/图片
 *   static/                                    ← jquery、axios、vue 等第三方静态库
 * 
* *

SPA 深层路由的兜底

* 本类**不负责** SPA 兜底(前端用 {@code createWebHistory()},刷新深层路由 * 会 404)。兜底由 {@link SpaForwardController} 显式枚举 5 类页面路径完成, * 这样既修复刷新 404,又不会把后端真实的 404 吞成 index.html。 * * @author 心电排队装机系统 */ @Configuration public class FrontendResourceConfig implements WebMvcConfigurer { /** 前端产物在 jar 内的位置,需与 jh-server/pom.xml 中 targetPath 保持一致 */ private static final String FRONTEND_LOCATION = "classpath:/META-INF/resources/frontend/"; /** 带内容哈希的资源可长缓存(30 天) */ private static final long CACHE_HASHED = 3600L * 24 * 30; /** 无哈希的根级文件(logo.gif 等)短缓存,避免更新后浏览器不刷新(1 小时) */ private static final long CACHE_UNHASHED = 3600L; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // Vite 产出的带哈希资源目录 registry.addResourceHandler("/assets/**") .addResourceLocations(FRONTEND_LOCATION + "assets/") .setCachePeriod((int) CACHE_HASHED); // public/ 下原样拷贝的第三方静态库(jquery、axios、vue、element-ui 等) // 这些文件名不含哈希,用短缓存 registry.addResourceHandler("/static/**") .addResourceLocations(FRONTEND_LOCATION + "static/") .setCachePeriod((int) CACHE_UNHASHED); // 根级静态文件。逐个列出,避免 /doc.html、/druid/** 等被误拦截 // 文件名不含哈希,用短缓存 registry.addResourceHandler( "/favicon.ico", "/logo.gif", "/logo.png", "/logo0.png") .addResourceLocations(FRONTEND_LOCATION) .setCachePeriod((int) CACHE_UNHASHED); // 注意:index.html 不在此处映射。 // 它只应通过 SpaForwardController 的 forward:/frontend/index.html 访问, // 避免出现"两个入口都能拿到首页"的歧义。 } /** * 注册前端免登录规则。 *

* 必须显式声明为 Bean,框架才会通过 * {@code JhWebSecurityConfigurerAdapter} 收集并生效。 * 缺少此 Bean 的典型症状:接口都正常,但浏览器打开是白屏 * ({@code /logo.gif}、{@code /favicon.ico}、页面路径均返回 * {@code 401 账号未登录})。 * * @see FrontendAuthorizeRequestsCustomizer */ @Bean public FrontendAuthorizeRequestsCustomizer frontendAuthorizeRequestsCustomizer() { return new FrontendAuthorizeRequestsCustomizer(); } }