feat:【system 系统功能】邮箱增加抄送、密送,支持多个

This commit is contained in:
YunaiV
2025-08-05 21:14:08 +08:00
parent 828901991d
commit 93cb8bad06
16 changed files with 215 additions and 309 deletions

View File

@@ -1259,9 +1259,9 @@ CREATE TABLE `system_mail_log` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`user_id` bigint NULL DEFAULT NULL COMMENT '用户编号', `user_id` bigint NULL DEFAULT NULL COMMENT '用户编号',
`user_type` tinyint NULL DEFAULT NULL COMMENT '用户类型', `user_type` tinyint NULL DEFAULT NULL COMMENT '用户类型',
`to_mail` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '接收邮箱地址', `to_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '接收邮箱地址',
`cc_mail` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '抄送邮箱地址', `cc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '抄送邮箱地址',
`bcc_mail` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密送邮箱地址', `bcc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密送邮箱地址',
`account_id` bigint NOT NULL COMMENT '邮箱账号编号', `account_id` bigint NOT NULL COMMENT '邮箱账号编号',
`from_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '发送邮箱地址', `from_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '发送邮箱地址',
`template_id` bigint NOT NULL COMMENT '模板编号', `template_id` bigint NOT NULL COMMENT '模板编号',

View File

@@ -21,13 +21,15 @@ public class MailSendApiImpl implements MailSendApi {
@Override @Override
public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) { public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) {
return mailSendService.sendSingleMailToAdmin(reqDTO.getMail(), reqDTO.getUserId(), return mailSendService.sendSingleMailToAdmin(reqDTO.getUserId(),
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
} }
@Override @Override
public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) { public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) {
return mailSendService.sendSingleMailToMember(reqDTO.getMail(), reqDTO.getUserId(), return mailSendService.sendSingleMailToMember(reqDTO.getUserId(),
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
} }

View File

@@ -4,6 +4,8 @@ import lombok.Data;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -16,13 +18,24 @@ public class MailSendSingleToUserReqDTO {
/** /**
* 用户编号 * 用户编号
*
* 如果非空,则加载对应用户的邮箱,添加到 {@link #toMails} 中
*/ */
private Long userId; private Long userId;
/** /**
* 邮箱 * 收件邮箱
*/ */
@Email private List<@Email String> toMails;
private String mail; /**
* 抄送邮箱
*/
private List<@Email String> ccMails;
/**
* 密送邮箱
*/
private List<@Email String> bccMails;
/** /**
* 邮件模板编号 * 邮件模板编号

View File

@@ -91,7 +91,8 @@ public class MailTemplateController {
@Operation(summary = "发送短信") @Operation(summary = "发送短信")
@PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')") @PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) { public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
return success(mailSendService.sendMultipleMailToAdmin(sendReqVO.getToMails(), sendReqVO.getCcMails(), sendReqVO.getBccMails(), getLoginUserId(), return success(mailSendService.sendSingleMailToAdmin(getLoginUserId(),
sendReqVO.getToMails(), sendReqVO.getCcMails(), sendReqVO.getBccMails(),
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
} }

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import java.util.Map; import java.util.Map;
@Schema(description = "管理后台 - 邮件日志 Response VO") @Schema(description = "管理后台 - 邮件日志 Response VO")
@@ -20,13 +21,13 @@ public class MailLogRespVO {
private Byte userType; private Byte userType;
@Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user1@example.com, user2@example.com") @Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user1@example.com, user2@example.com")
private String toMail; private List<String> toMails;
@Schema(description = "抄送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user3@example.com, user4@example.com") @Schema(description = "抄送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user3@example.com, user4@example.com")
private String ccMail; private List<String> ccMails;
@Schema(description = "密送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user5@example.com, user6@example.com") @Schema(description = "密送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user5@example.com, user6@example.com")
private String bccMail; private List<String> bccMails;
@Schema(description = "邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107") @Schema(description = "邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107")
private Long accountId; private Long accountId;

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
@@ -12,6 +13,7 @@ import lombok.*;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -47,18 +49,23 @@ public class MailLogDO extends BaseDO implements Serializable {
* 枚举 {@link UserTypeEnum} * 枚举 {@link UserTypeEnum}
*/ */
private Integer userType; private Integer userType;
/** /**
* 接收邮箱地址 * 接收邮箱地址
*/ */
private String toMail; @TableField(typeHandler = StringListTypeHandler.class)
private List<String> toMails;
/** /**
* 接收邮箱地址 * 接收邮箱地址
*/ */
private String ccMail; @TableField(typeHandler = StringListTypeHandler.class)
private List<String> ccMails;
/** /**
* 接收邮箱地址 * 密送邮箱地址
*/ */
private String bccMail; @TableField(typeHandler = StringListTypeHandler.class)
private List<String> bccMails;
/** /**
* 邮箱账号编号 * 邮箱账号编号
* *

View File

@@ -1,8 +1,10 @@
package cn.iocoder.yudao.module.system.dal.mysql.mail; package cn.iocoder.yudao.module.system.dal.mysql.mail;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@@ -14,11 +16,12 @@ public interface MailLogMapper extends BaseMapperX<MailLogDO> {
return selectPage(reqVO, new LambdaQueryWrapperX<MailLogDO>() return selectPage(reqVO, new LambdaQueryWrapperX<MailLogDO>()
.eqIfPresent(MailLogDO::getUserId, reqVO.getUserId()) .eqIfPresent(MailLogDO::getUserId, reqVO.getUserId())
.eqIfPresent(MailLogDO::getUserType, reqVO.getUserType()) .eqIfPresent(MailLogDO::getUserType, reqVO.getUserType())
.likeIfPresent(MailLogDO::getToMail, reqVO.getToMail())
.eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId()) .eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId())
.eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId()) .eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId())
.eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus()) .eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus())
.betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime()) .betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime())
.apply(StrUtil.isNotBlank(reqVO.getToMail()),
MyBatisUtils.findInSet("to_mails", reqVO.getToMail()))
.orderByDesc(MailLogDO::getId)); .orderByDesc(MailLogDO::getId));
} }

View File

@@ -5,6 +5,7 @@ import lombok.Data;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@@ -24,15 +25,15 @@ public class MailSendMessage {
* 接收邮件地址 * 接收邮件地址
*/ */
@NotEmpty(message = "接收邮件地址不能为空") @NotEmpty(message = "接收邮件地址不能为空")
private List<String> toMails; private Collection<String> toMails;
/** /**
* 抄送邮件地址 * 抄送邮件地址
*/ */
private List<String> ccMails; private Collection<String> ccMails;
/** /**
* 密送邮件地址 * 密送邮件地址
*/ */
private List<String> bccMails; private Collection<String> bccMails;
/** /**
* 邮件账号编号 * 邮件账号编号
*/ */

View File

@@ -7,6 +7,7 @@ import org.springframework.stereotype.Component;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List; import java.util.List;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
@@ -24,21 +25,6 @@ public class MailProducer {
@Resource @Resource
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
/**
* 发送 {@link MailSendMessage} 消息
*
* @param sendLogId 发送日志编码
* @param mail 接收邮件地址
* @param accountId 邮件账号编号
* @param nickname 邮件发件人
* @param title 邮件标题
* @param content 邮件内容
*/
public void sendMailSendMessage(Long sendLogId, String mail, Long accountId,
String nickname, String title, String content) {
sendMailSendMessage(sendLogId, singletonList(mail), null, null, accountId, nickname, title, content);
}
/** /**
* 发送 {@link MailSendMessage} 消息 * 发送 {@link MailSendMessage} 消息
* *
@@ -51,7 +37,8 @@ public class MailProducer {
* @param title 邮件标题 * @param title 邮件标题
* @param content 邮件内容 * @param content 邮件内容
*/ */
public void sendMailSendMessage(Long sendLogId, List<String> toMails, List<String> ccMails, List<String> bccMails, public void sendMailSendMessage(Long sendLogId,
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
Long accountId, String nickname, String title, String content) { Long accountId, String nickname, String title, String content) {
MailSendMessage message = new MailSendMessage() MailSendMessage message = new MailSendMessage()
.setLogId(sendLogId) .setLogId(sendLogId)

View File

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -33,23 +34,6 @@ public interface MailLogService {
*/ */
MailLogDO getMailLog(Long id); MailLogDO getMailLog(Long id);
/**
* 创建邮件日志
*
* @param userId 用户编码
* @param userType 用户类型
* @param toMail 收件人邮件
* @param account 邮件账号信息
* @param template 模版信息
* @param templateContent 模版内容
* @param templateParams 模版参数
* @param isSend 是否发送成功
* @return 日志编号
*/
Long createMailLog(Long userId, Integer userType, String toMail,
MailAccountDO account, MailTemplateDO template ,
String templateContent, Map<String, Object> templateParams, Boolean isSend);
/** /**
* 创建邮件日志 * 创建邮件日志
* *
@@ -65,7 +49,8 @@ public interface MailLogService {
* @param isSend 是否发送成功 * @param isSend 是否发送成功
* @return 日志编号 * @return 日志编号
*/ */
Long createMailLog(Long userId, Integer userType, List<String> toMails, List<String> ccMails, List<String> bccMails, Long createMailLog(Long userId, Integer userType,
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
MailAccountDO account, MailTemplateDO template, MailAccountDO account, MailTemplateDO template,
String templateContent, Map<String, Object> templateParams, Boolean isSend); String templateContent, Map<String, Object> templateParams, Boolean isSend);

View File

@@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.system.service.mail; package cn.iocoder.yudao.module.system.service.mail;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
@@ -13,9 +13,7 @@ import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.*;
import java.util.Map;
import java.util.Objects;
import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage;
@@ -43,7 +41,8 @@ public class MailLogServiceImpl implements MailLogService {
} }
@Override @Override
public Long createMailLog(Long userId, Integer userType, String toMail, public Long createMailLog(Long userId, Integer userType,
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
MailAccountDO account, MailTemplateDO template, MailAccountDO account, MailTemplateDO template,
String templateContent, Map<String, Object> templateParams, Boolean isSend) { String templateContent, Map<String, Object> templateParams, Boolean isSend) {
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
@@ -51,32 +50,8 @@ public class MailLogServiceImpl implements MailLogService {
logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus() logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
: MailSendStatusEnum.IGNORE.getStatus()) : MailSendStatusEnum.IGNORE.getStatus())
// 用户信息 // 用户信息
.userId(userId).userType(userType).toMail(toMail) .userId(userId).userType(userType)
.accountId(account.getId()).fromMail(account.getMail()) .toMails(ListUtil.toList(toMails)).ccMails(ListUtil.toList(ccMails)).bccMails(ListUtil.toList(bccMails))
// 模板相关字段
.templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname())
.templateTitle(template.getTitle()).templateContent(templateContent).templateParams(templateParams);
// 插入数据库
MailLogDO logDO = logDOBuilder.build();
mailLogMapper.insert(logDO);
return logDO.getId();
}
@Override
public Long createMailLog(Long userId, Integer userType, List<String> toMails, List<String> ccMails, List<String> bccMails,
MailAccountDO account, MailTemplateDO template,
String templateContent, Map<String, Object> templateParams, Boolean isSend) {
String toMail = CollUtil.isEmpty(toMails) ? "" : String.join(",", toMails);
String ccMail = CollUtil.isEmpty(ccMails) ? "" : String.join(",", ccMails);
String bccMail = CollUtil.isEmpty(bccMails) ? "" : String.join(",", bccMails);
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
// 根据是否要发送,设置状态
logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
: MailSendStatusEnum.IGNORE.getStatus())
// 用户信息
.userId(userId).userType(userType).toMail(toMail).ccMail(ccMail).bccMail(bccMail)
.accountId(account.getId()).fromMail(account.getMail()) .accountId(account.getId()).fromMail(account.getMail())
// 模板相关字段 // 模板相关字段
.templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname()) .templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname())

View File

@@ -1,8 +1,9 @@
package cn.iocoder.yudao.module.system.service.mail; package cn.iocoder.yudao.module.system.service.mail;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
import java.util.List; import java.util.Collection;
import java.util.Map; import java.util.Map;
/** /**
@@ -16,83 +17,55 @@ public interface MailSendService {
/** /**
* 发送单条邮件给管理后台的用户 * 发送单条邮件给管理后台的用户
* *
* @param mail 邮箱
* @param userId 用户编码 * @param userId 用户编码
* @param toMails 收件邮箱
* @param ccMails 抄送邮箱
* @param bccMails 密送邮箱
* @param templateCode 邮件模版编码 * @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数 * @param templateParams 邮件模版参数
* @return 发送日志编号 * @return 发送日志编号
*/ */
Long sendSingleMailToAdmin(String mail, Long userId, default Long sendSingleMailToAdmin(Long userId,
String templateCode, Map<String, Object> templateParams); Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
String templateCode, Map<String, Object> templateParams) {
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.ADMIN.getValue(),
templateCode, templateParams);
}
/** /**
* 发送单条邮件给用户 APP 的用户 * 发送单条邮件给用户 APP 的用户
* *
* @param mail 邮箱
* @param userId 用户编码 * @param userId 用户编码
* @param toMails 收件邮箱
* @param ccMails 抄送邮箱
* @param bccMails 密送邮箱
* @param templateCode 邮件模版编码 * @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数 * @param templateParams 邮件模版参数
* @return 发送日志编号 * @return 发送日志编号
*/ */
Long sendSingleMailToMember(String mail, Long userId, default Long sendSingleMailToMember(Long userId,
String templateCode, Map<String, Object> templateParams); Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
String templateCode, Map<String, Object> templateParams) {
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.MEMBER.getValue(),
templateCode, templateParams);
}
/** /**
* 发送单条邮件给用户 * 发送单条邮件
* *
* @param mail 邮箱 * @param toMails 收件邮箱
* @param userId 用户编码 * @param ccMails 抄送邮箱
* @param bccMails 密送邮箱
* @param userId 用户编号
* @param userType 用户类型 * @param userType 用户类型
* @param templateCode 邮件模版编码 * @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数 * @param templateParams 邮件模版参数
* @return 发送日志编号 * @return 发送日志编号
*/ */
Long sendSingleMail(String mail, Long userId, Integer userType, Long sendSingleMail(Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
Long userId, Integer userType,
String templateCode, Map<String, Object> templateParams); String templateCode, Map<String, Object> templateParams);
/**
* 发送多条邮件给管理后台的用户
*
* @param toMails 收件邮箱
* @param ccMails 抄送邮箱
* @param bccMails 密送邮箱
* @param userId 用户编码
* @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数
* @return 发送日志编号
*/
Long sendMultipleMailToAdmin(List<String> toMails, List<String> ccMails, List<String> bccMails,
Long userId, String templateCode, Map<String, Object> templateParams);
/**
* 发送多条邮件给用户 APP 的用户
*
* @param toMails 收件邮箱
* @param ccMails 抄送邮箱
* @param bccMails 密送邮箱
* @param userId 用户编码
* @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数
* @return 发送日志编号
*/
Long sendMultipleMailToMember(List<String> toMails, List<String> ccMails, List<String> bccMails,
Long userId, String templateCode, Map<String, Object> templateParams);
/**
* 发送单条邮件给用户
*
* @param toMails 收件邮箱
* @param ccMails 抄送邮箱
* @param bccMails 密送邮箱
* @param userId 用户编码
* @param userType 用户类型
* @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数
* @return 发送日志编号
*/
Long sendMultipleMail(List<String> toMails, List<String> ccMails, List<String> bccMails,
Long userId, Integer userType, String templateCode, Map<String, Object> templateParams);
/** /**
* 执行真正的邮件发送 * 执行真正的邮件发送
* 注意,该方法仅仅提供给 MQ Consumer 使用 * 注意,该方法仅仅提供给 MQ Consumer 使用

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.service.mail; package cn.iocoder.yudao.module.system.service.mail;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
@@ -14,16 +15,17 @@ import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.extra.mail.*; import org.dromara.hutool.extra.mail.MailAccount;
import org.dromara.hutool.extra.mail.MailUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.util.List; import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static java.util.Collections.singletonList;
/** /**
* 邮箱发送 Service 实现类 * 邮箱发送 Service 实现类
@@ -52,120 +54,67 @@ public class MailSendServiceImpl implements MailSendService {
private MailProducer mailProducer; private MailProducer mailProducer;
@Override @Override
public Long sendSingleMailToAdmin(String mail, Long userId, public Long sendSingleMail(Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
String templateCode, Map<String, Object> templateParams) { Long userId, Integer userType,
// 如果 mail 为空,则加载用户编号对应的邮箱
if (StrUtil.isEmpty(mail)) {
AdminUserDO user = adminUserService.getUser(userId);
if (user != null) {
mail = user.getEmail();
}
}
// 执行发送
return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
}
@Override
public Long sendSingleMailToMember(String mail, Long userId,
String templateCode, Map<String, Object> templateParams) {
// 如果 mail 为空,则加载用户编号对应的邮箱
if (StrUtil.isEmpty(mail)) {
mail = memberService.getMemberUserEmail(userId);
}
// 执行发送
return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
}
@Override
public Long sendSingleMail(String mail, Long userId, Integer userType,
String templateCode, Map<String, Object> templateParams) { String templateCode, Map<String, Object> templateParams) {
// 校验邮箱模版是否合法 // 1.1 校验邮箱模版是否合法
MailTemplateDO template = validateMailTemplate(templateCode); MailTemplateDO template = validateMailTemplate(templateCode);
// 校验邮箱账号是否合法 // 1.2 校验邮箱账号是否合法
MailAccountDO account = validateMailAccount(template.getAccountId()); MailAccountDO account = validateMailAccount(template.getAccountId());
// 1.3 校验邮件参数是否缺失
// 校验邮箱是否存在
mail = validateMail(mail);
validateTemplateParams(template, templateParams); validateTemplateParams(template, templateParams);
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 // 2. 组装邮箱
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); String userMail = getUserMail(userId, userType);
String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams); Collection<String> toMailSet = new LinkedHashSet<>();
String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams); Collection<String> ccMailSet = new LinkedHashSet<>();
Long sendLogId = mailLogService.createMailLog(userId, userType, mail, Collection<String> bccMailSet = new LinkedHashSet<>();
account, template, content, templateParams, isSend); if (Validator.isEmail(userMail)) {
// 发送 MQ 消息,异步执行发送短信 toMailSet.add(userMail);
if (isSend) {
mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(),
template.getNickname(), title, content);
} }
return sendLogId; if (CollUtil.isNotEmpty(toMails)) {
} toMails.stream().filter(Validator::isEmail).forEach(toMailSet::add);
@Override
public Long sendMultipleMailToAdmin(List<String> toMails, List<String> ccMails, List<String> bccMails, Long userId, String templateCode, Map<String, Object> templateParams) {
// 如果 mail 为空,则加载用户编号对应的邮箱
if (CollUtil.isEmpty(toMails)) {
AdminUserDO user = adminUserService.getUser(userId);
if (user != null) {
toMails = singletonList(user.getEmail());
}
}
// 执行发送
return sendMultipleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
}
@Override
public Long sendMultipleMailToMember(List<String> toMails, List<String> ccMails, List<String> bccMails, Long userId, String templateCode, Map<String, Object> templateParams) {
// 如果 mail 为空,则加载用户编号对应的邮箱
if (CollUtil.isEmpty(toMails)) {
toMails = singletonList(memberService.getMemberUserEmail(userId));
}
// 执行发送
return sendMultipleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
}
@Override
public Long sendMultipleMail(List<String> toMails, List<String> ccMails, List<String> bccMails, Long userId, Integer userType, String templateCode, Map<String, Object> templateParams) {
// 校验邮箱模版是否合法
MailTemplateDO template = validateMailTemplate(templateCode);
// 校验邮箱账号是否合法
MailAccountDO account = validateMailAccount(template.getAccountId());
// 校验邮件参数是否缺失
validateTemplateParams(template, templateParams);
if (CollUtil.isEmpty(toMails)) {
throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
}
// 校验邮箱是否存在
for (String mail : toMails) {
validateMail(mail);
} }
if (CollUtil.isNotEmpty(ccMails)) { if (CollUtil.isNotEmpty(ccMails)) {
for (String mail : ccMails) { ccMails.stream().filter(Validator::isEmail).forEach(ccMailSet::add);
validateMail(mail);
}
} }
if (CollUtil.isNotEmpty(bccMails)) { if (CollUtil.isNotEmpty(bccMails)) {
for (String mail : bccMails) { bccMails.stream().filter(Validator::isEmail).forEach(bccMailSet::add);
validateMail(mail); }
} if (CollUtil.isEmpty(toMailSet)) {
throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
} }
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams); String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams);
String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams); String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams);
Long sendLogId = mailLogService.createMailLog(userId, userType, toMails, ccMails, bccMails, Long sendLogId = mailLogService.createMailLog(userId, userType, toMailSet, ccMailSet, bccMailSet,
account, template, content, templateParams, isSend); account, template, content, templateParams, isSend);
// 发送 MQ 消息,异步执行发送短信 // 发送 MQ 消息,异步执行发送短信
if (isSend) { if (isSend) {
mailProducer.sendMailSendMessage(sendLogId, toMails, ccMails, bccMails, account.getId(), mailProducer.sendMailSendMessage(sendLogId, toMailSet, ccMailSet, bccMailSet,
template.getNickname(), title, content); account.getId(), template.getNickname(), title, content);
} }
return sendLogId; return sendLogId;
} }
private String getUserMail(Long userId, Integer userType) {
if (userId == null || userType == null) {
return null;
}
if (UserTypeEnum.ADMIN.getValue().equals(userType)) {
AdminUserDO user = adminUserService.getUser(userId);
if (user != null) {
return user.getEmail();
}
}
if (UserTypeEnum.MEMBER.getValue().equals(userType)) {
return memberService.getMemberUserEmail(userId);
}
return null;
}
@Override @Override
public void doSendMail(MailSendMessage message) { public void doSendMail(MailSendMessage message) {
// 1. 创建发送账号 // 1. 创建发送账号
@@ -213,14 +162,6 @@ public class MailSendServiceImpl implements MailSendService {
return account; return account;
} }
@VisibleForTesting
String validateMail(String mail) {
if (StrUtil.isEmpty(mail)) {
throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
}
return mail;
}
/** /**
* 校验邮件参数是否缺失 * 校验邮件参数是否缺失
* *

View File

@@ -10,10 +10,12 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper;
import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
@@ -43,7 +45,9 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
// 准备参数 // 准备参数
Long userId = randomLongId(); Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue(); Integer userType = randomEle(UserTypeEnum.values()).getValue();
String toMail = randomEmail(); Collection<String> toMails = Lists.newArrayList(randomEmail(), randomEmail());
Collection<String> ccMails = Lists.newArrayList(randomEmail());
Collection<String> bccMails = Lists.newArrayList(randomEmail());
MailAccountDO account = randomPojo(MailAccountDO.class); MailAccountDO account = randomPojo(MailAccountDO.class);
MailTemplateDO template = randomPojo(MailTemplateDO.class); MailTemplateDO template = randomPojo(MailTemplateDO.class);
String templateContent = randomString(); String templateContent = randomString();
@@ -52,14 +56,20 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
// mock 方法 // mock 方法
// 调用 // 调用
Long logId = mailLogService.createMailLog(userId, userType, toMail, account, template, templateContent, templateParams, isSend); Long logId = mailLogService.createMailLog(userId, userType, toMails, ccMails, bccMails,
account, template, templateContent, templateParams, isSend);
// 断言 // 断言
MailLogDO log = mailLogMapper.selectById(logId); MailLogDO log = mailLogMapper.selectById(logId);
assertNotNull(log); assertNotNull(log);
assertEquals(MailSendStatusEnum.INIT.getStatus(), log.getSendStatus()); assertEquals(MailSendStatusEnum.INIT.getStatus(), log.getSendStatus());
assertEquals(userId, log.getUserId()); assertEquals(userId, log.getUserId());
assertEquals(userType, log.getUserType()); assertEquals(userType, log.getUserType());
assertEquals(toMail, log.getToMail()); assertEquals(toMails.size(), log.getToMails().size());
assertTrue(log.getToMails().containsAll(toMails));
assertEquals(ccMails.size(), log.getCcMails().size());
assertTrue(log.getCcMails().containsAll(ccMails));
assertEquals(bccMails.size(), log.getBccMails().size());
assertTrue(log.getBccMails().containsAll(bccMails));
assertEquals(account.getId(), log.getAccountId()); assertEquals(account.getId(), log.getAccountId());
assertEquals(account.getMail(), log.getFromMail()); assertEquals(account.getMail(), log.getFromMail());
assertEquals(template.getId(), log.getTemplateId()); assertEquals(template.getId(), log.getTemplateId());
@@ -136,7 +146,9 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
MailLogDO dbMailLog = randomPojo(MailLogDO.class, o -> { // 等会查询到 MailLogDO dbMailLog = randomPojo(MailLogDO.class, o -> { // 等会查询到
o.setUserId(1L); o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue()); o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setToMail("768@qq.com"); o.setToMails(Lists.newArrayList("768@qq.com"));
o.setCcMails(Lists.newArrayList());
o.setBccMails(Lists.newArrayList());
o.setAccountId(10L); o.setAccountId(10L);
o.setTemplateId(100L); o.setTemplateId(100L);
o.setSendStatus(MailSendStatusEnum.INIT.getStatus()); o.setSendStatus(MailSendStatusEnum.INIT.getStatus());
@@ -148,8 +160,8 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserId(2L))); mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserId(2L)));
// 测试 userType 不匹配 // 测试 userType 不匹配
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 toMail 不匹配 // 测试 toMails 不匹配特殊find_in_set 无法单测)
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setToMail("788@.qq.com"))); // mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setToMails(Lists.newArrayList("788@qq.com"))));
// 测试 accountId 不匹配 // 测试 accountId 不匹配
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setAccountId(11L))); mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setAccountId(11L)));
// 测试 templateId 不匹配 // 测试 templateId 不匹配
@@ -162,7 +174,7 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
MailLogPageReqVO reqVO = new MailLogPageReqVO(); MailLogPageReqVO reqVO = new MailLogPageReqVO();
reqVO.setUserId(1L); reqVO.setUserId(1L);
reqVO.setUserType(UserTypeEnum.ADMIN.getValue()); reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
reqVO.setToMail("768"); // reqVO.setToMail("768@qq.com");
reqVO.setAccountId(10L); reqVO.setAccountId(10L);
reqVO.setTemplateId(100L); reqVO.setTemplateId(100L);
reqVO.setSendStatus(MailSendStatusEnum.INIT.getStatus()); reqVO.setSendStatus(MailSendStatusEnum.INIT.getStatus());

View File

@@ -20,6 +20,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockedStatic; import org.mockito.MockedStatic;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -65,14 +66,18 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
} }
@Test @Test
public void testSendSingleMailToAdmin() { public void testSendSingleMail_success() {
// 准备参数 // 准备参数
Long userId = randomLongId(); Long userId = randomLongId();
String templateCode = RandomUtils.randomString(); String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234") Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build(); .put("op", "login").build();
Collection<String> toMails = Lists.newArrayList("admin@test.com");
Collection<String> ccMails = Lists.newArrayList("cc@test.com");
Collection<String> bccMails = Lists.newArrayList("bcc@test.com");
// mock adminUserService 的方法 // mock adminUserService 的方法
AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300")); AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setEmail("admin@example.com"));
when(adminUserService.getUser(eq(userId))).thenReturn(user); when(adminUserService.getUser(eq(userId))).thenReturn(user);
// mock MailTemplateService 的方法 // mock MailTemplateService 的方法
@@ -93,61 +98,27 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account); when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
// mock MailLogService 的方法 // mock MailLogService 的方法
Long mailLogId = randomLongId(); Long mailLogId = randomLongId();
when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(user.getEmail()), when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.ADMIN.getValue()),
argThat(toMailSet -> toMailSet.contains(user.getEmail()) && toMailSet.contains("admin@test.com")),
argThat(ccMailSet -> ccMailSet.contains("cc@test.com")),
argThat(bccMailSet -> bccMailSet.contains("bcc@test.com")),
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId); eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
// 调用 // 调用
Long resultMailLogId = mailSendService.sendSingleMailToAdmin(null, userId, templateCode, templateParams); Long resultMailLogId = mailSendService.sendSingleMail(toMails, ccMails, bccMails, userId,
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
// 断言 // 断言
assertEquals(mailLogId, resultMailLogId); assertEquals(mailLogId, resultMailLogId);
// 断言调用 // 断言调用
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(user.getEmail()), verify(mailProducer).sendMailSendMessage(eq(mailLogId),
eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); argThat(toMailSet -> toMailSet.contains(user.getEmail()) && toMailSet.contains("admin@test.com")),
} argThat(ccMailSet -> ccMailSet.contains("cc@test.com")),
argThat(bccMailSet -> bccMailSet.contains("bcc@test.com")),
@Test
public void testSendSingleMailToMember() {
// 准备参数
Long userId = randomLongId();
String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock memberService 的方法
String mail = randomEmail();
when(memberService.getMemberUserEmail(eq(userId))).thenReturn(mail);
// mock MailTemplateService 的方法
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String title = RandomUtils.randomString();
when(mailTemplateService.formatMailTemplateContent(eq(template.getTitle()), eq(templateParams)))
.thenReturn(title);
String content = RandomUtils.randomString();
when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock MailAccountService 的方法
MailAccountDO account = randomPojo(MailAccountDO.class);
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
// mock MailLogService 的方法
Long mailLogId = randomLongId();
when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.MEMBER.getValue()), eq(mail),
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
// 调用
Long resultMailLogId = mailSendService.sendSingleMailToMember(null, userId, templateCode, templateParams);
// 断言
assertEquals(mailLogId, resultMailLogId);
// 断言调用
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail),
eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
} }
/** /**
* 发送成功,当短信模板开启时 * 发送成功,当邮件模板开启时
*/ */
@Test @Test
public void testSendSingleMail_successWhenMailTemplateEnable() { public void testSendSingleMail_successWhenMailTemplateEnable() {
@@ -158,6 +129,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
String templateCode = RandomUtils.randomString(); String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234") Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build(); .put("op", "login").build();
Collection<String> toMails = Lists.newArrayList(mail);
// mock MailTemplateService 的方法 // mock MailTemplateService 的方法
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> { MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
@@ -176,23 +149,29 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account); when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
// mock MailLogService 的方法 // mock MailLogService 的方法
Long mailLogId = randomLongId(); Long mailLogId = randomLongId();
when(mailLogService.createMailLog(eq(userId), eq(userType), eq(mail), when(mailLogService.createMailLog(eq(userId), eq(userType),
argThat(toMailSet -> toMailSet.contains(mail)),
argThat(Collection::isEmpty),
argThat(Collection::isEmpty),
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId); eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
// 调用 // 调用
Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams); Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams);
// 断言 // 断言
assertEquals(mailLogId, resultMailLogId); assertEquals(mailLogId, resultMailLogId);
// 断言调用 // 断言调用
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail), verify(mailProducer).sendMailSendMessage(eq(mailLogId),
argThat(toMailSet -> toMailSet.contains(mail)),
argThat(Collection::isEmpty),
argThat(Collection::isEmpty),
eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
} }
/** /**
* 发送成功,当短信模板关闭时 * 发送成功,当邮件模板关闭时
*/ */
@Test @Test
public void testSendSingleMail_successWhenSmsTemplateDisable() { public void testSendSingleMail_successWhenMailTemplateDisable() {
// 准备参数 // 准备参数
String mail = randomEmail(); String mail = randomEmail();
Long userId = randomLongId(); Long userId = randomLongId();
@@ -200,6 +179,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
String templateCode = RandomUtils.randomString(); String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234") Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build(); .put("op", "login").build();
Collection<String> toMails = Lists.newArrayList(mail);
// mock MailTemplateService 的方法 // mock MailTemplateService 的方法
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> { MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.DISABLE.getStatus()); o.setStatus(CommonStatusEnum.DISABLE.getStatus());
@@ -218,15 +199,18 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account); when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
// mock MailLogService 的方法 // mock MailLogService 的方法
Long mailLogId = randomLongId(); Long mailLogId = randomLongId();
when(mailLogService.createMailLog(eq(userId), eq(userType), eq(mail), when(mailLogService.createMailLog(eq(userId), eq(userType),
argThat(toMailSet -> toMailSet.contains(mail)),
argThat(Collection::isEmpty),
argThat(Collection::isEmpty),
eq(account), eq(template), eq(content), eq(templateParams), eq(false))).thenReturn(mailLogId); eq(account), eq(template), eq(content), eq(templateParams), eq(false))).thenReturn(mailLogId);
// 调用 // 调用
Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams); Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams);
// 断言 // 断言
assertEquals(mailLogId, resultMailLogId); assertEquals(mailLogId, resultMailLogId);
// 断言调用 // 断言调用
verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), anyString(), verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), any(), any(), any(),
anyLong(), anyString(), anyString(), anyString()); anyLong(), anyString(), anyString(), anyString());
} }
@@ -255,12 +239,29 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
} }
@Test @Test
public void testValidateMail_notExists() { public void testSendSingleMail_noValidEmail() {
// 准备参数 // 准备参数
// mock 方法 Long userId = randomLongId();
String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
Collection<String> toMails = Lists.newArrayList("invalid-email"); // 非法邮箱
// mock MailTemplateService 的方法
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
// mock MailAccountService 的方法
MailAccountDO account = randomPojo(MailAccountDO.class);
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
// 调用,并断言异常 // 调用,并断言异常
assertServiceException(() -> mailSendService.validateMail(null), assertServiceException(() -> mailSendService.sendSingleMail(toMails, null, null, userId,
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams),
MAIL_SEND_MAIL_NOT_EXISTS); MAIL_SEND_MAIL_NOT_EXISTS);
} }
@@ -286,7 +287,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
assertEquals(account.getPort(), mailAccount.getPort()); assertEquals(account.getPort(), mailAccount.getPort());
assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
return true; return true;
}), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))) }), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()),
eq(message.getTitle()), eq(message.getContent()), eq(true)))
.thenReturn(messageId); .thenReturn(messageId);
// 调用 // 调用
@@ -317,7 +319,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
assertEquals(account.getPort(), mailAccount.getPort()); assertEquals(account.getPort(), mailAccount.getPort());
assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
return true; return true;
}), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e); }), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()),
eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e);
// 调用 // 调用
mailSendService.doSendMail(message); mailSendService.doSendMail(message);

View File

@@ -553,7 +553,9 @@ CREATE TABLE IF NOT EXISTS "system_mail_log" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint, "user_id" bigint,
"user_type" varchar, "user_type" varchar,
"to_mail" varchar NOT NULL, "to_mails" varchar NOT NULL,
"cc_mails" varchar,
"bcc_mails" varchar,
"account_id" bigint NOT NULL, "account_id" bigint NOT NULL,
"from_mail" varchar NOT NULL, "from_mail" varchar NOT NULL,
"template_id" bigint NOT NULL, "template_id" bigint NOT NULL,