项目中集成mqtt客户端查询功能,使用到了EMQX api-v5
,具体步骤:
一、准备工作
首先在EMQX dashboard
中添加API 密钥
填写密钥名称,点击确定,会生成API Key
和Secret Key
,保存起来备用。
二、配置文件
在springboot的配置文件中添加如下配置
spring:# mqtt 配置mqtt:api:# mqtt dashboard的访问地址host: http://xxx.xxx.xxx.xxx:18083# 上图中的apiKeyapiKey: xxxxxxxxxxxx# 上图中的secretKeysecretKey: xxxxxxxxxxxx
三、后端实现
创建配置类MqttApiConfig
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.mqtt.api")
public class MqttApiConfig {private String host;private String apiKey;private String secretKey;
}
查询参数DeviceStatusRequest
@Data
public class DeviceStatusRequest {private String deviceId;private int pageNum = 1;private int pageSize = 20;
}
接收参数DeviceStatusInfo
@Data
public class DeviceStatusInfo {private Boolean connected;private String node;private Integer port;private Integer keepalive;private String ip_address;private String username;private String created_at;private String clientid;private String connected_at;private Boolean clean_start;
}
创建Controller的接口
@Slf4j
@RequestMapping("/mqtt/client")
@RestController
public class ClientController extends BaseController {@Resourceprivate MqttApiConfig mqttConfig;@Resourceprivate RestTemplate restTemplate;/*** 获取所有MQTT客户端列表*/private final String GET_ALL_MQTT_CLIENTS_URL = "%s/api/v5/clients?page=%s&limit=%s&fields=clientid,username,connected,ip_address,port,keepalive,clean_start,connected_at,node,disconnected_at,created_at";/*** 获取单个MQTT客户端状态信息*/private final String GET_MQTT_CLIENT_STATUS_URL = "%s/api/v5/clients?clientid=%s&fields=clientid,username,connected,ip_address,port,keepalive,clean_start,connected_at,node,disconnected_at,created_at";/*** 分页查询所有MQTT客户端** @return*/@GetMapping("/all")public PageResult<List<DeviceStatusInfo>> getClients(DeviceStatusRequest request) {String deviceId = request.getDeviceId();String url = String.format(GET_ALL_MQTT_CLIENTS_URL, mqttConfig.getHost(), request.getPageNum(), request.getPageSize());if (StringUtils.isNotBlank(deviceId)) {url = String.format(GET_MQTT_CLIENT_STATUS_URL, mqttConfig.getHost(), deviceId);}JSONObject object = exchange(url);if (object != null) {List<DeviceStatusInfo> list = JSONArray.parseArray(object.getString("data"), DeviceStatusInfo.class);JSONObject meta = object.getJSONObject("meta");Page<DeviceStatusInfo> page = new Page<>();page.addAll(list);page.setPageNum(meta.getInteger("page"));page.setPageSize(meta.getInteger("limit"));page.setTotal(meta.getLong("count"));return PageResult.success(page);}return new PageResult(500, "没有查询到数据");}private JSONObject exchange(String url) {HttpHeaders headers = new HttpHeaders();headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));headers.setBasicAuth(mqttConfig.getApiKey(), mqttConfig.getSecretKey(), StandardCharsets.UTF_8);HttpEntity entity = new HttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);log.info("response=>{}", response);if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {String body = response.getBody();return JSONObject.parseObject(body);}return null;}
四、前端实现
<template><div class="app-container"><el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px"><el-form-item label="客户端" prop="deviceId"><el-inputv-model="queryParams.deviceId"placeholder="请输入设备id"clearable@keyup.enter.native="handleQuery"style="width: 160px"/></el-form-item><el-form-item><el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button><el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button></el-form-item></el-form><el-table v-loading="loading" :data="list" style="width: 100%;"><el-table-column label="序号" type="index" align="center"/><el-table-column label="客户端ID" align="left" prop="clientid" min-width="180" :show-overflow-tooltip="true"/><el-table-column label="用户名" align="center" prop="username" min-width="150" :show-overflow-tooltip="true"/><el-table-column label="节点" align="left" prop="node" width="180" :show-overflow-tooltip="true"/><el-table-column label="连接状态" align="center" width="120"><template v-slot="scope"><el-tag :type="scope.row.connected ? 'success' : 'danger'">{{ scope.row.connected ? '已连接' : '未连接' }}</el-tag></template></el-table-column><el-table-column label="IP地址" align="left" prop="ip_address" min-width="150" :show-overflow-tooltip="true"><template v-slot="scope"><span>{{ scope.row.ip_address}}:{{scope.row.port}}</span></template></el-table-column><el-table-column label="心跳" align="center" prop="keepalive" width="120"/><el-table-column label="清除会话" align="center" width="120"><template v-slot="scope"><el-tag>{{ scope.row.clean_start }}</el-tag></template></el-table-column><el-table-column label="会话创建时间" align="center" width="180"><template v-slot="scope"><span>{{ parseTime(scope.row.created_at) }}</span></template></el-table-column><el-table-column label="连接时间" align="center" width="180"><template v-slot="scope"><span>{{ parseTime(scope.row.connected_at) }}</span></template></el-table-column></el-table><paginationv-show="total>0":total="total":page.sync="queryParams.pageNum":limit.sync="queryParams.pageSize"@pagination="getList"/></div>
</template><script>
import {getMqttClient} from "@/api/mqtt";export default {name: "MqttClient",data() {return {// 遮罩层loading: true,// 总条数total: 0,// 表格数据list: [],// 查询参数queryParams: {deviceId: undefined,pageNum: 1,pageSize: 20}};},created() {this.getList();},methods: {/** 查询登录日志列表 */getList() {this.loading = true;getMqttClient(this.queryParams).then(response => {this.list = response.data;this.total = response.count;this.loading = false;});},/** 搜索按钮操作 */handleQuery() {this.pageNum = 1;this.getList();},/** 重置按钮操作 */resetQuery() {this.resetForm("queryForm");this.handleQuery();},}
};
</script>