利用activeMQ消息中间件整合spring mail发邮件

来源:互联网 发布:淘宝店铺叫什么名字好 编辑:程序博客网 时间:2024/06/01 11:47

同理消费者监听类一样可以做发短信,微信等等。。。
看这篇文章首先确保你已经阅读过我上一篇spring boot整合activeMQ,实现ptp和topic两者消息模式
配置文件新增了spring mail的相关配置:

spring.mail.username=xxxxxxxxx@163.comspring.mail.password=xxxxxxxxxspring.mail.host=smtp.163.comspring.mail.port=25spring.mail.properties.mail.smtp.auth=truespring.mail.properties.mail.smtp.starttls.enable=truespring.mail.properties.mail.smtp.starttls.required=true

ps:这里提一下,由于使用163邮箱发邮件需要去163邮箱里设置勾选POP3/SMTP服务,选中后会让你设置独立密码,区别于邮箱登陆密码,spring.mail.password这个配置hi的密码就是独立密码而不是邮箱登录密码,否则会报权限报错
pom文件比之前多加入两个:

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-mail</artifactId></dependency><dependency>    <groupId>com.alibaba</groupId>    <artifactId>fastjson</artifactId>    <version>1.2.29</version></dependency>

1.首先为了方便测试我们要先把Customer2里面的@JmsListener监听注解注视掉,这样保证我们只有一个消费者监听消息队列。
2.我们需要在项目里新加一个utils包放工具类,EmailUtil就在其中

@Componentpublic class EmailUtil {    @Autowired    private JavaMailSender mailSenderAutowired;    private static JavaMailSender mailSender;    @Value("${spring.mail.username}")    private String usernameValue;    private static String username;    @PostConstruct//bean初始化之前调用    public void init() {        this.mailSender = mailSenderAutowired;        this.username = usernameValue;    }    public static void sendEmail(String to, String subject, String text){        SimpleMailMessage message = new SimpleMailMessage();        message = null;        message.setFrom(username);        message.setTo(to);        message.setSubject(subject);        message.setText(text);        mailSender.send(message);    }    public static void sendEmailWithFile(String to, String subject, String text, InputStreamSource file) throws MessagingException {        MimeMessage mimeMessage = mailSender.createMimeMessage();        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);        helper.setFrom(username);        helper.setTo(to);        helper.setSubject(subject);        helper.setText(text);        helper.addAttachment("附件-1.png", file);        mailSender.send(mimeMessage);    }}

这里说明一点:
由于是工具类,所以类里面的方法是静态方法,静态方法内部是不能使用类里非静态变量的,所以mailSender和username都定义为静态的,但问题来了,由于定义为静态,代码运行时是无法将配置信息注入到变量里(由于编译起就开辟内存空间,并没有赋值,所以运行期这两个变量是null),于是我们定义两个普通变量来注入配置信息,然后在通过这个注解@PostConstruct在bean初始化之前把普通变量的值交给静态变量,这样运行时就不会报NPE了。
先看一下发邮件方法的入口controller:

@RestController@RequestMapping("/sendEmail")public class SendEmailController {    @Autowired    private SendEmailService sendEmailService;    @GetMapping("/sendEmail/{text}")    public void advice(@PathVariable("text") String text){        sendEmailService.advice(text);    }}

很简单就一个普通的controller层,再看看service层:
先贴出来平时常规业务逻辑嵌入发邮件功能,这种常规写法存在很多问题,比如:
如果发送邮件出现异常那么发邮件下面的业务逻辑无法正常执行,即使try/catch了,由于这部分代码是同步的,下面的业务代码也需要等待邮件发完才能执行,耦合度很高,高并发情况下还有可能出现阻塞

public interface SendEmailService {    void sendEmail(String text);    void sendEmailWithFile(String text) throws MessagingException;    void advice(String text);}@Servicepublic class SendEmailServiceImpl implements SendEmailService{    @Autowired    private ProductService productService;    @Override    public void advice(String text) {//        JSONObject jsonObject = new JSONObject();//        jsonObject.put("key","email");//        jsonObject.put("text",text);//        this.productService.sendMessage(jsonObject.toJSONString());        this.sendEmail(text);        System.out.println("邮件发送成,邮件内容是:" + text);        //其他业务逻辑...    }    @Override    public void sendEmail(String text) {        EmailUtil.sendEmail("xxxxxx@qq.com","测试邮件",text);    }    @Override    public void sendEmailWithFile(String text) throws MessagingException {        InputStreamSource file = new FileSystemResource(new File("F:\\pic\\huaji.jpg"));        EmailUtil.sendEmailWithFile("xxxxxx@qq.com","测试邮件",text,file);    }}

再来看看利用消息队列中间件去发邮件:
好处是把业务逻辑和发邮件功能解耦,即使发邮件失败也不会影响下面的业务逻辑正常执行,由于使用了MQ发邮件和业务逻辑是异步的,下面的代码不必等待邮件发送完毕才执行。

@Servicepublic class SendEmailServiceImpl implements SendEmailService{    @Autowired    private ProductService productService;    @Override    public void advice(String text) {        JSONObject jsonObject = new JSONObject();        jsonObject.put("key","email");        jsonObject.put("text",text);        this.productService.sendMessage(jsonObject.toJSONString());//        this.sendEmail(text);        System.out.println("邮件发送成,邮件内容是:" + text);        //其他业务逻辑...    }    @Override    public void sendEmail(String text) {        EmailUtil.sendEmail("xxxxxx@qq.com","测试邮件",text);    }    @Override    public void sendEmailWithFile(String text) throws MessagingException {        InputStreamSource file = new FileSystemResource(new File("F:\\pic\\huaji.jpg"));        EmailUtil.sendEmailWithFile("xxxxxx@qq.com","测试邮件",text,file);    }}

由于使用mq做的不仅仅是发邮件还有其他功能所以定义一个json对方用key做标识,看一下Customer消费者部分代码:

@Servicepublic class Consumer {    @Autowired    private SendEmailService sendEmailService;    private static int index = 0;    // 使用JmsListener配置消费者监听的队列,其中text是接收到的消息    @JmsListener(destination = "zh-topic")    public void receiveQueue(String text) throws MessagingException {        System.out.println("重试次数:" + index);        System.out.println("Consumer收到:"+text);        this.index = ++index;        JSONObject jsonObject = JSONObject.parseObject(text);        if ("email".equals(jsonObject.getString("key"))){//发邮件            this.sendEmail(jsonObject.getString("text"));        }else{            //其他业务...        }    }    public void sendEmail(String text) throws MessagingException {        this.sendEmailService.sendEmailWithFile(text);    }}

这个类里面定义了一个静态的index变量是为了 测试mq在消费消息失败时候的重试机制,我们可以在EmailUtil的发邮件方法里自定义一个异常让发邮件失败,我们观察控制台会发现,activeMQ在消息未消费情况下会默认重试6次,每次重试间隔为1s钟
还要说的是,spring 提供的mail好方便,配置配置通过SimpleMailMessage或MimeMessage就可以发邮件了,添加附件也很方便,比以往使用java mail自己处理方便的多了

原创粉丝点击