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"的合并部署方案)。
|
*
|
* <h3>作用</h3>
|
* 把 jar 内 {@code META-INF/resources/frontend/} 下的前端构建产物映射到站点根路径。
|
*
|
* <pre>
|
* 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
|
* </pre>
|
*
|
* <h3>⚠ 为什么【不能】用 {@code /**} 通配(重要)</h3>
|
* 初版曾写成 {@code registry.addResourceHandler("/**")},这是**错误**的:
|
* 一旦把 {@code /**} 指向前端目录,以下后端自带的路径会被静态资源处理器
|
* 抢先匹配,导致静态文件找不到而**直接 404**,控制器不再有机会处理:
|
* <ul>
|
* <li>{@code /doc.html}、{@code /swagger-ui/**}、{@code /v3/api-docs/**}
|
* —— Knife4j / springdoc 接口文档</li>
|
* <li>{@code /druid/**} —— Druid 监控台(其 Servlet 已启用)</li>
|
* <li>{@code /actuator/**} —— Spring Boot 监控端点</li>
|
* <li>{@code /jmreport/**} —— 积木报表(若将来启用)</li>
|
* <li>{@code /admin-api/**} —— 全部业务接口</li>
|
* <li>{@code /profile/**} —— 心电模块
|
* {@code WebConfig} 映射到文件系统上传目录</li>
|
* </ul>
|
* 因此这里改为**显式枚举前端真实存在的资源前缀**,把根路径留给后端自己。
|
*
|
* <h3>前端产物实际包含哪些顶层条目</h3>
|
* 依据 {@code dist-prod} 的实际构建结果:
|
* <pre>
|
* index.html, favicon.ico, logo.gif ← 文件
|
* bigCall.html, smallCall.html ← kiosk 页(建议删除,见部署指南)
|
* assets/ ← 带内容哈希的 js/css/字体/图片
|
* static/ ← jquery、axios、vue 等第三方静态库
|
* </pre>
|
*
|
* <h3>SPA 深层路由的兜底</h3>
|
* 本类**不负责** 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 访问,
|
// 避免出现"两个入口都能拿到首页"的歧义。
|
}
|
|
/**
|
* 注册前端免登录规则。
|
* <p>
|
* 必须显式声明为 Bean,框架才会通过
|
* {@code JhWebSecurityConfigurerAdapter} 收集并生效。
|
* 缺少此 Bean 的典型症状:接口都正常,但浏览器打开是白屏
|
* ({@code /logo.gif}、{@code /favicon.ico}、页面路径均返回
|
* {@code 401 账号未登录})。
|
*
|
* @see FrontendAuthorizeRequestsCustomizer
|
*/
|
@Bean
|
public FrontendAuthorizeRequestsCustomizer frontendAuthorizeRequestsCustomizer() {
|
return new FrontendAuthorizeRequestsCustomizer();
|
}
|
}
|