springboot integrates rabbitmq to complete public account sending messages
1. Download rabbitmq
You can download it using brew
brew install rabbitmq
There may be problems, please ignore if not
fatal: not in a git directory Error: Command failed with exit 128: git
Solution:
Execute separately, and then re-execute: brew install rabbitmq
git config --global --add safe.directory /opt/homebrew/Library/Taps/homebrew/homebrew-core
git config --global --add safe.directory /opt/homebrew/Library/Taps/homebrew/homebrew-cask
2. Check whether rabbitmq is successful
Execution rabbitmq-server
If the following figure appears, it indicates successful startup.
3. Write code
3.1 Import pom dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>whispers</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!-- JSONObject的依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.71</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
</dependencies>
</project>
3.2 application.yml file configuration
spring:
datasource:
url: jdbc:mysql://localhost:3306/whisper?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
rabbitmq:
host: 127.0.0.1
username: test
port: 5672
virtual-host: /whhx
password: 123456
server:
port: 9999
mybatis:
mapper-locations:
- classpath:/mapper/*.xml
wx:
app-id: wxaa64d0c144ca81b5
app-secret: fcb7b645ecb419b5e55868706dd842d5
token-url: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s
message-url: https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s
management:
health:
rabbit:
enabled: false
3.3 Create a new MqSendMsgConfig configuration class
package com.xxx.config;
import com.xxx.constant.QueueConstant;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MqSendMsgConfig {
// 微信消息队列
@Bean
public Queue sendWxQueue(){
return new Queue(QueueConstant.WX_SEND_QUEUE);
}
@Bean
public DirectExchange sendWxEx(){
return new DirectExchange(QueueConstant.WX_SEND_EX);
}
@Bean
public Binding sendWxBind(){
return BindingBuilder.bind(sendWxQueue()).to(sendWxEx()).with(QueueConstant.WX_SEND_KEY);
}
}
3.4 Create a new WxAutoConfiguration configuration class
package com.xxx.config;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
@Configuration
@EnableConfigurationProperties(value = WxProperties.class)
@Slf4j
public class WxAutoConfiguration {
@Autowired
private RestTemplate restTemplate;
private String wxAccessToken;
/**
* spring实现注解规范:方法在所有的Bean对象创建之后, 项目启动完成之前执行
* 限制:不能有返回值,也不能有参数
*/
@PostConstruct
public void tokenInit(){
getAccessToken();
}
@Scheduled(initialDelay = 0, fixedRate = 7100 * 1000)
public void getAccessToken(){
String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", "wxaa64d0c144ca81b5", "d81bb0ef2dc54f1754e7d2eef91df3f1");
String accessTokenJsonStr = restTemplate.getForObject(url, String.class);
JSONObject accessTokenJson = JSONObject.parseObject(accessTokenJsonStr);
String accessToken = accessTokenJson.getString("access_token");
if (!StringUtils.isEmpty(accessToken)){
wxAccessToken = accessToken;
}else {
log.error("获取access_token失败");
}
}
public String getWxAccessToken() {
return wxAccessToken;
}
public void setWxAccessToken(String wxAccessToken) {
this.wxAccessToken = wxAccessToken;
}
}
3.5 Create a new WxProperties configuration class
package com.xxx.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "wx")
public class WxProperties {
private String appID;
private String appSecret;
private String accessTokenUrl;
private String sendMsgUrl;
}
3.6 Create a new QueueConstant interface
package com.xxx.constant;
public interface QueueConstant {
/**
* 发送微信消息的队列
*/
String WX_SEND_QUEUE = "wx.send.queue";
/**
* 发送微信消息的交换机
*/
String WX_SEND_EX = "wx.send.ex";
/**
* 发送微信消息的路由key
*/
String WX_SEND_KEY = "wx.send.key";
}
3.7 Create a new controller
@PostMapping("p/sms/sendWxMsg")
public ResponseEntity<Void> sendWxMsg(@RequestBody OpenIdName openIdName){
userService.sendWxMsg(openIdName.getOpenId(), openIdName.getUserName());
return ResponseEntity.ok().build();
}
3.8 Create a new OpenIdName class
package com.xxx.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OpenIdName {
private String openId;
private String userName;
}
3.9 Create a new service implementation class
package com.xxx.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxx.constant.QueueConstant;
import com.xxx.entity.User;
import com.xxx.mapper.UserMapper;
import com.xxx.model.WxMsgModel;
import com.xxx.service.UserService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送微信消息
*
* @param openId
* @param name
*/
@Override
public void sendWxMsg(String openId, String name) {
WxMsgModel wxMsgModel = new WxMsgModel();
wxMsgModel.setToUser(openId);
wxMsgModel.setTemplateId("ByimXumDgKGmfDlqGPA2kgYCQK36hqGZy8e5KkCU2Dg");
wxMsgModel.setUrl("https://www.baidu.com");
wxMsgModel.setTopColor("#FF0000");
HashMap<String, Map<String, String>> data = new HashMap<>();
data.put("userName", WxMsgModel.buildMap(name, "#173177"));
data.put("time", WxMsgModel.buildMap(new Date().toString(), "173177"));
data.put("product", WxMsgModel.buildMap("女朋友", "173177"));
data.put("money", WxMsgModel.buildMap("0.1", "173177"));
wxMsgModel.setData(data);
//用mq发送消息
rabbitTemplate.convertAndSend(QueueConstant.WX_SEND_EX, QueueConstant.WX_SEND_KEY, JSON.toJSONString(wxMsgModel));
}
}
3.10 Create a new service interface
/**
* 发送微信消息
* @param openId
* @param name
*/
void sendWxMsg(String openId, String name);
3.11 Create a new WxMsgModel class
package com.xxx.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.HashMap;
import java.util.Map;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WxMsgModel {
// 注意使用的@JsonProperty
@JsonProperty(value = "touser")
private String toUser;
@JsonProperty(value = "template_id")
private String templateId;
@JsonProperty(value = "url")
private String url;
@JsonProperty(value = "topcolor")
private String topColor;
@JsonProperty(value = "data")
private Map<String, Map<String, String>> data;
public static Map<String, String> buildMap(String value, String color){
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("value", value);
hashMap.put("color", color);
return hashMap;
}
}
3.12 Create a new listener
package com.xxx.listener;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import com.xxx.config.WxAutoConfiguration;
import com.xxx.config.WxProperties;
import com.xxx.constant.QueueConstant;
import com.xxx.model.WxMsgModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
@Slf4j
public class WxListener {
@Autowired
private WxProperties wxProperties;
@Autowired
private WxAutoConfiguration wxAutoConfiguration;
@Autowired
private RestTemplate restTemplate;
/**
* 处理微信公众号消息
*/
@RabbitListener(queues = QueueConstant.WX_SEND_QUEUE, concurrency = "3-5")
public void wxHandler(Message message, Channel channel){
String msgStr = new String(message.getBody());
WxMsgModel wxMsgModel = JSONObject.parseObject(msgStr, WxMsgModel.class);
try {
String response = sendWxMsg(wxMsgModel);
log.info("发送微信公众号消息成功");
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e){
log.error("发送微信公众号消息失败");
}
}
/**
* 发送微信消息
*/
private String sendWxMsg(WxMsgModel wxMsgModel){
String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
String wxAccessToken = wxAutoConfiguration.getWxAccessToken();
String url = String.format(accessTokenUrl, wxAccessToken);
return restTemplate.postForObject(url, wxMsgModel, String.class);
}
}
3.13 Startup class
package com.xxx;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@MapperScan(basePackages = "com.xxx.mapper")
@EnableScheduling
public class WhisperServiceApplication {
public static void main(String[] args) {
SpringApplication.run(WhisperServiceApplication.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
4. Overall project picture (user-related ones can be ignored)
This project is continued to be developed on a demo, and you can ignore the user-related aspects.
5. rabbitmq’s page
Page input URL: http://localhost:15672
Login account password: guest
5.1 Problems that may occur when starting the project
1、An unexpected connection driver error occured
2、Restarting Consumer@43f3c557: tags=[[]], channel=null, acknowledgeMode=AUTO
Wait, no matter what problem occurs, the problem related to mq is usually that mq cannot be connected. At this time, you need to create a new test account on the page. You can
refer to the link: https://blog.csdn.net/theRengar/article/details/ 118933418. Very simple
6. Project startup testing
You can use debug to test. Once the message is sent, the listener will immediately get the message and then consume it. Please add image description