摘要:给用户发送邮件的场景,其实也是比较常见的,比如用户注册需要邮箱验证,用户异地登录发送邮件通知等等,在这里我以 RabbitMQ 实现异步发送邮件。
项目git地址:https://github.com/gitcaiqing/RabbitMQ-Email
1.项目结构
2.构建项目
创建maven项目,引入jar包,pom.xml配置如下
4.0.0
com.sc
RabbitMQ-Emali
0.0.1-SNAPSHOT
war
UTF-8
4.1.4.RELEASE
2.5.0
1.2.3
com.rabbitmq
amqp-client
3.4.1
org.springframework.amqp
spring-rabbit
1.4.0.RELEASE
javax.mail
mail
1.4.7
org.springframework
spring-core
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-oxm
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-test
${spring.version}
log4j
log4j
1.2.17
org.slf4j
slf4j-api
1.7.7
org.slf4j
slf4j-log4j12
1.7.7
javax.servlet
javax.servlet-api
3.0.1
provided
javax.servlet
jstl
1.2
org.codehaus.jackson
jackson-mapper-asl
1.9.13
com.fasterxml.jackson.core
jackson-annotations
${jackson.version}
com.fasterxml.jackson.core
jackson-core
${jackson.version}
com.fasterxml.jackson.core
jackson-databind
${jackson.version}
org.apache.maven.plugins
maven-compiler-plugin
3.2
1.7
3.项目配置,着重实现邮件发送,配置简化处理
3.1 RabbitMQ和邮件地址配置config->config.properties
#RabbitMQ 连接配置
rmq.host=127.0.0.1
rmq.port=5672
rmq.user=guest
rmq.password=guest
rmq.channelCacheSize=25
rmq.virtual=/
#邮件发送配置
# 163 mail server
mail.protocol=smtp
mail.port=25
mail.host=smtp.163.com
#发送邮件的邮箱地址账号信息
[email protected]
[email protected]
mail.password=xxxxxxxxx
# qq mail server
#mail.protocol=smtp
#mail.port=465
#mail.host=smtp.exmail.qq.com
#[email protected]
#mail.password=
3.2 spring 配置spring->applicationContext.xml
3.3 spring邮件配置spring->spring-mail.xml
Spring 邮件发送bean配置
true
25000
javax.net.ssl.SSLSocketFactory
true
3.4 RabbitMQ配置spring-rabbitmq.xml
Spring RabbitMQ 路由模式(Routing)配置
3.5 spring mvc配置servlet->spring-mvc.xml
3.6 web.xml配置
RabbitMQ-Emali
contextConfigLocation
classpath*:spring/*.xml,classpath*:servlet/*.xml
org.springframework.web.context.ContextLoaderListener
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
forceEncoding
true
encodingFilter
/*
springMvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath*:servlet/*.xml
1
springMvc
/
30
login.jsp
4.创建用户对象entity->user
简单创建用户对象包含用户名,密码,邮箱属性
package com.sc.entity;
public class User implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private String username;
private String pwd;
private String email;
public User(String username, String pwd, String email) {
super();
this.username = username;
this.pwd = pwd;
this.email = email;
}
public String getUsername() {return username;}
public String getPwd() {return pwd;}
public String getEmail() {return email;}
public void setUsername(String username) {this.username = username;}
public void setPwd(String pwd) {this.pwd = pwd;}
public void setEmail(String email) {this.email = email;}
@Override
public String toString() {
return "User [username=" + username + ", pwd=" + pwd + ", email=" + email + "]";
}
}
5.邮件发送服务及其实现(生产者端)
package com.sc.service;
import com.sc.entity.User;
public interface MailSendService {
void sendMail(User user);
}
实现类
package com.sc.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
import com.sc.entity.User;
import com.sc.service.MailSendService;
@Service
public class MailSendServiceImpl implements MailSendService {
@Autowired
private MailSender mailSender;
/**
* 发送邮件
*/
@Override
public void sendMail(User use) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("[email protected]");
message.setTo(use.getEmail());
message.setSubject(use.getUsername());
//这里暂时已用户名作为发送的内容
message.setText(use.getUsername());
mailSender.send(message);
}
}
6.用户登录业务中邮件信息发布
这里可忽略登录业务,这里其实就是代指一个业务入口,简单处理。主要关注产生邮件信息
package com.sc.service;
public interface UserService {
//登陆
void login(String username, String pwd, String email);
}
实现类
package com.sc.service.impl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sc.entity.User;
import com.sc.service.UserService;
@Service
public class UserServiceImpl implements UserService{
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void login(String username, String pwd, String email) {
//TODO 执行登陆的业务逻辑,这里主要是介绍消息队列发送邮件,这里就忽略
User user = new User(username, pwd, email);
//这里将用户对象作为队列消息发送
rabbitTemplate.convertAndSend("info", user);
}
}
7消费者端消费信息,即实现邮件的异步发送
package com.sc.consumer;
import org.apache.commons.logging.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.utils.SerializationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import com.rabbitmq.client.Channel;
import com.sc.entity.User;
import com.sc.service.MailSendService;
/**
* 消费的消费者 实现 MessageListener或ChannelAwareMessageListener(需手动确认的实现此接口)
*/
public class Consumer implements ChannelAwareMessageListener{
private static final Logger log = LoggerFactory.getLogger(Consumer.class);
@Autowired
private MailSendService mailSendService;
@Override
public void onMessage(Message message, Channel channel) throws Exception {
try {
if(StringUtils.isEmpty(new String(message.getBody(),"UTF-8"))) {
return;
}
User user = (User) SerializationUtils.deserialize(message.getBody());
log.info("消费者消费{}",user);
//发送邮件
mailSendService.sendMail(user);
//手动确认
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
8.编写Controller层的接口测试
package com.sc.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.sc.service.UserService;
@Controller
@RequestMapping("/user")
public class UserLoginController {
@Autowired
private UserService userService;
@RequestMapping(value="/login", method=RequestMethod.POST)
@ResponseBody
public boolean login(String username,String pwd,String email) {
//这里简单模拟正常注册,没有数据库交互
//执行登陆逻辑
userService.login(username,pwd,email);
return true;
}
}