测试场景:直连设备(IotProductDeviceTypeEnum 的 DIRECT 类型)通过 UDP 协议直接连接平台 + * + *
使用步骤: + *
注意:UDP 协议是无状态的,每次请求需要在 params 中携带 token(与 HTTP 通过 Header 传递不同)
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+public class IotDirectDeviceUdpProtocolIntegrationTest {
+
+ private static final String SERVER_HOST = "127.0.0.1";
+ private static final int SERVER_PORT = 8093;
+ private static final int TIMEOUT_MS = 5000;
+
+ // ===================== 直连设备信息(根据实际情况修改,从 iot_device 表查询子设备) =====================
+ private static final String PRODUCT_KEY = "4aymZgOTOOCrDKRT";
+ private static final String DEVICE_NAME = "small";
+ private static final String DEVICE_SECRET = "0baa4c2ecc104ae1a26b4070c218bdf3";
+
+ /**
+ * 直连设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里
+ */
+ private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9kdWN0S2V5IjoiNGF5bVpnT1RPT0NyREtSVCIsImV4cCI6MTc2OTk0ODYzOCwiZGV2aWNlTmFtZSI6InNtYWxsIn0.TrOJisXhloZ3quLBOAIyowmpq6Syp9PHiEpfj-nQ9xo";
+
+ // ===================== 认证测试 =====================
+
+ /**
+ * 认证测试:获取设备 Token
+ */
+ @Test
+ public void testAuth() throws Exception {
+ // 1.1 构建请求
+ IotDeviceAuthReqDTO authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET);
+ IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()
+ .setClientId(authInfo.getClientId())
+ .setUsername(authInfo.getUsername())
+ .setPassword(authInfo.getPassword());
+ String payload = JsonUtils.toJsonString(MapUtil.builder()
+ .put("id", IdUtil.fastSimpleUUID())
+ .put("method", "auth")
+ .put("params", authReqDTO)
+ .build());
+ // 1.2 输出请求
+ log.info("[testAuth][请求体: {}]", payload);
+
+ // 2.1 发送请求
+ try (DatagramSocket socket = new DatagramSocket()) {
+ socket.setSoTimeout(TIMEOUT_MS);
+ String response = sendAndReceive(socket, payload);
+ // 2.2 输出结果
+ log.info("[testAuth][响应体: {}]", response);
+ log.info("[testAuth][请将返回的 token 复制到 TOKEN 常量中]");
+ }
+ }
+
+ // ===================== 直连设备属性上报测试 =====================
+
+ /**
+ * 属性上报测试
+ */
+ @Test
+ public void testPropertyPost() throws Exception {
+ // 1.1 构建请求(UDP 协议:token 放在 params 中)
+ String payload = JsonUtils.toJsonString(MapUtil.builder()
+ .put("id", IdUtil.fastSimpleUUID())
+ .put("method", IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod())
+ .put("version", "1.0")
+ .put("params", withToken(IotDevicePropertyPostReqDTO.of(MapUtil.
+ * 使用产品密钥(productSecret)验证身份,成功后返回设备密钥(deviceSecret)
+ *
+ * 注意:此接口不需要 Token 认证
+ */
+ @Test
+ public void testDeviceRegister() throws Exception {
+ // 1.1 构建请求参数
+ IotDeviceRegisterReqDTO reqDTO = new IotDeviceRegisterReqDTO();
+ reqDTO.setProductKey(PRODUCT_KEY);
+ reqDTO.setDeviceName("test-" + System.currentTimeMillis());
+ reqDTO.setProductSecret("test-product-secret");
+ // 1.2 构建请求
+ String payload = JsonUtils.toJsonString(MapUtil.builder()
+ .put("id", IdUtil.fastSimpleUUID())
+ .put("method", IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod())
+ .put("params", reqDTO)
+ .build());
+ // 1.3 输出请求
+ log.info("[testDeviceRegister][请求体: {}]", payload);
+
+ // 2.1 发送请求
+ try (DatagramSocket socket = new DatagramSocket()) {
+ socket.setSoTimeout(TIMEOUT_MS);
+ String response = sendAndReceive(socket, payload);
+ // 2.2 输出结果
+ log.info("[testDeviceRegister][响应体: {}]", response);
+ log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]");
+ }
+ }
+
+ // ===================== 辅助方法 =====================
+
+ /**
+ * 将 token 添加到 params 中
+ *
+ * 支持 Map 或普通对象,通过 JSON 转换统一处理
+ *
+ * @param params 原始参数(Map 或对象)
+ * @return 添加了 token 的 Map
+ */
+ @SuppressWarnings("unchecked")
+ private Map 使用步骤:
- *
- *
- *
- * @author 芋道源码
- */
-@Slf4j
-public class IotUdpProtocolIntegrationTest {
-
- private static final String SERVER_HOST = "127.0.0.1";
- private static final int SERVER_PORT = 8092;
- private static final int TIMEOUT_MS = 5000;
-
- // 设备信息(根据实际情况修改 PRODUCT_KEY、DEVICE_NAME、PASSWORD)
- private static final String PRODUCT_KEY = "4aymZgOTOOCrDKRT";
- private static final String DEVICE_NAME = "small";
- private static final String PASSWORD = "509e2b08f7598eb139d276388c600435913ba4c94cd0d50aebc5c0d1855bcb75";
-
- // TODO @芋艿:1、IotDeviceAuthUtils 调整下拼接;2、password 的生成;3、后续给 http 也整个单测;4、后续给 tcp 也整个单测;5、后续给 mqtt 也整个单测;6、后续给 emqp 也整个单测
- private static final String CLIENT_ID = PRODUCT_KEY + "." + DEVICE_NAME;
- private static final String USERNAME = DEVICE_NAME + "&" + PRODUCT_KEY;
-
- /**
- * 设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里
- */
- private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9kdWN0S2V5IjoiNGF5bVpnT1RPT0NyREtSVCIsImV4cCI6MTc2OTMxMTY0NiwiZGV2aWNlTmFtZSI6InNtYWxsIn0.re6LCaRfKiE9VQTP3w0Brh2ScVIgrvN3H96z_snndoM";
-
- /**
- * 认证测试:获取设备 Token
- */
- @Test
- public void testAuth() throws Exception {
- String payload = JsonUtils.toJsonString(MapUtil.builder()
- .put("id", IdUtil.fastSimpleUUID())
- .put("method", "auth")
- .put("params", MapUtil.builder()
- .put("clientId", CLIENT_ID)
- .put("username", USERNAME)
- .put("password", PASSWORD)
- .build())
- .build());
-
- try (DatagramSocket socket = new DatagramSocket()) {
- socket.setSoTimeout(TIMEOUT_MS);
-
- log.info("[testAuth][请求体: {}]", payload);
-
- String response = sendAndReceive(socket, payload);
-
- log.info("[testAuth][响应体: {}]", response);
- log.info("[testAuth][请将返回的 token 复制到 TOKEN 常量中]");
- }
- }
-
- /**
- * 属性上报测试
- */
- @Test
- public void testPropertyPost() throws Exception {
- String payload = JsonUtils.toJsonString(MapUtil.builder()
- .put("id", IdUtil.fastSimpleUUID())
- .put("method", IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod())
- .put("version", "1.0")
- .put("params", MapUtil.builder()
- .put("token", TOKEN)
- .put("width", 1)
- .put("height", "2")
- .build())
- .build());
-
- try (DatagramSocket socket = new DatagramSocket()) {
- socket.setSoTimeout(TIMEOUT_MS);
-
- log.info("[testPropertyPost][请求体: {}]", payload);
-
- String response = sendAndReceive(socket, payload);
-
- log.info("[testPropertyPost][响应体: {}]", response);
- }
- }
-
- /**
- * 事件上报测试
- */
- @Test
- public void testEventPost() throws Exception {
- String payload = JsonUtils.toJsonString(MapUtil.builder()
- .put("id", IdUtil.fastSimpleUUID())
- .put("method", IotDeviceMessageMethodEnum.EVENT_POST.getMethod())
- .put("version", "1.0")
- .put("params", MapUtil.builder()
- .put("identifier", "eat")
- .put("value", MapUtil.builder()
- .put("width", 1)
- .put("height", "2")
- .put("oneThree", "3")
- .build())
- .put("time", System.currentTimeMillis())
- .build())
- .build());
-
- try (DatagramSocket socket = new DatagramSocket()) {
- socket.setSoTimeout(TIMEOUT_MS);
-
- log.info("[testEventPost][请求体: {}]", payload);
-
- String response = sendAndReceive(socket, payload);
-
- log.info("[testEventPost][响应体: {}]", response);
- }
- }
-
- /**
- * 发送 UDP 请求并接收响应
- *
- * @param socket UDP Socket
- * @param payload 请求体
- * @return 响应内容
- */
- private String sendAndReceive(DatagramSocket socket, String payload) throws Exception {
- byte[] sendData = payload.getBytes(StandardCharsets.UTF_8);
- InetAddress address = InetAddress.getByName(SERVER_HOST);
-
- // 发送请求
- DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, address, SERVER_PORT);
- socket.send(sendPacket);
-
- // 接收响应
- byte[] receiveData = new byte[4096];
- DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
- try {
- socket.receive(receivePacket);
- return new String(receivePacket.getData(), 0, receivePacket.getLength(), StandardCharsets.UTF_8);
- } catch (java.net.SocketTimeoutException e) {
- log.warn("[sendAndReceive][接收响应超时]");
- return null;
- }
- }
-
-}