邮箱模块:完善 log 相关表结构

pull/2/head
YunaiV 2023-01-26 01:57:57 +08:00
parent afced9d420
commit f9ab45df18
13 changed files with 141 additions and 148 deletions

View File

@ -106,6 +106,10 @@
<artifactId>yudao-spring-boot-starter-captcha</artifactId> <artifactId>yudao-spring-boot-starter-captcha</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,14 @@
### 请求 /system/mail-template/send-mail 接口 => 成功
POST {{baseUrl}}/system/mail-template/send-mail
Authorization: Bearer {{token}}
Content-Type: application/json
tenant-id: {{adminTenentId}}
{
"templateCode": "test_01",
"mail": "7685413@qq.com",
"templateParams": {
"key01": "value01",
"key02": "value02"
}
}

View File

@ -3,8 +3,10 @@ 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.template.*; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.*;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSendReqVO;
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.MailSendService;
import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
@ -25,6 +27,8 @@ public class MailTemplateController {
@Resource @Resource
private MailTemplateService mailTempleService; private MailTemplateService mailTempleService;
@Resource
private MailSendService mailSendService;
@PostMapping("/create") @PostMapping("/create")
@ApiOperation("创建邮件模版") @ApiOperation("创建邮件模版")
@ -73,4 +77,13 @@ public class MailTemplateController {
List<MailTemplateDO> list = mailTempleService.getMailTemplateList(); List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
return success(MailTemplateConvert.INSTANCE.convertList02(list)); return success(MailTemplateConvert.INSTANCE.convertList02(list));
} }
@PostMapping("/send-mail")
@ApiOperation("发送短信")
@PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
return success(mailSendService.sendSingleMailToAdmin(sendReqVO.getMail(), null,
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
}
} }

View File

