package com.ruoyi.inhospvisit.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 出入院随访模块的 MVC 配置:把 {@link InhospVisitAvailabilityInterceptor} 挂到 * 本模块 URL 前缀下的全部端点上。 * *

⚠️ 用前缀通配,不逐个枚举路径(2025 二次调整)

* 本类曾逐个枚举 15 条路径,理由是"可被静态断言"。但那个设计有个实际代价: * 以后往本模块加接口时,必须记得回来改这个清单 —— 忘了就静默不受开关管, * 而"忘了"这件事本身不会有任何报错。 *

* 现在改为通配 {@link #GUARDED_PREFIX},语义是: * 本模块 URL 前缀下的所有端点都受开关管,新加接口自动生效,无需改配置。 *

* 丢掉的静态可断言性用探针补回来了,而且补得更强: * {@code sql/_probe/verify_inhospvisit_switch.py} 不再比对"清单字面量", * 而是做两件更本质的事: *

    *
  1. 从控制器源码实测端点全集,断言它们**全部**被 {@link #GUARDED_PREFIX} 覆盖 * —— 覆盖不到的端点会 FAIL(等价于"新加接口忘了配置"的防线);
  2. *
  3. 反射调用 {@link #addInterceptors},读 Spring 实际注册的模式 * ({@code InterceptorRegistration.getPatterns()}),断言就是 {@link #GUARDED_PREFIX} * —— 防"代码写着通配、实际注册的是别的"。
  4. *
* *

口径:关就整个模块的 HTTP 面不可用

* 用户实机把 {@code inhospvisit.enabled} 设为 false 后, * {@code POST /smartor/patinhosp/selectPatMedInhospList} 仍能查到数据。 * 原设计是"只拦会生成随访的触发端点",用户决定改为"关就整个模块不可用", * 于是本前缀下 15 个端点全部受管。 *

* 但只拦 HTTP,不动跨模块数据契约: *

* *

前缀的覆盖范围(实测,非照抄注释)

* 该前缀下实际有 15 个端点,来自三个控制器: * {@code InhospVisitController}(3 个随访触发)、 * {@code InhospVisitDataController}(9 个基础查询/CRUD)、 * {@code com.ruoyi.web.controller.smartor.PatMedInhospController}(3 个复合端点, * 实现仍留在 smartor 但 URL 属本前缀)。 *

* ⚠️ 旧注释写"14 个端点 / 复合端点 4 个",实测是 15 / 3 —— 这类"注释里的数字" * 正是口径混乱的来源,所以探针改为从源码实测。 */ @Configuration public class InhospVisitWebConfig implements WebMvcConfigurer { /** * 本模块的 URL 前缀。模块内所有控制器都挂在它下面 * ({@code InhospVisitController} 与 {@code InhospVisitDataController} 实测均为 * {@code @RequestMapping("/smartor/patinhosp")})。 *

* ⚠️ 加新控制器时必须也用这个前缀 —— 否则它不会受开关管。 * 探针会从源码实测所有控制器的 {@code @RequestMapping} 与端点, * 凡覆盖不到本前缀的都会 FAIL。 */ public static final String MODULE_URL_PREFIX = "/smartor/patinhosp"; /** * 拦截器实际注册的模式(通配整个前缀)。 */ public static final String GUARDED_PREFIX = MODULE_URL_PREFIX + "/**"; @Autowired private InhospVisitAvailabilityInterceptor inhospVisitAvailabilityInterceptor; /** * 供测试/非 Spring 环境直接构造 */ public InhospVisitWebConfig() { } public InhospVisitWebConfig(InhospVisitAvailabilityInterceptor interceptor) { this.inhospVisitAvailabilityInterceptor = interceptor; } /** * 本模块需要"关闭即明确报错"的路径模式。 *

* ⚠️ 只有一条通配(见类注释的取舍说明)。 * 不要把它当成"受管端点清单"用 —— * 真实端点清单请用 {@code sql/_probe/verify_inhospvisit_switch.py} 从控制器源码实测。 */ public static List guardedPathPatterns() { return new ArrayList<>(Arrays.asList(GUARDED_PREFIX)); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(inhospVisitAvailabilityInterceptor) .addPathPatterns(guardedPathPatterns()) // 拦截器本身很轻(只读一个 boolean),order 给个小值让它在业务拦截器之前执行 .order(-100); } }