邮件发送spring boot+ApplicationEventPublisher+线程池异步实现邮件发送

ApplicationEventPublisher:定义可以参考其他博客

在spring boot项目中用到需要发送邮件功能,以往只是简单抛个线程去做,现在看还有许多欠妥当地方,现在记录下来,先贴代码

ApplicationEventPublisher使用步骤

1.自定义一个邮箱事件 需要继承 ApplicationEvent 




import org.springframework.context.ApplicationEvent;

/**
 * <自定义邮箱事件>
 *
 * @author 
 */
public class EmailEvent extends ApplicationEvent {
    private String subject;//标题
    private String content;//内容
    private String sender;//发件人
    private String authorizationCode;//授权码
    private String receiver;//收件人


    /**
     * @param source
     */
    public EmailEvent(Object source) {
        super(source);

    }

    public EmailEvent(Object source,String subject, String content, String receiver) {
        super(source);
        this.subject = subject;
        this.content = content;
        this.receiver = receiver;
    }



    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }


    public String getAuthorizationCode() {
        return authorizationCode;
    }

    public void setAuthorizationCode(String authorizationCode) {
        this.authorizationCode = authorizationCode;
    }


    public String getSender() {
        return sender;
    }


    public void setSender(String sender) {
        this.sender = sender;
    }


    public String getReceiver() {
        return receiver;
    }


    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    
}

2.创建监听器,监听自定义的邮箱事件


package com.qgnjjl.organization.listener;

import com.qgnjjl.common.utils.EmailUtils;
import com.qgnjjl.common.utils.StringUtils;
import com.qgnjjl.organization.domain.EmailEvent;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import java.security.GeneralSecurityException;

/**
 * 〈邮箱发送〉<br> 
 * 发送邮件
 *
 * @author Administrator
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */


@Component
public class SendmailListener implements ApplicationListener<EmailEvent> {
    @Value("${email.sender}")
    private String sender;
    @Value("${email.authorizationCode}")
    private String authorizationCode;


    @Override
    @Async("taskExecutor")
    @Transactional(rollbackFor = Exception.class)
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void onApplicationEvent(EmailEvent emailEvent) {
        if (emailEvent == null || StringUtils.isEmpty(sender) || StringUtils.isEmpty(authorizationCode) || StringUtils.isEmpty(emailEvent.getReceiver()) ) {
            return ;
        }
        emailEvent.setSender(sender);
        emailEvent.setAuthorizationCode(authorizationCode);
        try {
            EmailUtils.sendMail(emailEvent);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
    }
}

3.推送邮箱事件


package com.qgnjjl.organization.publisher;

import com.qgnjjl.organization.domain.EmailEvent;
import com.qgnjjl.organization.domain.OrganizationDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

/**
 *ApplicationEventPublisher邮件推送
 *
 * @author xzx
 */
@Component
public class SendmaillEventPublisher {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void sendmail2MachineryEquipment(OrganizationDO organizationDO) {
        String sign = organizationDO.getUniquelyIdentifies();
        String key = organizationDO.getUniqueKey();
        //邮件内容
        String content = "内容"
        //邮件标题
        String subject ="主题";
        String email = organizationDO.getEmail();
        publisher.publishEvent(new EmailEvent(this,subject, content, email));
    }

}

4,在控制层调用邮箱推送

5.javaMail 工具类


package com.qgnjjl.common.utils;

import com.qgnjjl.organization.domain.EmailEvent;
import com.sun.mail.util.MailSSLSocketFactory;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.security.GeneralSecurityException;
import java.util.Properties;

/**
 * 〈一句话功能简述〉<br> 
 * 〈功能详细描述〉
 *
 * @author liuc
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class EmailUtils {

    public static String sendMail(EmailEvent event) throws GeneralSecurityException {
        String flag="发送成功!";
        System.out.println("=====邮件发送========");
        //使用MailSSLSocketFactory避免了需要添加证书
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        
        Properties prop = new Properties();
        prop.put("mail.host", "smtp.163.com");
        prop.put("mail.transport.protocol", "smtp");
        prop.put("mail.smtp.auth", false);
        prop.put("mail.smtp.ssl.enable", "true");
        prop.put("mail.smtp.ssl.socketFactory", sf);
        String nick="";
        try {
            // 使用java发送邮件5步骤
            // 1.创建sesssion
            Session session = Session.getInstance(prop);
            // 开启session的调试模式,可以查看当前邮件发送状态
            // session.setDebug(true);
            // 2.通过session获取Transport对象(发送邮件的核心API)
            Transport ts = session.getTransport();
            // 3.通过邮件用户名密码链接
            ts.connect(event.getSender(), event.getAuthorizationCode());
            // 4.创建邮件
            nick = MimeUtility.encodeText("昵称");
            Message msg = createSimpleMail(session, event.getSubject(), event.getContent(), event.getSender(), event.getReceiver());
            msg.setFrom(new InternetAddress(nick+"<"+event.getSender()+">"));
            // 5.发送电子邮件
            ts.sendMessage(msg, msg.getAllRecipients());
        } catch (Exception e) {
            e.printStackTrace();
            flag="发送失败!";
        }

        return flag;
    }

    public static MimeMessage createSimpleMail(Session session, String subject, String content, String from, String to)
            throws AddressException, MessagingException {
        // 创建邮件对象
        MimeMessage mm = new MimeMessage(session);
        // 设置发件人
        mm.setFrom(new InternetAddress(from));
        // 设置收件人
        mm.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
        // 设置抄送人
        // mm.setRecipient(Message.RecipientType.CC, new InternetAddress("[email protected]"));
        mm.setSubject(subject);
        mm.setContent(content, "text/html;charset=utf-8");
        return mm;
    }

}

6.线程池配置

package com.qgnjjl.common.config;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 〈线程池配置类〉<br> 
 *
 * @author lz
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
@EnableAsync
@Configuration
public class ExecutorConfig {
    /** 核心线程数 */
    private int corePoolSize = 10;
    /** 最大线程数  */
    private int maxPoolSize = 50;
    /** 队列大小  */
    private int queueCapacity = 10;
    /** 线程最大空闲时间   */
    private int keepAliveSeconds = 150;

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix("taskExecutor-");
        executor.setKeepAliveSeconds(keepAliveSeconds);
      
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

}
发布了10 篇原创文章 · 获赞 6 · 访问量 189

猜你喜欢

转载自blog.csdn.net/xzx19930928/article/details/95359206