diff --git a/pom.xml b/pom.xml index f7dc410..147ed86 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 jar com.budwk - zhgh_cug_v4 + zhgh_zjvtit_v4 5.6.0-plus 2.6.0-SNAPSHOT diff --git a/src/main/java/com/budwk/app/base/sms/impl/SmsServiceImpl.java b/src/main/java/com/budwk/app/base/sms/impl/SmsServiceImpl.java index 475245c..5eb114c 100644 --- a/src/main/java/com/budwk/app/base/sms/impl/SmsServiceImpl.java +++ b/src/main/java/com/budwk/app/base/sms/impl/SmsServiceImpl.java @@ -67,14 +67,14 @@ public class SmsServiceImpl implements SmsService { if (!Globals.MyConfig.getBoolean("AppSms", false)) { String message = "消息发送配置未开启,已跳过实际发送"; - log.warn(message); + logSendSkipped(sendType, resultReceivers.size(), message); saveSendRecord(sendType, title, content, pcUrl, mobileUrl, resultReceivers.size(), false, batchResults, message); return false; } if (!Globals.sso) { String message = "开发模式不允许发送学校消息中心通知"; - log.warn(message); + logSendSkipped(sendType, resultReceivers.size(), message); saveSendRecord(sendType, title, content, pcUrl, mobileUrl, resultReceivers.size(), false, batchResults, message); return false; @@ -95,6 +95,7 @@ public class SmsServiceImpl implements SmsService { saveSendRecord(sendType, title, content, pcUrl, mobileUrl, resultReceivers.size(), sendSuccess, batchResults, sendMessage); + logSendSummary(sendType, resultReceivers.size(), sendSuccess, sendMessage, batchResults); return sendSuccess; } @@ -161,9 +162,9 @@ public class SmsServiceImpl implements SmsService { if (StrUtil.isBlank(receiver.getString("userId"))) { throw new BaseException("接收人的userId不能为空"); } - if (sendType.contains("4") && StrUtil.isBlank(receiver.getString("mobile"))) { + /*if (sendType.contains("4") && StrUtil.isBlank(receiver.getString("mobile"))) { throw new BaseException("发送短信时接收人的mobile不能为空,userId=" + receiver.getString("userId")); - } + }*/ } /** @@ -202,6 +203,8 @@ public class SmsServiceImpl implements SmsService { payload.put("dingSendType", "text"); } + // 请求日志仅保留业务发送内容,接收人手机号脱敏,避免认证信息和个人信息明文写入日志。 + logBatchRequest(batchNo, receivers, payload); HttpRequest request = HttpUtil.createPost(MSG_API) .header("appId", APP_ID) .header("accessToken", ACCESS_TOKEN) @@ -213,11 +216,11 @@ public class SmsServiceImpl implements SmsService { result.put("rawBody", responseBody); if (response.getStatus() < 200 || response.getStatus() >= 300) { result.put("msg", "消息中心HTTP调用失败,状态码:" + response.getStatus()); - return result; + return logAndReturnBatchResult(result); } if (!JSONUtil.isTypeJSON(responseBody)) { result.put("msg", "消息中心返回内容不是合法JSON"); - return result; + return logAndReturnBatchResult(result); } JSONObject responseJson = JSONUtil.parseObj(responseBody); Integer status = responseJson.getInt("status"); @@ -225,15 +228,100 @@ public class SmsServiceImpl implements SmsService { result.put("status", status); result.put("msg", message); result.put("success", Integer.valueOf(200).equals(status)); - return result; + return logAndReturnBatchResult(result); } } catch (Exception e) { - log.error("学校消息中心第{}批发送异常", batchNo, e); result.put("msg", "消息中心调用异常:" + e.getMessage()); - return result; + log.error("\n====================【学校平台消息发送异常】====================\n批次号:{}\n异常信息:{}\n==============================================================", batchNo, e.getMessage(), e); + return logAndReturnBatchResult(result); } } + /** + * 在调用学校消息中心前输出当前批次的业务请求内容。 + * 接收人手机号只展示前三位和后四位,sign及accessToken等认证信息不写入日志。 + * + * @param batchNo 当前发送批次序号 + * @param receivers 当前批次接收人列表 + * @param payload 即将提交给消息中心的请求参数 + */ + private void logBatchRequest(int batchNo, List receivers, NutMap payload) { + NutMap logPayload = NutMap.NEW(); + logPayload.putAll(payload); + logPayload.remove("sign"); + List maskedReceivers = receivers.stream() + .map(receiver -> NutMap.NEW() + .addv("userId", receiver.getString("userId")) + .addv("mobile", maskMobile(receiver.getString("mobile"))) + .addv("email", receiver.getString("email")) + .addv("flag", receiver.get("flag"))) + .toList(); + logPayload.put("receivers", maskedReceivers); + log.info("\n====================【学校平台消息发送请求】====================\n批次号:{}\n请求地址:{}\n接收人数:{}\n发送内容:{}\n==============================================================", batchNo, MSG_API, receivers.size(), JSONUtil.toJsonStr(logPayload)); + } + + /** + * 输出单个批次的学校消息中心响应结果,并按成功或失败使用对应日志级别。 + * + * @param result 包含批次号、HTTP状态、平台状态、平台提示及原始响应的处理结果 + * @return 原样返回处理结果,便于发送流程继续汇总和入库 + */ + private NutMap logAndReturnBatchResult(NutMap result) { + String message = "\n====================【学校平台消息发送%s】====================\n批次号:{}\n发送结果:{}\n=============================================================="; + if (result.getBoolean("success", false)) { + log.info(message.formatted("成功"), result.getInt("batchNo"), JSONUtil.toJsonStr(result)); + } else { + log.warn(message.formatted("失败"), result.getInt("batchNo"), JSONUtil.toJsonStr(result)); + } + return result; + } + + /** + * 输出因运行配置或环境限制而跳过的发送提示,说明本次未发起第三方接口调用。 + * + * @param sendType 原计划使用的发送渠道组合 + * @param receiverCount 原计划发送的接收人数量 + * @param reason 跳过发送的具体原因 + */ + private void logSendSkipped(String sendType, int receiverCount, String reason) { + log.warn("\n====================【学校平台消息发送跳过】====================\n发送渠道:{}\n接收人数:{}\n跳过原因:{}\n说明:本次未调用学校消息中心接口。\n==============================================================", sendType, receiverCount, reason); + } + + /** + * 输出整次学校消息中心发送的最终汇总结果,便于从控制台快速确认全部批次状态。 + * + * @param sendType 发送渠道组合 + * @param receiverCount 本次待发送接收人数量 + * @param success 是否所有批次均发送成功 + * @param message 最终处理说明 + * @param batchResults 已完成批次的响应结果 + */ + private void logSendSummary(String sendType, int receiverCount, boolean success, String message, + List batchResults) { + String logMessage = "\n====================【学校平台消息发送%s】====================\n发送渠道:{}\n接收人数:{}\n最终说明:{}\n批次结果:{}\n=============================================================="; + if (success) { + log.info(logMessage.formatted("完成"), sendType, receiverCount, message, JSONUtil.toJsonStr(batchResults)); + } else { + log.warn(logMessage.formatted("失败"), sendType, receiverCount, message, JSONUtil.toJsonStr(batchResults)); + } + } + + /** + * 对手机号进行日志脱敏;空手机号保持为空,长度不足七位时完全隐藏。 + * + * @param mobile 接收人的原始手机号 + * @return 用于日志展示的脱敏手机号 + */ + private String maskMobile(String mobile) { + if (Strings.isBlank(mobile)) { + return ""; + } + if (mobile.length() <= 7) { + return "****"; + } + return mobile.substring(0, 3) + "****" + mobile.substring(mobile.length() - 4); + } + /** * 生成消息中心请求签名。 * diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java index b51d08b..d0a9bfd 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java @@ -23,7 +23,6 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig; import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin; import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; @@ -165,10 +164,6 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService for (Sys_user_source source : sources) { Sys_user user = userMap.get(source.getLoginname()); source.setMember(null); - String unitId = source.getUnitId(); - if (StringUtils.isNotBlank(unitId) && unitId.length() == 5) { - source.setUnitId(unitId.substring(0, 3)); - } // 创建用户对象 Sys_user u = new Sys_user(); @@ -450,6 +445,13 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService // 遍历带有DataCenterColumn注解的字段进行比较 for (FieldMapping mapping : getFieldMappings()) { try { + /* + * 单位由下方的专门逻辑统一记录:使用单位名称展示,并同步发布单位异动事件。 + * 此处跳过 unitId,避免通用比较与专门逻辑为同一次单位变更各生成一条历史明细。 + */ + if ("unitId".equals(mapping.field.getName())) { + continue; + } Object sourceValue = mapping.field.get(source); Object userValue = mapping.field.get(user); diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java index 18899c5..fe021d6 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java @@ -141,7 +141,8 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl } } - sysUser.setUnitId(resolveSourceUnitId(raw.getStr("bmdm"))); + // 人员单位编码必须与信息中心 bmdm 保持一致,不能按编码长度推断并替换为父级单位。 + sysUser.setUnitId(raw.getStr("bmdm")); sysUser.setUnitName(unitNameMap.get(sysUser.getUnitId())); // 设置拉取时间 @@ -263,22 +264,6 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl return new ArrayList<>(userMap.values()); } - /** - * 根据接口返回的所在单位号转换数据源用户单位。 - * 入参 rawUnitId 对应人员接口 bmdm:5位表示三级单位,需要写入其二级父单位;其他长度保持接口原值。 - * 返回值为 sys_user_source.unitId 使用的单位ID,找不到三级单位或父级为空时保留接口原始单位号,避免人员数据丢失。 - */ - private String resolveSourceUnitId(String rawUnitId) { - if (StrUtil.isBlank(rawUnitId) || rawUnitId.length() != 5) { - return rawUnitId; - } - Sys_unit unit = dao().fetch(Sys_unit.class, rawUnitId); - if (unit == null || StrUtil.isBlank(unit.getParentId())) { - return rawUnitId; - } - return unit.getParentId(); - } - @Override public NutMap searchOptions() { Sql sql = Sqls.create(""" diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysMsgServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysMsgServiceImpl.java index d4e568b..5dabe49 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysMsgServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysMsgServiceImpl.java @@ -112,14 +112,17 @@ public class SysMsgServiceImpl extends BaseServiceImpl implements SysMs .addv("flag", 0)) .toList(); if (receivers.isEmpty()) { - log.warn("学校平台消息没有符合要求的接收人,已跳过发送"); + log.warnf("\n====================【学校平台消息发送跳过】====================\n消息ID:%s\n消息标题:%s\n查询接收人数:%s\n跳过原因:未查询到可发送的接收人\n==============================================================", sysMsg.getId(), sysMsg.getTitle(), viewUsers.size()); return; } + log.infof("\n====================【学校平台消息开始发送】====================\n消息ID:%s\n消息标题:%s\n发送渠道:短信、钉钉\n接收人数:%s\n==============================================================", sysMsg.getId(), sysMsg.getTitle(), receivers.size()); boolean success = smsService.sendMsg("46", null, receivers, sysMsg.getTitle(), sysMsg.getNote(), sysMsg.getUrl(), sysMsg.getUrl()); if (!success) { - log.warnf("学校平台短信和钉钉组合消息发送失败,消息ID:%s", sysMsg.getId()); + log.warnf("\n====================【学校平台消息发送失败】====================\n消息ID:%s\n消息标题:%s\n发送渠道:短信、钉钉\n接收人数:%s\n详细批次结果请查看前序学校平台消息日志或全局消息发送记录。\n==============================================================", sysMsg.getId(), sysMsg.getTitle(), receivers.size()); + return; } + log.infof("\n====================【学校平台消息发送成功】====================\n消息ID:%s\n消息标题:%s\n发送渠道:短信、钉钉\n接收人数:%s\n==============================================================", sysMsg.getId(), sysMsg.getTitle(), receivers.size()); }); return sysMsg;