zoukankan      html  css  js  c++  java
  • Spring学习笔记3——消息队列(rabbitmq), 发送邮件

        本节的内容是用户注册时,将邮箱地址先存入rabbitmq队列,之后返回给用户注册成功;之后消息队列的接收者从队列中获取消息,发送邮件给用户。

    一、RabbitMQ介绍

        如果之前对rabbitmq不了解,推荐先看一下RabbitMQ Quick(快速手册)

    1、rabbitmq在mac上的安装

    2、rabbitmq简单介绍。

    生产者: 负责发送消息到Exchange。

    Exchange: 按照一定的策略,负责将消息存入到指定的队列。

    队列queue:  负责保存消息。

    消费者: 负责从队列中提取消息。

    binding: 负责Exchange和队列的关联映射,Exchange和queue是多对多的关系。

    二、RabbitMQ在Spring中的实现

    1、引入依赖包。

    <dependency>
                <groupId>org.springframework.amqp</groupId>
                <artifactId>spring-amqp</artifactId>
                <version>1.6.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.amqp</groupId>
                <artifactId>spring-rabbit</artifactId>
                <version>1.6.0.RELEASE</version>
            </dependency>

    2、rabbitmq配置文件。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/rabbit"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://www.springframework.org/schema/rabbit
                    http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
                  http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--1、配置连接工厂, 如果不配置host, port, username, passowrd, 则按默认值localhost:5672, guest/guest-->
        <!--<connection-factory id="connectionFactory" />-->
        <connection-factory id="connectionFactory"
                            host="localhost"
                            port="5672"
                            username="everSeeker"
                            password="333" />
    
        <!--2、配置队列queue, Exchange, 以及将他们结合在一起的binding-->
        <!--在queue以及exchange中, 有一个重要的属性durable, 默认为true, 可以防止宕机后数据丢失。-->
        <!--在listener-container中, 有acknowledge属性, 默认为auto, 即消费者成功处理消息后必须有个应答, 如果消费者程序发生异常或者宕机, 消息会被重新放回队列-->
        <admin connection-factory="connectionFactory" />
        <queue id="userAlertEmailQueue" name="user.alerts.email" durable="true" />
        <queue id="userAlertCellphoneQueue" name="user.alerts.cellphone" />     <!--durable默认为true-->
    
        <!--标准的AMQP Exchange有4种: Direct, Topic, Headers, Fanout, 根据实际需要选择。-->
        <!--Direct: 如果消息的routing key与bingding的routing key直接匹配的话, 消息将会路由到该队列上。-->
        <!--Topic: 如果消息的routing key与bingding的routing key符合通配符匹配的话, 消息将会路由到该队列上。-->
        <!--Headers: 如果消息参数表中的头信息和值都与binding参数表中相匹配, 消息将会路由到该队列上。-->
        <!--Fanout: 不管消息的routing key和参数表的头信息/值是什么, 消息将会路由到该队列上。-->
        <direct-exchange name="user.alert.email.exchange" durable="true">
            <bindings>
                <binding queue="user.alerts.email" />     <!--默认的routing key与队列的名称相同-->
            </bindings>
        </direct-exchange>
        <direct-exchange name="user.alert.cellphone.exchange">
            <bindings>
                <binding queue="user.alerts.cellphone" />
            </bindings>
        </direct-exchange>
    
        <!--3、配置RabbitTemplate发送消息-->
        <template id="rabbitTemplate"
                  connection-factory="connectionFactory" />
    
        <!--4、配置监听器容器和监听器来接收消息-->
        <beans:bean id="userListener" class="com.everSeeker.alerts.UserAlertHandler" />
        <listener-container connection-factory="connectionFactory" acknowledge="auto">
            <listener ref="userListener"
                      method="handleUserAlertToEmail"
                      queues="userAlertEmailQueue" />
            <listener ref="userListener"
                      method="handleUserAlertToCellphone"
                      queues="userAlertCellphoneQueue" />
        </listener-container>
    
    </beans:beans>

    如果配置connection-factory时,采用默认的guest/guest账号密码时,有可能会出现org.springframework.amqp.AmqpAuthenticationException: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.的错误提示,解决办法是新建一个管理员权限的用户,并允许访问虚拟主机。步骤如下:

    1、打开http://localhost:15672/
    2、Admin ——> Users, 新建用户,administrator权限。
    3、Virtual Hosts,设置新建用户允许访问。

    3、生产者发送消息到exchange。

    @Service("userAlertService")
    public class UserAlertServiceImpl implements UserAlertService {
        private RabbitTemplate rabbit;
    
        @Autowired
        public UserAlertServiceImpl(RabbitTemplate rabbit) {
            this.rabbit = rabbit;
        }
    
        public void sendUserAlertToEmail(User user) {
            //convertAndSend(String exchange, String routingKey, Object object), 将对象object封装成Message对象后, 发送给exchange
            rabbit.convertAndSend("user.alert.email.exchange", "user.alerts.email", user);
        }
    }

    4、配置消费者来接收消息。

    public class UserAlertHandler {
        
        public void handleUserAlertToEmail(User user) {
            System.out.println(user);
    }

    三、通过javax.mail来发送邮件

    1、引入依赖包。

    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId>mail</artifactId>
        <version>1.4.7</version>
    </dependency>

    2、配置邮件服务器信息。

    @Bean
    public MailSender mailSender(Environment env) {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        //如果为普通邮箱, 非ssl认证等, 比如163邮箱
        mailSender.setHost(env.getProperty("mailserver.host"));
        mailSender.setPort(Integer.parseInt(env.getProperty("mailserver.port")));
        mailSender.setUsername(env.getProperty("mailserver.username"));
        mailSender.setPassword(env.getProperty("mailserver.password"));
        mailSender.setDefaultEncoding("utf-8");
    
        //如果邮件服务器采用了ssl认证, 增加以下配置, 比如gmail邮箱, qq邮箱
        Properties props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port", "465");
        mailSender.setJavaMailProperties(props);
    
        return mailSender;
    }

    3、发送邮件。

    @Component("userMailService")
    public class UserMailServiceImpl implements UserMailService {
        private MailSender mailSender;
    
        @Autowired
        public UserMailServiceImpl(MailSender mailSender) {
            this.mailSender = mailSender;
        }
    
        public void sendSimpleUserMail(String to, User user) {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("xxxxxxxx@qq.com");
            message.setTo(to);
            message.setSubject(user.getUsername() + "信息确认");
            message.setText(user.toString());
            mailSender.send(message);
        }
    }

    4、消费者调用发送邮件方法即可。

    1、参考文献:Spring实战(第4版)。

    2、完整代码在github,地址:https://github.com/everseeker0307/spring-demo

  • 相关阅读:
    Redis源码分析(二十一)--- anet网络通信的封装
    leetcode 总结part1
    leetcode String to Integer (atoi)
    leetcode 165. Compare Version Numbers
    leetcode 189. Rotate Array
    leetcode 168. Excel Sheet Column Title
    leetcode 155. Min Stack
    leetcode 228. Summary Ranges
    leetcode 204. Count Primes
    leetcode 6. ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/everSeeker/p/5690984.html
Copyright © 2011-2022 走看看