邮件模块 添加邮箱账号缓存 修改校验方式
parent
ea92b84121
commit
8bc5254e30
|
@ -130,6 +130,6 @@ public interface ErrorCodeConstants {
|
|||
// ========== 邮箱模版 1002021000 ==========
|
||||
ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1002021000 , "邮箱模版不存在");
|
||||
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 字段。
|
||||
// 一个可以的做法,是 MailAccountBaseVO 不返回 password,然后 MailAccountCreateReqVO、MailAccountUpdateReqVO 添加这个字段
|
||||
// 一个可以的做法,是 MailAccountBaseVO 不返回 password,然后 MailAccountCreateReqVO、MailAccountUpdateReqVO 添加这个字段 DONE
|
||||
|
||||
@GetMapping("/get")
|
||||
@ApiOperation("获得邮箱账号")
|
||||
|
@ -76,7 +76,7 @@ public class MailAccountController {
|
|||
return success(MailAccountConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
// TODO @wangjingyi:getSimpleMailAccountList 单独定义一个类,只返回精简的信息,id,from 即可。像密码之类都是敏感信息,不应该返回
|
||||
// TODO @wangjingyi:getSimpleMailAccountList 单独定义一个类,只返回精简的信息,id,from 即可。像密码之类都是敏感信息,不应该返回 DONE
|
||||
|
||||
@GetMapping("/list-all-simple")
|
||||
@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.PageResult;
|
||||
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.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.controller.admin.mail.vo.template.*;
|
||||
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.service.mail.MailTemplateService;
|
||||
|
@ -29,9 +26,9 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|||
@RequestMapping("/system/mail-template")
|
||||
public class MailTemplateController {
|
||||
|
||||
// TODO @wangjingyi:private
|
||||
// TODO @wangjingyi:private DONE
|
||||
@Autowired
|
||||
MailTemplateService mailTempleService;
|
||||
private MailTemplateService mailTempleService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@ApiOperation("创建邮箱模版")
|
||||
|
@ -56,13 +53,13 @@ public class MailTemplateController {
|
|||
return success(true);
|
||||
}
|
||||
|
||||
// TODO @wangjingyi:下面几个 VO 也参考我在 account 给的建议
|
||||
// TODO @wangjingyi:下面几个 VO 也参考我在 account 给的建议 DONE RespVO中需要BaseVO 中哪些字段
|
||||
|
||||
@GetMapping("/get")
|
||||
@ApiOperation("获得邮箱模版")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@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);
|
||||
return success(MailTemplateConvert.INSTANCE.convert(mailTemplateDO));
|
||||
}
|
||||
|
@ -70,25 +67,17 @@ public class MailTemplateController {
|
|||
@GetMapping("/page")
|
||||
@ApiOperation("获得邮箱模版分页")
|
||||
@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);
|
||||
return success(MailTemplateConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/list-all-simple")
|
||||
@ApiOperation(value = "获得邮箱模版精简列表")
|
||||
public CommonResult<List<MailTemplateBaseVO>> getSimpleTemplateList() {
|
||||
public CommonResult<List<MailTemplateRespVO>> getSimpleTemplateList() {
|
||||
List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
|
||||
// 排序后,返回给前端
|
||||
list.sort(Comparator.comparing(MailTemplateDO::getId));
|
||||
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格式")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty(value = "密码",required = true,example = "123456")
|
||||
@NotNull(message = "密码必填")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "网站",required = true,example = "www.iocoder.cn")
|
||||
@NotNull(message = "网站必填")
|
||||
private String host;
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
package cn.iocoder.yudao.module.system.controller.admin.mail.vo.account;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("管理后台 - 邮箱账号创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
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 = "编号不能为空")
|
||||
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.module.system.controller.admin.mail.vo.account.MailAccountBaseVO;
|
||||
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.factory.Mappers;
|
||||
|
||||
|
@ -23,7 +24,7 @@ public interface MailAccountConvert {
|
|||
|
||||
List<MailAccountBaseVO> convertList02(List<MailAccountDO> list);
|
||||
|
||||
default MailAccount convertAccount(MailAccountDO mailAccountDO){
|
||||
default MailAccount convertAccount(MailSendMessage mailAccountDO){
|
||||
return new MailAccount()
|
||||
.setHost(mailAccountDO.getHost())
|
||||
.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.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 org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
@ -14,9 +15,9 @@ public interface MailTemplateConvert {
|
|||
|
||||
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.MailTemplateDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Mapper
|
||||
public interface MailAccountMapper extends BaseMapperX<MailAccountDO> {
|
||||
|
@ -25,4 +28,18 @@ public interface MailAccountMapper extends BaseMapperX<MailAccountDO> {
|
|||
return selectOne(new QueryWrapperX<MailAccountDO>()
|
||||
.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));
|
||||
};
|
||||
|
||||
@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);
|
||||
|
||||
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 = "邮箱地址不能为空")
|
||||
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;
|
||||
/**
|
||||
* 主机
|
||||
*/
|
||||
@NotNull(message = "host不能为空")
|
||||
private String host;
|
||||
/**
|
||||
* 端口
|
||||
*/
|
||||
@NotNull(message = "端口号不能为空")
|
||||
private Integer port;
|
||||
/**
|
||||
* 是否开启 SSL
|
||||
*/
|
||||
private Boolean sslEnable;
|
||||
|
||||
@Override
|
||||
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.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.mq.message.mail.MailAccountRefreshMessage;
|
||||
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.SmsSendMessage;
|
||||
import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage;
|
||||
|
@ -28,18 +30,18 @@ public class MailProducer {
|
|||
private RedisMQTemplate redisMQTemplate;
|
||||
|
||||
/**
|
||||
* 发送 {@link SmsChannelRefreshMessage} 消息
|
||||
* 发送 {@link MailTemplateRefreshMessage} 消息
|
||||
*/
|
||||
public void sendMailChannelRefreshMessage() {
|
||||
SmsChannelRefreshMessage message = new SmsChannelRefreshMessage();
|
||||
public void sendMailTemplateRefreshMessage() {
|
||||
MailTemplateRefreshMessage message = new MailTemplateRefreshMessage();
|
||||
redisMQTemplate.send(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 {@link SmsTemplateRefreshMessage} 消息
|
||||
* 发送 {@link MailTemplateRefreshMessage} 消息
|
||||
*/
|
||||
public void sendMailTemplateRefreshMessage() {
|
||||
SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage();
|
||||
public void sendMailAccountRefreshMessage() {
|
||||
MailAccountRefreshMessage message = new MailAccountRefreshMessage();
|
||||
redisMQTemplate.send(message);
|
||||
}
|
||||
|
||||
|
@ -56,6 +58,11 @@ public class MailProducer {
|
|||
MailSendMessage message = new MailSendMessage();
|
||||
message.setContent(content);
|
||||
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.setTitle(title);
|
||||
message.setTos(tos);
|
||||
|
|
|
@ -17,6 +17,11 @@ import java.util.List;
|
|||
*/
|
||||
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 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 {
|
||||
|
||||
/**
|
||||
* 初始化邮箱模版的本地缓存
|
||||
*/
|
||||
void initLocalCache();
|
||||
|
||||
/**
|
||||
|
@ -73,18 +76,11 @@ public interface MailTemplateService {
|
|||
*/
|
||||
MailTemplateDO getMailTemplateByCodeFromCache(String code);
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
*
|
||||
* @param mailReqVO 邮件发送信息
|
||||
*/
|
||||
void sendMail(MailReqVO mailReqVO);
|
||||
|
||||
/**
|
||||
* 邮件模版内容合成
|
||||
* @param content 邮箱模版
|
||||
* @param params 合成参数
|
||||
* @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;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
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.MailAccountPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
|
||||
import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
|
||||
import cn.iocoder.yudao.module.system.service.mail.MailAccountService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
@ -28,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
|||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class MailAccountServiceImpl implements MailAccountService {
|
||||
|
||||
@Resource
|
||||
|
@ -36,26 +45,71 @@ public class MailAccountServiceImpl implements MailAccountService {
|
|||
@Resource
|
||||
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
|
||||
public Long create(MailAccountCreateReqVO createReqVO) {
|
||||
// username 要校验唯一
|
||||
validateMailAccountOnlyByUserName(createReqVO.getUsername());
|
||||
this.validateMailAccountOnlyByUserName(createReqVO.getUsername());
|
||||
MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(createReqVO);
|
||||
mailAccountMapper.insert(mailAccountDO);
|
||||
|
||||
// 更新
|
||||
mailProducer.sendMailAccountRefreshMessage();
|
||||
return mailAccountDO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(MailAccountUpdateReqVO updateReqVO) {
|
||||
// username 要校验唯一 TODO @wangjingyi:校验唯一的时候,需要排除掉自己
|
||||
validateMailAccountExists(updateReqVO.getId());
|
||||
// username 要校验唯一 TODO @wangjingyi:校验唯一的时候,需要排除掉自己 DONE
|
||||
this.validateMailAccountOnlyByUserNameAndId(updateReqVO.getUsername(),updateReqVO.getId());
|
||||
MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(updateReqVO);
|
||||
// 校验是否存在
|
||||
validateMailAccountExists(mailAccountDO.getId());
|
||||
|
||||
// 更新
|
||||
mailProducer.sendMailAccountRefreshMessage();
|
||||
mailAccountMapper.updateById(mailAccountDO);
|
||||
}
|
||||
|
||||
|
@ -65,9 +119,10 @@ public class MailAccountServiceImpl implements MailAccountService {
|
|||
validateMailAccountExists(id);
|
||||
// 校验是否存在关联模版
|
||||
validateMailTemplateByAccountId(id);
|
||||
|
||||
// 删除
|
||||
mailAccountMapper.deleteById(id);
|
||||
// 更新
|
||||
mailProducer.sendMailAccountRefreshMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,17 +147,26 @@ public class MailAccountServiceImpl implements MailAccountService {
|
|||
}
|
||||
|
||||
private void validateMailAccountOnlyByUserName(String userName){
|
||||
MailAccountDO mailAccountDO = mailAccountMapper.selectByUserName(userName);
|
||||
if (mailAccountDO != null) {
|
||||
throw exception(MAIL_ACCOUNT_EXISTS);
|
||||
}
|
||||
mailAccountCache.forEach((key,value)->{
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void validateMailTemplateByAccountId(Long accountId){
|
||||
MailTemplateDO mailTemplateDO = mailTemplateMapper.selectOneByAccountId(accountId);
|
||||
if (mailTemplateDO != null) {
|
||||
// TODO wangjingyi:MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS
|
||||
throw exception(MAIL_RELATE_TEMPLATE_EXISTS);
|
||||
// TODO wangjingyi:MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS DONE
|
||||
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.mysql.mail.MailLogMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
|
||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
|
||||
import cn.iocoder.yudao.module.system.service.mail.MailLogService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -61,21 +59,14 @@ public class MailLogServiceImpl implements MailLogService {
|
|||
return mailLogDO.getId();
|
||||
}
|
||||
|
||||
// TODO @wangjingyi:不需要返回 id 呀
|
||||
// TODO @wangjingyi:不需要返回 id 呀 DONE
|
||||
@Override
|
||||
public Long updateSmsSendResult(Long logId, String result) {
|
||||
public void updateMailSendResult(Long logId, String result) {
|
||||
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
|
||||
logDOBuilder.id(logId);
|
||||
logDOBuilder.sendResult(result);
|
||||
MailLogDO mailLogDO = logDOBuilder.build();
|
||||
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;
|
||||
|
||||
import cn.hutool.extra.mail.MailAccount;
|
||||
import cn.hutool.extra.mail.MailUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
|
@ -21,8 +22,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_EXISTS;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 邮箱模版 服务实现类
|
||||
|
@ -49,36 +49,47 @@ public class MailSendServiceImpl implements MailSendService {
|
|||
|
||||
@Override
|
||||
public void sendMail(String templateCode, String from , String content , List<String> tos , String title) {
|
||||
// TODO @@wangjingyi:发送的时候,参考下短信;
|
||||
// TODO @@wangjingyi:发送的时候,参考下短信;DONE
|
||||
//校验邮箱模版是否合法
|
||||
MailTemplateDO mailTemplateDO = this.checkMailTemplateValid(templateCode);
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus());
|
||||
//查询账号信息
|
||||
MailAccountDO mailAccountDO = mailAccountMapper.selectOne(
|
||||
"from", from
|
||||
);
|
||||
//校验账号信息是否合法
|
||||
MailAccountDO mailAccountDO = this.checkMailAccountValid(from);
|
||||
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);
|
||||
|
||||
// 后续功能 TODO :附件查询
|
||||
//List<String> fileIds = mailSendVO.getFileIds();
|
||||
|
||||
//装载账号信息
|
||||
MailAccount account = MailAccountConvert.INSTANCE.convertAccount(mailAccountDO);
|
||||
|
||||
// 发送 MQ 消息,异步执行发送短信
|
||||
if (isSend) {
|
||||
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
|
||||
public void doSendMail(MailSendMessage message) {
|
||||
// TODO @wangjingyi:直接使用 hutool 发送,不要封装 mail client 哈,因为短信的客户端都是比较统一的
|
||||
//MailClient mailClient = mailClientFactory.getMailClient();
|
||||
//String result = mailClient.sendMail(message.getFrom() , message.getContent() , message.getTitle() , message.getTos());
|
||||
//mailLogService.updateSmsSendResult(message.getLogId() , result);
|
||||
// TODO @wangjingyi:直接使用 hutool 发送,不要封装 mail client 哈,因为短信的客户端都是比较统一的 DONE
|
||||
//装载账号信息
|
||||
MailAccount account = MailAccountConvert.INSTANCE.convertAccount(message);
|
||||
//发送邮件
|
||||
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) {
|
||||
|
|
|
@ -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.mysql.mail.MailAccountMapper;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -48,59 +49,53 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
|||
@Resource
|
||||
private MailTemplateMapper mailTemplateMapper;
|
||||
@Resource
|
||||
private MailAccountMapper mailAccountMapper;
|
||||
|
||||
private volatile List<MailTemplateDO> mailTemplateDOList;
|
||||
private MailProducer mailProducer;
|
||||
|
||||
/**
|
||||
* 邮件模板缓存
|
||||
* key:邮箱模板编码 {@link MailTemplateDO#getCode()}
|
||||
* key:邮箱模板编码 {@link MailTemplateDO#getId()}
|
||||
*
|
||||
* 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
|
||||
*/
|
||||
private volatile Map<String, MailTemplateDO> mailTemplateCache;
|
||||
private volatile Map<Long, MailTemplateDO> mailTemplateCache;
|
||||
|
||||
private volatile Date maxUpdateTime;
|
||||
|
||||
// TODO @wangjingyi:参考下别的模块的 initLocalCache 的实现
|
||||
// TODO @wangjingyi:参考下别的模块的 initLocalCache 的实现 DONE
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void initLocalCache() {
|
||||
if(maxUpdateTime == null){
|
||||
mailTemplateDOList = mailTemplateMapper.selectList();
|
||||
}else{
|
||||
if(mailTemplateMapper.selectByMaxUpdateTime(maxUpdateTime)<=0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
List<MailTemplateDO> mailTemplateDOList = this.loadMailTemplateIfUpdate(maxUpdateTime);
|
||||
if (CollUtil.isEmpty(mailTemplateDOList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 写入缓存
|
||||
mailTemplateCache = CollectionUtils.convertMap(mailTemplateDOList, MailTemplateDO::getCode);
|
||||
mailTemplateCache = CollectionUtils.convertMap(mailTemplateDOList, MailTemplateDO::getId);
|
||||
maxUpdateTime = CollectionUtils.getMaxValue(mailTemplateDOList, MailTemplateDO::getUpdateTime);
|
||||
log.info("[initLocalCache][初始化 mailTemplate 数量为 {}]", mailTemplateDOList.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long create(MailTemplateCreateReqVO createReqVO) {
|
||||
// code 要校验唯一
|
||||
// TODO @wangjingyi:参考下我在 account 给的唯一校验的说明。
|
||||
this.validateMailTemplateOnlyByCode(createReqVO.getCode());
|
||||
//要校验存在
|
||||
this.validateMailTemplateExists(createReqVO.getId());
|
||||
MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(createReqVO);
|
||||
mailTemplateMapper.insert(mailTemplateDO);
|
||||
// TODO @wangjingyi:mq 更新
|
||||
// TODO @wangjingyi:mq 更新 DONE
|
||||
mailProducer.sendMailTemplateRefreshMessage();
|
||||
return mailTemplateDO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
mailTemplateMapper.updateById(mailTemplateDO);
|
||||
// TODO @wangjingyi:mq 更新
|
||||
// TODO @wangjingyi:mq 更新 DONE
|
||||
mailProducer.sendMailTemplateRefreshMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,7 +103,8 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
|||
// 校验是否存在
|
||||
this.validateMailTemplateExists(id);
|
||||
mailTemplateMapper.deleteById(id);
|
||||
// TODO @wangjingyi:mq 更新
|
||||
// TODO @wangjingyi:mq 更新 DONE
|
||||
mailProducer.sendMailTemplateRefreshMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,43 +123,45 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
|||
return mailTemplateCache.get(code);
|
||||
}
|
||||
|
||||
// TODO @@wangjingyi:单词拼写错误 DONE
|
||||
@Override
|
||||
public void sendMail(MailReqVO mailReqVO) {
|
||||
// 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) {
|
||||
public String formatMailTemplateContent(String content, Map<String, String> params) {
|
||||
return StrUtil.format(content, params);
|
||||
}
|
||||
|
||||
private void validateMailTemplateExists(Long id) {
|
||||
if (mailTemplateMapper.selectById(id) == null) {
|
||||
if (mailTemplateCache.get(id) == null) {
|
||||
throw exception(MAIL_TEMPLATE_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMailTemplateOnlyByCode(String code){
|
||||
if (mailTemplateMapper.selectOneByCode(code) != null) {
|
||||
throw exception(MAIL_TEMPLATE_EXISTS);
|
||||
private void validateMailTemplateOnlyByCode(Long id ,String code){
|
||||
mailTemplateCache.forEach((key,value)->{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue