一、前言
  这里虽然是说MQTT客户端。其实对于服务器来说,这里的一个具有超级权限的MQTT客户端,就可以做很多事情。比如手机APP或者网页或者第三方服务需要发送数据到设备,但是这些又不是设备,又不能让他们连到MQTT。那么就可以通过HTTP请求业务服务器。然后由业务服务器利用这个MQTT客户端进行发送数据。
  还有,之前好多人问我,怎么保存这些物联网数据,真的要像前面的博客那样,要自己写插件吗?特别麻烦的啊。这里给出的结论是不需要。保存数据,除了写EMQ插件,还可以在EMQ的规则引擎上进行配置Web消息转发【EMQ 3.x 版本】,还有就是这种通过业务服务器订阅根Topic来保存物联网原始数据。
  这篇博客这讨论如何把MQTT客户端集成到业务服务器上(基于SpringBoot 2.0)。下一篇博客会讲到数据保存到InfluxDB,然后如何通过Grafana进行可视化Dashboard看板模式展示。

二、配置pom.xml,引入第三方库

         <!-- MQTT -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>

三、MQTT客户端代码(Java)

  MqttDemoApplication.java

 package com.wunaozai.mqtt;

 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import com.wunaozai.mqtt.tools.MqttPushClient; @SpringBootApplication
public class MqttDemoApplication { public static void main(String[] args) {
SpringApplication.run(MqttDemoApplication.class, args); test();
} private static void test(){
MqttPushClient.MQTT_HOST = "tcp://mqtt.com:1883";
MqttPushClient.MQTT_CLIENTID = "client";
MqttPushClient.MQTT_USERNAME = "username";
MqttPushClient.MQTT_PASSWORD = "password";
MqttPushClient client = MqttPushClient.getInstance();
client.subscribe("/#");
}
}

  MqttPushCallback.java

 package com.wunaozai.mqtt.tools;

 import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* MQTT 推送回调
* @author wunaozai
* @date 2018-08-22
*/
public class MqttPushCallback implements MqttCallback { private static final Logger log = LoggerFactory.getLogger(MqttPushCallback.class); @Override
public void connectionLost(Throwable cause) {
log.info("断开连接,建议重连" + this);
//断开连接,建议重连
} @Override
public void deliveryComplete(IMqttDeliveryToken token) {
//log.info(token.isComplete() + "");
} @Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
log.info("Topic: " + topic);
log.info("Message: " + new String(message.getPayload()));
} }

  MqttPushClient.java

 package com.wunaozai.mqtt.tools;

 import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* 创建一个MQTT客户端
