diff --git a/pom.xml b/pom.xml
index 1dafe18..35c55fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -114,6 +114,16 @@
jackson-annotations
2.21
+
+ com.google.code.gson
+ gson
+ 2.14.0
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ 2.0.62
+
diff --git a/src/main/java/com/aeon/tcp/config/DataCenterEnvConfig.java b/src/main/java/com/aeon/tcp/config/DataCenterEnvConfig.java
new file mode 100644
index 0000000..57fa55f
--- /dev/null
+++ b/src/main/java/com/aeon/tcp/config/DataCenterEnvConfig.java
@@ -0,0 +1,118 @@
+package com.aeon.tcp.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 系统配置
+ * */
+
+@Configuration
+public class DataCenterEnvConfig {
+
+
+ private String receiveUrl;
+
+ @Value("${data.center.receive.address}")
+ private String apiAddress;
+
+ @Value("${data.center.receive.api:#{'/v1/main_receiver'}}")
+ private String apiUrl;
+
+ @Value("${data.center.process.api:#{'/v1/generic/process'}}")
+ private String processApiUrl;
+
+ @Value("${data.center.ioserver_process.api:#{'/v1/generic/ioserver_process'}}")
+ private String processIoserverUrl;
+
+ @Value("${data.center.trendLog.api:#{'/v1/generic/trendlog_process'}}")
+ private String processTrendLogUrl;
+
+ @Value("${data.center.st150_process.api:#{'/v1/generic/st150_process'}}")
+ private String processGW150Url;
+
+ @Value("${data.center.zaiot_process.api:#{'/v1/generic/zaiot_process'}}")
+ private String zaiotProcessApiUrl;
+
+ @Value("${data.center.f10.api:#{'/v1/generic/f10'}}")
+ private String f10ApiUrl;
+
+ @Value("${data.center.csdj.api:#{'/v1/generic/csdj'}}")
+ private String csdjApiUrl;
+
+
+ public String getReceiveUrl() {
+ return apiAddress+apiUrl;
+ }
+
+ public void setReceiveUrl(String receiveUrl) {
+ this.receiveUrl = receiveUrl;
+ }
+
+ public String getApiAddress() {
+ return apiAddress;
+ }
+
+ public void setApiAddress(String apiAddress) {
+ this.apiAddress = apiAddress;
+ }
+
+ public String getApiUrl() {
+ return apiUrl;
+ }
+
+ public void setApiUrl(String apiUrl) {
+ this.apiUrl = apiUrl;
+ }
+
+ public String getProcessApiUrl() {
+ return apiAddress+processApiUrl;
+ }
+
+ public void setProcessApiUrl(String processApiUrl) {
+ this.processApiUrl = processApiUrl;
+ }
+
+ public String getProcessIoserverUrl() {
+ return apiAddress+processIoserverUrl;
+ }
+
+ public void setProcessTrendUrl(String processTrendLogUrl) {
+ this.processTrendLogUrl = processTrendLogUrl;
+ }
+ public String getProcessTrendLogUrl() {
+ return apiAddress+processTrendLogUrl;
+ }
+
+ public void setProcessIoserverUrl(String processIoserverUrl) {
+ this.processIoserverUrl = processIoserverUrl;
+ }
+
+ public String getZaiotProcessApiUrl() {
+ return apiAddress+zaiotProcessApiUrl;
+ }
+
+ public void setZaiotProcessApiUrl(String zaiotProcessApiUrl) {
+ this.zaiotProcessApiUrl = zaiotProcessApiUrl;
+ }
+
+ public String getProcessGW150Url() {
+ return processGW150Url;
+ }
+
+ public void setProcessGW150Url(String processGW150Url) {
+ this.processGW150Url = processGW150Url;
+ }
+
+ public String getGW150ProcessUrl() {
+ return apiAddress+this.processGW150Url;
+ }
+
+ public String getF10ApiUrl() {
+ return apiAddress+f10ApiUrl;
+ }
+
+ public String getCsdjApiUrl() {
+ return apiAddress+csdjApiUrl;
+ }
+}
diff --git a/src/main/java/com/aeon/tcp/config/RedisConfig.java b/src/main/java/com/aeon/tcp/config/RedisConfig.java
new file mode 100644
index 0000000..b0759fc
--- /dev/null
+++ b/src/main/java/com/aeon/tcp/config/RedisConfig.java
@@ -0,0 +1,36 @@
+package com.aeon.tcp.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+
+@Configuration
+public class RedisConfig {
+
+ @Bean
+ public RedisTemplate redisTemplate(
+ RedisConnectionFactory connectionFactory) {
+
+ RedisTemplate template = new RedisTemplate<>();
+
+ template.setConnectionFactory(connectionFactory);
+
+ // key 使用 String
+ template.setKeySerializer(new StringRedisSerializer());
+ template.setHashKeySerializer(new StringRedisSerializer());
+
+ // value 使用 Json
+ GenericJackson2JsonRedisSerializer serializer =
+ new GenericJackson2JsonRedisSerializer();
+
+ template.setValueSerializer(serializer);
+ template.setHashValueSerializer(serializer);
+
+ template.afterPropertiesSet();
+
+ return template;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/aeon/tcp/controller/CsdjDownlinkController.java b/src/main/java/com/aeon/tcp/controller/CsdjDownlinkController.java
new file mode 100644
index 0000000..1df3a8a
--- /dev/null
+++ b/src/main/java/com/aeon/tcp/controller/CsdjDownlinkController.java
@@ -0,0 +1,80 @@
+package com.aeon.tcp.controller;
+
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@RestController
+@RequestMapping("/csdj/downlink")
+@RequiredArgsConstructor
+public class CsdjDownlinkController {
+
+ private static final String DOWNLINK_KEY_PREFIX = "csdj:downlink:";
+
+ private final RedisTemplate redisTemplate;
+
+ @PostMapping("/task")
+ public Map createTask(@RequestBody DownlinkTaskRequest request) {
+ String payloadHex = normalizeHex(request.getPayloadHex());
+ String key = DOWNLINK_KEY_PREFIX + request.getTerminalId();
+
+ redisTemplate.opsForList().rightPush(key, payloadHex);
+ Long count = redisTemplate.opsForList().size(key);
+
+ Map result = new HashMap<>();
+ result.put("success", true);
+ result.put("terminalId", request.getTerminalId());
+ result.put("payloadHex", payloadHex);
+ result.put("pendingCount", count);
+ result.put("message", "success");
+ log.info("添加下行任务,terminalId={}, payloadHex={}, pendingCount={}", request.getTerminalId(), payloadHex, count);
+ return result;
+ }
+
+ @GetMapping("/pending/{terminalId}")
+ public Map getPendingTasks(@PathVariable String terminalId) {
+ String key = DOWNLINK_KEY_PREFIX + terminalId;
+ List