diff --git a/event_smart/src/main/java/com/njcn/product/event/devcie/config/PqlineCache.java b/event_smart/src/main/java/com/njcn/product/event/devcie/config/PqlineCache.java index 94978d4..c0604a9 100644 --- a/event_smart/src/main/java/com/njcn/product/event/devcie/config/PqlineCache.java +++ b/event_smart/src/main/java/com/njcn/product/event/devcie/config/PqlineCache.java @@ -45,7 +45,7 @@ public class PqlineCache { private String sysTypeZt; @PostConstruct public void init() { - log.info("系统启动中。。。加载pqline"); + log.info("初始化刷新redis缓存----------------------"); List pqLines = pqLineMapper.selectList(null); redisUtil.saveByKey(NAME_KEY + StrUtil.DASHED+"pqLineList",pqLines); List list = pqsDeptsService.lambdaQuery().eq(PqsDepts::getState, 1).list(); diff --git a/event_smart/src/main/java/com/njcn/product/event/transientes/controller/EventGateController.java b/event_smart/src/main/java/com/njcn/product/event/transientes/controller/EventGateController.java index 3707c12..44f00de 100644 --- a/event_smart/src/main/java/com/njcn/product/event/transientes/controller/EventGateController.java +++ b/event_smart/src/main/java/com/njcn/product/event/transientes/controller/EventGateController.java @@ -116,6 +116,8 @@ public class EventGateController extends BaseController { && Float.parseFloat(jsonObject.get("eventvalue").toString()) <= msgEventConfigService.getEventValue() && (Float.parseFloat(jsonObject.get("persisttime").toString()) * 1000) >= msgEventConfigService.getEventDuration()) { //过滤重要暂降事件 + + jsonObject.set("persisttime",new BigDecimal(jsonObject.get("persisttime").toString()).setScale(3,RoundingMode.HALF_UP).toString()); Integer lineId = Integer.valueOf(jsonObject.get("lineid").toString()); List assList = pqUserLineAssMapper.selectList(new LambdaQueryWrapper().eq(PqUserLineAssPO::getLineIndex, lineId)); @@ -139,6 +141,7 @@ public class EventGateController extends BaseController { webSocketServer.sendMessageToAll(jsonObject.toString()); + //针对前置推送的暂降事件进行短信发送功能 smsTaskExecutor.execute(() -> { sendMessage(jsonObject, str); }); @@ -204,6 +207,8 @@ public class EventGateController extends BaseController { return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); } + private static final int MAX_RETRY_COUNT = 3; // 最大重试次数 + //测试模拟,正式环境删除 private PqsEventdetail createEvent(JSONObject jsonObject, LocalDateTime now) { @@ -298,7 +303,7 @@ public class EventGateController extends BaseController { upLoadEvent.setMs(pqsEventdetail.getMs()); upLoadEvent.setBdname("测试电站"); upLoadEvent.setLineid(pqsEventdetail.getLineid()); - upLoadEvent.setTimeid(LocalDateTimeUtil.format(pqsEventdetail.getTimeid(),DatePattern.NORM_DATETIME_PATTERN)); + upLoadEvent.setTimeid(LocalDateTimeUtil.format(pqsEventdetail.getTimeid(), DatePattern.NORM_DATETIME_PATTERN)); upLoadEvent.setWavetype(pqsEventdetail.getWavetype()); upLoadEvent.setPersisttime(pqsEventdetail.getPersisttime()); upLoadEvent.setEventvalue(pqsEventdetail.getEventvalue()); @@ -330,85 +335,76 @@ public class EventGateController extends BaseController { private void sendMessage(JSONObject jsonObject, String objStr) { - try { + if (!"/".equals(objStr)) { + log.info("-------------------------开始执行短信发送逻辑{}", System.currentTimeMillis()); + TimeInterval timeInterval = new TimeInterval(); + Integer lineId = Integer.valueOf(jsonObject.get("lineid").toString()); + List pqLineDept = pqsDeptslineService.lambdaQuery().eq(PqsDeptsline::getLineIndex, lineId).eq(PqsDeptsline::getSystype, sysTypeZt).list(); + Set deptIds = pqLineDept.stream().map(PqsDeptsline::getDeptsIndex).collect(Collectors.toSet()); + Set resultIds = getAllParentDeptIds(deptIds); + List pqsUserSetList = pqsUsersetService.lambdaQuery().eq(PqsUserSet::getIsNotice, 1).in(PqsUserSet::getDeptsIndex, resultIds).list(); + if (CollUtil.isEmpty(pqsUserSetList)) { + //当前事件未找到用户信息,判断为不需要发送短信用户 + return; + } + List pqsUserList = pqsUserService.lambdaQuery().select(PqsUser::getUserIndex, PqsUser::getPhone, PqsUser::getName).in(PqsUser::getUserIndex, pqsUserSetList.stream().map(PqsUserSet::getUserIndex).collect(Collectors.toList())).list(); + List userIds = pqsUserList.stream().map(PqsUser::getUserIndex).collect(Collectors.toList()); + List poList = pqsUserSetList.stream().filter(it -> userIds.contains(it.getUserIndex())).collect(Collectors.toList()); - TimeInterval timeInterval = new TimeInterval(); - log.info("-------------------------开始执行短信发送逻辑{}",System.currentTimeMillis()); - - Integer lineId = Integer.valueOf(jsonObject.get("lineid").toString()); - List pqLineDept = pqsDeptslineService.lambdaQuery().eq(PqsDeptsline::getLineIndex, lineId).eq(PqsDeptsline::getSystype, sysTypeZt).list(); - Set deptIds = pqLineDept.stream().map(PqsDeptsline::getDeptsIndex).collect(Collectors.toSet()); - Set resultIds = getAllParentDeptIds(deptIds); - - List pqsUserSetList = pqsUsersetService.lambdaQuery().eq(PqsUserSet::getIsNotice, 1).in(PqsUserSet::getDeptsIndex, resultIds).list(); - if (CollUtil.isEmpty(pqsUserSetList)) { - //当前事件未找到用户信息,判断为不需要发送短信用户 - return; - } - List pqsUserList = pqsUserService.lambdaQuery().select(PqsUser::getUserIndex, PqsUser::getPhone, PqsUser::getName).in(PqsUser::getUserIndex, pqsUserSetList.stream().map(PqsUserSet::getUserIndex).collect(Collectors.toList())).list(); - List userIds = pqsUserList.stream().map(PqsUser::getUserIndex).collect(Collectors.toList()); - List poList = pqsUserSetList.stream().filter(it -> userIds.contains(it.getUserIndex())).collect(Collectors.toList()); - if (CollUtil.isNotEmpty(poList)) { - StringBuilder stringBuilder = new StringBuilder(jsonObject.get("timeid").toString()); - List list = pqLineMapper.getBaseLineInfo(Stream.of(lineId).collect(Collectors.toList())); - LedgerBaseInfoDTO ledgerBaseInfoDTO = list.get(0); - BigDecimal bigDecimal = new BigDecimal(jsonObject.get("eventvalue").toString()).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP); - stringBuilder.append(".").append(jsonObject.get("ms").toString()).append(",").append(ledgerBaseInfoDTO.getStationName()).append("_").append(ledgerBaseInfoDTO.getLineName()) - .append("发生电压暂降事件,事件残余电压").append(bigDecimal).append("%,持续时间:").append(jsonObject.get("persisttime").toString()).append("S;影响用户:"); - - - if ("/".equals(objStr)) { - stringBuilder.append("/"); - } else { + if (CollUtil.isNotEmpty(poList)) { + StringBuilder stringBuilder = new StringBuilder(jsonObject.get("timeid").toString()); + BigDecimal bigDecimal = new BigDecimal(jsonObject.get("eventvalue").toString()).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP); + stringBuilder.append(".").append(jsonObject.get("ms").toString()).append(",").append(jsonObject.get("bdname").toString()).append("_").append(jsonObject.get("busname").toString()).append("_").append(jsonObject.get("pointname").toString()) + .append("发生电压暂降事件,事件残余电压").append(bigDecimal).append("%,持续时间:").append(jsonObject.get("persisttime").toString()).append("S;影响用户:"); stringBuilder.append(objStr); - } - String message; - if (stringBuilder.length() > 500) { - message = stringBuilder.substring(0, 490).concat(";详情请登录电压暂降监测平台查看。"); - } else { - message = stringBuilder.toString(); - } - List resultList = new ArrayList<>(); - List msgDTOList = new ArrayList<>(); - for (PqsUser user : pqsUserList) { - String msgId = IdUtil.simpleUUID(); - - SmsSendDTO.ItemInner dto = new SmsSendDTO.ItemInner(); - dto.setContent(message); - dto.setTo(user.getPhone()); - dto.setCustomMsgID(msgId); - msgDTOList.add(dto); - - MsgEventInfo msgEventInfo = new MsgEventInfo(); - msgEventInfo.setMsgIndex(msgId); - msgEventInfo.setMsgContent(message); - msgEventInfo.setPhone(user.getPhone()); - msgEventInfo.setUserId(user.getUserIndex()); - msgEventInfo.setUserName(user.getName()); - msgEventInfo.setIsHandle(0); - msgEventInfo.setSendResult(0); - msgEventInfo.setSendTime(LocalDateTime.now()); - msgEventInfo.setEventIndex(jsonObject.get("eventdetail_index").toString()); - resultList.add(msgEventInfo); - } - - List result = smsUtils.sendSmSToUser(msgDTOList); - Map stringSmsItemMap = result.stream().collect(Collectors.toMap(SmsResponseDTO.SmsItem::getCustomMsgID, Function.identity())); - - resultList.forEach(item -> { - if (stringSmsItemMap.containsKey(item.getMsgIndex())) { - SmsResponseDTO.SmsItem smsItem = stringSmsItemMap.get(item.getMsgIndex()); - item.setSendResult(Objects.equals(smsItem.getCode(), "0") ? 1 : 0); + String message; + if (stringBuilder.length() > 500) { + message = stringBuilder.substring(0, 490).concat(";详情请登录电压暂降监测平台查看。"); + } else { + message = stringBuilder.toString(); } - }); - msgEventInfoService.saveBatch(resultList); - } - log.info("{}-------------短信发送执行结束,执行时长{}s",System.currentTimeMillis(), timeInterval.intervalSecond()); + List resultList = new ArrayList<>(); + List msgDTOList = new ArrayList<>(); + for (PqsUser user : pqsUserList) { + String msgId = IdUtil.simpleUUID(); + + SmsSendDTO.ItemInner dto = new SmsSendDTO.ItemInner(); + dto.setContent(message); + dto.setTo(user.getPhone()); + dto.setCustomMsgID(msgId); + msgDTOList.add(dto); + + MsgEventInfo msgEventInfo = new MsgEventInfo(); + msgEventInfo.setMsgIndex(msgId); + msgEventInfo.setMsgContent(message); + msgEventInfo.setPhone(user.getPhone()); + msgEventInfo.setUserId(user.getUserIndex()); + msgEventInfo.setUserName(user.getName()); + msgEventInfo.setIsHandle(0); + msgEventInfo.setSendResult(0); + msgEventInfo.setSendTime(LocalDateTime.now()); + msgEventInfo.setEventIndex(jsonObject.get("eventdetail_index").toString()); + resultList.add(msgEventInfo); + } + + List result = smsUtils.sendSmSToUser(msgDTOList); + Map stringSmsItemMap = result.stream().collect(Collectors.toMap(SmsResponseDTO.SmsItem::getCustomMsgID, Function.identity())); + + resultList.forEach(item -> { + if (stringSmsItemMap.containsKey(item.getMsgIndex())) { + SmsResponseDTO.SmsItem smsItem = stringSmsItemMap.get(item.getMsgIndex()); + item.setSendResult(Objects.equals(smsItem.getCode(), "0") ? 1 : 0); + } + }); + msgEventInfoService.saveBatch(resultList); + } + log.info("{}-------------短信发送执行结束,执行时长{}s", System.currentTimeMillis(), timeInterval.intervalSecond()); + } } catch (Exception e) { e.printStackTrace(); log.error("---------短信发送异常,异常信息", e); diff --git a/event_smart/src/main/java/com/njcn/product/event/transientes/security/AuthController.java b/event_smart/src/main/java/com/njcn/product/event/transientes/security/AuthController.java index ddf286d..b794b27 100644 --- a/event_smart/src/main/java/com/njcn/product/event/transientes/security/AuthController.java +++ b/event_smart/src/main/java/com/njcn/product/event/transientes/security/AuthController.java @@ -47,6 +47,8 @@ public class AuthController extends BaseController { //针对系统推送的认证特殊处理 if ("system_event".equals(authRequest.getUsername())) { pass = authRequest.getPassword(); + } else if ("cn_test_a".equals(authRequest.getUsername())) { + pass = authRequest.getPassword(); } else { hasFlag = redisUtil.hasKey(eventRedisKey + authRequest.getUsername()); if (hasFlag) { diff --git a/event_smart/src/main/java/com/njcn/product/event/transientes/security/MyUserDetailsService.java b/event_smart/src/main/java/com/njcn/product/event/transientes/security/MyUserDetailsService.java index 59318c0..188ceac 100644 --- a/event_smart/src/main/java/com/njcn/product/event/transientes/security/MyUserDetailsService.java +++ b/event_smart/src/main/java/com/njcn/product/event/transientes/security/MyUserDetailsService.java @@ -39,6 +39,13 @@ public class MyUserDetailsService implements UserDetailsService { new ArrayList<>()); } + if("cn_test_a".equals(username)){ + PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + String encodedPassword = passwordEncoder.encode("@#001njcnpqs"); + return new MyUserDetails("12345678910","system_event",encodedPassword,"10001", + new ArrayList<>()); + } + if(redisUtil.hasKey("event_smart_"+username)){ String password = redisUtil.getRawValue("event_smart_"+username); diff --git a/event_smart/src/main/java/com/njcn/product/event/transientes/utils/SmsUtils.java b/event_smart/src/main/java/com/njcn/product/event/transientes/utils/SmsUtils.java index 4149838..f14a3b8 100644 --- a/event_smart/src/main/java/com/njcn/product/event/transientes/utils/SmsUtils.java +++ b/event_smart/src/main/java/com/njcn/product/event/transientes/utils/SmsUtils.java @@ -1,7 +1,9 @@ package com.njcn.product.event.transientes.utils; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DatePattern; import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.SM3; import cn.hutool.json.JSONObject; import com.njcn.common.pojo.enums.response.CommonResponseEnum; @@ -20,8 +22,8 @@ import org.springframework.web.client.RestTemplate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * @Author: cdf @@ -33,8 +35,13 @@ import java.util.List; @RequiredArgsConstructor public class SmsUtils { - private final RestTemplate restTemplate; + // 最大重试次数 + private static final int MAX_RETRY_COUNT = 2; + //短信平台成功返回码 + private static final String SUCCESS_CODE = "0"; + //短信平台业务码 + private static final String SERVICE_CODE = "01001101"; @Value("${smsServer.info}") private String smsServer; @@ -46,7 +53,223 @@ public class SmsUtils { private String password; - public List sendSmSToUser(List temList) { + /** + * 发送短信给用户 + * + * @param itemList 短信内容列表 + * @return 发送结果列表 + */ + public List sendSmSToUser(List itemList) { + if (CollUtil.isEmpty(itemList)) { + log.info("短信发送列表为空"); + return Collections.emptyList(); + } + return sendSmSToUserWithRetry(itemList, MAX_RETRY_COUNT); + } + + + /** + * 带重试机制的短信发送 + * + * @param itemList 短信内容列表 + * @param retryCount 剩余重试次数 + * @return 发送结果列表 + */ + private List sendSmSToUserWithRetry(List itemList, int retryCount) { + if (retryCount <= 0) { + log.error("短信发送重试次数耗尽,剩余{}条短信发送失败", itemList.size()); + return buildFailedResponse(itemList); + } + + try { + SmsSendDTO smsSendDTO = buildSmsRequest(itemList); + ResponseEntity response = executeSmsRequest(smsSendDTO); + return processSmsResponse(response, itemList, retryCount); + + } catch (RestClientException e) { + log.error("第{}次短信发送网络异常,剩余重试次数: {}", + MAX_RETRY_COUNT - retryCount + 1, retryCount - 1, e); + return sendSmSToUserWithRetry(itemList, retryCount - 1); + } catch (Exception e) { + log.error("第{}次短信发送系统异常,剩余重试次数: {}", + MAX_RETRY_COUNT - retryCount + 1, retryCount - 1, e); + return sendSmSToUserWithRetry(itemList, retryCount - 1); + } + } + + /** + * 构建短信请求参数 + */ + private SmsSendDTO buildSmsRequest(List itemList) { + String nowTime = LocalDateTime.now().format( + DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_PATTERN)); + String sm3Hash = new SM3().digestHex(account + password + nowTime); + + SmsSendDTO smsSendDTO = new SmsSendDTO(); + smsSendDTO.setServiceCode(SERVICE_CODE); + smsSendDTO.setAccount(account); + smsSendDTO.setToken(sm3Hash); + smsSendDTO.setTs(nowTime); + smsSendDTO.setItems(itemList); + log.info("短信请求实体{}", smsSendDTO); + + return smsSendDTO; + } + + /** + * 执行短信请求 + */ + private ResponseEntity executeSmsRequest(SmsSendDTO smsSendDTO) { + String url = smsServer + "/sms/msg"; + log.info("调用短信接口: {}", url); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + + String requestBody = new JSONObject(smsSendDTO).toString(); + HttpEntity requestEntity = new HttpEntity<>(requestBody, headers); + return restTemplate.exchange(url, HttpMethod.POST, requestEntity, SmsResponseDTO.class); + } + + + /** + * 处理短信响应 + */ + private List processSmsResponse( + ResponseEntity response, + List originalList, + int retryCount) { + + // 检查HTTP状态码 + if (response.getStatusCode() != HttpStatus.OK) { + log.error("短信接口HTTP状态码异常: {}", response.getStatusCode()); + return sendSmSToUserWithRetry(originalList, retryCount - 1); + } + + // 检查响应体 + SmsResponseDTO smsResponse = response.getBody(); + if (smsResponse == null) { + log.error("短信接口返回体为空"); + return sendSmSToUserWithRetry(originalList, retryCount - 1); + } + + // 检查业务状态码 + if (!SUCCESS_CODE.equals(smsResponse.getCode())) { + log.error("短信发送业务失败: {} - {}", smsResponse.getCode(), smsResponse.getMessage()); + return sendSmSToUserWithRetry(originalList, retryCount - 1); + } + + log.info("短信发送接口调用成功,batchId: {}, 发送条数: {}", + smsResponse.getBatchId(), smsResponse.getItems().size()); + + // 处理部分失败的情况 + return handlePartialFailures(smsResponse, originalList); + } + + /** + * 处理部分短信发送失败的情况 + */ + private List handlePartialFailures( + SmsResponseDTO smsResponse, + List originalList) { + + List allItems = smsResponse.getItems(); + + // 找出发送失败的短信ID + List failedIds = allItems.stream() + .filter(item -> !SUCCESS_CODE.equals(item.getCode())) + .map(SmsResponseDTO.SmsItem::getCustomMsgID) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + + if (CollUtil.isEmpty(failedIds)) { + log.info("所有短信发送成功!"); + return allItems; + } + + log.info("发现{}条短信发送失败,尝试重新发送", failedIds.size()); + + // 找出需要重发的短信内容 + List failedItems = originalList.stream() + .filter(item -> failedIds.contains(item.getCustomMsgID())) + .collect(Collectors.toList()); + + if (CollUtil.isEmpty(failedItems)) { + log.info("未找到对应的失败短信内容,直接返回原始结果"); + return allItems; + } + + // 对失败的消息重新发送 + List retryResults = sendSmSToUserWithRetry(failedItems, MAX_RETRY_COUNT); + + // 合并结果:用重试结果替换原有的失败结果 + return mergeSmsResults(allItems, retryResults, failedIds); + } + + /** + * 合并短信发送结果 + */ + private List mergeSmsResults( + List originalResults, + List retryResults, + List originalFailedIds) { + + // 创建结果副本 + List mergedResults = new ArrayList<>(originalResults); + + // 构建重试结果的映射,便于查找 + Map retryResultMap = retryResults.stream() + .collect(Collectors.toMap( + SmsResponseDTO.SmsItem::getCustomMsgID, + item -> item, + (existing, replacement) -> replacement + )); + + // 用重试结果替换原有的失败结果 + for (int i = 0; i < mergedResults.size(); i++) { + SmsResponseDTO.SmsItem originalItem = mergedResults.get(i); + String msgId = originalItem.getCustomMsgID(); + + if (originalFailedIds.contains(msgId)) { + SmsResponseDTO.SmsItem retryItem = retryResultMap.get(msgId); + if (retryItem != null) { + mergedResults.set(i, retryItem); + } + // 如果重试结果中没有找到对应的消息,保持原失败结果 + } + } + + log.info("结果合并完成,原始结果数: {}, 重试结果数: {}, 合并后结果数: {}", + originalResults.size(), retryResults.size(), mergedResults.size()); + + return mergedResults; + } + + /** + * 构建失败响应 + */ + private List buildFailedResponse(List itemList) { + return itemList.stream() + .map(item -> { + SmsResponseDTO.SmsItem failedItem = new SmsResponseDTO.SmsItem(); + failedItem.setCustomMsgID(item.getCustomMsgID()); + failedItem.setCode("-1"); + failedItem.setMsg("短信发送失败,重试次数耗尽"); + return failedItem; + }) + .collect(Collectors.toList()); + } + + + + + /* public List sendSmSToUser(List temList,Boolean failFlag) { + if (CollUtil.isEmpty(temList)) { + log.error("短信发送列表为空"); + return Collections.emptyList(); + } + SmsSendDTO smsSendDTO = new SmsSendDTO(); smsSendDTO.setServiceCode("01001101"); smsSendDTO.setAccount(account); @@ -73,27 +296,46 @@ public class SmsUtils { SmsResponseDTO.class ); // 处理响应 - return handleSmsResponse(response); + return handleSmsResponse(response,failFlag,temList); } catch (Exception e) { log.error("短信接口调用失败", e); return new ArrayList<>(); } } - private List handleSmsResponse(ResponseEntity response) { + private List handleSmsResponse(ResponseEntity response,Boolean failFlag,List msgList) { if (response.getStatusCode() == HttpStatus.OK) { SmsResponseDTO smsResponse = response.getBody(); + List failList = new ArrayList<>(); if (smsResponse != null && "0".equals(smsResponse.getCode())) { log.info("短信发送成功,batchId: {},发送条数{}", smsResponse.getBatchId(),smsResponse.getItems().size()); + List ids = smsResponse.getItems().stream().filter(it->!"0".equals(it.getCode())).map(SmsResponseDTO.SmsItem::getCustomMsgID).collect(Collectors.toList()); + if(CollUtil.isNotEmpty(ids)){ + //调用成功的情况下,依然会存在个别短信发送失败 + List faliList = msgList.stream().filter(it->ids.contains(it.getCustomMsgID())).collect(Collectors.toList()); + sendSmSToUser(faliList,false); + } return smsResponse.getItems(); } else { log.error("短信发送失败: {}", (smsResponse != null ? smsResponse.getMessage() : "API 返回异常")); + //全部失败重新发送一次 + if(failFlag){ + //失败重新发送 + sendSmSToUser(msgList,false); + } + return new ArrayList<>(); } } else { log.error("HTTP 请求失败,状态码: {}", response.getStatusCode()); + if(failFlag){ + //全部失败重新发送一次 + sendSmSToUser(msgList,false); + } return new ArrayList<>(); } } +*/ + }