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