原来有个教程是关于Javamail的,但是那个是自己写Javamail的发送过程,这次不同的是:使用Spring的Mail功能,使用了消息队列。
先看一下设想的场景
不过本文重点不是消息队列,而是使用spring发送邮件。
首先针对于不会Maven和消息队列的小盆友们
依赖jar包:
spring系列jar包
Javamail
先建立一个封装Mail信息的类:很好理解,里面的成员变量代表(收件人,主题,内容)
packagecom.mq.entity;importjava.io.Serializable;public class MailInfo implementsSerializable {/****/
private static final long serialVersionUID = -5853264487189248317L;privateString to;privateString subject;privateString content;publicMailInfo() {
}publicMailInfo(String to, String subject, String content) {this.to =to;this.subject =subject;this.content =content;
}publicString getTo() {returnto;
}public voidsetTo(String to) {this.to =to;
}publicString getSubject() {returnsubject;
}public voidsetSubject(String subject) {this.subject =subject;
}publicString getContent() {returncontent;
}public voidsetContent(String content) {this.content =content;
}
}
然后呢,在classpath下面整一个属性文件,email.properties
mail.account=用户名
mail.pass=密码
mail.host=smtp.exmail.qq.com
mail.port=465mail.protocol=smtp
mail.debug=truemail.smtp.auth=truemail.smtp.ssl.enable=true
注意:企业邮箱不用什么授权码,就是密码
然后classpath下建立spring配置文件。
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd">
${mail.smtp.auth}
${mail.debug}
${mail.smtp.ssl.enable}
mailSSLSocketFactory
然后写一个发送邮件类
packagecom.mq.mail;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.mail.SimpleMailMessage;importorg.springframework.mail.javamail.JavaMailSender;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importorg.springframework.stereotype.Component;importcom.mq.entity.MailInfo;
@Componentpublic classSendMail {
@AutowiredprivateJavaMailSender javaMailSender;
@AutowiredprivateSimpleMailMessage simpleMailMessage;
@AutowiredprivateThreadPoolTaskExecutor threadPoolTaskExecutor;public void send(finalMailInfo mailInfo){
threadPoolTaskExecutor.execute(newRunnable() {
@Overridepublic voidrun() {try{
simpleMailMessage.setTo(mailInfo.getTo());
simpleMailMessage.setSubject(mailInfo.getSubject());
simpleMailMessage.setText(mailInfo.getContent());
javaMailSender.send(simpleMailMessage);
}catch(Exception e) {
e.printStackTrace();
}
}
});
}
}
最后写一个测试类:
packagecom.mq.test;importorg.springframework.context.support.ClassPathXmlApplicationContext;importcom.mq.entity.MailInfo;importcom.mq.mail.SendMail;public classTestMail {public static voidmain(String[] args) {
ClassPathXmlApplicationContext app= new ClassPathXmlApplicationContext("classpath:spring-mail.xml");
app.start();
MailInfo mailInfo= new MailInfo("XXX@qq.com", "这是主题", "这是内容");
app.getBean(SendMail.class).send(mailInfo);
app.close();
}
}
结果:
下面是Maven+消息队列的部分
我有两个工程,一个是生产者,一个是消费者。都是Maven的web工程。PS:这两个工程加入了mvc,因为本来想做个好玩的东西的,但是太忙了,先放下了,目前只有利用消息队列发送邮件的部分。这也是为啥依赖这么多的原因。
首先是生产者
Maven依赖:
4.3.9.RELEASE
junit
junit
4.12
test
org.springframework
spring-test
${spring.version}
test
org.springframework
spring-context
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-beans
${spring.version}
org.springframework
spring-core
${spring.version}
org.springframework
spring-jms
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-aspects
${spring.version}
org.springframework
spring-expression
${spring.version}
org.springframework
spring-messaging
${spring.version}
org.apache.activemq
activemq-all
5.15.0
org.apache.activemq
activemq-pool
5.15.0
com.alibaba
fastjson
1.2.35
com.fasterxml.jackson.core
jackson-core
2.8.9
com.fasterxml.jackson.core
jackson-databind
2.8.9
com.fasterxml.jackson.core
jackson-annotations
2.8.9
javax.mail
1.4.7
javax.servlet
jstl
1.2
建立ActiveMQ的属性文件:activemq.properties
activemq.brokerUrl=tcp://localhost:61616
activemq.userName=admin
activemq.password=admin
activemq.pool.maxConnection=10activemq.queueName=foodQueue
activemq.topicName=foodTopic
因为是本地测试,我就在windows系统启动了一个ActiveMQ。
下面建立spring-activemq.xml
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
${activemq.queueName}
${activemq.topicName}
spring.xml
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
接下来写代码,目录结构如下:(你不需要考虑controller,以及spring-mvc.xml,以及Food)
建立Mail信息类:
packagecom.mq.entity;importjava.io.Serializable;public class MailInfo implementsSerializable {/****/
private static final long serialVersionUID = -5853264487189248317L;privateString to;privateString subject;privateString content;publicMailInfo() {
}publicMailInfo(String to, String subject, String content) {this.to =to;this.subject =subject;this.content =content;
}publicString getTo() {returnto;
}public voidsetTo(String to) {this.to =to;
}publicString getSubject() {returnsubject;
}public voidsetSubject(String subject) {this.subject =subject;
}publicString getContent() {returncontent;
}public voidsetContent(String content) {this.content =content;
}
}
View Code
关于那个Food是我测试着玩的哈哈,满足你的好奇心
packagecom.mq.entity;importjava.io.Serializable;importjava.util.Date;public class Food implementsSerializable {private static final long serialVersionUID = 1L;privateString foodName;private doublefoodPrice;private intfoodNumber;privateDate orderTime;publicFood() {
}public Food(String foodName, double foodPrice, intfoodNumber, Date orderTime) {super();this.foodName =foodName;this.foodPrice =foodPrice;this.foodNumber =foodNumber;this.orderTime =orderTime;
}publicString getFoodName() {returnfoodName;
}public voidsetFoodName(String foodName) {this.foodName =foodName;
}public doublegetFoodPrice() {returnfoodPrice;
}public void setFoodPrice(doublefoodPrice) {this.foodPrice =foodPrice;
}public intgetFoodNumber() {returnfoodNumber;
}public void setFoodNumber(intfoodNumber) {this.foodNumber =foodNumber;
}publicDate getOrderTime() {returnorderTime;
}public voidsetOrderTime(Date orderTime) {this.orderTime =orderTime;
}
@OverridepublicString toString() {return "Food [foodName=" + foodName + ", foodPrice=" + foodPrice + ", foodNumber=" + foodNumber + ", orderTime="
+ orderTime + "]";
}
}
View Code
消息服务接口
packagecom.mq.service;importjavax.jms.Destination;importorg.springframework.stereotype.Service;importcom.mq.entity.Food;importcom.mq.entity.MailInfo;
@Servicepublic interfaceHelloService {voidsendMessage(Destination destination, Food food);voidsendMail(Destination destination, MailInfo mail);
}
消息服务实现:
packagecom.mq.service.impl;importjavax.jms.Destination;importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.Session;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.jms.core.JmsTemplate;importorg.springframework.jms.core.MessageCreator;importorg.springframework.stereotype.Service;importcom.alibaba.fastjson.JSONObject;importcom.mq.entity.Food;importcom.mq.entity.MailInfo;importcom.mq.service.HelloService;
@Servicepublic class HelloServiceImpl implementsHelloService {
@AutowiredprivateJmsTemplate jmsTemplate;
@Overridepublic voidsendMessage(Destination destination, Food food){
jmsTemplate.send(destination,newMessageCreator() {
@Overridepublic Message createMessage(Session session) throwsJMSException {returnsession.createTextMessage(JSONObject.toJSONString(food));//return session.createObjectMessage(new Food("蛋糕", 66.5, 1, new Date()));
}
});
}
@Overridepublic voidsendMail(Destination destination, MailInfo mail) {
jmsTemplate.send(destination,newMessageCreator() {
@Overridepublic Message createMessage(Session session) throwsJMSException {returnsession.createTextMessage(JSONObject.toJSONString(mail));
}
});
}
}
最后是测试类,这里使用了springTest。
packagecom.mq.test;importjavax.jms.Destination;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;importcom.mq.entity.MailInfo;importcom.mq.service.HelloService;
@ContextConfiguration(locations={"classpath:spring.xml"})
@RunWith(SpringJUnit4ClassRunner.class)public classMyTest {//@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。//使用@Autowired的话,想使用名称装配可以结合@Qualifier注解进行使用//@Resource(这个注解属于J2EE的),默认安照名称进行装配,名称可以通过name属性进行指定,//如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。
@AutowiredprivateHelloService helloService;
@Autowired
@Qualifier("queueDestination")privateDestination destination;
@Testpublic voidtest(){//helloService.sendMessage(destination, new Food("蛋糕", 66.5, 1, new Date()));
for (int i = 0; i < 1; i++) {
helloService.sendMail(destination,new MailInfo("XXX@qq.com", "Spring java mail"+i, "生产者-消息队列-消费者-spring-mail"));
}
}
}
下面是消费者:
依赖和生产者一样的,这里不重复了。activemq.properties也一样。
邮箱属性文件:
mail.account=用户名
mail.pass=密码
mail.host=smtp.exmail.qq.com
mail.port=465mail.protocol=smtp
mail.debug=truemail.smtp.auth=truemail.smtp.ssl.enable=true
spring-activemq.xml:
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
${activemq.queueName}
${activemq.topicName}
spring-mail.xml:
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd">
${mail.smtp.auth}
${mail.debug}
${mail.smtp.ssl.enable}
mailSSLSocketFactory
spring.xml
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
下面是工程结构:entity不说了,是一样的。
ActiveMQ监听器:
packagecom.mq.listener;importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.MessageListener;importjavax.jms.TextMessage;importorg.springframework.beans.factory.annotation.Autowired;importcom.alibaba.fastjson.JSONObject;importcom.mq.entity.MailInfo;importcom.mq.mail.SendMail;public class ActiveMQListener implementsMessageListener {
@AutowiredprivateSendMail sendMail;
@Overridepublic voidonMessage(Message message) {
TextMessage text=(TextMessage) message;try{
MailInfo mail= JSONObject.parseObject(text.getText(), MailInfo.class);if(mail != null){
System.out.println(mail.getTo()+ "," + mail.getSubject() + "," +mail.getContent());
System.out.println("发送邮件...");
sendMail.send(mail);
}
}catch(JMSException e) {//TODO Auto-generated catch block
e.printStackTrace();
}//try {//System.out.println(text.getText());//Food food = JSONObject.parseObject(text.getText(), Food.class);//System.out.println("============收到消息===========");//System.out.println(food);//} catch (JMSException e) {//e.printStackTrace();//}
}
}
SendMail:
packagecom.mq.mail;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.mail.SimpleMailMessage;importorg.springframework.mail.javamail.JavaMailSender;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importorg.springframework.stereotype.Component;importcom.mq.entity.MailInfo;
@Componentpublic classSendMail {
@AutowiredprivateJavaMailSender javaMailSender;
@AutowiredprivateSimpleMailMessage simpleMailMessage;
@AutowiredprivateThreadPoolTaskExecutor threadPoolTaskExecutor;public void send(finalMailInfo mailInfo){
threadPoolTaskExecutor.execute(newRunnable() {
@Overridepublic voidrun() {try{
simpleMailMessage.setTo(mailInfo.getTo());
simpleMailMessage.setSubject(mailInfo.getSubject());
simpleMailMessage.setText(mailInfo.getContent());
javaMailSender.send(simpleMailMessage);
}catch(Exception e) {
e.printStackTrace();
}
}
});
}
}
最后测试:
packagecom.mq.test;importjavax.jms.Destination;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration(locations={"classpath:spring.xml"})
@RunWith(SpringJUnit4ClassRunner.class)public classMyTest {//@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。//使用@Autowired的话,想使用名称装配可以结合@Qualifier注解进行使用//@Resource(这个注解属于J2EE的),默认安照名称进行装配,名称可以通过name属性进行指定,//如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。
@Autowired
@Qualifier("queueDestination")privateDestination destination;
@Testpublic voidtest(){try{
Thread.sleep(Integer.MAX_VALUE);
}catch(InterruptedException e) {//TODO Auto-generated catch block
e.printStackTrace();
}//在单元测试里,如果test方法先于我们要执行的任务结束,会导致任务出错,所以我们这里睡眠了MAX秒,就为了给我们的任务争取时间
}
}
先启动ActiveMQ,然后执行生产者的test方法,
然后执行消费者的test方法。
结果:
你运行的时候记得修改收件人哦,别给我发哦。