Commit 8bc5254e308ab0d774635f0629bc508f58c8041a

Authored by wangjingyi
1 parent ea92b841

邮件模块 添加邮箱账号缓存 修改校验方式

Showing 23 changed files with 318 additions and 132 deletions
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
@@ -130,6 +130,6 @@ public interface ErrorCodeConstants { @@ -130,6 +130,6 @@ public interface ErrorCodeConstants {
130 // ========== 邮箱模版 1002021000 ========== 130 // ========== 邮箱模版 1002021000 ==========
131 ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1002021000 , "邮箱模版不存在"); 131 ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1002021000 , "邮箱模版不存在");
132 ErrorCode MAIL_TEMPLATE_EXISTS = new ErrorCode(1002021001, "邮箱模版存在"); 132 ErrorCode MAIL_TEMPLATE_EXISTS = new ErrorCode(1002021001, "邮箱模版存在");
133 - ErrorCode MAIL_RELATE_TEMPLATE_EXISTS = new ErrorCode(1002021002, "存在关联邮箱模版"); 133 + ErrorCode MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS = new ErrorCode(1002021002, "存在关联邮箱模版");
134 134
135 } 135 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java
@@ -57,7 +57,7 @@ public class MailAccountController { @@ -57,7 +57,7 @@ public class MailAccountController {
57 } 57 }
58 58
59 // TODO @wangjingyi:getMailAccount 和 getMailAccountPage 这两个接口,定义一个对应的 Resp 类哈,参考别的模块。主要不要返回 password 字段。 59 // TODO @wangjingyi:getMailAccount 和 getMailAccountPage 这两个接口,定义一个对应的 Resp 类哈,参考别的模块。主要不要返回 password 字段。
60 - // 一个可以的做法,是 MailAccountBaseVO 不返回 password,然后 MailAccountCreateReqVO、MailAccountUpdateReqVO 添加这个字段 60 + // 一个可以的做法,是 MailAccountBaseVO 不返回 password,然后 MailAccountCreateReqVO、MailAccountUpdateReqVO 添加这个字段 DONE
61 61
62 @GetMapping("/get") 62 @GetMapping("/get")
63 @ApiOperation("获得邮箱账号") 63 @ApiOperation("获得邮箱账号")
@@ -76,7 +76,7 @@ public class MailAccountController { @@ -76,7 +76,7 @@ public class MailAccountController {
76 return success(MailAccountConvert.INSTANCE.convertPage(pageResult)); 76 return success(MailAccountConvert.INSTANCE.convertPage(pageResult));
77 } 77 }
78 78
79 - // TODO @wangjingyi:getSimpleMailAccountList 单独定义一个类,只返回精简的信息,id,from 即可。像密码之类都是敏感信息,不应该返回 79 + // TODO @wangjingyi:getSimpleMailAccountList 单独定义一个类,只返回精简的信息,id,from 即可。像密码之类都是敏感信息,不应该返回 DONE
80 80
81 @GetMapping("/list-all-simple") 81 @GetMapping("/list-all-simple")
82 @ApiOperation(value = "获得邮箱账号精简列表") 82 @ApiOperation(value = "获得邮箱账号精简列表")
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java
@@ -3,10 +3,7 @@ package cn.iocoder.yudao.module.system.controller.admin.mail; @@ -3,10 +3,7 @@ package cn.iocoder.yudao.module.system.controller.admin.mail;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.send.MailReqVO; 5 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.send.MailReqVO;
6 -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateBaseVO;  
7 -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateCreateReqVO;  
8 -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;  
9 -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateUpdateReqVO; 6 +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.*;
10 import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert; 7 import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert;
11 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; 8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
12 import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; 9 import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
@@ -29,9 +26,9 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -29,9 +26,9 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
29 @RequestMapping("/system/mail-template") 26 @RequestMapping("/system/mail-template")
30 public class MailTemplateController { 27 public class MailTemplateController {
31 28
32 - // TODO @wangjingyi:private 29 + // TODO @wangjingyi:private DONE
33 @Autowired 30 @Autowired
34 - MailTemplateService mailTempleService; 31 + private MailTemplateService mailTempleService;
35 32
36 @PostMapping("/create") 33 @PostMapping("/create")
37 @ApiOperation("创建邮箱模版") 34 @ApiOperation("创建邮箱模版")
@@ -56,13 +53,13 @@ public class MailTemplateController { @@ -56,13 +53,13 @@ public class MailTemplateController {
56 return success(true); 53 return success(true);
57 } 54 }
58 55
59 - // TODO @wangjingyi:下面几个 VO 也参考我在 account 给的建议 56 + // TODO @wangjingyi:下面几个 VO 也参考我在 account 给的建议 DONE RespVO中需要BaseVO 中哪些字段
60 57
61 @GetMapping("/get") 58 @GetMapping("/get")
62 @ApiOperation("获得邮箱模版") 59 @ApiOperation("获得邮箱模版")
63 @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) 60 @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
64 @PreAuthorize("@ss.hasPermission('system:mail-template:get')") 61 @PreAuthorize("@ss.hasPermission('system:mail-template:get')")
65 - public CommonResult<MailTemplateBaseVO> getMailTemplate(@RequestParam("id") Long id) { 62 + public CommonResult<MailTemplateRespVO> getMailTemplate(@RequestParam("id") Long id) {
66 MailTemplateDO mailTemplateDO = mailTempleService.getMailTemplate(id); 63 MailTemplateDO mailTemplateDO = mailTempleService.getMailTemplate(id);
67 return success(MailTemplateConvert.INSTANCE.convert(mailTemplateDO)); 64 return success(MailTemplateConvert.INSTANCE.convert(mailTemplateDO));
68 } 65 }
@@ -70,25 +67,17 @@ public class MailTemplateController { @@ -70,25 +67,17 @@ public class MailTemplateController {
70 @GetMapping("/page") 67 @GetMapping("/page")
71 @ApiOperation("获得邮箱模版分页") 68 @ApiOperation("获得邮箱模版分页")
72 @PreAuthorize("@ss.hasPermission('system:mail-template:query')") 69 @PreAuthorize("@ss.hasPermission('system:mail-template:query')")
73 - public CommonResult<PageResult<MailTemplateBaseVO>> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) { 70 + public CommonResult<PageResult<MailTemplateRespVO>> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) {
74 PageResult<MailTemplateDO> pageResult = mailTempleService.getMailTemplatePage(pageReqVO); 71 PageResult<MailTemplateDO> pageResult = mailTempleService.getMailTemplatePage(pageReqVO);
75 return success(MailTemplateConvert.INSTANCE.convertPage(pageResult)); 72 return success(MailTemplateConvert.INSTANCE.convertPage(pageResult));
76 } 73 }
77 74
78 @GetMapping("/list-all-simple") 75 @GetMapping("/list-all-simple")
79 @ApiOperation(value = "获得邮箱模版精简列表") 76 @ApiOperation(value = "获得邮箱模版精简列表")
80 - public CommonResult<List<MailTemplateBaseVO>> getSimpleTemplateList() { 77 + public CommonResult<List<MailTemplateRespVO>> getSimpleTemplateList() {
81 List<MailTemplateDO> list = mailTempleService.getMailTemplateList(); 78 List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
82 // 排序后,返回给前端 79 // 排序后,返回给前端
83 list.sort(Comparator.comparing(MailTemplateDO::getId)); 80 list.sort(Comparator.comparing(MailTemplateDO::getId));
84 return success(MailTemplateConvert.INSTANCE.convertList02(list)); 81 return success(MailTemplateConvert.INSTANCE.convertList02(list));
85 } 82 }
86 -  
87 - @PostMapping("/send")  
88 - @ApiOperation("发送邮件")  
89 - @PreAuthorize("@ss.hasPermission('system:mail-template:send')")  
90 - public CommonResult<Boolean> sendMail(@Valid @RequestBody MailReqVO mailReqVO){  
91 - mailTempleService.sendMail(mailReqVO);  
92 - return success(true);  
93 - }  
94 } 83 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountBaseVO.java
@@ -20,10 +20,6 @@ public class MailAccountBaseVO { @@ -20,10 +20,6 @@ public class MailAccountBaseVO {
20 @Email(message = "必须是Email格式") 20 @Email(message = "必须是Email格式")
21 private String username; 21 private String username;
22 22
23 - @ApiModelProperty(value = "密码",required = true,example = "123456")  
24 - @NotNull(message = "密码必填")  
25 - private String password;  
26 -  
27 @ApiModelProperty(value = "网站",required = true,example = "www.iocoder.cn") 23 @ApiModelProperty(value = "网站",required = true,example = "www.iocoder.cn")
28 @NotNull(message = "网站必填") 24 @NotNull(message = "网站必填")
29 private String host; 25 private String host;
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountCreateReqVO.java
1 package cn.iocoder.yudao.module.system.controller.admin.mail.vo.account; 1 package cn.iocoder.yudao.module.system.controller.admin.mail.vo.account;
2 2
3 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
6 import lombok.ToString; 7 import lombok.ToString;
7 8
  9 +import javax.validation.constraints.NotNull;
  10 +
8 @ApiModel("管理后台 - 邮箱账号创建 Request VO") 11 @ApiModel("管理后台 - 邮箱账号创建 Request VO")
9 @Data 12 @Data
10 @EqualsAndHashCode(callSuper = true) 13 @EqualsAndHashCode(callSuper = true)
11 @ToString(callSuper = true) 14 @ToString(callSuper = true)
12 public class MailAccountCreateReqVO extends MailAccountBaseVO { 15 public class MailAccountCreateReqVO extends MailAccountBaseVO {
13 16
  17 + @ApiModelProperty(value = "密码",required = true,example = "123456")
  18 + @NotNull(message = "密码必填")
  19 + private String password;
14 } 20 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountUpdateReqVO.java
@@ -18,4 +18,7 @@ public class MailAccountUpdateReqVO extends MailAccountBaseVO { @@ -18,4 +18,7 @@ public class MailAccountUpdateReqVO extends MailAccountBaseVO {
18 @NotNull(message = "编号不能为空") 18 @NotNull(message = "编号不能为空")
19 private Long id; 19 private Long id;
20 20
  21 + @ApiModelProperty(value = "密码",required = true,example = "123456")
  22 + @NotNull(message = "密码必填")
  23 + private String password;
21 } 24 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template;
  2 +
  3 +public class MailTemplateRespVO extends MailTemplateBaseVO{
  4 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java
@@ -4,6 +4,7 @@ import cn.hutool.extra.mail.MailAccount; @@ -4,6 +4,7 @@ import cn.hutool.extra.mail.MailAccount;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountBaseVO; 5 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountBaseVO;
6 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; 6 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
  7 +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
7 import org.mapstruct.Mapper; 8 import org.mapstruct.Mapper;
8 import org.mapstruct.factory.Mappers; 9 import org.mapstruct.factory.Mappers;
9 10
@@ -23,7 +24,7 @@ public interface MailAccountConvert { @@ -23,7 +24,7 @@ public interface MailAccountConvert {
23 24
24 List<MailAccountBaseVO> convertList02(List<MailAccountDO> list); 25 List<MailAccountBaseVO> convertList02(List<MailAccountDO> list);
25 26
26 - default MailAccount convertAccount(MailAccountDO mailAccountDO){ 27 + default MailAccount convertAccount(MailSendMessage mailAccountDO){
27 return new MailAccount() 28 return new MailAccount()
28 .setHost(mailAccountDO.getHost()) 29 .setHost(mailAccountDO.getHost())
29 .setPort(mailAccountDO.getPort()) 30 .setPort(mailAccountDO.getPort())
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailTemplateConvert.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.convert.mail; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.convert.mail;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateBaseVO; 4 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateBaseVO;
  5 +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateRespVO;
5 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; 6 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
6 import org.mapstruct.Mapper; 7 import org.mapstruct.Mapper;
7 import org.mapstruct.factory.Mappers; 8 import org.mapstruct.factory.Mappers;
@@ -14,9 +15,9 @@ public interface MailTemplateConvert { @@ -14,9 +15,9 @@ public interface MailTemplateConvert {
14 15
15 MailTemplateDO convert(MailTemplateBaseVO baseVO); 16 MailTemplateDO convert(MailTemplateBaseVO baseVO);
16 17
17 - MailTemplateBaseVO convert(MailTemplateDO mailTemplateDO); 18 + MailTemplateRespVO convert(MailTemplateDO mailTemplateDO);
18 19
19 - PageResult<MailTemplateBaseVO> convertPage(PageResult<MailTemplateDO> pageResult); 20 + PageResult<MailTemplateRespVO> convertPage(PageResult<MailTemplateDO> pageResult);
20 21
21 - List<MailTemplateBaseVO> convertList02(List<MailTemplateDO> list); 22 + List<MailTemplateRespVO> convertList02(List<MailTemplateDO> list);
22 } 23 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java
@@ -7,6 +7,9 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccou @@ -7,6 +7,9 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccou
7 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; 7 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; 8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
9 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
  10 +import org.apache.ibatis.annotations.Select;
  11 +
  12 +import java.util.Date;
10 13
11 @Mapper 14 @Mapper
12 public interface MailAccountMapper extends BaseMapperX<MailAccountDO> { 15 public interface MailAccountMapper extends BaseMapperX<MailAccountDO> {
@@ -25,4 +28,18 @@ public interface MailAccountMapper extends BaseMapperX&lt;MailAccountDO&gt; { @@ -25,4 +28,18 @@ public interface MailAccountMapper extends BaseMapperX&lt;MailAccountDO&gt; {
25 return selectOne(new QueryWrapperX<MailAccountDO>() 28 return selectOne(new QueryWrapperX<MailAccountDO>()
26 .eqIfPresent("username" , userName)); 29 .eqIfPresent("username" , userName));
27 }; 30 };
  31 +
  32 + default MailAccountDO selectByUserNameAndId(String userName,Long id){
  33 + return selectOne(new QueryWrapperX<MailAccountDO>()
  34 + .eqIfPresent("username" , userName)
  35 + .neIfPresent("id" , id));
  36 + };
  37 +
  38 + default MailAccountDO selectOneByFrom(String from){
  39 + return selectOne(new QueryWrapperX<MailAccountDO>()
  40 + .eqIfPresent("from" , from));
  41 + };
  42 +
  43 + @Select("SELECT COUNT(*) FROM system_mail_account WHERE update_time > #{maxUpdateTime}")
  44 + Long selectCountByUpdateTimeGt(Date maxUpdateTime);
28 } 45 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java
@@ -30,7 +30,7 @@ public interface MailTemplateMapper extends BaseMapperX&lt;MailTemplateDO&gt; { @@ -30,7 +30,7 @@ public interface MailTemplateMapper extends BaseMapperX&lt;MailTemplateDO&gt; {
30 .eqIfPresent("code" , code)); 30 .eqIfPresent("code" , code));
31 }; 31 };
32 32
33 - @Select("SELECT id FROM system_mail_template WHERE update_time > #{maxUpdateTime} LIMIT 1") 33 + @Select("SELECT COUNT(*) FROM system_mail_template WHERE update_time > #{maxUpdateTime} LIMIT 1")
34 Long selectByMaxUpdateTime(Date maxUpdateTime); 34 Long selectByMaxUpdateTime(Date maxUpdateTime);
35 35
36 default MailTemplateDO selectOneByAccountId(Long accountId){ 36 default MailTemplateDO selectOneByAccountId(Long accountId){
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailTemplateRefreshConsumer.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.mq.consumer.mail;
  2 +
  3 +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
  4 +import cn.iocoder.yudao.module.system.mq.message.mail.MailTemplateRefreshMessage;
  5 +import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage;
  6 +import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.springframework.stereotype.Component;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +/**
  13 + * 针对 {@link MailTemplateRefreshMessage} 的消费者
  14 + *
  15 + * @author wangjingyi
  16 + */
  17 +@Component
  18 +@Slf4j
  19 +public class MailTemplateRefreshConsumer extends AbstractChannelMessageListener<MailTemplateRefreshMessage> {
  20 +
  21 + @Resource
  22 + private MailTemplateService mailTemplateService;
  23 +
  24 + @Override
  25 + public void onMessage(MailTemplateRefreshMessage message) {
  26 + log.info("[onMessage][收到 MailTemplate 刷新信息]");
  27 + mailTemplateService.initLocalCache();
  28 + }
  29 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailAccountRefreshMessage.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.mq.message.mail;
  2 +
  3 +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +
  7 +/**
  8 + * 邮箱账号的数据刷新 Message
  9 + *
  10 + * @author wangjingyi
  11 + */
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +public class MailAccountRefreshMessage extends AbstractChannelMessage {
  15 + @Override
  16 + public String getChannel() {
  17 + return "system.mail-account.refresh";
  18 + }
  19 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java
@@ -28,6 +28,16 @@ public class MailSendMessage extends AbstractStreamMessage { @@ -28,6 +28,16 @@ public class MailSendMessage extends AbstractStreamMessage {
28 @NotNull(message = "邮箱地址不能为空") 28 @NotNull(message = "邮箱地址不能为空")
29 private String from; 29 private String from;
30 /** 30 /**
  31 + * 用户名
  32 + */
  33 + @NotNull(message = "用户名不能为空")
  34 + private String username;
  35 + /**
  36 + * 密码
  37 + */
  38 + @NotNull(message = "密码不能为空")
  39 + private String password;
  40 + /**
31 * 邮箱模板编号 41 * 邮箱模板编号
32 */ 42 */
33 @NotNull(message = "邮箱模板编号不能为空") 43 @NotNull(message = "邮箱模板编号不能为空")
@@ -45,6 +55,20 @@ public class MailSendMessage extends AbstractStreamMessage { @@ -45,6 +55,20 @@ public class MailSendMessage extends AbstractStreamMessage {
45 * 内容 55 * 内容
46 */ 56 */
47 private String content; 57 private String content;
  58 + /**
  59 + * 主机
  60 + */
  61 + @NotNull(message = "host不能为空")
  62 + private String host;
  63 + /**
  64 + * 端口
  65 + */
  66 + @NotNull(message = "端口号不能为空")
  67 + private Integer port;
  68 + /**
  69 + * 是否开启 SSL
  70 + */
  71 + private Boolean sslEnable;
48 72
49 @Override 73 @Override
50 public String getStreamKey() { 74 public String getStreamKey() {
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailTemplateRefreshMessage.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.mq.message.mail;
  2 +
  3 +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +
  7 +/**
  8 + * 邮箱模板的数据刷新 Message
  9 + *
  10 + * @author wangjingyi
  11 + */
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +public class MailTemplateRefreshMessage extends AbstractChannelMessage {
  15 + @Override
  16 + public String getChannel() {
  17 + return "system.mail-template.refresh";
  18 + }
  19 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java
@@ -4,7 +4,9 @@ import cn.iocoder.yudao.framework.common.core.KeyValue; @@ -4,7 +4,9 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
4 import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; 4 import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
5 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; 5 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
6 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; 6 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
  7 +import cn.iocoder.yudao.module.system.mq.message.mail.MailAccountRefreshMessage;
7 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; 8 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
  9 +import cn.iocoder.yudao.module.system.mq.message.mail.MailTemplateRefreshMessage;
8 import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage; 10 import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage;
9 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; 11 import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
10 import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage; 12 import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage;
@@ -28,18 +30,18 @@ public class MailProducer { @@ -28,18 +30,18 @@ public class MailProducer {
28 private RedisMQTemplate redisMQTemplate; 30 private RedisMQTemplate redisMQTemplate;
29 31
30 /** 32 /**
31 - * 发送 {@link SmsChannelRefreshMessage} 消息 33 + * 发送 {@link MailTemplateRefreshMessage} 消息
32 */ 34 */
33 - public void sendMailChannelRefreshMessage() {  
34 - SmsChannelRefreshMessage message = new SmsChannelRefreshMessage(); 35 + public void sendMailTemplateRefreshMessage() {
  36 + MailTemplateRefreshMessage message = new MailTemplateRefreshMessage();
35 redisMQTemplate.send(message); 37 redisMQTemplate.send(message);
36 } 38 }
37 39
38 /** 40 /**
39 - * 发送 {@link SmsTemplateRefreshMessage} 消息 41 + * 发送 {@link MailTemplateRefreshMessage} 消息
40 */ 42 */
41 - public void sendMailTemplateRefreshMessage() {  
42 - SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage(); 43 + public void sendMailAccountRefreshMessage() {
  44 + MailAccountRefreshMessage message = new MailAccountRefreshMessage();
43 redisMQTemplate.send(message); 45 redisMQTemplate.send(message);
44 } 46 }
45 47
@@ -56,6 +58,11 @@ public class MailProducer { @@ -56,6 +58,11 @@ public class MailProducer {
56 MailSendMessage message = new MailSendMessage(); 58 MailSendMessage message = new MailSendMessage();
57 message.setContent(content); 59 message.setContent(content);
58 message.setFrom(mailAccountDO.getFrom()); 60 message.setFrom(mailAccountDO.getFrom());
  61 + message.setHost(mailAccountDO.getHost());
  62 + message.setPort(mailAccountDO.getPort());
  63 + message.setPassword(mailAccountDO.getPassword());
  64 + message.setUsername(mailAccountDO.getUsername());
  65 + message.setSslEnable(mailAccountDO.getSslEnable());
59 message.setTemplateCode(mailTemplateDO.getCode()); 66 message.setTemplateCode(mailTemplateDO.getCode());
60 message.setTitle(title); 67 message.setTitle(title);
61 message.setTos(tos); 68 message.setTos(tos);
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java
@@ -18,6 +18,11 @@ import java.util.List; @@ -18,6 +18,11 @@ import java.util.List;
18 public interface MailAccountService { 18 public interface MailAccountService {
19 19
20 /** 20 /**
  21 + * 初始化邮箱账号的本地缓存
  22 + */
  23 + void initLocalCache();
  24 +
  25 + /**
21 * 创建邮箱账号 26 * 创建邮箱账号
22 * 27 *
23 * @param createReqVO 邮箱账号信息 28 * @param createReqVO 邮箱账号信息
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java
@@ -46,5 +46,11 @@ public interface MailLogService { @@ -46,5 +46,11 @@ public interface MailLogService {
46 */ 46 */
47 Long createMailLog(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String from, String content, List<String> tos, String title, Boolean isSend); 47 Long createMailLog(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String from, String content, List<String> tos, String title, Boolean isSend);
48 48
49 - Long updateSmsSendResult(Long logId, String result); 49 + /**
  50 + * 更新邮件发送结果
  51 + *
  52 + * @param logId 发送日志Id
  53 + * @param result 发送结果 默认返回messageId
  54 + */
  55 + void updateMailSendResult(Long logId, String result);
50 } 56 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java
@@ -19,6 +19,9 @@ import java.util.Map; @@ -19,6 +19,9 @@ import java.util.Map;
19 */ 19 */
20 public interface MailTemplateService { 20 public interface MailTemplateService {
21 21
  22 + /**
  23 + * 初始化邮箱模版的本地缓存
  24 + */
22 void initLocalCache(); 25 void initLocalCache();
23 26
24 /** 27 /**
@@ -74,17 +77,10 @@ public interface MailTemplateService { @@ -74,17 +77,10 @@ public interface MailTemplateService {
74 MailTemplateDO getMailTemplateByCodeFromCache(String code); 77 MailTemplateDO getMailTemplateByCodeFromCache(String code);
75 78
76 /** 79 /**
77 - * 发送邮件  
78 - *  
79 - * @param mailReqVO 邮件发送信息  
80 - */  
81 - void sendMail(MailReqVO mailReqVO);  
82 -  
83 - /**  
84 * 邮件模版内容合成 80 * 邮件模版内容合成
85 * @param content 邮箱模版 81 * @param content 邮箱模版
86 * @param params 合成参数 82 * @param params 合成参数
87 * @return 83 * @return
88 */ 84 */
89 - String formateMailTemplateContent(String content, Map<String, String> params); 85 + String formatMailTemplateContent(String content, Map<String, String> params);
90 } 86 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailAccountServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.mail.impl; 1 package cn.iocoder.yudao.module.system.service.mail.impl;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountCreateReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountCreateReqVO;
5 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
6 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO;
7 import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; 9 import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; 10 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
9 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; 11 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
  12 +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
10 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; 13 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
11 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; 14 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
  15 +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
12 import cn.iocoder.yudao.module.system.service.mail.MailAccountService; 16 import cn.iocoder.yudao.module.system.service.mail.MailAccountService;
  17 +import lombok.extern.slf4j.Slf4j;
13 import org.springframework.stereotype.Service; 18 import org.springframework.stereotype.Service;
14 import org.springframework.validation.annotation.Validated; 19 import org.springframework.validation.annotation.Validated;
15 20
  21 +import javax.annotation.PostConstruct;
16 import javax.annotation.Resource; 22 import javax.annotation.Resource;
  23 +import java.util.Date;
17 import java.util.List; 24 import java.util.List;
  25 +import java.util.Map;
18 26
19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
20 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 28 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@@ -28,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @@ -28,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
28 */ 36 */
29 @Service 37 @Service
30 @Validated 38 @Validated
  39 +@Slf4j
31 public class MailAccountServiceImpl implements MailAccountService { 40 public class MailAccountServiceImpl implements MailAccountService {
32 41
33 @Resource 42 @Resource
@@ -36,26 +45,71 @@ public class MailAccountServiceImpl implements MailAccountService { @@ -36,26 +45,71 @@ public class MailAccountServiceImpl implements MailAccountService {
36 @Resource 45 @Resource
37 private MailTemplateMapper mailTemplateMapper; 46 private MailTemplateMapper mailTemplateMapper;
38 47
  48 + @Resource
  49 + private MailProducer mailProducer;
  50 +
  51 + /**
  52 + * 邮箱账号缓存
  53 + * key:邮箱账号编码 {@link MailAccountDO#getId()}
  54 + *
  55 + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
  56 + */
  57 + private volatile Map<Long, MailAccountDO> mailAccountCache;
  58 +
  59 + /**
  60 + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新
  61 + */
  62 + private volatile Date maxUpdateTime;
  63 +
  64 + @Override
  65 + @PostConstruct
  66 + public void initLocalCache() {
  67 + List<MailAccountDO> mailAccountDOList = this.loadMailAccountIfUpdate(maxUpdateTime);
  68 + if (CollUtil.isEmpty(mailAccountDOList)) {
  69 + return;
  70 + }
  71 +
  72 + // 写入缓存
  73 + mailAccountCache = CollectionUtils.convertMap(mailAccountDOList, MailAccountDO::getId);
  74 + maxUpdateTime = CollectionUtils.getMaxValue(mailAccountDOList, MailAccountDO::getUpdateTime);
  75 + log.info("[initLocalCache][初始化 MailAccount 数量为 {}]", mailAccountDOList.size());
  76 + }
  77 +
  78 + private List<MailAccountDO> loadMailAccountIfUpdate(Date maxUpdateTime) {
  79 + //第一步 判断是否需要更新
  80 + if(null == maxUpdateTime){ // 如果更新时间为空,说明 DB 一定有新数据
  81 + log.info("[loadMailAccountIfUpdate][首次加载全量账号信息]");
  82 + }else{ // 判断数据库中是否有更新的账号信息
  83 + if (mailAccountMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  84 + return null;
  85 + }
  86 + log.info("[loadMailAccountIfUpdate][增量加载全量账号信息]");
  87 + }
  88 + return mailAccountMapper.selectList();
  89 + }
  90 +
39 @Override 91 @Override
40 public Long create(MailAccountCreateReqVO createReqVO) { 92 public Long create(MailAccountCreateReqVO createReqVO) {
41 // username 要校验唯一 93 // username 要校验唯一
42 - validateMailAccountOnlyByUserName(createReqVO.getUsername()); 94 + this.validateMailAccountOnlyByUserName(createReqVO.getUsername());
43 MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(createReqVO); 95 MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(createReqVO);
44 mailAccountMapper.insert(mailAccountDO); 96 mailAccountMapper.insert(mailAccountDO);
45 97
46 // 更新 98 // 更新
  99 + mailProducer.sendMailAccountRefreshMessage();
47 return mailAccountDO.getId(); 100 return mailAccountDO.getId();
48 } 101 }
49 102
50 @Override 103 @Override
51 public void update(MailAccountUpdateReqVO updateReqVO) { 104 public void update(MailAccountUpdateReqVO updateReqVO) {
52 - // username 要校验唯一 TODO @wangjingyi:校验唯一的时候,需要排除掉自己  
53 - validateMailAccountExists(updateReqVO.getId()); 105 + // username 要校验唯一 TODO @wangjingyi:校验唯一的时候,需要排除掉自己 DONE
  106 + this.validateMailAccountOnlyByUserNameAndId(updateReqVO.getUsername(),updateReqVO.getId());
54 MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(updateReqVO); 107 MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(updateReqVO);
55 // 校验是否存在 108 // 校验是否存在
56 validateMailAccountExists(mailAccountDO.getId()); 109 validateMailAccountExists(mailAccountDO.getId());
57 110
58 // 更新 111 // 更新
  112 + mailProducer.sendMailAccountRefreshMessage();
59 mailAccountMapper.updateById(mailAccountDO); 113 mailAccountMapper.updateById(mailAccountDO);
60 } 114 }
61 115
@@ -65,9 +119,10 @@ public class MailAccountServiceImpl implements MailAccountService { @@ -65,9 +119,10 @@ public class MailAccountServiceImpl implements MailAccountService {
65 validateMailAccountExists(id); 119 validateMailAccountExists(id);
66 // 校验是否存在关联模版 120 // 校验是否存在关联模版
67 validateMailTemplateByAccountId(id); 121 validateMailTemplateByAccountId(id);
68 -  
69 // 删除 122 // 删除
70 mailAccountMapper.deleteById(id); 123 mailAccountMapper.deleteById(id);
  124 + // 更新
  125 + mailProducer.sendMailAccountRefreshMessage();
71 } 126 }
72 127
73 @Override 128 @Override
@@ -92,17 +147,26 @@ public class MailAccountServiceImpl implements MailAccountService { @@ -92,17 +147,26 @@ public class MailAccountServiceImpl implements MailAccountService {
92 } 147 }
93 148
94 private void validateMailAccountOnlyByUserName(String userName){ 149 private void validateMailAccountOnlyByUserName(String userName){
95 - MailAccountDO mailAccountDO = mailAccountMapper.selectByUserName(userName);  
96 - if (mailAccountDO != null) {  
97 - throw exception(MAIL_ACCOUNT_EXISTS);  
98 - } 150 + mailAccountCache.forEach((key,value)->{
  151 + if(value.getUsername().equals(userName)){
  152 + throw exception(MAIL_ACCOUNT_EXISTS);
  153 + }
  154 + });
  155 + }
  156 + private void validateMailAccountOnlyByUserNameAndId(String userName,Long id){
  157 + mailAccountCache.forEach((key , value)->{
  158 + if (value.getUsername().equals(userName)){
  159 + if (!key.equals(id)){
  160 + throw exception(MAIL_ACCOUNT_EXISTS);
  161 + }
  162 + }
  163 + });
99 } 164 }
100 -  
101 private void validateMailTemplateByAccountId(Long accountId){ 165 private void validateMailTemplateByAccountId(Long accountId){
102 MailTemplateDO mailTemplateDO = mailTemplateMapper.selectOneByAccountId(accountId); 166 MailTemplateDO mailTemplateDO = mailTemplateMapper.selectOneByAccountId(accountId);
103 if (mailTemplateDO != null) { 167 if (mailTemplateDO != null) {
104 - // TODO wangjingyi:MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS  
105 - throw exception(MAIL_RELATE_TEMPLATE_EXISTS); 168 + // TODO wangjingyi:MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS DONE
  169 + throw exception(MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS);
106 } 170 }
107 } 171 }
108 } 172 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailLogServiceImpl.java
@@ -8,13 +8,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; @@ -8,13 +8,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; 8 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
9 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper; 9 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper;
10 import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; 10 import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
11 -import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;  
12 import cn.iocoder.yudao.module.system.service.mail.MailLogService; 11 import cn.iocoder.yudao.module.system.service.mail.MailLogService;
13 import org.springframework.beans.factory.annotation.Autowired; 12 import org.springframework.beans.factory.annotation.Autowired;
14 import org.springframework.stereotype.Service; 13 import org.springframework.stereotype.Service;
15 import org.springframework.validation.annotation.Validated; 14 import org.springframework.validation.annotation.Validated;
16 15
17 -import java.sql.Timestamp;  
18 import java.util.Date; 16 import java.util.Date;
19 import java.util.List; 17 import java.util.List;
20 import java.util.Objects; 18 import java.util.Objects;
@@ -61,21 +59,14 @@ public class MailLogServiceImpl implements MailLogService { @@ -61,21 +59,14 @@ public class MailLogServiceImpl implements MailLogService {
61 return mailLogDO.getId(); 59 return mailLogDO.getId();
62 } 60 }
63 61
64 - // TODO @wangjingyi:不需要返回 id 呀 62 + // TODO @wangjingyi:不需要返回 id 呀 DONE
65 @Override 63 @Override
66 - public Long updateSmsSendResult(Long logId, String result) { 64 + public void updateMailSendResult(Long logId, String result) {
67 MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); 65 MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
68 logDOBuilder.id(logId); 66 logDOBuilder.id(logId);
69 logDOBuilder.sendResult(result); 67 logDOBuilder.sendResult(result);
70 MailLogDO mailLogDO = logDOBuilder.build(); 68 MailLogDO mailLogDO = logDOBuilder.build();
71 mailLogMapper.updateById(mailLogDO); 69 mailLogMapper.updateById(mailLogDO);
72 - return logId;  
73 } 70 }
74 71
75 - // TODO @wangjingyi:无用的方法,需要进行删除  
76 - public Long create(){  
77 - MailLogDO mailLogDO = new MailLogDO();  
78 - mailLogMapper.insert(mailLogDO);  
79 - return mailLogDO.getId();  
80 - }  
81 } 72 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailSendServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.mail.impl; 1 package cn.iocoder.yudao.module.system.service.mail.impl;
2 2
3 import cn.hutool.extra.mail.MailAccount; 3 import cn.hutool.extra.mail.MailAccount;
  4 +import cn.hutool.extra.mail.MailUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; 6 import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
6 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; 7 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
@@ -21,8 +22,7 @@ import java.util.List; @@ -21,8 +22,7 @@ import java.util.List;
21 import java.util.Map; 22 import java.util.Map;
22 23
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_EXISTS;  
25 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; 25 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
26 26
27 /** 27 /**
28 * 邮箱模版 服务实现类 28 * 邮箱模版 服务实现类
@@ -49,36 +49,47 @@ public class MailSendServiceImpl implements MailSendService { @@ -49,36 +49,47 @@ public class MailSendServiceImpl implements MailSendService {
49 49
50 @Override 50 @Override
51 public void sendMail(String templateCode, String from , String content , List<String> tos , String title) { 51 public void sendMail(String templateCode, String from , String content , List<String> tos , String title) {
52 - // TODO @@wangjingyi:发送的时候,参考下短信; 52 + // TODO @@wangjingyi:发送的时候,参考下短信;DONE
  53 + //校验邮箱模版是否合法
53 MailTemplateDO mailTemplateDO = this.checkMailTemplateValid(templateCode); 54 MailTemplateDO mailTemplateDO = this.checkMailTemplateValid(templateCode);
54 // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 55 // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
55 Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus()); 56 Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus());
56 - //查询账号信息  
57 - MailAccountDO mailAccountDO = mailAccountMapper.selectOne(  
58 - "from", from  
59 - ); 57 + //校验账号信息是否合法
  58 + MailAccountDO mailAccountDO = this.checkMailAccountValid(from);
60 Map<String , String> params = MailAccountConvert.INSTANCE.convertToMap(mailAccountDO , content); 59 Map<String , String> params = MailAccountConvert.INSTANCE.convertToMap(mailAccountDO , content);
61 - content = mailTemplateService.formateMailTemplateContent(mailTemplateDO.getContent(), params); 60 + content = mailTemplateService.formatMailTemplateContent(mailTemplateDO.getContent(), params);
62 Long sendLogId = mailLogService.createMailLog(mailAccountDO , mailTemplateDO , from , content , tos , title , isSend); 61 Long sendLogId = mailLogService.createMailLog(mailAccountDO , mailTemplateDO , from , content , tos , title , isSend);
63 62
64 // 后续功能 TODO :附件查询 63 // 后续功能 TODO :附件查询
65 //List<String> fileIds = mailSendVO.getFileIds(); 64 //List<String> fileIds = mailSendVO.getFileIds();
66 65
67 - //装载账号信息  
68 - MailAccount account = MailAccountConvert.INSTANCE.convertAccount(mailAccountDO);  
69 -  
70 // 发送 MQ 消息,异步执行发送短信 66 // 发送 MQ 消息,异步执行发送短信
71 if (isSend) { 67 if (isSend) {
72 mailProducer.sendMailSendMessage(mailAccountDO , mailTemplateDO ,content , tos , title , sendLogId); 68 mailProducer.sendMailSendMessage(mailAccountDO , mailTemplateDO ,content , tos , title , sendLogId);
73 } 69 }
74 } 70 }
75 71
  72 + private MailAccountDO checkMailAccountValid(String from) {
  73 + MailAccountDO mailAccountDO = mailAccountMapper.selectOneByFrom(from);
  74 + if(null == mailAccountDO){
  75 + throw exception(MAIL_ACCOUNT_NOT_EXISTS);
  76 + }
  77 + return mailAccountDO;
  78 + }
  79 +
76 @Override 80 @Override
77 public void doSendMail(MailSendMessage message) { 81 public void doSendMail(MailSendMessage message) {
78 - // TODO @wangjingyi:直接使用 hutool 发送,不要封装 mail client 哈,因为短信的客户端都是比较统一的  
79 - //MailClient mailClient = mailClientFactory.getMailClient();  
80 - //String result = mailClient.sendMail(message.getFrom() , message.getContent() , message.getTitle() , message.getTos());  
81 - //mailLogService.updateSmsSendResult(message.getLogId() , result); 82 + // TODO @wangjingyi:直接使用 hutool 发送,不要封装 mail client 哈,因为短信的客户端都是比较统一的 DONE
  83 + //装载账号信息
  84 + MailAccount account = MailAccountConvert.INSTANCE.convertAccount(message);
  85 + //发送邮件
  86 + try{
  87 + String messageId = MailUtil.send(account,message.getTos(),message.getTitle(),message.getContent(),false,null);
  88 + mailLogService.updateMailSendResult(message.getLogId() , messageId);
  89 + }catch (Exception e){
  90 + mailLogService.updateMailSendResult(message.getLogId() , e.getMessage());
  91 + }
  92 +
82 } 93 }
83 94
84 private MailTemplateDO checkMailTemplateValid(String templateCode) { 95 private MailTemplateDO checkMailTemplateValid(String templateCode) {
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/impl/MailTemplateServiceImpl.java
@@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; @@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
18 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; 18 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
19 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; 19 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
20 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; 20 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
  21 +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
21 import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; 22 import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
22 import lombok.extern.slf4j.Slf4j; 23 import lombok.extern.slf4j.Slf4j;
23 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
@@ -48,59 +49,53 @@ public class MailTemplateServiceImpl implements MailTemplateService { @@ -48,59 +49,53 @@ public class MailTemplateServiceImpl implements MailTemplateService {
48 @Resource 49 @Resource
49 private MailTemplateMapper mailTemplateMapper; 50 private MailTemplateMapper mailTemplateMapper;
50 @Resource 51 @Resource
51 - private MailAccountMapper mailAccountMapper;  
52 -  
53 - private volatile List<MailTemplateDO> mailTemplateDOList; 52 + private MailProducer mailProducer;
54 53
55 /** 54 /**
56 * 邮件模板缓存 55 * 邮件模板缓存
57 - * key:邮箱模板编码 {@link MailTemplateDO#getCode()} 56 + * key:邮箱模板编码 {@link MailTemplateDO#getId()}
58 * 57 *
59 * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 58 * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
60 */ 59 */
61 - private volatile Map<String, MailTemplateDO> mailTemplateCache; 60 + private volatile Map<Long, MailTemplateDO> mailTemplateCache;
62 61
63 private volatile Date maxUpdateTime; 62 private volatile Date maxUpdateTime;
64 63
65 - // TODO @wangjingyi:参考下别的模块的 initLocalCache 的实现 64 + // TODO @wangjingyi:参考下别的模块的 initLocalCache 的实现 DONE
66 @Override 65 @Override
67 @PostConstruct 66 @PostConstruct
68 public void initLocalCache() { 67 public void initLocalCache() {
69 - if(maxUpdateTime == null){  
70 - mailTemplateDOList = mailTemplateMapper.selectList();  
71 - }else{  
72 - if(mailTemplateMapper.selectByMaxUpdateTime(maxUpdateTime)<=0){  
73 - return;  
74 - }  
75 - } 68 + List<MailTemplateDO> mailTemplateDOList = this.loadMailTemplateIfUpdate(maxUpdateTime);
76 if (CollUtil.isEmpty(mailTemplateDOList)) { 69 if (CollUtil.isEmpty(mailTemplateDOList)) {
77 return; 70 return;
78 } 71 }
79 72
80 // 写入缓存 73 // 写入缓存
81 - mailTemplateCache = CollectionUtils.convertMap(mailTemplateDOList, MailTemplateDO::getCode); 74 + mailTemplateCache = CollectionUtils.convertMap(mailTemplateDOList, MailTemplateDO::getId);
82 maxUpdateTime = CollectionUtils.getMaxValue(mailTemplateDOList, MailTemplateDO::getUpdateTime); 75 maxUpdateTime = CollectionUtils.getMaxValue(mailTemplateDOList, MailTemplateDO::getUpdateTime);
83 log.info("[initLocalCache][初始化 mailTemplate 数量为 {}]", mailTemplateDOList.size()); 76 log.info("[initLocalCache][初始化 mailTemplate 数量为 {}]", mailTemplateDOList.size());
84 } 77 }
85 78
86 @Override 79 @Override
87 public Long create(MailTemplateCreateReqVO createReqVO) { 80 public Long create(MailTemplateCreateReqVO createReqVO) {
88 - // code 要校验唯一  
89 - // TODO @wangjingyi:参考下我在 account 给的唯一校验的说明。  
90 - this.validateMailTemplateOnlyByCode(createReqVO.getCode()); 81 + //要校验存在
  82 + this.validateMailTemplateExists(createReqVO.getId());
91 MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(createReqVO); 83 MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(createReqVO);
92 mailTemplateMapper.insert(mailTemplateDO); 84 mailTemplateMapper.insert(mailTemplateDO);
93 - // TODO @wangjingyi:mq 更新 85 + // TODO @wangjingyi:mq 更新 DONE
  86 + mailProducer.sendMailTemplateRefreshMessage();
94 return mailTemplateDO.getId(); 87 return mailTemplateDO.getId();
95 } 88 }
96 89
97 @Override 90 @Override
98 public void update(@Valid MailTemplateUpdateReqVO updateReqVO) { 91 public void update(@Valid MailTemplateUpdateReqVO updateReqVO) {
99 - // 校验是否存在  
100 - this.validateMailTemplateExists(updateReqVO.getId()); 92 + // 校验是否唯一
  93 + // TODO @wangjingyi:参考下我在 account 给的唯一校验的说明。
  94 + this.validateMailTemplateOnlyByCode(updateReqVO.getId(),updateReqVO.getCode());
101 MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO); 95 MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO);
102 mailTemplateMapper.updateById(mailTemplateDO); 96 mailTemplateMapper.updateById(mailTemplateDO);
103 - // TODO @wangjingyi:mq 更新 97 + // TODO @wangjingyi:mq 更新 DONE
  98 + mailProducer.sendMailTemplateRefreshMessage();
104 } 99 }
105 100
106 @Override 101 @Override
@@ -108,7 +103,8 @@ public class MailTemplateServiceImpl implements MailTemplateService { @@ -108,7 +103,8 @@ public class MailTemplateServiceImpl implements MailTemplateService {
108 // 校验是否存在 103 // 校验是否存在
109 this.validateMailTemplateExists(id); 104 this.validateMailTemplateExists(id);
110 mailTemplateMapper.deleteById(id); 105 mailTemplateMapper.deleteById(id);
111 - // TODO @wangjingyi:mq 更新 106 + // TODO @wangjingyi:mq 更新 DONE
  107 + mailProducer.sendMailTemplateRefreshMessage();
112 } 108 }
113 109
114 @Override 110 @Override
@@ -127,43 +123,45 @@ public class MailTemplateServiceImpl implements MailTemplateService { @@ -127,43 +123,45 @@ public class MailTemplateServiceImpl implements MailTemplateService {
127 return mailTemplateCache.get(code); 123 return mailTemplateCache.get(code);
128 } 124 }
129 125
  126 + // TODO @@wangjingyi:单词拼写错误 DONE
130 @Override 127 @Override
131 - public void sendMail(MailReqVO mailReqVO) {  
132 - // TODO @@wangjingyi:发送的时候,参考下短信;  
133 - MailTemplateDO mailTemplateDO = mailTemplateMapper.selectById(mailReqVO.getTemplateId());  
134 - //查询账号信息  
135 - MailAccountDO mailAccountDO = mailAccountMapper.selectOne(  
136 - "from", mailReqVO.getFrom()  
137 - );  
138 - String content = mailReqVO.getContent();  
139 - Map<String , String> params = MailAccountConvert.INSTANCE.convertToMap(mailAccountDO , content);  
140 - content = StrUtil.format(mailTemplateDO.getContent(), params);  
141 -  
142 - // 后续功能 TODO :附件查询  
143 - //List<String> fileIds = mailSendVO.getFileIds();  
144 -  
145 - //装载账号信息  
146 - MailAccount account = MailAccountConvert.INSTANCE.convertAccount(mailAccountDO);  
147 -  
148 - //发送  
149 - MailUtil.send(account , mailReqVO.getTos() , mailReqVO.getTitle() , content , false);  
150 - }  
151 -  
152 - // TODO @@wangjingyi:单词拼写错误  
153 - @Override  
154 - public String formateMailTemplateContent(String content, Map<String, String> params) { 128 + public String formatMailTemplateContent(String content, Map<String, String> params) {
155 return StrUtil.format(content, params); 129 return StrUtil.format(content, params);
156 } 130 }
157 131
158 private void validateMailTemplateExists(Long id) { 132 private void validateMailTemplateExists(Long id) {
159 - if (mailTemplateMapper.selectById(id) == null) { 133 + if (mailTemplateCache.get(id) == null) {
160 throw exception(MAIL_TEMPLATE_NOT_EXISTS); 134 throw exception(MAIL_TEMPLATE_NOT_EXISTS);
161 } 135 }
162 } 136 }
163 137
164 - private void validateMailTemplateOnlyByCode(String code){  
165 - if (mailTemplateMapper.selectOneByCode(code) != null) {  
166 - throw exception(MAIL_TEMPLATE_EXISTS); 138 + private void validateMailTemplateOnlyByCode(Long id ,String code){
  139 + mailTemplateCache.forEach((key,value)->{
  140 + if (value.getCode().equals(code)){
  141 + if (!key.equals(id)){
  142 + throw exception(MAIL_TEMPLATE_EXISTS);
  143 + }
  144 + }
  145 + });
  146 + }
  147 + /**
  148 + * 如果邮件模板发生变化,从数据库中获取最新的全量邮件模板。
  149 + * 如果未发生变化,则返回空
  150 + *
  151 + * @param maxUpdateTime 当前邮件模板的最大更新时间
  152 + * @return 邮件模板列表
  153 + */
  154 + private List<MailTemplateDO> loadMailTemplateIfUpdate(Date maxUpdateTime) {
  155 + // 第一步,判断是否要更新。
  156 + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
  157 + log.info("[loadMailTemplateIfUpdate][首次加载全量邮件模板]");
  158 + } else { // 判断数据库中是否有更新的邮件模板
  159 + if (mailTemplateMapper.selectByMaxUpdateTime(maxUpdateTime) == 0) {
  160 + return null;
  161 + }
  162 + log.info("[loadSmsTemplateIfUpdate][增量加载全量邮件模板]");
167 } 163 }
  164 + // 第二步,如果有更新,则从数据库加载所有邮件模板
  165 + return mailTemplateMapper.selectList();
168 } 166 }
169 } 167 }