Commit d7305739d3fcef6efe25c12d33c02b903c181308

Authored by wangjingyi
1 parent d1812761

邮件模块 添加邮件发送api

Showing 44 changed files with 1085 additions and 59 deletions
yudao-framework/pom.xml
... ... @@ -30,6 +30,7 @@
30 30 <module>yudao-spring-boot-starter-biz-operatelog</module>
31 31 <module>yudao-spring-boot-starter-biz-dict</module>
32 32 <module>yudao-spring-boot-starter-biz-sms</module>
  33 + <module>yudao-spring-boot-starter-biz-mail</module>
33 34 <module>yudao-spring-boot-starter-activiti</module>
34 35 <module>yudao-spring-boot-starter-biz-pay</module>
35 36 <module>yudao-spring-boot-starter-biz-weixin</module>
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <groupId>cn.iocoder.boot</groupId>
  7 + <artifactId>yudao-framework</artifactId>
  8 + <version>${revision}</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 + <artifactId>yudao-spring-boot-starter-biz-mail</artifactId>
  12 + <packaging>jar</packaging>
  13 +
  14 + <dependencies>
  15 + <dependency>
  16 + <groupId>cn.iocoder.boot</groupId>
  17 + <artifactId>yudao-common</artifactId>
  18 + </dependency>
  19 +
  20 + <!-- Spring 核心 -->
  21 + <dependency>
  22 + <groupId>org.springframework.boot</groupId>
  23 + <artifactId>spring-boot-starter</artifactId>
  24 + </dependency>
  25 +
  26 + <!-- 监控相关 -->
  27 + <dependency>
  28 + <groupId>io.opentracing</groupId>
  29 + <artifactId>opentracing-util</artifactId> <!-- aliyun 短信需要,进行链路追踪 -->
  30 + </dependency>
  31 +
  32 + <!-- Test 测试相关 -->
  33 + <dependency>
  34 + <groupId>cn.iocoder.boot</groupId>
  35 + <artifactId>yudao-spring-boot-starter-test</artifactId>
  36 + <scope>test</scope>
  37 + </dependency>
  38 +
  39 + <!-- 工具类相关 -->
  40 + <dependency>
  41 + <groupId>com.google.guava</groupId>
  42 + <artifactId>guava</artifactId>
  43 + <optional>true</optional> <!-- 设置为可选,因为使用到 @VisibleForTesting 用于单元测试 -->
  44 + </dependency>
  45 +
  46 + <dependency>
  47 + <groupId>com.fasterxml.jackson.core</groupId>
  48 + <artifactId>jackson-databind</artifactId>
  49 + </dependency>
  50 + <dependency>
  51 + <groupId>com.fasterxml.jackson.core</groupId>
  52 + <artifactId>jackson-core</artifactId>
  53 + </dependency>
  54 +
  55 + <dependency>
  56 + <groupId>jakarta.validation</groupId>
  57 + <artifactId>jakarta.validation-api</artifactId>
  58 + </dependency>
  59 + <dependency>
  60 + <groupId>org.projectlombok</groupId>
  61 + <artifactId>lombok</artifactId>
  62 + </dependency>
  63 + </dependencies>
  64 +
  65 +</project>
