在日常开发中,可能会遇到这样的开发需求:一些告警消息或者通知消息会使用邮件发送(针对一些消息重要但是对消息实时性要求不是特别高的场景),然而一些企业可能会有多个邮件服务器,每个邮件服务器每天只能发送指定数量的邮件,如何合理高效利用这些邮件服务器是开发者需要重点考虑的。由于SpringBoot项目对JavaMail进行了封装,方便开箱即用,然而此方案的缺陷在于只能配置一个邮件服务器地址,无法满足本文的需求。本文将基于上述需求,设计实现一种多邮件服务器发送邮件的功能,方便大家参考学习。
系统有一些通知消息和告警消息需要利用邮件服务器发送,有多个邮件服务器,每个邮件服务器每天能发送固定数量的邮件(超过最大数不再发送)。
1.由于有多个邮件服务器,因此需要存储邮件服务器信息,考虑到变更和新增情况,此处选择存储在数据库中;
2.为了减轻每次查询邮件服务器信息所给数据库带来的压力,将邮件服务器信息同时存储到缓存中(设置过期时间),查询邮件服务器信息时先查询缓存,缓存中不存在时再查询数据库;
3.为了记录每台邮件服务器已发送邮件数量,缓存中需要记录邮件服务器已发送邮件数量;
4.多个线程同步发送邮件,更新缓存中邮件发送数量时需要加锁,本文利用redisLock来实现加锁操作;
5.本文使用Apache的commons-email来发送邮件,因为commons-email发送邮件的代码看起来更加简洁,commons-email底层需要依赖于JavaMail,因此在pom文件中需要引入commons-email和JavaMail。
CREATE TABLE `vdo_email_server` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`smtp_addr` varchar(100) DEFAULT NULL COMMENT 'smtp地址',
`mail_port` int(11) DEFAULT '0' COMMENT '服务器端口号',
`user_name` varchar(100) DEFAULT NULL COMMENT '邮箱登陆用户名',
`password` varchar(50) DEFAULT NULL COMMENT '第三方登陆授权码',
`ssl_flag` int(2) DEFAULT NULL COMMENT 'https是否开启',
`send_time` bigint(11) DEFAULT '30000' COMMENT '邮件发送时间的限制,单位毫秒',
`connect_time` bigint(11) DEFAULT '30000' COMMENT '连接时间,单位毫秒',
`receive_time` bigint(11) DEFAULT '30000' COMMENT '邮件接收时间限制,单位毫秒',
`sender_account` varchar(100) DEFAULT NULL COMMENT '发送者账号',
`max_quantity` int(11) DEFAULT '0' COMMENT '邮件最大发送值',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`modify_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` int(11) DEFAULT '0' COMMENT '账户状态(0:启用,1:禁用)',
`remark` varchar(255) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.github.chimmhuang</groupId>
<artifactId>redislock</artifactId>
<version>1.0.2</version>
</dependency>
import com.alibaba.fastjson.JSON;
import com.pubinfo.common.util.StringUtils;
import com.pubinfo.video.email.domain.EmailInfo;
import com.pubinfo.video.email.domain.EmailServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.mail.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class EmailUtils {
private static final String CHARSET_UTF8 = "UTF-8";
public static void pushSimpleEmail(EmailServer server, EmailInfo emailInfo) {
log.info("发送邮件:{},至邮件服务器:{}", JSON.toJSONString(emailInfo), JSON.toJSONString(server));
Email email = new SimpleEmail();
email.setHostName(server.getSmtpAddr());
email.setSmtpPort(server.getMailPort());
//用户名称和授权码
email.setAuthentication(server.getUserName(), server.getPassword());
email.setCharset(CHARSET_UTF8);
try {
email.addTo(emailInfo.getDestination());
email.setFrom(server.getUserName(), server.getSenderAccount());
email.setSubject(emailInfo.getSubject());
email.setMsg(emailInfo.getContent());
email.setSSLOnConnect(server.getSslFlag() == 0);
Map<String, String> map = new HashMap<>();
if (!StringUtils.isEmpty(emailInfo.getTitle())) {
map.put("主题", emailInfo.getTitle());
} else {
map.put("主题", emailInfo.getSubject());
}
email.setHeaders(map);
email.setSentDate(new Date());
email.send();
log.info("邮件:{},发送成功", JSON.toJSONString(emailInfo));
} catch (EmailException e) {
log.info("邮件发送失败:{},message:{}", e);
}
}
public static void pushAttachmentEmail(EmailServer server, EmailInfo emailInfo) {
log.info("发送带附件的邮件:{},至邮件服务器:{}", JSON.toJSONString(emailInfo), JSON.toJSONString(server));
EmailAttachment attachment = new EmailAttachment();
attachment.setDescription(emailInfo.getAttachmentDescription());
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setName(emailInfo.getAttachmentName());
attachment.setPath(emailInfo.getAttachmentPath());
MultiPartEmail email = new MultiPartEmail();
email.setHostName(server.getSmtpAddr());
email.setSmtpPort(server.getMailPort());
//用户名称和授权码
email.setAuthentication(server.getUserName(), server.getPassword());
email.setCharset(CHARSET_UTF8);
try {
email.addTo(emailInfo.getDestination());
if (server.getSslFlag() == 0) {
email.setSSLOnConnect(true);
} else {
email.setSSLOnConnect(false);
}
email.attach(attachment);
email.setFrom(server.getUserName(), server.getSenderAccount());
email.setSubject(emailInfo.getSubject());
email.setMsg(emailInfo.getContent());
Map<String, String> map = new HashMap<>();
map.put("主题", emailInfo.getTitle());
email.send();
email.setHeaders(map);
log.info("带附件的邮件发送成功:{}", JSON.toJSONString(attachment));
} catch (EmailException e) {
log.info("邮件发送失败:{},message:{}", e, JSON.toJSONString(attachment));
}
}
}
@Data
public class EmailInfo {
/**
* 邮件标题
*/
@ApiModelProperty(value = "邮件标题")
private String title;
/**
* 邮件内容
*/
@ApiModelProperty(value = "邮件内容")
private String content;
/**
* 邮件主题
*/
@ApiModelProperty(value = "邮件主题")
private String subject;
/**
* 收件者账号
*/
@ApiModelProperty(value = "收件者账号")
private String destination;
/**
* 附件地址
*/
@ApiModelProperty(value = "附件地址")
private String attachmentPath;
/**
* 附件描述
*/
@ApiModelProperty(value = "附件描述")
private String attachmentDescription;
/**
* 附件名称
*/
@ApiModelProperty(value = "附件名称")
private String attachmentName;
}
@Data
public class EmailServer implements Serializable {
private Long id;
/**
* smtp地址
*/
@ApiModelProperty(value = "smtp地址,必填")
private String smtpAddr;
/**
* 服务器端口号
*/
@ApiModelProperty(value = "邮件发送服务器端口号,必填")
private Integer mailPort;
/**
* 邮箱登陆用户名
*/
@ApiModelProperty(value = "邮箱登陆用户名,必填")
private String userName;
/**
* 第三方登陆授权码
*/
@ApiModelProperty(value = "第三方登陆授权码,必填")
private String password;
/**
* https是否开启(0:开启 1:关闭)
*/
@ApiModelProperty(value = "https是否开启(0:开启 1:关闭)")
private Integer sslFlag;
/**
* 邮件发送时间的限制,单位毫秒
*/
@ApiModelProperty(value = "邮件发送时间的限制,单位毫秒")
private Long sendTime;
/**
* 连接时间,单位毫秒
*/
@ApiModelProperty(value = "连接时间,单位毫秒")
private Long connectTime;
/**
* 邮件接收时间限制,单位毫秒
*/
@ApiModelProperty(value = "邮件接收时间限制,单位毫秒")
private Long receiveTime;
/**
* 发送者账号
*/
@ApiModelProperty(value = "发送者账号")
private String senderAccount;
/**
* 邮件最大发送值
*/
@ApiModelProperty(value = "邮件最大发送值(天)")
private Integer maxQuantity;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty(value = "修改时间")
private Date modifyTime;
/**
* 账户状态(0:启用,1:禁用)
*/
@ApiModelProperty(value = "账户状态(0:启用,1:禁用)")
private Integer status;
/**
* 描述
*/
@ApiModelProperty(value = "描述")
private String remark;
private static final long serialVersionUID = 1L;
}
@Data
public class MessageSystem implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键id", required = false)
private Long id;
/**
* 图片url
*/
@ApiModelProperty(value = "图片url", required = false)
private String imageUrl;
/**
* 告警内容
*/
@ApiModelProperty(value = "告警内容", required = false)
private String content;
/**
* 发表用户id
*/
@ApiModelProperty(value = "发表用户id", required = false)
private Long userId;
/**
* 发表用户姓名
*/
@ApiModelProperty(value = "发表用户姓名", required = false)
private String userName;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间", required = false)
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty(value = "修改时间", required = false)
private Date modifyTime;
/**
* 描述
*/
@ApiModelProperty(value = "描述", required = false)
private String remark;
/**
* 推送时间(默认为null,表示实时推送)
*/
@ApiModelProperty(value = "推送时间(默认为null,表示实时推送)", required = false)
private Date sendTime;
/**
* 标题
*/
@ApiModelProperty(value = "标题", required = false)
private String title;
/**
* 是否邮件推送(0:是,1:否,默认为1)
*/
@ApiModelProperty(value = "是否邮件推送(0:是,1:否,默认为1)", required = false)
private Integer emailSend;
}
package com.pubinfo.video.email.thread;
import com.alibaba.fastjson.JSON;
import com.github.chimmhuang.redislock.lock.RedisLock;
import com.pubinfo.common.util.RedisUtils;
import com.pubinfo.common.util.ResultBean;
import com.pubinfo.common.util.StringUtils;
import com.pubinfo.common.util.springutil.SpringHelper;
import com.pubinfo.video.email.constant.Constant;
import com.pubinfo.video.email.domain.EmailInfo;
import com.pubinfo.video.email.domain.EmailServer;
import com.pubinfo.video.email.service.EmailService;
import com.pubinfo.video.email.util.EmailUtils;
import com.pubinfo.video.notifications.entity.MessageSystem;
import com.pubinfo.video.user.entity.User;
import com.pubinfo.video.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class PushEmailThread implements Runnable {
private static final long REDIS_LOCK_EXPIRE = 30L;
private RedisUtils redisUtils;
private String message;
private RedisLock redisLock;
private UserService userService = SpringHelper.getBean("userService");
private EmailService emailService = SpringHelper.getBean("emailService");
public PushEmailThread(RedisUtils redisUtils, String message, RedisLock redisLock) {
this.redisUtils = redisUtils;
this.message = message;
this.redisLock = redisLock;
}
@Override
public void run() {
MessageSystem messageSystem = JSON.parseObject(message, MessageSystem.class);
log.info("邮件发送系统消息为:{}", JSON.toJSONString(messageSystem));
if (messageSystem.getEmailSend().equals(0)) {
Map<Object, Object> serverMap = redisUtils.hGetAll(Constant.EMAIL_SERVER_INFO);
redisLock.lock(Constant.EMAIL_SERVER_SET_LOCK, REDIS_LOCK_EXPIRE);
//获取邮件发送服务器
List<EmailServer> servers = getEmailServerLists(serverMap);
log.info("获取邮件发送服务器信息:{}", JSON.toJSONString(servers));
redisLock.unlock(Constant.EMAIL_SERVER_SET_LOCK);
//获取所有邮件接收者信息
List<User> allEmail = getEmailUsers();
//按时间:单位(天)来存储邮件发送最大值,
Calendar calendar = Calendar.getInstance();
Date time = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format = sdf.format(time);
//获取所有发送服务器信息
if (messageSystem.getReceiveUser().equals(1)) {
//推送至所有用户,获取所有邮箱不为空的用户,进行遍历发送
if (!CollectionUtils.isEmpty(allEmail)) {
List<User> users = allEmail.stream().distinct().collect(Collectors.toList());
List<EmailServer> finalServers = servers;
users.forEach(user -> {
//封装邮件发送方,发送对象,由于当前系统消息数量较少,可以遍历邮件推送方式,若邮件数量庞大,需要考虑线程池推送
EmailServer emailServer = null;
//按天获取每个server每天的发送邮件数量,成功+1,若当天发送数量大于最大发送值max,停止该邮箱使用
Integer total = null;
for (EmailServer emailServer1 : finalServers) {
total = (Integer) redisUtils.get(Constant.EMAIL_SERVER_SEND_QUANTITY + emailServer1.getUserName() + "#" + format);
if (total != null && total <= emailServer1.getMaxQuantity()) {
emailServer = emailServer1;
break;
} else if (total == null) {
redisLock.lock(Constant.EMAIL_QUALITY_SET_LOCK, REDIS_LOCK_EXPIRE);
redisUtils.set(Constant.EMAIL_SERVER_SEND_QUANTITY + emailServer1.getUserName() + "#" + format, emailServer1.getMaxQuantity());
emailServer = emailServer1;
redisLock.unlock(Constant.EMAIL_QUALITY_SET_LOCK);
total = 0;
break;
}
}
if (emailServer != null) {
productEmailAndSend(emailServer, messageSystem, user, format, total);
}
});
}
} else {
//推送到指定用户,根据用户id推送
List<Long> ids = messageSystem.getIds();
for (Long id : ids) {
User user = new User();
user.setId(id);
ResultBean resultBean = userService.queryByUser(user);
if (resultBean == null || !resultBean.getErrorCode().equals("0")) {
log.error("该用户不存在!");
continue;
}
User userResult = (User) resultBean.getData();
if (!StringUtils.isEmpty(userResult.getEmail())) {
if (!CollectionUtils.isEmpty(allEmail)) {
//封装邮件发送方,发送对象,由于当前系统消息数量较少,可以遍历邮件推送方式,若邮件数量庞大,需要考虑线程池推送
EmailServer emailServer = null;
//按天获取每个server每天的发送邮件数量,成功+1,若当天发送数量大于最大发送值max,停止该邮箱使用
Integer total = null;
//遍历获取可用邮件服务器
for (EmailServer emailServer1 : servers) {
total = (Integer) redisUtils.get(Constant.EMAIL_SERVER_SEND_QUANTITY + emailServer1.getUserName() + "#" + format);
if (total != null && total <= emailServer1.getMaxQuantity()) {
emailServer = emailServer1;
break;
} else if (total == null) {
redisUtils.set(Constant.EMAIL_SERVER_SEND_QUANTITY + emailServer1.getUserName() + "#" + format, emailServer1.getMaxQuantity());
emailServer = emailServer1;
total = 0;
break;
}
}
if (emailServer != null) {
//组装并发送邮件
productEmailAndSend(emailServer, messageSystem, userResult, format, total);
} else {
log.error("无可用邮件服务器");
}
}
}
}
}
}
}
/**
* 获取所有邮件服务器信息
*
* @param serverMap
* @return
*/
private List<EmailServer> getEmailServerLists(Map<Object, Object> serverMap) {
List<EmailServer> servers = new ArrayList<>();
if (!CollectionUtils.isEmpty(serverMap)) {
for (Map.Entry<Object, Object> item : serverMap.entrySet()) {
servers.add((EmailServer) serverMap.get(item.getKey()));
}
log.info("从Redis中获取邮件服务器信息:{}", JSON.toJSONString(servers));
} else {
//缓存中无对应key,从数据库中查找
servers = emailService.selectAllEmailServer();
if (!CollectionUtils.isEmpty(servers)) {
List<EmailServer> emailServers = servers.stream().distinct().collect(Collectors.toList());
emailServers.forEach(email -> {
if (!StringUtils.isEmpty(email.getUserName())) {
redisUtils.hset(Constant.EMAIL_SERVER_INFO, email.getUserName(), email);
}
});
//设置key过期时间为1h
redisUtils.expire(Constant.EMAIL_SERVER_INFO, 60 * 60L);
}
log.info("从数据库中获取邮件服务器信息:{}", JSON.toJSONString(servers));
}
return servers.stream().distinct().collect(Collectors.toList());
}
/**
* 获取所有邮件发送者信息,先从缓存中获取,缓存中没有则从数据库中获取,再存入缓存
*
* @return
*/
private List<User> getEmailUsers() {
Map<Object, Object> map = redisUtils.hGetAll(Constant.EMAIL_USER_INFO);
List<User> allEmail = new ArrayList<>();
if (!CollectionUtils.isEmpty(map)) {
for (Map.Entry<Object, Object> item : map.entrySet()) {
allEmail.add((User) map.get(item.getKey()));
}
log.info("从缓存中获取邮件接收者信息:{}", JSON.toJSONString(allEmail));
} else {
allEmail = userService.getAllEmail();
List<User> users = null;
if (!CollectionUtils.isEmpty(allEmail)) {
users = allEmail.stream().distinct().collect(Collectors.toList());
}
//加锁
redisLock.lock(Constant.EMAIL_USER_SET_LOCK, REDIS_LOCK_EXPIRE);
users.forEach(email -> {
if (!StringUtils.isEmpty(email.getEmail())) {
redisUtils.hset(Constant.EMAIL_USER_INFO, email.getEmail(), email);
}
});
//设置key过期时间为1h
redisUtils.expire(Constant.EMAIL_USER_INFO, 60 * 60L);
redisLock.unlock(Constant.EMAIL_USER_SET_LOCK);
log.info("获取邮件接收者信息为:{}", JSON.toJSONString(allEmail));
}
return allEmail.stream().distinct().collect(Collectors.toList());
}
/**
* 组装并发送邮件信息
*
* @param emailServer 发送邮件的服务器
* @param messageSystem 需要发送的信息
* @param user 接收的用户
* @param format redis key组装
* @param total 服务发送邮件数量
*/
private void productEmailAndSend(EmailServer emailServer, MessageSystem messageSystem, User user, String
format, Integer total) {
EmailInfo emailInfo = new EmailInfo();
emailInfo.setSubject(messageSystem.getTitle());
emailInfo.setContent(messageSystem.getContent());
emailInfo.setDestination(user.getEmail());
emailInfo.setTitle(messageSystem.getTitle());
try {
EmailUtils.pushSimpleEmail(emailServer, emailInfo);
//发送成功后再加锁更新maxCount
//加锁,更新maxCount
redisLock.lock(Constant.SYSTEM_MESSAGE_LOCK, REDIS_LOCK_EXPIRE);
total++;
redisUtils.set(Constant.EMAIL_SERVER_SEND_QUANTITY + emailServer.getUserName() + "#" + format, total);
//解锁
redisLock.unlock(Constant.SYSTEM_MESSAGE_LOCK);
log.info("邮件信息发送完成:{},{}", JSON.toJSONString(emailInfo), JSON.toJSONString(emailServer));
} catch (Exception e) {
log.error("邮件发送异常:{}", e);
redisUtils.zadd(Constant.EMAIL_SEND_FAIL_QUEUE, JSON.toJSONString(messageSystem), System.currentTimeMillis() + 5 * 60 * 1000);
}
}
}
针对邮件服务器操作的业务逻辑代码如下:
import com.alibaba.fastjson.JSON;
import com.github.chimmhuang.redislock.lock.RedisLock;
import com.pubinfo.common.base.Page;
import com.pubinfo.common.enums.ErrorCode;
import com.pubinfo.common.exception.VideoPrivateWebException;
import com.pubinfo.common.util.RedisUtils;
import com.pubinfo.common.util.StringUtils;
import com.pubinfo.video.email.constant.Constant;
import com.pubinfo.video.email.dao.EmailServerMapper;
import com.pubinfo.video.email.domain.EmailServer;
import com.pubinfo.video.email.service.EmailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
@Slf4j
@Service("emailService")
public class EmailServiceImpl implements EmailService {
private static final Long CONNECT_TIME = 30 * 1000L;
private static final long REDIS_LOCK_EXPIRE = 30L;
@Resource
private EmailServerMapper emailServerMapper;
@Autowired
private RedisUtils redisUtils;
@Autowired
private RedisLock redisLock;
@Override
public void add(EmailServer emailServer) {
if (emailServer == null) {
log.error("emailServer不能为空!");
throw new VideoPrivateWebException(ErrorCode.CODE_10005, "emailServer");
}
if (emailServer.getSendTime() == null) {
emailServer.setSendTime(CONNECT_TIME);
}
if (emailServer.getReceiveTime() == null) {
emailServer.setReceiveTime(CONNECT_TIME);
}
if (emailServer.getConnectTime() == null) {
emailServer.setConnectTime(CONNECT_TIME);
}
Date date = new Date();
emailServer.setCreateTime(date);
emailServer.setModifyTime(date);
try {
EmailServer emailServer1 = emailServerMapper.selectByEmailAccount(emailServer.getUserName());
if (emailServer1 != null) {
log.error("邮件服务器已存在:{}", JSON.toJSONString(emailServer1));
throw new VideoPrivateWebException(ErrorCode.CODE_10108, "邮件服务器信息已存在");
}
emailServerMapper.insert(emailServer);
//更新信息到缓存中
if (!StringUtils.isEmpty(emailServer.getUserName())) {
redisUtils.hset(Constant.EMAIL_SERVER_INFO, emailServer.getUserName(), emailServer);
}
log.info("插入数据成功:{}", JSON.toJSONString(emailServer));
} catch (Exception e) {
log.error("数据库异常:{}", e);
throw new VideoPrivateWebException(ErrorCode.CODE_10004, e);
}
}
@Override
public void delete(Long id) {
if (id == null) {
log.error("id不能为空!");
throw new VideoPrivateWebException(ErrorCode.CODE_10005, "id");
}
try {
EmailServer emailServer = emailServerMapper.selectByPrimaryKey(id);
//同步清除缓存中信息
if (!StringUtils.isEmpty(emailServer.getUserName())) {
redisUtils.hdel(Constant.EMAIL_SERVER_INFO, emailServer.getUserName());
}
emailServerMapper.deleteByPrimaryKey(id);
log.info("删除数据成功,id:{}", id);
} catch (Exception e) {
log.error("数据库操作异常:{}", e);
throw new VideoPrivateWebException(ErrorCode.CODE_10004, e);
}
}
@Override
public void update(EmailServer emailServer) {
if (emailServer == null || emailServer.getId() == null) {
log.error("id不能为空!");
throw new VideoPrivateWebException(ErrorCode.CODE_10005, "id");
}
if (emailServer.getConnectTime() == null) {
emailServer.setConnectTime(CONNECT_TIME);
}
if (emailServer.getReceiveTime() == null) {
emailServer.setReceiveTime(CONNECT_TIME);
}
if (emailServer.getSendTime() == null) {
emailServer.setReceiveTime(CONNECT_TIME);
}
Date date = new Date();
emailServer.setModifyTime(date);
try {
EmailServer unUpdateServerInfo = emailServerMapper.selectByPrimaryKey(emailServer.getId());
emailServerMapper.updateByPrimaryKeySelective(emailServer);
EmailServer emailServer1 = emailServerMapper.selectByPrimaryKey(emailServer.getId());
//同步删除缓存中邮件服务器信息
if (!StringUtils.isEmpty(emailServer.getUserName())) {
EmailServer emailServerRedis = (EmailServer)redisUtils.hget(Constant.EMAIL_SERVER_INFO, unUpdateServerInfo.getUserName());
redisLock.lock(Constant.EMAIL_USER_SET_LOCK, REDIS_LOCK_EXPIRE);
if (emailServerRedis != null) {
//清除缓存中原先的服务器信息,设置新的服务器信息到缓存中
if (StringUtils.isEmpty(emailServer.getUserName()) || emailServer.getUserName().equals(unUpdateServerInfo.getUserName())) {
redisUtils.hdel(Constant.EMAIL_SERVER_INFO, emailServer1.getUserName());
} else {
redisUtils.hdel(Constant.EMAIL_SERVER_INFO, unUpdateServerInfo.getUserName());
}
}
redisUtils.hset(Constant.EMAIL_SERVER_INFO, emailServer1.getUserName(), emailServer1);
redisLock.unlock(Constant.EMAIL_USER_SET_LOCK);
}
log.info("更新邮件服务信息成功:{}", JSON.toJSONString(emailServer));
} catch (Exception e) {
log.error("数据更新异常:{}", e);
throw new VideoPrivateWebException(ErrorCode.CODE_10004, e);
}
}
@Override
public Page<EmailServer> queryListByParams(EmailServer emailServer) {
Integer pageSize = emailServer.getPageSize();
Integer start = (emailServer.getPageNo() - 1) * pageSize;
Page<EmailServer> page = new Page<>();
page.setPageNo(emailServer.getPageNo());
page.setPageSize(pageSize);
List<EmailServer> emailServers = null;
try {
Integer total = emailServerMapper.countByParams(emailServer);
page.setTotalCount(total);
emailServers = emailServerMapper.queryListByParams(emailServer, start, pageSize);
page.setList(emailServers);
log.info("根据条件查询emailServers,结果为:{}", JSON.toJSONString(emailServers));
} catch (Exception e) {
log.error("查询异常:{}", e);
throw new VideoPrivateWebException(ErrorCode.CODE_10004, e);
}
return page;
}
@Override
public EmailServer queryByParams(EmailServer emailServer) {
EmailServer emailServer1 = null;
try {
emailServer1 = emailServerMapper.queryByParams(emailServer);
log.info("根据条件查询emailServer,结果为:{}", JSON.toJSONString(emailServer));
} catch (Exception e) {
log.error("查询异常:{}", e);
throw new VideoPrivateWebException(ErrorCode.CODE_10004, e);
}
return emailServer1;
}
@Override
public List<EmailServer> selectAllEmailServer() {
List<EmailServer> emailServers = emailServerMapper.queryListByParams(null, null, null);
log.info("查询所有发送服务器信息:{}", JSON.toJSONString(emailServers));
return emailServers;
}
}
package com.pubinfo.config;
import com.github.chimmhuang.redislock.listener.RedisListener;
import com.github.chimmhuang.redislock.lock.RedisLock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import javax.annotation.Resource;
@Configuration
public class RedisLockConfiguration {
@Resource
RedisConnectionFactory redisConnectionFactory;
@Resource
private RedisTemplate<String, String> stringRedisTemplate;
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
return container;
}
@Bean
public RedisListener redisListener(RedisMessageListenerContainer redisMessageListenerContainer) {
return new RedisListener(redisMessageListenerContainer);
}
@Bean
public RedisLock redisLock() {
return new RedisLock(stringRedisTemplate);
}
}
1.本文主要利用JAVA实现多邮件服务器发送邮件,完善了SpringBoot开箱即用功能中只能配置单一邮件服务器的功能;
2.本文是基础功能的实现,未考虑并发情况,实际生产中,需要考虑并发所带来的数据不一致问题,以及发送失败的重试机制;
3.commons-email需要和JavaMail的包一起引入,否则会抛出异常。