From 764d883b5ea3bdc06abbec548b6df0511e567978 Mon Sep 17 00:00:00 2001
From: linwe <872216996@qq.com>
Date: Tue, 03 Sep 2024 09:46:05 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/binlog' into binlog
---
src/main/java/org/springblade/modules/sms/service/impl/SmsSendServiceImpl.java | 522 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 522 insertions(+), 0 deletions(-)
diff --git a/src/main/java/org/springblade/modules/sms/service/impl/SmsSendServiceImpl.java b/src/main/java/org/springblade/modules/sms/service/impl/SmsSendServiceImpl.java
new file mode 100644
index 0000000..ea44fe0
--- /dev/null
+++ b/src/main/java/org/springblade/modules/sms/service/impl/SmsSendServiceImpl.java
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the dreamlu.net developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.modules.sms.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson.JSON;
+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.utils.HttpClientUtils;
+import org.springblade.common.utils.SpringUtils;
+import org.springblade.common.utils.UtilRandom;
+import org.springblade.common.utils.sms.AlipaySignature;
+import org.springblade.core.redis.cache.BladeRedis;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.modules.resource.entity.Sms;
+import org.springblade.modules.resource.service.ISmsService;
+import org.springblade.modules.sms.entity.SmsRecordEntity;
+import org.springblade.modules.sms.entity.SmsTemplateEntity;
+import org.springblade.modules.sms.mapper.SmsTemplateMapper;
+import org.springblade.modules.sms.service.ISmsRecordService;
+import org.springblade.modules.sms.service.ISmsSendService;
+import org.springblade.modules.sms.service.ISmsTemplateService;
+import org.springblade.modules.smsTask.entity.SmsTaskEntity;
+import org.springblade.modules.smsTask.service.ISmsTaskService;
+import org.springblade.modules.system.entity.User;
+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.*;
+
+/**
+ * 短信模版表 服务实现类
+ *
+ * @author BladeX
+ * @since 2024-03-06
+ */
+@Service
+public class SmsSendServiceImpl extends ServiceImpl<SmsTemplateMapper, SmsTemplateEntity> implements ISmsSendService {
+ @Autowired
+ private BladeRedis redisTemplate;
+ private static Logger logger = LoggerFactory.getLogger(SmsSendServiceImpl.class);
+ // 确保这些字符串被适当地定义和管理
+ public static final String SMS_VALIDATE_PHONE = "sms:validate:code:";
+ 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 DateTimeFormatter SECOND_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+
+ @Autowired
+ private ISmsService iSmsService;
+
+ @Autowired
+ private ISmsTemplateService iSmsTemplateService;
+
+ @Override
+ 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;
+ }
+
+ 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, serviceOne.getTemplateId()));
+ 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;
+ }
+
+
+ /**
+ * @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);
+ List<User> phoneList = taskService.selectSmsTaskListByPhone(smsTaskEntity);
+ if (CollectionUtil.isEmpty(phoneList)) {
+ 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, smsTaskEntity.getSmsTemplate()));
+ if (smsTemplateEntity == null) {
+ logger.error("未找到对应的短信模板");
+ return false;
+ }
+ ISmsRecordService smsRecordService = SpringUtils.getBean(ISmsRecordService.class);
+ Boolean aBoolean = false;
+ for (User user : phoneList) {
+ // 发送的手机号
+ List<Map> phonesList = new ArrayList<>();
+ Map phoneMap = new HashMap();
+ phoneMap.put("phone", user.getPhone());
+ 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());
+ // 短信发送记录
+ SmsRecordEntity smsRecordEntity = saveSmsRecord(user.getPhone(), serviceOne, user.getName(), content);
+ aBoolean = false; //sendSmsGet(serviceOne, params);
+ if (aBoolean){
+ smsRecordEntity.setStatus(2);
+ smsRecordService.updateById(smsRecordEntity);
+ }
+ }
+
+ return aBoolean;
+
+ }
+
+ /**
+ * 发送短信并获取发送结果。
+ *
+ * @param serviceOne 用于发送短信的服务对象
+ * @param params 发送短信所需的参数映射
+ * @return 如果短信发送成功,则返回true;否则返回false。
+ */
+ @NotNull
+ private Boolean sendSmsGet(Sms serviceOne, Map params) {
+ try {
+ // 尝试发送短信并解析响应结果
+ 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)) {
+ // 如果响应代码为200,表示短信发送成功
+ return true;
+ } else {
+ // 记录短信发送失败的日志
+ logger.error("短信发送失败!");
+ }
+ } catch (Exception e) {
+ // 记录发送短信过程中出现的异常
+ logger.error(SMS_SEND_FAILED, e);
+ throw new RuntimeException(e);
+ }
+ // 如果执行到这里,表示短信发送失败或出现异常
+ return false;
+ }
+
+ /**
+ * 保存短信发送记录
+ *
+ * @param phone 接收短信的手机号码
+ * @param serviceOne 发送短信所使用的服务
+ * @param code 短信中的验证码
+ * @param content 短信内容,其中可能包含占位符"#P_1#"用于被验证码替换
+ */
+ private static SmsRecordEntity 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);
+ return smsRecordEntity;
+ }
+
+ public String sendSms(Object bizContent, String method, Sms serviceOne) throws Exception {
+
+ // 公共请求参数
+ Map<String, String> params = new HashMap<String, String>();
+ params.put("app_id", serviceOne.getAccessKey());
+ params.put("method", method);
+ params.put("format", "json");
+ params.put("charset", "utf-8");
+ params.put("sign_type", "RSA2");
+ params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ params.put("version", "1.0");
+
+ // 业务参数
+ params.put("biz_content", JSON.toJSONString(bizContent));
+ String content = AlipaySignature.getSignContent(params);
+ String sign = AlipaySignature.rsa256Sign(content, serviceOne.getSecretKey(), "utf-8");
+ params.put("sign", sign);
+ logger.info("短信请求参数:" + buildParamQuery(params));
+ String responseData = HttpClientUtils.doGet(serviceOne.getRemark(), params);// 发送请求
+ logger.info("短信响应结果:" + responseData);
+ return responseData;
+ }
+
+ protected static String buildParamQuery(Map<String, String> params) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry<String, String> entry : params.entrySet()) {
+ sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());
+ }
+ return sb.toString().substring(1);
+ }
+
+ protected static String buildUrlQuery(Map<String, String> params) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry<String, String> entry : params.entrySet()) {
+ try {
+ sb.append("&").append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ return sb.toString().substring(1);
+ }
+}
--
Gitblit v1.9.3