@ -1,37 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.mail.vo.send;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import java.util.List;
@ApiModel("管理后台 - 邮件发送 Req VO")
@Data
public class MailReqVO { // TODO @wangjingqi1, 不用空格2应该只要传递 templateCode、参数就好title、from、content、附件应该都是参数里的
@ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com")
@NotNull(message = "邮箱账号不能为空")
@Email(message = "邮箱账号格式错误")
private String from;
@ApiModelProperty(value = "标题",example = "标题")
private String title;
@ApiModelProperty(value = "内容",example = "内容")
private String content;
@ApiModelProperty(value = "邮箱模版id",example = "1024")
@NotNull(message = "邮箱模版id不能为空")
private Integer templateId;
@ApiModelProperty(value = "收件人",required = true,example = "yudaoyuanma@123.com")
@NotNull(message = "收件人不能为空")
private List<String> tos;
@ApiModelProperty(value = "附件",example = "附件编码")
private List<String> fileIds;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Map;
@ApiModel("管理后台 - 邮件发送 Req VO")
@Data
public class MailTemplateSendReqVO {
@ApiModelProperty(value = "接收邮箱", required = true, example = "7685413@qq.com")
@NotEmpty(message = "接收邮箱不能为空")
private String mail;
@ApiModelProperty(value = "模板编码", required = true, example = "test_01")
@NotNull(message = "模板编码不能为空")
private String templateCode;
@ApiModelProperty(value = "模板参数")
private Map<String, Object> templateParams;
}

View File

@ -33,7 +33,7 @@ public interface MailAccountConvert {
.setHost(bean.getHost()) .setHost(bean.getHost())
.setPort(bean.getPort()) .setPort(bean.getPort())
.setAuth(true) .setAuth(true)
.setFrom(bean.getFromAddress()) .setFrom(bean.getMail())
.setUser(bean.getUsername()) .setUser(bean.getUsername())
.setPass(bean.getPassword()) .setPass(bean.getPassword())
.setSslEnable(bean.getSslEnable()); .setSslEnable(bean.getSslEnable());

View File

@ -96,7 +96,7 @@ public class MailLogDO extends BaseDO implements Serializable {
* {@link MailTemplateDO#getParams()} * {@link MailTemplateDO#getParams()}
*/ */
@TableField(typeHandler = JacksonTypeHandler.class) @TableField(typeHandler = JacksonTypeHandler.class)
private Map<String,Object> templateParams; private Map<String, Object> templateParams;
// ========= 发送相关字段 ========= // ========= 发送相关字段 =========
/** /**
@ -109,16 +109,13 @@ public class MailLogDO extends BaseDO implements Serializable {
* *
*/ */
private Date sendTime; private Date sendTime;
/**
// ========= 接收相关字段 ========= * ID
*/
private String sendMessageId;
/** /**
* *
*/ */
private String sendResult; private String sendResult;
/**
* ID
*/
private String messageId;
} }

View File

@ -1,13 +1,11 @@
package cn.iocoder.yudao.module.system.mq.message.mail; package cn.iocoder.yudao.module.system.mq.message.mail;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage; import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
/** /**
* *
@ -19,61 +17,35 @@ import java.util.Map;
public class MailSendMessage extends AbstractStreamMessage { public class MailSendMessage extends AbstractStreamMessage {
/** /**
* id *
*/ */
@NotNull(message = "邮箱日志id不能为空") @NotNull(message = "邮件日志编号不能为空")
private Long logId; private Long logId;
/** /**
* *
*/ */
@NotNull(message = "邮箱地址不能为空") @NotNull(message = "接收邮件地址不能为空")
private String fromAddress; private String mail;
/** /**
* *
*/ */
@NotNull(message = "用户名不能为空") @NotNull(message = "邮件账号编号不能为空")
private String username; private Long accountId;
/** /**
* *
*/ */
@NotNull(message = "密码不能为空") private String nickname;
private String password;
/** /**
* *
*/
@NotNull(message = "邮箱模板编号不能为空")
private String templateCode;
/**
*
*/
@NotNull(message = "收件人不能为空")
private String to;
/**
*
*/ */
@NotEmpty(message = "邮件标题不能为空")
private String title; private String title;
/** /**
* *
*/ */
@NotEmpty(message = "邮件内容不能为空")
private String content; private String content;
/**
*
*/
@NotNull(message = "host不能为空")
private String host;
/**
*
*/
@NotNull(message = "端口号不能为空")
private Integer port;
/**
* SSL
*/
private Boolean sslEnable;
/**
*
*/
private List<KeyValue<String, Object>> templateParams;
@Override @Override
public String getStreamKey() { public String getStreamKey() {

View File

@ -1,9 +1,6 @@
package cn.iocoder.yudao.module.system.mq.producer.mail; package cn.iocoder.yudao.module.system.mq.producer.mail;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; import cn.iocoder.yudao.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.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.mail.MailTemplateRefreshMessage;
@ -11,13 +8,12 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
/** /**
* Mail Producer * Mail Producer
* *
* @author wangjingyi * @author wangjingyi
* @date 2021/4/19 13:33 * @since 2021/4/19 13:33
*/ */
@Slf4j @Slf4j
@Component @Component
@ -46,26 +42,18 @@ public class MailProducer {
* {@link MailSendMessage} * {@link MailSendMessage}
* *
* @param sendLogId * @param sendLogId
* @param mailAccountDO * @param mail
* @param mailTemplateDO * @param accountId
* @param content * @param nickname
* @param templateParams * @param title
* @param to * @param content
*/ */
public void sendMailSendMessage(Long sendLogId,MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String content,List<KeyValue<String, Object>> templateParams,String to) { public void sendMailSendMessage(Long sendLogId, String mail, Long accountId,
MailSendMessage message = new MailSendMessage(); String nickname, String title, String content) {
message.setContent(content) MailSendMessage message = new MailSendMessage()
.setFromAddress(mailAccountDO.getMail()) .setLogId(sendLogId).setMail(mail).setAccountId(accountId)
.setHost(mailAccountDO.getHost()) .setNickname(nickname).setTitle(title).setContent(content);
.setPort(mailAccountDO.getPort())
.setPassword(mailAccountDO.getPassword())
.setUsername(mailAccountDO.getUsername())
.setSslEnable(mailAccountDO.getSslEnable())
.setTemplateCode(mailTemplateDO.getCode())
.setTitle(mailTemplateDO.getTitle())
.setTo(to)
.setLogId(sendLogId)
.setTemplateParams(templateParams);
redisMQTemplate.send(message); redisMQTemplate.send(message);
} }
} }

View File

@ -11,7 +11,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* * Service
* *
* @author wangjingyi * @author wangjingyi
* @since 2022-03-21 * @since 2022-03-21
@ -19,7 +19,7 @@ import java.util.Map;
public interface MailLogService { public interface MailLogService {
/** /**
* *
* *
* @param pageVO * @param pageVO
* @return * @return
@ -27,7 +27,7 @@ public interface MailLogService {
PageResult<MailLogDO> getMailLogPage(MailLogPageReqVO pageVO); PageResult<MailLogDO> getMailLogPage(MailLogPageReqVO pageVO);
/** /**
* *
* *
* @param exportReqVO * @param exportReqVO
* @return * @return
@ -35,12 +35,12 @@ public interface MailLogService {
List<MailLogDO> getMailLogList(MailLogExportReqVO exportReqVO); List<MailLogDO> getMailLogList(MailLogExportReqVO exportReqVO);
/** /**
* *
* *
* @param userId * @param userId
* @param userType * @param userType
* @param to * @param to
* @param mailAccountDO * @param mailAccountDO
* @param template * @param template
* @param templateContent * @param templateContent
* @param templateParams * @param templateParams

View File

@ -8,7 +8,6 @@ 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.service.mail.MailLogService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -19,7 +18,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
* * Service
* *
* @author wangjingyi * @author wangjingyi
* @since 2022-03-21 * @since 2022-03-21
@ -42,29 +41,19 @@ public class MailLogServiceImpl implements MailLogService {
} }
@Override @Override
public Long createMailLog(Long userId,Integer userType,String to,MailAccountDO mailAccountDO, MailTemplateDO template , String templateContent, Map<String, Object> templateParams, Boolean isSend) { public Long createMailLog(Long userId, Integer userType, String toMail,
MailAccountDO account, MailTemplateDO template,
String templateContent, Map<String, Object> templateParams, Boolean isSend) {
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
// TODO @wangjingyi使用 builder 的时候,不用每个 set 是一行。DONE
// 根据是否要发送,设置状态 // 根据是否要发送,设置状态
logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus() logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
: MailSendStatusEnum.IGNORE.getStatus()) : MailSendStatusEnum.IGNORE.getStatus())
// 设置邮箱相关字段 // 用户信息
.fromMail(mailAccountDO.getMail()) .userId(userId).userType(userType).toMail(toMail)
.accountId(mailAccountDO.getId()) .accountId(account.getId()).fromMail(account.getMail())
// TODO @wangjingyiuserId、userType // 模板相关字段
//用户信息 .templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname())
.userId(userId).userType(userType) .templateTitle(template.getTitle()).templateContent(templateContent).templateParams(templateParams);
//模版信息
.templateId(template.getId()).templateParams(templateParams).templateContent(templateContent);
logDOBuilder.fromMail(mailAccountDO.getMail());
logDOBuilder.accountId(mailAccountDO.getId());
// TODO @wangjingyi每个接收人一条日志。发送多个人就调用多次业务方。因为某个邮箱有问题会导致所有都发送失败。 DONE
// 设置模板相关字段
// TODO @wangjingyi可以参考下 sms 短信的逻辑templateContent、templateParams
// TODO @wangjingyi有结果的时候才是 sendTime 哈 DONE
//logDOBuilder.sendTime(new Date());
// 插入数据库 // 插入数据库
MailLogDO logDO = logDOBuilder.build(); MailLogDO logDO = logDOBuilder.build();
@ -76,7 +65,7 @@ public class MailLogServiceImpl implements MailLogService {
@Override @Override
public void updateMailSendResult(Long logId, String result) { public void updateMailSendResult(Long logId, String result) {
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
logDOBuilder.id(logId).sendTime(new Date()).sendResult(result).messageId(result).sendStatus(MailSendStatusEnum.SUCCESS.getStatus()); logDOBuilder.id(logId).sendTime(new Date()).sendResult(result).sendMessageId(result).sendStatus(MailSendStatusEnum.SUCCESS.getStatus());
MailLogDO mailLogDO = logDOBuilder.build(); MailLogDO mailLogDO = logDOBuilder.build();
mailLogMapper.updateById(mailLogDO); mailLogMapper.updateById(mailLogDO);
} }

View File

@ -100,22 +100,23 @@ public class MailSendServiceImpl implements MailSendService {
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams); String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams);
Long sendLogId = mailLogService.createMailLog(userId, userType, mail, Long sendLogId = mailLogService.createMailLog(userId, userType, mail,
account, template, content, templateParams, isSend); // TODO 芋艿:待测试 account, template, content, templateParams, isSend);
// 发送 MQ 消息,异步执行发送短信 // 发送 MQ 消息,异步执行发送短信
if (isSend) { if (isSend) {
mailProducer.sendMailSendMessage(sendLogId, account, template, content, newTemplateParams, mail); // TODO 芋艿:待测试 mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(),
template.getNickname(), template.getTitle(), content);
} }
return sendLogId; return sendLogId;
} }
@Override @Override
public void doSendMail(MailSendMessage message) { public void doSendMail(MailSendMessage message) {
// TODO @wangjingyi直接使用 hutool 发送,不要封装 mail client 哈,因为短信的客户端都是比较统一的 DONE // 装载账号信息
//装载账号信息 MailAccount mailAccount = MailAccountConvert.INSTANCE.convertAccount(message);
MailAccount account = MailAccountConvert.INSTANCE.convertAccount(message); // 发送邮件
//发送邮件
try { try {
String messageId = MailUtil.send(account,message.getTo(),message.getTitle(),message.getContent(),false,null); String messageId = MailUtil.send(mailAccount, message.getMail(),
message.getTitle(), message.getContent(),true);
mailLogService.updateMailSendResult(message.getLogId() , messageId); mailLogService.updateMailSendResult(message.getLogId() , messageId);
} catch (Exception e){ } catch (Exception e){
mailLogService.updateFailMailSendResult(message.getLogId() , e.getMessage()); mailLogService.updateFailMailSendResult(message.getLogId() , e.getMessage());

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.service.mail;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class MailSendServiceImplTest {
/**
*
*/
@Test
@Disabled
public void testDemo() {
MailAccount mailAccount = new MailAccount()
.setFrom("奥特曼 <ydym_test@163.com>")
.setHost("smtp.163.com").setPort(465).setSslEnable(true)
.setAuth(true).setUser("ydym_test@163.com").setPass("WBZTEINMIFVRYSOE");
String messageId = MailUtil.send(mailAccount, "7685413@qq.com", "主题", "内容", false);
System.out.println("发送结果:" + messageId);
}
}