* @author wunaozai
* @date 2018-08-22
*/
public class MqttPushClient { private static final Logger log = LoggerFactory.getLogger(MqttPushClient.class);
public static String MQTT_HOST = "";
public static String MQTT_CLIENTID = "";
public static String MQTT_USERNAME = "";
public static String MQTT_PASSWORD = "";
public static int MQTT_TIMEOUT = 10;
public static int MQTT_KEEPALIVE = 10; private MqttClient client;
private static volatile MqttPushClient mqttClient = null;
public static MqttPushClient getInstance() {
if(mqttClient == null) {
synchronized (MqttPushClient.class) {
if(mqttClient == null) {
mqttClient = new MqttPushClient();
}
}
}
return mqttClient;
} private MqttPushClient() {
log.info("Connect MQTT: " + this);
connect();
} private void connect() {
try {
client = new MqttClient(MQTT_HOST, MQTT_CLIENTID, new MemoryPersistence());
MqttConnectOptions option = new MqttConnectOptions();
option.setCleanSession(true);
option.setUserName(MQTT_USERNAME);
option.setPassword(MQTT_PASSWORD.toCharArray());
option.setConnectionTimeout(MQTT_TIMEOUT);
option.setKeepAliveInterval(MQTT_KEEPALIVE);
option.setAutomaticReconnect(true);
try {
client.setCallback(new MqttPushCallback());
client.connect(option);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发布主题,用于通知<br>
* 默认qos为1 非持久化
* @param topic
* @param data
*/
public void publish(String topic, String data) {
publish(topic, data, 1, false);
}
/**
* 发布
* @param topic
* @param data
* @param qos
* @param retained
*/
public void publish(String topic, String data, int qos, boolean retained) {
MqttMessage message = new MqttMessage();
message.setQos(qos);
message.setRetained(retained);
message.setPayload(data.getBytes());
MqttTopic mqttTopic = client.getTopic(topic);
if(null == mqttTopic) {
log.error("Topic Not Exist");
}
MqttDeliveryToken token;
try {
token = mqttTopic.publish(message);
token.waitForCompletion();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 订阅某个主题 qos默认为1
* @param topic
*/
public void subscribe(String topic) {
subscribe(topic, 1);
}
/**
* 订阅某个主题
* @param topic
* @param qos
*/
public void subscribe(String topic, int qos) {
try {
client.subscribe(topic, qos);
} catch (Exception e) {
e.printStackTrace();
}
}
}

四、MQTT客户端代码(C#)
  为了下下篇博客Grafana有数据可以展示,我需要开发一个PC小工具【设备仿真】,用来模拟设备一直发送数据。这里就不对C#开发进行过多的说明了。通过nuget,引入第三方mqtt库。这个工具是我现在开发平台工具链的一个小工具。至于里面的Payload协议,可以不用管。读者可以根据自己的业务制定自己的通信协议。

  部分C#代码(连接服务器与发送数据)

 using MQTTClient.Model;
using MQTTnet;
using MQTTnet.Core;
using MQTTnet.Core.Client;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace MQTTClient
{
public partial class MainPage : Form
{
public MainPage()
{
InitializeComponent();
init();
}
private void init()
{
txtusername.Text = "";
txtpassword.Text = "";
txtclientid.Text = "";
txttopic.Text = "iot/UUID/device/devicepub/update";
} IMqttClient client = null;
private async Task ConnectMqttServerAsync()
{
if(client == null)
{
client = new MqttClientFactory().CreateMqttClient() as MqttClient;
client.ApplicationMessageReceived += mqttClientApplicationMessageReceived;
client.Connected += mqttClientConnected;
client.Disconnected += mqttClientDisconnected;
}
try
{
await client.DisconnectAsync();
var option = getMQTTOption();
await client.ConnectAsync(option);
}catch(Exception e)
{
Invoke((new Action(() =>
{
lblStatus.Text = "连接服务器失败: " + e.Message;
})));
}
}
private void mqttClientDisconnected(object sender, EventArgs e)
{
Invoke((new Action(() =>
{
lblStatus.Text = "连接服务器失败: ERROR";
})));
}
private void mqttClientConnected(object sender, EventArgs e)
{
Invoke((new Action(() =>
{
lblStatus.Text = "连接服务器成功";
})));
}
private void mqttClientApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
{
//本工具部收数据
throw new NotImplementedException();
} private void btnconnect_Click(object sender, EventArgs e)
{
Task.Run(async () => { await ConnectMqttServerAsync(); });
}
private void btndisconnect_Click(object sender, EventArgs e)
{
client.DisconnectAsync();
}
private void btnsendone_Click(object sender, EventArgs e)
{
sendPayload();
}
private void btnsendts_Click(object sender, EventArgs e)
{
timer1.Interval = Convert.ToInt32(txttime.Text);
timer1.Enabled = true;
}
private void btnstopts_Click(object sender, EventArgs e)
{
timer1.Enabled = false;
}
private void timer1_Tick(object sender, EventArgs e)
{
sendPayload();
}
private int sendPayload()
{
if (client.IsConnected == false)
{
return -;
}
PayloadModel payload = getPayload();
string json = JsonConvert.SerializeObject(payload, Formatting.Indented);
txtview.Text = json;
string topic = txttopic.Text;
var msg = new MqttApplicationMessage(topic, Encoding.Default.GetBytes(json),
MQTTnet.Core.Protocol.MqttQualityOfServiceLevel.AtMostOnce, false);
client.PublishAsync(msg);
lblSendStatus.Text = "发送: " + DateTime.Now.ToLongTimeString();
return ;
} private MqttClientTcpOptions getMQTTOption()
{
MqttClientTcpOptions option = new MqttClientTcpOptions();
string hostname = txthostname.Text;
string[] host_port = hostname.Split(':');
int port = ;
if(host_port.Length >= )
{
hostname = host_port[];
port = Convert.ToInt32(host_port[]);
}
option.Server = hostname;
option.ClientId = txtclientid.Text;
option.UserName = txtusername.Text;
option.Password = txtpassword.Text;
option.Port = port;
option.CleanSession = true;
return option;
} private PayloadModel getPayload()
{
PayloadModel payload = new PayloadModel();
//略
return payload;
} Random rand1 = new Random(System.DateTime.Now.Millisecond);
private int getRandomNum()
{
int data = rand1.Next(, );
return data;
} int linenum = ;
Random rand2 = new Random(System.DateTime.Now.Millisecond);
private int getLineNum()
{
int f = rand2.Next(, );
int data = rand2.Next(, );
if(f % == )
{
linenum += data;
}
else
{
linenum -= data;
}
return linenum;
} }
}

本文地址: https://www.cnblogs.com/wunaozai/p/11147841.html

物联网架构成长之路(32)-SpringBoot集成MQTT客户端的更多相关文章

  1. 物联网架构成长之路(13)-SpringBoot入门

    1. 前言 下载最新版的JavaEE eclipse-jee-oxygen-2-win32-x86_64.zip 安装STS插件 Window->Eclipse Marketplace -> ...

  2. 物联网架构成长之路(14)-SpringBoot整合thymeleaf

    使用thymeleaf作为模版进行测试 在pom.xml 增加依赖 <dependency> <groupId>org.springframework.boot</gro ...

  3. 物联网架构成长之路(25)-Docker构建项目用到的镜像1

    0. 前言 现在项目处于初级阶段,按照规划,先构建几个以后可能会用到的Image,并上传到阿里云的Docker仓库.以后博客中用到的Image,大部分都会用到这几个基础的Image,构建一个简单的物联 ...

  4. 物联网架构成长之路(31)-EMQ基于HTTP权限验证

    看过之前的文章就知道,我之前是通过搞插件,或者通过里面的MongoDB来进行EMQ的鉴权登录和权限验证.但是前段时间发现,还是通过HTTP WebHook 方式来调用鉴权接口比较适合实际使用.还是实现 ...

  5. 物联网架构成长之路(6)-EMQ权限控制

    1. 前言 EMQTT属于一个比较小众的开源软件,很多资料不全,很麻烦,很多功能都是靠猜测,还有就是看官方提供的那几个插件,了解. 2. 说明 上一小节的插件 emq_plugin_wunaozai ...

  6. 物联网架构成长之路(8)-EMQ-Hook了解、连接Kafka发送消息

    1. 前言 按照我自己设计的物联网框架,对于MQTT集群中的所有消息,是要持久化到磁盘的,这里采用一个消息队列中间件Kafka作为数据缓冲,缓冲结果存到数据仓库中,以供后续作为数据分析.由于MQTT集 ...

  7. 物联网架构成长之路(15)-Jenkins部署SpringBoot

    1.前言 现在慢慢也在负责一些工作了.这段时间有空,就多了解了解软件多人开发的一些知识.以前项目都是我一个人做的,从数据库设计到后端再到前端,全部放在一个war包丢到tomcat里面然后运行,利用to ...

  8. 物联网架构成长之路(47)-利用GitLab实现CI持续集成

    0.前言 前段时间,考虑到要练习部署一套CI/CD的系统.一开始考虑到Jenkins,随着这两天的了解,发现最新版的GitLab已经提供有CI/CD集成了.所以本次博客,干脆一步到位,直接用GitLa ...

  9. 物联网架构成长之路(33)-EMQ数据存储到influxDB

    一.前言 时隔一年半,技术变化特别快,学习也要跟上才行.以前写过EMQ数据转存问题,当时用了比较笨的方法,通过写插件的方式,把MQTT里面的数据发送到数据库进行存储.当时也是为了学习erlang和em ...

随机推荐

  1. 你需要知道的OpenGL

    它是谁? OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D.3D矢量图形的跨语言.跨平台的应用程序编程接口(API).这个接口由近3 ...

  2. js常用但是不容易记住的代码

    <!-- iframe 自适应高度度 --><iframe src="__CONTROLLER__/showlist" frameborder="0&q ...

  3. 【计算机网络】如何让Ajax通信过程携带Cookie呢?

    Ajax 1. 介绍一下ajax并代码实现 1.1 基本概念 JavaScript 和XML(Asynchronous JavaScript And XML).简单点说,就是使用 XMLHttpReq ...

  4. javascript在数组的循环中删除元素

    在开发JavaScript应用的过程中,经常会遇到在循环中移除指定元素的需求. 按照常规的思路,就是对数组进行一个for循环,然后在循环里面进行if判断,在判断中删除掉指定元素即可. 但是实际情况往往 ...

  5. pandas 学习 第6篇:DataFrame - 数据处理(长宽格式、透视表)

    长宽格式的转换 宽格式是指:一列或多列作为标识变量(id_vars),其他变量作为度量变量(value_vars),直观上看,这种格式的数据比较宽,举个列子,列名是:id1.id2.var1.var2 ...

  6. SpringBoot(14)—注解装配Bean

    SpringBoot(14)-注解装配Bean SpringBoot装配Bean方式主要有两种 通过Java配置文件@Bean的方式定义Bean. 通过注解扫描的方式@Component/@Compo ...

  7. Java的23种设计模式,详细讲解(三)

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  8. python+java蓝桥杯ACM日常算法题训练(一)10基础题

    目录 1.简单的a+b 2.第一个HelloWorld程序! 3.三个数最大值 4.密码破译 5.母牛的故事 6.7.8.9.10 @(这里写自定义目录标题) 算法题训练网站:http://www.d ...

  9. Tomcat启动分析(二)-自己编译Tomcat

    为了方便分析Tomcat源码,利用大家习惯的方式来进行Debug调试,那么如何将Tomcat源码导入到Eclipse呢,这就是本文的重点 1 准备 1.1 获取Tomcat源码 获取tomcat源码有 ...

  10. REST API的使用

    需求描述 GET: http://localhost:8080/MyWebsite/user/ Header: Content-Type = application/json Body: 空 Resp ...