mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-07-17 04:25:06 +08:00
邮件模块 添加邮件发送api
This commit is contained in:
@ -47,6 +47,10 @@
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-mail</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
|
||||
@ -102,6 +106,7 @@
|
||||
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.yudao.module.system.api.mail;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* 邮件发送 API 接口
|
||||
*
|
||||
* @author wangjingyi
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class MailSendApiImpl implements MailSendApi{
|
||||
}
|
@ -4,28 +4,34 @@ import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("管理后台 - 邮箱账号基类 Base VO")
|
||||
@Data
|
||||
public class MailAccountBaseVO { // TODO @wangjingqi:1), 不用空格;2)from、username、password、host、sslEnable 都要参数校验,非空;3)username 要 Email 格式;port Integer;
|
||||
public class MailAccountBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "邮箱" , required = true , example = "yudaoyuanma@123.com")
|
||||
@ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com")
|
||||
@NotNull(message = "邮箱必填")
|
||||
private String from;
|
||||
|
||||
@ApiModelProperty(value = "用户名" , required = true , example = "yudao")
|
||||
@ApiModelProperty(value = "用户名",required = true,example = "yudao")
|
||||
@NotNull(message = "用户名必填")
|
||||
@Email(message = "必须是Email格式")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty(value = "密码" , required = true , example = "123456")
|
||||
@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 = "网站必填")
|
||||
private String host;
|
||||
|
||||
@ApiModelProperty(value = "端口" , required = true , example = "80")
|
||||
private String port;
|
||||
@ApiModelProperty(value = "端口",required = true,example = "80")
|
||||
private Integer port;
|
||||
|
||||
@ApiModelProperty(value = "是否开启ssl" , required = true , example = "2")
|
||||
@ApiModelProperty(value = "是否开启ssl",required = true,example = "2")
|
||||
@NotNull(message = "是否开启ssl必填")
|
||||
private Boolean sslEnable;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@ -30,10 +31,10 @@ public class MailLogExcelVO {
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@ExcelProperty(value = "发送时间" )
|
||||
private Timestamp sendTime;
|
||||
private Date sendTime;
|
||||
|
||||
@ExcelProperty(value = "发送状态")
|
||||
private Boolean sendStatus;
|
||||
private Integer sendStatus;
|
||||
|
||||
@ExcelProperty(value = "发送结果")
|
||||
private String sendResult;
|
||||
|
@ -36,7 +36,7 @@ public class MailLogRespVO {
|
||||
private Timestamp sendTime;
|
||||
|
||||
@ApiModelProperty(value = "发送状态" , required = false , example = "1")
|
||||
private Boolean sendStatus;
|
||||
private Integer sendStatus;
|
||||
|
||||
@ApiModelProperty(value = "发送结果" , required = false , example = "yudaoyuanma@123.com")
|
||||
private String sendResult;
|
||||
|
@ -4,6 +4,7 @@ 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;
|
||||
|
||||
@ -11,25 +12,26 @@ import java.util.List;
|
||||
@Data
|
||||
public class MailReqVO { // TODO @wangjingqi:1), 不用空格;2)应该只要传递 templateCode、参数就好,title、from、content、附件应该都是参数里的
|
||||
|
||||
@ApiModelProperty(value = "邮箱" , required = true , example = "yudaoyuanma@123.com")
|
||||
@ApiModelProperty(value = "邮箱",required = true,example = "yudaoyuanma@123.com")
|
||||
@NotNull(message = "邮箱账号不能为空")
|
||||
@Email(message = "邮箱账号格式错误")
|
||||
private String from;
|
||||
|
||||
@ApiModelProperty(value = "标题" , example = "标题")
|
||||
@ApiModelProperty(value = "标题",example = "标题")
|
||||
private String title;
|
||||
|
||||
@ApiModelProperty(value = "内容" , example = "内容")
|
||||
@ApiModelProperty(value = "内容",example = "内容")
|
||||
private String content;
|
||||
|
||||
@ApiModelProperty(value = "邮箱模版id" , example = "1024")
|
||||
@ApiModelProperty(value = "邮箱模版id",example = "1024")
|
||||
@NotNull(message = "邮箱模版id不能为空")
|
||||
private Integer templateId;
|
||||
|
||||
@ApiModelProperty(value = "收件人" , required = true , example = "yudaoyuanma@123.com")
|
||||
@ApiModelProperty(value = "收件人",required = true,example = "yudaoyuanma@123.com")
|
||||
@NotNull(message = "收件人不能为空")
|
||||
private List<String> tos;
|
||||
|
||||
@ApiModelProperty(value = "附件" , example = "附件编码")
|
||||
@ApiModelProperty(value = "附件",example = "附件编码")
|
||||
private List<String> fileIds;
|
||||
|
||||
|
||||
|
@ -4,15 +4,18 @@ import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("管理后台 - 邮箱模版基类 Base VO")
|
||||
@Data
|
||||
public class MailTemplateBaseVO { // TODO @wangjingqi:1)swagger 注解不完善;2)id、name、code、username、title、content、status 是不是要参数校验呀
|
||||
public class MailTemplateBaseVO {
|
||||
@ApiModelProperty("主键")
|
||||
@NotNull(message = "主键不能为空")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("名称")
|
||||
@NotNull(message = "名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("标识")
|
||||
@ -20,16 +23,21 @@ public class MailTemplateBaseVO { // TODO @wangjingqi:1)swagger 注解不
|
||||
private String code;
|
||||
|
||||
@ApiModelProperty("发件人")
|
||||
@NotNull(message = "发件人不能为空")
|
||||
@Email(message = "发件人格式有误")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty("标题")
|
||||
@NotNull(message = "标题不能为空")
|
||||
private String title;
|
||||
|
||||
@ApiModelProperty("内容")
|
||||
@NotNull(message = "内容不能为空")
|
||||
private String content;
|
||||
|
||||
@ApiModelProperty("状态")
|
||||
private String status;
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
|
@ -31,7 +31,7 @@ public class MailTemplatePageReqVO extends PageParam {
|
||||
private String content;
|
||||
|
||||
@ApiModelProperty("状态")
|
||||
private String status;
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
|
@ -1,12 +1,12 @@
|
||||
package cn.iocoder.yudao.module.system.dal.dataobject.mail;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 邮箱日志
|
||||
@ -18,6 +18,10 @@ import java.sql.Timestamp;
|
||||
@TableName(value = "system_mail_log", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MailLogDO extends BaseDO implements Serializable {
|
||||
|
||||
/**
|
||||
@ -29,7 +33,7 @@ public class MailLogDO extends BaseDO implements Serializable {
|
||||
/**
|
||||
* 邮箱账号编号
|
||||
*/
|
||||
private String accountCode;
|
||||
private Long accountId;
|
||||
|
||||
// TODO @wangjingyi:如果是冗余字段,记得 @ 下;
|
||||
/**
|
||||
@ -40,7 +44,7 @@ public class MailLogDO extends BaseDO implements Serializable {
|
||||
/**
|
||||
* 模版主键
|
||||
*/
|
||||
private String templateId;
|
||||
private Long templateId;
|
||||
|
||||
/**
|
||||
* 模版编号
|
||||
@ -65,16 +69,18 @@ public class MailLogDO extends BaseDO implements Serializable {
|
||||
/**
|
||||
* 发送时间
|
||||
*/
|
||||
private Timestamp sendTime;
|
||||
private Date sendTime;
|
||||
|
||||
/**
|
||||
* 发送状态
|
||||
*
|
||||
* 枚举 {@link MailSendStatusEnum}
|
||||
*/
|
||||
// TODO @wangjingyi:四个状态,参考短信模块
|
||||
private Boolean sendStatus;
|
||||
private Integer sendStatus;
|
||||
|
||||
/**
|
||||
* 发送结果
|
||||
*
|
||||
*/
|
||||
private String sendResult;
|
||||
|
||||
|
@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 邮箱模版
|
||||
*
|
||||
@ -29,11 +31,10 @@ public class MailTemplateDO extends BaseDO {
|
||||
* 模版编号
|
||||
*/
|
||||
private String code;
|
||||
// TODO @wangjingyi:应该使用 accountId 呀
|
||||
/**
|
||||
* 用户名
|
||||
* 邮箱账号主键
|
||||
*/
|
||||
private String username;
|
||||
private Long accountId;
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@ -47,7 +48,7 @@ public class MailTemplateDO extends BaseDO {
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private String status; // TODO @wangjingyi:Integer
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
|
||||
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;
|
||||
|
||||
@Mapper
|
||||
@ -21,9 +22,7 @@ public interface MailAccountMapper extends BaseMapperX<MailAccountDO> {
|
||||
}
|
||||
|
||||
default MailAccountDO selectByUserName(String userName){
|
||||
// TODO @wangjingyi:selectOne 有封装的方法;然后,编码一定要学会使用泛型呀。例如说 QueryWrapperX<MailAccountDO> queryWrapperX = new QueryWrapperX<>();
|
||||
QueryWrapperX<MailAccountDO> queryWrapperX = new QueryWrapperX<>();
|
||||
queryWrapperX.eqIfPresent("username", userName);
|
||||
return this.selectOne(queryWrapperX);
|
||||
return selectOne(new QueryWrapperX<MailAccountDO>()
|
||||
.eqIfPresent("username" , userName));
|
||||
};
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
|
||||
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
|
||||
@ -23,7 +26,15 @@ public interface MailTemplateMapper extends BaseMapperX<MailTemplateDO> {
|
||||
}
|
||||
|
||||
default MailTemplateDO selectOneByCode(String code){
|
||||
// TODO @wangjingyi:优先使用 lambada 查询
|
||||
return selectOne("code" , code);
|
||||
return selectOne(new QueryWrapperX<MailTemplateDO>()
|
||||
.eqIfPresent("code" , code));
|
||||
};
|
||||
|
||||
@Select("SELECT id FROM system_mail_template WHERE update_time > #{maxUpdateTime} LIMIT 1")
|
||||
Long selectByMaxUpdateTime(Date maxUpdateTime);
|
||||
|
||||
default MailTemplateDO selectOneByAccountId(Long accountId){
|
||||
return selectOne(new QueryWrapperX<MailTemplateDO>()
|
||||
.eqIfPresent("account_id" , accountId));
|
||||
};
|
||||
}
|
||||
|
@ -2,17 +2,23 @@ package cn.iocoder.yudao.module.system.mq.consumer.mail;
|
||||
|
||||
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
|
||||
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
|
||||
import cn.iocoder.yudao.module.system.service.mail.MailSendService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
// TODO 芋艿:这个暂未实现
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MailSendConsumer extends AbstractStreamMessageListener<MailSendMessage> {
|
||||
|
||||
@Resource
|
||||
private MailSendService mailSendService;
|
||||
@Override
|
||||
public void onMessage(MailSendMessage message) {
|
||||
log.info("[onMessage][消息内容({})]", message);
|
||||
mailSendService.doSendMail(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -16,29 +17,34 @@ import java.util.Map;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class MailSendMessage extends AbstractStreamMessage {
|
||||
|
||||
/**
|
||||
* 日志id
|
||||
*/
|
||||
@NotNull(message = "邮箱日志id不能为空")
|
||||
private Long logId;
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
@NotNull(message = "邮箱地址不能为空")
|
||||
private String address;
|
||||
private String from;
|
||||
/**
|
||||
* 短信模板编号
|
||||
* 邮箱模板编号
|
||||
*/
|
||||
@NotNull(message = "短信模板编号不能为空")
|
||||
@NotNull(message = "邮箱模板编号不能为空")
|
||||
private String templateCode;
|
||||
/**
|
||||
* 短信模板参数
|
||||
* 收件人
|
||||
*/
|
||||
private Map<String, Object> templateParams;
|
||||
|
||||
@NotNull(message = "收件人不能为空")
|
||||
private List<String> tos;
|
||||
/**
|
||||
* 用户编号,允许空
|
||||
* 标题
|
||||
*/
|
||||
private Integer userId;
|
||||
private String title;
|
||||
/**
|
||||
* 用户类型,允许空
|
||||
* 内容
|
||||
*/
|
||||
private Integer userType;
|
||||
private String content;
|
||||
|
||||
@Override
|
||||
public String getStreamKey() {
|
||||
|
@ -0,0 +1,65 @@
|
||||
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.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.MailSendMessage;
|
||||
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;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mail 邮件相关消息的 Producer
|
||||
*
|
||||
* @author wangjingyi
|
||||
* @date 2021/4/19 13:33
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MailProducer {
|
||||
|
||||
@Resource
|
||||
private RedisMQTemplate redisMQTemplate;
|
||||
|
||||
/**
|
||||
* 发送 {@link SmsChannelRefreshMessage} 消息
|
||||
*/
|
||||
public void sendMailChannelRefreshMessage() {
|
||||
SmsChannelRefreshMessage message = new SmsChannelRefreshMessage();
|
||||
redisMQTemplate.send(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 {@link SmsTemplateRefreshMessage} 消息
|
||||
*/
|
||||
public void sendMailTemplateRefreshMessage() {
|
||||
SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage();
|
||||
redisMQTemplate.send(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 {@link MailSendMessage} 消息
|
||||
*
|
||||
* @param mailAccountDO 邮箱账号信息
|
||||
* @param mailTemplateDO 邮箱模版信息
|
||||
* @param content 内容
|
||||
* @param tos 收件人
|
||||
* @param title 标题
|
||||
*/
|
||||
public void sendMailSendMessage(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String content, List<String> tos, String title , Long sendLogId) {
|
||||
MailSendMessage message = new MailSendMessage();
|
||||
message.setContent(content);
|
||||
message.setFrom(mailAccountDO.getFrom());
|
||||
message.setTemplateCode(mailTemplateDO.getCode());
|
||||
message.setTitle(title);
|
||||
message.setTos(tos);
|
||||
message.setLogId(sendLogId);
|
||||
redisMQTemplate.send(message);
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@ package cn.iocoder.yudao.module.system.service.mail;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -28,4 +30,18 @@ public interface MailLogService {
|
||||
* @return
|
||||
*/
|
||||
List<MailLogDO> getMailLogList(MailLogExportReqVO exportReqVO);
|
||||
|
||||
/**
|
||||
* 创建邮箱日志
|
||||
* @param mailAccountDO 邮箱账号信息
|
||||
* @param mailTemplateDO 模版信息
|
||||
* @param from 邮箱
|
||||
* @param content 内容
|
||||
* @param tos 收件人
|
||||
* @param title 标题
|
||||
* @param isSend 是否发送成功
|
||||
*/
|
||||
Long createMailLog(MailAccountDO mailAccountDO, MailTemplateDO mailTemplateDO, String from, String content, List<String> tos, String title, Boolean isSend);
|
||||
|
||||
Long updateSmsSendResult(Long logId, String result);
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail;
|
||||
|
||||
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.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.dal.dataobject.mail.MailTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 邮箱模版服务类
|
||||
*
|
||||
* @author wangjingyi
|
||||
* @since 2022-03-21
|
||||
*/
|
||||
public interface MailSendService {
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
*
|
||||
* @param templateCode 邮件模版编码
|
||||
* @param from 邮箱
|
||||
* @param content 内容
|
||||
* @param tos 收件人
|
||||
* @param title 标题
|
||||
*/
|
||||
void sendMail(String templateCode, String from , String content , List<String> tos , String title);
|
||||
|
||||
/**
|
||||
* 执行真正的邮件发送
|
||||
* 注意,该方法仅仅提供给 MQ Consumer 使用
|
||||
*
|
||||
* @param message 邮件
|
||||
*/
|
||||
void doSendMail(MailSendMessage message);
|
||||
}
|
@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 邮箱模版服务类
|
||||
@ -18,6 +19,7 @@ import java.util.List;
|
||||
*/
|
||||
public interface MailTemplateService {
|
||||
|
||||
void initLocalCache();
|
||||
/**
|
||||
* 邮箱模版创建
|
||||
*
|
||||
@ -62,6 +64,13 @@ public interface MailTemplateService {
|
||||
* @return 模版数组
|
||||
*/
|
||||
List<MailTemplateDO> getMailTemplateList();
|
||||
/**
|
||||
*从缓存中获取邮箱模版
|
||||
*
|
||||
* @param code 模板编码
|
||||
* @return 邮箱模板
|
||||
*/
|
||||
MailTemplateDO getMailTemplateByCodeFromCache(String code);
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
@ -69,4 +78,12 @@ public interface MailTemplateService {
|
||||
* @param mailReqVO 邮件发送信息
|
||||
*/
|
||||
void sendMail(MailReqVO mailReqVO);
|
||||
|
||||
/**
|
||||
* 邮件模版内容合成
|
||||
* @param content 邮箱模版
|
||||
* @param params 合成参数
|
||||
* @return
|
||||
*/
|
||||
String formateMailTemplateContent(String content, Map<String, String> params);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccou
|
||||
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.mysql.mail.MailAccountMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
|
||||
import cn.iocoder.yudao.module.system.service.mail.MailAccountService;
|
||||
@ -16,8 +17,7 @@ import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
|
||||
/**
|
||||
@ -47,8 +47,8 @@ public class MailAccountServiceImpl implements MailAccountService {
|
||||
|
||||
@Override
|
||||
public void update(MailAccountUpdateReqVO updateReqVO) {
|
||||
// username 要校验唯一 // TODO @wangjingyi:更新的就是自己,username 这样写,会重复呀。
|
||||
this.validateMailAccountOnlyByUserName(updateReqVO.getUsername());
|
||||
// username 要校验唯一
|
||||
this.validateMailAccountExists(updateReqVO.getId());
|
||||
MailAccountDO mailAccountDO = MailAccountConvert.INSTANCE.convert(updateReqVO);
|
||||
// 校验是否存在
|
||||
this.validateMailAccountExists(mailAccountDO.getId());
|
||||
@ -57,9 +57,10 @@ public class MailAccountServiceImpl implements MailAccountService {
|
||||
|
||||
@Override
|
||||
public void delete(Long id) {
|
||||
// TODO @wangjingyi:删除时,要判断是否有使用的模板
|
||||
// 校验是否存在
|
||||
// 校验是否存在账号
|
||||
this.validateMailAccountExists(id);
|
||||
// 校验是否存在关联模版
|
||||
this.validateMailTemplateByAccountId(id);
|
||||
mailAccountMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@ -90,4 +91,11 @@ public class MailAccountServiceImpl implements MailAccountService {
|
||||
throw exception(MAIL_ACCOUNT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMailTemplateByAccountId(Long accountId){
|
||||
MailTemplateDO mailTemplateDO = mailTemplateMapper.selectOneByAccountId(accountId);
|
||||
if (mailTemplateDO != null) {
|
||||
throw exception(MAIL_RELATE_TEMPLATE_EXISTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,21 @@ package cn.iocoder.yudao.module.system.service.mail.impl;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogExportReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 邮箱日志实现类
|
||||
@ -35,4 +42,39 @@ public class MailLogServiceImpl implements MailLogService {
|
||||
public List<MailLogDO> getMailLogList(MailLogExportReqVO exportReqVO) {
|
||||
return mailLogMapper.selectList(exportReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createMailLog(MailAccountDO mailAccountDO , MailTemplateDO mailTemplateDO , String from, String content, List<String> tos, String title, Boolean isSend) {
|
||||
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
|
||||
logDOBuilder.from(mailAccountDO.getFrom());
|
||||
logDOBuilder.accountId(mailAccountDO.getId());
|
||||
logDOBuilder.content(content);
|
||||
logDOBuilder.title(title);
|
||||
logDOBuilder.templateCode(mailTemplateDO.getCode());
|
||||
logDOBuilder.templateId(mailTemplateDO.getId());
|
||||
logDOBuilder.to(tos.toString());
|
||||
logDOBuilder.sendTime(new Date());
|
||||
logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
|
||||
: MailSendStatusEnum.IGNORE.getStatus());
|
||||
|
||||
MailLogDO mailLogDO = logDOBuilder.build();
|
||||
mailLogMapper.insert(mailLogDO);
|
||||
return mailLogDO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long updateSmsSendResult(Long logId, String result) {
|
||||
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
|
||||
logDOBuilder.id(logId);
|
||||
logDOBuilder.sendResult(result);
|
||||
MailLogDO mailLogDO = logDOBuilder.build();
|
||||
mailLogMapper.updateById(mailLogDO);
|
||||
return logId;
|
||||
}
|
||||
|
||||
public Long create(){
|
||||
MailLogDO mailLogDO = new MailLogDO();
|
||||
mailLogMapper.insert(mailLogDO);
|
||||
return mailLogDO.getId();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail.impl;
|
||||
|
||||
|
||||
import cn.hutool.extra.mail.MailAccount;
|
||||
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;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
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.message.mail.MailSendMessage;
|
||||
import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
|
||||
import cn.iocoder.yudao.module.system.service.mail.MailLogService;
|
||||
import cn.iocoder.yudao.module.system.service.mail.MailSendService;
|
||||
import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import cn.iocoder.yudao.framework.mail.core.client.MailClientFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import cn.iocoder.yudao.framework.mail.core.client.MailClient;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 邮箱模版 服务实现类
|
||||
*
|
||||
* @author wangjingyi
|
||||
* @since 2022-03-21
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class MailSendServiceImpl implements MailSendService {
|
||||
|
||||
@Resource
|
||||
private MailTemplateMapper mailTemplateMapper;
|
||||
@Resource
|
||||
private MailAccountMapper mailAccountMapper;
|
||||
@Resource
|
||||
private MailTemplateService mailTemplateService;
|
||||
@Resource
|
||||
private MailLogService mailLogService;
|
||||
@Resource
|
||||
private MailClientFactory mailClientFactory;
|
||||
@Resource
|
||||
private MailProducer mailProducer;
|
||||
|
||||
|
||||
@Override
|
||||
public void sendMail(String templateCode, String from , String content , List<String> tos , String title) {
|
||||
// TODO @@wangjingyi:发送的时候,参考下短信;
|
||||
MailTemplateDO mailTemplateDO = this.checkMailTemplateValid(templateCode);
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(mailTemplateDO.getStatus());
|
||||
//查询账号信息
|
||||
MailAccountDO mailAccountDO = mailAccountMapper.selectOne(
|
||||
"from", from
|
||||
);
|
||||
Map<String , String> params = MailAccountConvert.INSTANCE.convertToMap(mailAccountDO , content);
|
||||
content = mailTemplateService.formateMailTemplateContent(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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSendMail(MailSendMessage message) {
|
||||
MailClient mailClient = mailClientFactory.getMailClient();
|
||||
String result = mailClient.sendMail(message.getFrom() , message.getContent() , message.getTitle() , message.getTos());
|
||||
mailLogService.updateSmsSendResult(message.getLogId() , result);
|
||||
}
|
||||
|
||||
private MailTemplateDO checkMailTemplateValid(String templateCode) {
|
||||
MailTemplateDO mailTemplateDO = mailTemplateService.getMailTemplateByCodeFromCache(templateCode);
|
||||
if (mailTemplateDO == null){
|
||||
throw exception(MAIL_TEMPLATE_NOT_EXISTS);
|
||||
}
|
||||
return mailTemplateDO;
|
||||
}
|
||||
|
||||
private void validateMailTemplateExists(Long id) {
|
||||
if (mailTemplateMapper.selectById(id) == null) {
|
||||
throw exception(MAIL_TEMPLATE_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMailTemplateOnlyByCode(String code){
|
||||
if (mailTemplateMapper.selectOneByCode(code) != null) {
|
||||
throw exception(MAIL_TEMPLATE_EXISTS);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.mail.MailAccount;
|
||||
import cn.hutool.extra.mail.MailUtil;
|
||||
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.send.MailReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateCreateReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
|
||||
@ -13,14 +15,18 @@ import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
|
||||
import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert;
|
||||
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.service.mail.MailTemplateService;
|
||||
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 javax.validation.Valid;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -36,6 +42,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPL
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
@Resource
|
||||
@ -43,6 +50,38 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
@Resource
|
||||
private MailAccountMapper mailAccountMapper;
|
||||
|
||||
private volatile List<MailTemplateDO> mailTemplateDOList;
|
||||
|
||||
/**
|
||||
* 邮件模板缓存
|
||||
* key:邮箱模板编码 {@link MailTemplateDO#getCode()}
|
||||
*
|
||||
* 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
|
||||
*/
|
||||
private volatile Map<String, MailTemplateDO> mailTemplateCache;
|
||||
|
||||
private volatile Date maxUpdateTime;
|
||||
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void initLocalCache() {
|
||||
if(maxUpdateTime == null){
|
||||
mailTemplateDOList = mailTemplateMapper.selectList();
|
||||
}else{
|
||||
if(mailTemplateMapper.selectByMaxUpdateTime(maxUpdateTime)<=0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (CollUtil.isEmpty(mailTemplateDOList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 写入缓存
|
||||
mailTemplateCache = CollectionUtils.convertMap(mailTemplateDOList, MailTemplateDO::getCode);
|
||||
maxUpdateTime = CollectionUtils.getMaxValue(mailTemplateDOList, MailTemplateDO::getUpdateTime);
|
||||
log.info("[initLocalCache][初始化 mailTemplate 数量为 {}]", mailTemplateDOList.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long create(MailTemplateCreateReqVO createReqVO) {
|
||||
// code 要校验唯一
|
||||
@ -54,11 +93,9 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
@Override
|
||||
public void update(@Valid MailTemplateUpdateReqVO updateReqVO) {
|
||||
// code 要校验唯一
|
||||
this.validateMailTemplateOnlyByCode(updateReqVO.getCode()); // TODO @wangjingyi:code 这样写,修改自己会有问题
|
||||
MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO);
|
||||
// 校验是否存在
|
||||
this.validateMailTemplateExists(mailTemplateDO.getId());
|
||||
this.validateMailTemplateExists(updateReqVO.getId());
|
||||
MailTemplateDO mailTemplateDO = MailTemplateConvert.INSTANCE.convert(updateReqVO);
|
||||
mailTemplateMapper.updateById(mailTemplateDO);
|
||||
}
|
||||
|
||||
@ -80,6 +117,11 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
@Override
|
||||
public List<MailTemplateDO> getMailTemplateList() {return mailTemplateMapper.selectList();}
|
||||
|
||||
@Override
|
||||
public MailTemplateDO getMailTemplateByCodeFromCache(String code) {
|
||||
return mailTemplateCache.get(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(MailReqVO mailReqVO) {
|
||||
// TODO @@wangjingyi:发送的时候,参考下短信;
|
||||
@ -102,6 +144,11 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
MailUtil.send(account , mailReqVO.getTos() , mailReqVO.getTitle() , content , false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formateMailTemplateContent(String content, Map<String, String> params) {
|
||||
return StrUtil.format(content, params);
|
||||
}
|
||||
|
||||
private void validateMailTemplateExists(Long id) {
|
||||
if (mailTemplateMapper.selectById(id) == null) {
|
||||
throw exception(MAIL_TEMPLATE_NOT_EXISTS);
|
||||
|
Reference in New Issue
Block a user