RabbitMQ implements asynchronous communication of SMS service in SpingBoot

Basic usage of RabbitMQ in SpingBoot:

RabbitMQ is an open source messaging middleware with the following uses and advantages:

  1. Asynchronous communication: RabbitMQ can be used as a medium for asynchronous communication between applications. Producers can send messages to RabbitMQ, and consumers can get messages from them and process them. This asynchronous communication can decouple various parts of the system and improve the scalability and performance of the system.

  2. Application decoupling: By using RabbitMQ, different applications can be decoupled by sending and receiving messages, and reduce dependencies between applications. This increases the flexibility of the system and makes it easier to maintain and expand.

  3. Reliable messaging: RabbitMQ ensures the reliability of messaging. It provides persistence and message confirmation mechanisms to ensure that messages are not lost or duplicated even in the event of message sending or consumer failure.

  4. Flexible message routing and switching: RabbitMQ supports multiple message routing modes and switch types, such as direct, sector, topic and head switches. This allows messages to be routed to different queues based on their content and tags to meet various complex application scenarios.

  5. Delayed message processing: RabbitMQ supports the sending and processing of delayed messages, and can be used to handle scheduled tasks, delayed notifications, and scheduling needs.

  6. Coordination in distributed systems: RabbitMQ plays a key role in distributed systems and can be used to implement task distribution, event publishing and subscription, distributed locks, etc. in distributed systems. It provides a simple yet powerful way to handle communication and coordination mechanisms between distributed systems.

RabbitMQ is a powerful, reliable and easy-to-use messaging middleware. It has wide applications in asynchronous communication, application decoupling, reliable message delivery, flexible message routing and switching, deferred message processing, and coordination in distributed systems.

When using SpringbBoot, you first need to create a new queue and switch in the rabbitmq management interface.


RabbitMQ supports multiple types of switches for defining routing rules for messages. Here are a few common switch types:

  1. Direct Exchange: accurately routes messages to matching queues based on the routing key of the message. For example, by setting the routing key of a message to a specific keyword, the message can be sent to the corresponding queue for processing by the consumer.
  2. Fanout Exchange: Broadcasts messages to all queues bound to the switch. Regardless of the message’s routing key, the sector switch sends the message to all bound queues. Suitable for scenarios where multiple consumers need to process the same message.
  3. Topic Exchange: Matching and routing based on the pattern of routing keys. You can use the wildcard symbol “*” to match one word, and “#” to match zero or more words. Topic switches can meet more complex routing needs and can route messages to multiple queues.
  4. Headers Exchange: Matching and routing based on the header attributes of the message. The message publisher can add custom attributes to the header of the message when sending the message, and the switch will match and route based on these attributes.

Different types of switches are suitable for different application scenarios. Developers can choose the appropriate switch type for message routing and distribution according to specific needs.

Introduce dependencies into the project:

<!-- RabbitMQ -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

yml file configuration:

The username and password of rabbitmq are default

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/market?useSSl=true & useUnicode=true$characterEncoding=utf-8 & serverTimezone=GMT+8
    username: root
    password: 010409
  rabbitmq:
      host: 127.0.0.1
      port: 5672
      username: guest
      password: guest

Switch and queue binding configuration:

@Configuration
public class RabbitMQConfig {<!-- -->

    private static final String MARKET = "market";
    private static final String ORDER = "order";
    private static final String EXCHANGE = "market.exChanges";

    @Bean
    public Queue queue01(){<!-- -->
        return new Queue(MARKET);
    }

    @Bean
    public Queue queue02(){<!-- -->
        return new Queue(ORDER);
    }

    @Bean
    public DirectExchange fanoutExchange(){<!-- -->
        return new DirectExchange(EXCHANGE);
    }

    // Bind the switch and queue
    @Bean
    public Binding binding01(){<!-- -->
        return BindingBuilder.bind(queue01()).to(fanoutExchange()).with("market");
    }

    @Bean
    public Binding binding02(){<!-- -->
        return BindingBuilder.bind(queue02()).to(fanoutExchange()).with("order");
    }

}

Application scenario: SMS verification code service. Here I use Alibaba Cloud SMS service SMS to store the SMS verification code and the mobile phone number entered at the front end into the queue, and store the verification code in redis to facilitate verification code verification during subsequent registration. Finally, the listening queue sends the text message after getting the information.

SMS dependency and configuration, you need to modify the configuration to your own

<!-- Alibaba Cloud SMS dependency -->
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.5.16</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
    <version>2.1.0</version>
</dependency>
@Service
public class SmsService {<!-- -->
    public boolean send(Map<String, Object> param, String phone) {<!-- -->

        if(StringUtils.isEmpty(phone)) return false;
        //default regional node, the default is fine, followed by Alibaba Cloud's id and secret key (remember to go to Alibaba Cloud to copy your own id and secret key here)
        DefaultProfile profile = DefaultProfile.getProfile("default", "LTAI5tNtEzgs7etoRVhWQuXz", "X8odaVou1eSwT0boKEgvYxPSUtWafL");
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();

        request.setProtocol(ProtocolType.HTTPS);
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");

        request.putQueryParameter("PhoneNumbers", phone); //Mobile phone number
        request.putQueryParameter("SignName", "Alibaba Cloud SMS Test"); //Apply for Alibaba Cloud signature name (temporarily using Alibaba Cloud for testing, you cannot register a signature yet)
        request.putQueryParameter("TemplateCode", "SMS_154950909"); //Apply for Alibaba Cloud template code (the one used is also tested by Alibaba Cloud)
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));

        try {<!-- -->
            CommonResponse response = client.getCommonResponse(request);
// System.out.println(response.getData());
            return response.getHttpResponse().isSuccess();
        } catch (Exception e) {<!-- -->
            e.printStackTrace();
        }
        return false;
    }
}

Interface for sending SMS:

@RequestMapping("/sendCode")
public Result sendCode(String phone){<!-- -->
    return UserService.sendCode(phone);
}

accomplish:

 @Override
    public Result sendCode(String phone) {<!-- -->
        // 1. Verify mobile phone number
        String regex = "^1[3456789]\d{9}$";

        if (!phone.matches(regex)) {<!-- -->
            // 2. If it does not match, return an error message
            return new Result(100,"Mobile phone number format is wrong!");
        }

// 3. Generate verification code
        String code = "";
        for (int i = 0; i < 6; i + + ) {<!-- -->
            int var = new Random().nextInt(10);
            code = code + var;
        }

        Map<String,Object> param = new HashMap<>();
        param.put("code", code);

        // 4. Save the verification code to redis
        redisCache.setCacheObject(phone,code);

        Map<String,String> map=new HashMap();
        map.put("phone", phone);
        map.put("code", code);
        // 5. Save the verification code and mobile phone number to the queue
        rabbitTemplate.convertAndSend("market.exChanges","market",map);

        return new Result(200, "Sent successfully");
    }

Listen to the queue and send text messages.

@RabbitListener(queues = "market")
@RabbitHandler
public void executeSPC(Map<String, String> map, Channel channel, @Headers Map<String, Object> headers) throws IOException {<!-- -->
    try {<!-- -->
        Map<String,Object> param = new HashMap<>();
        param.put("code", map.get("code"));
        smsService.send(param, map.get("phone"));

        // Manually send ACK to confirm that the message has been received
        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        channel.basicAck(deliveryTag, false);
    } catch (Exception e) {<!-- -->
        // Handle abnormal situations and choose whether to re-enqueue or reject messages according to business needs.
        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        channel.basicNack(deliveryTag, false, true);
    }
}