liusheng
5 天以前 cc479e6a056785103996cc7ea67dbd5faa3e800e
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
package com.ruoyi.inhospvisit.config;
 
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * 出入院随访模块开关拦截器。
 * <p>
 * <b>作用</b>:当开关关闭({@code sys_config} 中 {@code inhospvisit.enabled=false})时,
 * 命中出入院随访端点的请求会被立即拦下并抛出 {@link ServiceException},
 * 由 RuoYi 的全局异常处理器返回<b>明确的业务错误提示</b>(而不是 404 或静默返回空数据)。
 * <p>
 * 开关值由 {@link InhospVisitSwitch} 在运行时读取({@code sys_config},10 秒进程内缓存),
 * 因此改完参数设置<b>不需要重启</b>,最多 10 秒即生效。
 *
 * <h3>⚠️ 本拦截器<b>不覆盖定时任务</b></h3>
 * {@code RyTask.dealOutHospInfo} 等定时入口不走 MVC,因此不受本开关影响 —— 这是刻意的:
 * 关掉定时任务 = 当天全院随访停摆,而开关是热读的,一次误操作毫无反馈渠道。
 * 要停定时任务请到「系统管理 → 定时任务」暂停对应的 {@code sys_job}。
 *
 * <h3>为什么不用 {@code @ConditionalOnProperty} 让 Controller 直接不注册</h3>
 * <ul>
 *   <li>那样调用方只会拿到 HTTP 404 —— 前端/运维无法区分"模块被关闭"和"地址写错了";</li>
 *   <li>而且 {@code @ConditionalOnProperty} 只在<b>启动时</b>求值一次,
 *       做不到"改完参数配置就生效",与参数表开关的诉求冲突。</li>
 * </ul>
 *
 * <h3>为什么不会影响其它业务与启动</h3>
 * <ul>
 *   <li>本拦截器只登记在<b>本模块的端点</b>的精确路径上(见 {@link InhospVisitWebConfig}),
 *       绝不用 {@code /smartor/patinhosp/**} 这种前缀 —— 那个前缀下还有大量出入院记录 CRUD 端点
 *       ({@code selectPatMedInhospList} / {@code add} / {@code edit} / {@code remove} / {@code export} …),
 *       它们属于记录管理业务,模块关闭时必须继续可用;</li>
 *   <li>模块关闭时,Controller 与 Service 依旧是普通 Bean(启动不受影响),
 *       其它模块通过 {@code InhospVisitFacade} 调用时拿到的是安全空值,
 *       只有"专门调随访触发端点"的请求才会收到错误。</li>
 * </ul>
 */
@Slf4j
@Component
public class InhospVisitAvailabilityInterceptor implements HandlerInterceptor {
 
    /**
     * 模块被关闭时返回给调用方的错误提示(前端可直接展示)
     * <p>
     * ⚠️ <b>2025 更正</b>:本常量原先在末尾补了一句
     * 「定时任务不受此开关控制,如需停止请在「系统管理 → 定时任务」暂停对应的任务」—— 
     * 那句话<b>已不成立</b>:定时任务的 5 个入口现已全部接开关
     * (4 个走门面、{@code dealSubtaskDeadline} 走入口守卫)。
     * 提示语是运维直接看到的文本,留着它比不写更糟(会让人去停 sys_job)。
     */
    public static final String DISABLED_MESSAGE =
            "出入院随访功能未启用(参数配置 inhospvisit.enabled=false),该接口不可用";
 
    private final InhospVisitSwitch inhospVisitSwitch;
 
    public InhospVisitAvailabilityInterceptor(InhospVisitSwitch inhospVisitSwitch) {
        this.inhospVisitSwitch = inhospVisitSwitch;
    }
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!inhospVisitSwitch.isEnabled()) {
            // request 允许为 null(单元测试直接调 preHandle 时不构造请求对象)
            String method = request == null ? "-" : request.getMethod();
            String uri = request == null ? "-" : request.getRequestURI();
            log.warn("【出入院随访】模块已关闭(参数配置 inhospvisit.enabled=false),拒绝访问 {} {}", method, uri);
            throw new ServiceException(DISABLED_MESSAGE);
        }
        return true;
    }
}