change
This commit is contained in:
@@ -8,49 +8,5 @@ import java.util.List;
|
||||
|
||||
public interface SmsService {
|
||||
|
||||
/**
|
||||
* 发送短信消息。
|
||||
*
|
||||
* @param request 短信请求参数,需传接收人、发送人、模板ID或消息内容等字段
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
MsgPlatformResponse sendSms(MsgPlatformSmsRequest request);
|
||||
|
||||
/**
|
||||
* 通过工号发送短信文本消息的便捷方法。
|
||||
* controller 只需要传接收人工号,以及短信内容即可。
|
||||
*
|
||||
* @param account 接收人工号
|
||||
* @param content 短信内容
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
MsgPlatformResponse sendSmsByAccount(String account, String content);
|
||||
|
||||
/**
|
||||
* 通过手机号发送短信文本消息的便捷方法。
|
||||
* controller 只需要传接收人手机号,以及短信内容即可。
|
||||
*
|
||||
* @param mobile 接收人手机号
|
||||
* @param content 短信内容
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
MsgPlatformResponse sendSmsByMobile(String mobile, String content);
|
||||
|
||||
/**
|
||||
* 发送微信消息。
|
||||
*
|
||||
* @param request 微信请求参数,需传接收人、发送人、消息类型、模板ID或消息内容等字段
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
MsgPlatformResponse sendWechat(MsgPlatformWechatRequest request);
|
||||
|
||||
/**
|
||||
* 发送微信文本消息的便捷方法。
|
||||
* controller 只需要传接收人工号或手机号,以及微信文本内容即可。
|
||||
*
|
||||
* @param accountOrMobile 接收人工号或手机号
|
||||
* @param content 微信文本内容
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
MsgPlatformResponse sendWechatTextByAccountOrMobile(String accountOrMobile, String content);
|
||||
Boolean sendSmMsg(String loginName, String content);
|
||||
}
|
||||
|
||||
@@ -4,13 +4,16 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.sms.SmsService;
|
||||
import com.budwk.app.base.sms.model.*;
|
||||
import com.budwk.app.web.commons.base.Globals;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.integration.jedis.RedisService;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
@@ -43,502 +46,115 @@ import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
@IocBean
|
||||
public class SmsServiceImpl implements SmsService {
|
||||
private static final Log log = Logs.get();
|
||||
private static final String SMS_API_PATH = "/tp_mp/api/SmsService/saveSmsInfo";
|
||||
private static final String WECHAT_API_PATH = "/tp_mp/api/WechatService/saveWechatInfo";
|
||||
private static final int MAX_RECEIVER_COUNT = 500;
|
||||
private static final String TOKEN_URL = "https://api.swufe.edu.cn/sms/gettoken";
|
||||
private static final String SMS_SEND_URL = "https://api.swufe.edu.cn/sms/smsend";
|
||||
private static final String USERNAME = "xiaogonghui";
|
||||
private static final String PASSWORD = "90A089-KJ765_$L1bQbM@x";
|
||||
private static final String FLAG = "8FA490968B2FB6E95B7991AA0C9C31FD";
|
||||
|
||||
@Inject
|
||||
private PropertiesProxy conf;
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
|
||||
/**
|
||||
* 发送短信消息。
|
||||
*
|
||||
* @param request 短信请求参数,需传接收人、发送人、模板ID或消息内容等字段
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
@Override
|
||||
public MsgPlatformResponse sendSms(MsgPlatformSmsRequest request) {
|
||||
validateCommonRequest(request);
|
||||
JSONObject payload = buildCommonPayload(request, true);
|
||||
return doPost(SMS_API_PATH, payload);
|
||||
}
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
/**
|
||||
* 通过工号发送短信文本消息的便捷方法。
|
||||
* 该方法适合 controller 里只传“工号 + 内容”的简单场景,发送人信息从配置中读取。
|
||||
*
|
||||
* @param account 接收人工号
|
||||
* @param content 短信内容
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
@Override
|
||||
public MsgPlatformResponse sendSmsByAccount(String account, String content) {
|
||||
MsgPlatformSmsRequest request = new MsgPlatformSmsRequest();
|
||||
request.setInfo(content);
|
||||
request.setRecipients(buildAccountRecipients(account));
|
||||
fillDefaultSenderInfo(request);
|
||||
return sendSms(request);
|
||||
}
|
||||
@Inject
|
||||
private PropertiesProxy conf;
|
||||
|
||||
/**
|
||||
* 通过手机号发送短信文本消息的便捷方法。
|
||||
* 该方法适合 controller 里只传“手机号 + 内容”的简单场景,发送人信息从配置中读取。
|
||||
*
|
||||
* @param mobile 接收人手机号
|
||||
* @param content 短信内容
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
@Override
|
||||
public MsgPlatformResponse sendSmsByMobile(String mobile, String content) {
|
||||
MsgPlatformSmsRequest request = new MsgPlatformSmsRequest();
|
||||
request.setInfo(content);
|
||||
request.setRecipients(buildMobileRecipients(mobile));
|
||||
request.setCustomVar(Map.of("1","","2","","3",content));
|
||||
fillDefaultSenderInfo(request);
|
||||
return sendSms(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送微信消息。
|
||||
*
|
||||
* @param request 微信请求参数,需传接收人、发送人、消息类型、模板ID或消息内容等字段
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
@Override
|
||||
public MsgPlatformResponse sendWechat(MsgPlatformWechatRequest request) {
|
||||
validateCommonRequest(request);
|
||||
if (Strings.isBlank(request.getWechatType())) {
|
||||
request.setWechatType("text");
|
||||
}
|
||||
if ("news".equalsIgnoreCase(request.getWechatType()) && Strings.isBlank(request.getInfo())) {
|
||||
if (request.getNewsItems() == null || request.getNewsItems().isEmpty()) {
|
||||
throw new BaseException("微信图文消息必须传 info 或 newsItems");
|
||||
}
|
||||
request.setInfo(JSONUtil.toJsonStr(request.getNewsItems()));
|
||||
}
|
||||
JSONObject payload = buildCommonPayload(request, false);
|
||||
payload.set("wechat_type", request.getWechatType());
|
||||
return doPost(WECHAT_API_PATH, payload);
|
||||
}
|
||||
/**
|
||||
* 发送短信
|
||||
*
|
||||
* @param loginname 工号
|
||||
* @param content 消息内容
|
||||
* @return 发送结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean sendSmMsg(String loginname, String content) {
|
||||
try {
|
||||
if (!Globals.sso){
|
||||
log.error("【log】开发模式不允许发送消息通知");
|
||||
throw new RuntimeException("开发模式不允许发送消息通知");
|
||||
}
|
||||
if (!Globals.MyConfig.getBoolean("AppSms", false)) {
|
||||
log.error("【log】短信配置未开启");
|
||||
throw new RuntimeException("短信配置未开启");
|
||||
}
|
||||
if (!conf.getBoolean("msg.platform.enabled", false)) {
|
||||
throw new RuntimeException("短信配置未开启");
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送微信文本消息的便捷方法。
|
||||
* 该方法适合 controller 里只传“工号/手机号 + 内容”的简单场景,发送人信息从配置中读取。
|
||||
*
|
||||
* @param accountOrMobile 接收人工号或手机号
|
||||
* @param content 微信文本内容
|
||||
* @return 通讯平台返回结果,返回类型为 {@link MsgPlatformResponse}
|
||||
*/
|
||||
@Override
|
||||
public MsgPlatformResponse sendWechatTextByAccountOrMobile(String accountOrMobile, String content) {
|
||||
MsgPlatformWechatRequest request = new MsgPlatformWechatRequest();
|
||||
request.setInfo(content);
|
||||
request.setWechatType("text");
|
||||
request.setRecipients(buildWechatRecipients(accountOrMobile));
|
||||
fillDefaultSenderInfo(request);
|
||||
return sendWechat(request);
|
||||
}
|
||||
if (StrUtil.isBlank(loginname) || StrUtil.isBlank(content)) {
|
||||
log.info("发送失败,缺少需要参数请检查!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
throw new RuntimeException("发送失败,缺少需要参数请检查");
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装平台公共请求体。
|
||||
*
|
||||
* @param request 平台请求参数
|
||||
* @param includeMobile 是否在 person_info 第 5 段写入手机号
|
||||
* @return 返回发送给第三方平台的 JSON 对象
|
||||
*/
|
||||
private JSONObject buildCommonPayload(MsgPlatformBaseRequest request, boolean includeMobile) {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.set("tp_name", getRequiredConfig("msg.platform.tp-name", "请先配置 msg.platform.tp-name"));
|
||||
payload.set("secret_key", getSecretKey());
|
||||
payload.set("person_info", resolvePersonInfo(request, includeMobile));
|
||||
payload.set("template_id", Strings.sNull(request.getTemplateId()));
|
||||
payload.set("info", Strings.sNull(request.getInfo()));
|
||||
payload.set("send_priority", Strings.isBlank(request.getSendPriority()) ? "3" : request.getSendPriority());
|
||||
payload.set("send_user_id", Strings.sNull(request.getSendUserId()));
|
||||
payload.set("send_user_name", Strings.sNull(request.getSendUserName()));
|
||||
payload.set("send_time", Strings.sNull(request.getSendTime()));
|
||||
payload.set("send_unit_id", Strings.sNull(request.getSendUnitId()));
|
||||
payload.set("send_unit_name", Strings.sNull(request.getSendUnitName()));
|
||||
payload.set("send_user_sign", Strings.sNull(request.getSendUserSign()));
|
||||
payload.set("receipt_id", Strings.isBlank(request.getReceiptId()) ? "0" : request.getReceiptId());
|
||||
if (request.getCustomVar() != null && !request.getCustomVar().isEmpty()) {
|
||||
payload.set("custom_var", JSONUtil.toJsonStr(request.getCustomVar()));
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
String token = getToken();
|
||||
if (StrUtil.isBlank(token)) {
|
||||
log.info("获取 token 失败!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
throw new RuntimeException("获取 token 失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验公共请求参数,避免 controller 传错参数后才到第三方接口报错。
|
||||
*
|
||||
* @param request 平台请求参数
|
||||
*/
|
||||
private void validateCommonRequest(MsgPlatformBaseRequest request) {
|
||||
if (request == null) {
|
||||
throw new BaseException("请求参数不能为空");
|
||||
}
|
||||
if (Strings.isBlank(request.getPersonInfo()) && (request.getRecipients() == null || request.getRecipients().isEmpty())) {
|
||||
throw new BaseException("personInfo 和 recipients 不能同时为空");
|
||||
}
|
||||
if (Strings.isBlank(request.getTemplateId()) && Strings.isBlank(request.getInfo())) {
|
||||
throw new BaseException("templateId 和 info 至少需要传一个");
|
||||
}
|
||||
if (Strings.isBlank(request.getSendUserId())) {
|
||||
throw new BaseException("sendUserId 不能为空");
|
||||
}
|
||||
if (Strings.isBlank(request.getSendUserName())) {
|
||||
throw new BaseException("sendUserName 不能为空");
|
||||
}
|
||||
if (Strings.isBlank(request.getSendPriority())) {
|
||||
request.setSendPriority("3");
|
||||
}
|
||||
if ("4".equals(request.getSendPriority()) && Strings.isBlank(request.getSendTime())) {
|
||||
throw new BaseException("sendPriority=4 时必须传 sendTime");
|
||||
}
|
||||
validateReceiverCount(request.getPersonInfo(), request.getRecipients());
|
||||
}
|
||||
com.alibaba.fastjson.JSONObject requestJson = new com.alibaba.fastjson.JSONObject();
|
||||
requestJson.put("zh", loginname);
|
||||
requestJson.put("smstxt", content);
|
||||
requestJson.put("token", token);
|
||||
requestJson.put("flag", FLAG);
|
||||
|
||||
/**
|
||||
* 解析 person_info。
|
||||
* 已传原始 personInfo 时直接使用;否则根据 recipients 自动拼接平台要求的格式。
|
||||
*
|
||||
* @param request 平台请求参数
|
||||
* @param includeMobile 是否在第 5 段写入手机号
|
||||
* @return 平台要求的 person_info 字符串
|
||||
*/
|
||||
private String resolvePersonInfo(MsgPlatformBaseRequest request, boolean includeMobile) {
|
||||
if (Strings.isNotBlank(request.getPersonInfo())) {
|
||||
return request.getPersonInfo();
|
||||
}
|
||||
List<MsgPlatformRecipient> recipients = request.getRecipients();
|
||||
if (recipients == null || recipients.isEmpty()) {
|
||||
throw new BaseException("接收人列表不能为空");
|
||||
}
|
||||
return recipients.stream().map(recipient -> buildReceiverLine(recipient, includeMobile)).collect(Collectors.joining("^@^"));
|
||||
}
|
||||
String response = HttpUtil.createPost(SMS_SEND_URL).body(Json.toJson(requestJson)).execute().body();
|
||||
log.info("短信发送响应:" + response);
|
||||
|
||||
/**
|
||||
* 将单个接收人转成平台要求的分隔符格式。
|
||||
*
|
||||
* @param recipient 接收人对象
|
||||
* @param includeMobile 是否在最后一段补手机号
|
||||
* @return 单个接收人的 person_info 片段
|
||||
*/
|
||||
private String buildReceiverLine(MsgPlatformRecipient recipient, boolean includeMobile) {
|
||||
if (recipient == null) {
|
||||
throw new BaseException("接收人信息中存在空对象");
|
||||
}
|
||||
List<String> segments = new ArrayList<>(5);
|
||||
segments.add(Strings.sNull(recipient.getName()));
|
||||
segments.add(Strings.sNull(recipient.getAccount()));
|
||||
segments.add(Strings.sNull(recipient.getUnitId()));
|
||||
segments.add(Strings.sNull(recipient.getUnitName()));
|
||||
if (includeMobile) {
|
||||
segments.add(resolveSmsMobile(recipient));
|
||||
} else {
|
||||
segments.add("");
|
||||
}
|
||||
return String.join("|", segments);
|
||||
}
|
||||
com.alibaba.fastjson.JSONObject responseJson = JSON.parseObject(response);
|
||||
if (responseJson != null && responseJson.getIntValue("code") == 200) {
|
||||
log.info("短信发送成功!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
return true;
|
||||
} else {
|
||||
log.info("短信发送失败!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + response);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析短信接收人手机号。
|
||||
* 如果 controller 传的是手机号,则校验手机号格式;
|
||||
* 如果传的是工号,则允许手机号为空,按“姓名|工号|部门ID|部门名称|”格式发送。
|
||||
*
|
||||
* @param recipient 接收人信息
|
||||
* @return 短信 person_info 第 5 段内容
|
||||
*/
|
||||
private String resolveSmsMobile(MsgPlatformRecipient recipient) {
|
||||
String mobile = recipient.getMobile();
|
||||
if (Strings.isBlank(mobile)) {
|
||||
if (Strings.isBlank(recipient.getAccount())) {
|
||||
throw new BaseException("短信接收人手机号和工号不能同时为空");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
if (!mobile.matches("^\\d{11}$")) {
|
||||
throw new BaseException("短信接收人手机号必须为11位数字");
|
||||
}
|
||||
return mobile;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("短信发送异常!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验接收人数量,避免超过第三方平台单次上限。
|
||||
*
|
||||
* @param personInfo 原始 person_info
|
||||
* @param recipients 接收人列表
|
||||
*/
|
||||
private void validateReceiverCount(String personInfo, List<MsgPlatformRecipient> recipients) {
|
||||
int receiverCount;
|
||||
if (Strings.isNotBlank(personInfo)) {
|
||||
receiverCount = personInfo.split("\\^@\\^", -1).length;
|
||||
} else {
|
||||
receiverCount = recipients == null ? 0 : recipients.size();
|
||||
}
|
||||
if (receiverCount > MAX_RECEIVER_COUNT) {
|
||||
throw new BaseException("单次发送人数不能超过" + MAX_RECEIVER_COUNT + "人");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取 token
|
||||
*
|
||||
* @return token
|
||||
*/
|
||||
private String getToken() {
|
||||
try {
|
||||
String token = redisService.get("msg_token");
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建工号发送专用接收人列表。
|
||||
*
|
||||
* @param account controller 传入的工号
|
||||
* @return 仅包含一个接收人的列表
|
||||
*/
|
||||
private List<MsgPlatformRecipient> buildAccountRecipients(String account) {
|
||||
if (Strings.isBlank(account)) {
|
||||
throw new BaseException("接收人工号不能为空");
|
||||
}
|
||||
MsgPlatformRecipient recipient = new MsgPlatformRecipient();
|
||||
recipient.setAccount(account);
|
||||
List<MsgPlatformRecipient> recipients = new ArrayList<>(1);
|
||||
recipients.add(recipient);
|
||||
return recipients;
|
||||
}
|
||||
com.alibaba.fastjson.JSONObject requestJson = new com.alibaba.fastjson.JSONObject();
|
||||
requestJson.put("username", USERNAME);
|
||||
requestJson.put("password", PASSWORD);
|
||||
requestJson.put("flag", FLAG);
|
||||
|
||||
/**
|
||||
* 构建手机号发送专用接收人列表。
|
||||
*
|
||||
* @param mobile controller 传入的手机号
|
||||
* @return 仅包含一个接收人的列表
|
||||
*/
|
||||
private List<MsgPlatformRecipient> buildMobileRecipients(String mobile) {
|
||||
if (Strings.isBlank(mobile)) {
|
||||
throw new BaseException("接收人手机号不能为空");
|
||||
}
|
||||
if (!mobile.matches("^\\d{11}$")) {
|
||||
throw new BaseException("接收人手机号必须为11位数字");
|
||||
}
|
||||
MsgPlatformRecipient recipient = new MsgPlatformRecipient();
|
||||
recipient.setMobile(mobile);
|
||||
List<MsgPlatformRecipient> recipients = new ArrayList<>(1);
|
||||
recipients.add(recipient);
|
||||
return recipients;
|
||||
}
|
||||
String response = HttpUtil.post(TOKEN_URL, requestJson.toJSONString());
|
||||
log.info("Token 获取响应:" + response);
|
||||
|
||||
/**
|
||||
* 构建微信便捷发送专用接收人列表。
|
||||
*
|
||||
* @param accountOrMobile controller 传入的企业微信成员ID、工号或手机号
|
||||
* @return 仅包含一个接收人的列表
|
||||
*/
|
||||
private List<MsgPlatformRecipient> buildWechatRecipients(String accountOrMobile) {
|
||||
if (Strings.isBlank(accountOrMobile)) {
|
||||
throw new BaseException("微信接收人工号或手机号不能为空");
|
||||
}
|
||||
MsgPlatformRecipient recipient = new MsgPlatformRecipient();
|
||||
recipient.setAccount(accountOrMobile);
|
||||
List<MsgPlatformRecipient> recipients = new ArrayList<>(1);
|
||||
recipients.add(recipient);
|
||||
return recipients;
|
||||
}
|
||||
JSONObject responseJson = JSON.parseObject(response);
|
||||
if (responseJson != null && responseJson.getIntValue("code") == 200) {
|
||||
token = responseJson.getString("data");
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
redisService.setex("msg_token", 60 * 25, token);
|
||||
log.info("Token 获取成功!!!!!!!!!!!!!!!!!!!!!!!!a!!!!!");
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为便捷发送方法补默认发送人信息。
|
||||
* 这些字段从配置中读取,避免 controller 每次重复传固定参数。
|
||||
*
|
||||
* @param request 平台请求参数
|
||||
*/
|
||||
private void fillDefaultSenderInfo(MsgPlatformBaseRequest request) {
|
||||
request.setSendUserId(getRequiredConfig("msg.platform.default-send-user-id", "请先配置 msg.platform.default-send-user-id"));
|
||||
request.setSendUserName(getRequiredConfig("msg.platform.default-send-user-name", "请先配置 msg.platform.default-send-user-name"));
|
||||
request.setSendUnitId(conf.get("msg.platform.default-send-unit-id", ""));
|
||||
request.setSendUnitName(conf.get("msg.platform.default-send-unit-name", ""));
|
||||
request.setSendUserSign(conf.get("msg.platform.default-send-user-sign", ""));
|
||||
request.setTemplateId(conf.get("msg.platform.default-template-id", ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用地大通讯平台 REST 接口。
|
||||
*
|
||||
* @param apiPath 具体接口路径
|
||||
* @param payload 发送报文
|
||||
* @return 平台响应结果
|
||||
*/
|
||||
private MsgPlatformResponse doPost(String apiPath, JSONObject payload) {
|
||||
|
||||
if (!Globals.sso){
|
||||
log.error("【log】开发模式不允许发送消息通知");
|
||||
MsgPlatformResponse response = new MsgPlatformResponse();
|
||||
response.setHttpStatus(200);
|
||||
response.setCode(0);
|
||||
response.setResult(true);
|
||||
response.setMsg("开发模式不允许发送消息通知");
|
||||
response.setRawBody(JSONUtil.toJsonStr(payload));
|
||||
return response;
|
||||
}
|
||||
if (!Globals.MyConfig.getBoolean("AppSms", false)) {
|
||||
log.error("【log】短信配置未开启");
|
||||
MsgPlatformResponse response = new MsgPlatformResponse();
|
||||
response.setHttpStatus(200);
|
||||
response.setCode(0);
|
||||
response.setResult(true);
|
||||
response.setMsg("短信配置未开启");
|
||||
response.setRawBody(JSONUtil.toJsonStr(payload));
|
||||
return response;
|
||||
}
|
||||
if (!conf.getBoolean("msg.platform.enabled", false)) {
|
||||
MsgPlatformResponse response = new MsgPlatformResponse();
|
||||
response.setHttpStatus(200);
|
||||
response.setCode(0);
|
||||
response.setResult(true);
|
||||
response.setMsg("通讯平台未启用,已跳过实际发送");
|
||||
response.setRawBody(JSONUtil.toJsonStr(payload));
|
||||
return response;
|
||||
}
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
String requestBody = JSONUtil.toJsonStr(payload);
|
||||
log.error("发送内容:=================================================="+requestBody);
|
||||
String requestUrl = buildRequestUrl(apiPath);
|
||||
log.warnf("发送地址:=================================================="+requestUrl);
|
||||
connection = (HttpURLConnection) new URL(requestUrl).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
connection.setUseCaches(false);
|
||||
connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
|
||||
connection.setConnectTimeout(conf.getInt("msg.platform.connect-timeout", 5000));
|
||||
connection.setReadTimeout(conf.getInt("msg.platform.read-timeout", 10000));
|
||||
try (OutputStream outputStream = connection.getOutputStream()) {
|
||||
outputStream.write(requestBody.getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.flush();
|
||||
}
|
||||
int httpStatus = connection.getResponseCode();
|
||||
String responseBody = readResponseBody(connection, httpStatus);
|
||||
MsgPlatformResponse response = parseResponse(httpStatus, responseBody);
|
||||
log.warnf("接口调用返回结果=============================="+responseBody);
|
||||
if (response.getCode() != null && response.getCode() != 0) {
|
||||
log.warnf("通讯平台调用失败, httpStatus=%s, body=%s", httpStatus, responseBody);
|
||||
}
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
log.error("调用通讯平台接口异常", e);
|
||||
throw new BaseException("调用通讯平台接口失败: " + e.getMessage());
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建完整请求地址,支持配置带或不带结尾斜杠的 base-url。
|
||||
*
|
||||
* @param apiPath 接口路径
|
||||
* @return 完整请求地址
|
||||
*/
|
||||
private String buildRequestUrl(String apiPath) {
|
||||
String baseUrl = getRequiredConfig("msg.platform.base-url", "请先配置 msg.platform.base-url");
|
||||
if (baseUrl.endsWith("/")) {
|
||||
return baseUrl.substring(0, baseUrl.length() - 1) + apiPath;
|
||||
}
|
||||
return baseUrl + apiPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取第三方接口响应报文。
|
||||
*
|
||||
* @param connection HttpURLConnection
|
||||
* @param httpStatus HTTP 状态码
|
||||
* @return 原始响应字符串
|
||||
* @throws IOException 读取流失败时抛出
|
||||
*/
|
||||
private String readResponseBody(HttpURLConnection connection, int httpStatus) throws IOException {
|
||||
InputStream inputStream = httpStatus >= 200 && httpStatus < 400 ? connection.getInputStream() : connection.getErrorStream();
|
||||
if (inputStream == null) {
|
||||
return "";
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析平台响应体。
|
||||
*
|
||||
* @param httpStatus HTTP 状态码
|
||||
* @param responseBody 原始响应字符串
|
||||
* @return 解析后的平台响应对象
|
||||
*/
|
||||
private MsgPlatformResponse parseResponse(int httpStatus, String responseBody) {
|
||||
MsgPlatformResponse response = new MsgPlatformResponse();
|
||||
response.setHttpStatus(httpStatus);
|
||||
response.setRawBody(responseBody);
|
||||
if (Strings.isBlank(responseBody)) {
|
||||
response.setCode(httpStatus);
|
||||
response.setResult(false);
|
||||
response.setMsg("通讯平台未返回响应内容");
|
||||
return response;
|
||||
}
|
||||
if (!JSONUtil.isTypeJSON(responseBody)) {
|
||||
response.setCode(httpStatus);
|
||||
response.setResult(false);
|
||||
response.setMsg("通讯平台返回内容不是合法JSON");
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonObject = JSONUtil.parseObj(responseBody);
|
||||
response.setCode(jsonObject.getInt("code"));
|
||||
response.setMsg(jsonObject.getStr("msg"));
|
||||
response.setResult(jsonObject.getBool("result"));
|
||||
response.setMsgId(jsonObject.getStr("msg_id"));
|
||||
response.setRemainingQuota(jsonObject.getInt("remaining_quota"));
|
||||
response.setDescription(jsonObject.getStr("description"));
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平台密钥。
|
||||
* 优先读取已加密密钥;未配置时再根据原始密钥按“Base64 后 SHA”规则自动计算。
|
||||
*
|
||||
* @return 平台要求的 secret_key
|
||||
*/
|
||||
private String getSecretKey() {
|
||||
String encryptedSecretKey = conf.get("msg.platform.encrypted-secret-key", "");
|
||||
if (Strings.isNotBlank(encryptedSecretKey)) {
|
||||
return encryptedSecretKey;
|
||||
}
|
||||
String rawSecret = getRequiredConfig("msg.platform.raw-secret-key", "请先配置 msg.platform.raw-secret-key 或 msg.platform.encrypted-secret-key");
|
||||
return shaHex(rawSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取必填配置项。
|
||||
*
|
||||
* @param key 配置 key
|
||||
* @param errorMessage 配置缺失时抛出的异常信息
|
||||
* @return 配置值
|
||||
*/
|
||||
private String getRequiredConfig(String key, String errorMessage) {
|
||||
String value = conf.get(key, "");
|
||||
if (Strings.isBlank(value)) {
|
||||
throw new BaseException(errorMessage);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 SHA 十六进制摘要。
|
||||
*
|
||||
* @param content 待加密内容
|
||||
* @return SHA 十六进制字符串
|
||||
*/
|
||||
private String shaHex(String content) {
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
|
||||
messageDigest.update(content.getBytes());
|
||||
byte[] hash = messageDigest.digest();
|
||||
return Base64.getEncoder().encodeToString(hash);
|
||||
} catch (Exception e) {
|
||||
throw new BaseException("生成通讯平台 secret_key 失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
log.info("Token 获取失败!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + response);
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Token 获取异常!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,12 +65,13 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Column
|
||||
@Comment("出生日期")
|
||||
@ColDefine(type = ColType.DATE)
|
||||
@DataCenterColumn(name = "出生日期", key = "CSRQ")
|
||||
private Date birthday;
|
||||
|
||||
@Column
|
||||
@Comment("政治面貌")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@DataCenterColumn(name = "政治面貌", key = "ZZMMM", dict = "USER_POLITICAL")
|
||||
@DataCenterColumn(name = "政治面貌", key = "ZZMM", dict = "USER_POLITICAL")
|
||||
private String political;
|
||||
|
||||
@Column
|
||||
@@ -81,7 +82,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Column
|
||||
@Comment("民族")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
@DataCenterColumn(name = "民族", key = "MZM", dict = "USER_NATION")
|
||||
@DataCenterColumn(name = "民族", key = "MZ", dict = "USER_NATION")
|
||||
private String nation;
|
||||
|
||||
@Column
|
||||
@@ -101,7 +102,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Comment("证件号码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@DataCenterColumn(name = "证件号码", key = "SFZJH")
|
||||
private String idCard;
|
||||
|
||||
@@ -175,7 +176,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Column
|
||||
@Comment("来校时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||
@DataCenterColumn(name = "来校时间", key = "LXNY")
|
||||
@DataCenterColumn(name = "来校时间", key = "RXRQ")
|
||||
private String arrivalAtSchoolDate;
|
||||
|
||||
@Column
|
||||
@@ -208,7 +209,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Column
|
||||
@Comment("教职工类别码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@DataCenterColumn(name = "教职工类别码", key = "RYLX", dict = "USER_PERSON_TYPE")
|
||||
@DataCenterColumn(name = "教职工类别码", key = "JZGRYLB", dict = "USER_PERSON_TYPE")
|
||||
private String personType;
|
||||
|
||||
@Column
|
||||
@@ -263,7 +264,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@DataCenterColumn(name = "单位", key = "SZDWH")
|
||||
@DataCenterColumn(name = "单位", key = "DWDM")
|
||||
private String unitId;
|
||||
|
||||
@Column
|
||||
@@ -439,4 +440,10 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Comment("基金会员退出时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date aidFundMemberQuitTime;
|
||||
|
||||
@Column
|
||||
@Comment("职务")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@DataCenterColumn(name = "职务", key = "ZYJSZW")
|
||||
private String position;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.budwk.app.sys.services.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
@@ -14,20 +15,18 @@ import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_unit;
|
||||
import com.budwk.app.sys.services.SysDataUnitPullService;
|
||||
import com.budwk.app.sys.services.SysUnitService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -41,11 +40,13 @@ import java.util.stream.Collectors;
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implements SysDataUnitPullService {
|
||||
|
||||
private static final String DMP_UNIT_KEY = "unit";
|
||||
private static final String UNIT_KEY = "unit";
|
||||
private static final int DMP_PAGE_SIZE = 1000;
|
||||
|
||||
@Inject
|
||||
private DataCenterProperties dataCenterProperties;
|
||||
@Inject
|
||||
private SysUnitService sysUnitService;
|
||||
|
||||
public SysDataUnitPullServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
@@ -55,7 +56,9 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void updateUnits() {
|
||||
updateUnits(List.of());
|
||||
List<Sys_unit> sys_units = sysUnitService.query();
|
||||
List<String> list = sys_units.stream().map(Sys_unit::getId).collect(Collectors.toList());
|
||||
updateUnits(list);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,15 +68,40 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void updateUnits(List<String> unitIds) {
|
||||
String accessToken = getDmpAccessToken();
|
||||
List<JSONObject> rawDataList = distinctDmpUnits(pullDmpUnits(getDmpUnitUrl(), accessToken));
|
||||
Set<String> parentCodes = rawDataList.stream()
|
||||
.map(this::getNormalizedParentCode)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
List<JSONObject> rawDataList = pullUnits(getDmpUnitUrl(), accessToken);
|
||||
|
||||
rawDataList.stream()
|
||||
.sorted(Comparator.comparingInt(this::getUnitLevel))
|
||||
.forEach(raw -> saveOrUpdateUnit(raw, parentCodes));
|
||||
List<Sys_unit> units = new ArrayList<>();
|
||||
for (JSONObject row : rawDataList) {
|
||||
Map entity = new HashMap();
|
||||
row.forEach((k, v) -> {
|
||||
if (UNIT_FIELD_RELATION.containsKey(k)) {
|
||||
for (String key : UNIT_FIELD_RELATION.get(k)) {
|
||||
entity.put(key, v);
|
||||
}
|
||||
}
|
||||
});
|
||||
units.add(BeanUtil.mapToBean(entity, Sys_unit.class, true));
|
||||
}
|
||||
|
||||
for (Sys_unit unit : units) {
|
||||
unit.setParentId("0");
|
||||
unit.setUnitLevel(2);
|
||||
unit.setUnitTypeCode(1);
|
||||
if (unitIds.contains(unit.getId())) {
|
||||
sysUnitService.updateIgnoreNull(unit);
|
||||
} else {
|
||||
Map<String, Object> beanMap = BeanUtil.beanToMap(unit);
|
||||
beanMap.remove("child");
|
||||
sysUnitService.save(unit, "0");
|
||||
}
|
||||
}
|
||||
|
||||
units.forEach(v -> {
|
||||
if (sysUnitService.count(Cnd.where("parentId", "=", v.getId())) > 0) { //查询此单位是否有父级单位
|
||||
v.setHasChildren(true); //设置子级菜单
|
||||
sysUnitService.updateIgnoreNull(v);
|
||||
}
|
||||
});
|
||||
|
||||
log.info("信息中心单位数据同步完成,本次接口返回单位数量: {},待检查单位编码数量: {}", rawDataList.size(), unitIds == null ? 0 : unitIds.size());
|
||||
}
|
||||
@@ -97,10 +125,10 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
||||
throw new BaseException("未配置信息中心token secret: data-center.secret");
|
||||
}
|
||||
|
||||
String params = URLUtil.buildQuery(Map.of("key", key, "secret", secret), StandardCharsets.UTF_8);
|
||||
String tokenResBody = HttpUtil.createGet(tokenUrl + "?" + params).execute().body();
|
||||
String params = URLUtil.buildQuery(Map.of("loginName", key, "secretKey", secret), StandardCharsets.UTF_8);
|
||||
String tokenResBody = HttpUtil.createPost(tokenUrl + "?" + params).execute().body();
|
||||
JSONObject tokenJsonBody = JSONUtil.parseObj(tokenResBody);
|
||||
String accessToken = tokenJsonBody.getStr("access_token");
|
||||
String accessToken = tokenJsonBody.getStr("data");
|
||||
if (StrUtil.isBlank(accessToken) && tokenJsonBody.getJSONObject("result") != null) {
|
||||
accessToken = tokenJsonBody.getJSONObject("result").getStr("access_token");
|
||||
}
|
||||
@@ -121,9 +149,9 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
||||
* 配置项为 data-center.urls.unit,返回值为单位全量接口URL。
|
||||
*/
|
||||
private String getDmpUnitUrl() {
|
||||
String url = dataCenterProperties.getUrls().get(DMP_UNIT_KEY);
|
||||
String url = dataCenterProperties.getUrls().get(UNIT_KEY);
|
||||
if (StrUtil.isBlank(url)) {
|
||||
throw new BaseException("未配置信息中心单位接口地址: data-center.urls." + DMP_UNIT_KEY);
|
||||
throw new BaseException("未配置信息中心单位接口地址: data-center.urls." + UNIT_KEY);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
@@ -134,39 +162,33 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
||||
* 请求 body 包含 access_token、per_page、page;
|
||||
* 返回值为 result.data 合并后的单位原始 JSON 列表。
|
||||
*/
|
||||
private List<JSONObject> pullDmpUnits(String url, String accessToken) {
|
||||
private List<JSONObject> pullUnits(String url, String accessToken) {
|
||||
List<JSONObject> rawDataList = new ArrayList<>();
|
||||
int page = 1;
|
||||
int maxPage = 1;
|
||||
int total = 0;
|
||||
|
||||
String key = dataCenterProperties.getKey();
|
||||
do {
|
||||
HttpRequest httpRequest = HttpUtil.createPost(url);
|
||||
HttpRequest httpRequest = HttpUtil.createPost(url + "?token=%s&loginName=%s&rows=100".formatted(accessToken, key));
|
||||
httpRequest.header(Header.CONTENT_TYPE, "application/json");
|
||||
httpRequest.body(JSONUtil.toJsonStr(Map.of(
|
||||
"access_token", accessToken,
|
||||
"per_page", String.valueOf(DMP_PAGE_SIZE),
|
||||
"page", String.valueOf(page)
|
||||
)));
|
||||
|
||||
log.info("请求信息中心单位数据,第{}页: {}", page, httpRequest);
|
||||
String resBody = httpRequest.execute().body();
|
||||
log.info("请求信息中心单位数据第{}页结果: {}", page, resBody);
|
||||
JSONObject jsonBody = JSONUtil.parseObj(resBody);
|
||||
|
||||
if (jsonBody.getInt("code") != 10000) {
|
||||
throw new BaseException("获取信息中心单位数据失败,错误码: " + jsonBody.getInt("code") + ";错误原因:" + jsonBody.getStr("message"));
|
||||
if (!jsonBody.getBool("success")) {
|
||||
throw new BaseException("获取信息中心单位数据失败,错误原因:" + jsonBody.getStr("msg"));
|
||||
}
|
||||
|
||||
JSONObject result = jsonBody.getJSONObject("result");
|
||||
JSONObject result = jsonBody.getJSONObject("data");
|
||||
if (result == null) {
|
||||
break;
|
||||
}
|
||||
total = result.getInt("total", total);
|
||||
maxPage = result.getInt("max_page", maxPage);
|
||||
JSONArray data = result.getJSONArray("data");
|
||||
if (CollUtil.isNotEmpty(data)) {
|
||||
rawDataList.addAll(data.stream().map(v -> (JSONObject) v).toList());
|
||||
JSONArray records = result.getJSONArray("records");
|
||||
if (CollUtil.isNotEmpty(records)) {
|
||||
rawDataList.addAll(records.stream().map(v -> (JSONObject) v).toList());
|
||||
}
|
||||
log.info("信息中心单位数据拉取进度: {}/{}", rawDataList.size(), total);
|
||||
page++;
|
||||
@@ -175,6 +197,14 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
||||
return rawDataList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单位对应接口字段
|
||||
*/
|
||||
Map<String, String[]> UNIT_FIELD_RELATION = new HashMap() {{
|
||||
put("DWMCDM", new String[]{"id", "unitcode"});
|
||||
put("DWMC", new String[]{"name"});
|
||||
}};
|
||||
|
||||
/**
|
||||
* 按单位代码去重,避免接口分页或源数据重复导致同一 DWDM 重复写入。
|
||||
*/
|
||||
|
||||
@@ -121,7 +121,7 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
|
||||
Sys_unit sysUnit = new Sys_unit();
|
||||
sysUnit.setId(entry.getKey());
|
||||
sysUnit.setName(entry.getValue());
|
||||
sysUnit.setParentId("1");
|
||||
sysUnit.setParentId("0");
|
||||
sysUnit.setUnitLevel(2);
|
||||
return sysUnit;
|
||||
}).toList();
|
||||
|
||||
@@ -51,8 +51,8 @@ import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source> implements SysDataUserPullService {
|
||||
|
||||
private static final String DMP_TEACHER_KEY = "teacher";
|
||||
private static final String DMP_DISPATCH_KEY = "dispatch";
|
||||
|
||||
private static final String TEACHER_KEY = "teacher";
|
||||
private static final int DMP_PAGE_SIZE = 1000;
|
||||
|
||||
@Inject
|
||||
@@ -120,14 +120,12 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
// 字典码表Map,key为父级编码,value为子级字典列表
|
||||
Map<String, List<Sys_data_dict>> dataDictMap = dataDictList.stream().collect(Collectors.groupingBy(Sys_data_dict::getParentCode));
|
||||
|
||||
String accessToken = getDmpAccessToken();
|
||||
List<JSONObject> rawDataList = new ArrayList<>();
|
||||
rawDataList.addAll(pullDmpUsers(getDmpUrl(DMP_TEACHER_KEY), accessToken, "在岗教职工"));
|
||||
rawDataList.addAll(pullDmpUsers(getDmpUrl(DMP_DISPATCH_KEY), accessToken, "在岗劳务派遣"));
|
||||
rawDataList = distinctDmpUsers(rawDataList);
|
||||
String accessToken = getAccessToken();
|
||||
List<JSONObject> rawDataList = pullUsers(getDmpUrl(TEACHER_KEY), accessToken);
|
||||
|
||||
if (rawDataList.isEmpty()) {
|
||||
log.warn("当前未获取到人员数据");
|
||||
throw new RuntimeException("当前未获取到人员数据");
|
||||
}
|
||||
|
||||
Date nowDate = new Date();
|
||||
@@ -141,7 +139,6 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
try {
|
||||
// 根据字段类型设置值
|
||||
if (mapping.field.getType() == String.class) {
|
||||
|
||||
if (StrUtil.isNotBlank(mapping.dict)) {
|
||||
List<Sys_data_dict> sysDataDicts = dataDictMap.getOrDefault(mapping.dict, Collections.emptyList());
|
||||
Sys_data_dict sysDataDict = sysDataDicts.stream()
|
||||
@@ -153,28 +150,33 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
if ("SFZJH".equals(mapping.key)) {
|
||||
String idCard = raw.getStr(mapping.key);
|
||||
mapping.field.set(sysUser, idCard);
|
||||
// 设置出生年月
|
||||
try {
|
||||
sysUser.setBirthday(IdcardUtil.getBirthDate(idCard));
|
||||
} catch (Exception e) {
|
||||
sysUser.setBirthday(null);
|
||||
} else if ("RXRQ".equals(mapping.key)) {
|
||||
String str = raw.getStr(mapping.key);
|
||||
if (StrUtil.isNotBlank(str) && str.length() == 6) {
|
||||
String year = str.toString().substring(0, 4);
|
||||
String month = str.toString().substring(4, 6);
|
||||
mapping.field.set(sysUser, year + "-" + month);
|
||||
}
|
||||
} else if ("LXNY".equals(mapping.key)) {
|
||||
mapping.field.set(sysUser, normalizeArrivalAtSchoolDate(raw.getStr(mapping.key)));
|
||||
} else {
|
||||
mapping.field.set(sysUser, raw.getStr(mapping.key));
|
||||
}
|
||||
}
|
||||
} else if (mapping.field.getType() == Date.class) {
|
||||
mapping.field.set(sysUser, raw.getDate(mapping.key));
|
||||
String birthdayText = raw.getStr(mapping.key);
|
||||
if ("CSRQ".equals(mapping.key)
|
||||
&& StrUtil.isNotBlank(birthdayText)
|
||||
&& birthdayText.matches("\\d{8}")) {
|
||||
mapping.field.set(sysUser, DateUtil.parse(birthdayText, "yyyyMMdd"));
|
||||
} else {
|
||||
mapping.field.set(sysUser, raw.getDate(mapping.key));
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
log.error("设置字段值失败: {}", mapping.field.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
sysUser.setUnitName(raw.getStr("SZDW"));
|
||||
sysUser.setUnitId(resolveSourceUnitId(raw.getStr("SZDWH")));
|
||||
sysUser.setUnitId(raw.getStr("DWDM"));
|
||||
|
||||
// 设置拉取时间
|
||||
sysUser.setPullTime(nowDate);
|
||||
@@ -230,7 +232,7 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
* 获取信息中心开放平台访问令牌。
|
||||
* 返回值为接口后续调用使用的 access_token 字符串。
|
||||
*/
|
||||
private String getDmpAccessToken() {
|
||||
private String getAccessToken() {
|
||||
String tokenUrl = dataCenterProperties.getTokenUrl();
|
||||
if (StrUtil.isBlank(tokenUrl)) {
|
||||
throw new BaseException("未配置信息中心token地址: data-center.token-url");
|
||||
@@ -244,23 +246,20 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
throw new BaseException("未配置信息中心token secret: data-center.secret");
|
||||
}
|
||||
// 信息中心token接口要求key和secret通过URL参数传入,配置中分开维护,调用时统一组装。
|
||||
String params = URLUtil.buildQuery(Map.of("key", key, "secret", secret), StandardCharsets.UTF_8);
|
||||
HttpRequest tokenHttpRequest = HttpUtil.createGet(tokenUrl + "?" + params);
|
||||
String params = URLUtil.buildQuery(Map.of("loginName", key, "secretKey", secret), StandardCharsets.UTF_8);
|
||||
HttpRequest tokenHttpRequest = HttpUtil.createPost(tokenUrl + "?" + params);
|
||||
log.info("请求信息中心token: {}", tokenHttpRequest);
|
||||
String tokenResBody = tokenHttpRequest.execute().body();
|
||||
log.info("请求信息中心token结果: {}", tokenResBody);
|
||||
|
||||
JSONObject tokenJsonBody = JSONUtil.parseObj(tokenResBody);
|
||||
String accessToken = tokenJsonBody.getStr("access_token");
|
||||
String accessToken = tokenJsonBody.getStr("data");
|
||||
if (StrUtil.isBlank(accessToken) && tokenJsonBody.getJSONObject("result") != null) {
|
||||
accessToken = tokenJsonBody.getJSONObject("result").getStr("access_token");
|
||||
}
|
||||
if (StrUtil.isBlank(accessToken) && tokenJsonBody.getJSONObject("data") != null) {
|
||||
accessToken = tokenJsonBody.getJSONObject("data").getStr("access_token");
|
||||
}
|
||||
if (StrUtil.isBlank(accessToken)) {
|
||||
accessToken = tokenJsonBody.getStr("token");
|
||||
}
|
||||
if (StrUtil.isBlank(accessToken)) {
|
||||
throw new BaseException("获取信息中心token失败");
|
||||
}
|
||||
@@ -284,42 +283,36 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
* 入参 url 为人员接口地址,accessToken 为信息中心令牌,sourceName 用于日志区分接口来源。
|
||||
* 返回值为该接口所有分页合并后的原始人员 JSON 列表。
|
||||
*/
|
||||
private List<JSONObject> pullDmpUsers(String url, String accessToken, String sourceName) {
|
||||
private List<JSONObject> pullUsers(String url, String accessToken) {
|
||||
List<JSONObject> rawDataList = new ArrayList<>();
|
||||
int page = 1;
|
||||
int maxPage = 1;
|
||||
int total = 0;
|
||||
|
||||
String key = dataCenterProperties.getKey();
|
||||
do {
|
||||
// 信息中心接口单页最多返回1000条,按page循环拉完当前接口全部数据。
|
||||
HttpRequest httpRequest = HttpUtil.createPost(url);
|
||||
HttpRequest httpRequest = HttpUtil.createPost(url + "?token=%s&loginName=%s&rows=10000".formatted(accessToken, key));
|
||||
httpRequest.header(Header.CONTENT_TYPE, "application/json");
|
||||
httpRequest.body(JSONUtil.toJsonStr(Map.of(
|
||||
"access_token", accessToken,
|
||||
"per_page", String.valueOf(DMP_PAGE_SIZE),
|
||||
"page", String.valueOf(page)
|
||||
)));
|
||||
|
||||
log.info("请求{}人员数据,第{}页: {}", sourceName, page, httpRequest);
|
||||
log.info("请求人员数据,第{}页: {}", page, httpRequest);
|
||||
String resBody = httpRequest.execute().body();
|
||||
log.info("请求{}人员数据第{}页结果: {}", sourceName, page, resBody);
|
||||
log.info("请求人员数据第{}页结果: {}", page, resBody);
|
||||
JSONObject jsonBody = JSONUtil.parseObj(resBody);
|
||||
|
||||
if (jsonBody.getInt("code") != 10000) {
|
||||
throw new BaseException("获取" + sourceName + "人员数据失败,错误码: " + jsonBody.getInt("code") + ";错误原因:" + jsonBody.getStr("message"));
|
||||
if (!jsonBody.getBool("success")) {
|
||||
throw new BaseException("获取人员数据失败,错误原因:" + jsonBody.getStr("msg"));
|
||||
}
|
||||
|
||||
JSONObject result = jsonBody.getJSONObject("result");
|
||||
JSONObject result = jsonBody.getJSONObject("data");
|
||||
if (result == null) {
|
||||
break;
|
||||
}
|
||||
total = result.getInt("total", total);
|
||||
maxPage = result.getInt("max_page", maxPage);
|
||||
JSONArray data = result.getJSONArray("data");
|
||||
JSONArray data = result.getJSONArray("records");
|
||||
if (CollUtil.isNotEmpty(data)) {
|
||||
rawDataList.addAll(data.stream().map(v -> (JSONObject) v).toList());
|
||||
}
|
||||
log.info("{}人员数据拉取进度: {}/{}", sourceName, rawDataList.size(), total);
|
||||
log.info("人员数据拉取进度: {}/{}", rawDataList.size(), total);
|
||||
page++;
|
||||
} while (page <= maxPage);
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ public class SysMsgServiceImpl extends BaseServiceImpl<Sys_msg> implements SysMs
|
||||
//发送学校平台消息
|
||||
ThreadUtil.execute(() -> {
|
||||
for (String loginName : loginNames) {
|
||||
smsService.sendSmsByAccount(loginName,sysMsg.getNote());
|
||||
smsService.sendWechatTextByAccountOrMobile(loginName,sysMsg.getNote());
|
||||
smsService.sendSmMsg(loginName,sysMsg.getNote());
|
||||
// smsService.sendWechatTextByAccountOrMobile(loginName,sysMsg.getNote());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ public class SmsMessageSendStrategy implements GlobalMessageSendStrategy {
|
||||
// 构建短信内容
|
||||
String smsContent = buildSmsContent(title, content, type);
|
||||
|
||||
smsService.sendSmsByAccount(loginName, smsContent);
|
||||
smsService.sendSmMsg(loginName, smsContent);
|
||||
log.info("短信发送完成:用户{},工号:{}", user.getUsername(), loginName);
|
||||
} catch (Exception e) {
|
||||
log.error("发送短信给用户{}时出错:{}", user.getUsername(), e.getMessage(), e);
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ public class WechatMessageSendStrategy implements GlobalMessageSendStrategy {
|
||||
}
|
||||
|
||||
String wechatContent = buildWechatContent(title, content, type);
|
||||
smsService.sendWechatTextByAccountOrMobile(loginName, wechatContent);
|
||||
// smsService.sendWechatTextByAccountOrMobile(loginName, wechatContent);
|
||||
log.info("微信发送完成:用户{},工号:{}", user.getUsername(), loginName);
|
||||
} catch (Exception e) {
|
||||
log.error("发送微信给用户{}时出错:{}", user.getUsername(), e.getMessage(), e);
|
||||
|
||||
Reference in New Issue
Block a user