# Conflicts:
#	yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java
#	yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java
#	yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java
#	yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java
#	yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java
This commit is contained in:
YunaiV
2026-01-18 18:15:27 +08:00
42 changed files with 239 additions and 139 deletions

View File

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

View File

@@ -1,9 +1,10 @@
package cn.iocoder.yudao.module.system.api.mail.dto;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.util.List;
import java.util.Map;
@@ -46,4 +47,9 @@ public class MailSendSingleToUserReqDTO {
*/
private Map<String, Object> templateParams;
/**
* 附件
*/
private File[] attachments;
}

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.api.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
@@ -33,6 +34,7 @@ public class AdminUserApiImpl implements AdminUserApi {
private DeptService deptService;
@Override
@DataPermission(enable = false) // 忽略数据权限避免因为过滤导致无法查询用户。类似https://github.com/YunaiV/ruoyi-vue-pro/issues/1051
public AdminUserRespDTO getUser(Long id) {
AdminUserDO user = userService.getUser(id);
return BeanUtils.toBean(user, AdminUserRespDTO.class);

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.convert.auth;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
@@ -39,8 +40,6 @@ public interface AuthConvert {
.build();
}
AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu);
/**
* 将菜单列表,构建成菜单树
*
@@ -59,9 +58,10 @@ public interface AuthConvert {
// 构建菜单树
// 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。
Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>();
menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu)));
menuList.forEach(menu -> treeNodeMap.put(menu.getId(),
BeanUtils.toBean(menu, AuthPermissionInfoRespVO.MenuVO.class)));
// 处理父子关系
treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> {
treeNodeMap.values().stream().filter(node -> ObjUtil.notEqual(node.getParentId(), ID_ROOT)).forEach(childNode -> {
// 获得父节点
AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId());
if (parentNode == null) {

View File

@@ -1,12 +1,11 @@
package cn.iocoder.yudao.module.system.mq.message.mail;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.util.Collection;
import java.util.List;
/**
* 邮箱发送消息
@@ -55,4 +54,9 @@ public class MailSendMessage {
@NotEmpty(message = "邮件内容不能为空")
private String content;
/**
* 附件
*/
private File[] attachments;
}

View File

@@ -1,16 +1,13 @@
package cn.iocoder.yudao.module.system.mq.producer.mail;
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.File;
import java.util.Collection;
import java.util.List;
import static java.util.Collections.singletonList;
/**
* Mail 邮件相关消息的 Producer
@@ -28,23 +25,25 @@ public class MailProducer {
/**
* 发送 {@link MailSendMessage} 消息
*
* @param sendLogId 发送日志编码
* @param toMails 接收邮件地址
* @param ccMails 抄送邮件地址
* @param bccMails 密送邮件地址
* @param accountId 邮件账号编号
* @param nickname 邮件发件人
* @param title 邮件标题
* @param content 邮件内容
* @param sendLogId 发送日志编码
* @param toMails 接收邮件地址
* @param ccMails 抄送邮件地址
* @param bccMails 密送邮件地址
* @param accountId 邮件账号编号
* @param nickname 邮件发件人
* @param title 邮件标题
* @param content 邮件内容
* @param attachments 附件
*/
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,
File[] attachments) {
MailSendMessage message = new MailSendMessage()
.setLogId(sendLogId)
.setToMails(toMails).setCcMails(ccMails).setBccMails(bccMails)
.setAccountId(accountId).setNickname(nickname)
.setTitle(title).setContent(content);
.setTitle(title).setContent(content).setAttachments(attachments);
applicationContext.publishEvent(message);
}

View File

