diff --git a/pqs-common/common-oss/src/main/java/com/njcn/oss/constant/OssPath.java b/pqs-common/common-oss/src/main/java/com/njcn/oss/constant/OssPath.java index 65bdd4035..5cd4ce1d0 100644 --- a/pqs-common/common-oss/src/main/java/com/njcn/oss/constant/OssPath.java +++ b/pqs-common/common-oss/src/main/java/com/njcn/oss/constant/OssPath.java @@ -12,6 +12,8 @@ public interface OssPath { */ String WAVE_DIR="comtrade/"; + String WAVE_FILE="wave/"; + /*** * 下载文件 */ diff --git a/pqs-event/event-common/src/main/java/com/njcn/event/common/mapper/WlRmpEventDetailMapper.java b/pqs-event/event-common/src/main/java/com/njcn/event/common/mapper/WlRmpEventDetailMapper.java new file mode 100644 index 000000000..1f94ac414 --- /dev/null +++ b/pqs-event/event-common/src/main/java/com/njcn/event/common/mapper/WlRmpEventDetailMapper.java @@ -0,0 +1,18 @@ +package com.njcn.event.common.mapper; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.event.pojo.po.RmpEventDetailPO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 暂态事件明细 + * + * @author yzh + * @date 2022/10/12 + */ +@Mapper +@DS("sjzx") +public interface WlRmpEventDetailMapper extends BaseMapper { + +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/constant/SmsConstant.java b/pqs-user/user-api/src/main/java/com/njcn/user/constant/SmsConstant.java new file mode 100644 index 000000000..bee82d20c --- /dev/null +++ b/pqs-user/user-api/src/main/java/com/njcn/user/constant/SmsConstant.java @@ -0,0 +1,66 @@ +package com.njcn.user.constant; + +/** + * 短信发送的一些常量,微服务添加在nacos中 + * + * @author hongawen + * @version 1.0.0 + * @date 2023年08月24日 18:25 + */ +public interface SmsConstant { + + String DEFAULT_CONNECT_TIME_OUT = "sun.net.client.defaultConnectTimeout"; + String DEFAULT_READ_TIME_OUT = "sun.net.client.defaultReadTimeout"; + //短信API产品名称(短信产品名固定,无需修改) + String PRODUCT = "Dysmsapi"; + //短信API产品域名(接口地址固定,无需修改) + String DOMAIN = "dysmsapi.aliyuncs.com"; + //accessKeyId + String ACCESS_KEY_ID = "LTAI4FxsR76x2dq3w9c5puUe"; + //accessKeySecret + String ACCESS_KEY_SECRET = "GxkTR8fsrvHtixTlD9UPmOGli35tZs"; + //短信所属地 + String LOCATION = "cn-hangzhou"; + + /** + * 通知签名 + */ + String SGIN = "灿能云"; + String CNWL = "灿能物联"; + String NJCNDL = "南京灿能电力"; + + /** + * 验证码签名 + */ + String VERIFICATION_SIGNATURE = "南京灿能电力自动化股份"; + + /** + * 短信接口地址 + */ + String SMS_API_URL = "https://sms.ymeeting.cn/smsv2"; + + /** + * 短信接口内容类型 + */ + String SMS_CONTENT_TYPE = "application/json;charset=utf-8"; + + /** + * 接口编码方式 + */ + String SMS_CHARSET = "UTF-8"; + + /** + * 短信接口账号 + */ + String SMS_ACCOUNT = "925631"; + + /** + * 短信接口密码 + */ + String SMS_PASSWORD = "AMW2pOVrdky"; + + /** + * 虚拟接入码 + */ + String SMS_ACCESS_CODE = "106905631"; +} diff --git a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/constant/UserValidMessage.java b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/constant/UserValidMessage.java index 6601c4cd5..d9323a67c 100644 --- a/pqs-user/user-api/src/main/java/com/njcn/user/pojo/constant/UserValidMessage.java +++ b/pqs-user/user-api/src/main/java/com/njcn/user/pojo/constant/UserValidMessage.java @@ -14,7 +14,7 @@ public interface UserValidMessage { String LOGIN_NAME_NOT_BLANK = "登录名不能为空,请检查loginName参数"; - String LOGIN_NAME_FORMAT_ERROR = "登录名格式错误,需3-16位的英文字母或数字,请检查loginName参数"; + String LOGIN_NAME_FORMAT_ERROR = "登录名格式错误,首字符必须是字母,需3-16位的英文字母或数字,请检查loginName参数"; String PASSWORD_NOT_BLANK = "密码不能为空,请检查password参数"; diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java index 9084fdecf..cbb1d1541 100644 --- a/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/service/impl/AppUserServiceImpl.java @@ -1,7 +1,6 @@ package com.njcn.user.service.impl; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; -import com.aliyuncs.exceptions.ClientException; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.njcn.common.pojo.constant.PatternRegex; @@ -22,11 +21,13 @@ import com.njcn.user.pojo.po.UserSet; import com.njcn.user.pojo.po.app.AppInfoSet; import com.njcn.user.pojo.po.app.AppSendMsg; import com.njcn.user.service.*; +import com.njcn.user.util.SmsApiUtil; import com.njcn.user.util.SmsUtil; import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -63,6 +64,8 @@ public class AppUserServiceImpl extends ServiceImpl impleme private final SmsUtil smsUtil; + private final SmsApiUtil smsApiUtil; + @Override @Transactional(rollbackFor = Exception.class) public String setMessage(String phone, String devCode, String type) { @@ -70,6 +73,7 @@ public class AppUserServiceImpl extends ServiceImpl impleme throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); } SendSmsResponse sendSmsResponse = null; + ResponseEntity response = null; String msgTemplate = SmsUtil.getMessageTemplate(type); String vcode = null; try { @@ -91,27 +95,75 @@ public class AppUserServiceImpl extends ServiceImpl impleme } } } + //开始执行短信发送 vcode = getMessageCode(); - //获取短信发送结果 - sendSmsResponse = smsUtil.sendSms(phone,msgTemplate,"code",vcode); + //开始执行短信发送 + String mobiles = phone; + String content = SmsUtil.getLianTongMessageTemplate(type, vcode); + response = smsApiUtil.sendBatchSms(mobiles, content); String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone; - if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) { - //成功发送短信验证码后,保存进redis,验证码失效为5分钟 - redisUtil.saveByKeyWithExpire(key, vcode,300L); - } else { - throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); - } + //成功发送短信验证码后,保存进redis + redisUtil.saveByKeyWithExpire(key, vcode, 300L); //短信入库 - addSendMessage(phone,vcode,msgTemplate,sendSmsResponse); + addZdSendMessage(phone,vcode,msgTemplate,response); } catch (Exception e) { logger.error("发送短信异常,异常为:"+e.getMessage()); //短信入库 - addSendMessage(phone,vcode,msgTemplate,sendSmsResponse); + addZdSendMessage(phone,vcode,msgTemplate,response); throw new BusinessException(e.getMessage()); } - return sendSmsResponse.getCode(); + return "OK"; } +// @Override +// @Transactional(rollbackFor = Exception.class) +// public String setMessage(String phone, String devCode, String type) { +// if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){ +// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); +// } +// SendSmsResponse sendSmsResponse = null; +// String msgTemplate = SmsUtil.getMessageTemplate(type); +// String vcode = null; +// try { +// //type为4,账号替换为新手机号 +// if (!msgTemplate.equalsIgnoreCase(MessageEnum.REGISTER.getTemplateCode())) { +// User user = this.lambdaQuery().eq(User::getPhone,phone).one(); +// if ("4".equalsIgnoreCase(type)) { +// //注册,无需判断手机号与设备的匹配 +// if (user != null) { +// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_FAIL); +// } +// } else { +// if (null == user) { +// throw new BusinessException(UserResponseEnum.LOGIN_PHONE_NOT_REGISTER); +// } else { +// user.setDevCode(devCode); +// logger.info("更新手机id:" + devCode); +// this.updateById(user); +// } +// } +// } +// vcode = getMessageCode(); +// //获取短信发送结果 +// sendSmsResponse = smsUtil.sendSms(phone,msgTemplate,"code",vcode); +// String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone; +// if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) { +// //成功发送短信验证码后,保存进redis,验证码失效为5分钟 +// redisUtil.saveByKeyWithExpire(key, vcode,300L); +// } else { +// throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); +// } +// //短信入库 +// addSendMessage(phone,vcode,msgTemplate,sendSmsResponse); +// } catch (Exception e) { +// logger.error("发送短信异常,异常为:"+e.getMessage()); +// //短信入库 +// addSendMessage(phone,vcode,msgTemplate,sendSmsResponse); +// throw new BusinessException(e.getMessage()); +// } +// return sendSmsResponse.getCode(); +// } + @Override @Transactional(rollbackFor = {Exception.class}) public void register(String phone, String code, String devCode) { @@ -123,7 +175,7 @@ public class AppUserServiceImpl extends ServiceImpl impleme } judgeCode(phone, code); String password = null; - SendSmsResponse sendSmsResponse = null; + ResponseEntity response = null; //先根据手机号查询是否已被注册 User user = this.lambdaQuery().eq(User::getPhone,phone).ne(User::getState,0).one(); if (!Objects.isNull(user)){ @@ -147,25 +199,75 @@ public class AppUserServiceImpl extends ServiceImpl impleme appInfoSet.setExFactoryBug(0); appInfoSetService.save(appInfoSet); //发送用户初始密码 - try { - password = redisUtil.getStringByKey(newUser.getId()); - sendSmsResponse = smsUtil.sendSms(phone,MessageEnum.getTemplateByCode(3),"pwd",password); - if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) { - //成功发送短信验证码后,删除用户密码信息 - redisUtil.delete(newUser.getId()); - } else { - throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); - } - addSendMessage(phone,password,MessageEnum.getTemplateByCode(3),sendSmsResponse); - } catch (ClientException e) { - logger.error("发送短信异常,异常为:"+e.getMessage()); - addSendMessage(phone,password,MessageEnum.getTemplateByCode(3),sendSmsResponse); + password = redisUtil.getStringByKey(newUser.getId()); + String content = SmsUtil.getLianTongMessageTemplate("3", password); + response = smsApiUtil.sendBatchSms(phone, content); + if (response != null && response.getStatusCodeValue() == 200) { + //成功发送短信验证码后,删除用户密码信息 + redisUtil.delete(newUser.getId()); + } else { + throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); } + addZdSendMessage(phone,password,MessageEnum.getTemplateByCode(3),response); //删除验证码 deleteCode(phone); } } +// @Override +// @Transactional(rollbackFor = {Exception.class}) +// public void register(String phone, String code, String devCode) { +// if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){ +// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG); +// } +// if (StringUtils.isBlank(devCode)) { +// throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG); +// } +// judgeCode(phone, code); +// String password = null; +// SendSmsResponse sendSmsResponse = null; +// //先根据手机号查询是否已被注册 +// User user = this.lambdaQuery().eq(User::getPhone,phone).ne(User::getState,0).one(); +// if (!Objects.isNull(user)){ +// throw new BusinessException(UserResponseEnum.REGISTER_PHONE_REPEAT); +// } else { +// //新增用户配置表 +// UserSet userSet = userSetService.addAppUserSet(); +// //新增用户表 +// User newUser = cloneUserBoToUser(phone,devCode,userSet); +// //新增用户角色关系表 +// Role role = roleService.getRoleByCode(AppRoleEnum.TOURIST.getCode()); +// userRoleService.addUserRole(newUser.getId(), Collections.singletonList(role.getId())); +// //消息默认配置 +// AppInfoSet appInfoSet = new AppInfoSet(); +// appInfoSet.setUserId(newUser.getId()); +// appInfoSet.setHarmonicInfo(1); +// appInfoSet.setEventInfo(1); +// appInfoSet.setRunInfo(1); +// appInfoSet.setAlarmInfo(1); +// appInfoSet.setFunctionBug(0); +// appInfoSet.setExFactoryBug(0); +// appInfoSetService.save(appInfoSet); +// //发送用户初始密码 +// try { +// password = redisUtil.getStringByKey(newUser.getId()); +// sendSmsResponse = smsUtil.sendSms(phone,MessageEnum.getTemplateByCode(3),"pwd",password); +// if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) { +// //成功发送短信验证码后,删除用户密码信息 +// redisUtil.delete(newUser.getId()); +// } else { +// throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL); +// } +// addSendMessage(phone,password,MessageEnum.getTemplateByCode(3),sendSmsResponse); +// } catch (ClientException e) { +// logger.error("发送短信异常,异常为:"+e.getMessage()); +// addSendMessage(phone,password,MessageEnum.getTemplateByCode(3),sendSmsResponse); +// } +// //删除验证码 +// deleteCode(phone); +// } +// } + @Override public void modifyPsd(String userId, String phone, String code, String password, String devCode) { if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){ @@ -346,4 +448,22 @@ public class AppUserServiceImpl extends ServiceImpl impleme appSendMsgService.save(appSendMsg); } + /** + * 中国电信验证码入库 + */ + public void addZdSendMessage(String phone, String vcode, String template, ResponseEntity response) { + AppSendMsg appSendMsg = new AppSendMsg(); + appSendMsg.setPhone(phone); + appSendMsg.setMessage(vcode); + appSendMsg.setSendTime(LocalDateTime.now()); + if (Objects.isNull(response)){ + appSendMsg.setSendStatus("无状态"); + appSendMsg.setRemark(null); + } else { + appSendMsg.setSendStatus(String.valueOf(response.getStatusCodeValue())); + } + appSendMsg.setTemplate(template); + appSendMsgService.save(appSendMsg); + } + } diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/util/SmsApiUtil.java b/pqs-user/user-boot/src/main/java/com/njcn/user/util/SmsApiUtil.java new file mode 100644 index 000000000..1fe180b0f --- /dev/null +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/util/SmsApiUtil.java @@ -0,0 +1,139 @@ +package com.njcn.user.util; + +import com.njcn.user.constant.SmsConstant; +import com.njcn.web.utils.RestTemplateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * 短信接口管理静态工具类 + * 统一管理各种短信接口操作 + * + * @date 2025-08-25 + */ +@Component +public class SmsApiUtil { + + @Resource + private RestTemplateUtil restTemplateUtil; + + private static final Logger log = LoggerFactory.getLogger(SmsApiUtil.class); + + + /** + * 群发短信接口 + * + * @param mobiles 手机号列表,多个手机号用逗号分隔 + * @param content 短信内容 + * @return 发送结果 + */ + public ResponseEntity sendBatchSms(String mobiles, String content) { + return sendBatchSms(SmsConstant.SMS_ACCOUNT, SmsConstant.SMS_PASSWORD, mobiles, content); + } + + /** + * 群发短信接口 + * + * @param account 账号 + * @param password 密码 + * @param mobiles 手机号列表,多个手机号用逗号分隔 + * @param content 短信内容 + * @return 发送结果 + */ + public ResponseEntity sendBatchSms(String account, String password, String mobiles, String content) { + try { + String[] mobileArray = mobiles.split(","); + log.info("开始群发短信,手机号数量: {}, 扩展号码: {}", mobileArray.length, SmsConstant.SMS_ACCESS_CODE); + + // 构建请求参数 + Map request = new HashMap<>(); + request.put("action", "send"); + request.put("account", account); + request.put("password", password); + request.put("mobile", mobiles); + request.put("content", content); + request.put("extno", SmsConstant.SMS_ACCESS_CODE); + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", SmsConstant.SMS_CONTENT_TYPE); + + // 发送请求 + ResponseEntity response = restTemplateUtil.post( + SmsConstant.SMS_API_URL, + request, + headers, + String.class + ); + + log.info("群发短信完成,响应状态: {}, 响应内容: {}", + response.getStatusCode(), response.getBody()); + + return response; + + } catch (Exception e) { + log.error("群发短信失败: {}", e.getMessage(), e); + throw new RuntimeException("群发短信失败", e); + } + } + + + /** + * 消息状态报告查询接口 + * + * @param size 查询数量,建议不超过1000 + * @return 状态报告查询结果 + */ + public ResponseEntity messageReport(Integer size) { + return messageReport(SmsConstant.SMS_ACCOUNT, SmsConstant.SMS_PASSWORD, size); + } + + /** + * 消息状态报告查询接口 + * + * @param account 账号 + * @param password 密码 + * @param size 查询数量,建议不超过1000 + * @return 状态报告查询结果 + */ + public ResponseEntity messageReport(String account, String password, Integer size) { + try { + log.info("开始查询消息状态报告,查询数量: {}", size); + + // 构建请求参数 + Map request = new HashMap<>(); + request.put("action", "report"); + request.put("account", account); + request.put("password", password); + request.put("size", size != null ? size : 1000); + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", SmsConstant.SMS_CONTENT_TYPE); + + // 发送请求 + ResponseEntity response = restTemplateUtil.post( + SmsConstant.SMS_API_URL, + request, + headers, + String.class + ); + + log.info("消息状态报告查询完成,响应状态: {}, 响应内容: {}", + response.getStatusCode(), response.getBody()); + + return response; + + } catch (Exception e) { + log.error("消息状态报告查询失败: {}", e.getMessage(), e); + throw new RuntimeException("消息状态报告查询失败", e); + } + } +} \ No newline at end of file diff --git a/pqs-user/user-boot/src/main/java/com/njcn/user/util/SmsUtil.java b/pqs-user/user-boot/src/main/java/com/njcn/user/util/SmsUtil.java index 71774e7ec..45e8721d0 100644 --- a/pqs-user/user-boot/src/main/java/com/njcn/user/util/SmsUtil.java +++ b/pqs-user/user-boot/src/main/java/com/njcn/user/util/SmsUtil.java @@ -10,6 +10,7 @@ import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; import com.njcn.common.pojo.exception.BusinessException; import com.njcn.user.config.Message; +import com.njcn.user.constant.SmsConstant; import com.njcn.user.enums.MessageEnum; import com.njcn.user.enums.UserResponseEnum; import lombok.AllArgsConstructor; @@ -92,6 +93,37 @@ public class SmsUtil { return msgTemplate; } + //验证码类型(0:登录 1:注册 2:修改密码 4:换绑新手机 5.老手机校验 6:忘记密码) + public static String getLianTongMessageTemplate(String type, String vcode) { + String msgTemplate = null; + switch (type) { + case "0": + msgTemplate = "【" + SmsConstant.NJCNDL + "】" + "验证码为:" + vcode + ",您正在登录,若非本人操作,请勿泄露!"; + break; + case "1": + msgTemplate = "【" + SmsConstant.NJCNDL + "】" + "验证码为:" + vcode + ",您正在注册成为平台会员,感谢您的支持!"; + break; + case "2": + case "6": + msgTemplate = "【" + SmsConstant.NJCNDL + "】" + "验证码为:" + vcode + ",您正在修改密码,如非本人操作,请忽略本短信!"; + break; + case "3": + msgTemplate = "【" + SmsConstant.NJCNDL + "】" + "恭喜您注册成功,您的初始密码为:"+vcode+",请及时修改为常用密码,避免遗忘,感谢您的支持!"; + break; + case "7": + case "8": + msgTemplate = "【" + SmsConstant.NJCNDL + "】" + "验证码为:" + vcode + ",您正在进行敏感操作,如非本人操作,请忽略本短信!"; + break; + case "4": + case "5": + msgTemplate = "【" + SmsConstant.NJCNDL + "】" + "验证码为:" + vcode + ",您正在尝试重新绑定手机号,请妥善保管账户信息!"; + break; + default: + throw new BusinessException(UserResponseEnum.CODE_TYPE_ERROR); + } + return msgTemplate; + } + /** * 发送消息 * @param phone 手机号