第一次提交

This commit is contained in:
wyw
2024-08-08 00:31:26 +08:00
commit c202e2b63d
1819 changed files with 221890 additions and 0 deletions

View File

@ -0,0 +1,11 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>fastbee-plugs</artifactId>
<groupId>com.fastbee</groupId>
<version>3.8.5</version>
</parent>
<artifactId>fastbee-mqtt-client</artifactId>
</project>

View File

@ -0,0 +1,12 @@
package com.fastbee.mqttclient;
import com.fastbee.common.core.mq.DeviceReportBo;
/**
* @author bill
*/
public interface IEmqxMessageProducer {
public void sendEmqxMessage(String topicName, DeviceReportBo deviceReportBo);
}

View File

@ -0,0 +1,58 @@
package com.fastbee.mqttclient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/** mqtt配置信息*/
@Data
@Component
@ConfigurationProperties(prefix = "spring.mqtt")
public class MqttClientConfig {
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 连接地址
*/
private String hostUrl;
/**
* 客户Id
*/
private String clientId;
/**
* 默认连接话题
*/
private String defaultTopic;
/**
* 超时时间
*/
private int timeout;
/**
* 保持连接数
*/
private int keepalive;
/**是否清除session*/
private boolean clearSession;
/**是否共享订阅*/
private boolean isShared;
/**分组共享订阅*/
private boolean isSharedGroup;
/**
* true: 使用netty搭建的mqttBroker false: 使用emq
*/
@Value("${server.broker.enabled}")
private Boolean enabled;
}

View File

