diff --git a/src/main/java/com/whdc/model/entity/SmsBirthday.java b/src/main/java/com/whdc/model/entity/SmsBirthday.java index b4cad64..7ef57de 100644 --- a/src/main/java/com/whdc/model/entity/SmsBirthday.java +++ b/src/main/java/com/whdc/model/entity/SmsBirthday.java @@ -36,6 +36,7 @@ public class SmsBirthday implements Serializable { /** * 任务执行时间 + * 例:08:00:00 */ @TableField("EXECUTION_TM_STR") @ApiModelProperty(value = "任务执行时间") diff --git a/src/main/java/com/whdc/model/entity/Specialist.java b/src/main/java/com/whdc/model/entity/Specialist.java index 245f14d..a1ddf0b 100644 --- a/src/main/java/com/whdc/model/entity/Specialist.java +++ b/src/main/java/com/whdc/model/entity/Specialist.java @@ -21,7 +21,7 @@ import java.util.Date; @Data @EqualsAndHashCode @Accessors(chain = true) -@ApiModel(description = "专家通讯录") +@ApiModel(description = "专家") @TableName("SPECIALIST") public class Specialist implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/whdc/service/ISmsBirthdayService.java b/src/main/java/com/whdc/service/ISmsBirthdayService.java index ac5c18d..1638493 100644 --- a/src/main/java/com/whdc/service/ISmsBirthdayService.java +++ b/src/main/java/com/whdc/service/ISmsBirthdayService.java @@ -2,6 +2,9 @@ package com.whdc.service; import com.baomidou.mybatisplus.extension.service.IService; import com.whdc.model.entity.SmsBirthday; +import com.whdc.model.entity.Specialist; + +import java.util.List; /** * 生日短信服务接口 @@ -10,4 +13,13 @@ import com.whdc.model.entity.SmsBirthday; * @since 2025-09-23 */ public interface ISmsBirthdayService extends IService { + /** + * 查询今天过生日专家 + */ + List listBirthdayToday(); + + /** + * 发送生日短信 + */ + void sendBirthdaySms(List specialists); } \ No newline at end of file diff --git a/src/main/java/com/whdc/service/impl/SmsBirthdayServiceImpl.java b/src/main/java/com/whdc/service/impl/SmsBirthdayServiceImpl.java index 9b5c099..0dff075 100644 --- a/src/main/java/com/whdc/service/impl/SmsBirthdayServiceImpl.java +++ b/src/main/java/com/whdc/service/impl/SmsBirthdayServiceImpl.java @@ -1,11 +1,28 @@ package com.whdc.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.whdc.mapper.SmsBirthdayMapper; +import com.whdc.mapper.SmsLogMapper; +import com.whdc.mapper.SpecialistMapper; import com.whdc.model.entity.SmsBirthday; +import com.whdc.model.entity.SmsLog; +import com.whdc.model.entity.Specialist; import com.whdc.service.ISmsBirthdayService; +import com.whdc.utils.SmsHelper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + /** * 生日短信服务实现类 * @@ -13,5 +30,197 @@ import org.springframework.stereotype.Service; * @since 2025-09-23 */ @Service +@Slf4j public class SmsBirthdayServiceImpl extends ServiceImpl implements ISmsBirthdayService { + + @Autowired + private SpecialistMapper specialistMapper; + + @Autowired + private SmsLogMapper smsLogMapper; + + @Autowired + private SmsHelper smsHelper; + + // 记录今日是否已发送生日短信 - 使用原子变量保证线程安全 + private final AtomicBoolean birthdaySmsSentToday = new AtomicBoolean(false); + + @Override + public List listBirthdayToday() { + try { + // 获取当前日期的月和日 + LocalDate today = LocalDate.now(); + String monthDay = today.format(DateTimeFormatter.ofPattern("MM-dd")); + + // 查询今天过生日的专家(状态为有效的) + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper + .apply("DATE_FORMAT(BIRTHDAY, '%m-%d') = {0}", monthDay) + .eq(Specialist::getStatus, 1); // 1:有效 + + List specialists = specialistMapper.selectList(queryWrapper); + return specialists != null ? specialists : Collections.emptyList(); + } catch (Exception e) { + // 记录异常并返回空列表 + return Collections.emptyList(); + } + } + + @Override + public void sendBirthdaySms(List specialists) { + if (specialists == null || specialists.isEmpty()) { + log.info("没有需要发送生日短信的专家"); + return; + } + + // 获取生日短信模板 + SmsBirthday smsBirthday = this.getById(1L); // 使用ID=1的记录 + if (smsBirthday == null || smsBirthday.getStatus() != 1) { + log.warn("生日短信模板不存在或未启用"); + return; // 模板不存在或未启用 + } + + String template = smsBirthday.getTemplate(); + if (template == null || template.trim().isEmpty()) { + log.warn("生日短信模板内容为空"); + return; // 模板内容为空 + } + + // 逐个发送个性化短信 + for (Specialist specialist : specialists) { + try { + // 替换模板中的占位符 + String content = template.replace("{姓名}", specialist.getName()) + .replace("{称呼}", specialist.getTitle() != null ? specialist.getTitle() : ""); + + // 创建短信日志记录 + SmsLog smsLog = new SmsLog(); + smsLog.setName(specialist.getName()) + .setPhone(specialist.getPhone()) + .setContent(content) + .setRemark("生日短信") + .setSendTm(new java.util.Date()); + + // 使用SmsHelper发送个性化短信 + List phoneList = Collections.singletonList(specialist.getPhone()); + String sendResult = smsHelper.send(phoneList, content); + log.info("向专家{}发送生日短信结果: {}", specialist.getName(), sendResult); + + // 根据发送结果设置备注 + if ("发送成功".equals(sendResult)) { + smsLog.setRemark("生日短信-发送成功"); + } else { + smsLog.setRemark("生日短信-发送失败: " + sendResult); + } + + // 保存短信日志记录 + smsLogMapper.insert(smsLog); + + } catch (Exception e) { + log.error("向专家{}发送生日短信时发生异常: {}", specialist.getName(), e.getMessage(), e); + + // 即使发送失败,也保存短信记录 + try { + SmsLog failedSmsLog = new SmsLog(); + failedSmsLog.setName(specialist.getName()) + .setPhone(specialist.getPhone()) + .setContent(template.replace("{name}", specialist.getName()) + .replace("{title}", specialist.getTitle() != null ? specialist.getTitle() : "")) + .setRemark("生日短信-发送异常: " + e.getMessage()) + .setSendTm(new java.util.Date()); + smsLogMapper.insert(failedSmsLog); + } catch (Exception logException) { + log.error("保存发送失败的短信日志时发生异常: {}", logException.getMessage(), logException); + } + } + } + } + + /** + * 定时检查并发送生日短信 + * 每分钟执行一次 + */ + @Scheduled(cron = "0 * * * * ?") + public void checkAndSendBirthdaySms() { + try { + // 如果已经发送过,不再重复发送 + if (birthdaySmsSentToday.get()) { + log.debug("今日已经发送过生日短信,跳过执行"); + return; + } + + // 获取生日短信配置 + SmsBirthday smsBirthday = this.getById(1L); + if (smsBirthday == null || smsBirthday.getStatus() != 1) { + log.debug("生日短信功能未启用"); + return; + } + + // 检查执行时间 + String executionTime = smsBirthday.getExecutionTmStr(); + if (executionTime == null || executionTime.trim().isEmpty()) { + log.warn("生日短信执行时间未配置"); + return; + } + + // 获取当前时间 + LocalDateTime now = LocalDateTime.now(); + + try { + // 将执行时间字符串与当前日期拼接 + String todayWithExecutionTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " " + executionTime; + + // 解析为完整的LocalDateTime + LocalDateTime scheduledTime = LocalDateTime.parse( + todayWithExecutionTime, + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + ); + + // 检查当前时间是否大于等于执行时间 + if (now.isEqual(scheduledTime) || now.isAfter(scheduledTime)) { + // 原子性检查和设置发送状态 + if (birthdaySmsSentToday.compareAndSet(false, true)) { + log.info("到达生日短信发送时间: {}, 开始执行发送任务", executionTime); + + // 查询今天过生日的专家 + List birthdaySpecialists = listBirthdayToday(); + + if (birthdaySpecialists.isEmpty()) { + log.info("今天没有专家过生日,无需发送生日短信"); + } else { + log.info("今天有{}位专家过生日,开始发送生日短信", birthdaySpecialists.size()); + + // 发送生日短信 + sendBirthdaySms(birthdaySpecialists); + log.info("生日短信发送任务完成"); + } + } else { + log.debug("其他线程正在执行生日短信发送任务"); + } + } else { + log.debug("当前时间{}未到执行时间{}", now.format(DateTimeFormatter.ofPattern("HH:mm:ss")), executionTime); + } + + } catch (Exception e) { + log.error("执行时间格式解析失败: {}", executionTime, e); + } + + } catch (Exception e) { + log.error("定时检查生日短信任务执行异常: {}", e.getMessage(), e); + } + } + + /** + * 重置每日发送状态 + * 每天凌晨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); + } + } } \ No newline at end of file