diff --git a/yudao-framework/pom.xml b/yudao-framework/pom.xml index 73bb614cd..42c887c56 100644 --- a/yudao-framework/pom.xml +++ b/yudao-framework/pom.xml @@ -30,6 +30,7 @@ yudao-spring-boot-starter-biz-operatelog yudao-spring-boot-starter-biz-dict yudao-spring-boot-starter-biz-sms + yudao-spring-boot-starter-biz-mail yudao-spring-boot-starter-activiti yudao-spring-boot-starter-biz-pay yudao-spring-boot-starter-biz-weixin diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/pom.xml b/yudao-framework/yudao-spring-boot-starter-biz-mail/pom.xml new file mode 100644 index 000000000..8cca21778 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/pom.xml @@ -0,0 +1,65 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-biz-mail + jar + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter + + + + + io.opentracing + opentracing-util + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + + com.google.guava + guava + true + + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-core + + + + jakarta.validation + jakarta.validation-api + + + org.projectlombok + lombok + + + + \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/config/YudaoMailAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/config/YudaoMailAutoConfiguration.java new file mode 100644 index 000000000..c83b1e5f1 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/config/YudaoMailAutoConfiguration.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.mail.config; + +import cn.iocoder.yudao.framework.mail.core.client.MailClientFactory; +import cn.iocoder.yudao.framework.mail.core.client.impl.MailClientFactoryImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 邮箱配置类 + * + * @author 芋道源码 + */ +@Configuration +public class YudaoMailAutoConfiguration { + + @Bean + public MailClientFactory mailClientFactory() { + return new MailClientFactoryImpl(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClient.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClient.java new file mode 100644 index 000000000..a17260410 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClient.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.framework.mail.core.client; + +import java.util.List; + +/** + * 邮件客户端,用于对接各邮箱平台的 SDK,实现邮件发送等功能 + * + * @author wangjingyi + * @date 2021/4/19 19:21 + */ +public interface MailClient { + + /** + * 发送邮件 + * + * @param from 邮箱账号 + * @param content 内容 + * @param title 标题 + * @param tos 收件人 + * @return 邮件发送结果 + */ + String sendMail(String from, String content, String title, List tos); +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClientFactory.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClientFactory.java new file mode 100644 index 000000000..3244dfe76 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailClientFactory.java @@ -0,0 +1,5 @@ +package cn.iocoder.yudao.framework.mail.core.client; + +public interface MailClientFactory { + MailClient getMailClient(); +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCodeMapping.java new file mode 100644 index 000000000..c33b4be3e --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCodeMapping.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.framework.mail.core.client; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.mail.core.enums.MailFrameworkErrorCodeConstants; + +import java.util.function.Function; + +/** + * 将 API 的错误码,转换为通用的错误码 + * + * @see MailCommonResult + * @see MailFrameworkErrorCodeConstants + * + * @author 芋道源码 + */ +public interface MailCodeMapping extends Function { +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCommonResult.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCommonResult.java new file mode 100644 index 000000000..a53a3b989 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/MailCommonResult.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.framework.mail.core.client; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import cn.iocoder.yudao.framework.mail.core.enums.MailFrameworkErrorCodeConstants; + +/** + * 短信的 CommonResult 拓展类 + * + * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段 + * + * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段 + * + * @author 芋道源码 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MailCommonResult extends CommonResult { + + /** + * API 返回错误码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiCode; + /** + * API 返回提示 + */ + private String apiMsg; + + /** + * API 请求编号 + */ + private String apiRequestId; + + private MailCommonResult() { + } + + public static MailCommonResult build(String apiCode, String apiMsg, String apiRequestId, + T data, MailCodeMapping codeMapping) { + Assert.notNull(codeMapping, "参数 codeMapping 不能为空"); + MailCommonResult result = new MailCommonResult().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId); + result.setData(data); + // 翻译错误码 + if (codeMapping != null) { + ErrorCode errorCode = codeMapping.apply(apiCode); + if (errorCode == null) { + errorCode = MailFrameworkErrorCodeConstants.MAIL_UNKNOWN; + } + result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg()); + } + return result; + } + + public static MailCommonResult error(Throwable ex) { + MailCommonResult result = new MailCommonResult<>(); + result.setCode(MailFrameworkErrorCodeConstants.EXCEPTION.getCode()); + result.setMsg(ExceptionUtil.getRootCauseMessage(ex)); + return result; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailReceiveRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailReceiveRespDTO.java new file mode 100644 index 000000000..11f27f58a --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailReceiveRespDTO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.framework.mail.core.client.dto; + +import lombok.Data; + +import java.util.Date; + +/** + * 消息接收 Response DTO + * + * @author 芋道源码 + */ +@Data +public class MailReceiveRespDTO { + + /** + * 是否接收成功 + */ + private Boolean success; + /** + * API 接收结果的编码 + */ + private String errorCode; + /** + * API 接收结果的说明 + */ + private String errorMsg; + + /** + * 手机号 + */ + private String mobile; + /** + * 用户接收时间 + */ + private Date receiveTime; + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + /** + * 短信日志编号 + * + * 对应 SysSmsLogDO 的编号 + */ + private Long logId; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailSendRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailSendRespDTO.java new file mode 100644 index 000000000..b4a94a634 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailSendRespDTO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.mail.core.client.dto; + +import lombok.Data; + +/** + * 短信发送 Response DTO + * + * @author 芋道源码 + */ +@Data +public class MailSendRespDTO { + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailTemplateRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailTemplateRespDTO.java new file mode 100644 index 000000000..14bdeacd8 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/dto/MailTemplateRespDTO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.mail.core.client.dto; + +import lombok.Data; + +/** + * 短信模板 Response DTO + * + * @author 芋道源码 + */ +@Data +public class MailTemplateRespDTO { + + /** + * 模板编号 + */ + private String id; + /** + * 短信内容 + */ + private String content; + /** + * 审核状态 + * + */ + private Integer auditStatus; + /** + * 审核未通过的理由 + */ + private String auditReason; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/AbstractMailClient.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/AbstractMailClient.java new file mode 100644 index 000000000..097c8e095 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/AbstractMailClient.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.framework.mail.core.client.impl; + +import lombok.extern.slf4j.Slf4j; +import cn.iocoder.yudao.framework.mail.core.client.MailClient; + +/** + * 短信客户端的抽象类,提供模板方法,减少子类的冗余代码 + * + * @author zzf + * @date 2021/2/1 9:28 + */ +@Slf4j +public abstract class AbstractMailClient implements MailClient { +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/MailClientFactoryImpl.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/MailClientFactoryImpl.java new file mode 100644 index 000000000..9923bd3df --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/MailClientFactoryImpl.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.framework.mail.core.client.impl; + +import cn.iocoder.yudao.framework.mail.core.client.MailClient; +import cn.iocoder.yudao.framework.mail.core.client.impl.hutool.HutoolMailClient; +import lombok.extern.slf4j.Slf4j; +import cn.iocoder.yudao.framework.mail.core.client.MailClientFactory; +import cn.iocoder.yudao.framework.mail.core.enums.MailChannelEnum; +import org.springframework.validation.annotation.Validated; + +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +@Validated +@Slf4j +public class MailClientFactoryImpl implements MailClientFactory { + + private final ConcurrentMap channelCodeClients = new ConcurrentHashMap<>(); + + public MailClientFactoryImpl (){ + Arrays.stream(MailChannelEnum.values()).forEach(mailChannelEnum -> { + AbstractMailClient abstractMailClient = createMailClient(mailChannelEnum); + channelCodeClients.put(mailChannelEnum.getCode() , abstractMailClient); + }); + } + + private AbstractMailClient createMailClient(MailChannelEnum mailChannelEnum) { + switch (mailChannelEnum){ + case HUTOOL: return new HutoolMailClient(); + } + // 创建失败,错误日志 + 抛出异常 + log.error("[createMailClient][配置({}) 找不到合适的客户端实现]" , mailChannelEnum); + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", mailChannelEnum)); + } + + @Override + public MailClient getMailClient() { + return channelCodeClients.get("HUTOOL"); + } +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailClient.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailClient.java new file mode 100644 index 000000000..457ad7e37 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailClient.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.framework.mail.core.client.impl.hutool; + +import cn.hutool.extra.mail.MailUtil; +import cn.iocoder.yudao.framework.mail.core.client.impl.AbstractMailClient; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + + +/** + * 邮件客户端实现 + * + * @author wangjingyi + * @date 2021/4/25 14:25 + */ +@Slf4j +public class HutoolMailClient extends AbstractMailClient { + + @Override + public String sendMail(String from, String content, String title, List tos) { + try{ + return MailUtil.send(from , title , content , false , null); + }catch (Exception e){ + log.error(e.getMessage()); + } + return ""; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailCodeMapping.java new file mode 100644 index 000000000..711d36950 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/client/impl/hutool/HutoolMailCodeMapping.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.framework.mail.core.client.impl.hutool; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.mail.core.client.MailCodeMapping; + +/** + * 阿里云的 SmsCodeMapping 实现类 + * + * 参见 https://help.aliyun.com/document_detail/101346.htm 文档 + * + * @author 芋道源码 + */ +public class HutoolMailCodeMapping implements MailCodeMapping { + + @Override + public ErrorCode apply(String apiCode) { + return null; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailChannelEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailChannelEnum.java new file mode 100644 index 000000000..51d2f1fca --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailChannelEnum.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.mail.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信渠道枚举 + * + * @author zzf + * @date 2021/1/25 10:56 + */ +@Getter +@AllArgsConstructor +public enum MailChannelEnum { + HUTOOL("HUTOOL" , "HUTOOL"), + ; + + /** + * 编码 + */ + private final String code; + /** + * 名字 + */ + private final String name; + + public static MailChannelEnum getByCode(String code) { + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailFrameworkErrorCodeConstants.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailFrameworkErrorCodeConstants.java new file mode 100644 index 000000000..e5ef74cf3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailFrameworkErrorCodeConstants.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.framework.mail.core.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * 短信框架的错误码枚举 + * + * 短信框架,使用 2-001-000-000 段 + * + * @author 芋道源码 + */ +public interface MailFrameworkErrorCodeConstants { + + ErrorCode MAIL_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析"); + + // ========== 权限 / 限流等相关 2001000100 ========== + + ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限"); + // 云片:可以配置 IP 白名单,只有在白名单中才可以发送短信 + ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信"); + + // 阿里云:将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 + ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流"); + // 阿里云:已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置,修改发送总量阈值。 + ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流"); + + ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词"); + + // ========== 模板相关 2001000200 ========== + ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在 + ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确"); + + // ========== 签名相关 2001000300 ========== + ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用"); + + // ========== 账户相关 2001000400 ========== + ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足"); + ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在"); + + // ========== 其它相关 2001000900 开头 ========== + ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失"); + ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确"); + ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中"); + + ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常"); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailTemplateAuditStatusEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailTemplateAuditStatusEnum.java new file mode 100644 index 000000000..95c3c31a3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/enums/MailTemplateAuditStatusEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.mail.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信模板的审核状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum MailTemplateAuditStatusEnum { + + CHECKING(1), + SUCCESS(2), + FAIL(3); + + private final Integer status; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/property/MailChannelProperties.java b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/property/MailChannelProperties.java new file mode 100644 index 000000000..1f19ac12b --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-mail/src/main/java/cn/iocoder/yudao/framework/mail/core/property/MailChannelProperties.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.framework.mail.core.property; + +import lombok.Data; +import cn.iocoder.yudao.framework.mail.core.enums.MailChannelEnum; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 短信渠道配置类 + * + * @author zzf + * @date 2021/1/25 17:01 + */ +@Data +@Validated +public class MailChannelProperties { + + /** + * 渠道编号 + */ + @NotNull(message = "短信渠道 ID 不能为空") + private Long id; + /** + * 短信签名 + */ + @NotEmpty(message = "短信签名不能为空") + private String signature; + /** + * 渠道编码 + * + * 枚举 {@link MailChannelEnum} + */ + @NotEmpty(message = "渠道编码不能为空") + private String code; + /** + * 短信 API 的账号 + */ + @NotEmpty(message = "短信 API 的账号不能为空") + private String apiKey; + /** + * 短信 API 的秘钥 + */ + @NotEmpty(message = "短信 API 的秘钥不能为空") + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; + +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApi.java new file mode 100644 index 000000000..2ffe0d7cb --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApi.java @@ -0,0 +1,4 @@ +package cn.iocoder.yudao.module.system.api.mail; + +public interface MailSendApi { +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendReqDTO.java new file mode 100644 index 000000000..a3b0f2e35 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendReqDTO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.system.api.mail.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotNull; +import java.util.List; + +@ApiModel("管理后台 - 邮件发送 Req VO") +@Data +public class MailSendReqDTO { // TODO @wangjingqi:1), 不用空格;2)应该只要传递 templateCode、参数就好,title、from、content、附件应该都是参数里的 + + @ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com") + @NotNull(message = "邮箱账号不能为空") + @Email(message = "邮箱账号格式错误") + private String from; + + @ApiModelProperty(value = "标题",example = "标题") + private String title; + + @ApiModelProperty(value = "内容",example = "内容") + private String content; + + @ApiModelProperty(value = "邮箱模版id",example = "1024") + @NotNull(message = "邮箱模版id不能为空") + private Integer templateId; + + @ApiModelProperty(value = "收件人",required = true,example = "yudaoyuanma@123.com") + @NotNull(message = "收件人不能为空") + private List tos; + + @ApiModelProperty(value = "附件",example = "附件编码") + private List fileIds; + + +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 8520cb115..07322ccd7 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -126,5 +126,6 @@ public interface ErrorCodeConstants { // ========== 邮箱模版 1002020000 ========== ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1002020000 , "邮箱模版不存在"); ErrorCode MAIL_TEMPLATE_EXISTS = new ErrorCode(1002020001, "邮箱模版存在"); + ErrorCode MAIL_RELATE_TEMPLATE_EXISTS = new ErrorCode(1002020002, "存在关联邮箱模版"); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/mail/MailSendStatusEnum.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/mail/MailSendStatusEnum.java new file mode 100644 index 000000000..8936ea9c7 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/mail/MailSendStatusEnum.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.enums.mail; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 邮件的发送状态枚举 + * + * @author wangjingyi + * @date 2022/4/10 13:39 + */ +@Getter +@AllArgsConstructor +public enum MailSendStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 发送成功 + FAILURE(20), // 发送失败 + IGNORE(30), // 忽略,即不发送 + ; + + private final int status; + +} diff --git a/yudao-module-system/yudao-module-system-impl/pom.xml b/yudao-module-system/yudao-module-system-impl/pom.xml index b297830b5..65dc74d03 100644 --- a/yudao-module-system/yudao-module-system-impl/pom.xml +++ b/yudao-module-system/yudao-module-system-impl/pom.xml @@ -47,6 +47,10 @@ cn.iocoder.boot yudao-spring-boot-starter-biz-dict + + cn.iocoder.boot + yudao-spring-boot-starter-biz-mail + cn.iocoder.boot yudao-spring-boot-starter-biz-data-permission @@ -102,6 +106,7 @@ yudao-spring-boot-starter-excel + diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java new file mode 100644 index 000000000..cce0ed388 --- /dev/null +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.system.api.mail; + +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * 邮件发送 API 接口 + * + * @author wangjingyi + */ +@Service +@Validated +public class MailSendApiImpl implements MailSendApi{ +} diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountBaseVO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountBaseVO.java index 67cf9ba3a..d8650b52e 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountBaseVO.java +++ b/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; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; @ApiModel("管理后台 - 邮箱账号基类 Base VO") @Data -public class MailAccountBaseVO { // TODO @wangjingqi:1), 不用空格;2)from、username、password、host、sslEnable 都要参数校验,非空;3)username 要 Email 格式;port Integer; +public class MailAccountBaseVO { - @ApiModelProperty(value = "邮箱" , required = true , example = "yudaoyuanma@123.com") + @ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com") + @NotNull(message = "邮箱必填") private String from; - @ApiModelProperty(value = "用户名" , required = true , example = "yudao") + @ApiModelProperty(value = "用户名",required = true,example = "yudao") @NotNull(message = "用户名必填") + @Email(message = "必须是Email格式") private String username; - @ApiModelProperty(value = "密码" , required = true , example = "123456") + @ApiModelProperty(value = "密码",required = true,example = "123456") + @NotNull(message = "密码必填") private String password; - @ApiModelProperty(value = "网站" , required = true , example = "www.iocoder.cn") + @ApiModelProperty(value = "网站",required = true,example = "www.iocoder.cn") + @NotNull(message = "网站必填") private String host; - @ApiModelProperty(value = "端口" , required = true , example = "80") - private String port; + @ApiModelProperty(value = "端口",required = true,example = "80") + private Integer port; - @ApiModelProperty(value = "是否开启ssl" , required = true , example = "2") + @ApiModelProperty(value = "是否开启ssl",required = true,example = "2") + @NotNull(message = "是否开启ssl必填") private Boolean sslEnable; } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogExcelVO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogExcelVO.java index 442a101a3..d341ce678 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogExcelVO.java +++ b/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; import org.springframework.format.annotation.DateTimeFormat; import java.sql.Timestamp; +import java.util.Date; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -30,10 +31,10 @@ public class MailLogExcelVO { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @ExcelProperty(value = "发送时间" ) - private Timestamp sendTime; + private Date sendTime; @ExcelProperty(value = "发送状态") - private Boolean sendStatus; + private Integer sendStatus; @ExcelProperty(value = "发送结果") private String sendResult; diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogRespVO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogRespVO.java index af8e81698..024e075f4 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogRespVO.java +++ b/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 { private Timestamp sendTime; @ApiModelProperty(value = "发送状态" , required = false , example = "1") - private Boolean sendStatus; + private Integer sendStatus; @ApiModelProperty(value = "发送结果" , required = false , example = "yudaoyuanma@123.com") private String sendResult; diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/send/MailReqVO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/send/MailReqVO.java index 4ce06a718..65142ee3f 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/send/MailReqVO.java +++ b/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; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; import java.util.List; @@ -11,25 +12,26 @@ import java.util.List; @Data public class MailReqVO { // TODO @wangjingqi:1), 不用空格;2)应该只要传递 templateCode、参数就好,title、from、content、附件应该都是参数里的 - @ApiModelProperty(value = "邮箱" , required = true , example = "yudaoyuanma@123.com") + @ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com") @NotNull(message = "邮箱账号不能为空") + @Email(message = "邮箱账号格式错误") private String from; - @ApiModelProperty(value = "标题" , example = "标题") + @ApiModelProperty(value = "标题",example = "标题") private String title; - @ApiModelProperty(value = "内容" , example = "内容") + @ApiModelProperty(value = "内容",example = "内容") private String content; - @ApiModelProperty(value = "邮箱模版id" , example = "1024") + @ApiModelProperty(value = "邮箱模版id",example = "1024") @NotNull(message = "邮箱模版id不能为空") private Integer templateId; - @ApiModelProperty(value = "收件人" , required = true , example = "yudaoyuanma@123.com") + @ApiModelProperty(value = "收件人",required = true,example = "yudaoyuanma@123.com") @NotNull(message = "收件人不能为空") private List tos; - @ApiModelProperty(value = "附件" , example = "附件编码") + @ApiModelProperty(value = "附件",example = "附件编码") private List fileIds; diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateBaseVO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateBaseVO.java index e3c9797ab..1e44336aa 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateBaseVO.java +++ b/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; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; @ApiModel("管理后台 - 邮箱模版基类 Base VO") @Data -public class MailTemplateBaseVO { // TODO @wangjingqi:1)swagger 注解不完善;2)id、name、code、username、title、content、status 是不是要参数校验呀 +public class MailTemplateBaseVO { @ApiModelProperty("主键") + @NotNull(message = "主键不能为空") private Long id; @ApiModelProperty("名称") + @NotNull(message = "名称不能为空") private String name; @ApiModelProperty("标识") @@ -20,16 +23,21 @@ public class MailTemplateBaseVO { // TODO @wangjingqi:1)swagger 注解不 private String code; @ApiModelProperty("发件人") + @NotNull(message = "发件人不能为空") + @Email(message = "发件人格式有误") private String username; @ApiModelProperty("标题") + @NotNull(message = "标题不能为空") private String title; @ApiModelProperty("内容") + @NotNull(message = "内容不能为空") private String content; @ApiModelProperty("状态") - private String status; + @NotNull(message = "状态不能为空") + private Integer status; @ApiModelProperty("备注") private String remark; diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java index 398e6ac03..a48c5a91a 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java +++ b/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 { private String content; @ApiModelProperty("状态") - private String status; + private Integer status; @ApiModelProperty("备注") private String remark; diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java index f6b9e689c..7454d2acb 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; +import lombok.*; import java.io.Serializable; -import java.sql.Timestamp; +import java.util.Date; /** * 邮箱日志 @@ -18,6 +18,10 @@ import java.sql.Timestamp; @TableName(value = "system_mail_log", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor public class MailLogDO extends BaseDO implements Serializable { /** @@ -29,7 +33,7 @@ public class MailLogDO extends BaseDO implements Serializable { /** * 邮箱账号编号 */ - private String accountCode; + private Long accountId; // TODO @wangjingyi:如果是冗余字段,记得 @ 下; /** @@ -40,7 +44,7 @@ public class MailLogDO extends BaseDO implements Serializable { /** * 模版主键 */ - private String templateId; + private Long templateId; /** * 模版编号 @@ -65,16 +69,18 @@ public class MailLogDO extends BaseDO implements Serializable { /** * 发送时间 */ - private Timestamp sendTime; + private Date sendTime; /** * 发送状态 + * + * 枚举 {@link MailSendStatusEnum} */ - // TODO @wangjingyi:四个状态,参考短信模块 - private Boolean sendStatus; + private Integer sendStatus; /** * 发送结果 + * */ private String sendResult; diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java index b86e39e95..96f9ba4ab 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java +++ b/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; import lombok.Data; import lombok.EqualsAndHashCode; +import java.util.Date; + /** * 邮箱模版 * @@ -29,11 +31,10 @@ public class MailTemplateDO extends BaseDO { * 模版编号 */ private String code; - // TODO @wangjingyi:应该使用 accountId 呀 /** - * 用户名 + * 邮箱账号主键 */ - private String username; + private Long accountId; /** * 标题 */ @@ -47,7 +48,7 @@ public class MailTemplateDO extends BaseDO { * * 枚举 {@link CommonStatusEnum} */ - private String status; // TODO @wangjingyi:Integer + private Integer status; /** * 备注 */ diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java index 8697b2151..651f5c75f 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java +++ b/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; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import org.apache.ibatis.annotations.Mapper; @Mapper @@ -21,9 +22,7 @@ public interface MailAccountMapper extends BaseMapperX { } default MailAccountDO selectByUserName(String userName){ - // TODO @wangjingyi:selectOne 有封装的方法;然后,编码一定要学会使用泛型呀。例如说 QueryWrapperX queryWrapperX = new QueryWrapperX<>(); - QueryWrapperX queryWrapperX = new QueryWrapperX<>(); - queryWrapperX.eqIfPresent("username", userName); - return this.selectOne(queryWrapperX); + return selectOne(new QueryWrapperX() + .eqIfPresent("username" , userName)); }; } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java index d65887e54..a5cbf0b2a 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java +++ b/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; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.Date; @Mapper @@ -23,7 +26,15 @@ public interface MailTemplateMapper extends BaseMapperX { } default MailTemplateDO selectOneByCode(String code){ - // TODO @wangjingyi:优先使用 lambada 查询 - return selectOne("code" , code); + return selectOne(new QueryWrapperX() + .eqIfPresent("code" , code)); + }; + + @Select("SELECT id FROM system_mail_template WHERE update_time > #{maxUpdateTime} LIMIT 1") + Long selectByMaxUpdateTime(Date maxUpdateTime); + + default MailTemplateDO selectOneByAccountId(Long accountId){ + return selectOne(new QueryWrapperX() + .eqIfPresent("account_id" , accountId)); }; } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java index 4b02f760e..978ea5997 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java +++ b/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; import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener; import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import cn.iocoder.yudao.module.system.service.mail.MailSendService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -// TODO 芋艿:这个暂未实现 +import javax.annotation.Resource; + + @Component @Slf4j public class MailSendConsumer extends AbstractStreamMessageListener { + @Resource + private MailSendService mailSendService; @Override public void onMessage(MailSendMessage message) { log.info("[onMessage][消息内容({})]", message); + mailSendService.doSendMail(message); } } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java index aee02c76e..275a45825 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java +++ b/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; import lombok.EqualsAndHashCode; import javax.validation.constraints.NotNull; +import java.util.List; import java.util.Map; /** @@ -16,29 +17,34 @@ import java.util.Map; @EqualsAndHashCode(callSuper = true) public class MailSendMessage extends AbstractStreamMessage { + /** + * 日志id + */ + @NotNull(message = "邮箱日志id不能为空") + private Long logId; /** * 邮箱地址 */ @NotNull(message = "邮箱地址不能为空") - private String address; + private String from; /** - * 短信模板编号 + * 邮箱模板编号 */ - @NotNull(message = "短信模板编号不能为空") + @NotNull(message = "邮箱模板编号不能为空") private String templateCode; /** - * 短信模板参数 + * 收件人 */ - private Map templateParams; - + @NotNull(message = "收件人不能为空") + private List tos; /** - * 用户编号,允许空 + * 标题 */ - private Integer userId; + private String title; /** - * 用户类型,允许空 + * 内容 */ - private Integer userType; + private String content; @Override public String getStreamKey() { diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java new file mode 100644 index 000000000..ed82c24a4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.system.mq.producer.mail; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; +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.mq.message.mail.MailSendMessage; +import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage; +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; +import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +/** + * Mail 邮件相关消息的 Producer + * + * @author wangjingyi + * @date 2021/4/19 13:33 + */ +@Slf4j +@Component +public class MailProducer { + + @Resource + private RedisMQTemplate redisMQTemplate; + + /** + * 发送 {@link SmsChannelRefreshMessage} 消息 + */ + public void sendMailChannelRefreshMessage() { + SmsChannelRefreshMessage message = new SmsChannelRefreshMessage(); + redisMQTemplate.send(message); + } + + /** + * 发送 {@link SmsTemplateRefreshMessage} 消息 + */ + public void sendMailTemplateRefreshMessage() { + SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage(); + redisMQTemplate.send(message); + } + + /** + * 发送 {@link MailSendMessage} 消息 + * + * @param mailAccountDO 邮箱账号信息 + * @param mailTemplateDO 邮箱模版信息 + * @param content 内容 + * @param tos 收件人 + * @param title 标题 + */ + public void sendMailSendMessage(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String content, List tos, String title , Long sendLogId) { + MailSendMessage message = new MailSendMessage(); + message.setContent(content); + message.setFrom(mailAccountDO.getFrom()); + message.setTemplateCode(mailTemplateDO.getCode()); + message.setTitle(title); + message.setTos(tos); + message.setLogId(sendLogId); + redisMQTemplate.send(message); + } +} diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java index fa195259b..0a5d25ba2 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java +++ b/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; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import java.util.List; @@ -28,4 +30,18 @@ public interface MailLogService { * @return */ List getMailLogList(MailLogExportReqVO exportReqVO); + + /** + * 创建邮箱日志 + * @param mailAccountDO 邮箱账号信息 + * @param mailTemplateDO 模版信息 + * @param from 邮箱 + * @param content 内容 + * @param tos 收件人 + * @param title 标题 + * @param isSend 是否发送成功 + */ + Long createMailLog(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String from, String content, List tos, String title, Boolean isSend); + + Long updateSmsSendResult(Long logId, String result); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java new file mode 100644 index 000000000..31f6a3f3e --- /dev/null +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java @@ -0,0 +1,41 @@ +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; + +/** + * 邮箱模版服务类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailSendService { + + /** + * 发送邮件 + * + * @param templateCode 邮件模版编码 + * @param from 邮箱 + * @param content 内容 + * @param tos 收件人 + * @param title 标题 + */ + void sendMail(String templateCode, String from , String content , List tos , String title); + + /** + * 执行真正的邮件发送 + * 注意,该方法仅仅提供给 MQ Consumer 使用 + * + * @param message 邮件 + */ + void doSendMail(MailSendMessage message); +} diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java index 1071eae5d..b8101f0af 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java +++ b/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; import javax.validation.Valid; import java.util.List; +import java.util.Map; /** * 邮箱模版服务类 @@ -18,6 +19,7 @@ import java.util.List; */ public interface MailTemplateService { + void initLocalCache(); /** * 邮箱模版创建 * @@ -62,6 +64,13 @@ public interface MailTemplateService { * @return 模版数组 */ List getMailTemplateList(); + /** + *从缓存中获取邮箱模版 + * + * @param code 模板编码 + * @return 邮箱模板 + */ + MailTemplateDO getMailTemplateByCodeFromCache(String code); /** * 发送邮件 @@ -69,4 +78,12 @@ public interface MailTemplateService { * @param mailReqVO 邮件发送信息 */ void sendMail(MailReqVO mailReqVO); + + /** + * 邮件模版内容合成 + * @param content 邮箱模版 + * @param params 合成参数 + * @return + */ + String formateMailTemplateContent(String content, Map params); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java index aa1fb1d46..36ca05213 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java +++ b/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 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO; import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; import cn.iocoder.yudao.module.system.service.mail.MailAccountService; @@ -16,8 +17,7 @@ import javax.annotation.Resource; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_EXISTS; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; /** @@ -47,8 +47,8 @@ public class MailAccountServiceImpl implements MailAccountService { @Override public void update(MailAccountUpdateReqVO updateReqVO) { - // username 要校验唯一 // TODO @wangjingyi:更新的就是自己,username 这样写,会重复呀。 - this.validateMailAccountOnlyByUserName(updateReqVO.getUsername()); + // username 要校验唯一 + this.validateMailAccountExists(updateReqVO.getId()); MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(updateReqVO); // 校验是否存在 this.validateMailAccountExists(mailAccountDO.getId()); @@ -57,9 +57,10 @@ public class MailAccountServiceImpl implements MailAccountService { @Override public void delete(Long id) { - // TODO @wangjingyi:删除时,要判断是否有使用的模板 - // 校验是否存在 + // 校验是否存在账号 this.validateMailAccountExists(id); + // 校验是否存在关联模版 + this.validateMailTemplateByAccountId(id); mailAccountMapper.deleteById(id); } @@ -90,4 +91,11 @@ public class MailAccountServiceImpl implements MailAccountService { throw exception(MAIL_ACCOUNT_EXISTS); } } + + private void validateMailTemplateByAccountId(Long accountId){ + MailTemplateDO mailTemplateDO = mailTemplateMapper.selectOneByAccountId(accountId); + if (mailTemplateDO != null) { + throw exception(MAIL_RELATE_TEMPLATE_EXISTS); + } + } } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java index c6b492498..bdceb0d72 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java +++ b/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; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper; +import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; +import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum; import cn.iocoder.yudao.module.system.service.mail.MailLogService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.sql.Timestamp; +import java.util.Date; import java.util.List; +import java.util.Objects; /** * 邮箱日志实现类 @@ -35,4 +42,39 @@ public class MailLogServiceImpl implements MailLogService { public List getMailLogList(MailLogExportReqVO exportReqVO) { return mailLogMapper.selectList(exportReqVO); } + + @Override + public Long createMailLog(MailAccountDO mailAccountDO , MailTemplateDO mailTemplateDO , String from, String content, List tos, String title, Boolean isSend) { + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); + logDOBuilder.from(mailAccountDO.getFrom()); + logDOBuilder.accountId(mailAccountDO.getId()); + logDOBuilder.content(content); + logDOBuilder.title(title); + logDOBuilder.templateCode(mailTemplateDO.getCode()); + logDOBuilder.templateId(mailTemplateDO.getId()); + logDOBuilder.to(tos.toString()); + logDOBuilder.sendTime(new Date()); + logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus() + : MailSendStatusEnum.IGNORE.getStatus()); + + MailLogDO mailLogDO = logDOBuilder.build(); + mailLogMapper.insert(mailLogDO); + return mailLogDO.getId(); + } + + @Override + public Long updateSmsSendResult(Long logId, String result) { + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); + logDOBuilder.id(logId); + logDOBuilder.sendResult(result); + MailLogDO mailLogDO = logDOBuilder.build(); + mailLogMapper.updateById(mailLogDO); + return logId; + } + + public Long create(){ + MailLogDO mailLogDO = new MailLogDO(); + mailLogMapper.insert(mailLogDO); + return mailLogDO.getId(); + } } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java new file mode 100644 index 000000000..61e428048 --- /dev/null +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.system.service.mail.impl; + + +import cn.hutool.extra.mail.MailAccount; +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.dal.mysql.mail.MailTemplateMapper; +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 lombok.extern.slf4j.Slf4j; +import cn.iocoder.yudao.framework.mail.core.client.MailClientFactory; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import cn.iocoder.yudao.framework.mail.core.client.MailClient; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_EXISTS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; + +/** + * 邮箱模版 服务实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailSendServiceImpl implements MailSendService { + + @Resource + private MailTemplateMapper mailTemplateMapper; + @Resource + private MailAccountMapper mailAccountMapper; + @Resource + private MailTemplateService mailTemplateService; + @Resource + private MailLogService mailLogService; + @Resource + private MailClientFactory mailClientFactory; + @Resource + private MailProducer mailProducer; + + + @Override + public void sendMail(String templateCode, String from , String content , List tos , String title) { + // TODO @@wangjingyi:发送的时候,参考下短信; + MailTemplateDO mailTemplateDO = this.checkMailTemplateValid(templateCode); + // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus()); + //查询账号信息 + MailAccountDO mailAccountDO = mailAccountMapper.selectOne( + "from", from + ); + Map params = MailAccountConvert.INSTANCE.convertToMap(mailAccountDO , content); + content = mailTemplateService.formateMailTemplateContent(mailTemplateDO.getContent(), params); + Long sendLogId = mailLogService.createMailLog(mailAccountDO , mailTemplateDO , from , content , tos , title , isSend); + + // 后续功能 TODO :附件查询 + //List fileIds = mailSendVO.getFileIds(); + + //装载账号信息 + MailAccount account = MailAccountConvert.INSTANCE.convertAccount(mailAccountDO); + + // 发送 MQ 消息,异步执行发送短信 + if (isSend) { + mailProducer.sendMailSendMessage(mailAccountDO , mailTemplateDO ,content , tos , title , sendLogId); + } + } + + @Override + public void doSendMail(MailSendMessage message) { + MailClient mailClient = mailClientFactory.getMailClient(); + String result = mailClient.sendMail(message.getFrom() , message.getContent() , message.getTitle() , message.getTos()); + mailLogService.updateSmsSendResult(message.getLogId() , result); + } + + private MailTemplateDO checkMailTemplateValid(String templateCode) { + MailTemplateDO mailTemplateDO = mailTemplateService.getMailTemplateByCodeFromCache(templateCode); + if (mailTemplateDO == null){ + throw exception(MAIL_TEMPLATE_NOT_EXISTS); + } + return mailTemplateDO; + } + + private void validateMailTemplateExists(Long id) { + if (mailTemplateMapper.selectById(id) == null) { + throw exception(MAIL_TEMPLATE_NOT_EXISTS); + } + } + + private void validateMailTemplateOnlyByCode(String code){ + if (mailTemplateMapper.selectOneByCode(code) != null) { + throw exception(MAIL_TEMPLATE_EXISTS); + } + } +} diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java index 2bd74ac4c..e1d212186 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.system.service.mail.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.mail.MailAccount; import cn.hutool.extra.mail.MailUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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; @@ -13,14 +15,18 @@ import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert; 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.SmsTemplateDO; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.Date; import java.util.List; import java.util.Map; @@ -36,6 +42,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPL */ @Service @Validated +@Slf4j public class MailTemplateServiceImpl implements MailTemplateService { @Resource @@ -43,6 +50,38 @@ public class MailTemplateServiceImpl implements MailTemplateService { @Resource private MailAccountMapper mailAccountMapper; + private volatile List mailTemplateDOList; + + /** + * 邮件模板缓存 + * key:邮箱模板编码 {@link MailTemplateDO#getCode()} + * + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 + */ + private volatile Map mailTemplateCache; + + private volatile Date maxUpdateTime; + + @Override + @PostConstruct + public void initLocalCache() { + if(maxUpdateTime == null){ + mailTemplateDOList = mailTemplateMapper.selectList(); + }else{ + if(mailTemplateMapper.selectByMaxUpdateTime(maxUpdateTime)<=0){ + return; + } + } + if (CollUtil.isEmpty(mailTemplateDOList)) { + return; + } + + // 写入缓存 + mailTemplateCache = CollectionUtils.convertMap(mailTemplateDOList, MailTemplateDO::getCode); + maxUpdateTime = CollectionUtils.getMaxValue(mailTemplateDOList, MailTemplateDO::getUpdateTime); + log.info("[initLocalCache][初始化 mailTemplate 数量为 {}]", mailTemplateDOList.size()); + } + @Override public Long create(MailTemplateCreateReqVO createReqVO) { // code 要校验唯一 @@ -54,11 +93,9 @@ public class MailTemplateServiceImpl implements MailTemplateService { @Override public void update(@Valid MailTemplateUpdateReqVO updateReqVO) { - // code 要校验唯一 - this.validateMailTemplateOnlyByCode(updateReqVO.getCode()); // TODO @wangjingyi:code 这样写,修改自己会有问题 - MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO); // 校验是否存在 - this.validateMailTemplateExists(mailTemplateDO.getId()); + this.validateMailTemplateExists(updateReqVO.getId()); + MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO); mailTemplateMapper.updateById(mailTemplateDO); } @@ -80,6 +117,11 @@ public class MailTemplateServiceImpl implements MailTemplateService { @Override public List getMailTemplateList() {return mailTemplateMapper.selectList();} + @Override + public MailTemplateDO getMailTemplateByCodeFromCache(String code) { + return mailTemplateCache.get(code); + } + @Override public void sendMail(MailReqVO mailReqVO) { // TODO @@wangjingyi:发送的时候,参考下短信; @@ -102,6 +144,11 @@ public class MailTemplateServiceImpl implements MailTemplateService { MailUtil.send(account , mailReqVO.getTos() , mailReqVO.getTitle() , content , false); } + @Override + public String formateMailTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + private void validateMailTemplateExists(Long id) { if (mailTemplateMapper.selectById(id) == null) { throw exception(MAIL_TEMPLATE_NOT_EXISTS);