From afced9d420626919b9cf8e165a073abad9713b65 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 25 Jan 2023 21:32:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=82=AE=E7=AE=B1=E6=A8=A1=E5=9D=97=EF=BC=9A?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8F=91=E9=80=81=20send=20=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/enums/ErrorCodeConstants.java | 7 +- .../dal/mysql/mail/MailAccountMapper.java | 5 - .../service/mail/MailAccountService.java | 8 + .../{impl => }/MailAccountServiceImpl.java | 12 +- .../mail/{impl => }/MailLogServiceImpl.java | 3 +- .../system/service/mail/MailSendService.java | 47 +++-- .../service/mail/MailSendServiceImpl.java | 172 ++++++++++++++++++ .../service/mail/MailTemplateService.java | 2 +- .../{impl => }/MailTemplateServiceImpl.java | 38 ++-- .../mail/impl/MailSendServiceImpl.java | 116 ------------ .../system/service/member/MemberService.java | 8 + .../service/member/MemberServiceImpl.java | 21 ++- .../service/sms/SmsTemplateServiceImpl.java | 2 +- 13 files changed, 275 insertions(+), 166 deletions(-) rename yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/{impl => }/MailAccountServiceImpl.java (92%) rename yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/{impl => }/MailLogServiceImpl.java (97%) create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java rename yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/{impl => }/MailTemplateServiceImpl.java (87%) delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.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 577fcb2ad..5eea402f7 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 24ce1ef06..e14fc18d7 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 2c90a9121..b0e02cb4b 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 @@ -22,6 +22,14 @@ public interface MailAccountService { */ void initLocalCache(); + /** + * 从缓存中获取邮箱账号 + * + * @param id 编号 + * @return 邮箱账号 + */ + MailAccountDO getMailAccountFromCache(Long id); + /** * 创建邮箱账号 * 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/MailAccountServiceImpl.java similarity index 92% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java index 2da58091b..bb673a7ad 100644 --- 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/MailAccountServiceImpl.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.system.service.mail.impl; +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; @@ -8,8 +8,6 @@ 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; @@ -21,8 +19,7 @@ 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; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; /** * 邮箱账号 Service 实现类 @@ -63,6 +60,11 @@ public class MailAccountServiceImpl implements MailAccountService { mailAccountCache = convertMap(accounts, MailAccountDO::getId); } + @Override + public MailAccountDO getMailAccountFromCache(Long id) { + return mailAccountCache.get(id); + } + @Override public Long createMailAccount(MailAccountCreateReqVO createReqVO) { // 插入 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/MailLogServiceImpl.java similarity index 97% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java index c489ad9bb..0582679d1 100644 --- 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/MailLogServiceImpl.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.system.service.mail.impl; +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; @@ -28,7 +28,6 @@ import java.util.Objects; @Validated public class MailLogServiceImpl implements MailLogService { - // TODO @wangjingyi:private,然后使用 @Resource DONE @Resource private MailLogMapper mailLogMapper; 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 615b34fcf..898816868 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 000000000..2ffd99a5c --- /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 704f7d653..cb9dc61ef 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/impl/MailTemplateServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java similarity index 87% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java index 753614683..c3e72f444 100644 --- 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/MailTemplateServiceImpl.java @@ -1,12 +1,9 @@ -package cn.iocoder.yudao.module.system.service.mail.impl; +package cn.iocoder.yudao.module.system.service.mail; - -import cn.hutool.core.collection.CollUtil; 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.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; @@ -14,7 +11,6 @@ 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; @@ -23,12 +19,12 @@ 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 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.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; /** @@ -42,6 +38,11 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @Slf4j public class MailTemplateServiceImpl implements MailTemplateService { + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + @Resource private MailTemplateMapper mailTemplateMapper; @@ -73,7 +74,8 @@ public class MailTemplateServiceImpl implements MailTemplateService { validateCodeUnique(null, createReqVO.getCode()); // 插入 - MailTemplateDO template = MailTemplateConvert.INSTANCE.convert(createReqVO); + MailTemplateDO template = MailTemplateConvert.INSTANCE.convert(createReqVO) + .setParams(parseTemplateContentParams(createReqVO.getContent())); mailTemplateMapper.insert(template); // 发送刷新消息 mailProducer.sendMailTemplateRefreshMessage(); @@ -88,7 +90,8 @@ public class MailTemplateServiceImpl implements MailTemplateService { validateCodeUnique(updateReqVO.getId(),updateReqVO.getCode()); // 更新 - MailTemplateDO updateObj = MailTemplateConvert.INSTANCE.convert(updateReqVO); + MailTemplateDO updateObj = MailTemplateConvert.INSTANCE.convert(updateReqVO) + .setParams(parseTemplateContentParams(updateReqVO.getContent())); mailTemplateMapper.updateById(updateObj); // 发送刷新消息 mailProducer.sendMailTemplateRefreshMessage(); @@ -118,6 +121,12 @@ public class MailTemplateServiceImpl implements MailTemplateService { 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);} @@ -135,14 +144,13 @@ public class MailTemplateServiceImpl implements MailTemplateService { } @Override - public String formatMailTemplateContent(String content, Map params) { + 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); - } + @VisibleForTesting + public List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); } @Override 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 9a9e9fe50..000000000 --- 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/member/MemberService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java index d96352b15..933e5bfc0 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 676a95a4e..7b31e0456 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,16 +21,29 @@ public class MemberServiceImpl implements MemberService { @Override public String getMemberUserMobile(Long id) { - if (id == null) { - return null; - } - Object user = ReflectUtil.invoke(getMemberUserApi(), "getUser", id); + Object user = getMemberUser(id); if (user == null) { return null; } return ReflectUtil.invoke(user, "getMobile"); } + @Override + public String getMemberUserEmail(Long id) { + Object user = getMemberUser(id); + if (user == null) { + return null; + } + return ReflectUtil.invoke(user, "getEmail"); + } + + private Object getMemberUser(Long id) { + if (id == null) { + return null; + } + return ReflectUtil.invoke(getMemberUserApi(), "getUser", id); + } + private Object getMemberUserApi() { if (memberUserApi == null) { memberUserApi = SpringUtil.getBean(ClassUtil.loadClass(String.format("%s.module.member.api.user.MemberUserApi", basePackage))); 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 fd6a03f4f..031edb7cc 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