Commit 5228e67e by zhangxingmin

修复

parent 7a030aa7
......@@ -5,6 +5,7 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication(scanBasePackages = "com.yd")
@MapperScan("com.yd.**.dao")
......
package com.yd.email.api.async;
import com.alibaba.fastjson.JSON;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.email.api.service.*;
import com.yd.email.feign.dto.ApiEmailSenderConfigDto;
import com.yd.email.feign.dto.ApiSendMailDto;
import com.yd.email.feign.enums.EmailTaskStatusEnum;
import com.yd.email.feign.utils.StringUtil;
import com.yd.email.service.model.EmailTask;
import com.yd.email.service.model.EmailTaskRecipients;
import com.yd.email.service.service.IEmailTaskRecipientsService;
import com.yd.email.service.service.IEmailTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Component
public class ApiEmailSendAsyncService {
@Autowired
private IEmailTaskService iEmailTaskService;
@Autowired
private IEmailTaskRecipientsService iEmailTaskRecipientsService;
@Autowired
private ApiEmailSenderConfigService apiEmailSenderConfigService;
@Autowired
private ApiEmailService apiEmailService;
@Autowired
private ApiEmailContactService apiEmailContactService;
/**
* 立即发送邮件-异步方法
* @param emailTask
* @param recipients
* @return
*/
@Async("emailTaskExecutor")
public void sendImmediatelyEmail(EmailTask emailTask, List<EmailTaskRecipients> recipients) {
//主任务发送时间
LocalDateTime taskSendTime = LocalDateTime.now();
try {
//调用邮件服务发送邮件入参DTO
ApiSendMailDto apiSendMailDto = new ApiSendMailDto();
BeanUtils.copyProperties(emailTask,apiSendMailDto);
//根据发件人唯一业务ID获取发件人信息和发件人绑定的服务商信息
Result<ApiEmailSenderConfigDto> result = apiEmailSenderConfigService.getApiEmailSenderConfigDto(emailTask.getSenderBizId());
ApiEmailSenderConfigDto apiEmailSenderConfigDto = result.getData();
BeanUtils.copyProperties(apiEmailSenderConfigDto,apiSendMailDto);
//该任务下的所有收件人信息
log.info("查询该任务下的所有收件人信息: {}: " + JSON.toJSONString(recipients));
// 初始化成功和失败计数器
int successCount = 0;
int failCount = 0;
// 遍历所有收件人,逐个发送邮件
for (EmailTaskRecipients recipient : recipients) {
try {
log.info("遍历所有收件人,逐个发送邮件->recipient单个对象:{}",JSON.toJSONString(recipient));
// 添加发送间隔,避免频率过高
if (successCount > 0) {
Thread.sleep(1000); // 1秒间隔
}
// 处理抄送人列表:将数据库中的逗号分隔字符串转换为List
List<String> ccEmailList = StringUtils.isNotBlank(recipient.getCcEmail()) ?
Arrays.asList(recipient.getCcEmail().split(";")) :
new ArrayList<>();
log.info("处理抄送人列表:将数据库中的逗号分隔字符串转换为List: {}: " + JSON.toJSONString(ccEmailList));
//收件人邮箱(单个)
apiSendMailDto.setReceiveEmail(recipient.getReceiveEmail());
//抄送人邮箱列表
apiSendMailDto.setCcEmailList(ccEmailList);
//邮件内容
if (StringUtil.hasPlaceholdersSimple(emailTask.getContent())
&& StringUtils.isNotBlank(emailTask.getVariableGroupBizId())) {
//检测内容是否有占位符,有占位符并且变量分组唯一业务ID不为空就替换具体内容,替换具体内容:recipient.getVariables()
apiSendMailDto.setContent(StringUtil.replacePlaceholders(emailTask.getContent(),
recipient.getVariables()));
}else if (StringUtil.hasPlaceholdersSimple(emailTask.getContent())
&& StringUtils.isBlank(emailTask.getVariableGroupBizId())) {
//检测内容是否有占位符,有占位符并且变量分组唯一业务ID为空就替换具体内容。替换具体内容:通用变量字段:收件人姓名、收件人称谓、公司,这三个字段内容从收件人联系人获取
apiSendMailDto.setContent(apiEmailContactService.replacePlaceholders(emailTask.getContent(),recipient.getContactBizId()));
}
// 调用邮件服务发送邮件
apiEmailService.sendMail(apiSendMailDto);
// 发送成功:更新收件人状态为成功
recipient.setStatus(EmailTaskStatusEnum.SUCCESSFUL.getItemValue());
recipient.setSendTime(LocalDateTime.now()); // 记录实际发送时间
iEmailTaskRecipientsService.saveOrUpdate(recipient);
successCount++; // 成功计数加1
} catch (Exception e) {
// 发送失败:记录错误日志
log.error("发送邮件失败: {}", recipient.getReceiveEmail(), e);
// 更新收件人状态为失败
recipient.setStatus(EmailTaskStatusEnum.FAILED.getItemValue());
recipient.setErrorMsg(e.getMessage()); // 保存错误信息
iEmailTaskRecipientsService.saveOrUpdate(recipient);
failCount++; // 失败计数加1
}
}
// 根据发送结果更新邮件任务状态
emailTask.setStatus(failCount == 0 ?
EmailTaskStatusEnum.ALL_SUCCESSFUL.getItemValue() :
EmailTaskStatusEnum.PARTIAL_FAILURE.getItemValue());
//主任务发送时间
emailTask.setSendTime(taskSendTime);
iEmailTaskService.saveOrUpdate(emailTask);
// 记录任务完成日志
log.info("邮件发送任务完成: 成功{}个, 失败{}个", successCount, failCount);
// 设置任务执行结果
if (failCount == 0) {
log.info("发送完成: 成功" + successCount + "个");
} else {
log.info("发送完成: 成功" + successCount + "个, 失败" + failCount + "个");
}
} catch (Exception e) {
// 任务执行过程中发生异常
log.error("邮件发送任务执行异常", e);
// 更新任务状态为全部发送失败
emailTask.setStatus(EmailTaskStatusEnum.ALL_FAILED.getItemValue());
iEmailTaskService.saveOrUpdate(emailTask);
// 返回任务执行异常信息
log.error("任务执行异常: " + e.getMessage());
throw new BusinessException("立即发送邮件异常");
}
}
}
package com.yd.email.api.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig {
@Bean("emailTaskExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("EmailAsync-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
log.info("异步线程池初始化完成,线程名前缀: EmailAsync-");
return executor;
}
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yd.common.result.Result;
import com.yd.email.api.service.ApiEmailContactService;
import com.yd.email.api.service.ApiEmailSenderConfigService;
import com.yd.email.api.service.ApiEmailService;
import com.yd.email.feign.dto.ApiEmailSenderConfigDto;
......@@ -45,6 +46,9 @@ public class EmailSendJobHandler {
@Autowired
private ApiEmailSenderConfigService apiEmailSenderConfigService;
@Autowired
private ApiEmailContactService apiEmailContactService;
/**
* XXL-Job任务执行入口方法
*/
......@@ -110,9 +114,14 @@ public class EmailSendJobHandler {
apiSendMailDto.setCcEmailList(ccEmailList);
//邮件内容
if (StringUtil.hasPlaceholdersSimple(apiSendMailDto.getContent())) {
//检测内容是否有占位符,有占位符就替换具体内容,每收件人的占位符内容是不一样的。
//检测内容是否有占位符,有占位符并且变量分组唯一业务ID不为空就替换具体内容,替换具体内容:recipient.getVariables()
apiSendMailDto.setContent(StringUtil.replacePlaceholders(apiSendMailDto.getContent(),
recipient.getVariables()));
}else if (StringUtil.hasPlaceholdersSimple(emailTask.getContent())
&& StringUtils.isBlank(emailTask.getVariableGroupBizId())) {
//检测内容是否有占位符,有占位符并且变量分组唯一业务ID为空就替换具体内容。替换具体内容:通用变量字段:收件人姓名、收件人称谓、公司,这三个字段内容从收件人联系人获取
apiSendMailDto.setContent(apiEmailContactService.replacePlaceholders(emailTask.getContent(),recipient.getContactBizId()));
}
// 调用邮件服务发送邮件
apiEmailService.sendMail(apiSendMailDto);
......
......@@ -18,4 +18,6 @@ public interface ApiEmailContactService {
Result<ApiEmailContactDetailResponse> detail(String contactBizId);
Result del(String contactBizId);
String replacePlaceholders(String content, String contactBizId);
}
......@@ -3,8 +3,14 @@ package com.yd.email.api.service;
import com.yd.common.result.Result;
import com.yd.email.feign.request.ApiSendEmailRequest;
import com.yd.email.feign.response.ApiSendEmailResponse;
import com.yd.email.service.model.EmailTask;
import com.yd.email.service.model.EmailTaskRecipients;
import org.springframework.scheduling.annotation.Async;
import java.util.List;
public interface ApiEmailSendService {
Result<ApiSendEmailResponse> sendEmail(ApiSendEmailRequest request);
Result<ApiSendEmailResponse> testSendEmail(ApiSendEmailRequest request);
......
package com.yd.email.api.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.common.enums.CommonEnum;
......@@ -176,4 +179,23 @@ public class ApiEmailContactServiceImpl implements ApiEmailContactService {
}
return Result.success(emailContact);
}
/**
* 通用变量模板-替换邮件模板内容的变量占位符
* @param content 替换的占位符内容
* @param contactBizId 收件人业务ID
* @return
*/
@Override
public String replacePlaceholders(String content, String contactBizId) {
String result = content;
//查询收件人信息
EmailContact emailContact = iEmailContactService.queryOne(contactBizId);
if (!Objects.isNull(emailContact)) {
result = result.replace("{{name}}", emailContact.getName());
result = result.replace("{{appellation}}", emailContact.getAppellation());
result = result.replace("{{compantName}}", emailContact.getCompanyName());
}
return result;
}
}
package com.yd.email.api.service.impl;
import com.alibaba.fastjson.JSON;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.DateUtil;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.email.api.async.ApiEmailSendAsyncService;
import com.yd.email.api.service.*;
import com.yd.email.feign.dto.ApiEmailSenderConfigDto;
import com.yd.email.feign.dto.ApiSendMailDto;
......@@ -15,16 +15,13 @@ import com.yd.email.feign.response.ApiSendEmailResponse;
import com.yd.email.feign.utils.StringUtil;
import com.yd.email.service.model.EmailTask;
import com.yd.email.service.model.EmailTaskRecipients;
import com.yd.email.service.service.IEmailTaskRecipientsService;
import com.yd.email.service.service.IEmailTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
......@@ -42,9 +39,6 @@ public class ApiEmailSendServiceImpl implements ApiEmailSendService {
private IEmailTaskService iEmailTaskService;
@Autowired
private IEmailTaskRecipientsService iEmailTaskRecipientsService;
@Autowired
private ApiEmailSenderConfigService apiEmailSenderConfigService;
@Autowired
......@@ -53,12 +47,16 @@ public class ApiEmailSendServiceImpl implements ApiEmailSendService {
@Autowired
private ApiEmailTaskRecipientsService apiEmailTaskRecipientsService;
@Autowired
private ApiEmailSendAsyncService apiEmailSendAsyncService;
/**
* 发送邮件
* @param request
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Result<ApiSendEmailResponse> sendEmail(ApiSendEmailRequest request) {
ApiSendEmailResponse response = new ApiSendEmailResponse();
try {
......@@ -83,7 +81,7 @@ public class ApiEmailSendServiceImpl implements ApiEmailSendService {
jobId = xxlJobService.addScheduleJob(taskBizId, DateUtil.convertDateByLocalDateTime(request.getScheduleTime()));
}else {
//为空表示立即发送
sendImmediatelyEmail(mailTask,recipientsList);
apiEmailSendAsyncService.sendImmediatelyEmail(mailTask, recipientsList);
}
response.setJobId(jobId);
response.setScheduleTime(request.getScheduleTime());
......@@ -95,105 +93,7 @@ public class ApiEmailSendServiceImpl implements ApiEmailSendService {
}
}
/**
* 立即发送邮件
* @param emailTask
* @param recipients
* @return
*/
public Result sendImmediatelyEmail(EmailTask emailTask,List<EmailTaskRecipients> recipients) {
//主任务发送时间
LocalDateTime taskSendTime = LocalDateTime.now();
try {
//调用邮件服务发送邮件入参DTO
ApiSendMailDto apiSendMailDto = new ApiSendMailDto();
BeanUtils.copyProperties(emailTask,apiSendMailDto);
//根据发件人唯一业务ID获取发件人信息和发件人绑定的服务商信息
Result<ApiEmailSenderConfigDto> result = apiEmailSenderConfigService.getApiEmailSenderConfigDto(emailTask.getSenderBizId());
ApiEmailSenderConfigDto apiEmailSenderConfigDto = result.getData();
BeanUtils.copyProperties(apiEmailSenderConfigDto,apiSendMailDto);
//该任务下的所有收件人信息
log.info("查询该任务下的所有收件人信息: {}: " + JSON.toJSONString(recipients));
// 初始化成功和失败计数器
int successCount = 0;
int failCount = 0;
// 遍历所有收件人,逐个发送邮件
for (EmailTaskRecipients recipient : recipients) {
try {
log.info("遍历所有收件人,逐个发送邮件->recipient单个对象:{}",JSON.toJSONString(recipient));
// 添加发送间隔,避免频率过高
if (successCount > 0) {
Thread.sleep(1000); // 1秒间隔
}
// 处理抄送人列表:将数据库中的逗号分隔字符串转换为List
List<String> ccEmailList = StringUtils.isNotBlank(recipient.getCcEmail()) ?
Arrays.asList(recipient.getCcEmail().split(";")) :
new ArrayList<>();
log.info("处理抄送人列表:将数据库中的逗号分隔字符串转换为List: {}: " + JSON.toJSONString(ccEmailList));
//收件人邮箱(单个)
apiSendMailDto.setReceiveEmail(recipient.getReceiveEmail());
//抄送人邮箱列表
apiSendMailDto.setCcEmailList(ccEmailList);
//邮件内容
if (StringUtil.hasPlaceholdersSimple(emailTask.getContent())) {
//检测内容是否有占位符,有占位符就替换具体内容,每收件人的占位符内容是不一样的。
apiSendMailDto.setContent(StringUtil.replacePlaceholders(emailTask.getContent(),
recipient.getVariables()));
}
// 调用邮件服务发送邮件
apiEmailService.sendMail(apiSendMailDto);
// 发送成功:更新收件人状态为成功
recipient.setStatus(EmailTaskStatusEnum.SUCCESSFUL.getItemValue());
recipient.setSendTime(LocalDateTime.now()); // 记录实际发送时间
iEmailTaskRecipientsService.saveOrUpdate(recipient);
successCount++; // 成功计数加1
} catch (Exception e) {
// 发送失败:记录错误日志
log.error("发送邮件失败: {}", recipient.getReceiveEmail(), e);
// 更新收件人状态为失败
recipient.setStatus(EmailTaskStatusEnum.FAILED.getItemValue());
recipient.setErrorMsg(e.getMessage()); // 保存错误信息
iEmailTaskRecipientsService.saveOrUpdate(recipient);
failCount++; // 失败计数加1
}
}
// 根据发送结果更新邮件任务状态
emailTask.setStatus(failCount == 0 ?
EmailTaskStatusEnum.ALL_SUCCESSFUL.getItemValue() :
EmailTaskStatusEnum.PARTIAL_FAILURE.getItemValue());
//主任务发送时间
emailTask.setSendTime(taskSendTime);
iEmailTaskService.saveOrUpdate(emailTask);
// 记录任务完成日志
log.info("邮件发送任务完成: 成功{}个, 失败{}个", successCount, failCount);
// 设置任务执行结果
if (failCount == 0) {
log.info("发送完成: 成功" + successCount + "个");
} else {
log.info("发送完成: 成功" + successCount + "个, 失败" + failCount + "个");
}
} catch (Exception e) {
// 任务执行过程中发生异常
log.error("邮件发送任务执行异常", e);
// 更新任务状态为全部发送失败
emailTask.setStatus(EmailTaskStatusEnum.ALL_FAILED.getItemValue());
iEmailTaskService.saveOrUpdate(emailTask);
// 返回任务执行异常信息
log.error("任务执行异常: " + e.getMessage());
throw new BusinessException("立即发送邮件异常");
}
return Result.success();
}
/**
* 测试发送邮件
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment