ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

我们都买过火车票,买完后会有邮件提醒,有时候邮件并不是买完票立马就能收到邮件通知,这个就用到了异步邮件发送。这篇文章介绍了怎么实现异步邮件发送

大家好,又见面了,我是全栈君。

现在邮件发送功能已经是几乎每个系统或网址必备的功能了,从用户注册的确认到找回密码再到消息提醒,这些功能普遍的会用到邮件发送功能。我们都买过火车票,买完后会有邮件提醒,有时候邮件并不是买完票立马就能收到邮件通知,这个就用到了异步邮件发送。

那怎么实现邮件的异步发送呢?

很显然,引入MQ是一个不错的选择。刚好这段时间在练习ActiveMQ,那就拿activemq来实现异步发送邮件吧。

一、springboot整合JavaMailSender

在发送异步邮件之前,先来简单介绍下邮件发送的基本内容,了解邮件是怎么发送的,然后再在此基础上添加activemq。

要发送邮件就要用到JavaMail,它是Java官方为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持常见的邮件协议:SMTP/POP3/IMAP/MIME等。想要发送邮件只需要调用JavaMail的API即可。后来,Spring对于JavaMail进行了封装,然后springboot又进一步封装,现在使用起来非常方便。请看代码:

  1. 新建springboot工程:mail-sender
  2. 添加配置文件:application.properties
    ###mail config ###
    spring.mail.host=smtp.qq.com(配置邮件发送协议)
    spring.mail.username=xxxx@qq.com(发件人,具体配成你需要的邮箱)
    spring.mail.password=对于qq邮箱来说,这里不是密码,而是授权码
    spring.mail.default-encoding=utf-8
    
    mail.to=xxxx@qq.com (为了方便,我这里将收件人统一配置成一个,实际业务中肯定按照实际情况发送的)

    至于授权码的获取,需要到qq邮箱里面 设置->账户,然后到图示的地方,开启服务,然后根据提示获取授权码ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

     

  3. 接下来实现发送邮件的代码
    package com.mail.service.impl;
    
    import com.mail.service.MailService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.core.io.FileSystemResource;
    import org.springframework.mail.SimpleMailMessage;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.mail.javamail.MimeMessageHelper;
    import org.springframework.stereotype.Service;
    import org.springframework.util.StringUtils;
    
    import javax.mail.internet.MimeMessage;
    import java.io.File;
    
    @Service
    public class MailServiceImpl implements MailService {
    
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
        @Autowired
        private JavaMailSender mailSender;//注入JavaMailSender,具体发送工作需要它完成
    
        @Value("${spring.mail.username}")//从配置文件中获取发件人邮箱
        public String from;
    
        /**
         * 发送普通文本邮件
         */
        @Override
        public void sendSimpleMail(String to, String subject, String context){
            SimpleMailMessage mailMessage = new SimpleMailMessage();
            mailMessage.setFrom(from);//发件人
            mailMessage.setTo(to);//收件人
            mailMessage.setSubject(subject);//邮件主题
            mailMessage.setText(context);//邮件正文
    
            mailSender.send(mailMessage);//发送邮件
            logger.info("邮件发送成功");
        }
    
        /**
         * 发送HTML邮件
         */
        @Override
        public void sendMimeMail(String to, String subject, String context){
            MimeMessage mailMessage = mailSender.createMimeMessage();
            try{//发送非纯文本的邮件都需要用的helper来解析
                MimeMessageHelper helper = new MimeMessageHelper(mailMessage);
                helper.setFrom(from);
                helper.setTo(to);
    //            helper.setBcc("xxxx@qq.com");//抄送人
                helper.setSubject(subject);
                helper.setText(context,true);//这里的第二个参数要为true才会解析html内容
                mailSender.send(mailMessage);
                logger.info("邮件发送成功");
            } catch(Exception ex){
                logger.error("邮件发送失败",ex);
            }
        }
    
        /**
         * 发送带附件的邮件
         */
        @Override
        public void sendAttachMail(String[] to, String subject, String context, String filePath) {
            MimeMessage message = mailSender.createMimeMessage();
            try{
                MimeMessageHelper helper = new MimeMessageHelper(message,true);
                helper.setFrom(from);
                helper.setTo(to);
                helper.setSubject(subject);
                helper.setText(context);
    
                FileSystemResource file = new FileSystemResource(new File(filePath));
                helper.addAttachment(file.getFilename(),file);//添加附件,需要用到FileStstemResource
    
                mailSender.send(message);
                logger.info("带邮件的附件发送成功");
            }catch(Exception ex){
                logger.error("带附件的邮件发送失败",ex);
            }
        }
    
        /**
         * 发送正文带图片的邮件
         */
        @Override
        public void sendInlineMail(String to, String subject, String context, String filePath, String resId) {
            MimeMessage message = mailSender.createMimeMessage();
            try{
                MimeMessageHelper helper = new MimeMessageHelper(message,true);
                helper.setFrom(from);
                helper.setTo(to);
                helper.setSubject(subject);
                helper.setText(context,true);
    
                FileSystemResource res = new FileSystemResource(new File(filePath));
                helper.addInline(resId, res);
                mailSender.send(message);
                logger.info("邮件发送成功");
            } catch (Exception ex){
                logger.error("邮件发送失败",ex);
            }
        }
    
    }

    代码中分别对发送普通文本邮件、HTML邮件、代码附件的邮件、带图片的邮件进行了示范

  4. 编写测试类
    package com.mail;
    
    import com.mail.service.MailService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MailServiceTest {
        @Autowired
        MailService mailService;
    
        @Value("${mail.to}")
        private String mailTo;
        
        @Test
        public  void testSimpleMail(){
            mailService.sendSimpleMail(mailTo,"纯文本邮件","你好,这是一封测试邮件");
        }
        @Test
        public  void testMimeMail(){
            String context = "<html>\n" +
                    "<body>\n" +
                    "你好,<br>" +
                    "这是一封HTML邮件\n" +
                    "</body>\n" +
                    "</html>";
            mailService.sendMimeMail(mailTo,"HTML邮件",context);
        }
    
        @Test
        public void testSendAttachMail(){
            String[] to = {mailTo,这里是收件人邮箱};
            mailService.sendAttachMail(to,"带附件的邮件","你好,这是一封带附件的邮件","D:\\1.jpg");
        }
    
        @Test
        public void testSendInlineMail(){
            String resId = "1";
            String context = "<html><body>你好,<br>这是一封带静态资源的邮件<br><img src=\'cid:"+resId+"\'></body></html>";
            mailService.sendInlineMail(mailTo,"带静态图片的邮件",context,"D:\\1.jpg",resId);
        }
    
    }

     

  5. 分别执行以上@Test方法ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

     

