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 ...
随机推荐
- 领扣(LeetCode)有效的括号 个人题解
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空字符串可被认 ...
- ubuntu server 1604 配置网络信息
对于新安装的linux 服务器(ubuntu server 1604) 一,配置网络 连接网线与路由器 查看系统的网卡信息 ifconfig -a //列出所有的网卡信息,不管启用还是没有启用的 ...
- PostGIS 爆管分析之根据爆点找出所有影响阀门
环境: Win10 ArcMap10.4(用于数据处理) postgresql9.4 postgis2.2.3 pgRouting2.3(postgresql插件) 说明: 做爆管分析的第一步,需要先 ...
- RxJS入门
一.RxJS是什么? 官方文档使用了一句话总结RxJS: Think of RxJS as Lodash for events.那么Lodash主要解决了什么问题?Lodash主要集成了一系列关于数组 ...
- [译]Nginx入门引导教程
本文为[Beginner's Guide]译文,原文地址:http://nginx.org/en/docs/beginners_guide.html Guide 本教程基础的介绍了 nginx,以及能 ...
- 使用zuul实现验证自定义请求头中的token
路由:她会把外部所有对请求转发到具体的微服务实例上,是实现外部访问同一接口的基础 过滤: 就是权限的检查, 判断当前的请求是否有权限区访问那些服务集群 搭建后台网关: 导入eureka - clien ...
- linux 进程简介
进程相关知识简介 进程定义: 一个运行中的程序即一个process task struct: 内核存储进程信息的固定格式称为task struct,task struct记录了例如该进程内存下一跳位置 ...
- day 31 网络基础的补充
一.网络基础 1.端口 - 端口,是什么?为什么要有? 端口是为了将同一个电脑上的不同程序进行隔离. IP是找电脑 端口是找电脑上的程序 示例: MySQL是一个软件,软件帮助我们在硬盘上进行文件操作 ...
- Glibc编译报错:*** These critical programs are missing or too old: as ld gcc
Binutils版本升级 这里是binutils版本过低导致, 查看已部署版本 上传离线升级包 [root@sdw1 glibc]# tar -zxvf binutils-2.32.tar.gz [r ...
- vue下谷歌浏览器的扩展程序(vue-devtools-master)
1,在百度网盘中下载压缩包,网盘地址:https://pan.baidu.com/s/1BnwWHANHNyJzG3Krpy7S8A ,密码:xm6s 2,将压缩包解压到F盘,F:\chromeVue ...