阿里云物联网平台云端采用AMQP方式接入同时订阅与发布消息

工业互联网需要采集设备底层数据进行实时数据展示与状态预警,由于底层硬件设备无法采用http等重量级请求发送数据,工业上常常采用MQTT协议进行数据传输,本次基于阿里云物联网平台进行数据采集,本次主要云端收集信息与数据下发,云端采用AMQP方式接入,该方式使得云端服务同时具体发布与订阅功能;设备端采用阿里云IOT平台MQTT.fx模拟接入
环境:JDK1.8+maven+springboot
GitHub源码地址:https://github.com/hou296498161/amqp
1.添加以下依赖

org.springframework.boot
spring-boot-starter-web


com.aliyun
aliyun-java-sdk-core
3.7.1


com.aliyun
aliyun-java-sdk-iot
6.11.0


org.msgpack
msgpack
0.6.12



commons-codec
commons-codec
1.10


org.apache.qpid
qpid-jms-client
0.47.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1)、阿里云创建产品,定义自定义topic,类型为发布订阅
2)、创建产品、
3)、创建服务端订阅
在这里插入图片描述

2、服务端订阅消息
package com.ali.amqp.subscribe;

import org.apache.commons.codec.binary.Base64;
import org.apache.qpid.jms.JmsConnection;
import org.apache.qpid.jms.JmsConnectionListener;
import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.net.URI;
import java.util.Hashtable;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**

  • 云端订阅消息
    */
    public class AmqpJavaClient {

    private final static Logger logger = LoggerFactory.getLogger(AmqpJavaClient.class);
    //业务处理异步线程池,线程池参数可以根据您的业务特点调整;或者您也可以用其他异步方式处理接收到的消息
    private final static ExecutorService executorService = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors(),
    Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(50000));
    public static void subscribe() throws Exception {
    //参数说明参见阿里云文档:AMQP客户端接入说明。
    String accessKey = “你的阿里云accessKey”;
    String accessSecret = “你的阿里云 accessSecret”;
    //消费组ID
    String consumerGroupId = “DEFAULT_GROUP”;
    long timeStamp = System.currentTimeMillis();
    //签名方法:支持hmacmd5,hmacsha1和hmacsha256
    String signMethod = “hmacsha1”;
    //控制台服务端订阅中消费组状态页客户端ID一栏将显示clientId参数。
    //建议使用机器UUID、MAC地址、IP等唯一标识等作为clientId。便于您区分识别不同的客户端。
    String clientId = UUID.randomUUID().toString().replaceAll("-","");

     //UserName组装方法,请参见阿里云文档:AMQP客户端接入说明。
     String userName = clientId + "|authMode=aksign"
             + ",signMethod=" + signMethod
             + ",timestamp=" + timeStamp
             + ",authId=" + accessKey
             + ",consumerGroupId=" + consumerGroupId
             + "|";
     //password组装方法,请参见上一篇文档:AMQP客户端接入说明。
     String signContent = "authId=" + accessKey + "&timestamp=" + timeStamp;
     String password = doSign(signContent,accessSecret, signMethod);
     //按照qpid-jms的规范,组装连接URL。
     String connectionUrl = "failover:(amqps://1090243284576461.iot-amqp.cn-shanghai.aliyuncs.com:5671?amqp.idleTimeout=80000)"
             + "?failover.reconnectDelay=30";
     Hashtable<String, String> hashtable = new Hashtable<>();
     hashtable.put("connectionfactory.SBCF",connectionUrl);
     hashtable.put("queue.QUEUE", "default");
     hashtable.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
     Context context = new InitialContext(hashtable);
     ConnectionFactory cf = (ConnectionFactory)context.lookup("SBCF");
     Destination queue = (Destination)context.lookup("QUEUE");
     // Create Connection
     Connection connection = cf.createConnection(userName, password);
     ((JmsConnection) connection).addConnectionListener(myJmsConnectionListener);
    
     // Create Session
     // Session.CLIENT_ACKNOWLEDGE: 收到消息后,需要手动调用message.acknowledge()
     // Session.AUTO_ACKNOWLEDGE: SDK自动ACK(推荐)
     Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
     connection.start();
     // Create Receiver Link
     MessageConsumer consumer = session.createConsumer(queue);
     consumer.setMessageListener(messageListener);
    

    }

    private static MessageListener messageListener = new MessageListener() {
    @Override
    public void onMessage(Message message) {
    try {
    if (message.getBody(byte[].class)==null){
    logger.error(“收到一条空的消息,topic->{}”,message.getStringProperty(“topic”));
    }else {
    logger.info(“收到消息:topic->{}:{}”,message.getStringProperty(“topic”),new String(message.getBody(byte[].class)));
    }
    //1.收到消息之后一定要ACK
    // 推荐做法:创建Session选择Session.AUTO_ACKNOWLEDGE,这里会自动ACK。
    // 其他做法:创建Session选择Session.CLIENT_ACKNOWLEDGE,这里一定要调message.acknowledge()来ACK。
    // message.acknowledge();
    //2.建议异步处理收到的消息,确保onMessage函数里没有耗时逻辑。
    // 如果业务处理耗时过程过长阻塞住线程,可能会影响SDK收到消息后的正常回调。

             executorService.submit(() ->System.out.println(""));
         } catch (Exception e) {
             logger.error("submit task occurs exception ", e);
         }
     }
    

    };

    private static JmsConnectionListener myJmsConnectionListener = new JmsConnectionListener() {
    /**
    * 连接成功建立
    */
    @Override
    public void onConnectionEstablished(URI remoteURI) {
    logger.info(“onConnectionEstablished, remoteUri:{}”, remoteURI);
    }

     /**
      * 尝试过最大重试次数之后,最终连接失败。
      */
     @Override
     public void onConnectionFailure(Throwable error) {
         logger.error("onConnectionFailure, {}", error.getMessage());
     }
    
     /**
      * 连接中断。
      */
     @Override
     public void onConnectionInterrupted(URI remoteURI) {
         logger.info("onConnectionInterrupted, remoteUri:{}", remoteURI);
     }
    
     /**
      * 连接中断后又自动重连上。
      */
     @Override
     public void onConnectionRestored(URI remoteURI) {
         logger.info("onConnectionRestored, remoteUri:{}", remoteURI);
     }
    
     @Override
     public void onInboundMessage(JmsInboundMessageDispatch envelope) {}
    
     @Override
     public void onSessionClosed(Session session, Throwable cause) {}
    
     @Override
     public void onConsumerClosed(MessageConsumer consumer, Throwable cause) {}
    
     @Override
     public void onProducerClosed(MessageProducer producer, Throwable cause) {}
    

    };

    /**

    • password签名计算方法,请参见阿里云文档:AMQP客户端接入说明。
      */
      private static String doSign(String toSignString, String secret, String signMethod) throws Exception {
      SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), signMethod);
      Mac mac = Mac.getInstance(signMethod);
      mac.init(signingKey);
      byte[] rawHmac = mac.doFinal(toSignString.getBytes());
      return Base64.encodeBase64String(rawHmac);
      }
      }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