邮件发送的代码基本实现了解了,接下来引入activemq的实现。 

二、springboot整合ActiveMQ实现异步邮件发送

springboot整合ActiveMQ其实也比较简单,首先配置文件中需要添加ActiveMQ的相关配置,然后生产者通过注入JmsTemplate发送消息,消费者实现监听消费。

实现功能后,最终代码结构:

ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

controller+ActiveMQService扮演生产者角色,发送消息给消费者;

listener扮演消费者角色,接收到消息后调用MailService的接口执行邮件发送。

具体代码如下:

  1. 修改application.properties,添加如下内容
    ###queue name###
    com.sam.mail.queue=com.sam.mail.queue
    
    ###activemq config###
    #mq服务地址
    spring.activemq.broker-url=tcp://localhost:61616
    spring.activemq.pool.enabled=false
    #mq用户名和密码
    spring.activemq.user=admin
    spring.activemq.password=admin
    #处理序列化对象需要用到的配置
    spring.activemq.packages.trusted=true
    spring.activemq.packages.trust-all=true

     

  2. 实现MQ发送的service
    package com.mail.service.impl;
    
    import com.alibaba.fastjson.JSON;
    import com.mail.model.MailBean;
    import com.mail.service.ActiveMQService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.stereotype.Service;
    
    @Service
    public class ActiveMQServiceImpl implements ActiveMQService {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
        @Autowired
        JmsTemplate template;
    
        @Value("${com.sam.mail.queue}")
        private String queueName;
    
        @Override
        public void sendMQ(String[] to, String subject, String content) {
    
            this.sendMQ(to,subject,content,null);
        }
    
        @Override
        public void sendMQ(String[] to, String subject, String content, String filePath) {
            this.sendMQ(to,subject,content,filePath,null);
        }
    
        @Override
        public void sendMQ(String[] to, String subject, String content, String filePath, String srcId) {
            MailBean bean = new MailBean();
            bean.setTo(to);
            bean.setSubject(subject);
            bean.setContent(content);
            bean.setFilePath(filePath);
            bean.setSrcId(srcId);
            template.convertAndSend(queueName,bean);
            logger.info("邮件已经发送到MQ:"+ JSON.toJSONString(bean));
        }
    }

     

  3. 实现消息发送的controller
    package com.mail.controller;
    
    import com.mail.service.ActiveMQService;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    
    /**
     * @author JAVA开发老菜鸟
     */
    
    @RestController
    public class MailSenderController {
    
        @Resource
        ActiveMQService activeMQService;
    
        @Value("${mail.to}")
        private String mailTo;
        
        @RequestMapping("/sendSimpleMail.do")
        public void sendSimpleMail(){
            String[] to = {mailTo};
            String subject = "普通邮件";
            String context = "你好,这是一封普通邮件";
            activeMQService.sendMQ(to, subject, context);
        }
    
        @RequestMapping("/sendAttachMail.do")
        public void sendAttachMail(){
            String[] to = {mailTo};
            String subject = "带附件的邮件";
            String context = "<html><body>你好,<br>这是一封带附件的邮件,<br>具体请见附件</body></html>";
            String filePath = "D:\\1.jpg";
            activeMQService.sendMQ(to, subject, context, filePath);
        }
    
        @RequestMapping("/sendMimeMail.do")
        public void sendMimeMail(){
            String[] to = {mailTo};
            String subject = "普通邮件";
    
            String filePath = "D:\\1.jpg";
            String resId = "1.jpg";
            String context = "<html><body>你好,<br>这是一封带图片的邮件,<br>请见图片<br><img src=\'cid:"+resId+"\'></body></html>";
            activeMQService.sendMQ(to, subject, context, filePath, resId);
        }
    
    }

     

  4. MailBean的具体实现
    public class MailBean implements Serializable {
        private String from;//发件人
        private String[] to;//收件人列表
        private String subject;//邮件主题
        private String content;//邮件正文
        private String filePath;//文件(图片)路径
        private String srcId;//图片名
    
        ......  
        getter/setter略
        ......  
    }

     

  5. 消费者监听实现
    package com.mail.listener;
    
    import com.mail.model.MailBean;
    import com.mail.service.MailService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jms.annotation.JmsListener;
    import org.springframework.stereotype.Service;
    
    import javax.jms.ObjectMessage;
    import java.io.Serializable;
    
    /**
     * 监听到MQ后调用mailService执行邮件发送操作
     */
    @Service
    public class SendMailMQListener {
    
        Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        MailService mailService;
    
        /**
         * 通过监听目标队列实现功能
         */
        @JmsListener(destination = "${com.sam.mail.queue}")
        public void dealSenderMailMQ(ObjectMessage message){
            try{
                Serializable object = message.getObject();
                MailBean bean =  (MailBean) object;
                mailService.sendMail(bean.getTo(),bean.getSubject(),bean.getContent(),bean.getFilePath(),bean.getSrcId());
                logger.error("消费者消费邮件信息成功");
            } catch (Exception ex){
                logger.error("消费者消费邮件信息失败:"+ ex);
            }
    
        }
    }

     

  6. 监听器调用的发送接口在前面没有,是新加的
    @Override
        public void sendMail(String[] to, String subject, String context, String filePath, String resId ){
            MimeMessage message = mailSender.createMimeMessage();
            try{
                MimeMessageHelper helper = new MimeMessageHelper(message, true);
                helper.setFrom(from);
                helper.setTo(to);
                helper.setSubject(subject);
                helper.setText(context, true);
                if(!StringUtils.isEmpty(filePath) && !StringUtils.isEmpty(resId)){//文件路径和resId都不为空,视为静态图片
                    FileSystemResource resource = new FileSystemResource(new File(filePath));
                    helper.addInline(resId, resource);
                } else if(!StringUtils.isEmpty(filePath)){//只有文件路径不为空,视为附件
                    FileSystemResource resource = new FileSystemResource(new File(filePath));
                    helper.addAttachment(resource.getFilename(),resource);
                }
    
                mailSender.send(message);
                logger.info("邮件发送成功");
            } catch (Exception ex){
                logger.error("邮件发送错误:", ex);
            }

     

  7. 启动工程,分别调用controller中的uri,查看结果ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

    ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

    ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

    ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

     

  8. 查看下mq的页面控制台ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送「建议收藏」

     

 至此,功能已经实现。

三、遇到过的问题

在实现这个demo的时候,遇到了一些问题,也把它们列出来,给别人一个参考

第一个问题:

消费者消费邮件信息失败:javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Forbidden class com.mail.model.MailBean! This class is not trusted to be serialized as ObjectMessage payload. Please take a look at http://activemq.apache.org/objectmessage.html for more information on how to configure trusted classes.

This class is not trusted to be serialized as ObjectMessage payload,是说我的MailBean对象不是可以新人的序列化对象,

原因:

传递对象消息时 ,ActiveMQ的ObjectMessage依赖于Java的序列化和反序列化,但是这个过程被认为是不安全的。具体信息查看报错后面的那个网址:

http://activemq.apache.org/objectmessage.html

解决方法:

在application.properties文件中追加下面的配置即可

spring.activemq.packages.trust-all=true

 

第二个问题:

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean of type 'com.mail.service.ActiveMQService' that could not be found.


Action:

Consider defining a bean of type 'com.mail.service.ActiveMQService' in your configuration.

原因:

ActiveMQService没有被spring扫描并初始化,然后我在代码用通过@Autowaired注解使用获取不到。 找了之后发现是我的@Service注解放到了interface上,应该放到service的impl类上。

解决方法:

将@Service注解放到impl类上

 

 好,以上就是Springboot+ActiveMQ+JavaMail实现异步邮件发送的全部内容了,

觉得有帮助的话,记得点赞哦~~

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120885.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 到底什么是爱_pipeline模式

    到底什么是爱_pipeline模式在各个领域,有一个词眼出现得越来越频繁,即Pipeline。开始接触的时候,百思不得其解,要么觉得作者在用个洋名字在装高大上,其实,鲁迅先生说过一句话,太阳底下没有新鲜事一切的一切,都是纸老虎,Pipeline,你土味一点你把它翻译成一条龙服务专业一点,叫它综合解决方案,就行。算法或者大数据分析里的可重复使用,针对新的数据,直接输入数据,…

    2022年10月22日
  • navict 15激活码_最新在线免费激活2022.02.17

    (navict 15激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlFZP9ED60OK-eyJsaWNlbnNlSWQi…

  • vscode中svn使用详解_iis配置步骤

    vscode中svn使用详解_iis配置步骤XcodeSVN配置方法    Mac自带svn,所以我们就不需要下载了,稍稍修改一下subversion配置就能使用。大大教了两种方法:第一步,配置Subversion  Leopard中自带了SVN,但Xcode的项目文件中,并不是所有文件都适于加入SVN中进行管理,比如编译后的文件和编译过程中产生的文件,这些文件不属于源代码,应该告诉svn忽略掉,方法:  编辑~/.subversi

  • rsync服务的三种模式测试[通俗易懂]

    rsync服务的三种模式测试[通俗易懂]目录1什么是rsync1.1rsync简介rsync特性1.3rsync的企业工作场景说明2rsync三种模式:2.1rsync常用参数选项2.2rsync本地模式2.3rsyncshell模式2.4rsyncdaemon模式3rsync服务故障模拟4rsync多模块实战5rsync排除及无差异同步实战6rsync优缺点6….

    2022年10月13日
  • savefiledialog用法python_openfiledialog选择文件夹

    savefiledialog用法python_openfiledialog选择文件夹publicTestOne(){InitializeComponent();SaveFileDialog();//调用打开保存对话框}#region保存对话框privatevoidSaveFileDialog(){//stringlocalFilePath,fileNameExt,newFileName

  • 计算机二级python备考经验_计算机基础知识点

    计算机二级python备考经验_计算机基础知识点计算机二级于18年新增了Python栏目,我正好在上学期自学了Python语言。说实话,Python语言正的简洁强大,也是因为它让我改变了对编程的理解,当然还得感谢一位老师:北京理工的嵩天老师,他的网课很nice,也是他的讲解让我喜欢上了Python,喜欢上了编程,虽然之前有学过C/C++,web设计等语言,但有许多还是不够理解的。下面介绍正题:二级Python整体来说难度不大:20道选择…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号