feat(sms):优化生日短信发送逻辑并添加去重机制

- 修改查询条件,增加对专家生日短信已发送标记的过滤
- 实现发送前手机号去重逻辑,避免重复发送
- 添加发送成功后更新专家短信发送标记的逻辑
- 实现定时任务每天重置专家短信发送标记- 添加定时任务,每天凌晨重置短信发送状态
- 增加发送短信抄送功能,抄送指定人员
- 优化线程安全控制,防止重复执行短信发送任务
- 更新 Specialist 实体类,增加短信发送标记字段
- 修改 SpecialistMapper,添加重置短信发送标记的方法- 更新数据库表结构,添加短信发送标记字段
master
李一帆 2025-09-26 10:55:25 +08:00
parent adecc084dd
commit c32e27b174
4 changed files with 82 additions and 35 deletions

View File

@ -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
);

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
}
/**
* 0flagBirthdaySentToday0
*/
@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);
// }
// }
}