liusheng
4 天以前 0bbbd746e8c39d91ad7b47a4e36e29ab972dc98c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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} 挂到
 * <b>本模块 URL 前缀下的全部端点</b>上。
 *
 * <h3>⚠️ 用前缀通配,不逐个枚举路径(2025 二次调整)</h3>
 * 本类曾逐个枚举 15 条路径,理由是"可被静态断言"。但那个设计有个实际代价:
 * <b>以后往本模块加接口时,必须记得回来改这个清单</b> —— 忘了就静默不受开关管,
 * 而"忘了"这件事本身不会有任何报错。
 * <p>
 * 现在改为通配 {@link #GUARDED_PREFIX},语义是:
 * <b>本模块 URL 前缀下的所有端点都受开关管,新加接口自动生效,无需改配置</b>。
 * <p>
 * <b>丢掉的静态可断言性用探针补回来了,而且补得更强</b>:
 * {@code sql/_probe/verify_inhospvisit_switch.py} 不再比对"清单字面量",
 * 而是做两件更本质的事:
 * <ol>
 *   <li><b>从控制器源码实测</b>端点全集,断言它们**全部**被 {@link #GUARDED_PREFIX} 覆盖
 *       —— 覆盖不到的端点会 FAIL(等价于"新加接口忘了配置"的防线);</li>
 *   <li>反射调用 {@link #addInterceptors},读 Spring 实际注册的模式
 *       ({@code InterceptorRegistration.getPatterns()}),断言就是 {@link #GUARDED_PREFIX}
 *       —— 防"代码写着通配、实际注册的是别的"。</li>
 * </ol>
 *
 * <h3>口径:关就整个模块的 HTTP 面不可用</h3>
 * 用户实机把 {@code inhospvisit.enabled} 设为 false 后,
 * {@code POST /smartor/patinhosp/selectPatMedInhospList} 仍能查到数据。
 * 原设计是"只拦会生成随访的触发端点",用户决定改为"关就整个模块不可用",
 * 于是本前缀下 15 个端点全部受管。
 * <p>
 * <b>但只拦 HTTP,<u>不</u>动跨模块数据契约</b>:
 * <ul>
 *   <li>✅ HTTP(本前缀下全部端点)→ 关闭时报
 *       「出入院随访功能未启用(参数配置 inhospvisit.enabled=false),该接口不可用」;</li>
 *   <li>❌ {@code InhospVisitDataService}(HIS 采集、档案汇聚、统计等<b>模块内部/跨模块</b>访问)
 *       → <b>照常可用</b>。关掉随访不该让 HIS 写不进出入院记录
 *       (数据断流比"页面看不到"严重得多,且难恢复);
 *   <li>所以"整个模块不可用"的准确含义是<b>「该模块的 HTTP 面不可用」</b>。</li>
 * </ul>
 *
 * <h3>前缀的覆盖范围(实测,非照抄注释)</h3>
 * 该前缀下实际有 <b>15 个端点</b>,来自三个控制器:
 * {@code InhospVisitController}(3 个随访触发)、
 * {@code InhospVisitDataController}(9 个基础查询/CRUD)、
 * {@code com.ruoyi.web.controller.smartor.PatMedInhospController}(3 个复合端点,
 * 实现仍留在 smartor 但 URL 属本前缀)。
 * <p>
 * ⚠️ 旧注释写"14 个端点 / 复合端点 4 个",实测是 15 / 3 —— 这类"注释里的数字"
 * 正是口径混乱的来源,所以探针改为从源码实测。
 */
@Configuration
public class InhospVisitWebConfig implements WebMvcConfigurer {
 
    /**
     * 本模块的 URL 前缀。模块内所有控制器都挂在它下面
     * ({@code InhospVisitController} 与 {@code InhospVisitDataController} 实测均为
     * {@code @RequestMapping("/smartor/patinhosp")})。
     * <p>
     * ⚠️ 加新控制器时<b>必须</b>也用这个前缀 —— 否则它不会受开关管。
     * 探针会从源码实测所有控制器的 {@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;
    }
 
    /**
     * 本模块需要"关闭即明确报错"的路径模式。
     * <p>
     * ⚠️ 只有一条通配(见类注释的取舍说明)。
     * <b>不要</b>把它当成"受管端点清单"用 ——
     * 真实端点清单请用 {@code sql/_probe/verify_inhospvisit_switch.py} 从控制器源码实测。
     */
    public static List<String> guardedPathPatterns() {
        return new ArrayList<>(Arrays.asList(GUARDED_PREFIX));
    }
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(inhospVisitAvailabilityInterceptor)
                .addPathPatterns(guardedPathPatterns())
                // 拦截器本身很轻(只读一个 boolean),order 给个小值让它在业务拦截器之前执行
                .order(-100);
    }
}