activemq java 异步_ActiveMQ入门系列之应用:Springboot+ActiveMQ+JavaMail实现异步邮件发送...

本文介绍了如何使用Springboot结合ActiveMQ实现异步邮件发送。首先讲解了JavaMailSender的基本用法,然后展示了如何配置Springboot与JavaMailSender发送不同类型的邮件。接着,文章介绍了如何整合ActiveMQ,通过JmsTemplate发送消息到队列,并创建监听器消费消息以实现异步邮件发送。最后,文中列出了解决ActiveMQ中遇到的序列化和bean初始化问题的方法。
摘要由CSDN通过智能技术生成

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

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

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

一、springboot整合JavaMailSender

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

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

新建springboot工程:mail-sender

添加配置文件: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-8mail.to=xxxx@qq.com (为了方便,我这里将收件人统一配置成一个,实际业务中肯定按照实际情况发送的)

至于授权码的获取,需要到qq邮箱里面 设置->账户,然后到图示的地方,开启服务,然后根据提示获取授权码

525951acd84f758e36e4e36668f010c4.png

接下来实现发送邮件的代码

packagecom.mail.service.impl;importcom.mail.service.MailService;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.core.io.FileSystemResource;importorg.springframework.mail.SimpleMailMessage;importorg.springframework.mail.javamail.JavaMailSender;importorg.springframework.mail.javamail.MimeMessageHelper;importorg.springframework.stereotype.Service;importorg.springframework.util.StringUtils;importjavax.mail.internet.MimeMessage;importjava.io.File;

@Servicepublic class MailServiceImpl implementsMailService {private final Logger logger = LoggerFactory.getLogger(this.getClass());

@AutowiredprivateJavaMailSender mailSender;//注入JavaMailSender,具体发送工作需要它完成

@Value("${spring.mail.username}")//从配置文件中获取发件人邮箱publicString from;/*** 发送普通文本邮件*/@Overridepublic voidsendSimpleMail(String to, String subject, String context){

SimpleMailMessage mailMessage= newSimpleMailMessage();

mailMessage.setFrom(from);//发件人

mailMessage.setTo(to);//收件人

mailMessage.setSubject(subject);//邮件主题

mailMessage.setText(context);//邮件正文

mailSender.send(mailMessage);//发送邮件

logger.info("邮件发送成功");

}/*** 发送HTML邮件*/@Overridepublic voidsendMimeMail(String to, String subject, String context){

MimeMessage mailMessage=mailSender.createMimeMessage();try{//发送非纯文本的邮件都需要用的helper来解析

MimeMessageHelper helper= newMimeMessageHelper(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);

}

}/*** 发送带附件的邮件*/@Overridepublic voidsendAttachMail(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(newFile(filePath));

helper.addAttachment(file.getFilename(),file);//添加附件,需要用到FileStstemResource

mailSender.send(message);

logger.info("带邮件的附件发送成功");

}catch(Exception ex){

logger.error("带附件的邮件发送失败",ex);

}

}/*** 发送正文带图片的邮件*/@Overridepublic voidsendInlineMail(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(newFile(filePath));

helper.addInline(resId, res);

mailSender.send(message);

logger.info("邮件发送成功");

}catch(Exception ex){

logger.error("邮件发送失败",ex);

}

}}

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

编写测试类

packagecom.mail;importcom.mail.service.MailService;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)

@SpringBootTestpublic classMailServiceTest {

@Autowired

MailService mailService;

@Value("${mail.to}")privateString mailTo;

@Testpublic voidtestSimpleMail(){

mailService.sendSimpleMail(mailTo,"纯文本邮件","你好,这是一封测试邮件");

}

@Testpublic voidtestMimeMail(){

String context= "\n" +

"

\n" +

"你好,
" +

"这是一封HTML邮件\n" +

"\n" +

"";

mailService.sendMimeMail(mailTo,"HTML邮件",context);

}

@Testpublic voidtestSendAttachMail(){

String[] to= {mailTo,这里是收件人邮箱};

mailService.sendAttachMail(to,"带附件的邮件","你好,这是一封带附件的邮件","D:\\1.jpg");

}

@Testpublic voidtestSendInlineMail(){

String resId= "1";

String context= "

你好,
这是一封带静态资源的邮件 %5C'cid:%22+resId+%22%5C'";

mailService.sendInlineMail(mailTo,"带静态图片的邮件",context,"D:\\1.jpg",resId);

}

}

分别执行以上@Test方法

3b634bd38848bee19f215a5e2ba4dbd1.png

