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 ...
随机推荐
- 一.web服务机制
web服务机制 我们先跟着**(Web服务器工作原理总体描述01)这张图,将一次Web服务的工作流程过一遍,我们假设以浏览器作为客户端(1) 用户做出了一个操作,可以是填写网址敲回车,可以是点击链接, ...
- Python3.7.1学习(一):redis的连接和简单使用
1.python 利用 redis 第三方库 首先安装:pip install redis 2.reids的连接 Redis使用StrictRedis对象来管理对一个redis server 的所有连 ...
- 官网例子,mt-field password获取不到
新尝试了Mint-UI,在使用表单组件Field时, 直接从demo中拷贝了如下代码: <mt-field label="username" placeholder=&quo ...
- W5500设计方案
W5500是韩国一款集成全硬件 TCP/IP 协议栈的嵌入式以太网控制器,W5500同时也是一颗工业级以太网控制芯片,最近发现我们国内也有和W5500 芯片一样芯片 介绍给大家 如下图:
- PostGIS 爆管分析之找出总阀门
这个算法算是被摒弃了,但是很多自己思考过后留下的成果,虽然不用了,留着做记录. 算法目的是为了发生爆管后找到总阀门,这里分了几个步骤: 1.找到爆管点所在管段 2.通过遍历找到爆管点所有影响的阀门 3 ...
- Mybaits学习总结
一.Mybatis介绍 邮箱:1727292697 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的 ...
- tensorflow学习笔记——模型持久化的原理,将CKPT转为pb文件,使用pb模型预测
由题目就可以看出,本节内容分为三部分,第一部分就是如何将训练好的模型持久化,并学习模型持久化的原理,第二部分就是如何将CKPT转化为pb文件,第三部分就是如何使用pb模型进行预测. 一,模型持久化 为 ...
- Scala学习笔记三
scala变量理解: package com.cxy.scala object Hello { def main(args: Array[String]): Unit = { println(&quo ...
- 使用scrapy-redis搭建分布式爬虫环境
scrapy-redis简介 scrapy-redis是scrapy框架基于redis数据库的组件,用于scrapy项目的分布式开发和部署. 有如下特征: 分布式爬取 您可以启动多个spider工 ...
- Android最大方法数和解决方案
转载请标明出处:http://blog.csdn.net/shensky711/article/details/52329035 本文出自: [HansChen的博客] 什么是64K限制和Linear ...