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 ...
随机推荐
- Centos7編譯安裝LAMP平臺
什麽是LAMP? 拆開看 L 就是Linux系統 A是Apache的縮寫 M.P則是MySQL和PHP的简写. 其实就是把Apache, MySQL以及PHP安装在Linux系统上,组成一个环境来运行 ...
- vue cli3.0 封装组件全局引入js文件并发布到npm
首先用 vue create创建一个项目 当前的项目目录是这样的: 首先需要创建一个 packages 目录,用来存放组件 然后将 src 目录改为 examples 用作示例 二.修改配置 启动项目 ...
- C# 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”
“Microsoft.Jet.OLEDB.4.0” 是数据库接口驱动,用来连接数据库的,一般多用于连Access和Excel.我在在winform开发时,在本地运行没有问题,可是部署到另一台服务器上就 ...
- GDG Xi'an DevFest 2019 闪电演讲 -《假如我是一个浏览器》PPT(经典多图,建议收藏)
GDG Xi'an DevFest2019演讲PPT链接: http://tmp.link/f/5dd9e6bf461b6 闪电演讲<假如我是一个浏览器>PPT链接: https://gi ...
- 【Elasticsearch 7 探索之路】(四)Analyzer 分析
上一篇,什么是倒排索引以及原理是什么.本篇讲解 Analyzer,了解 Analyzer 是什么 ,分词器是什么,以及 Elasticsearch 内置的分词器,最后再讲解中文分词是怎么做的. 一.A ...
- OpenStack集成ceph
openstack组件集成ceph OpenStack集成ceph详细过程可以查看ceph官方文档:ceph document OpenStack Queens版本,1台控制节点controller, ...
- java的回调和C#的委托
曾经有人对我说java的回调很巧妙. 今天我自己看了一下,回调的关键就是一个接口的事情. 也许是因为用了一定的手法,一开始不好懂吧,所以看懂了会感觉巧妙. 但是我心里的想法却是,真啰嗦! 回调的实例 ...
- day 30 多线程 socketserver模块补充
内容回顾: socket 模块 服务端:收发数据 - > accept/recv 客户端:收发数据 -> connect/recv 1. 考试题 1. 解释性和编译型 编译型: 先把代码编 ...
- CSS中如果实现元素浮动,看这篇文章就足够了
浮动基本介绍 在标准文档流中元素分为2种,块级元素和行内元素,如果想让一些元素既要有块级元素的特点也同时保留行内元素特点,只能让这些元素脱离标准文档流即可. 浮动可以让元素脱离标准文档流,可以实现让多 ...
- Linux上ES单机版安装
设置 IP 地址 vi /etc/sysconfig/network-scripts/ifcfg-ens32 重启网卡 [root@localhost ~] systemctl restart n ...