mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 04:08:43 +08:00 
			
		
		
		
	邮箱模块:完善发送 send 逻辑
This commit is contained in:
		@@ -17,9 +17,4 @@ public interface MailAccountMapper extends BaseMapperX<MailAccountDO> {
 | 
			
		||||
                .likeIfPresent(MailAccountDO::getUsername , pageReqVO.getUsername()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default MailAccountDO selectOneByFrom(String from){
 | 
			
		||||
        return selectOne(new QueryWrapperX<MailAccountDO>()
 | 
			
		||||
                .eqIfPresent("from_address" , from));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,14 @@ public interface MailAccountService {
 | 
			
		||||
     */
 | 
			
		||||
    void initLocalCache();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 从缓存中获取邮箱账号
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 编号
 | 
			
		||||
     * @return 邮箱账号
 | 
			
		||||
     */
 | 
			
		||||
    MailAccountDO getMailAccountFromCache(Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建邮箱账号
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
        // 插入
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
@@ -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<String, Object> templateParams);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送单条邮件给用户 APP 的用户
 | 
			
		||||
     *
 | 
			
		||||
     * @param mail 邮箱
 | 
			
		||||
     * @param userId 用户编码
 | 
			
		||||
     * @param templateCode 邮件模版编码
 | 
			
		||||
     * @param templateParams 邮件模版参数
 | 
			
		||||
     * @return 发送日志编号
 | 
			
		||||
     */
 | 
			
		||||
    Long sendSingleMailToMember(String mail, Long userId,
 | 
			
		||||
                                String templateCode, Map<String, Object> 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<String, Object> templateParams);
 | 
			
		||||
    Long sendSingleMail(String mail, Long userId, Integer userType,
 | 
			
		||||
                        String templateCode, Map<String, Object> templateParams);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 执行真正的邮件发送
 | 
			
		||||
@@ -40,4 +56,5 @@ public interface MailSendService {
 | 
			
		||||
     * @param message 邮件
 | 
			
		||||
     */
 | 
			
		||||
    void doSendMail(MailSendMessage message);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<String, Object> 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<String, Object> templateParams) {
 | 
			
		||||
        // 如果 mail 为空,则加载用户编号对应的邮箱
 | 
			
		||||
        if (StrUtil.isEmpty(mail)) {
 | 
			
		||||
            mail = memberService.getMemberUserEmail(userId);
 | 
			
		||||
        }
 | 
			
		||||
        // 执行发送
 | 
			
		||||
        return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Long sendSingleMail(String mail, Long userId, Integer userType,
 | 
			
		||||
                               String templateCode, Map<String, Object> templateParams) {
 | 
			
		||||
        // 校验邮箱模版是否合法
 | 
			
		||||
        MailTemplateDO template = checkMailTemplateValid(templateCode);
 | 
			
		||||
        // 校验邮箱账号是否合法
 | 
			
		||||
        MailAccountDO account = checkMailAccountValid(template.getAccountId());
 | 
			
		||||
 | 
			
		||||
        // 校验邮箱是否存在
 | 
			
		||||
        mail = checkMail(mail);
 | 
			
		||||
        // 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
 | 
			
		||||
        List<KeyValue<String, Object>> 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<KeyValue<String, Object>> buildTemplateParams(MailTemplateDO template, Map<String, Object> 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());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -83,7 +83,7 @@ public interface MailTemplateService {
 | 
			
		||||
     * @param params 合成参数
 | 
			
		||||
     * @return 格式化后的内容
 | 
			
		||||
     */
 | 
			
		||||
    String formatMailTemplateContent(String content, Map<String, String> params);
 | 
			
		||||
    String formatMailTemplateContent(String content, Map<String, Object> params);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得指定邮件账号下的邮件模板数量
 | 
			
		||||
 
 | 
			
		||||
@@ -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<String, String> params) {
 | 
			
		||||
    public String formatMailTemplateContent(String content, Map<String, Object> 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<String> parseTemplateContentParams(String content) {
 | 
			
		||||
        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -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<String, Object> templateParams) {
 | 
			
		||||
        // TODO @@wangjingyi:发送的时候,参考下短信;DONE
 | 
			
		||||
        //校验邮箱模版是否合法
 | 
			
		||||
        MailTemplateDO mailTemplateDO =  this.checkMailTemplateValid(templateCode);
 | 
			
		||||
        // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
 | 
			
		||||
        Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus());
 | 
			
		||||
        //校验账号信息是否合法
 | 
			
		||||
        MailAccountDO mailAccountDO = this.checkMailAccountValid(from);
 | 
			
		||||
        Map<String , String> 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<KeyValue<String,Object>> 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<KeyValue<String, Object>> buildTemplateParams(MailTemplateDO template, Map<String, Object> 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());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -15,4 +15,12 @@ public interface MemberService {
 | 
			
		||||
     */
 | 
			
		||||
    String getMemberUserMobile(Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得会员用户的邮箱
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 会员用户编号
 | 
			
		||||
     * @return 邮箱
 | 
			
		||||
     */
 | 
			
		||||
    String getMemberUserEmail(Long id);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)));
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user