@ -0,0 +1,120 @@
package com.fastbee.mqttclient;
import com.fastbee.common.utils.gateway.mq.TopicsPost;
import com.fastbee.common.utils.gateway.mq.TopicsUtils;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
/**
* mqtt客户端回调
*/
@Slf4j
@Component
@Data
@NoArgsConstructor
public class PubMqttCallBack implements MqttCallbackExtended {
/**
* mqtt客户端
*/
private MqttAsyncClient client;
/**
* 创建客户端参数
*/
private MqttConnectOptions options;
@Resource
private TopicsUtils topicsUtils;
private Boolean enabled;
private IMqttMessageListener listener;
public PubMqttCallBack(MqttAsyncClient client, MqttConnectOptions options, Boolean enabled, IMqttMessageListener listener) {
this.client = client;
this.options = options;
this.enabled = enabled;
this.listener = listener;
}
/**
* mqtt客户端连接
*
* @param cause 错误
*/
@Override
public void connectionLost(Throwable cause) {
// 连接丢失后,一般在这里面进行重连
log.debug("=>mqtt 连接丢失", cause);
int count = 1;
// int sleepTime = 0;
boolean willConnect = true;
while (willConnect) {
try {
Thread.sleep(1000);
log.debug("=>连接[{}]断开,尝试重连第{}次", this.client.getServerURI(), count++);
this.client.connect(this.options);
log.debug("=>重连成功");
willConnect = false;
} catch (Exception e) {
log.error("=>重连异常", e);
}
}
}
/**
* 客户端订阅主题回调消息
*
* @param topic 主题
* @param message 消息
*/
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
// subscribe后得到的消息会执行到这里面
try {
listener.messageArrived(topic, message);
} catch (Exception e) {
log.warn("mqtt 订阅消息异常", e);
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
/**
* 监听mqtt连接消息
*/
@Override
public void connectComplete(boolean reconnect, String serverURI) {
log.info("MQTT内部客户端已经连接!");
System.out.print("" +
" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \n" +
" * _⚲_⚲_ ______ _ ____ * \n" +
" * | / \\ | | ____| | | | _ \\ * \n" +
" * | | | ● | | | | |__ __ _ ___| |_ | |_) | ___ ___ * \n" +
" * | \\ / | | __/ _` / __| __| | _ < / _ \\/ _ \\ * \n" +
" * \\ / | | | (_| \\__ \\ |_ | |_) | __/ __/ * \n" +
" * V |_| \\__,_|___/\\__| |____/ \\___|\\___| * \n" +
" * * \n" +
" * * * * * * * * * * * * FastBee物联网平台[✔启动成功] * * * * * * * * * * * * \n");
//连接后订阅, enable为false表示使用emq
if (!enabled) {
try {
TopicsPost allPost = topicsUtils.getAllPost();
client.subscribe(allPost.getTopics(), allPost.getQos());
log.info("mqtt监控主题,{}", Arrays.asList(allPost.getTopics()));
} catch (MqttException e) {
log.error("=>订阅主题失败 error={}", e.getMessage());
}
}
}
}

View File

@ -0,0 +1,202 @@
package com.fastbee.mqttclient;
import com.fastbee.common.constant.FastBeeConstant;
import com.fastbee.common.core.redis.RedisCache;
import com.fastbee.common.exception.ServiceException;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 发布服务mqtt客户端
*/
@Component
@Slf4j
public class PubMqttClient {
@Resource
private MqttClientConfig mqttConfig;
@Resource(name = "pubMqttCallBack")
private PubMqttCallBack mqttCallBack;
/**
* 连接配置
*/
private MqttConnectOptions options;
/**
* MQTT异步客户端
*/
private MqttAsyncClient client;
/**
* 是否连接标记
*/
private boolean isConnected = false;
@Resource
private RedisCache redisCache;
@Setter
private IMqttMessageListener listener;
/**
* 启动MQTT客户端
*/
public synchronized void initialize() {
try {
setOptions();
createClient();
while (!client.isConnected()) {
IMqttToken token = client.connect(options);
if(token != null && token.isComplete()) {
log.debug("=>内部MQTT客户端启动成功");
this.isConnected = true;
break;
}
log.debug("=>内部mqtt客户端连接中...");
Thread.sleep(20000);
}
} catch (MqttException ex) {
log.error("=>MQTT客户端初始化异常", ex);
} catch (Exception e) {
log.error("=>连接MQTT服务器异常", e);
this.isConnected = false;
}
}
public boolean isConnected() {
return this.isConnected;
}
private void createClient() {
try {
if (client == null) {
/*host为主机名clientId是连接MQTT的客户端ID*/
client = new MqttAsyncClient(mqttConfig.getHostUrl(), getClientId(), new MemoryPersistence());
//设置回调函数
client.setCallback(mqttCallBack);
mqttCallBack.setClient(client);
mqttCallBack.setOptions(this.options);
mqttCallBack.setEnabled(mqttConfig.getEnabled());
mqttCallBack.setListener(this.listener);
}
} catch (Exception e) {
log.error("=>mqtt客户端创建错误");
}
}
/**
* 设置连接属性
*/
private void setOptions() {
if (options != null) {
options = null;
}
options = new MqttConnectOptions();
options.setConnectionTimeout(mqttConfig.getTimeout());
options.setKeepAliveInterval(mqttConfig.getKeepalive());
options.setUserName(mqttConfig.getUsername());
options.setPassword(mqttConfig.getPassword().toCharArray());
//设置自动重新连接
options.setAutomaticReconnect(true);
/*设置为false断开连接不清除session重连后还是原来的session
保留订阅的主题,能接收离线期间的消息*/
options.setCleanSession(true);
}
/**
* 断开与mqtt的连接
*/
public synchronized void disconnect() {
//判断客户端是否null 是否连接
if (client != null && client.isConnected()) {
try {
IMqttToken token = client.disconnect();
token.waitForCompletion();
} catch (MqttException e) {
log.error("=>断开mqtt连接发生错误 message={}", e.getMessage());
throw new ServiceException("断开mqtt连接发生错误" + e.getMessage());
}
}
client = null;
}
/**
* 重新连接MQTT
*/
public synchronized void refresh() {
disconnect();
initialize();
}
/**
* 拼接客户端id
*/
public final String getClientId() {
return FastBeeConstant.SERVER.WM_PREFIX + System.currentTimeMillis();
}
/**
* 发布主题
*
* @param message payload消息体
* @param topic 主题
* @param retained 是否保留消息
* @param qos 消息质量
* Qos1消息发送一次不确保
* Qos2至少分发一次服务器确保接收消息进行确认
* Qos3只分发一次确保消息送达和只传递一次
*/
public void publish(byte[] message, String topic, boolean retained, int qos) {
//设置mqtt消息
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setQos(qos);
mqttMessage.setRetained(retained);
mqttMessage.setPayload(message);
IMqttDeliveryToken token;
try {
token = client.publish(topic, mqttMessage);
token.waitForCompletion();
} catch (MqttPersistenceException e) {
log.error("=>发布主题时发生错误 topic={},message={}", topic, e.getMessage());
throw new ServiceException(e.getMessage());
} catch (MqttException ex) {
throw new ServiceException(ex.getMessage());
}
}
/**
* 发布
*
* @param qos 连接方式
* @param retained 是否保留
* @param topic 主题
* @param pushMessage 消息体
*/
public void publish(int qos, boolean retained, String topic, String pushMessage) {
redisCache.incr2(FastBeeConstant.REDIS.MESSAGE_SEND_TOTAL, -1L);
redisCache.incr2(FastBeeConstant.REDIS.MESSAGE_SEND_TODAY, 60 * 60 * 24);
MqttMessage message = new MqttMessage();
message.setQos(qos);
message.setRetained(retained);
message.setPayload(pushMessage.getBytes());
try {
IMqttDeliveryToken token = client.publish(topic, message);
token.waitForCompletion();
log.info("发布主题[{}],发布消息[{}]" , topic,pushMessage);
} catch (MqttPersistenceException e) {
e.printStackTrace();
} catch (MqttException e) {
log.error("=>发布主题时发生错误 topic={},message={}", topic, e.getMessage());
}
}
}