feat(sms):优化生日短信发送逻辑并添加去重机制
- 修改查询条件,增加对专家生日短信已发送标记的过滤 - 实现发送前手机号去重逻辑,避免重复发送 - 添加发送成功后更新专家短信发送标记的逻辑 - 实现定时任务每天重置专家短信发送标记- 添加定时任务,每天凌晨重置短信发送状态 - 增加发送短信抄送功能,抄送指定人员 - 优化线程安全控制,防止重复执行短信发送任务 - 更新 Specialist 实体类,增加短信发送标记字段 - 修改 SpecialistMapper,添加重置短信发送标记的方法- 更新数据库表结构,添加短信发送标记字段master
parent
adecc084dd
commit
c32e27b174
|
|
@ -9,7 +9,9 @@ CREATE TABLE SPECIALIST (
|
|||
ADDRESS VARCHAR(20) COMMENT '区域',
|
||||
PHONE VARCHAR(20) UNIQUE COMMENT '电话号码',
|
||||
STATUS INT DEFAULT 1 COMMENT '生效状态 1:有效 0:无效',
|
||||
CREATE_TM DATETIME DEFAULT CURRENT_TIME COMMENT '创建日期'
|
||||
CREATE_TM DATETIME DEFAULT CURRENT_TIME COMMENT '创建日期',
|
||||
FLAG_BIRTHDAY_SENT_TODAY INT DEFAULT 0
|
||||
FLAG_HOLIDAY_SENT_TODAY INT DEFAULT 0
|
||||
);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.whdc.mapper;
|
|||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.whdc.model.entity.Specialist;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
/**
|
||||
* 专家通讯录Mapper接口
|
||||
|
|
@ -10,4 +11,6 @@ import com.whdc.model.entity.Specialist;
|
|||
* @since 2025-09-23
|
||||
*/
|
||||
public interface SpecialistMapper extends BaseMapper<Specialist> {
|
||||
@Update("update specialist set flag_birthday_sent_today = 0")
|
||||
void resetFlagBirthdaySentToday();
|
||||
}
|
||||
|
|
@ -83,4 +83,12 @@ public class Specialist implements Serializable {
|
|||
@ApiModelProperty(value = "创建日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTm;
|
||||
|
||||
//标记今天已经发送过生日短信的flag
|
||||
@TableField("FLAG_BIRTHDAY_SENT_TODAY")
|
||||
private Integer flagBirthdaySentToday;
|
||||
|
||||
//标记今天已经发送过节日短信的flag
|
||||
@TableField("FLAG_HOLIDAY_SENT_TODAY")
|
||||
private Integer flagHolidaySentToday;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ import org.springframework.stereotype.Service;
|
|||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
|
|
@ -42,7 +41,7 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
private SmsHelper smsHelper;
|
||||
|
||||
// 记录今日是否已发送生日短信 - 使用原子变量保证线程安全
|
||||
private final AtomicBoolean birthdaySmsSentToday = new AtomicBoolean(false);
|
||||
private final AtomicBoolean sending = new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
public List<Specialist> listBirthdayToday() {
|
||||
|
|
@ -54,8 +53,9 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
// 查询今天过生日的专家(状态为有效的)
|
||||
LambdaQueryWrapper<Specialist> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper
|
||||
.apply("DATE_FORMAT(BIRTHDAY, '%m-%d') = {0}", monthDay)
|
||||
.eq(Specialist::getStatus, 1); // 1:有效
|
||||
.apply("DATE_FORMAT(BIRTHDAY, '%m-%d') = {0}", monthDay)
|
||||
.eq(Specialist::getFlagBirthdaySentToday, 0)
|
||||
.eq(Specialist::getStatus, 1); // 1:有效
|
||||
|
||||
List<Specialist> specialists = specialistMapper.selectList(queryWrapper);
|
||||
return specialists != null ? specialists : Collections.emptyList();
|
||||
|
|
@ -89,8 +89,14 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
int totalSpecialists = specialists.size();
|
||||
log.info("开始向{}位专家发送生日短信", totalSpecialists);
|
||||
|
||||
//去重
|
||||
Set<String> distinct = new HashSet<>();
|
||||
for (int i = 0; i < specialists.size(); i++) {
|
||||
Specialist specialist = specialists.get(i);
|
||||
if (distinct.contains(specialist.getPhone())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String content = template.replace("{姓名}", specialist.getName());
|
||||
try {
|
||||
log.info("正在发送第{}/{}位专家{}的生日短信", i + 1, totalSpecialists, specialist.getName());
|
||||
|
|
@ -98,14 +104,18 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
// 创建短信日志记录
|
||||
SmsLog smsLog = new SmsLog();
|
||||
smsLog.setName(specialist.getName())
|
||||
.setPhone(specialist.getPhone())
|
||||
.setContent(content)
|
||||
.setRemark("生日短信")
|
||||
.setSendTm(new java.util.Date());
|
||||
.setPhone(specialist.getPhone())
|
||||
.setContent(content)
|
||||
.setRemark("生日短信")
|
||||
.setSendTm(new java.util.Date());
|
||||
|
||||
// 使用SmsHelper发送个性化短信
|
||||
List<String> phoneList = Collections.singletonList(specialist.getPhone());
|
||||
String sendResult = smsHelper.send(phoneList, content);
|
||||
// 更新专家的flagBirthdaySentToday
|
||||
specialist.setFlagBirthdaySentToday(1);
|
||||
specialistMapper.updateById(specialist);
|
||||
distinct.add(specialist.getPhone());
|
||||
log.info("向专家{}发送生日短信结果: {}", specialist.getName(), sendResult);
|
||||
|
||||
// 根据发送结果设置备注
|
||||
|
|
@ -114,7 +124,8 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
} else {
|
||||
smsLog.setRemark("生日短信-发送失败: " + sendResult);
|
||||
}
|
||||
|
||||
//应唐科要求,每次发送短讯要抄送给唐威,陈锋
|
||||
carbonCopy(content);
|
||||
// 保存短信日志记录
|
||||
smsLogMapper.insert(smsLog);
|
||||
|
||||
|
|
@ -137,10 +148,10 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
try {
|
||||
SmsLog failedSmsLog = new SmsLog();
|
||||
failedSmsLog.setName(specialist.getName())
|
||||
.setPhone(specialist.getPhone())
|
||||
.setContent(content)
|
||||
.setRemark("生日短信-发送异常: " + e.getMessage())
|
||||
.setSendTm(new java.util.Date());
|
||||
.setPhone(specialist.getPhone())
|
||||
.setContent(content)
|
||||
.setRemark("生日短信-发送异常: " + e.getMessage())
|
||||
.setSendTm(new java.util.Date());
|
||||
smsLogMapper.insert(failedSmsLog);
|
||||
} catch (Exception logException) {
|
||||
log.error("保存发送失败的短信日志时发生异常: {}", logException.getMessage(), logException);
|
||||
|
|
@ -151,6 +162,24 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
log.info("生日短信批量发送任务完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 抄送
|
||||
*/
|
||||
private void carbonCopy(String content) {
|
||||
List<String> phoneList = new ArrayList<>();
|
||||
phoneList.add("18154318312"); //唐威
|
||||
phoneList.add("13247155309"); //陈锋
|
||||
phoneList.add("15671545233"); //李
|
||||
smsHelper.send(phoneList, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每天0点重置所有专家的flagBirthdaySentToday为0
|
||||
*/
|
||||
@Scheduled(cron = "0 0 0 * * ?")
|
||||
public void resetFlagBirthdaySentToday() {
|
||||
specialistMapper.resetFlagBirthdaySentToday();
|
||||
}
|
||||
/**
|
||||
* 定时检查并发送生日短信
|
||||
* 每分钟执行一次
|
||||
|
|
@ -158,12 +187,6 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
@Scheduled(cron = "0 * * * * ?")
|
||||
public void checkAndSendBirthdaySms() {
|
||||
try {
|
||||
// 如果已经发送过,不再重复发送
|
||||
if (birthdaySmsSentToday.get()) {
|
||||
log.debug("今日已经发送过生日短信,跳过执行");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取生日短信配置
|
||||
SmsBirthday smsBirthday = this.getById(1L);
|
||||
if (smsBirthday == null || smsBirthday.getStatus() != 1) {
|
||||
|
|
@ -178,6 +201,12 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
return;
|
||||
}
|
||||
|
||||
// 如果已经发送过,不再重复发送
|
||||
if (sending.get()) {
|
||||
log.debug("其他线程正在执行生日短信发送任务");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前时间
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
|
|
@ -187,14 +216,14 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
|
||||
// 解析为完整的LocalDateTime
|
||||
LocalDateTime scheduledTime = LocalDateTime.parse(
|
||||
todayWithExecutionTime,
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
todayWithExecutionTime,
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
);
|
||||
|
||||
// 检查当前时间是否大于等于执行时间
|
||||
if (now.isEqual(scheduledTime) || now.isAfter(scheduledTime)) {
|
||||
// 原子性检查和设置发送状态
|
||||
if (birthdaySmsSentToday.compareAndSet(false, true)) {
|
||||
if (sending.compareAndSet(false, true)) {
|
||||
log.info("到达生日短信发送时间: {}, 开始执行发送任务", executionTime);
|
||||
|
||||
// 查询今天过生日的专家
|
||||
|
|
@ -205,8 +234,12 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
} else {
|
||||
log.info("今天有{}位专家过生日,开始发送生日短信", birthdaySpecialists.size());
|
||||
|
||||
// 发送生日短信
|
||||
sendBirthdaySms(birthdaySpecialists);
|
||||
try {
|
||||
// 发送生日短信
|
||||
sendBirthdaySms(birthdaySpecialists);
|
||||
} finally {
|
||||
sending.set(false);
|
||||
}
|
||||
log.info("生日短信发送任务完成");
|
||||
}
|
||||
} else {
|
||||
|
|
@ -229,13 +262,14 @@ public class SmsBirthdayServiceImpl extends ServiceImpl<SmsBirthdayMapper, SmsBi
|
|||
* 重置每日发送状态
|
||||
* 每天凌晨00:00:01执行
|
||||
*/
|
||||
@Scheduled(cron = "1 0 0 * * ?")
|
||||
public void resetDailySendStatus() {
|
||||
try {
|
||||
birthdaySmsSentToday.set(false);
|
||||
log.info("生日短信每日发送状态已重置");
|
||||
} catch (Exception e) {
|
||||
log.error("重置生日短信每日发送状态异常: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
//todo delete this
|
||||
// @Scheduled(cron = "1 0 0 * * ?")
|
||||
// public void resetDailySendStatus() {
|
||||
// try {
|
||||
// sending.set(false);
|
||||
// log.info("生日短信每日发送状态已重置");
|
||||
// } catch (Exception e) {
|
||||
// log.error("重置生日短信每日发送状态异常: {}", e.getMessage(), e);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Loading…
Reference in New Issue