| | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.jetbrains.annotations.NotNull; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springblade.common.config.SmsConfig; |
| | | import org.springblade.common.utils.HttpClientUtils; |
| | | import org.springblade.common.utils.SpringUtils; |
| | | import org.springblade.common.utils.UtilRandom; |
| | |
| | | import org.springblade.modules.sms.mapper.SmsTemplateMapper; |
| | | import org.springblade.modules.sms.service.ISmsSendService; |
| | | import org.springblade.modules.sms.service.ISmsTemplateService; |
| | | import org.springblade.modules.smsRecord.entity.SmsRecordEntity; |
| | | import org.springblade.modules.smsRecord.service.ISmsRecordService; |
| | | import org.springblade.modules.sms.entity.SmsRecordEntity; |
| | | import org.springblade.modules.sms.service.ISmsRecordService; |
| | | import org.springblade.modules.smsTask.entity.SmsTaskEntity; |
| | | import org.springblade.modules.smsTask.service.ISmsTaskService; |
| | | import org.springblade.modules.system.service.IUserService; |
| | | import org.springblade.modules.system.vo.UserVO; |
| | | import org.springblade.modules.task.entity.TaskPlaceSelfCheckEntity; |
| | | import org.springblade.modules.task.entity.TaskResidencePermitApplyEntity; |
| | | import org.springblade.modules.task.service.ITaskPlaceSelfCheckService; |
| | | import org.springblade.modules.task.service.ITaskResidencePermitApplyService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.net.URLEncoder; |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * 短信模版表 服务实现类 |
| | |
| | | public static final String SMS_VALIDATE_PHONE_NUM = "sms:validate:phone:"; |
| | | private static final String SMS_SEND_FAILED = "短信发送失败!"; |
| | | private static final String MESSAGE_SOP_EQUALS_MES_RESPONSE_CODE = "message_sop_equalsMes_response"; |
| | | private static final String SEND_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; |
| | | private static final DateTimeFormatter SECOND_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| | | |
| | | |
| | | @Autowired |
| | |
| | | private ISmsTemplateService iSmsTemplateService; |
| | | |
| | | @Override |
| | | public Boolean smsSend(String phone) { |
| | | public Boolean sendVerificationCode(String phone) { |
| | | if (phone == null || phone.length() != 11) { |
| | | logger.error("手机号格式错误"); |
| | | return false; |
| | | } |
| | | |
| | | if (redisTemplate.exists(SMS_VALIDATE_PHONE_NUM + phone)) { |
| | | logger.error("同一个手机号一分钟内只能发送一条记录"); |
| | | return false; |
| | | } |
| | | |
| | |
| | | |
| | | //发送的手机号 |
| | | List<Map> phonesList = new ArrayList<>(); |
| | | |
| | | Map phoneMap = new HashMap(); |
| | | phoneMap.put("phone", phone); |
| | | |
| | | List<String> varList = new ArrayList<>(); |
| | | Integer code = UtilRandom.randomCount(111111, 999999); |
| | | |
| | | varList.add(code.toString()); |
| | | phoneMap.put("varList", varList); |
| | | |
| | | phonesList.add(phoneMap); |
| | | //短信主题 |
| | | String subject = "对外接口不同内容发送-动态模板"; |
| | | //短信内容 |
| | | String content = smsTemplateEntity.getContent(); |
| | | //短信模板 |
| | | String template_id = null; |
| | | //发送时间 |
| | | SimpleDateFormat df = new SimpleDateFormat(SEND_TIME_FORMAT); |
| | | String send_time = df.format(new Date()); |
| | | //优先级,高级=5,中级=3,低级=1 |
| | | String priority = "1"; |
| | | //不同内容发送类型,1=动态模板发送,2=文件内容发送 |
| | | String type = "1"; |
| | | LocalDateTime nowDateTime = LocalDateTime.now(); |
| | | String send_time = nowDateTime.format(SECOND_FORMATTER); |
| | | Map params = new HashMap(); |
| | | params.put("phones", phonesList); |
| | | params.put("subject", subject); |
| | | //短信主题 |
| | | params.put("subject", "对外接口不同内容发送-动态模板"); |
| | | params.put("content", content); |
| | | params.put("template_id", template_id); |
| | | //短信模板 |
| | | params.put("template_id", null); |
| | | // 发送时间 |
| | | params.put("send_time", send_time); |
| | | params.put("priority", priority); |
| | | params.put("type", type); |
| | | //优先级,高级=5,中级=3,低级=1 |
| | | params.put("priority", "1"); |
| | | //不同内容发送类型,1=动态模板发送,2=文件内容发送 |
| | | params.put("type", "1"); |
| | | //创建人主键 |
| | | params.put("sop_create_by", serviceOne.getSmsCode()); |
| | | String result = null; |
| | | //短信发送记录 |
| | | saveSmsRecord(phone, serviceOne, code.toString(), content); |
| | | Boolean aBoolean = sendSmsGet(serviceOne, params); |
| | | if (aBoolean) { |
| | | // 将验证码存入redis,其中phone为手机号,code为验证码 |
| | | // SMS_VALIDATE_PHONE 为前缀,通过phone和code在redis中设置一个过期的键值对 |
| | | redisTemplate.setEx(SMS_VALIDATE_PHONE + phone, code, 300L); |
| | | // 同时,为了记录该手机短时间内已接收的验证码次数,使用另一个键值对进行计数 |
| | | // SMS_VALIDATE_PHONE_NUM 为计数器的前缀,过期时间为60秒 |
| | | redisTemplate.setEx(SMS_VALIDATE_PHONE_NUM + phone, 1, 60L); |
| | | } |
| | | return aBoolean; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @param templateId |
| | | * @param residenceId |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Boolean sendNotice(Long templateId, Long residenceId) { |
| | | |
| | | Sms serviceOne = iSmsService.getOne(Wrappers.<Sms>lambdaQuery().eq(Sms::getStatus, 2)); |
| | | if (serviceOne == null) { |
| | | logger.error("未找到状态为2的Sms服务"); |
| | | return false; |
| | | } |
| | | SmsTemplateEntity smsTemplateEntity = iSmsTemplateService.getOne(Wrappers.<SmsTemplateEntity>lambdaQuery() |
| | | .eq(SmsTemplateEntity::getId, templateId)); |
| | | if (smsTemplateEntity == null) { |
| | | logger.error("未找到对应的短信模板"); |
| | | return false; |
| | | } |
| | | ITaskResidencePermitApplyService bean = SpringUtils.getBean(ITaskResidencePermitApplyService.class); |
| | | TaskResidencePermitApplyEntity residencePermitApplyEntity = bean.getById(residenceId); |
| | | String phone = residencePermitApplyEntity.getPhone(); |
| | | //发送的手机号 |
| | | List<Map> phonesList = new ArrayList<>(); |
| | | Map phoneMap = new HashMap(); |
| | | phoneMap.put("phone", phone); |
| | | List<String> varList = new ArrayList<>(); |
| | | // 设置参数 |
| | | |
| | | varList.add(residencePermitApplyEntity.getName()); |
| | | phoneMap.put("varList", varList); |
| | | phonesList.add(phoneMap); |
| | | //短信内容 |
| | | String content = smsTemplateEntity.getContent(); |
| | | //发送时间 |
| | | LocalDateTime nowDateTime = LocalDateTime.now(); |
| | | String send_time = nowDateTime.format(SECOND_FORMATTER); |
| | | Map params = new HashMap(); |
| | | params.put("phones", phonesList); |
| | | //短信主题 |
| | | params.put("subject", "对外接口不同内容发送-动态模板"); |
| | | params.put("content", content); |
| | | //短信模板 |
| | | params.put("template_id", null); |
| | | // 发送时间 |
| | | params.put("send_time", send_time); |
| | | //优先级,高级=5,中级=3,低级=1 |
| | | params.put("priority", "1"); |
| | | //不同内容发送类型,1=动态模板发送,2=文件内容发送 |
| | | params.put("type", "1"); |
| | | //创建人主键 |
| | | params.put("sop_create_by", serviceOne.getSmsCode()); |
| | | //短信发送记录 |
| | | saveSmsRecord(phone, serviceOne, residencePermitApplyEntity.getName(), content); |
| | | Boolean aBoolean = sendSmsGet(serviceOne, params); |
| | | return aBoolean; |
| | | } |
| | | |
| | | /** |
| | | * @param templateId |
| | | * @param placeSelfCheckId |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Boolean sendRectificationNotice(Long templateId, Long placeSelfCheckId) { |
| | | |
| | | Sms serviceOne = iSmsService.getOne(Wrappers.<Sms>lambdaQuery().eq(Sms::getStatus, 2)); |
| | | if (serviceOne == null) { |
| | | logger.error("未找到状态为2的Sms服务"); |
| | | return false; |
| | | } |
| | | SmsTemplateEntity smsTemplateEntity = iSmsTemplateService.getOne(Wrappers.<SmsTemplateEntity>lambdaQuery() |
| | | .eq(SmsTemplateEntity::getId, templateId)); |
| | | if (smsTemplateEntity == null) { |
| | | logger.error("未找到对应的短信模板"); |
| | | return false; |
| | | } |
| | | ITaskPlaceSelfCheckService bean = SpringUtils.getBean(ITaskPlaceSelfCheckService.class); |
| | | TaskPlaceSelfCheckEntity placeSelfCheckEntity = bean.getById(placeSelfCheckId); |
| | | IUserService userService = SpringUtils.getBean(IUserService.class); |
| | | UserVO userVO = userService.getuserById(placeSelfCheckEntity.getId()); |
| | | String phone = userVO.getPhone(); |
| | | //发送的手机号 |
| | | List<Map> phonesList = new ArrayList<>(); |
| | | Map phoneMap = new HashMap(); |
| | | phoneMap.put("phone", phone); |
| | | List<String> varList = new ArrayList<>(); |
| | | // 设置参数 |
| | | |
| | | varList.add(userVO.getName()); |
| | | varList.add(placeSelfCheckEntity.getPlaceName()); |
| | | phoneMap.put("varList", varList); |
| | | phonesList.add(phoneMap); |
| | | //短信内容 |
| | | String content = smsTemplateEntity.getContent(); |
| | | //发送时间 |
| | | LocalDateTime nowDateTime = LocalDateTime.now(); |
| | | String send_time = nowDateTime.format(SECOND_FORMATTER); |
| | | Map params = new HashMap(); |
| | | params.put("phones", phonesList); |
| | | //短信主题 |
| | | params.put("subject", "对外接口不同内容发送-动态模板"); |
| | | params.put("content", content); |
| | | //短信模板 |
| | | params.put("template_id", null); |
| | | // 发送时间 |
| | | params.put("send_time", send_time); |
| | | //优先级,高级=5,中级=3,低级=1 |
| | | params.put("priority", "1"); |
| | | //不同内容发送类型,1=动态模板发送,2=文件内容发送 |
| | | params.put("type", "1"); |
| | | //创建人主键 |
| | | params.put("sop_create_by", serviceOne.getSmsCode()); |
| | | //短信发送记录 |
| | | saveSmsRecord(phone, serviceOne, placeSelfCheckEntity.getPlaceName(), content); |
| | | Boolean aBoolean = sendSmsGet(serviceOne, params); |
| | | return aBoolean; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean loginSendVerificationCode(String phone) { |
| | | if (phone == null || phone.length() != 11) { |
| | | logger.error("手机号格式错误"); |
| | | return false; |
| | | } |
| | | |
| | | if (redisTemplate.exists(SMS_VALIDATE_PHONE_NUM + phone)) { |
| | | logger.error("同一个手机号一分钟内只能发送一条记录"); |
| | | return false; |
| | | } |
| | | |
| | | Sms serviceOne = iSmsService.getOne(Wrappers.<Sms>lambdaQuery().eq(Sms::getStatus, 2)); |
| | | if (serviceOne == null) { |
| | | logger.error("未找到状态为2的Sms服务"); |
| | | return false; |
| | | } |
| | | SmsTemplateEntity smsTemplateEntity = iSmsTemplateService.getOne(Wrappers.<SmsTemplateEntity>lambdaQuery() |
| | | .eq(SmsTemplateEntity::getId, "1783764287897939969")); |
| | | if (smsTemplateEntity == null) { |
| | | logger.error("未找到对应的短信模板"); |
| | | return false; |
| | | } |
| | | |
| | | //发送的手机号 |
| | | List<Map> phonesList = new ArrayList<>(); |
| | | Map phoneMap = new HashMap(); |
| | | phoneMap.put("phone", phone); |
| | | List<String> varList = new ArrayList<>(); |
| | | Integer code = UtilRandom.randomCount(111111, 999999); |
| | | varList.add(code.toString()); |
| | | phoneMap.put("varList", varList); |
| | | phonesList.add(phoneMap); |
| | | //短信内容 |
| | | String content = smsTemplateEntity.getContent(); |
| | | //发送时间 |
| | | LocalDateTime nowDateTime = LocalDateTime.now(); |
| | | String send_time = nowDateTime.format(SECOND_FORMATTER); |
| | | Map params = new HashMap(); |
| | | params.put("phones", phonesList); |
| | | //短信主题 |
| | | params.put("subject", "对外接口不同内容发送-动态模板"); |
| | | params.put("content", content); |
| | | //短信模板 |
| | | params.put("template_id", null); |
| | | // 发送时间 |
| | | params.put("send_time", send_time); |
| | | //优先级,高级=5,中级=3,低级=1 |
| | | params.put("priority", "1"); |
| | | //不同内容发送类型,1=动态模板发送,2=文件内容发送 |
| | | params.put("type", "1"); |
| | | //创建人主键 |
| | | params.put("sop_create_by", serviceOne.getSmsCode()); |
| | | //短信发送记录 |
| | | saveSmsRecord(phone, serviceOne, code.toString(), content); |
| | | Boolean aBoolean = sendSmsGet(serviceOne, params); |
| | | if (aBoolean) { |
| | | // 将验证码存入redis,其中phone为手机号,code为验证码 |
| | | // SMS_VALIDATE_PHONE 为前缀,通过phone和code在redis中设置一个过期的键值对 |
| | | redisTemplate.setEx(SMS_VALIDATE_PHONE + phone, code, 300L); |
| | | // 同时,为了记录该手机短时间内已接收的验证码次数,使用另一个键值对进行计数 |
| | | // SMS_VALIDATE_PHONE_NUM 为计数器的前缀,过期时间为60秒 |
| | | redisTemplate.setEx(SMS_VALIDATE_PHONE_NUM + phone, 1, 60L); |
| | | } |
| | | return aBoolean; |
| | | } |
| | | |
| | | @Override |
| | | public String checkCode(String phone, String code) { |
| | | if (StringUtils.isNotBlank(phone)) { |
| | | if (StringUtils.isBlank(code)) { |
| | | return "验证码不能为空!"; |
| | | } |
| | | Object validateCode = redisTemplate.get(SMS_VALIDATE_PHONE + phone); |
| | | if (validateCode == null) { |
| | | return "验证码不存在或已过期"; |
| | | } |
| | | if (!validateCode.toString().equals(code)) { |
| | | return "验证码错误"; |
| | | } |
| | | //删除验证码 |
| | | redisTemplate.del(SMS_VALIDATE_PHONE + phone); |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean batchSendNotice(Long smsTaskId) { |
| | | ISmsTaskService taskService = SpringUtils.getBean(ISmsTaskService.class); |
| | | SmsTaskEntity smsTaskEntity = taskService.getById(smsTaskId); |
| | | |
| | | Sms serviceOne = iSmsService.getOne(Wrappers.<Sms>lambdaQuery().eq(Sms::getStatus, 2)); |
| | | if (serviceOne == null) { |
| | | logger.error("未找到状态为2的Sms服务"); |
| | | return false; |
| | | } |
| | | SmsTemplateEntity smsTemplateEntity = iSmsTemplateService.getOne(Wrappers.<SmsTemplateEntity>lambdaQuery() |
| | | .eq(SmsTemplateEntity::getId, smsTaskEntity.getSmsTemplate())); |
| | | if (smsTemplateEntity == null) { |
| | | logger.error("未找到对应的短信模板"); |
| | | return false; |
| | | } |
| | | |
| | | //发送的手机号 |
| | | List<Map> phonesList = new ArrayList<>(); |
| | | Map phoneMap = new HashMap(); |
| | | // phoneMap.put("phone", phone); |
| | | List<String> varList = new ArrayList<>(); |
| | | // 设置参数 |
| | | phoneMap.put("varList", varList); |
| | | phonesList.add(phoneMap); |
| | | //短信内容 |
| | | String content = smsTemplateEntity.getContent(); |
| | | //发送时间 |
| | | LocalDateTime nowDateTime = LocalDateTime.now(); |
| | | String send_time = nowDateTime.format(SECOND_FORMATTER); |
| | | Map params = new HashMap(); |
| | | params.put("phones", phonesList); |
| | | //短信主题 |
| | | params.put("subject", "对外接口不同内容发送-动态模板"); |
| | | params.put("content", content); |
| | | //短信模板 |
| | | params.put("template_id", null); |
| | | // 发送时间 |
| | | params.put("send_time", send_time); |
| | | //优先级,高级=5,中级=3,低级=1 |
| | | params.put("priority", "1"); |
| | | //不同内容发送类型,1=动态模板发送,2=文件内容发送 |
| | | params.put("type", "1"); |
| | | //创建人主键 |
| | | params.put("sop_create_by", serviceOne.getSmsCode()); |
| | | //短信发送记录 |
| | | // saveSmsRecord(phone, serviceOne, placeSelfCheckEntity.getPlaceName(), content); |
| | | Boolean aBoolean = sendSmsGet(serviceOne, params); |
| | | return aBoolean; |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 发送短信并获取发送结果。 |
| | | * |
| | | * @param serviceOne 用于发送短信的服务对象 |
| | | * @param params 发送短信所需的参数映射 |
| | | * @return 如果短信发送成功,则返回true;否则返回false。 |
| | | */ |
| | | @NotNull |
| | | private Boolean sendSmsGet(Sms serviceOne, Map params) { |
| | | try { |
| | | //短信发送记录 |
| | | saveSmsRecord(phone, serviceOne, code, content); |
| | | result = testGet(params, "message.sop.differentMes", serviceOne); |
| | | // 尝试发送短信并解析响应结果 |
| | | String result = sendSms(params, "message.sop.differentMes", serviceOne); |
| | | JSONObject jsonObject = JSON.parseObject(result); |
| | | JSONObject messageSopEqualsMesResponse = (JSONObject) jsonObject.get(MESSAGE_SOP_EQUALS_MES_RESPONSE_CODE); |
| | | if (messageSopEqualsMesResponse.get("code").equals(200)) { |
| | | // 将验证码存入redis |
| | | redisTemplate.setEx(SMS_VALIDATE_PHONE + phone, code, 300L); |
| | | redisTemplate.setEx(SMS_VALIDATE_PHONE_NUM + phone, 1, 60L); |
| | | // 如果响应代码为200,表示短信发送成功 |
| | | return true; |
| | | } else { |
| | | // 记录短信发送失败的日志 |
| | | logger.error("短信发送失败!"); |
| | | } |
| | | } catch (Exception e) { |
| | | // 记录发送短信过程中出现的异常 |
| | | logger.error(SMS_SEND_FAILED, e); |
| | | throw new RuntimeException(e); |
| | | } |
| | | // 如果执行到这里,表示短信发送失败或出现异常 |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 保存短信发送记录 |
| | | * |
| | | * @param phone 接收短信的手机号码 |
| | | * @param phone 接收短信的手机号码 |
| | | * @param serviceOne 发送短信所使用的服务 |
| | | * @param code 短信中的验证码 |
| | | * @param content 短信内容,其中可能包含占位符"#P_1#"用于被验证码替换 |
| | | * @param code 短信中的验证码 |
| | | * @param content 短信内容,其中可能包含占位符"#P_1#"用于被验证码替换 |
| | | */ |
| | | private static void saveSmsRecord(String phone, Sms serviceOne, Integer code, String content) { |
| | | // 通过Spring工具类获取短信记录服务的实例 |
| | | ISmsRecordService smsRecordService = SpringUtils.getBean(ISmsRecordService.class); |
| | | // 创建一个新的短信记录实体 |
| | | SmsRecordEntity smsRecordEntity = new SmsRecordEntity(); |
| | | // 设置短信内容,将占位符"#P_1#"替换为验证码 |
| | | smsRecordEntity.setContent(content.replace("#P_1#", code.toString())); |
| | | // 设置手机号码 |
| | | smsRecordEntity.setPhone(phone); |
| | | // 设置短信模板ID |
| | | smsRecordEntity.setTemplateId(Long.valueOf(serviceOne.getTemplateId())); |
| | | // 设置创建用户ID,来自认证工具类 |
| | | smsRecordEntity.setCreateUser(AuthUtil.getUserId()); |
| | | // 保存短信记录实体 |
| | | smsRecordService.save(smsRecordEntity); |
| | | private static void saveSmsRecord(String phone, Sms serviceOne, String code, String content) { |
| | | // 通过Spring工具类获取短信记录服务的实例 |
| | | ISmsRecordService smsRecordService = SpringUtils.getBean(ISmsRecordService.class); |
| | | // 创建一个新的短信记录实体 |
| | | SmsRecordEntity smsRecordEntity = new SmsRecordEntity(); |
| | | // 设置短信内容,将占位符"#P_1#"替换为验证码 |
| | | smsRecordEntity.setContent(content.replace("#P_1#", code)); |
| | | // 设置手机号码 |
| | | smsRecordEntity.setPhone(phone); |
| | | // 设置短信模板ID |
| | | smsRecordEntity.setTemplateId(Long.valueOf(serviceOne.getTemplateId())); |
| | | // 设置创建用户ID,来自认证工具类 |
| | | smsRecordEntity.setCreateUser(AuthUtil.getUserId()); |
| | | // 保存短信记录实体 |
| | | smsRecordService.save(smsRecordEntity); |
| | | } |
| | | |
| | | public String testGet(Object bizContent, String method, Sms serviceOne) throws Exception { |
| | | public String sendSms(Object bizContent, String method, Sms serviceOne) throws Exception { |
| | | |
| | | // 公共请求参数 |
| | | Map<String, String> params = new HashMap<String, String>(); |
| | |
| | | String content = AlipaySignature.getSignContent(params); |
| | | String sign = AlipaySignature.rsa256Sign(content, serviceOne.getSecretKey(), "utf-8"); |
| | | params.put("sign", sign); |
| | | |
| | | System.out.println("----------- 请求信息 -----------"); |
| | | System.out.println("请求参数:" + buildParamQuery(params)); |
| | | System.out.println("商户秘钥:" + serviceOne.getSecretKey()); |
| | | System.out.println("待签名内容:" + content); |
| | | System.out.println("签名(sign):" + sign); |
| | | System.out.println("URL参数:" + buildUrlQuery(params)); |
| | | |
| | | System.out.println("----------- 返回结果 -----------"); |
| | | logger.info("短信请求参数:" + buildParamQuery(params)); |
| | | String responseData = HttpClientUtils.doGet(serviceOne.getRemark(), params);// 发送请求 |
| | | System.out.println("返回数据" + responseData); |
| | | logger.info("短信响应结果:" + responseData); |
| | | return responseData; |
| | | } |
| | | |