From afced9d420626919b9cf8e165a073abad9713b65 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 25 Jan 2023 21:32:32 +0800 Subject: [PATCH] 邮箱模块:完善发送 send 逻辑 --- yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java | 7 +++++-- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java | 5 ----- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java | 8 ++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java | 47 ++++++++++++++++++++++++++++++++--------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java | 125 ----------------------------------------------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java | 92 -------------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java | 116 -------------------------------------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java | 153 --------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java | 8 ++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java | 19 ++++++++++++++++--- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java | 2 +- 16 files changed, 622 insertions(+), 513 deletions(-) create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 577fcb2..5eea402 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -145,9 +145,12 @@ public interface ErrorCodeConstants { ErrorCode MAIL_ACCOUNT_NOT_EXISTS = new ErrorCode(1002023000, "邮箱账号不存在"); ErrorCode MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS = new ErrorCode(1002023001, "无法删除,该邮箱账号还有邮件模板"); - // ========== 邮箱模版 1002024000 ========== + // ========== 邮件模版 1002024000 ========== ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1002024000, "邮件模版不存在"); ErrorCode MAIL_TEMPLATE_CODE_EXISTS = new ErrorCode(1002024001, "邮件模版 code({}) 已存在"); - ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002021003, "模板参数({})缺失"); // TODO 优化 + + // ========== 邮件发送 1002025000 ========== + ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失"); + ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1002025000, "邮箱不存在"); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java index 24ce1ef..e14fc18 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java @@ -17,9 +17,4 @@ public interface MailAccountMapper extends BaseMapperX { .likeIfPresent(MailAccountDO::getUsername , pageReqVO.getUsername())); } - default MailAccountDO selectOneByFrom(String from){ - return selectOne(new QueryWrapperX() - .eqIfPresent("from_address" , from)); - } - } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java index 2c90a91..b0e02cb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java @@ -23,6 +23,14 @@ public interface MailAccountService { void initLocalCache(); /** + * 从缓存中获取邮箱账号 + * + * @param id 编号 + * @return 邮箱账号 + */ + MailAccountDO getMailAccountFromCache(Long id); + + /** * 创建邮箱账号 * * @param createReqVO 邮箱账号信息 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java new file mode 100644 index 0000000..bb673a7 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java @@ -0,0 +1,127 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO; +import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 邮箱账号 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailAccountServiceImpl implements MailAccountService { + + @Resource + private MailAccountMapper mailAccountMapper; + + @Resource + private MailTemplateService mailTemplateService; + + @Resource + private MailProducer mailProducer; + + /** + * 邮箱账号缓存 + * key:邮箱账号编码 {@link MailAccountDO#getId()} + * + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 + */ + private volatile Map mailAccountCache; + + @Override + @PostConstruct + public void initLocalCache() { + // 第一步:查询数据 + List accounts = mailAccountMapper.selectList(); + log.info("[initLocalCache][缓存邮箱账号,数量:{}]", accounts.size()); + + // 第二步:构建缓存 + mailAccountCache = convertMap(accounts, MailAccountDO::getId); + } + + @Override + public MailAccountDO getMailAccountFromCache(Long id) { + return mailAccountCache.get(id); + } + + @Override + public Long createMailAccount(MailAccountCreateReqVO createReqVO) { + // 插入 + MailAccountDO account = MailAccountConvert.INSTANCE.convert(createReqVO); + mailAccountMapper.insert(account); + + // 发送刷新消息 + mailProducer.sendMailAccountRefreshMessage(); + return account.getId(); + } + + @Override + public void updateMailAccount(MailAccountUpdateReqVO updateReqVO) { + // 校验是否存在 + validateMailAccountExists(updateReqVO.getId()); + + // 更新 + MailAccountDO updateObj = MailAccountConvert.INSTANCE.convert(updateReqVO); + mailAccountMapper.updateById(updateObj); + // 发送刷新消息 + mailProducer.sendMailAccountRefreshMessage(); + } + + @Override + public void deleteMailAccount(Long id) { + // 校验是否存在账号 + validateMailAccountExists(id); + // 校验是否存在关联模版 + if (mailTemplateService.countByAccountId(id) > 0) { + throw exception(MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS); + } + + // 删除 + mailAccountMapper.deleteById(id); + // 发送刷新消息 + mailProducer.sendMailAccountRefreshMessage(); + } + + private void validateMailAccountExists(Long id) { + if (mailAccountMapper.selectById(id) == null) { + throw exception(MAIL_ACCOUNT_NOT_EXISTS); + } + } + + @Override + public MailAccountDO getMailAccount(Long id) { + return mailAccountMapper.selectById(id); + } + + @Override + public PageResult getMailAccountPage(MailAccountPageReqVO pageReqVO) { + return mailAccountMapper.selectPage(pageReqVO); + } + + @Override + public List getMailAccountList() { + return mailAccountMapper.selectList(); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java new file mode 100644 index 0000000..0582679 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO; +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.MailLogDO; +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.enums.mail.MailSendStatusEnum; +import cn.iocoder.yudao.module.system.service.mail.MailLogService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 邮箱日志实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +public class MailLogServiceImpl implements MailLogService { + + @Resource + private MailLogMapper mailLogMapper; + + @Override + public PageResult getMailLogPage(MailLogPageReqVO pageVO) { + return mailLogMapper.selectPage(pageVO); + } + + @Override + public List getMailLogList(MailLogExportReqVO exportReqVO) { + return mailLogMapper.selectList(exportReqVO); + } + + @Override + public Long createMailLog(Long userId,Integer userType,String to,MailAccountDO mailAccountDO, MailTemplateDO template , String templateContent, Map templateParams, Boolean isSend) { + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); + // TODO @wangjingyi:使用 builder 的时候,不用每个 set 是一行。DONE + // 根据是否要发送,设置状态 + logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus() + : MailSendStatusEnum.IGNORE.getStatus()) + // 设置邮箱相关字段 + .fromMail(mailAccountDO.getMail()) + .accountId(mailAccountDO.getId()) + // TODO @wangjingyi:userId、userType + //用户信息 + .userId(userId).userType(userType) + //模版信息 + .templateId(template.getId()).templateParams(templateParams).templateContent(templateContent); + + + logDOBuilder.fromMail(mailAccountDO.getMail()); + logDOBuilder.accountId(mailAccountDO.getId()); + // TODO @wangjingyi:每个接收人一条日志。发送多个人,就调用多次,业务方。因为某个邮箱有问题,会导致所有都发送失败。 DONE + // 设置模板相关字段 + // TODO @wangjingyi:可以参考下 sms 短信的逻辑,templateContent、templateParams + // TODO @wangjingyi:有结果的时候,才是 sendTime 哈 DONE + //logDOBuilder.sendTime(new Date()); + + // 插入数据库 + MailLogDO logDO = logDOBuilder.build(); + mailLogMapper.insert(logDO); + return logDO.getId(); + } + + // TODO @wangjingyi:还是加几个字段哈,日志上。sendStatus,成功、失败;messageId 消息标号。sendException 记录发送的异常。这样界面才好筛选邮件的发送结果。DONE + @Override + public void updateMailSendResult(Long logId, String result) { + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); + logDOBuilder.id(logId).sendTime(new Date()).sendResult(result).messageId(result).sendStatus(MailSendStatusEnum.SUCCESS.getStatus()); + MailLogDO mailLogDO = logDOBuilder.build(); + mailLogMapper.updateById(mailLogDO); + } + + @Override + public void updateFailMailSendResult(Long logId, String exception) { + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); + logDOBuilder.id(logId).sendTime(new Date()).sendResult(exception).sendStatus(MailSendStatusEnum.FAILURE.getStatus()); + MailLogDO mailLogDO = logDOBuilder.build(); + mailLogMapper.updateById(mailLogDO); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java index 615b34f..8988168 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java @@ -1,19 +1,11 @@ package cn.iocoder.yudao.module.system.service.mail; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.send.MailReqVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateUpdateReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; -import javax.validation.Valid; -import java.util.List; import java.util.Map; /** - * 邮箱模版服务类 + * 邮件发送 Service 接口 * * @author wangjingyi * @since 2022-03-21 @@ -21,17 +13,41 @@ import java.util.Map; public interface MailSendService { /** - * 发送邮件 + * 发送单条邮件给管理后台的用户 * + * @param mail 邮箱 + * @param userId 用户编码 * @param templateCode 邮件模版编码 - * @param from 邮箱 - * @param content 内容 - * @param templateParams 模版参数 - * @param to 收件人 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMailToAdmin(String mail, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条邮件给用户 APP 的用户 + * + * @param mail 邮箱 + * @param userId 用户编码 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMailToMember(String mail, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条邮件给用户 + * + * @param mail 邮箱 * @param userId 用户编码 * @param userType 用户类型 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 */ - void sendMail(Long userId, Integer userType, String templateCode, String from,String to, String content, Map templateParams); + Long sendSingleMail(String mail, Long userId, Integer userType, + String templateCode, Map templateParams); /** * 执行真正的邮件发送 @@ -40,4 +56,5 @@ public interface MailSendService { * @param message 邮件 */ void doSendMail(MailSendMessage message); + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java new file mode 100644 index 0000000..2ffd99a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java @@ -0,0 +1,172 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.MailAccount; +import cn.hutool.extra.mail.MailUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; +import cn.iocoder.yudao.module.system.service.mail.MailLogService; +import cn.iocoder.yudao.module.system.service.mail.MailSendService; +import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; +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 lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 邮箱模版 服务实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailSendServiceImpl implements MailSendService { + + @Resource + private AdminUserService adminUserService; + @Resource + private MemberService memberService; + + @Resource + private MailAccountService mailAccountService; + @Resource + private MailTemplateService mailTemplateService; + + @Resource + private MailLogService mailLogService; + @Resource + private MailProducer mailProducer; + + @Override + public Long sendSingleMailToAdmin(String mail, Long userId, + String templateCode, Map templateParams) { + // 如果 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 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 templateParams) { + // 校验邮箱模版是否合法 + MailTemplateDO template = checkMailTemplateValid(templateCode); + // 校验邮箱账号是否合法 + MailAccountDO account = checkMailAccountValid(template.getAccountId()); + + // 校验邮箱是否存在 + mail = checkMail(mail); + // 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志 + List> newTemplateParams = buildTemplateParams(template, templateParams); + + // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); + String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams); + Long sendLogId = mailLogService.createMailLog(userId, userType, mail, + account, template, content, templateParams, isSend); // TODO 芋艿:待测试 + // 发送 MQ 消息,异步执行发送短信 + if (isSend) { + mailProducer.sendMailSendMessage(sendLogId, account, template, content, newTemplateParams, mail); // TODO 芋艿:待测试 + } + return sendLogId; + } + + @Override + public void doSendMail(MailSendMessage message) { + // TODO @wangjingyi:直接使用 hutool 发送,不要封装 mail client 哈,因为短信的客户端都是比较统一的 DONE + //装载账号信息 + MailAccount account = MailAccountConvert.INSTANCE.convertAccount(message); + //发送邮件 + try { + String messageId = MailUtil.send(account,message.getTo(),message.getTitle(),message.getContent(),false,null); + mailLogService.updateMailSendResult(message.getLogId() , messageId); + } catch (Exception e){ + mailLogService.updateFailMailSendResult(message.getLogId() , e.getMessage()); + } + } + + @VisibleForTesting + public MailTemplateDO checkMailTemplateValid(String templateCode) { + // 获得邮件模板。考虑到效率,从缓存中获取 + MailTemplateDO template = mailTemplateService.getMailTemplateByCodeFromCache(templateCode); + // 邮件模板不存在 + if (template == null) { + throw exception(MAIL_TEMPLATE_NOT_EXISTS); + } + return template; + } + + @VisibleForTesting + public MailAccountDO checkMailAccountValid(Long accountId) { + // 获得邮箱账号。考虑到效率,从缓存中获取 + MailAccountDO account = mailAccountService.getMailAccountFromCache(accountId); + // 邮箱账号不存在 + if (account == null) { + throw exception(MAIL_ACCOUNT_NOT_EXISTS); + } + return account; + } + + @VisibleForTesting + public String checkMail(String mail) { + if (StrUtil.isEmpty(mail)) { + throw exception(MAIL_SEND_MAIL_NOT_EXISTS); + } + return mail; + } + + /** + * 将参数模板,处理成有序的 KeyValue 数组 + * + * @param template 邮箱模板 + * @param templateParams 原始参数 + * @return 处理后的参数 + */ + @VisibleForTesting + public List> buildTemplateParams(MailTemplateDO template, Map templateParams) { + return template.getParams().stream().map(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key); + } + return new KeyValue<>(key, value); + }).collect(Collectors.toList()); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java index 704f7d6..cb9dc61 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java @@ -83,7 +83,7 @@ public interface MailTemplateService { * @param params 合成参数 * @return 格式化后的内容 */ - String formatMailTemplateContent(String content, Map params); + String formatMailTemplateContent(String content, Map params); /** * 获得指定邮件账号下的邮件模板数量 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java new file mode 100644 index 0000000..c3e72f4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java @@ -0,0 +1,161 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateUpdateReqVO; +import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 邮箱模版 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailTemplateServiceImpl implements MailTemplateService { + + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + + @Resource + private MailTemplateMapper mailTemplateMapper; + + @Resource + private MailProducer mailProducer; + + /** + * 邮件模板缓存 + * key:邮件模版标识 {@link MailTemplateDO#getCode()} + * + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 + */ + private volatile Map mailTemplateCache; + + @Override + @PostConstruct + public void initLocalCache() { + // 第一步:查询数据 + List templates = mailTemplateMapper.selectList(); + log.info("[initLocalCache][缓存邮件模版,数量:{}]", templates.size()); + + // 第二步:构建缓存 + mailTemplateCache = convertMap(templates, MailTemplateDO::getCode); + } + + @Override + public Long createMailTemplate(MailTemplateCreateReqVO createReqVO) { + // 校验 code 是否唯一 + validateCodeUnique(null, createReqVO.getCode()); + + // 插入 + MailTemplateDO template = MailTemplateConvert.INSTANCE.convert(createReqVO) + .setParams(parseTemplateContentParams(createReqVO.getContent())); + mailTemplateMapper.insert(template); + // 发送刷新消息 + mailProducer.sendMailTemplateRefreshMessage(); + return template.getId(); + } + + @Override + public void updateMailTemplate(@Valid MailTemplateUpdateReqVO updateReqVO) { + // 校验是否存在 + validateMailTemplateExists(updateReqVO.getId()); + // 校验 code 是否唯一 + validateCodeUnique(updateReqVO.getId(),updateReqVO.getCode()); + + // 更新 + MailTemplateDO updateObj = MailTemplateConvert.INSTANCE.convert(updateReqVO) + .setParams(parseTemplateContentParams(updateReqVO.getContent())); + mailTemplateMapper.updateById(updateObj); + // 发送刷新消息 + mailProducer.sendMailTemplateRefreshMessage(); + } + + @VisibleForTesting + public void validateCodeUnique(Long id, String code) { + MailTemplateDO template = mailTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 存在 template 记录的情况下 + if (id == null // 新增时,说明重复 + || ObjUtil.notEqual(id, template.getId())) { // 更新时,如果 id 不一致,说明重复 + throw exception(MAIL_TEMPLATE_CODE_EXISTS); + } + } + + @Override + public void deleteMailTemplate(Long id) { + // 校验是否存在 + validateMailTemplateExists(id); + + // 删除 + mailTemplateMapper.deleteById(id); + // 发送刷新消息 + mailProducer.sendMailTemplateRefreshMessage(); + } + + private void validateMailTemplateExists(Long id) { + if (mailTemplateMapper.selectById(id) == null) { + throw exception(MAIL_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public MailTemplateDO getMailTemplate(Long id) {return mailTemplateMapper.selectById(id);} + + @Override + public PageResult getMailTemplatePage(MailTemplatePageReqVO pageReqVO) { + return mailTemplateMapper.selectPage(pageReqVO); + } + + @Override + public List getMailTemplateList() {return mailTemplateMapper.selectList();} + + @Override + public MailTemplateDO getMailTemplateByCodeFromCache(String code) { + return mailTemplateCache.get(code); + } + + @Override + public String formatMailTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + + @VisibleForTesting + public List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + + @Override + public long countByAccountId(Long accountId) { + return mailTemplateMapper.selectCountByAccountId(accountId); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java deleted file mode 100644 index 2da5809..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java +++ /dev/null @@ -1,125 +0,0 @@ -package cn.iocoder.yudao.module.system.service.mail.impl; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO; -import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; -import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; -import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; -import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; -import cn.iocoder.yudao.module.system.service.mail.MailAccountService; -import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.PostConstruct; -import javax.annotation.Resource; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS; - -/** - * 邮箱账号 Service 实现类 - * - * @author wangjingyi - * @since 2022-03-21 - */ -@Service -@Validated -@Slf4j -public class MailAccountServiceImpl implements MailAccountService { - - @Resource - private MailAccountMapper mailAccountMapper; - - @Resource - private MailTemplateService mailTemplateService; - - @Resource - private MailProducer mailProducer; - - /** - * 邮箱账号缓存 - * key:邮箱账号编码 {@link MailAccountDO#getId()} - * - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 - */ - private volatile Map mailAccountCache; - - @Override - @PostConstruct - public void initLocalCache() { - // 第一步:查询数据 - List accounts = mailAccountMapper.selectList(); - log.info("[initLocalCache][缓存邮箱账号,数量:{}]", accounts.size()); - - // 第二步:构建缓存 - mailAccountCache = convertMap(accounts, MailAccountDO::getId); - } - - @Override - public Long createMailAccount(MailAccountCreateReqVO createReqVO) { - // 插入 - MailAccountDO account = MailAccountConvert.INSTANCE.convert(createReqVO); - mailAccountMapper.insert(account); - - // 发送刷新消息 - mailProducer.sendMailAccountRefreshMessage(); - return account.getId(); - } - - @Override - public void updateMailAccount(MailAccountUpdateReqVO updateReqVO) { - // 校验是否存在 - validateMailAccountExists(updateReqVO.getId()); - - // 更新 - MailAccountDO updateObj = MailAccountConvert.INSTANCE.convert(updateReqVO); - mailAccountMapper.updateById(updateObj); - // 发送刷新消息 - mailProducer.sendMailAccountRefreshMessage(); - } - - @Override - public void deleteMailAccount(Long id) { - // 校验是否存在账号 - validateMailAccountExists(id); - // 校验是否存在关联模版 - if (mailTemplateService.countByAccountId(id) > 0) { - throw exception(MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS); - } - - // 删除 - mailAccountMapper.deleteById(id); - // 发送刷新消息 - mailProducer.sendMailAccountRefreshMessage(); - } - - private void validateMailAccountExists(Long id) { - if (mailAccountMapper.selectById(id) == null) { - throw exception(MAIL_ACCOUNT_NOT_EXISTS); - } - } - - @Override - public MailAccountDO getMailAccount(Long id) { - return mailAccountMapper.selectById(id); - } - - @Override - public PageResult getMailAccountPage(MailAccountPageReqVO pageReqVO) { - return mailAccountMapper.selectPage(pageReqVO); - } - - @Override - public List getMailAccountList() { - return mailAccountMapper.selectList(); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java deleted file mode 100644 index c489ad9..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java +++ /dev/null @@ -1,92 +0,0 @@ -package cn.iocoder.yudao.module.system.service.mail.impl; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO; -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.MailLogDO; -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.enums.mail.MailSendStatusEnum; -import cn.iocoder.yudao.module.system.service.mail.MailLogService; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * 邮箱日志实现类 - * - * @author wangjingyi - * @since 2022-03-21 - */ -@Service -@Validated -public class MailLogServiceImpl implements MailLogService { - - // TODO @wangjingyi:private,然后使用 @Resource DONE - @Resource - private MailLogMapper mailLogMapper; - - @Override - public PageResult getMailLogPage(MailLogPageReqVO pageVO) { - return mailLogMapper.selectPage(pageVO); - } - - @Override - public List getMailLogList(MailLogExportReqVO exportReqVO) { - return mailLogMapper.selectList(exportReqVO); - } - - @Override - public Long createMailLog(Long userId,Integer userType,String to,MailAccountDO mailAccountDO, MailTemplateDO template , String templateContent, Map templateParams, Boolean isSend) { - MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); - // TODO @wangjingyi:使用 builder 的时候,不用每个 set 是一行。DONE - // 根据是否要发送,设置状态 - logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus() - : MailSendStatusEnum.IGNORE.getStatus()) - // 设置邮箱相关字段 - .fromMail(mailAccountDO.getMail()) - .accountId(mailAccountDO.getId()) - // TODO @wangjingyi:userId、userType - //用户信息 - .userId(userId).userType(userType) - //模版信息 - .templateId(template.getId()).templateParams(templateParams).templateContent(templateContent); - - - logDOBuilder.fromMail(mailAccountDO.getMail()); - logDOBuilder.accountId(mailAccountDO.getId()); - // TODO @wangjingyi:每个接收人一条日志。发送多个人,就调用多次,业务方。因为某个邮箱有问题,会导致所有都发送失败。 DONE - // 设置模板相关字段 - // TODO @wangjingyi:可以参考下 sms 短信的逻辑,templateContent、templateParams - // TODO @wangjingyi:有结果的时候,才是 sendTime 哈 DONE - //logDOBuilder.sendTime(new Date()); - - // 插入数据库 - MailLogDO logDO = logDOBuilder.build(); - mailLogMapper.insert(logDO); - return logDO.getId(); - } - - // TODO @wangjingyi:还是加几个字段哈,日志上。sendStatus,成功、失败;messageId 消息标号。sendException 记录发送的异常。这样界面才好筛选邮件的发送结果。DONE - @Override - public void updateMailSendResult(Long logId, String result) { - MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); - logDOBuilder.id(logId).sendTime(new Date()).sendResult(result).messageId(result).sendStatus(MailSendStatusEnum.SUCCESS.getStatus()); - MailLogDO mailLogDO = logDOBuilder.build(); - mailLogMapper.updateById(mailLogDO); - } - - @Override - public void updateFailMailSendResult(Long logId, String exception) { - MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); - logDOBuilder.id(logId).sendTime(new Date()).sendResult(exception).sendStatus(MailSendStatusEnum.FAILURE.getStatus()); - MailLogDO mailLogDO = logDOBuilder.build(); - mailLogMapper.updateById(mailLogDO); - } -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java deleted file mode 100644 index 9a9e9fe..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -package cn.iocoder.yudao.module.system.service.mail.impl; - -import cn.hutool.extra.mail.MailAccount; -import cn.hutool.extra.mail.MailUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; -import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; -import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; -import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; -import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; -import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; -import cn.iocoder.yudao.module.system.service.mail.MailLogService; -import cn.iocoder.yudao.module.system.service.mail.MailSendService; -import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; -import com.google.common.annotations.VisibleForTesting; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; - -/** - * 邮箱模版 服务实现类 - * - * @author wangjingyi - * @since 2022-03-21 - */ -@Service -@Validated -@Slf4j -public class MailSendServiceImpl implements MailSendService { - - @Resource - private MailAccountMapper mailAccountMapper; - @Resource - private MailTemplateService mailTemplateService; - @Resource - private MailLogService mailLogService; - @Resource - private MailProducer mailProducer; - - - @Override - public void sendMail(Long userId, Integer userType, String templateCode, String from,String to, String content, Map templateParams) { - // TODO @@wangjingyi:发送的时候,参考下短信;DONE - //校验邮箱模版是否合法 - MailTemplateDO mailTemplateDO = this.checkMailTemplateValid(templateCode); - // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 - Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus()); - //校验账号信息是否合法 - MailAccountDO mailAccountDO = this.checkMailAccountValid(from); - Map params = MailAccountConvert.INSTANCE.convertToMap(mailAccountDO , content); - content = mailTemplateService.formatMailTemplateContent(mailTemplateDO.getContent(), params); - Long sendLogId = mailLogService.createMailLog(userId,userType,to,mailAccountDO , mailTemplateDO , content, templateParams, isSend); - List> newTemplateParams = buildTemplateParams(mailTemplateDO,templateParams); - // 发送 MQ 消息,异步执行发送短信 - if (isSend) { - mailProducer.sendMailSendMessage(sendLogId,mailAccountDO , mailTemplateDO ,content, newTemplateParams,to); - } - } - - private MailAccountDO checkMailAccountValid(String from) { - MailAccountDO mailAccountDO = mailAccountMapper.selectOneByFrom(from); - if(null == mailAccountDO){ - throw exception(MAIL_ACCOUNT_NOT_EXISTS); - } - return mailAccountDO; - } - - @Override - public void doSendMail(MailSendMessage message) { - // TODO @wangjingyi:直接使用 hutool 发送,不要封装 mail client 哈,因为短信的客户端都是比较统一的 DONE - //装载账号信息 - MailAccount account = MailAccountConvert.INSTANCE.convertAccount(message); - //发送邮件 - try{ - String messageId = MailUtil.send(account,message.getTo(),message.getTitle(),message.getContent(),false,null); - mailLogService.updateMailSendResult(message.getLogId() , messageId); - }catch (Exception e){ - mailLogService.updateFailMailSendResult(message.getLogId() , e.getMessage()); - } - - } - - private MailTemplateDO checkMailTemplateValid(String templateCode) { - MailTemplateDO mailTemplateDO = mailTemplateService.getMailTemplateByCodeFromCache(templateCode); - if (mailTemplateDO == null){ - throw exception(MAIL_TEMPLATE_NOT_EXISTS); - } - return mailTemplateDO; - } - /** - * 将参数模板,处理成有序的 KeyValue 数组 - * - * @param template 邮箱模板 - * @param templateParams 原始参数 - * @return 处理后的参数 - */ - @VisibleForTesting - public List> buildTemplateParams(MailTemplateDO template, Map templateParams) { - return template.getParams().stream().map(key -> { - Object value = templateParams.get(key); - if (value == null) { - throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key); - } - return new KeyValue<>(key, value); - }).collect(Collectors.toList()); - } -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java deleted file mode 100644 index 7536146..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java +++ /dev/null @@ -1,153 +0,0 @@ -package cn.iocoder.yudao.module.system.service.mail.impl; - - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateUpdateReqVO; -import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert; -import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; -import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; -import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; -import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; -import com.google.common.annotations.VisibleForTesting; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.PostConstruct; -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.Date; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; - -/** - * 邮箱模版 Service 实现类 - * - * @author wangjingyi - * @since 2022-03-21 - */ -@Service -@Validated -@Slf4j -public class MailTemplateServiceImpl implements MailTemplateService { - - @Resource - private MailTemplateMapper mailTemplateMapper; - - @Resource - private MailProducer mailProducer; - - /** - * 邮件模板缓存 - * key:邮件模版标识 {@link MailTemplateDO#getCode()} - * - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 - */ - private volatile Map mailTemplateCache; - - @Override - @PostConstruct - public void initLocalCache() { - // 第一步:查询数据 - List templates = mailTemplateMapper.selectList(); - log.info("[initLocalCache][缓存邮件模版,数量:{}]", templates.size()); - - // 第二步:构建缓存 - mailTemplateCache = convertMap(templates, MailTemplateDO::getCode); - } - - @Override - public Long createMailTemplate(MailTemplateCreateReqVO createReqVO) { - // 校验 code 是否唯一 - validateCodeUnique(null, createReqVO.getCode()); - - // 插入 - MailTemplateDO template = MailTemplateConvert.INSTANCE.convert(createReqVO); - mailTemplateMapper.insert(template); - // 发送刷新消息 - mailProducer.sendMailTemplateRefreshMessage(); - return template.getId(); - } - - @Override - public void updateMailTemplate(@Valid MailTemplateUpdateReqVO updateReqVO) { - // 校验是否存在 - validateMailTemplateExists(updateReqVO.getId()); - // 校验 code 是否唯一 - validateCodeUnique(updateReqVO.getId(),updateReqVO.getCode()); - - // 更新 - MailTemplateDO updateObj = MailTemplateConvert.INSTANCE.convert(updateReqVO); - mailTemplateMapper.updateById(updateObj); - // 发送刷新消息 - mailProducer.sendMailTemplateRefreshMessage(); - } - - @VisibleForTesting - public void validateCodeUnique(Long id, String code) { - MailTemplateDO template = mailTemplateMapper.selectByCode(code); - if (template == null) { - return; - } - // 存在 template 记录的情况下 - if (id == null // 新增时,说明重复 - || ObjUtil.notEqual(id, template.getId())) { // 更新时,如果 id 不一致,说明重复 - throw exception(MAIL_TEMPLATE_CODE_EXISTS); - } - } - - @Override - public void deleteMailTemplate(Long id) { - // 校验是否存在 - validateMailTemplateExists(id); - - // 删除 - mailTemplateMapper.deleteById(id); - // 发送刷新消息 - mailProducer.sendMailTemplateRefreshMessage(); - } - - @Override - public MailTemplateDO getMailTemplate(Long id) {return mailTemplateMapper.selectById(id);} - - @Override - public PageResult getMailTemplatePage(MailTemplatePageReqVO pageReqVO) { - return mailTemplateMapper.selectPage(pageReqVO); - } - - @Override - public List getMailTemplateList() {return mailTemplateMapper.selectList();} - - @Override - public MailTemplateDO getMailTemplateByCodeFromCache(String code) { - return mailTemplateCache.get(code); - } - - @Override - public String formatMailTemplateContent(String content, Map params) { - return StrUtil.format(content, params); - } - - private void validateMailTemplateExists(Long id) { - if (mailTemplateMapper.selectById(id) == null) { - throw exception(MAIL_TEMPLATE_NOT_EXISTS); - } - } - - @Override - public long countByAccountId(Long accountId) { - return mailTemplateMapper.selectCountByAccountId(accountId); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java index d96352b..933e5bf 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java @@ -15,4 +15,12 @@ public interface MemberService { */ String getMemberUserMobile(Long id); + /** + * 获得会员用户的邮箱 + * + * @param id 会员用户编号 + * @return 邮箱 + */ + String getMemberUserEmail(Long id); + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java index 676a95a..7b31e04 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java @@ -21,14 +21,27 @@ public class MemberServiceImpl implements MemberService { @Override public String getMemberUserMobile(Long id) { - if (id == null) { + Object user = getMemberUser(id); + if (user == null) { return null; } - Object user = ReflectUtil.invoke(getMemberUserApi(), "getUser", id); + return ReflectUtil.invoke(user, "getMobile"); + } + + @Override + public String getMemberUserEmail(Long id) { + Object user = getMemberUser(id); if (user == null) { return null; } - return ReflectUtil.invoke(user, "getMobile"); + return ReflectUtil.invoke(user, "getEmail"); + } + + private Object getMemberUser(Long id) { + if (id == null) { + return null; + } + return ReflectUtil.invoke(getMemberUserApi(), "getUser", id); } private Object getMemberUserApi() { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java index fd6a03f..031edb7 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java @@ -39,7 +39,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; * 短信模板 Service 实现类 * * @author zzf - * @date 2021/1/25 9:25 + * @since 2021/1/25 9:25 */ @Service @Slf4j -- libgit2 0.21.4