package com.ruoyi.message.config;
|
|
import com.ruoyi.message.MessageChannel;
|
import com.ruoyi.message.SendResult;
|
import com.ruoyi.message.sms.SmsSendRequest;
|
import com.ruoyi.message.sms.SmsSender;
|
import com.ruoyi.message.sms.SmsSenderFactory;
|
import com.ruoyi.message.sms.provider.shiyi.ShiyiSmsUtil;
|
import com.ruoyi.message.wechat.WechatSendRequest;
|
import com.ruoyi.message.wechat.WechatSender;
|
import com.ruoyi.message.wechat.WechatSenderFactory;
|
import org.springframework.boot.context.properties.bind.Bindable;
|
import org.springframework.boot.context.properties.bind.Binder;
|
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.StandardEnvironment;
|
|
import java.io.IOException;
|
import java.util.Collections;
|
import java.util.List;
|
|
/**
|
* 「新增 {@code message.*} 前缀项」的绑定与工厂装配校验(不依赖 JUnit)。
|
* <p>
|
* 覆盖两件事:
|
* <ol>
|
* <li>{@code message.sms.*} / {@code message.wechat.*} 能绑到对应的嵌套字段,未覆盖的项回落默认值;</li>
|
* <li>工厂按 key 路由确实是「调用到对应发送方」——这是四个站点发送链路里本地唯一能验证的一环。</li>
|
* </ol>
|
*/
|
public final class MessagePrefixBindingCheck {
|
|
private static int failed = 0;
|
|
private MessagePrefixBindingCheck() {
|
}
|
|
public static void main(String[] args) throws Exception {
|
String[] yaml = {
|
"message:",
|
" sms:",
|
" shiyi:",
|
" ws-url: http://his.example.com:7790/MediInfoHis.svc",
|
" default-caozuoydm: OPR001",
|
" messaging-insert:",
|
" ws-url: http://msg.example.com:8081/MessagingInsert.asmx",
|
" wechat:",
|
" shiyi:",
|
" title: 自定义标题",
|
" xinhua:",
|
" service: custom.service",
|
};
|
ConfigurableEnvironment environment = environment(yaml);
|
Binder binder = new Binder(ConfigurationPropertySources.get(environment));
|
|
// ---------- 1) 前缀项绑定 ----------
|
MessageProperties.Sms sms = binder
|
.bind(ConfigurationPropertyName.of("message.sms"), Bindable.of(MessageProperties.Sms.class))
|
.orElseGet(MessageProperties.Sms::new);
|
MessageProperties.Wechat wechat = binder
|
.bind(ConfigurationPropertyName.of("message.wechat"), Bindable.of(MessageProperties.Wechat.class))
|
.orElseGet(MessageProperties.Wechat::new);
|
|
check("message.sms.shiyi.ws-url", "http://his.example.com:7790/MediInfoHis.svc",
|
sms.getShiyi().getWsUrl());
|
check("message.sms.shiyi.default-caozuoydm", "OPR001", sms.getShiyi().getDefaultCaozuoydm());
|
check("message.sms.messaging-insert.ws-url", "http://msg.example.com:8081/MessagingInsert.asmx",
|
sms.getMessagingInsert().getWsUrl());
|
check("message.wechat.shiyi.title", "自定义标题", wechat.getShiyi().getTitle());
|
check("message.wechat.xinhua.service", "custom.service", wechat.getXinhua().getService());
|
// 同组未覆盖项应回落默认值
|
check("message.wechat.shiyi.url(回落默认)", "http://192.200.54.14:5003/sfjk/SendMessage",
|
wechat.getShiyi().getUrl());
|
check("message.sms.shiyi.ws-url 默认值不丢", "http://192.178.0.104:7790/MediInfoHis.svc",
|
new MessageProperties.Sms().getShiyi().getWsUrl());
|
|
// ---------- 2) 工厂路由确实调到对应发送方 ----------
|
SmsSenderFactory smsFactory = new SmsSenderFactory(Collections.<SmsSender>singletonList(new CountingSmsSender()));
|
WechatSenderFactory wechatFactory = new WechatSenderFactory(Collections.<WechatSender>singletonList(new CountingWechatSender()));
|
|
SendResult smsResult = smsFactory.send("probe-channel", SmsSendRequest.of("13500000001", "内容"));
|
check("短信工厂按 key 路由到对应发送方", "true", String.valueOf(smsResult.isOk()));
|
|
SendResult wechatResult = wechatFactory.send("probe-channel", new WechatSendRequest());
|
check("公众号工厂按 key 路由到对应发送方", "true", String.valueOf(wechatResult.isOk()));
|
|
try {
|
smsFactory.send("不存在的渠道", SmsSendRequest.of("13500000001", "内容"));
|
check("未知渠道应抛 SendException", "抛异常", "没抛");
|
} catch (com.ruoyi.message.SendException e) {
|
check("未知渠道应抛 SendException", "抛异常", "抛异常");
|
}
|
|
// ---------- 3) ShiyiSmsUtil 仍能正常构造(保底回调/参数校验行为不丢) ----------
|
ShiyiSmsUtil shiyiSmsUtil = new ShiyiSmsUtil(new MessageProperties(new RootMessageProperties()));
|
boolean paramChecked = false;
|
try {
|
shiyiSmsUtil.sendSms(null);
|
} catch (IllegalArgumentException e) {
|
paramChecked = "短信请求不能为空".equals(e.getMessage());
|
}
|
check("ShiyiSmsUtil 入参校验仍生效", "true", String.valueOf(paramChecked));
|
|
System.out.println();
|
if (failed == 0) {
|
System.out.println("===== message.* 绑定与工厂路由校验全部通过 =====");
|
} else {
|
System.out.println("===== message.* 绑定与工厂路由校验失败 " + failed + " 项 =====");
|
System.exit(1);
|
}
|
}
|
|
private static ConfigurableEnvironment environment(String[] inlineYaml) throws IOException {
|
ConfigurableEnvironment environment = new StandardEnvironment();
|
environment.getPropertySources()
|
.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
|
environment.getPropertySources()
|
.remove(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
|
org.springframework.boot.env.YamlPropertySourceLoader loader =
|
new org.springframework.boot.env.YamlPropertySourceLoader();
|
List<PropertySource<?>> sources = loader.load("inline.yml",
|
new org.springframework.core.io.ByteArrayResource(
|
String.join("\n", inlineYaml).getBytes(java.nio.charset.StandardCharsets.UTF_8)));
|
for (PropertySource<?> source : sources) {
|
environment.getPropertySources().addLast(source);
|
}
|
return environment;
|
}
|
|
private static void check(String key, String expected, String actual) {
|
boolean ok = expected.equals(actual);
|
if (!ok) {
|
failed++;
|
}
|
System.out.println((ok ? "[OK] " : "[FAIL] ") + key + " 期望=[" + expected + "] 实际=[" + actual + "]");
|
}
|
|
/** 探针短信发送方 */
|
static class CountingSmsSender implements SmsSender {
|
@Override
|
public String key() {
|
return "probe-channel";
|
}
|
|
@Override
|
public SendResult send(SmsSendRequest request) {
|
return SendResult.success(key(), MessageChannel.SMS, "called");
|
}
|
}
|
|
/** 探针公众号发送方 */
|
static class CountingWechatSender implements WechatSender {
|
@Override
|
public String key() {
|
return "probe-channel";
|
}
|
|
@Override
|
public SendResult send(WechatSendRequest request) {
|
return SendResult.success(key(), MessageChannel.WECHAT, "called");
|
}
|
}
|
}
|