@@ -3,6 +3,7 @@ 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 java.io.File;
import java.util.Collection;
import java.util.Map;
@@ -23,13 +24,15 @@ public interface MailSendService {
* @param bccMails 密送邮箱
* @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数
* @param attachments 附件
* @return 发送日志编号
*/
default Long sendSingleMailToAdmin(Long userId,
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
String templateCode, Map<String, Object> templateParams) {
String templateCode, Map<String, Object> templateParams,
File... attachments) {
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.ADMIN.getValue(),
templateCode, templateParams);
templateCode, templateParams, attachments);
}
/**
@@ -41,13 +44,15 @@ public interface MailSendService {
* @param bccMails 密送邮箱
* @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数
* @param attachments 附件
* @return 发送日志编号
*/
default Long sendSingleMailToMember(Long userId,
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
String templateCode, Map<String, Object> templateParams) {
String templateCode, Map<String, Object> templateParams,
File... attachments) {
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.MEMBER.getValue(),
templateCode, templateParams);
templateCode, templateParams, attachments);
}
/**
@@ -60,11 +65,13 @@ public interface MailSendService {
* @param userType 用户类型
* @param templateCode 邮件模版编码
* @param templateParams 邮件模版参数
* @param attachments 附件
* @return 发送日志编号
*/
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,
File... attachments);
/**
* 执行真正的邮件发送

View File

@@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.system.service.mail;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
@@ -15,11 +13,14 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.extra.mail.MailAccount;
import org.dromara.hutool.extra.mail.MailUtil;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.io.File;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -56,7 +57,8 @@ public class MailSendServiceImpl implements MailSendService {
@Override
public 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,
File... attachments) {
// 1.1 校验邮箱模版是否合法
MailTemplateDO template = validateMailTemplate(templateCode);
// 1.2 校验邮箱账号是否合法
@@ -94,7 +96,7 @@ public class MailSendServiceImpl implements MailSendService {
// 发送 MQ 消息,异步执行发送短信
if (isSend) {
mailProducer.sendMailSendMessage(sendLogId, toMailSet, ccMailSet, bccMailSet,
account.getId(), template.getNickname(), title, content);
account.getId(), template.getNickname(), title, content, attachments);
}
return sendLogId;
}
@@ -123,7 +125,7 @@ public class MailSendServiceImpl implements MailSendService {
// 2. 发送邮件
try {
String messageId = MailUtil.send(mailAccount, message.getToMails(), message.getCcMails(), message.getBccMails(),
message.getTitle(), message.getContent(), true);
message.getTitle(), message.getContent(), true, message.getAttachments());
// 3. 更新结果(成功)
mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
} catch (Exception e) {
@@ -135,7 +137,7 @@ public class MailSendServiceImpl implements MailSendService {
private MailAccount buildMailAccount(MailAccountDO account, String nickname) {
String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
return new MailAccount().setFrom(from).setAuth(true)
.setUser(account.getUsername()).setPass(account.getPassword())
.setUser(account.getUsername()).setPass(account.getPassword().toCharArray())
.setHost(account.getHost()).setPort(account.getPort())
.setSslEnable(account.getSslEnable()).setStarttlsEnable(account.getStarttlsEnable());
}

View File

@@ -102,6 +102,19 @@ public class SocialClientServiceImpl implements SocialClientService {
@Value("${yudao.wxa-subscribe-message.miniprogram-state:formal}")
public String miniprogramState;
/**
* 上传发货信息重试次数
*/
private static final int UPLOAD_SHIPPING_INFO_MAX_RETRIES = 5;
/**
* 上传发货信息重试间隔
*/
private static final Duration UPLOAD_SHIPPING_INFO_RETRY_INTERVAL = Duration.ofMillis(500L);
/**
* 微信错误码:支付单不存在
*/
private static final int WX_ERR_CODE_PAY_ORDER_NOT_EXIST = 10060001;
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
@Autowired(required = false) // 由于 justauth.enable 配置项,可以关闭 AuthRequestFactory 的功能,所以这里只能不强制注入
private AuthRequestFactory authRequestFactory;
@@ -372,16 +385,34 @@ public class SocialClientServiceImpl implements SocialClientService {
.payer(PayerBean.builder().openid(reqDTO.getOpenid()).build())
.uploadTime(ZonedDateTime.now().format(UTC_MS_WITH_XXX_OFFSET_FORMATTER))
.build();
try {
WxMaOrderShippingInfoBaseResponse response = service.getWxMaOrderShippingService().upload(request);
if (response.getErrCode() != 0) {
// 重试机制:解决支付回调与订单信息上传之间的时间差导致的 10060001 错误
// 对应 ISSUEhttps://gitee.com/zhijiantianya/yudao-cloud/pulls/230
for (int attempt = 1; attempt <= UPLOAD_SHIPPING_INFO_MAX_RETRIES; attempt++) {
try {
WxMaOrderShippingInfoBaseResponse response = service.getWxMaOrderShippingService().upload(request);
// 成功,直接返回
if (response.getErrCode() == 0) {
log.info("[uploadWxaOrderShippingInfo][上传微信小程序发货信息成功request({}) response({})]", request, response);
return;
}
// 如果是 10060001 错误(支付单不存在)且还有重试次数,则等待后重试
if (response.getErrCode() == WX_ERR_CODE_PAY_ORDER_NOT_EXIST && attempt < UPLOAD_SHIPPING_INFO_MAX_RETRIES) {
log.warn("[uploadWxaOrderShippingInfo][第 {} 次尝试失败,支付单不存在,{} 后重试request({}) response({})]",
attempt, UPLOAD_SHIPPING_INFO_RETRY_INTERVAL, request, response);
Thread.sleep(UPLOAD_SHIPPING_INFO_RETRY_INTERVAL.toMillis());
continue;
}
// 其他错误或重试次数用尽,抛出异常
log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败request({}) response({})]", request, response);
throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, response.getErrMsg());
} catch (WxErrorException ex) {
log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败request({})]", request, ex);
throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, ex.getError().getErrorMsg());
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
log.error("[uploadWxaOrderShippingInfo][重试等待被中断request({})]", request, ex);
throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, "重试等待被中断");
}
log.info("[uploadWxaOrderShippingInfo][上传微信小程序发货信息成功request({}) response({})]", request, response);
} catch (WxErrorException ex) {
log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败request({})]", request, ex);
throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, ex.getError().getErrorMsg());
}
}

