业务需要订阅第三方主题,于是碰见了Mqtt接着就发现了 在 springboot 中整合mqtt 回调方法 messageArrived()获取数据时如果直接操作数据库会使连接断开

头大,网上查了好久,看了好多哥们的博客,也没记下来都借鉴了哪些的。感谢各位大佬,啥也不说了,贴代码记录一下

@Slf4j
public class McListener {



private MqttClient client_sub;
private MqttConnectOptions options_sub;
// 用户名
private final String username = "****";
// 密钥
private final String password = "********";
// 主题
private final String footballTopic = "*******";
// 主题
private final String basketballTopic = "*******";

private final String broker = "*******";//你订阅的地址

private final String clientId = "MqttClient_"+ System.currentTimeMillis();

private static final McListener listener = new McListener();

public static McListener getInstance() {
return listener;
}

private McListener() {

}
public void initMQTTListener() {
try {
//获取配置信息
// HOST_MQ为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
client_sub = new MqttClient(broker, clientId, new MemoryPersistence());
// MQTT的连接设置
options_sub = new MqttConnectOptions();
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
options_sub.setCleanSession(false);
// 设置连接的用户名
options_sub.setUserName(username);
// 设置连接的密码
options_sub.setPassword(password.toCharArray());
// 设置会话心跳时间 单位为秒 服务器会每隔90秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options_sub.setKeepAliveInterval(90);
//订阅topic定义
int[] Qos = new int[]{0, 0};
String[] topics = new String[]{footballTopic, basketballTopic};

// 设置回调
client_sub.setCallback(new PushCallback());
//连接mqtt服务器broker
client_sub.connect(options_sub);
//订阅消息
client_sub.subscribe(topics, Qos);
} catch (Exception e) {
// TODO Auto-generated catch block
log.error("init listener MQTT err info: {}", e.toString());
System.exit(-1);
}
}
public void reConnect() {
try {
if (null != client_sub && !(client_sub.isConnected())) {
client_sub.reconnect();
log.error("=======尝试重新连接==============");
}
} catch (MqttException e) {
log.error("=======重新连接失败:{}==============", e.toString());
}
}
/**
* 向某个主题发布消息 默认qos:1
*
* @param topic:发布的主题
* @param msg:发布的消息
*/
public void pub(String topic, String msg) throws MqttException {
MqttMessage mqttMessage = new MqttMessage();
//mqttMessage.setQos(2);
mqttMessage.setPayload(msg.getBytes());
MqttTopic mqttTopic = client_sub.getTopic(topic);
MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
token.waitForCompletion();
}

/**
* 向某个主题发布消息
*
* @param topic: 发布的主题
* @param msg: 发布的消息
* @param qos: 消息质量 Qos:0、1、2
*/
public void pub(String topic, String msg, int qos) throws MqttException {
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setQos(qos);
mqttMessage.setPayload(msg.getBytes());
MqttTopic mqttTopic = client_sub.getTopic(topic);
MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
token.waitForCompletion();
}

/**
* 订阅某一个主题 ,此方法默认的的Qos等级为:1
*
* @param topic 主题
*/
public void sub(String topic) throws MqttException {
client_sub.subscribe(topic);
}

/**
* 订阅某一个主题,可携带Qos
*
* @param topic 所要订阅的主题
* @param qos 消息质量:0、1、2
*/
public void sub(String topic, int qos) throws MqttException {
client_sub.subscribe(topic, qos);
}
/**
* 关闭MQTT连接
*/
public void close() throws MqttException {
client_sub.close();
client_sub.disconnect();
}
}

=====================================分割线======================================================
上面这些看着人畜无害,但是就在 messageArrived()里处理数据的时候就出问题了,上面的代码没有,是修改之后的,然后一并这个方法也挪走了

不哔哔了,贴代码
PushCallback 实现 MqttCallback 划重点


@Slf4j
public class PushCallback implements MqttCallback {

@Autowired
private McListener mcListener;


public void connectionLost(Throwable cause) {
mcListener.reConnect();
}

public void deliveryComplete(IMqttDeliveryToken token) {
log.error("deliveryComplete---------" + token.isComplete());
}

public void messageArrived(String topic, MqttMessage message) throws Exception {
log.debug("接收消息主题 : " + topic);
String res = new String(message.getPayload());
log.debug("接收消息内容 : " + res);
SendMsg.sendMsg.sendMsgtoCust(res,topic);

}




   =============================================重点这里=============================================
    所有相关数据库一类的操作也好其他逻辑也好在这里写

    sendMsgtoCust()就是你的方法名,里面写你的逻辑


@Component
public static class SendMsg{


private static SendMsg sendMsg; //必须要重写一下!!


@PostConstruct
public void init(){
sendMsg = this;
}
      
public void sendMsgtoCust(String msg,String topic){
try {

int type;
if (topic.equals("sports/football/match.v1")){
type = 1;
} else {
type = 2;
}

WsClient.send(msg,type);
// 判断是否连接成功,未成功后面发送消息时会报错

log.info("推送成功");
} catch (Exception e) {

e.printStackTrace();
}
}

}

}

调用的时候     SendMsg.sendMsg.sendMsgtoCust(res,topic);  嗯,就可以了,理论太菜,有空研究

posted on 2021-11-28 20:22  独醉笑清风  阅读(3508)  评论(0编辑  收藏  举报