3服务端发布
package com.ali.amqp.publish;

import com.ali.amqp.subscribe.AmqpJavaClient;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.iot.model.v20180120.PubRequest;
import com.aliyuncs.iot.model.v20180120.PubResponse;
import com.aliyuncs.profile.DefaultProfile;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;

/**

  • 云端下发消息
    */
    public class PopPubServer {
    private final static Logger logger = LoggerFactory.getLogger(PopPubServer.class);

    public static boolean sendToTopic(String topic) throws UnsupportedEncodingException {
    String regionId = “cn-shanghai”;
    String accessKey = “你的accessKey”;
    String accessSecret = “你的accessSecret”;
    final String productKey = “设备productKey”;
    //设置client的参数
    DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKey, accessSecret);
    IAcsClient autoClient = new DefaultAcsClient(profile);
    PubRequest request = new PubRequest();
    request.setQos(0);
    //设置发布消息的topic
    request.setTopicFullName("/a14UPaWxJCF/test_device/user/test");
    request.setProductKey(productKey);
    //设置消息的内容,一定要用base64编码,否则乱码
    Base64 base64 = new Base64();
    request.setMessageContent(base64.encodeToString(“hello”.getBytes(“UTF-8”)));
    try {
    PubResponse response = autoClient.getAcsResponse(request);
    Boolean success = response.getSuccess();
    return success;
    } catch (Exception e) {
    logger.warn(“阿里云消息发送异常,topic:{},异常信息:{}”,topic,e.getMessage());
    return false;
    }
    }
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用阿里云提供的Java SDK来实现与AMQP服务器建立长连接。以下是一个简单的示例: 1. 添加依赖 在pom.xml中添加以下依赖: ``` <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-amqp</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> ``` 2. 配置AMQP连接参数 在application.properties中配置AMQP连接参数: ``` spring.rabbitmq.host=amqp://xxxxx.mq-amqp.cn-shanghai-a.aliyuncs.com spring.rabbitmq.username=xxxxx spring.rabbitmq.password=xxxxx ``` 3. 编写AMQP客户端代码 在Spring Boot应用程序中,可以使用@RabbitListener注释来创建AMQP客户端。以下是一个简单的示例: ``` @Configuration @EnableRabbit public class AmqpConfig { @Bean public ConnectionFactory connectionFactory() { CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); connectionFactory.setHost(environment.getProperty("spring.rabbitmq.host")); connectionFactory.setUsername(environment.getProperty("spring.rabbitmq.username")); connectionFactory.setPassword(environment.getProperty("spring.rabbitmq.password")); return connectionFactory; } @Bean public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames("amqp.queue.example"); container.setMessageListener(new MessageListenerAdapter(new AmqpMessageHandler())); return container; } public static class AmqpMessageHandler { // 处理接收到的消息 public void handleMessage(String message) { System.out.println("Received message: " + message); } } } ``` 在上面的代码中,我们定义了一个名为messageListenerContainer的消息监听器容器。该容器使用我们在步骤2中配置的连接工厂和队列名称。消息监听器是一个简单的处理程序,它将打印接收到的消息。 4. 启动应用程序 现在,我们可以启动应用程序并开始接收来自AMQP服务器的消息。当应用程序启动时,它将建立一个长连接并开始监听队列。如果接收到新消息,它将调用我们在步骤3中定义的消息处理程序。 ``` @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值