Spring boot 集成 阿里 Mqtt
因为公司业务需求,需要接入 阿里Mqtt,自己基于Spring写了一个小demo,记录下来,已备以后需要。
第一步
创建一个实体bean用来装载 MqttClient
private MqttClient mqttClient;
@Autowired
private MqttConnectOptions mqttConnectOptions;
@Autowired
private MqttConfig mqttConfig;
@Autowired
private MqttCallback mqttCallback;
private void start() throws MqttException {
final MemoryPersistence memoryPersistence = new MemoryPersistence();
/**
* 客户端使用的协议和端口必须匹配,具体参考文档 https://help.aliyun.com/document_detail/44866.html?spm=a2c4g.11186623.6.552.25302386RcuYFB
* 如果是 SSL 加密则设置ssl://endpoint:8883
*/
this.mqttClient= new MqttClient("tcp://" + mqttConfig.getConnectEndpoint() + ":1883",
mqttConfig.getGroupId() + "@@@" + mqttConfig.getClientId(), memoryPersistence);
mqttClient.setTimeToWait(mqttConfig.getTimeToWait());
mqttClient.setCallback(mqttCallback);
mqttClient.connect(mqttConnectOptions);
}
private void shutdown() throws MqttException {
this.mqttClient.disconnect();
}
public MqttClient getMqttClient(){
return this.mqttClient;
}
第二步
对MqClient 进行加载
@Autowired
private MqttConfig mqttConfig;
@Bean
public MqttConnectOptions getMqttConnectOptions() throws NoSuchAlgorithmException, InvalidKeyException {
MqttConnectOptions mqttConnectOptions=new MqttConnectOptions();
//组装用户名密码
mqttConnectOptions.setUserName("Signature|" + mqttConfig.getAccessKey() + "|" + mqttConfig.getInstanceId());
//密码签名
mqttConnectOptions.setPassword(info.feibiao.live.config.mqtt.Tools.macSignature(mqttConfig.getGroupId()+"@@@"+mqttConfig.getClientId(), mqttConfig.getSecretKey()).toCharArray());
mqttConnectOptions.setCleanSession(true);
mqttConnectOptions.setKeepAliveInterval(90);
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setMqttVersion(MQTT_VERSION_3_1_1);
//连接超时时间
mqttConnectOptions.setConnectionTimeout(5000);
mqttConnectOptions.setKeepAliveInterval(2);
return mqttConnectOptions;
}
@Bean(initMethod = "start", destroyMethod = "shutdown")
public MqttClientBean getClient() {
return new MqttClientBean();
}
第三步
创建接收消息,连接成功,连接丢失 回调类
连接成功后需要订阅相关主题
@Autowired
MqttClientBean mqttClientBean;
@Autowired
MqttConfig mqttConfig;
@Override
public void connectComplete(boolean reconnect, String serverURI) {
/**
* 客户端连接成功后就需要尽快订阅需要的 topic
*/
System.out.println("connect success");
ExecutorService mqttExecutorService = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
mqttExecutorService.submit(() -> {
try {
//订阅主题,主主题后面可以跟子主题 过滤规则 +:过滤一级 ,#:过滤所有
final String[] topicFilter = {mqttConfig.getTopicId() + "/" + "testMq4Iot"};
int qosLevel=0;
final int[] qos = {qosLevel};
MqttClient mqttClient = mqttClientBean.getMqttClient();
mqttClient.subscribe(topicFilter, qos);
} catch (MqttException e) {
e.printStackTrace();
}
});
}
@Override
public void connectionLost(Throwable throwable) {
throwable.printStackTrace();
}
@Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
/**
* 这个地方消费
* 消费消息的回调接口,需要确保该接口不抛异常,该接口运行返回即代表消息消费成功。
* 消费消息需要保证在规定时间内完成,如果消费耗时超过服务端约定的超时时间,对于可靠传输的模式,服务端可能会重试推送,业务需要做好幂等去重处理。超时时间约定参考限制
* https://help.aliyun.com/document_detail/63620.html?spm=a2c4g.11186623.6.546.229f1f6ago55Fj
*/
System.out.println(
"receive msg from topic " + s + " , body is " + new String(mqttMessage.getPayload()));
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("send msg succeed topic is : " + iMqttDeliveryToken.getTopics()[0]);
}
第四步
添加配置实体类,从yml配置文件中读取配置数据
/**
* 可在阿里云控制台找到(实例id)
*/
private String instanceId;
/**
* accessKey
*/
private String accessKey;
/**
* 密钥
*/
private String secretKey;
/**
* TCP 协议接入点
*/
private String connectEndpoint;
/**
* 话题id
*/
private String topicId;
/**
* 群组id
*/
private String groupId;
/**
* 消息模式(广播订阅, 集群订阅)
*/
private String messageModel;
/**
* 超时时间
*/
private String sendMsgTimeoutMillis;
/**
* 顺序消息消费失败进行重试前的等待时间 单位(毫秒)
*/
private String suspendTimeMillis;
/**
* 消息消费失败时的最大重试次数
*/
private String maxReconsumeTimes;
/**
* 公网token服务器
*/
private String mqttClientTokenServer;
/**
* 过期时间(默认1个月)
*/
private Long mqttClientTokenExpireTime;
/**
* 分发给客户端的token的操作权限
*/
private String mqttAction;
/**
* 客户端标识
*/
private String clientId;
/**
* QoS参数代表传输质量,可选0,1,2,根据实际需求合理设置,具体参考 https://help.aliyun.com/document_detail/42420.html?spm=a2c4g.11186623.6.544.1ea529cfAO5zV3
*/
private int qosLevel = 0;
/**
* 客户端超时时间
*/
private int timeToWait;
配置文件:
spring.application.name: mqtt-server-demo
server.port: 18005
# mqtt消息
mqtt.msg:
instanceId: post-cn-0pp13c3gn0u #实例Id
accessKey: LTAIPZjAd2naVfA0 #appId
secretKey: 38ZLMHoP5r4p0a4gUEGUhzL46EdzQx #密钥 阿里云控制台查看
connectEndpoint: post-cn-0pp13c3gn0u.mqtt.aliyuncs.com #端点
topicId: TID_liveChat #父级主题
groupId: GID_liveChat #分组
messageModel: BROADCASTING #广播订阅方式, 默认是 CLUSTERING 集群订阅
sendMsgTimeoutMillis: 20000 # 发消息超时时间30s
suspendTimeMillis: 500 #顺序消息消费失败进行重试前的等待时间 单位(毫秒)
maxReconsumeTimes: 3 #消息消费失败时的最大重试次数
mqttClientTokenServer: mqauth.aliyuncs.com # 公网token服务器
mqttClientTokenExpireTime: 2592000000 # token 过期时间1个月
mqttAction: R,W # 读写操作
clientId: FEI_JAVA #客户端名称
qosLevel: 0 #QoS参数代表传输质量,可选0,1,2
timeToWait: 5000 #客户端超时时间
spring.main.allow-bean-definition-overriding: true
最后贴上签名方法:
/**
* 计算签名,参数分别是参数对以及密钥
*
* @param requestParams 参数对,即参与计算签名的参数
* @param secretKey 密钥
* @return 签名字符串
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static String doHttpSignature(Map<String, String> requestParams,
String secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
List<String> paramList = new ArrayList<String>();
for (Map.Entry<String, String> entry : requestParams.entrySet()) {
paramList.add(entry.getKey() + "=" + entry.getValue());
}
Collections.sort(paramList);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < paramList.size(); i++) {
if (i > 0) {
sb.append('&');
}
sb.append(paramList.get(i));
}
return macSignature(sb.toString(), secretKey);
}
/**
* @param text 要签名的文本
* @param secretKey 阿里云MQ secretKey
* @return 加密后的字符串
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
*/
public static String macSignature(String text,
String secretKey) throws InvalidKeyException, NoSuchAlgorithmException {
Charset charset = Charset.forName("UTF-8");
String algorithm = "HmacSHA1";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(secretKey.getBytes(charset), algorithm));
byte[] bytes = mac.doFinal(text.getBytes(charset));
return new String(Base64.encodeBase64(bytes), charset);
}
阿里云mqtt支持Token 模式:
获取token以及销毁token:
private static final String applyTokenUrl = "/token/apply";
private static final String revokeTokenUrl = "/token/revoke";
/**
* 申请 Token 接口,具体参数参考链接
* https://help.aliyun.com/document_detail/54276.html?spm=a2c4g.11186623.6.562.f12033f5ay6nu5
*
* @param apiUrl token 服务器地址,参考文档设置正确的地址
* @param accessKey 账号 AccessKey,由控制台获取
* @param secretKey 账号 SecretKey,由控制台获取
* @param topics 申请的 topic 列表
* @param action Token类型
* @param expireTime Token 过期的时间戳
* @param instanceId MQ4IoT 实例 Id
* @return 如果申请成功则返回 token 内容
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws IOException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
* @throws KeyManagementException
*/
public String applyToken(String apiUrl, String accessKey, String secretKey, List<String> topics,
String action,
long expireTime,
String instanceId) throws InvalidKeyException, NoSuchAlgorithmException, IOException, KeyStoreException, UnrecoverableKeyException, KeyManagementException {
Map<String, String> paramMap = new HashMap<>();
Collections.sort(topics);
StringBuilder builder = new StringBuilder();
for (String topic : topics) {
builder.append(topic).append(",");
}
if (builder.length() > 0) {
builder.setLength(builder.length() - 1);
}
paramMap.put("resources", builder.toString());
paramMap.put("actions", action);
paramMap.put("serviceName", "mq");
paramMap.put("expireTime", String.valueOf(System.currentTimeMillis() + expireTime));
paramMap.put("instanceId", instanceId);
String signature = Tools.doHttpSignature(paramMap, secretKey);
paramMap.put("proxyType", "MQTT");
paramMap.put("accessKey", accessKey);
paramMap.put("signature", signature);
JSONObject object = Tools.httpsPost("http://"+apiUrl + applyTokenUrl, paramMap);
if (object != null) {
return (String) object.get("tokenData");
}
return null;
}
/**
* 提前注销 token,一般在 token 泄露出现安全问题时,提前禁用特定的客户端
*
* @param apiUrl token 服务器地址,参考文档设置正确的地址
* @param accessKey 账号 AccessKey,由控制台获取
* @param secretKey 账号 SecretKey,由控制台获取
* @param token 禁用的 token 内容
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws IOException
* @throws UnrecoverableKeyException
* @throws KeyStoreException
* @throws KeyManagementException
*/
public void revokeToken(String apiUrl, String accessKey, String secretKey,
String token) throws InvalidKeyException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyStoreException, KeyManagementException {
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("token", token);
String signature = Tools.doHttpSignature(paramMap, secretKey);
paramMap.put("signature", signature);
paramMap.put("accessKey", accessKey);
JSONObject object = Tools.httpsPost("http://"+apiUrl + revokeTokenUrl, paramMap);
}
Token模式客户端使用方式:
在构建ConnectionOptionWrapper的时候使用签发的token:
String token="LzMT+XLFl5u**********************************KhCznZx";
Map<String, String> tokenData = new HashMap<String, String>();
tokenData.put("RW", token);
ConnectionOptionWrapper connectionOptionWrapper = new ConnectionOptionWrapper(instanceId, accessKey, clientId, tokenData);
码云地址:
https://gitee.com/ioso/mqtt-demo
Spring boot 集成 阿里 Mqtt的更多相关文章
- Spring Boot 集成阿里云 OSS 进行文件存储
最近因为项目中需要存储很多的图片,不想存储到服务器上,因此就直接选用阿里云的对象服务(Object Storage Service,简称 OSS)来进行存储,本文将介绍 Spring Boot 集成 ...
- spring boot集成阿里云短信发送接收短信回复功能
1.集成阿里云通信发送短信: 在pom.xml文件里添加依赖 <!--阿里短信服务--> <dependency> <groupId>com.aliyun</ ...
- 玩转spring boot——结合阿里云持续交付
前言 在互联网项目中,项目测试.部署往往需要花费大量时间.传统方式是在本地打包.测试完毕程序,然后通过ftp上传至服务器,再把测试的配置文件修改为生产环境的配置文件,最后重新运行服务.这一过程如果交给 ...
- Spring Boot 集成 Swagger 生成 RESTful API 文档
原文链接: Spring Boot 集成 Swagger 生成 RESTful API 文档 简介 Swagger 官网是这么描述它的:The Best APIs are Built with Swa ...
- Spring Boot集成Shiro实战
Spring Boot集成Shiro权限验证框架,可参考: https://shiro.apache.org/spring-boot.html 引入依赖 <dependency> < ...
- Spring Boot集成Jasypt安全框架
Jasypt安全框架提供了Spring的集成,主要是实现 PlaceholderConfigurerSupport类或者其子类. 在Sring 3.1之后,则推荐使用PropertySourcesPl ...
- Spring boot集成swagger2
一.Swagger2是什么? Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件. Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格 ...
- Spring Boot 集成 Swagger,生成接口文档就这么简单!
之前的文章介绍了<推荐一款接口 API 设计神器!>,今天栈长给大家介绍下如何与优秀的 Spring Boot 框架进行集成,简直不能太简单. 你所需具备的基础 告诉你,Spring Bo ...
- spring boot 集成 zookeeper 搭建微服务架构
PRC原理 RPC 远程过程调用(Remote Procedure Call) 一般用来实现部署在不同机器上的系统之间的方法调用,使得程序能够像访问本地系统资源一样,通过网络传输去访问远程系统资源,R ...
随机推荐
- 用c语言打印一个三角形
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h&g ...
- [javascript] 编写一个计算器,实现加减法
1.代码 <script> function sum(){ //加法 var value1 = document.getElementById("num1").valu ...
- PHP 向数组头部插入数据
PHP 向数组头部插入数据 函数: array_unshift() 示例: $s = array('a' => 0, 'b' => 3); array_unshift($s, '5'); ...
- ArcGIS API For Javascript:热力图不同级别下的优化方法
我们在地图缩放的不同级别下,热力图的显示效果会不同,由于点密度与模糊参数默认是固定的,因此需要对参数进行动态修改,以满足不同缩放级别下可以得到较好的显示效果. 思路是监听地图缩放级别,将地图缩放级别作 ...
- 机器学习 TensorFlow 实现智能鉴黄
前言 最近在做一款图床服务,关注公号的小伙伴一定记得小柒曾说过,会在周末放出的,不好意思放大家鸽子了.之所以一直没敢放出,是因为鉴黄接口一直没调试好,虽然我对公号的小伙伴百分之百信任,奈何互联网鱼龙混 ...
- 使用sklearn和caffe进行逻辑回归 | Brewing Logistic Regression then Going Deeper
原文首发于个人博客https://kezunlin.me/post/c50b0018/,欢迎阅读! Brewing Logistic Regression then Going Deeper. Bre ...
- 【原创】(十二)Linux内存管理之vmap与vmalloc
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- 【前端】之jQuery基础知识
jQuery 简介 在项目中引入jQuery: 去jQuery官网下载jQuery包:jquery-3.2.1.min.js 将下载的jQuery包添加到项目目录中 在标签下添加jQuery引用:&l ...
- python加载csv数据
入门机器学习时,一些测试数据是网络上的csv文件.这里总结了两种加载csv文件的方式: 1 通过numpy.urllib2加载 import numpy as np import urllib2 ur ...
- Python高级用法
Python高级用法 三元表达式 x = 10 y = 20 print(x if x > y else y) x = 100 y = 20 print(x if x > y else y ...