View File

@@ -44,6 +44,7 @@ import javax.annotation.Resource;
import javax.validation.ConstraintViolationException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
@@ -284,11 +285,14 @@ public class AdminUserServiceImpl implements AdminUserService {
@Override
public PageResult<AdminUserDO> getUserPage(UserPageReqVO reqVO) {
// 如果有角色编号,查询角色对应的用户编号
Set<Long> userIds = reqVO.getRoleId() != null ?
permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())) : null;
if (userIds != null && userIds.isEmpty()) {
return PageResult.empty();
Set<Long> userIds = null;
if (reqVO.getRoleId() != null) {
userIds = permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId()));
if (CollUtil.isEmpty(userIds)) {
return PageResult.empty();
}
}
// 分页查询
return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()), userIds);
}
@@ -484,12 +488,15 @@ public class AdminUserServiceImpl implements AdminUserService {
// 2. 遍历,逐个创建 or 更新
UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
AtomicInteger index = new AtomicInteger(1);
importUsers.forEach(importUser -> {
int currentIndex = index.getAndIncrement();
// 2.1.1 校验字段是否符合要求
try {
ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(initPassword));
} catch (ConstraintViolationException ex){
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
} catch (ConstraintViolationException ex) {
String key = StrUtil.blankToDefault(importUser.getUsername(), "" + currentIndex + "");
respVO.getFailureUsernames().put(key, ex.getMessage());
return;
}
// 2.1.2 校验,判断是否有不符合的原因

View File

@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.system.service.mail;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.mail.*;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
@@ -14,12 +13,15 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import org.assertj.core.util.Lists;
import org.dromara.hutool.extra.mail.MailAccount;
import org.dromara.hutool.extra.mail.MailUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -60,7 +62,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
// .setFrom("奥特曼 <ydym_test@163.com>")
.setFrom("ydym_test@163.com") // 邮箱地址
.setHost("smtp.163.com").setPort(465).setSslEnable(true) // SMTP 服务器
.setAuth(true).setUser("ydym_test@163.com").setPass("WBZTEINMIFVRYSOE"); // 登录账号密码
.setAuth(true).setUser("ydym_test@163.com").setPass("WBZTEINMIFVRYSOE".toCharArray()); // 登录账号密码
String messageId = MailUtil.send(mailAccount, "7685413@qq.com", "主题", "内容", false);
System.out.println("发送结果:" + messageId);
}
@@ -106,7 +108,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
// 调用
Long resultMailLogId = mailSendService.sendSingleMail(toMails, ccMails, bccMails, userId,
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, (File[]) null);
// 断言
assertEquals(mailLogId, resultMailLogId);
// 断言调用
@@ -114,7 +116,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
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.getId()), eq(template.getNickname()), eq(title), eq(content));
eq(account.getId()), eq(template.getNickname()), eq(title), eq(content), isNull());
}
/**
@@ -156,7 +158,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
// 调用
Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams);
Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams, (java.io.File[]) null);
// 断言
assertEquals(mailLogId, resultMailLogId);
// 断言调用
@@ -164,7 +166,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
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), isNull());
}
/**
@@ -206,12 +208,12 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
eq(account), eq(template), eq(content), eq(templateParams), eq(false))).thenReturn(mailLogId);
// 调用
Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams);
Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams, (java.io.File[]) null);
// 断言
assertEquals(mailLogId, resultMailLogId);
// 断言调用
verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), any(), any(), any(),
anyLong(), anyString(), anyString(), anyString());
anyLong(), anyString(), anyString(), anyString(), any());
}
@Test
@@ -261,7 +263,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
// 调用,并断言异常
assertServiceException(() -> mailSendService.sendSingleMail(toMails, null, null, userId,
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams),
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, (java.io.File[]) null),
MAIL_SEND_MAIL_NOT_EXISTS);
}
@@ -282,13 +284,13 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
assertTrue(mailAccount.isAuth());
assertEquals(account.getUsername(), mailAccount.getUser());
assertEquals(account.getPassword(), mailAccount.getPass());
assertArrayEquals(account.getPassword().toCharArray(), mailAccount.getPass());
assertEquals(account.getHost(), mailAccount.getHost());
assertEquals(account.getPort(), mailAccount.getPort());
assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
return true;
}), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()),
eq(message.getTitle()), eq(message.getContent()), eq(true)))
eq(message.getTitle()), eq(message.getContent()), eq(true), eq(message.getAttachments())))
.thenReturn(messageId);
// 调用
@@ -311,16 +313,16 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
// mock 方法(发送邮件)
Exception e = new NullPointerException("啦啦啦");
mailUtilMock.when(() -> MailUtil.send(argThat(mailAccount -> {
assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
assertTrue(mailAccount.isAuth());
assertEquals(account.getUsername(), mailAccount.getUser());
assertEquals(account.getPassword(), mailAccount.getPass());
assertEquals(account.getHost(), mailAccount.getHost());
assertEquals(account.getPort(), mailAccount.getPort());
assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
return true;
}), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()),
eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e);
assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
assertTrue(mailAccount.isAuth());
assertEquals(account.getUsername(), mailAccount.getUser());
assertArrayEquals(account.getPassword().toCharArray(), mailAccount.getPass());
assertEquals(account.getHost(), mailAccount.getHost());
assertEquals(account.getPort(), mailAccount.getPort());
assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
return true;
}), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()),
eq(message.getTitle()), eq(message.getContent()), eq(true), same(message.getAttachments()))).thenThrow(e);
// 调用
mailSendService.doSendMail(message);