JAVA实现多邮件服务器发送邮件

1.概述

在日常开发中,可能会遇到这样的开发需求:一些告警消息或者通知消息会使用邮件发送(针对一些消息重要但是对消息实时性要求不是特别高的场景),然而一些企业可能会有多个邮件服务器,每个邮件服务器每天只能发送指定数量的邮件,如何合理高效利用这些邮件服务器是开发者需要重点考虑的。由于SpringBoot项目对JavaMail进行了封装,方便开箱即用,然而此方案的缺陷在于只能配置一个邮件服务器地址,无法满足本文的需求。本文将基于上述需求,设计实现一种多邮件服务器发送邮件的功能,方便大家参考学习。

2.实现方案

2.1 详细需求

系统有一些通知消息和告警消息需要利用邮件服务器发送,有多个邮件服务器,每个邮件服务器每天能发送固定数量的邮件(超过最大数不再发送)。

2.2 分析设计

1.由于有多个邮件服务器,因此需要存储邮件服务器信息,考虑到变更和新增情况,此处选择存储在数据库中;
2.为了减轻每次查询邮件服务器信息所给数据库带来的压力,将邮件服务器信息同时存储到缓存中(设置过期时间),查询邮件服务器信息时先查询缓存,缓存中不存在时再查询数据库;
3.为了记录每台邮件服务器已发送邮件数量,缓存中需要记录邮件服务器已发送邮件数量;
4.多个线程同步发送邮件,更新缓存中邮件发送数量时需要加锁,本文利用redisLock来实现加锁操作;
5.本文使用Apache的commons-email来发送邮件,因为commons-email发送邮件的代码看起来更加简洁,commons-email底层需要依赖于JavaMail,因此在pom文件中需要引入commons-email和JavaMail。

2.3 具体实现

2.3.1 数据库设计

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;

2.3.2 pom文件引入

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

2.3.3 邮件发送工具类编写

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

2.3.4 相关实体

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


}

2.3.5 业务逻辑代码

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

2.3.6 RedisLock的配置

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

3.小结

1.本文主要利用JAVA实现多邮件服务器发送邮件,完善了SpringBoot开箱即用功能中只能配置单一邮件服务器的功能;
2.本文是基础功能的实现,未考虑并发情况,实际生产中,需要考虑并发所带来的数据不一致问题,以及发送失败的重试机制;
3.commons-email需要和JavaMail的包一起引入,否则会抛出异常。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值