0 66 \ No newline at end of file
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/config/YudaoMailAutoConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.config;
  2 +
  3 +import cn.iocoder.yudao.framework.mail.core.client.MailClientFactory;
  4 +import cn.iocoder.yudao.framework.mail.core.client.impl.MailClientFactoryImpl;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.Configuration;
  7 +
  8 +/**
  9 + * 邮箱配置类
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Configuration
  14 +public class YudaoMailAutoConfiguration {
  15 +
  16 + @Bean
  17 + public MailClientFactory mailClientFactory() {
  18 + return new MailClientFactoryImpl();
  19 + }
  20 +
  21 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClient.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client;
  2 +
  3 +import java.util.List;
  4 +
  5 +/**
  6 + * 邮件客户端,用于对接各邮箱平台的 SDK,实现邮件发送等功能
  7 + *
  8 + * @author wangjingyi
  9 + * @date 2021/4/19 19:21
  10 + */
  11 +public interface MailClient {
  12 +
  13 + /**
  14 + * 发送邮件
  15 + *
  16 + * @param from 邮箱账号
  17 + * @param content 内容
  18 + * @param title 标题
  19 + * @param tos 收件人
  20 + * @return 邮件发送结果
  21 + */
  22 + String sendMail(String from, String content, String title, List<String> tos);
  23 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClientFactory.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client;
  2 +
  3 +public interface MailClientFactory {
  4 + MailClient getMailClient();
  5 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCodeMapping.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client;
  2 +
  3 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  4 +import cn.iocoder.yudao.framework.mail.core.enums.MailFrameworkErrorCodeConstants;
  5 +
  6 +import java.util.function.Function;
  7 +
  8 +/**
  9 + * 将 API 的错误码,转换为通用的错误码
  10 + *
  11 + * @see MailCommonResult
  12 + * @see MailFrameworkErrorCodeConstants
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface MailCodeMapping extends Function<String, ErrorCode> {
  17 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCommonResult.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client;
  2 +
  3 +import cn.hutool.core.exceptions.ExceptionUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  6 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
  10 +import cn.iocoder.yudao.framework.mail.core.enums.MailFrameworkErrorCodeConstants;
  11 +
  12 +/**
  13 + * 短信的 CommonResult 拓展类
  14 + *
  15 + * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段
  16 + *
  17 + * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +@ToString(callSuper = true)
  24 +public class MailCommonResult<T> extends CommonResult<T> {
  25 +
  26 + /**
  27 + * API 返回错误码
  28 + *
  29 + * 由于第三方的错误码可能是字符串,所以使用 String 类型
  30 + */
  31 + private String apiCode;
  32 + /**
  33 + * API 返回提示
  34 + */
  35 + private String apiMsg;
  36 +
  37 + /**
  38 + * API 请求编号
  39 + */
  40 + private String apiRequestId;
  41 +
  42 + private MailCommonResult() {
  43 + }
  44 +
  45 + public static <T> MailCommonResult<T> build(String apiCode, String apiMsg, String apiRequestId,
  46 + T data, MailCodeMapping codeMapping) {
  47 + Assert.notNull(codeMapping, "参数 codeMapping 不能为空");
  48 + MailCommonResult<T> result = new MailCommonResult<T>().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId);
  49 + result.setData(data);
  50 + // 翻译错误码
  51 + if (codeMapping != null) {
  52 + ErrorCode errorCode = codeMapping.apply(apiCode);
  53 + if (errorCode == null) {
  54 + errorCode = MailFrameworkErrorCodeConstants.MAIL_UNKNOWN;
  55 + }
  56 + result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg());
  57 + }
  58 + return result;
  59 + }
  60 +
  61 + public static <T> MailCommonResult<T> error(Throwable ex) {
  62 + MailCommonResult<T> result = new MailCommonResult<>();
  63 + result.setCode(MailFrameworkErrorCodeConstants.EXCEPTION.getCode());
  64 + result.setMsg(ExceptionUtil.getRootCauseMessage(ex));
  65 + return result;
  66 + }
  67 +
  68 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailReceiveRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.Date;
  6 +
  7 +/**
  8 + * 消息接收 Response DTO
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +public class MailReceiveRespDTO {
  14 +
  15 + /**
  16 + * 是否接收成功
  17 + */
  18 + private Boolean success;
  19 + /**
  20 + * API 接收结果的编码
  21 + */
  22 + private String errorCode;
  23 + /**
  24 + * API 接收结果的说明
  25 + */
  26 + private String errorMsg;
  27 +
  28 + /**
  29 + * 手机号
  30 + */
  31 + private String mobile;
  32 + /**
  33 + * 用户接收时间
  34 + */
  35 + private Date receiveTime;
  36 +
  37 + /**
  38 + * 短信 API 发送返回的序号
  39 + */
  40 + private String serialNo;
  41 + /**
  42 + * 短信日志编号
  43 + *
  44 + * 对应 SysSmsLogDO 的编号
  45 + */
  46 + private Long logId;
  47 +
  48 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailSendRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * 短信发送 Response DTO
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +@Data
  11 +public class MailSendRespDTO {
  12 +
  13 + /**
  14 + * 短信 API 发送返回的序号
  15 + */
  16 + private String serialNo;
  17 +
  18 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailTemplateRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * 短信模板 Response DTO
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +@Data
  11 +public class MailTemplateRespDTO {
  12 +
  13 + /**
  14 + * 模板编号
  15 + */
  16 + private String id;
  17 + /**
  18 + * 短信内容
  19 + */
  20 + private String content;
  21 + /**
  22 + * 审核状态
  23 + *
  24 + */
  25 + private Integer auditStatus;
  26 + /**
  27 + * 审核未通过的理由
  28 + */
  29 + private String auditReason;
  30 +
  31 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/AbstractMailClient.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client.impl;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import cn.iocoder.yudao.framework.mail.core.client.MailClient;
  5 +
  6 +/**
  7 + * 短信客户端的抽象类,提供模板方法,减少子类的冗余代码
  8 + *
  9 + * @author zzf
  10 + * @date 2021/2/1 9:28
  11 + */
  12 +@Slf4j
  13 +public abstract class AbstractMailClient implements MailClient {
  14 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/MailClientFactoryImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client.impl;
  2 +
  3 +import cn.iocoder.yudao.framework.mail.core.client.MailClient;
  4 +import cn.iocoder.yudao.framework.mail.core.client.impl.hutool.HutoolMailClient;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import cn.iocoder.yudao.framework.mail.core.client.MailClientFactory;
  7 +import cn.iocoder.yudao.framework.mail.core.enums.MailChannelEnum;
  8 +import org.springframework.validation.annotation.Validated;
  9 +
  10 +import java.util.Arrays;
  11 +import java.util.concurrent.ConcurrentHashMap;
  12 +import java.util.concurrent.ConcurrentMap;
  13 +@Validated
  14 +@Slf4j
  15 +public class MailClientFactoryImpl implements MailClientFactory {
  16 +
  17 + private final ConcurrentMap<String, AbstractMailClient> channelCodeClients = new ConcurrentHashMap<>();
  18 +
  19 + public MailClientFactoryImpl (){
  20 + Arrays.stream(MailChannelEnum.values()).forEach(mailChannelEnum -> {
  21 + AbstractMailClient abstractMailClient = createMailClient(mailChannelEnum);
  22 + channelCodeClients.put(mailChannelEnum.getCode() , abstractMailClient);
  23 + });
  24 + }
  25 +
  26 + private AbstractMailClient createMailClient(MailChannelEnum mailChannelEnum) {
  27 + switch (mailChannelEnum){
  28 + case HUTOOL: return new HutoolMailClient();
  29 + }
  30 + // 创建失败,错误日志 + 抛出异常
  31 + log.error("[createMailClient][配置({}) 找不到合适的客户端实现]" , mailChannelEnum);
  32 + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", mailChannelEnum));
  33 + }
  34 +
  35 + @Override
  36 + public MailClient getMailClient() {
  37 + return channelCodeClients.get("HUTOOL");
  38 + }
  39 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailClient.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client.impl.hutool;
  2 +
  3 +import cn.hutool.extra.mail.MailUtil;
  4 +import cn.iocoder.yudao.framework.mail.core.client.impl.AbstractMailClient;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +
  7 +import java.util.List;
  8 +
  9 +
  10 +/**
  11 + * 邮件客户端实现
  12 + *
  13 + * @author wangjingyi
  14 + * @date 2021/4/25 14:25
  15 + */
  16 +@Slf4j
  17 +public class HutoolMailClient extends AbstractMailClient {
  18 +
  19 + @Override
  20 + public String sendMail(String from, String content, String title, List<String> tos) {
  21 + try{
  22 + return MailUtil.send(from , title , content , false , null);
  23 + }catch (Exception e){
  24 + log.error(e.getMessage());
  25 + }
  26 + return "";
  27 + }
  28 +
  29 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailCodeMapping.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.client.impl.hutool;
  2 +
  3 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  4 +import cn.iocoder.yudao.framework.mail.core.client.MailCodeMapping;
  5 +
  6 +/**
  7 + * 阿里云的 SmsCodeMapping 实现类
  8 + *
  9 + * 参见 https://help.aliyun.com/document_detail/101346.htm 文档
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public class HutoolMailCodeMapping implements MailCodeMapping {
  14 +
  15 + @Override
  16 + public ErrorCode apply(String apiCode) {
  17 + return null;
  18 + }
  19 +
  20 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailChannelEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.enums;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +/**
  8 + * 短信渠道枚举
  9 + *
  10 + * @author zzf
  11 + * @date 2021/1/25 10:56
  12 + */
  13 +@Getter
  14 +@AllArgsConstructor
  15 +public enum MailChannelEnum {
  16 + HUTOOL("HUTOOL" , "HUTOOL"),
  17 + ;
  18 +
  19 + /**
  20 + * 编码
  21 + */
  22 + private final String code;
  23 + /**
  24 + * 名字
  25 + */
  26 + private final String name;
  27 +
  28 + public static MailChannelEnum getByCode(String code) {
  29 + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
  30 + }
  31 +
  32 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailFrameworkErrorCodeConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.enums;
  2 +
  3 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  4 +
  5 +/**
  6 + * 短信框架的错误码枚举
  7 + *
  8 + * 短信框架,使用 2-001-000-000 段
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +public interface MailFrameworkErrorCodeConstants {
  13 +
  14 + ErrorCode MAIL_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析");
  15 +
  16 + // ========== 权限 / 限流等相关 2001000100 ==========
  17 +
  18 + ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限");
  19 + // 云片:可以配置 IP 白名单,只有在白名单中才可以发送短信
  20 + ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信");
  21 +
  22 + // 阿里云:将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。
  23 + ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流");
  24 + // 阿里云:已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置,修改发送总量阈值。
  25 + ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流");
  26 +
  27 + ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词");
  28 +
  29 + // ========== 模板相关 2001000200 ==========
  30 + ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在
  31 + ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确");
  32 +
  33 + // ========== 签名相关 2001000300 ==========
  34 + ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用");
  35 +
  36 + // ========== 账户相关 2001000400 ==========
  37 + ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足");
  38 + ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在");
  39 +
  40 + // ========== 其它相关 2001000900 开头 ==========
  41 + ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失");
  42 + ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确");
  43 + ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中");
  44 +
  45 + ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常");
  46 +
  47 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailTemplateAuditStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 短信模板的审核状态枚举
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@AllArgsConstructor
  12 +@Getter
  13 +public enum MailTemplateAuditStatusEnum {
  14 +
  15 + CHECKING(1),
  16 + SUCCESS(2),
  17 + FAIL(3);
  18 +
  19 + private final Integer status;
  20 +
  21 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/property/MailChannelProperties.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mail.core.property;
  2 +
  3 +import lombok.Data;
  4 +import cn.iocoder.yudao.framework.mail.core.enums.MailChannelEnum;
  5 +import org.springframework.validation.annotation.Validated;
  6 +
  7 +import javax.validation.constraints.NotEmpty;
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +/**
  11 + * 短信渠道配置类
  12 + *
  13 + * @author zzf
  14 + * @date 2021/1/25 17:01
  15 + */
  16 +@Data
  17 +@Validated
  18 +public class MailChannelProperties {
  19 +
  20 + /**
  21 + * 渠道编号
  22 + */
  23 + @NotNull(message = "短信渠道 ID 不能为空")
  24 + private Long id;
  25 + /**
  26 + * 短信签名
  27 + */
  28 + @NotEmpty(message = "短信签名不能为空")
  29 + private String signature;
  30 + /**
  31 + * 渠道编码
  32 + *
  33 + * 枚举 {@link MailChannelEnum}
  34 + */
  35 + @NotEmpty(message = "渠道编码不能为空")
  36 + private String code;
  37 + /**
  38 + * 短信 API 的账号
  39 + */
  40 + @NotEmpty(message = "短信 API 的账号不能为空")
  41 + private String apiKey;
  42 + /**
  43 + * 短信 API 的秘钥
  44 + */
  45 + @NotEmpty(message = "短信 API 的秘钥不能为空")
  46 + private String apiSecret;
  47 + /**
  48 + * 短信发送回调 URL
  49 + */
  50 + private String callbackUrl;
  51 +
  52 +}
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.api.mail;
  2 +
  3 +public interface MailSendApi {
  4 +}
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.api.mail.dto;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.Email;
  8 +import javax.validation.constraints.NotNull;
  9 +import java.util.List;
  10 +
  11 +@ApiModel("管理后台 - 邮件发送 Req VO")
  12 +@Data
  13 +public class MailSendReqDTO { // TODO @wangjingqi:1), 不用空格;2)应该只要传递 templateCode、参数就好,title、from、content、附件应该都是参数里的
  14 +
  15 + @ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com")
  16 + @NotNull(message = "邮箱账号不能为空")
  17 + @Email(message = "邮箱账号格式错误")
  18 + private String from;
  19 +
  20 + @ApiModelProperty(value = "标题",example = "标题")
  21 + private String title;
  22 +
  23 + @ApiModelProperty(value = "内容",example = "内容")
  24 + private String content;
  25 +
  26 + @ApiModelProperty(value = "邮箱模版id",example = "1024")
  27 + @NotNull(message = "邮箱模版id不能为空")
  28 + private Integer templateId;
  29 +
  30 + @ApiModelProperty(value = "收件人",required = true,example = "yudaoyuanma@123.com")
  31 + @NotNull(message = "收件人不能为空")
  32 + private List<String> tos;
  33 +
  34 + @ApiModelProperty(value = "附件",example = "附件编码")
  35 + private List<String> fileIds;
  36 +
  37 +
  38 +}
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
... ... @@ -126,5 +126,6 @@ public interface ErrorCodeConstants {
126 126 // ========== 邮箱模版 1002020000 ==========
127 127 ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1002020000 , "邮箱模版不存在");
128 128 ErrorCode MAIL_TEMPLATE_EXISTS = new ErrorCode(1002020001, "邮箱模版存在");
  129 + ErrorCode MAIL_RELATE_TEMPLATE_EXISTS = new ErrorCode(1002020002, "存在关联邮箱模版");
129 130  
130 131 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/mail/MailSendStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.enums.mail;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 邮件的发送状态枚举
  8 + *
  9 + * @author wangjingyi
  10 + * @date 2022/4/10 13:39
  11 + */
  12 +@Getter
  13 +@AllArgsConstructor
  14 +public enum MailSendStatusEnum {
  15 +
  16 + INIT(0), // 初始化
  17 + SUCCESS(10), // 发送成功
  18 + FAILURE(20), // 发送失败
  19 + IGNORE(30), // 忽略,即不发送
  20 + ;
  21 +
  22 + private final int status;
  23 +
  24 +}
... ...
yudao-module-system/yudao-module-system-impl/pom.xml
... ... @@ -49,6 +49,10 @@
49 49 </dependency>
50 50 <dependency>
51 51 <groupId>cn.iocoder.boot</groupId>
  52 + <artifactId>yudao-spring-boot-starter-biz-mail</artifactId>
  53 + </dependency>
  54 + <dependency>
  55 + <groupId>cn.iocoder.boot</groupId>
52 56 <artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
53 57 </dependency>
54 58 <dependency>
... ... @@ -102,6 +106,7 @@
102 106 <artifactId>yudao-spring-boot-starter-excel</artifactId>
103 107 </dependency>
104 108  
  109 +
105 110 </dependencies>
106 111  
107 112 </project>
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.api.mail;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import org.springframework.validation.annotation.Validated;
  5 +
  6 +/**
  7 + * 邮件发送 API 接口
  8 + *
  9 + * @author wangjingyi
  10 + */
  11 +@Service
  12 +@Validated
  13 +public class MailSendApiImpl implements MailSendApi{
  14 +}
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountBaseVO.java
... ... @@ -4,28 +4,34 @@ import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.Data;
6 6  
  7 +import javax.validation.constraints.Email;
7 8 import javax.validation.constraints.NotNull;
8 9  
9 10 @ApiModel("管理后台 - 邮箱账号基类 Base VO")
10 11 @Data
11   -public class MailAccountBaseVO { // TODO @wangjingqi:1), 不用空格;2)from、username、password、host、sslEnable 都要参数校验,非空;3)username 要 Email 格式;port Integer;
  12 +public class MailAccountBaseVO {
12 13  
13   - @ApiModelProperty(value = "邮箱" , required = true , example = "yudaoyuanma@123.com")
  14 + @ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com")
  15 + @NotNull(message = "邮箱必填")
14 16 private String from;
15 17  
16   - @ApiModelProperty(value = "用户名" , required = true , example = "yudao")
  18 + @ApiModelProperty(value = "用户名",required = true,example = "yudao")
17 19 @NotNull(message = "用户名必填")
  20 + @Email(message = "必须是Email格式")
18 21 private String username;
19 22  
20   - @ApiModelProperty(value = "密码" , required = true , example = "123456")
  23 + @ApiModelProperty(value = "密码",required = true,example = "123456")
  24 + @NotNull(message = "密码必填")
21 25 private String password;
22 26  
23   - @ApiModelProperty(value = "网站" , required = true , example = "www.iocoder.cn")
  27 + @ApiModelProperty(value = "网站",required = true,example = "www.iocoder.cn")
  28 + @NotNull(message = "网站必填")
24 29 private String host;
25 30  
26   - @ApiModelProperty(value = "端口" , required = true , example = "80")
27   - private String port;
  31 + @ApiModelProperty(value = "端口",required = true,example = "80")
  32 + private Integer port;
28 33  
29   - @ApiModelProperty(value = "是否开启ssl" , required = true , example = "2")
  34 + @ApiModelProperty(value = "是否开启ssl",required = true,example = "2")
  35 + @NotNull(message = "是否开启ssl必填")
30 36 private Boolean sslEnable;
31 37 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogExcelVO.java
... ... @@ -6,6 +6,7 @@ import lombok.Data;
6 6 import org.springframework.format.annotation.DateTimeFormat;
7 7  
8 8 import java.sql.Timestamp;
  9 +import java.util.Date;
9 10  
10 11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
11 12  
... ... @@ -30,10 +31,10 @@ public class MailLogExcelVO {
30 31  
31 32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
32 33 @ExcelProperty(value = "发送时间" )
33   - private Timestamp sendTime;
  34 + private Date sendTime;
34 35  
35 36 @ExcelProperty(value = "发送状态")
36   - private Boolean sendStatus;
  37 + private Integer sendStatus;
37 38  
38 39 @ExcelProperty(value = "发送结果")
39 40 private String sendResult;
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogRespVO.java
... ... @@ -36,7 +36,7 @@ public class MailLogRespVO {
36 36 private Timestamp sendTime;
37 37  
38 38 @ApiModelProperty(value = "发送状态" , required = false , example = "1")
39   - private Boolean sendStatus;
  39 + private Integer sendStatus;
40 40  
41 41 @ApiModelProperty(value = "发送结果" , required = false , example = "yudaoyuanma@123.com")
42 42 private String sendResult;
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/send/MailReqVO.java
... ... @@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.Data;
6 6  
  7 +import javax.validation.constraints.Email;
7 8 import javax.validation.constraints.NotNull;
8 9 import java.util.List;
9 10  
... ... @@ -11,25 +12,26 @@ import java.util.List;
11 12 @Data
12 13 public class MailReqVO { // TODO @wangjingqi:1), 不用空格;2)应该只要传递 templateCode、参数就好,title、from、content、附件应该都是参数里的
13 14  
14   - @ApiModelProperty(value = "邮箱" , required = true , example = "yudaoyuanma@123.com")
  15 + @ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com")
15 16 @NotNull(message = "邮箱账号不能为空")
  17 + @Email(message = "邮箱账号格式错误")
16 18 private String from;
17 19  
18   - @ApiModelProperty(value = "标题" , example = "标题")
  20 + @ApiModelProperty(value = "标题",example = "标题")
19 21 private String title;
20 22  
21   - @ApiModelProperty(value = "内容" , example = "内容")
  23 + @ApiModelProperty(value = "内容",example = "内容")
22 24 private String content;
23 25  
24   - @ApiModelProperty(value = "邮箱模版id" , example = "1024")
  26 + @ApiModelProperty(value = "邮箱模版id",example = "1024")
25 27 @NotNull(message = "邮箱模版id不能为空")
26 28 private Integer templateId;
27 29  
28   - @ApiModelProperty(value = "收件人" , required = true , example = "yudaoyuanma@123.com")
  30 + @ApiModelProperty(value = "收件人",required = true,example = "yudaoyuanma@123.com")
29 31 @NotNull(message = "收件人不能为空")
30 32 private List<String> tos;
31 33  
32   - @ApiModelProperty(value = "附件" , example = "附件编码")
  34 + @ApiModelProperty(value = "附件",example = "附件编码")
33 35 private List<String> fileIds;
34 36  
35 37  
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateBaseVO.java
... ... @@ -4,15 +4,18 @@ import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.Data;
6 6  
  7 +import javax.validation.constraints.Email;
7 8 import javax.validation.constraints.NotNull;
8 9  
9 10 @ApiModel("管ç†åŽå° - 邮箱模版基类 Base VO")
10 11 @Data
11   -public class MailTemplateBaseVO { // TODO @wangjingqi:1)swagger 注解ä¸å®Œå–„ï¼›2)idã€nameã€codeã€usernameã€titleã€contentã€status æ˜¯ä¸æ˜¯è¦å‚数校验呀
  12 +public class MailTemplateBaseVO {
12 13 @ApiModelProperty("主键")
  14 + @NotNull(message = "主键ä¸èƒ½ä¸ºç©º")
13 15 private Long id;
14 16  
15 17 @ApiModelProperty("åç§°")
  18 + @NotNull(message = "åç§°ä¸èƒ½ä¸ºç©º")
16 19 private String name;
17 20  
18 21 @ApiModelProperty("标识")
... ... @@ -20,16 +23,21 @@ public class MailTemplateBaseVO { // TODO @wangjingqi:1)swagger 注解ä¸å®
20 23 private String code;
21 24  
22 25 @ApiModelProperty("å‘件人")
  26 + @NotNull(message = "å‘件人ä¸èƒ½ä¸ºç©º")
  27 + @Email(message = "å‘ä»¶äººæ ¼å¼æœ‰è¯¯")
23 28 private String username;
24 29  
25 30 @ApiModelProperty("标题")
  31 + @NotNull(message = "标题ä¸èƒ½ä¸ºç©º")
26 32 private String title;
27 33  
28 34 @ApiModelProperty("内容")
  35 + @NotNull(message = "内容ä¸èƒ½ä¸ºç©º")
29 36 private String content;
30 37  
31 38 @ApiModelProperty("状æ€")
32   - private String status;
  39 + @NotNull(message = "状æ€ä¸èƒ½ä¸ºç©º")
  40 + private Integer status;
33 41  
34 42 @ApiModelProperty("备注")
35 43 private String remark;
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java
... ... @@ -31,7 +31,7 @@ public class MailTemplatePageReqVO extends PageParam {
31 31 private String content;
32 32  
33 33 @ApiModelProperty("状态")
34   - private String status;
  34 + private Integer status;
35 35  
36 36 @ApiModelProperty("备注")
37 37 private String remark;
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java
1 1 package cn.iocoder.yudao.module.system.dal.dataobject.mail;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
4 5 import com.baomidou.mybatisplus.annotation.TableName;
5   -import lombok.Data;
6   -import lombok.EqualsAndHashCode;
  6 +import lombok.*;
7 7  
8 8 import java.io.Serializable;
9   -import java.sql.Timestamp;
  9 +import java.util.Date;
10 10  
11 11 /**
12 12 * 邮箱日志
... ... @@ -18,6 +18,10 @@ import java.sql.Timestamp;
18 18 @TableName(value = "system_mail_log", autoResultMap = true)
19 19 @Data
20 20 @EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +@Builder
  23 +@AllArgsConstructor
  24 +@NoArgsConstructor
21 25 public class MailLogDO extends BaseDO implements Serializable {
22 26  
23 27 /**
... ... @@ -29,7 +33,7 @@ public class MailLogDO extends BaseDO implements Serializable {
29 33 /**
30 34 * 邮箱账号编号
31 35 */
32   - private String accountCode;
  36 + private Long accountId;
33 37  
34 38 // TODO @wangjingyi:如果是冗余字段,记得 @ 下;
35 39 /**
... ... @@ -40,7 +44,7 @@ public class MailLogDO extends BaseDO implements Serializable {
40 44 /**
41 45 * 模版主键
42 46 */
43   - private String templateId;
  47 + private Long templateId;
44 48  
45 49 /**
46 50 * 模版编号
... ... @@ -65,16 +69,18 @@ public class MailLogDO extends BaseDO implements Serializable {
65 69 /**
66 70 * 发送时间
67 71 */
68   - private Timestamp sendTime;
  72 + private Date sendTime;
69 73  
70 74 /**
71 75 * 发送状态
  76 + *
  77 + * 枚举 {@link MailSendStatusEnum}
72 78 */
73   - // TODO @wangjingyi:四个状态,参考短信模块
74   - private Boolean sendStatus;
  79 + private Integer sendStatus;
75 80  
76 81 /**
77 82 * 发送结果
  83 + *
78 84 */
79 85 private String sendResult;
80 86  
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java
... ... @@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
6 6 import lombok.Data;
7 7 import lombok.EqualsAndHashCode;
8 8  
  9 +import java.util.Date;
  10 +
9 11 /**
10 12 * 邮箱模版
11 13 *
... ... @@ -29,11 +31,10 @@ public class MailTemplateDO extends BaseDO {
29 31 * 模版编号
30 32 */
31 33 private String code;
32   - // TODO @wangjingyi:应该使用 accountId 呀
33 34 /**
34   - * 用户名
  35 + * 邮箱账号主键
35 36 */
36   - private String username;
  37 + private Long accountId;
37 38 /**
38 39 * 标题
39 40 */
... ... @@ -47,7 +48,7 @@ public class MailTemplateDO extends BaseDO {
47 48 *
48 49 * 枚举 {@link CommonStatusEnum}
49 50 */
50   - private String status; // TODO @wangjingyi:Integer
  51 + private Integer status;
51 52 /**
52 53 * 备注
53 54 */
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
6 6 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
7 7 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
  8 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
8 9 import org.apache.ibatis.annotations.Mapper;
9 10  
10 11 @Mapper
... ... @@ -21,9 +22,7 @@ public interface MailAccountMapper extends BaseMapperX&lt;MailAccountDO&gt; {
21 22 }
22 23  
23 24 default MailAccountDO selectByUserName(String userName){
24   - // TODO @wangjingyi:selectOne 有封装的方法;然后,编码一定要学会使用泛型呀。例如说 QueryWrapperX<MailAccountDO> queryWrapperX = new QueryWrapperX<>();
25   - QueryWrapperX<MailAccountDO> queryWrapperX = new QueryWrapperX<>();
26   - queryWrapperX.eqIfPresent("username", userName);
27   - return this.selectOne(queryWrapperX);
  25 + return selectOne(new QueryWrapperX<MailAccountDO>()
  26 + .eqIfPresent("username" , userName));
28 27 };
29 28 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java
... ... @@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
6 6 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
7 7 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
8 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Select;
  10 +
  11 +import java.util.Date;
9 12  
10 13  
11 14 @Mapper
... ... @@ -23,7 +26,15 @@ public interface MailTemplateMapper extends BaseMapperX&lt;MailTemplateDO&gt; {
23 26 }
24 27  
25 28 default MailTemplateDO selectOneByCode(String code){
26   - // TODO @wangjingyi:优先使用 lambada 查询
27   - return selectOne("code" , code);
  29 + return selectOne(new QueryWrapperX<MailTemplateDO>()
  30 + .eqIfPresent("code" , code));
  31 + };
  32 +
  33 + @Select("SELECT id FROM system_mail_template WHERE update_time > #{maxUpdateTime} LIMIT 1")
  34 + Long selectByMaxUpdateTime(Date maxUpdateTime);
  35 +
  36 + default MailTemplateDO selectOneByAccountId(Long accountId){
  37 + return selectOne(new QueryWrapperX<MailTemplateDO>()
  38 + .eqIfPresent("account_id" , accountId));
28 39 };
29 40 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java
... ... @@ -2,17 +2,23 @@ package cn.iocoder.yudao.module.system.mq.consumer.mail;
2 2  
3 3 import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
4 4 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
  5 +import cn.iocoder.yudao.module.system.service.mail.MailSendService;
5 6 import lombok.extern.slf4j.Slf4j;
6 7 import org.springframework.stereotype.Component;
7 8  
8   -// TODO 芋艿:这个暂未实现
  9 +import javax.annotation.Resource;
  10 +
  11 +
9 12 @Component
10 13 @Slf4j
11 14 public class MailSendConsumer extends AbstractStreamMessageListener<MailSendMessage> {
12 15  
  16 + @Resource
  17 + private MailSendService mailSendService;
13 18 @Override
14 19 public void onMessage(MailSendMessage message) {
15 20 log.info("[onMessage][消息内容({})]", message);
  21 + mailSendService.doSendMail(message);
16 22 }
17 23  
18 24 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java
... ... @@ -5,6 +5,7 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6  
7 7 import javax.validation.constraints.NotNull;
  8 +import java.util.List;
8 9 import java.util.Map;
9 10  
10 11 /**
... ... @@ -17,28 +18,33 @@ import java.util.Map;
17 18 public class MailSendMessage extends AbstractStreamMessage {
18 19  
19 20 /**
  21 + * 日志id
  22 + */
  23 + @NotNull(message = "邮箱日志id不能为空")
  24 + private Long logId;
  25 + /**
20 26 * 邮箱地址
21 27 */
22 28 @NotNull(message = "邮箱地址不能为空")
23   - private String address;
  29 + private String from;
24 30 /**
25   - * 短信模板编号
  31 + * 邮箱模板编号
26 32 */
27   - @NotNull(message = "短信模板编号不能为空")
  33 + @NotNull(message = "邮箱模板编号不能为空")
28 34 private String templateCode;
29 35 /**
30   - * 短信模板参数
  36 + * 收件人
31 37 */
32   - private Map<String, Object> templateParams;
33   -
  38 + @NotNull(message = "收件人不能为空")
  39 + private List<String> tos;
34 40 /**
35   - * 用户编号,允许空
  41 + * 标题
36 42 */
37   - private Integer userId;
  43 + private String title;
38 44 /**
39   - * 用户类型,允许空
  45 + * 内容
40 46 */
41   - private Integer userType;
  47 + private String content;
42 48  
43 49 @Override
44 50 public String getStreamKey() {
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.mq.producer.mail;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.KeyValue;
  4 +import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
  6 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
  7 +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
  8 +import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage;
  9 +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
  10 +import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import javax.annotation.Resource;
  15 +import java.util.List;
  16 +
  17 +/**
  18 + * Mail 邮件相关消息的 Producer
  19 + *
  20 + * @author wangjingyi
  21 + * @date 2021/4/19 13:33
  22 + */
  23 +@Slf4j
  24 +@Component
  25 +public class MailProducer {
  26 +
  27 + @Resource
  28 + private RedisMQTemplate redisMQTemplate;
  29 +
  30 + /**
  31 + * 发送 {@link SmsChannelRefreshMessage} 消息
  32 + */
  33 + public void sendMailChannelRefreshMessage() {
  34 + SmsChannelRefreshMessage message = new SmsChannelRefreshMessage();
  35 + redisMQTemplate.send(message);
  36 + }
  37 +
  38 + /**
  39 + * 发送 {@link SmsTemplateRefreshMessage} 消息
  40 + */
  41 + public void sendMailTemplateRefreshMessage() {
  42 + SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage();
  43 + redisMQTemplate.send(message);
  44 + }
  45 +
  46 + /**
  47 + * 发送 {@link MailSendMessage} 消息
  48 + *
  49 + * @param mailAccountDO 邮箱账号信息
  50 + * @param mailTemplateDO 邮箱模版信息
  51 + * @param content 内容
  52 + * @param tos 收件人
  53 + * @param title 标题
  54 + */
  55 + public void sendMailSendMessage(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String content, List<String> tos, String title , Long sendLogId) {
  56 + MailSendMessage message = new MailSendMessage();
  57 + message.setContent(content);
  58 + message.setFrom(mailAccountDO.getFrom());
  59 + message.setTemplateCode(mailTemplateDO.getCode());
  60 + message.setTitle(title);
  61 + message.setTos(tos);
  62 + message.setLogId(sendLogId);
  63 + redisMQTemplate.send(message);
  64 + }
  65 +}
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java
... ... @@ -4,7 +4,9 @@ package cn.iocoder.yudao.module.system.service.mail;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO;
6 6 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
  7 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
7 8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
  9 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
8 10  
9 11 import java.util.List;
10 12  
... ... @@ -28,4 +30,18 @@ public interface MailLogService {
28 30 * @return
29 31 */
30 32 List<MailLogDO> getMailLogList(MailLogExportReqVO exportReqVO);
  33 +
  34 + /**
  35 + * 创建邮箱日志
  36 + * @param mailAccountDO 邮箱账号信息
  37 + * @param mailTemplateDO 模版信息
  38 + * @param from 邮箱
  39 + * @param content 内容
  40 + * @param tos 收件人
  41 + * @param title 标题
  42 + * @param isSend 是否发送成功
  43 + */
  44 + Long createMailLog(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String from, String content, List<String> tos, String title, Boolean isSend);
  45 +
  46 + Long updateSmsSendResult(Long logId, String result);
31 47 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.mail;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.send.MailReqVO;
  5 +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateCreateReqVO;
  6 +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
  7 +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateUpdateReqVO;
  8 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
  9 +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
  10 +
  11 +import javax.validation.Valid;
  12 +import java.util.List;
  13 +import java.util.Map;
  14 +
  15 +/**
  16 + * 邮箱模版服务类
  17 + *
  18 + * @author wangjingyi
  19 + * @since 2022-03-21
  20 + */
  21 +public interface MailSendService {
  22 +
  23 + /**
  24 + * 发送邮件
  25 + *
  26 + * @param templateCode 邮件模版编码
  27 + * @param from 邮箱
  28 + * @param content 内容
  29 + * @param tos 收件人
  30 + * @param title 标题
  31 + */
  32 + void sendMail(String templateCode, String from , String content , List<String> tos , String title);
  33 +
  34 + /**
  35 + * 执行真正的邮件发送
  36 + * 注意,该方法仅仅提供给 MQ Consumer 使用
  37 + *
  38 + * @param message 邮件
  39 + */
  40 + void doSendMail(MailSendMessage message);
  41 +}
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java
... ... @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
9 9  
10 10 import javax.validation.Valid;
11 11 import java.util.List;
  12 +import java.util.Map;
12 13  
13 14 /**
14 15 * 邮箱模版服务类
... ... @@ -18,6 +19,7 @@ import java.util.List;
18 19 */
19 20 public interface MailTemplateService {
20 21  
  22 + void initLocalCache();
21 23 /**
22 24 * 邮箱模版创建
23 25 *
... ... @@ -62,6 +64,13 @@ public interface MailTemplateService {
62 64 * @return 模版数组
63 65 */
64 66 List<MailTemplateDO> getMailTemplateList();
  67 + /**
  68 + *从缓存中获取邮箱模版
  69 + *
  70 + * @param code 模板编码
  71 + * @return 邮箱模板
  72 + */
  73 + MailTemplateDO getMailTemplateByCodeFromCache(String code);
65 74  
66 75 /**
67 76 * 发送邮件
... ... @@ -69,4 +78,12 @@ public interface MailTemplateService {
69 78 * @param mailReqVO 邮件发送信息
70 79 */
71 80 void sendMail(MailReqVO mailReqVO);
  81 +
  82 + /**
  83 + * 邮件模版内容合成
  84 + * @param content 邮箱模版
  85 + * @param params 合成参数
  86 + * @return
  87 + */
  88 + String formateMailTemplateContent(String content, Map<String, String> params);
72 89 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccou
6 6 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO;
7 7 import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
8 8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
  9 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
9 10 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
10 11 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
11 12 import cn.iocoder.yudao.module.system.service.mail.MailAccountService;
... ... @@ -16,8 +17,7 @@ import javax.annotation.Resource;
16 17 import java.util.List;
17 18  
18 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_EXISTS;
20   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS;
  20 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
21 21  
22 22  
23 23 /**
... ... @@ -47,8 +47,8 @@ public class MailAccountServiceImpl implements MailAccountService {
47 47  
48 48 @Override
49 49 public void update(MailAccountUpdateReqVO updateReqVO) {
50   - // username 要校验唯一 // TODO @wangjingyi:更新的就是自己,username 这样写,会重复呀。
51   - this.validateMailAccountOnlyByUserName(updateReqVO.getUsername());
  50 + // username 要校验唯一
  51 + this.validateMailAccountExists(updateReqVO.getId());
52 52 MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(updateReqVO);
53 53 // 校验是否存在
54 54 this.validateMailAccountExists(mailAccountDO.getId());
... ... @@ -57,9 +57,10 @@ public class MailAccountServiceImpl implements MailAccountService {
57 57  
58 58 @Override
59 59 public void delete(Long id) {
60   - // TODO @wangjingyi:删除时,要判断是否有使用的模板
61   - // 校验是否存在
  60 + // 校验是否存在账号
62 61 this.validateMailAccountExists(id);
  62 + // 校验是否存在关联模版
  63 + this.validateMailTemplateByAccountId(id);
63 64 mailAccountMapper.deleteById(id);
64 65 }
65 66  
... ... @@ -90,4 +91,11 @@ public class MailAccountServiceImpl implements MailAccountService {
90 91 throw exception(MAIL_ACCOUNT_EXISTS);
91 92 }
92 93 }
  94 +
  95 + private void validateMailTemplateByAccountId(Long accountId){
  96 + MailTemplateDO mailTemplateDO = mailTemplateMapper.selectOneByAccountId(accountId);
  97 + if (mailTemplateDO != null) {
  98 + throw exception(MAIL_RELATE_TEMPLATE_EXISTS);
  99 + }
  100 + }
93 101 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java
... ... @@ -4,14 +4,21 @@ package cn.iocoder.yudao.module.system.service.mail.impl;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO;
6 6 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
  7 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
7 8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
  9 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
8 10 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper;
  11 +import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
  12 +import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
9 13 import cn.iocoder.yudao.module.system.service.mail.MailLogService;
10 14 import org.springframework.beans.factory.annotation.Autowired;
11 15 import org.springframework.stereotype.Service;
12 16 import org.springframework.validation.annotation.Validated;
13 17  
  18 +import java.sql.Timestamp;
  19 +import java.util.Date;
14 20 import java.util.List;
  21 +import java.util.Objects;
15 22  
16 23 /**
17 24 * 邮箱日志实现类
... ... @@ -35,4 +42,39 @@ public class MailLogServiceImpl implements MailLogService {
35 42 public List<MailLogDO> getMailLogList(MailLogExportReqVO exportReqVO) {
36 43 return mailLogMapper.selectList(exportReqVO);
37 44 }
  45 +
  46 + @Override
  47 + public Long createMailLog(MailAccountDO mailAccountDO , MailTemplateDO mailTemplateDO , String from, String content, List<String> tos, String title, Boolean isSend) {
  48 + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
  49 + logDOBuilder.from(mailAccountDO.getFrom());
  50 + logDOBuilder.accountId(mailAccountDO.getId());
  51 + logDOBuilder.content(content);
  52 + logDOBuilder.title(title);
  53 + logDOBuilder.templateCode(mailTemplateDO.getCode());
  54 + logDOBuilder.templateId(mailTemplateDO.getId());
  55 + logDOBuilder.to(tos.toString());
  56 + logDOBuilder.sendTime(new Date());
  57 + logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
  58 + : MailSendStatusEnum.IGNORE.getStatus());
  59 +
  60 + MailLogDO mailLogDO = logDOBuilder.build();
  61 + mailLogMapper.insert(mailLogDO);
  62 + return mailLogDO.getId();
  63 + }
  64 +
  65 + @Override
  66 + public Long updateSmsSendResult(Long logId, String result) {
  67 + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
  68 + logDOBuilder.id(logId);
  69 + logDOBuilder.sendResult(result);
  70 + MailLogDO mailLogDO = logDOBuilder.build();
  71 + mailLogMapper.updateById(mailLogDO);
  72 + return logId;
  73 + }
  74 +
  75 + public Long create(){
  76 + MailLogDO mailLogDO = new MailLogDO();
  77 + mailLogMapper.insert(mailLogDO);
  78 + return mailLogDO.getId();
  79 + }
38 80 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.mail.impl;
  2 +
  3 +
  4 +import cn.hutool.extra.mail.MailAccount;
  5 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  6 +import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
  7 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
  8 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
  9 +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
  10 +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
  11 +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
  12 +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
  13 +import cn.iocoder.yudao.module.system.service.mail.MailLogService;
  14 +import cn.iocoder.yudao.module.system.service.mail.MailSendService;
  15 +import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
  16 +import lombok.extern.slf4j.Slf4j;
  17 +import cn.iocoder.yudao.framework.mail.core.client.MailClientFactory;
  18 +import org.springframework.stereotype.Service;
  19 +import org.springframework.validation.annotation.Validated;
  20 +import cn.iocoder.yudao.framework.mail.core.client.MailClient;
  21 +
  22 +import javax.annotation.Resource;
  23 +import java.util.List;
  24 +import java.util.Map;
  25 +
  26 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  27 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_EXISTS;
  28 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS;
  29 +
  30 +/**
  31 + * 邮箱模版 服务实现类
  32 + *
  33 + * @author wangjingyi
  34 + * @since 2022-03-21
  35 + */
  36 +@Service
  37 +@Validated
  38 +@Slf4j
  39 +public class MailSendServiceImpl implements MailSendService {
  40 +
  41 + @Resource
  42 + private MailTemplateMapper mailTemplateMapper;
  43 + @Resource
  44 + private MailAccountMapper mailAccountMapper;
  45 + @Resource
  46 + private MailTemplateService mailTemplateService;
  47 + @Resource
  48 + private MailLogService mailLogService;
  49 + @Resource
  50 + private MailClientFactory mailClientFactory;
  51 + @Resource
  52 + private MailProducer mailProducer;
  53 +
  54 +
  55 + @Override
  56 + public void sendMail(String templateCode, String from , String content , List<String> tos , String title) {
  57 + // TODO @@wangjingyi:发送的时候,参考下短信;
  58 + MailTemplateDO mailTemplateDO = this.checkMailTemplateValid(templateCode);
  59 + // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
  60 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus());
  61 + //查询账号信息
  62 + MailAccountDO mailAccountDO = mailAccountMapper.selectOne(
  63 + "from", from
  64 + );
  65 + Map<String , String> params = MailAccountConvert.INSTANCE.convertToMap(mailAccountDO , content);
  66 + content = mailTemplateService.formateMailTemplateContent(mailTemplateDO.getContent(), params);
  67 + Long sendLogId = mailLogService.createMailLog(mailAccountDO , mailTemplateDO , from , content , tos , title , isSend);
  68 +
  69 + // 后续功能 TODO :附件查询
  70 + //List<String> fileIds = mailSendVO.getFileIds();
  71 +
  72 + //装载账号信息
  73 + MailAccount account = MailAccountConvert.INSTANCE.convertAccount(mailAccountDO);
  74 +
  75 + // 发送 MQ 消息,异步执行发送短信
  76 + if (isSend) {
  77 + mailProducer.sendMailSendMessage(mailAccountDO , mailTemplateDO ,content , tos , title , sendLogId);
  78 + }
  79 + }
  80 +
  81 + @Override
  82 + public void doSendMail(MailSendMessage message) {
  83 + MailClient mailClient = mailClientFactory.getMailClient();
  84 + String result = mailClient.sendMail(message.getFrom() , message.getContent() , message.getTitle() , message.getTos());
  85 + mailLogService.updateSmsSendResult(message.getLogId() , result);
  86 + }
  87 +
  88 + private MailTemplateDO checkMailTemplateValid(String templateCode) {
  89 + MailTemplateDO mailTemplateDO = mailTemplateService.getMailTemplateByCodeFromCache(templateCode);
  90 + if (mailTemplateDO == null){
  91 + throw exception(MAIL_TEMPLATE_NOT_EXISTS);
  92 + }
  93 + return mailTemplateDO;
  94 + }
  95 +
  96 + private void validateMailTemplateExists(Long id) {
  97 + if (mailTemplateMapper.selectById(id) == null) {
  98 + throw exception(MAIL_TEMPLATE_NOT_EXISTS);
  99 + }
  100 + }
  101 +
  102 + private void validateMailTemplateOnlyByCode(String code){
  103 + if (mailTemplateMapper.selectOneByCode(code) != null) {
  104 + throw exception(MAIL_TEMPLATE_EXISTS);
  105 + }
  106 + }
  107 +}
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java
1 1 package cn.iocoder.yudao.module.system.service.mail.impl;
2 2  
3 3  
  4 +import cn.hutool.core.collection.CollUtil;
4 5 import cn.hutool.core.util.StrUtil;
5 6 import cn.hutool.extra.mail.MailAccount;
6 7 import cn.hutool.extra.mail.MailUtil;
7 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 10 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.send.MailReqVO;
9 11 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateCreateReqVO;
10 12 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
... ... @@ -13,14 +15,18 @@ import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
13 15 import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert;
14 16 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
15 17 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
  18 +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
16 19 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
17 20 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
18 21 import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
  22 +import lombok.extern.slf4j.Slf4j;
19 23 import org.springframework.stereotype.Service;
20 24 import org.springframework.validation.annotation.Validated;
21 25  
  26 +import javax.annotation.PostConstruct;
22 27 import javax.annotation.Resource;
23 28 import javax.validation.Valid;
  29 +import java.util.Date;
24 30 import java.util.List;
25 31 import java.util.Map;
26 32  
... ... @@ -36,6 +42,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPL
36 42 */
37 43 @Service
38 44 @Validated
  45 +@Slf4j
39 46 public class MailTemplateServiceImpl implements MailTemplateService {
40 47  
41 48 @Resource
... ... @@ -43,6 +50,38 @@ public class MailTemplateServiceImpl implements MailTemplateService {
43 50 @Resource
44 51 private MailAccountMapper mailAccountMapper;
45 52  
  53 + private volatile List<MailTemplateDO> mailTemplateDOList;
  54 +
  55 + /**
  56 + * 邮件模板缓存
  57 + * key:邮箱模板编码 {@link MailTemplateDO#getCode()}
  58 + *
  59 + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
  60 + */
  61 + private volatile Map<String, MailTemplateDO> mailTemplateCache;
  62 +
  63 + private volatile Date maxUpdateTime;
  64 +
  65 + @Override
  66 + @PostConstruct
  67 + public void initLocalCache() {
  68 + if(maxUpdateTime == null){
  69 + mailTemplateDOList = mailTemplateMapper.selectList();
  70 + }else{
  71 + if(mailTemplateMapper.selectByMaxUpdateTime(maxUpdateTime)<=0){
  72 + return;
  73 + }
  74 + }
  75 + if (CollUtil.isEmpty(mailTemplateDOList)) {
  76 + return;
  77 + }
  78 +
  79 + // 写入缓存
  80 + mailTemplateCache = CollectionUtils.convertMap(mailTemplateDOList, MailTemplateDO::getCode);
  81 + maxUpdateTime = CollectionUtils.getMaxValue(mailTemplateDOList, MailTemplateDO::getUpdateTime);
  82 + log.info("[initLocalCache][初始化 mailTemplate 数量为 {}]", mailTemplateDOList.size());
  83 + }
  84 +
46 85 @Override
47 86 public Long create(MailTemplateCreateReqVO createReqVO) {
48 87 // code 要校验唯一
... ... @@ -54,11 +93,9 @@ public class MailTemplateServiceImpl implements MailTemplateService {
54 93  
55 94 @Override
56 95 public void update(@Valid MailTemplateUpdateReqVO updateReqVO) {
57   - // code 要校验唯一
58   - this.validateMailTemplateOnlyByCode(updateReqVO.getCode()); // TODO @wangjingyi:code 这样写,修改自己会有问题
59   - MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO);
60 96 // 校验是否存在
61   - this.validateMailTemplateExists(mailTemplateDO.getId());
  97 + this.validateMailTemplateExists(updateReqVO.getId());
  98 + MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO);
62 99 mailTemplateMapper.updateById(mailTemplateDO);
63 100 }
64 101  
... ... @@ -81,6 +118,11 @@ public class MailTemplateServiceImpl implements MailTemplateService {
81 118 public List<MailTemplateDO> getMailTemplateList() {return mailTemplateMapper.selectList();}
82 119  
83 120 @Override
  121 + public MailTemplateDO getMailTemplateByCodeFromCache(String code) {
  122 + return mailTemplateCache.get(code);
  123 + }
  124 +
  125 + @Override
84 126 public void sendMail(MailReqVO mailReqVO) {
85 127 // TODO @@wangjingyi:发送的时候,参考下短信;
86 128 MailTemplateDO mailTemplateDO = mailTemplateMapper.selectById(mailReqVO.getTemplateId());
... ... @@ -102,6 +144,11 @@ public class MailTemplateServiceImpl implements MailTemplateService {
102 144 MailUtil.send(account , mailReqVO.getTos() , mailReqVO.getTitle() , content , false);
103 145 }
104 146  
  147 + @Override
  148 + public String formateMailTemplateContent(String content, Map<String, String> params) {
  149 + return StrUtil.format(content, params);
  150 + }
  151 +
105 152 private void validateMailTemplateExists(Long id) {
106 153 if (mailTemplateMapper.selectById(id) == null) {
107 154 throw exception(MAIL_TEMPLATE_NOT_EXISTS);
... ...