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

pull/2/head
wangjingyi 2022-05-05 03:06:00 +08:00
parent ea92b84121
commit 8bc5254e30
23 changed files with 318 additions and 132 deletions

View File

@ -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, "存在关联邮箱模版");
} }

View File

@ -57,7 +57,7 @@ public class MailAccountController {
} }
// TODO @wangjingyigetMailAccount 和 getMailAccountPage 这两个接口,定义一个对应的 Resp 类哈,参考别的模块。主要不要返回 password 字段。 // TODO @wangjingyigetMailAccount 和 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 @wangjingyigetSimpleMailAccountList 单独定义一个类只返回精简的信息idfrom 即可。像密码之类都是敏感信息,不应该返回 // TODO @wangjingyigetSimpleMailAccountList 单独定义一个类只返回精简的信息idfrom 即可。像密码之类都是敏感信息,不应该返回 DONE
@GetMapping("/list-all-simple") @GetMapping("/list-all-simple")
@ApiOperation(value = "获得邮箱账号精简列表") @ApiOperation(value = "获得邮箱账号精简列表")

View File

@ -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 @wangjingyiprivate // TODO @wangjingyiprivate 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);
}
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -0,0 +1,4 @@
package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template;
public class MailTemplateRespVO extends MailTemplateBaseVO{
}

View File

@ -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())

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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){

View File

@ -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();
}
}

View File

@ -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";
}
}

View File

@ -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() {

View File

@ -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";
}
}

View File

@ -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);

View File

@ -17,6 +17,11 @@ import java.util.List;
*/ */
public interface MailAccountService { public interface MailAccountService {
/**
*
*/
void initLocalCache();
/** /**
* *
* *

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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); 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);
}
}
});
} }
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 wangjingyiMAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS // TODO wangjingyiMAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS DONE
throw exception(MAIL_RELATE_TEMPLATE_EXISTS); throw exception(MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS);
} }
} }
} }

View File

@ -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();
}
} }

View File

@ -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) {

View File

@ -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 @wangjingyimq 更新 // TODO @wangjingyimq 更新 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 @wangjingyimq 更新 // TODO @wangjingyimq 更新 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 @wangjingyimq 更新 // TODO @wangjingyimq 更新 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)->{
throw exception(MAIL_TEMPLATE_EXISTS); if (value.getCode().equals(code)){
if (!key.equals(id)){
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();
} }
} }