96088572728614cd2e561bb903628895.png

5db2c156f005bed3481b70abb9a2b40d.png

d75b4130f83ca17e997dc5778988d7aa.png

cca91501b70c070628a4f2e3ceb4434b.png

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

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

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

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

2625f0620f07cea8e9f5df2b8045f2ee.png

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

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

具体代码如下:

修改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=truespring.activemq.packages.trust-all=true

实现MQ发送的service

packagecom.mail.service.impl;importcom.alibaba.fastjson.JSON;importcom.mail.model.MailBean;importcom.mail.service.ActiveMQService;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.jms.core.JmsTemplate;importorg.springframework.stereotype.Service;

@Servicepublic class ActiveMQServiceImpl implementsActiveMQService {private Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired

JmsTemplate template;

@Value("${com.sam.mail.queue}")privateString queueName;

@Overridepublic voidsendMQ(String[] to, String subject, String content) {this.sendMQ(to,subject,content,null);

}

@Overridepublic voidsendMQ(String[] to, String subject, String content, String filePath) {this.sendMQ(to,subject,content,filePath,null);

}

@Overridepublic voidsendMQ(String[] to, String subject, String content, String filePath, String srcId) {

MailBean bean= newMailBean();

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

}

}

实现消息发送的controller

packagecom.mail.controller;importcom.mail.service.ActiveMQService;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjavax.annotation.Resource;/***@authorJAVA开发老菜鸟*/@RestControllerpublic classMailSenderController {

@Resource

ActiveMQService activeMQService;

@Value("${mail.to}")privateString mailTo;

@RequestMapping("/sendSimpleMail.do")public voidsendSimpleMail(){

String[] to={mailTo};

String subject= "普通邮件";

String context= "你好,这是一封普通邮件";

activeMQService.sendMQ(to, subject, context);

}

@RequestMapping("/sendAttachMail.do")public voidsendAttachMail(){

String[] to={mailTo};

String subject= "带附件的邮件";

String context= "

你好,
这是一封带附件的邮件,
具体请见附件";

String filePath= "D:\\1.jpg";

activeMQService.sendMQ(to, subject, context, filePath);

}

@RequestMapping("/sendMimeMail.do")public voidsendMimeMail(){

String[] to={mailTo};

String subject= "普通邮件";

String filePath= "D:\\1.jpg";

String resId= "1.jpg";

String context= "

你好,
这是一封带图片的邮件,
请见图片 %5C'cid:%22+resId+%22%5C'";

activeMQService.sendMQ(to, subject, context, filePath, resId);

}

}

MailBean的具体实现

public class MailBean implementsSerializable {private String from;//发件人

private String[] to;//收件人列表

private String subject;//邮件主题

private String content;//邮件正文

private String filePath;//文件(图片)路径

private String srcId;//图片名

......

getter/setter略

......

}

消费者监听实现

packagecom.mail.listener;importcom.mail.model.MailBean;importcom.mail.service.MailService;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.jms.annotation.JmsListener;importorg.springframework.stereotype.Service;importjavax.jms.ObjectMessage;importjava.io.Serializable;/*** 监听到MQ后调用mailService执行邮件发送操作*/@Servicepublic classSendMailMQListener {

Logger logger= LoggerFactory.getLogger(this.getClass());

@Autowired

MailService mailService;/*** 通过监听目标队列实现功能*/@JmsListener(destination= "${com.sam.mail.queue}")public voiddealSenderMailMQ(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);

}

}

}

监听器调用的发送接口在前面没有,是新加的

@Overridepublic voidsendMail(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(newFile(filePath));

helper.addInline(resId, resource);

}else if(!StringUtils.isEmpty(filePath)){//只有文件路径不为空,视为附件

FileSystemResource resource = new FileSystemResource(newFile(filePath));

helper.addAttachment(resource.getFilename(),resource);

}

mailSender.send(message);

logger.info("邮件发送成功");

}catch(Exception ex){

logger.error("邮件发送错误:", ex);

}

启动工程,分别调用controller中的uri,查看结果

e7ad0273070c292410d53743692e93aa.png

e1a09729d9f37884ad8b86d33779f57b.png

e30cb8e97f57ae52514afb8fb6005e2e.png

f417a32c64bc7b7db49e3934fe258887.png

查看下mq的页面控制台

73a1b935161a6a65f5023c53536e6e6c.png

至此,功能已经实现。

三、遇到过的问题

在实现这个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实现异步邮件发送的全部内容了,

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值