package com.ruoyi.message.config; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; /** * 消息发送配置自检。 *

* 存在的意义:这些 key 过去是散落在各处的 {@code @Value},改成 {@code @ConfigurationProperties} * 之后如果前缀/层级写错,**编译期完全发现不了**,直到线上发短信时才发现参数是 null。 * 因此启动时把当前 profile 真正用到的配置项打印出来(密钥脱敏),并对空值告警。 */ @Slf4j @Component public class MessageConfigValidator implements ApplicationRunner { private final MessageProperties properties; @Value("${spring.profiles.active:}") private String active; public MessageConfigValidator(MessageProperties properties) { this.properties = properties; } @Override public void run(ApplicationArguments args) { MessageProperties.Sms sms = properties.getSms(); XhsmsConfig xhsms = sms.getXhsms(); MtSmsConfig mt = sms.getMt(); AliyunSmsConfig aliyun = sms.getAliyun(); log.info("【消息配置自检】active={},xhsms: path={}, account={}, pwd={}, extno={}", active, mask(xhsms.getPath()), mask(xhsms.getAccount()), maskSecret(xhsms.getPwd()), mask(xhsms.getExtno())); log.info("【消息配置自检】mt(nhfy): url={}, accountName={}, password={}, sourceAddr={}, serviceCode={}, appkey={}, flag={}", mask(mt.getUrl()), mask(mt.getAccountName()), maskSecret(mt.getPassword()), mask(mt.getSourceAddr()), mask(mt.getServiceCode()), mask(mt.getAppkey()), mask(mt.getFlag())); log.info("【消息配置自检】aliyun: accessKeyId={}, accessKeySecret={}, signName={}", mask(aliyun.getAccessKeyId()), maskSecret(aliyun.getAccessKeySecret()), mask(aliyun.getSignName())); log.info("【消息配置自检】wechat: shiyi.url={}, shiyi.key={}, xinhua.service={}", mask(properties.getWechat().getShiyi().getUrl()), maskSecret(properties.getWechat().getShiyi().getKey()), mask(properties.getWechat().getXinhua().getService())); check("active", active); if ("xh".equals(active) || "hzszlyy".equals(active)) { check("xhsmsPath", xhsms.getPath()); check("xhsmsAccount", xhsms.getAccount()); check("xhsmsPwd", xhsms.getPwd()); } else if ("nhfy".equals(active)) { check("sms_url", mt.getUrl()); check("sms_accountName", mt.getAccountName()); check("sms_password", mt.getPassword()); check("sms_sourceAddr", mt.getSourceAddr()); check("sms_serviceCode", mt.getServiceCode()); check("sms_flag", mt.getFlag()); } } private void check(String key, String value) { if (value == null || value.trim().isEmpty()) { log.warn("【消息配置自检】⚠️ 当前 profile({})需要 {},但该配置为空/未绑定!" + "请检查 application-{}.yml 与 MessageProperties/RootMessageProperties 的绑定层级。", active, key, active); } } private String mask(String value) { if (value == null) { return ""; } if (value.isEmpty()) { return "<空>"; } return value; } private String maskSecret(String value) { if (value == null) { return ""; } if (value.isEmpty()) { return "<空>"; } if (value.length() <= 2) { return "**"; } return value.substring(0, 1) + "***" + value.substring(value.length() - 1); } }