فهرست منبع

1、增加、删除、修改逻辑调整;2、配置文件调整,后期打包可直接修改对应的配置文件,无需再去对应代码行修改。

pc147123 4 ماه پیش
والد
کامیت
df6e184ccf
27فایلهای تغییر یافته به همراه1072 افزوده شده و 467 حذف شده
  1. 6 0
      pom.xml
  2. 1 2
      src/main/java/com/example/unusualsounds/UnusualSoundsApplication.java
  3. 6 0
      src/main/java/com/example/unusualsounds/common/constant/HttpStatus.java
  4. 58 0
      src/main/java/com/example/unusualsounds/common/utils/ResponseObj.java
  5. 129 13
      src/main/java/com/example/unusualsounds/common/utils/VoiceAnalysisUtils.java
  6. 160 0
      src/main/java/com/example/unusualsounds/common/utils/WebUtils.java
  7. 0 3
      src/main/java/com/example/unusualsounds/framework/minio/MinioConfig.java
  8. 11 0
      src/main/java/com/example/unusualsounds/framework/minio/MinioUtil.java
  9. 90 59
      src/main/java/com/example/unusualsounds/project/device/controller/SensorsController.java
  10. 3 0
      src/main/java/com/example/unusualsounds/project/device/entity/vo/RegisterSoundSensors.java
  11. 1 0
      src/main/java/com/example/unusualsounds/project/device/entity/vo/SoundSensorsQueryVo.java
  12. 23 8
      src/main/java/com/example/unusualsounds/project/device/service/DevicesSoundSensorsService.java
  13. 257 59
      src/main/java/com/example/unusualsounds/project/device/service/impl/DevicesSoundSensorsServiceImpl.java
  14. 192 256
      src/main/java/com/example/unusualsounds/project/vox/config/VideoTaskManager.java
  15. 2 2
      src/main/java/com/example/unusualsounds/project/vox/controller/CheckVoxController.java
  16. 2 2
      src/main/java/com/example/unusualsounds/project/vox/entity/Alarms.java
  17. 17 0
      src/main/java/com/example/unusualsounds/project/vox/entity/DevicesSoundSensorsList.java
  18. 3 0
      src/main/java/com/example/unusualsounds/project/vox/service/impl/AlarmReportsServiceImpl.java
  19. 13 3
      src/main/java/com/example/unusualsounds/project/vox/service/impl/AlarmsServiceImpl.java
  20. 11 8
      src/main/java/com/example/unusualsounds/project/vox/service/impl/EdgeOrganizationServiceImpl.java
  21. 2 5
      src/main/java/com/example/unusualsounds/project/vox/service/impl/VideoServiceImpl.java
  22. 1 1
      src/main/java/com/example/unusualsounds/project/vox/task/TicketsTask.java
  23. 20 13
      src/main/resources/application-dev.yml
  24. 6 7
      src/main/resources/application-edge.yml
  25. 15 8
      src/main/resources/application-prod.yml
  26. 9 10
      src/main/resources/application-test.yml
  27. 34 8
      src/test/java/com/example/unusualsounds/UnusualSoundsApplicationTests.java

+ 6 - 0
pom.xml

@@ -24,9 +24,15 @@
         <fastjson.version>2.0.28</fastjson.version>
         <mybatis-plus-extension>3.3.0</mybatis-plus-extension>
         <hutool.version>5.8.16</hutool.version>
+        <beanutils.version>1.9.4</beanutils.version>
     </properties>
     <dependencies>
 
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>${beanutils.version}</version>
+        </dependency>
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
             <artifactId>okhttp</artifactId>

+ 1 - 2
src/main/java/com/example/unusualsounds/UnusualSoundsApplication.java

@@ -15,9 +15,8 @@ import org.springframework.web.client.RestTemplate;
 public class UnusualSoundsApplication {
 
     @Autowired
-    //RestTemplateBuilder
     private RestTemplateBuilder builder;
-    // spring默认已经注入了RestTemplateBuilder实例
+
     @Bean
     public RestTemplate restTemplate() {
         return builder.build();

+ 6 - 0
src/main/java/com/example/unusualsounds/common/constant/HttpStatus.java

@@ -89,4 +89,10 @@ public class HttpStatus {
      * 系统警告消息
      */
     public static final int WARN = 601;
+
+
+    /**
+     * 系统内部错误
+     */
+    public static final int ARGUMENT_ERROR = 10001;
 }

+ 58 - 0
src/main/java/com/example/unusualsounds/common/utils/ResponseObj.java

@@ -0,0 +1,58 @@
+package com.example.unusualsounds.common.utils;
+
+import com.alibaba.fastjson2.JSON;
+
+import java.util.Map;
+
+public class ResponseObj<T> {
+
+    private int statusCodeValue = 200;
+    private T body;
+    private String bodyStr;
+    private Map<String, Object> bodyMap;
+
+    public ResponseObj() {
+    }
+
+    public void setStatusCodeValue(int val) {
+        this.statusCodeValue = val;
+    }
+
+    public int getStatusCodeValue() {
+        return this.statusCodeValue;
+    }
+
+    public T getBody() {
+        return this.body;
+    }
+
+    public String getBodyStr() {
+        return this.bodyStr;
+    }
+
+    public Map<String, Object> getBodyMap() {
+        return this.bodyMap;
+    }
+
+    public void setBody(T val) {
+        this.body = val;
+        if (val != null) {
+            this.bodyStr = val.toString();
+            if (val instanceof String) {
+                String valStr = (String)val;
+
+                try {
+                    this.bodyMap = JSON.parseObject(valStr);
+                } catch (Exception var4) {
+                    this.bodyMap = null;
+                }
+            } else if (val instanceof Map) {
+                this.bodyMap = (Map)val;
+            }
+        } else {
+            this.bodyStr = null;
+            this.bodyMap = null;
+        }
+
+    }
+}

+ 129 - 13
src/main/java/com/example/unusualsounds/common/utils/VoiceAnalysisUtils.java

@@ -1,44 +1,160 @@
 package com.example.unusualsounds.common.utils;
 
-import jakarta.annotation.Resource;
-import lombok.extern.java.Log;
-import org.hibernate.validator.constraints.Length;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.example.unusualsounds.project.device.entity.DevicesSoundSensors;
+import com.example.unusualsounds.project.device.entity.vo.RegisterSoundSensors;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.*;
 import org.springframework.stereotype.Component;
 import org.springframework.web.client.RestTemplate;
 
-import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 音频算法分析类
  */
-@Log
+//@Log
 @Component
+@Slf4j
 public final class VoiceAnalysisUtils {
 
     private static RestTemplate restTemplateStatic;
-    @Autowired
-    public void setRestTemplate(RestTemplate restTemplate) {
-        VoiceAnalysisUtils.restTemplateStatic = restTemplate;
-    }
 
-    public static String postVoxAnalysis(Map<String,Object> maps,String postAnalysisUrl){
+    public static String postVoxAnalysis(Map<String, Object> maps, String postAnalysisUrl) {
 
         HttpHeaders httpHeaders = new HttpHeaders();
         httpHeaders.setContentType(MediaType.APPLICATION_JSON);
         HttpEntity<Map<String, Object>> mapHttpEntity = new HttpEntity<>(maps, httpHeaders);
         try {
             ResponseEntity<String> stringResponseEntity = restTemplateStatic.postForEntity(postAnalysisUrl, mapHttpEntity, String.class);
-            if (stringResponseEntity.getStatusCode() == HttpStatus.OK){
+            if (stringResponseEntity.getStatusCode() == HttpStatus.OK) {
                 return "通知算法成功";
             }
             return "通知算法失败";
-        }catch (Exception e){
-            return "发送失败:"+e.getMessage();
+        } catch (Exception e) {
+            return "发送失败:" + e.getMessage();
+        }
+
+    }
+
+    /**
+     * 向中心端发送请求
+     *
+     * @return
+     */
+    // todo ghjghj
+    public static Boolean postCenterSensorsUp(String url, Object obj) {
+        try {
+            Map<String, Object> requestBody = new HashMap<>();
+            ResponseObj responseObj = null;
+
+            HttpHeaders httpHeaders = new HttpHeaders();
+            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+            String jsonList = null;
+            HttpEntity<Map<String, Object>> mapHttpEntity = null;
+            HttpEntity<List<String>> ListHttpEntity = null;
+            ResponseEntity<String> stringResponseEntity = null;
+
+//            if (obj instanceof DevicesSoundSensors) {
+            if (obj instanceof RegisterSoundSensors) {
+                requestBody = JSONObject.parseObject(JSONObject.toJSONString(obj));
+                log.info("requestBody:{}", JSON.toJSONString(requestBody));
+                // todo ghjghj 修改发送请求的函数。
+                url = url.trim();
+                responseObj = WebUtils.sendPostRequest(url, null, null, requestBody, null, 20);
+                log.info("--->add or mod responseObj:{}", JSON.toJSONString(responseObj));
+
+            } else if (obj instanceof List<?>) {
+                // todo ghjghj
+                List<?> list = (List<?>) obj;
+                List<String> collect = list.stream()
+                        .filter(item -> item instanceof String)
+                        .map(item -> (String) item)
+                        .collect(Collectors.toList());
+                log.info("list obj:{}", JSON.toJSONString(collect));
+                responseObj = WebUtils.sendPostRequest(url, null, null, null, collect, 20);
+//                ListHttpEntity = new HttpEntity<>(collect, httpHeaders);
+//                stringResponseEntity = restTemplateStatic.postForEntity(url, mapHttpEntity, String.class);
+                log.info("--->del responseObj:{}", JSON.toJSONString(responseObj));
+
+            }
+            // todo ghjghj
+            if (null != responseObj && StringUtils.isNoneBlank(responseObj.getBody().toString())) {
+                if (responseObj.getBodyMap().get("code").toString().equals("10001")) {
+                    log.info("return false");
+                    return false;
+                }
+                log.info("return true");
+                return true;
+            }
+//            if (stringResponseEntity.getStatusCode() == HttpStatus.OK) {
+//                return true;
+//            }
+            return false;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            log.info("向中心端发送请求异常 ex:{}", ex);
+            return false;
         }
 
     }
 
+    public static Boolean postCenterSensors(String url, Object obj) {
+        try {
+//        Map<String, Object> requestBody = new HashMap<>();
+            Map<String, Object> requestBody = new HashMap<>();
+            HttpHeaders httpHeaders = new HttpHeaders();
+            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+            String jsonList = null;
+            HttpEntity<Map<String, Object>> mapHttpEntity = null;
+            HttpEntity<List<String>> ListHttpEntity = null;
+            ResponseEntity<String> stringResponseEntity = null;
+
+            if (obj instanceof DevicesSoundSensors) {
+                requestBody = JSONObject.parseObject(JSONObject.toJSONString(obj));
+
+//            log.info("---start---:{}", JSON.toJSONString(requestBody));
+//            requestBody.forEach(
+//                    (k,v)->{
+//                        System.out.println(k+":"+v);
+//            }
+//            );
+//            log.info("---end---");
+                mapHttpEntity = new HttpEntity<>(requestBody, httpHeaders);
+                // todo ghjghj 修改发送请求的函数。
+                url = url.trim();
+                ResponseObj responseObj = WebUtils.sendPostRequest(url, null, null, requestBody, null, 20);
+                log.info("--->responseObj:{}", JSON.toJSONString(responseObj));
+//            stringResponseEntity = restTemplateStatic.postForEntity(url, mapHttpEntity, String.class);
+//            log.info("stringResponseEntity:{}",stringResponseEntity.toString());
+            } else if (obj instanceof List<?>) {
+                List<?> list = (List<?>) obj;
+                List<String> collect = list.stream()
+                        .filter(item -> item instanceof String)
+                        .map(item -> (String) item)
+                        .collect(Collectors.toList());
+                ListHttpEntity = new HttpEntity<>(collect, httpHeaders);
+                stringResponseEntity = restTemplateStatic.postForEntity(url, mapHttpEntity, String.class);
+            }
+            if (stringResponseEntity.getStatusCode() == HttpStatus.OK) {
+                return true;
+            }
+            return false;
+        } catch (Exception e) {
+            return false;
+        }
+
+    }
+
+    @Autowired
+    public void setRestTemplate(RestTemplate restTemplate) {
+        VoiceAnalysisUtils.restTemplateStatic = restTemplate;
+    }
+
 }

+ 160 - 0
src/main/java/com/example/unusualsounds/common/utils/WebUtils.java

@@ -0,0 +1,160 @@
+package com.example.unusualsounds.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public class WebUtils {
+    public WebUtils() {
+
+    }
+
+    public static ResponseObj sendPostRequest(String url, Map<String, Object> headerMap, Map<String, Object> paraMap, Map<String, Object> dataMap, List<String> ids, int requestTimeoutSeconds) {
+        return sendPostRequest(url, headerMap, paraMap, dataMap, ids, requestTimeoutSeconds, String.class);
+    }
+
+    public static <T> ResponseObj<T> sendPostRequest(String url, Map<String, Object> headerMap, Map<String, Object> paraMap, Map<String, Object> dataMap, List<String> ids, int requestTimeoutSeconds, Class<T> responseBodyType) {
+        SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
+        clientHttpRequestFactory.setConnectTimeout(requestTimeoutSeconds * 1000);
+        clientHttpRequestFactory.setReadTimeout(requestTimeoutSeconds * 1000);
+        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        String paramUrl;
+        if (headerMap != null && !headerMap.isEmpty()) {
+            Iterator var9 = headerMap.keySet().iterator();
+
+            while (var9.hasNext()) {
+                paramUrl = (String) var9.next();
+                headers.add(paramUrl, String.valueOf(headerMap.get(paramUrl)));
+            }
+        }
+
+//        HttpEntity<Map<String, Object>> request = new HttpEntity(dataMap, headers);
+        paramUrl = url;
+        ResponseEntity<T> response = null;
+
+        try {
+            if (paraMap != null) {
+                boolean findParam = false;
+
+                for (Iterator var13 = paraMap.keySet().iterator(); var13.hasNext(); findParam = true) {
+                    String param = (String) var13.next();
+                    if (!findParam) {
+                        paramUrl = paramUrl + "?";
+                    } else {
+                        paramUrl = paramUrl + "&";
+                    }
+
+                    paramUrl = paramUrl + param + "={" + param + "}";
+                }
+                // 不通数据类型,这里单独处理。
+                if (null != dataMap) {
+                    HttpEntity<Map<String, Object>> request = new HttpEntity(dataMap, headers);
+                    response = restTemplate.postForEntity(paramUrl, request, responseBodyType, paraMap);
+                } else if (null != ids) {
+                    HttpEntity<List<String>> request = new HttpEntity<>(ids, headers);
+                    response = restTemplate.postForEntity(paramUrl, request, responseBodyType, paraMap);
+                }else {
+                    HttpEntity<Map<String, Object>> request = new HttpEntity(dataMap, headers);
+                    response = restTemplate.postForEntity(paramUrl, request, responseBodyType, paraMap);
+                }
+
+            } else {
+                // 不通数据类型,这里单独处理。
+                if (null != dataMap) {
+                    HttpEntity<Map<String, Object>> request = new HttpEntity(dataMap, headers);
+                    response = restTemplate.postForEntity(paramUrl, request, responseBodyType, new Object[0]);
+                } else if (null != ids) {
+                    HttpEntity<List<String>> request = new HttpEntity<>(ids, headers);
+                    response = restTemplate.postForEntity(paramUrl, request, responseBodyType, new Object[0]);
+                }else {
+                    HttpEntity<Map<String, Object>> request = new HttpEntity(dataMap, headers);
+                    response = restTemplate.postForEntity(paramUrl, request, responseBodyType, new Object[0]);
+                }
+            }
+        } catch (Exception var15) {
+            log.info("Exception var15:{}", var15);
+        } catch (Throwable var16) {
+            log.info("Throwable var16:{}", var16);
+        }
+
+        ResponseObj<T> obj = new ResponseObj();
+        if (response != null) {
+            obj.setStatusCodeValue(response.getStatusCodeValue());
+            obj.setBody(response.getBody());
+        }
+
+        return obj;
+    }
+
+//    public static ResponseObj sendPostDelRequest(String url, Map<String, Object> headerMap, Map<String, Object> paraMap, List<String> ids, int requestTimeoutSeconds) {
+//        return sendPostDelRequest(url, null, null, ids, requestTimeoutSeconds, String.class);
+//    }
+//
+//    public static <T> ResponseObj<T> sendPostDelRequest(String url, Map<String, Object> headerMap, Map<String, Object> paraMap, List<String> ids, int requestTimeoutSeconds, Class<T> responseBodyType) {
+//
+//        SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
+//        clientHttpRequestFactory.setConnectTimeout(requestTimeoutSeconds * 1000);
+//        clientHttpRequestFactory.setReadTimeout(requestTimeoutSeconds * 1000);
+//        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
+//        HttpHeaders headers = new HttpHeaders();
+//        headers.setContentType(MediaType.APPLICATION_JSON);
+//        String paramUrl;
+//        if (headerMap != null && !headerMap.isEmpty()) {
+//            Iterator var9 = headerMap.keySet().iterator();
+//
+//            while (var9.hasNext()) {
+//                paramUrl = (String) var9.next();
+//                headers.add(paramUrl, String.valueOf(headerMap.get(paramUrl)));
+//            }
+//        }
+//
+////        HttpEntity<Map<String, Object>> request = new HttpEntity(dataMap, headers);
+//        HttpEntity<List<String>> request = new HttpEntity<>(ids, headers);
+//        paramUrl = url;
+//        ResponseEntity<T> response = null;
+//
+//        try {
+//            if (paraMap != null) {
+//                boolean findParam = false;
+//
+//                for (Iterator var13 = paraMap.keySet().iterator(); var13.hasNext(); findParam = true) {
+//                    String param = (String) var13.next();
+//                    if (!findParam) {
+//                        paramUrl = paramUrl + "?";
+//                    } else {
+//                        paramUrl = paramUrl + "&";
+//                    }
+//
+//                    paramUrl = paramUrl + param + "={" + param + "}";
+//                }
+//
+//                response = restTemplate.postForEntity(paramUrl, request, responseBodyType, paraMap);
+//            } else {
+//                response = restTemplate.postForEntity(paramUrl, request, responseBodyType, new Object[0]);
+//            }
+//        } catch (Exception var15) {
+//            log.info("Exception var15:{}", var15);
+//        } catch (Throwable var16) {
+//            log.info("Throwable var16:{}", var16);
+//        }
+//
+//        ResponseObj<T> obj = new ResponseObj();
+//        if (response != null) {
+//            obj.setStatusCodeValue(response.getStatusCodeValue());
+//            obj.setBody(response.getBody());
+//        }
+//
+//        return obj;
+//    }
+}

+ 0 - 3
src/main/java/com/example/unusualsounds/framework/minio/MinioConfig.java

@@ -63,7 +63,4 @@ public class MinioConfig {
                 .build();
     }
 
-
-
-
 }

+ 11 - 0
src/main/java/com/example/unusualsounds/framework/minio/MinioUtil.java

@@ -116,6 +116,16 @@ public class MinioUtil {
                 pool.idleConnectionCount(),
                 pool.connectionCount());
 
+        //方案1:修改视频切片线程池 ForkJoinPool.commonPool会使用同一okhttp,即使过期
+        //方案2:上传文件检查连接是否过期、并重新初始化局部变。测试方案2
+        try {
+            minioClient.listBuckets(); // 简单健康检查
+        } catch (Exception e) {
+            log.warn("MinIO客户端连接异常{}", e.getMessage());
+            log.info("重新初始化····");
+            minioClient = prop.minioClient();
+        }
+
         String originalFilename = file.getOriginalFilename();
         if (StringUtils.isBlank(originalFilename)) {
             throw new RuntimeException("文件名为空");
@@ -149,6 +159,7 @@ public class MinioUtil {
         }
     }
 
+
     /**
      * 预览图片
      *

+ 90 - 59
src/main/java/com/example/unusualsounds/project/device/controller/SensorsController.java

@@ -2,6 +2,7 @@ package com.example.unusualsounds.project.device.controller;
 
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.unusualsounds.common.constant.HttpStatus;
 import com.example.unusualsounds.common.utils.RedisUtils;
 import com.example.unusualsounds.common.utils.UUID;
 import com.example.unusualsounds.framework.minio.MinioUtil;
@@ -10,21 +11,23 @@ import com.example.unusualsounds.project.device.entity.vo.RegisterSoundSensors;
 import com.example.unusualsounds.project.device.entity.vo.SoundSensorsQueryVo;
 import com.example.unusualsounds.project.device.service.impl.DeviceVoiceServiceImpl;
 import com.example.unusualsounds.project.device.service.impl.DevicesSoundSensorsServiceImpl;
+import com.example.unusualsounds.project.vox.entity.DevicesSoundSensorsList;
 import com.example.unusualsounds.web.entity.AjaxResult;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
-
-import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 @RestController
 @Tag(name = "ser")
 @RequestMapping("/voiceSer")
+@Slf4j
 public class SensorsController {
 
     @Value("${minio.dir}")
@@ -45,78 +48,95 @@ public class SensorsController {
 
     @Operation(summary = "上传文件,校验文件")
     @PostMapping("/uploadVoiceFile")
-    public AjaxResult uploadFile(@RequestParam("file") MultipartFile file){
+    public AjaxResult uploadFile(@RequestParam("file") MultipartFile file) {
         AjaxResult ajaxResult = new AjaxResult();
 
         //简单约束一下文件大小和后缀
-        if(!deviceVoiceServiceImpl.checkVoiceFile(file.getOriginalFilename(), file.getSize())){
-            ajaxResult.put("code",10001);
-            ajaxResult.put("msg","文件上传失败,请检查文件大小和格式");
+        if (!deviceVoiceServiceImpl.checkVoiceFile(file.getOriginalFilename(), file.getSize())) {
+            ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+            ajaxResult.put("msg", "文件上传失败,请检查文件大小和格式");
             return ajaxResult;
         }
 
         String uuid = UUID.generateUUIDWithoutHyphens();
-        String upload = minioUtil.upload(file,dir);
-        boolean b = RedisUtils.setForeverKey(uuid, upload);
-        ajaxResult.put("code",200);
-        ajaxResult.put("msg","文件上传成功");
-        ajaxResult.put("fileUUID",uuid);
+        String upload = minioUtil.upload(file, dir);
+        RedisUtils.set(uuid, upload, 6, TimeUnit.HOURS);
+        ajaxResult.put("code", HttpStatus.SUCCESS);
+        ajaxResult.put("msg", "文件上传成功");
+        ajaxResult.put("fileUUID", uuid);
         return ajaxResult;
 
     }
 
 
-
     @Operation(summary = "增加传感器,修改传感器技能信息")
     @PostMapping("/uploadSensors")
-    public AjaxResult testMinio(HttpServletRequest request,@RequestBody RegisterSoundSensors soundSensors){
+    public AjaxResult testMinio(@RequestBody RegisterSoundSensors soundSensors) {
         AjaxResult ajaxResult = new AjaxResult();
-
-        String remoteHost = request.getHeader("Ip");
-        if (remoteHost==null||"".equals(remoteHost)){
-            remoteHost = " ";
-        }
-        System.out.println("remoteHost:"+remoteHost);
-
-//        String remoteHost = "测试IP";
-
         //修改传感器技能信息
-        if(soundSensors.getSoundSensorUuid()!=null&& soundSensors.getSoundSensorUuid()!=""){
-            boolean updateSensorSkill = devicesSoundSensorsServiceImpl.updateSensorSkill(soundSensors);
-            ajaxResult.put("code",200);
-            ajaxResult.put("msg","技能修改成功!");
-            return ajaxResult;
+        if (soundSensors.getSoundSensorUuid() != null && soundSensors.getSoundSensorUuid() != "") {
+            // todo ghjghj 如果soundSensorUuid不为空,1)边缘端或中心端修改skillid。2)中心端做插入操作,而不是走修改逻辑。
+            Boolean selBySensorUuid = devicesSoundSensorsServiceImpl.selBySensorUuid(soundSensors.getSoundSensorUuid());
+            if (selBySensorUuid){
+                log.info("to update 技能信息");
+                boolean updateSensorSkill = false;
+                try {
+                    updateSensorSkill = devicesSoundSensorsServiceImpl.updateSensorSkill(soundSensors);
+                } catch (Exception e) {
+                    //消除手动回滚的异常
+                    updateSensorSkill = false;
+                    log.info("修改传感器技能信息 :{}", e);
+                }
+                if (updateSensorSkill) {
+                    ajaxResult.put("code", HttpStatus.SUCCESS);
+                    ajaxResult.put("msg", "技能修改成功!");
+
+                } else {
+                    ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+                    ajaxResult.put("msg", "技能修改失败!");
+                }
+                return ajaxResult;
+            }else {
+                log.info("to insert device_sounds_sensor 技能信息");
+            }
         }
         boolean checkSensorName = devicesSoundSensorsServiceImpl.checkSensorName(soundSensors.getSoundSensorName());
-        if(!checkSensorName){
-            ajaxResult.put("code",10001);
-            ajaxResult.put("msg","传感器名称重复!");
+        if (!checkSensorName) {
+            ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+            ajaxResult.put("msg", "传感器名称重复!");
             return ajaxResult;
         }
 
-        switch (soundSensors.getSoundSensorType()){
+        switch (soundSensors.getSoundSensorType()) {
             case "file":
-                if (soundSensors.getSoundFileUUid()==null||"".equals(soundSensors.getSoundFileUUid())){
-                    ajaxResult.put("code",10001);
-                    ajaxResult.put("msg","文件UUID不能为空!");
+                if (soundSensors.getSoundFileUUid() == null || "".equals(soundSensors.getSoundFileUUid())) {
+                    ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+                    ajaxResult.put("msg", "文件UUID不能为空!");
                     return ajaxResult;
                 }
                 break;
             case "sensor":
-                if (soundSensors.getSoundSensorUrl()==null||"".equals(soundSensors.getSoundSensorUrl())){
-                    ajaxResult.put("code",10001);
-                    ajaxResult.put("msg","传感器链接不能为空!");
+                if (soundSensors.getSoundSensorUrl() == null || "".equals(soundSensors.getSoundSensorUrl())) {
+                    ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+                    ajaxResult.put("msg", "传感器链接不能为空!");
                     return ajaxResult;
                 }
                 break;
             default:
-                ajaxResult.put("code",10001);
-                ajaxResult.put("msg","传感器类型错误!");
+                ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+                ajaxResult.put("msg", "传感器类型错误!");
                 return ajaxResult;
         }
-        boolean saveSensor =devicesSoundSensorsServiceImpl.saveSensor(soundSensors,remoteHost);
-        ajaxResult.put("code",200);
-        ajaxResult.put("msg","传感器添加成功");
+        boolean saveSensor = devicesSoundSensorsServiceImpl.saveSensor(soundSensors);
+
+        if (saveSensor) {
+            ajaxResult.put("code", HttpStatus.SUCCESS);
+            ajaxResult.put("msg", "传感器添加成功");
+        } else {
+            ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+            ajaxResult.put("msg", "传感器添加失败");
+        }
+
         return ajaxResult;
 
     }
@@ -124,38 +144,49 @@ public class SensorsController {
 
     @Operation(summary = "删除传感器")
     @PostMapping("/delSensor")
-    public AjaxResult delSensor(@RequestBody List<String> sensorUuids){
+    public AjaxResult delSensor(@RequestBody List<String> sensorUuids) {
+        AjaxResult ajaxResult = new AjaxResult();
 
-        if(sensorUuids.size()==0||sensorUuids==null){
-         return AjaxResult.error("请选择要删除的传感器!");
+
+        if (sensorUuids.size() == 0 || sensorUuids == null) {
+            ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+            ajaxResult.put("msg", "请选择要删除的传感器!");
+            return ajaxResult;
+        }
+        Boolean delSensor = null;
+        try {
+            delSensor = devicesSoundSensorsServiceImpl.delSensor(sensorUuids);
+        } catch (Exception e) {
+            delSensor = false;
         }
-       Integer delSensor =  devicesSoundSensorsServiceImpl.delSensor(sensorUuids);
 
-       if (delSensor>1){
-           return AjaxResult.success("删除传感器成功!");
-       }
-       return AjaxResult.error("删除传感器失败!");
+        if (delSensor) {
+            ajaxResult.put("code", HttpStatus.SUCCESS);
+            ajaxResult.put("msg", "删除传感器成功!");
+            return ajaxResult;
+        }
+        ajaxResult.put("code", HttpStatus.ARGUMENT_ERROR);
+        ajaxResult.put("msg", "删除传感器失败!");
+        return ajaxResult;
     }
 
     @Operation(summary = "查询传感器列表")
     @PostMapping("/getSensorList")
-    private AjaxResult getSensorList(HttpServletRequest request,@RequestBody SoundSensorsQueryVo soundSensorsQueryVo){
-        String remoteHost = request.getHeader("Ip");
-        IPage<DevicesSoundSensors>  sensorList = devicesSoundSensorsServiceImpl.getSensorList(soundSensorsQueryVo,remoteHost);
+    private AjaxResult getSensorList(@RequestBody SoundSensorsQueryVo soundSensorsQueryVo) {
+        DevicesSoundSensorsList sensorList = devicesSoundSensorsServiceImpl.getSensorList(soundSensorsQueryVo);
         return AjaxResult.success(sensorList);
-
     }
 
 
     @Operation(summary = "上传封面图片")
     @PostMapping("/upPrint")
-    public AjaxResult uploadPrint(@RequestParam("file") MultipartFile file){
+    public AjaxResult uploadPrint(@RequestParam("file") MultipartFile file) {
         AjaxResult ajaxResult = new AjaxResult();
 
-        String upload = minioUtil.upload(file,printDir);
-        ajaxResult.put("code",200);
-        ajaxResult.put("msg","文件上传成功");
-        ajaxResult.put("fileUUID",upload);
+        String upload = minioUtil.upload(file, printDir);
+        ajaxResult.put("code", HttpStatus.SUCCESS);
+        ajaxResult.put("msg", "文件上传成功");
+        ajaxResult.put("fileUUID", upload);
         return ajaxResult;
 
     }

+ 3 - 0
src/main/java/com/example/unusualsounds/project/device/entity/vo/RegisterSoundSensors.java

@@ -80,4 +80,7 @@ public class RegisterSoundSensors {
      */
     @Schema(description = "设备Uuid")
     private String soundSensorUuid;
+
+    @Schema(description = "判别当前是中心端还是边缘端")
+    private String soundSensorIp;
 }

+ 1 - 0
src/main/java/com/example/unusualsounds/project/device/entity/vo/SoundSensorsQueryVo.java

@@ -60,4 +60,5 @@ public class SoundSensorsQueryVo implements Serializable {
 
 
 
+
 }

+ 23 - 8
src/main/java/com/example/unusualsounds/project/device/service/DevicesSoundSensorsService.java

@@ -1,22 +1,24 @@
 package com.example.unusualsounds.project.device.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.example.unusualsounds.project.device.entity.DevicesSoundSensors;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.unusualsounds.project.device.entity.DevicesSoundSensors;
 import com.example.unusualsounds.project.device.entity.vo.RegisterSoundSensors;
 import com.example.unusualsounds.project.device.entity.vo.SoundSensorsQueryVo;
+import com.example.unusualsounds.project.vox.entity.DevicesSoundSensorsList;
 
 import java.util.List;
 
 /**
-* @author pengc
-* @description 针对表【devices_sound_sensors(设备信息表)】的数据库操作Service
-* @createDate 2025-02-21 13:23:08
-*/
+ * @author pengc
+ * @description 针对表【devices_sound_sensors(设备信息表)】的数据库操作Service
+ * @createDate 2025-02-21 13:23:08
+ */
 public interface DevicesSoundSensorsService extends IService<DevicesSoundSensors> {
 
     /**
      * 检查是否有重名的文件uuid
+     *
      * @param originalFilename
      * @return
      */
@@ -24,6 +26,7 @@ public interface DevicesSoundSensorsService extends IService<DevicesSoundSensors
 
     /**
      * 检查是否有重名的传感器名称
+     *
      * @param soundSensorName
      * @return
      */
@@ -31,13 +34,17 @@ public interface DevicesSoundSensorsService extends IService<DevicesSoundSensors
 
     /**
      * 保存传感器信息
+     *
      * @param soundSensors
      * @return
      */
-    boolean saveSensor(RegisterSoundSensors soundSensors,String remoteHost);
+    boolean saveSensor(RegisterSoundSensors soundSensors);
 
     /**
      * 更新传感器技能信息
+     * ------
+     * 添加回滚注解@Transactional
+     *
      * @param soundSensors
      * @return
      */
@@ -45,15 +52,23 @@ public interface DevicesSoundSensorsService extends IService<DevicesSoundSensors
 
     /**
      * 批量删除传感器信息
+     * ------
+     * 添加回滚注解@Transactional
+     *
      * @param sensorUuids
      * @return
      */
-    Integer delSensor(List<String> sensorUuids);
+    Boolean delSensor(List<String> sensorUuids);
 
     /**
      * 查询传感器列表
+     *
      * @param soundSensorsQueryVo
      * @return
      */
-    IPage<DevicesSoundSensors> getSensorList(SoundSensorsQueryVo soundSensorsQueryVo,String remoteHost);
+//    IPage<DevicesSoundSensors> getSensorList(SoundSensorsQueryVo soundSensorsQueryVo);
+    DevicesSoundSensorsList getSensorList(SoundSensorsQueryVo soundSensorsQueryVo);
+
+    // todo ghjghj 根据soundSensorUuid查询中心端数据库是否存在该条数据,如果存在,则走更新 返回true;否则走新增 返回false。
+    Boolean selBySensorUuid(String uuid);
 }

+ 257 - 59
src/main/java/com/example/unusualsounds/project/device/service/impl/DevicesSoundSensorsServiceImpl.java

@@ -5,23 +5,24 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.example.unusualsounds.common.utils.BaiDuUtils;
 import com.example.unusualsounds.common.utils.RedisUtils;
 import com.example.unusualsounds.common.utils.UUID;
 import com.example.unusualsounds.common.utils.VoiceAnalysisUtils;
 import com.example.unusualsounds.project.device.entity.DevicesSoundSensors;
 import com.example.unusualsounds.project.device.entity.vo.RegisterSoundSensors;
 import com.example.unusualsounds.project.device.entity.vo.SoundSensorsQueryVo;
-import com.example.unusualsounds.project.device.service.DevicesSoundSensorsService;
 import com.example.unusualsounds.project.device.mapper.DevicesSoundSensorsMapper;
+import com.example.unusualsounds.project.device.service.DevicesSoundSensorsService;
+import com.example.unusualsounds.project.vox.entity.DevicesSoundSensorsList;
 import com.example.unusualsounds.project.vox.entity.Skills;
 import com.example.unusualsounds.project.vox.service.impl.EdgeOrganizationServiceImpl;
 import com.example.unusualsounds.project.vox.service.impl.SkillsServiceImpl;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.*;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.RestTemplate;
 
 import java.util.Date;
@@ -34,19 +35,29 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 /**
-* @author pengc
-* @description 针对表【devices_sound_sensors(设备信息表)】的数据库操作Service实现
-* @createDate 2025-02-21 13:23:08
-*/
+ * @author pengc
+ * @description 针对表【devices_sound_sensors(设备信息表)】的数据库操作Service实现
+ * @createDate 2025-02-21 13:23:08
+ */
 @Service
 @Slf4j
 public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSensorsMapper, DevicesSoundSensors>
-    implements DevicesSoundSensorsService{
+        implements DevicesSoundSensorsService {
+
+
+    @Value(" ${CENTER_CODE}")
+    private String centerCode;
 
+    @Value(" ${EDGE_CODE}")
+    private String edgeCode;
+
+    @Value(" ${CENTER_URL}")
+    private String centerUrl;
 
     @Value("${vox.post-analysis-url}")
     private String postAnalysisUrl;
 
+
     @Autowired
     private SkillsServiceImpl skillsServiceImpl;
 
@@ -64,10 +75,10 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
         String s1 = UUID.removeHyphens(s);
 
         QueryWrapper<DevicesSoundSensors> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("file_uuid",s1).last("limit 1");
+        queryWrapper.eq("file_uuid", s1).last("limit 1");
 
         DevicesSoundSensors devicesSoundSensors = baseMapper.selectOne(queryWrapper);
-        if (devicesSoundSensors != null){
+        if (devicesSoundSensors != null) {
             return devicesSoundSensors.getFileUuid();
         }
         return s1;
@@ -75,27 +86,34 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
 
     @Override
     public boolean checkSensorName(String soundSensorName) {
+
+        //中心端不校验重名
+        if (StringUtils.equals(centerCode.trim(), centerUrl.trim())) {
+            return true;
+        }
+
         QueryWrapper<DevicesSoundSensors> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("name",soundSensorName).last("limit 1");
+        queryWrapper.eq("name", soundSensorName).last("limit 1");
 
         DevicesSoundSensors devicesSoundSensors = baseMapper.selectOne(queryWrapper);
 
-        if (devicesSoundSensors != null){
+        if (devicesSoundSensors != null) {
             return false;
         }
         return true;
     }
 
     @Override
-    public boolean saveSensor(RegisterSoundSensors soundSensors,String remoteHost) {
+    public boolean saveSensor(RegisterSoundSensors soundSensors) {
 
         DevicesSoundSensors devicesSoundSensors = initSoundSensors();
+        String serviceCode = this.checkServiceCode();
 
         devicesSoundSensors.setName(soundSensors.getSoundSensorName());
         devicesSoundSensors.setDeptUuid(soundSensors.getDeptUuid());
 
-        if("file".equals(soundSensors.getSoundSensorType())){
-            System.out.println("获取:"+soundSensors.getSoundFileUUid().toString());
+        if ("file".equals(soundSensors.getSoundSensorType())) {
+            System.out.println("获取:" + soundSensors.getSoundFileUUid().toString());
             Object o = RedisUtils.get(soundSensors.getSoundFileUUid());
 
             devicesSoundSensors.setStreamUrl(o.toString());
@@ -103,7 +121,7 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
             devicesSoundSensors.setStatus("online");
             devicesSoundSensors.setVideoType("file");
             devicesSoundSensors.setFileUuid(soundSensors.getSoundFileUUid());
-        }else {
+        } else {
             devicesSoundSensors.setStreamUrl(soundSensors.getSoundSensorUrl());
             devicesSoundSensors.setSrcUrl(soundSensors.getSoundSensorUrl());
             devicesSoundSensors.setStatus("offline");
@@ -112,17 +130,55 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
         HashMap<String, String> organizations = edgeOrganizationServiceImpl.getOrganizations();
 
         devicesSoundSensors.setOrgUuid(organizations.get("orgUuid"));
-        devicesSoundSensors.setDepartment("{\"id\":\""+soundSensors.getDeptUuid()+"\",\"name\":\""+soundSensors.getDepartment()+"\"}");
+        devicesSoundSensors.setDepartment("{\"id\":\"" + soundSensors.getDeptUuid() + "\",\"name\":\"" + soundSensors.getDepartment() + "\"}");
         devicesSoundSensors.setSkillUuid(soundSensors.getSkillUuid());
-        devicesSoundSensors.setIp(remoteHost);
+        devicesSoundSensors.setIp(serviceCode.trim());
         devicesSoundSensors.setResponsiblePerson(soundSensors.getResponsiblePerson());
         devicesSoundSensors.setDescription(soundSensors.getDescription());
 
-        int insert = baseMapper.insert(devicesSoundSensors);
-        RedisUtils.delete(soundSensors.getSoundFileUUid());
-        //对文件进行立刻通知算法解析(如果是文件类型,通知算法解析)
+        //当前为中心端接入,直接插入
+        Boolean isFlag = false;
+        log.info("insert ----> centerCode:{},edgeCode:{}", centerCode, edgeCode);
+//        if (StringUtils.equals(centerCode, edgeCode)) {
+        if (centerCode.trim().equals(edgeCode.trim())) {
+            log.info("当前为中心端接入,直接插入");
+            if (null != soundSensors.getSoundSensorIp() && StringUtils.isNotBlank(soundSensors.getSoundSensorIp())) {
+                devicesSoundSensors.setIp(soundSensors.getSoundSensorIp().trim());
+            } else {
+                devicesSoundSensors.setIp(centerCode.trim());
+            }
+            if (null != soundSensors.getSoundSensorUuid() && StringUtils.isNotBlank(soundSensors.getSoundSensorUuid())) {
+                devicesSoundSensors.setUuid(soundSensors.getSoundSensorUuid());
+            } else {
+                devicesSoundSensors.setUuid(UUID.generateUUIDWithoutHyphens());
+            }
+            int insert = baseMapper.insert(devicesSoundSensors);
+            RedisUtils.delete(soundSensors.getSoundFileUUid());
+            if (insert > 0) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            //当前为边端,先插入中心再插入本地
+            log.info("当前为边端,先插入中心再插入本地");
+            String url = centerUrl + "voiceSer/uploadSensors";
+            log.info("to center url:{}", url);
+            try {
+                soundSensors.setSoundSensorUuid(devicesSoundSensors.getUuid());
+                soundSensors.setSoundSensorIp(devicesSoundSensors.getIp().trim());
+                isFlag = this.insertSensors(url, devicesSoundSensors, soundSensors, soundSensors.getSoundFileUUid());
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.error("设备插入失败 e:{}", e);
+                isFlag = false;
+            }
+        }
+
 
-        if("file".equals(soundSensors.getSoundSensorType())){
+        //对文件进行立刻通知算法解析(如果是文件类型,通知算法解析)
+        if ("file".equals(soundSensors.getSoundSensorType())) {
+            log.info("对文件进行立刻通知算法解析(如果是文件类型,通知算法解析) start");
 //            QueryWrapper<Skills> skillsQueryWrapper = new QueryWrapper<>();
 //            skillsQueryWrapper.eq("uuid",soundSensors.getSkillUuid()).last("limit 1");
 //            Skills skills = skillsServiceImpl.getBaseMapper().selectOne(skillsQueryWrapper);
@@ -133,69 +189,160 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
             for (Skills skills : skillByName) {
                 if (skills.getUuid().equals(soundSensors.getSkillUuid())) skillName = skills.getName();
             }
-            this.analysisSoundFile(devicesSoundSensors.getSrcUrl(),skillName, devicesSoundSensors.getUuid(),
-                    devicesSoundSensors.getName(),soundSensors.getSkillUuid());
-        }
-        if (insert > 0){
-            return true;
-        }else {
-            return false;
+            this.analysisSoundFile(devicesSoundSensors.getSrcUrl(), skillName, devicesSoundSensors.getUuid(),
+                    devicesSoundSensors.getName(), soundSensors.getSkillUuid());
+
+            log.info("对文件进行立刻通知算法解析(如果是文件类型,通知算法解析) end");
         }
+        return isFlag;
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public boolean updateSensorSkill(RegisterSoundSensors soundSensors) {
 
-        UpdateWrapper<DevicesSoundSensors> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.eq("uuid",soundSensors.getSoundSensorUuid())
-                        .set("skill_uuid",soundSensors.getSkillUuid());
-        int update = baseMapper.update(null, updateWrapper);
-        if (update > 0){
-            return true;
+        try {
+            Boolean isFlag = false;
+            //当前为边端时
+            log.info("当前端 centerCode:{},edgeCode:{}", centerCode, edgeCode);
+            if (!StringUtils.equals(centerCode.trim(), edgeCode.trim())) {
+//                log.info("当前为中心端");
+                log.info("当前为边缘端");
+                String url = centerUrl.trim() + "voiceSer/uploadSensors";
+                log.info("updateSensorSkill url:{}", url);
+                isFlag = VoiceAnalysisUtils.postCenterSensorsUp(url, soundSensors);
+            } else {
+                isFlag = true;
+                log.info("当前为中心端");
+            }
+            if (isFlag) {
+                log.info("中心端更新成功,解析来嗯行边缘端");
+            } else {
+                log.info("中心端更新失败");
+                log.error("中心端 更新技能失败,进行回滚");
+                throw new RuntimeException("中心端 更新技能失败");
+            }
+            UpdateWrapper<DevicesSoundSensors> updateWrapper = new UpdateWrapper<>();
+            updateWrapper.eq("uuid", soundSensors.getSoundSensorUuid())
+                    .set("skill_uuid", soundSensors.getSkillUuid());
+            int update = baseMapper.update(null, updateWrapper);
+            if (update > 0 && isFlag) {
+                return true;
+            } else {
+                return false;
+            }
+//            if (update > 0 && isFlag) return true;
+//            return false;
+        } catch (Exception e) {
+            log.error("更新技能失败,进行回滚");
+            throw new RuntimeException(e);
         }
-        return false;
     }
 
     @Override
-    public Integer delSensor(List<String> sensorUuids) {
+//    @Transactional
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean delSensor(List<String> sensorUuids) {
 
-        QueryWrapper<DevicesSoundSensors> queryWrapper = new QueryWrapper<>();
-        queryWrapper.in("uuid",sensorUuids);
+        try {
+            Boolean isFlag = false;
+            for (String sensorUuid : sensorUuids) {
+                Map<String, Object> delMap = new HashMap<>();
+                delMap.put("uuid", sensorUuid);
+                List<DevicesSoundSensors> devicesSoundSensors = baseMapper.selectByMap(delMap);
+                if (devicesSoundSensors.size() <= 0) {
+                    return false;
+                }
+            }
+            //当为边端时
+            log.info("当前端 centerCode:{},edgeCode:{}", centerCode, edgeCode);
+            if (!StringUtils.equals(centerCode.trim(), edgeCode.trim())) {
+                String url = centerUrl.trim() + "voiceSer/delSensor";
+                log.info("当前为边缘端 url:{}", url);
+                isFlag = VoiceAnalysisUtils.postCenterSensorsUp(url, sensorUuids);
+
+                if (isFlag) {
+                    log.info("中心端删除成功,接下来执行边缘端");
+                } else {
+                    log.info("中心端删除失败");
+                    log.error("中心端 删除失败,进行回滚");
+                    throw new RuntimeException("中心端 删除失败");
+                }
+            } else {
+                isFlag = true;
+                log.info("当前为中心端");
+            }
+
+            QueryWrapper<DevicesSoundSensors> queryWrapper = new QueryWrapper<>();
+            queryWrapper.in("uuid", sensorUuids);
+            int delete = baseMapper.delete(queryWrapper);
+            if (delete > 0 && isFlag) return true;
+            return false;
+        } catch (Exception e) {
+            log.error("设备删除失败,进行回滚");
+            throw new RuntimeException(e);
+        }
 
-        int delete = baseMapper.delete(queryWrapper);
 
-        return delete;
     }
 
     @Override
-    public IPage<DevicesSoundSensors> getSensorList(SoundSensorsQueryVo soundSensorsQueryVo,String remoteHost) {
+    public DevicesSoundSensorsList getSensorList(SoundSensorsQueryVo soundSensorsQueryVo) {
 
         Page<DevicesSoundSensors> sensorsPage = new Page<>(soundSensorsQueryVo.getPageNum(), soundSensorsQueryVo.getPageSize());
 
         QueryWrapper<DevicesSoundSensors> queryWrapper = new QueryWrapper<>();
 
-        if (soundSensorsQueryVo.getName() != null && !"".equals(soundSensorsQueryVo.getName())){
-            queryWrapper.like("name",soundSensorsQueryVo.getName());
+        if (soundSensorsQueryVo.getName() != null && !"".equals(soundSensorsQueryVo.getName())) {
+            queryWrapper.like("name", soundSensorsQueryVo.getName());
         }
-        if (soundSensorsQueryVo.getStatus() != null && !"".equals(soundSensorsQueryVo.getStatus())){
-            queryWrapper.eq("status",soundSensorsQueryVo.getStatus());
+        if (soundSensorsQueryVo.getStatus() != null && !"".equals(soundSensorsQueryVo.getStatus())) {
+            queryWrapper.eq("status", soundSensorsQueryVo.getStatus());
         }
-        if(soundSensorsQueryVo.getDeptUuid() != null && !"".equals(soundSensorsQueryVo.getDeptUuid())){
-            queryWrapper.eq("dept_uuid",soundSensorsQueryVo.getDeptUuid());
+        if (soundSensorsQueryVo.getDeptUuid() != null && !"".equals(soundSensorsQueryVo.getDeptUuid())) {
+            queryWrapper.eq("dept_uuid", soundSensorsQueryVo.getDeptUuid());
         }
-        if(remoteHost != null && !"".equals(remoteHost)){
-            queryWrapper.eq("ip",remoteHost);
+        // todo ghjghj
+        log.info("------>centerCode:{},edgeCode:{}", centerCode, edgeCode);
+        boolean equalsCode = StringUtils.equals(centerCode.trim(), edgeCode.trim());
+        if (!equalsCode) {
+            log.info("----> ip:{}", this.checkServiceCode());
+            queryWrapper.eq("ip", this.checkServiceCode().trim());
         }
+        // todo ghjghj
+        queryWrapper.orderByDesc("id");
         IPage<DevicesSoundSensors> page = baseMapper.selectPage(sensorsPage, queryWrapper);
-        return page;
+//        if (!StringUtils.equals(centerCode.trim(), edgeCode.trim())) {
+//            log.info("当前列表为边缘端");
+//            DevicesSoundSensorsList devicesSoundSensorsList = DevicesSoundSensorsList.builder()
+//                    .edgeName(edgeCode.trim()).soundSensors(page).build();
+//            return devicesSoundSensorsList;
+//        }else {
+//            log.info("当前列表为中心端");
+//            DevicesSoundSensorsList devicesSoundSensorsList = DevicesSoundSensorsList.builder()
+//                    .edgeName(centerCode.trim()).soundSensors(page).build();
+//            return devicesSoundSensorsList;
+//        }
+        DevicesSoundSensorsList devicesSoundSensorsList = DevicesSoundSensorsList.builder()
+                .edgeName(checkServiceCode()).soundSensors(page).build();
+        return devicesSoundSensorsList;
+    }
+
+    @Override
+    public Boolean selBySensorUuid(String uuid) {
+        Map<String, Object> selMap = new HashMap<>();
+        selMap.put("uuid", uuid);
+        List<DevicesSoundSensors> devicesSoundSensors = baseMapper.selectByMap(selMap);
+        return devicesSoundSensors.size() > 0 ? true : false;
     }
 
 
     /**
      * 初始化声音传感器部分基本信息
+     *
      * @return
      */
-    public DevicesSoundSensors initSoundSensors(){
+    public DevicesSoundSensors initSoundSensors() {
 
         DevicesSoundSensors devicesSoundSensors = new DevicesSoundSensors();
         devicesSoundSensors.setUuid(UUID.generateUUIDWithoutHyphens());
@@ -225,9 +372,10 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
 
     /**
      * 通知算法对声音文件进行解析
+     *
      * @param
      */
-    public void analysisSoundFile(String filePath,String skillName,String streamId,String deviceName,String skillId) {
+    public void analysisSoundFile(String filePath, String skillName, String streamId, String deviceName, String skillId) {
 
         //同时支持20个用户上传文件解析
         ExecutorService executorService = Executors.newFixedThreadPool(20);
@@ -236,25 +384,75 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
             log.info("通知算法解析用户自定义上传文件");
 
             Map<String, Object> map = new HashMap<>();
-            map.put("filePath",filePath);
-            map.put("skillName",skillName);
-            map.put("streamId",streamId);
-            map.put("deviceName",deviceName);
-            map.put("skillId",skillId);
+            map.put("filePath", filePath);
+            map.put("skillName", skillName);
+            map.put("streamId", streamId + "_" + skillName);
+            map.put("deviceName", deviceName);
+            map.put("skillId", skillId);
+
+            map.forEach(
+                    (k, v) -> System.out.println(k + ":" + v)
+            );
 
             log.info(VoiceAnalysisUtils.postVoxAnalysis(map, postAnalysisUrl));
 
-        },executorService);
+        }, executorService);
         try {
             future.get();
 
             executorService.shutdown();
         } catch (InterruptedException e) {
+            log.info("通知算法对声音文件进行解析 InterruptedException:{}", e);
             throw new RuntimeException(e);
         } catch (ExecutionException e) {
+            log.info("通知算法对声音文件进行解析 ExecutionException:{}", e);
             throw new RuntimeException(e);
         }
 
+    }
+
+    /**
+     * 对比code,区分当前端是中心端还是边端
+     *
+     * @return
+     */
+    private String checkServiceCode() {
+
+        if (StringUtils.equals(centerCode.trim(), edgeCode.trim())) {
+            return centerCode.trim();
+        } else {
+            return edgeCode;
+        }
+    }
+
+    /**
+     * 事务回滚
+     *
+     * @param url
+     * @param devicesSoundSensors
+     * @param soundFileUUid
+     * @return
+     */
+    @Transactional
+    public Boolean insertSensors(String url, DevicesSoundSensors devicesSoundSensors, RegisterSoundSensors soundSensors, String soundFileUUid) {
+
+        try {
+            // todo ghjghj
+            Boolean aBoolean = VoiceAnalysisUtils.postCenterSensorsUp(url, soundSensors);
+            if (!aBoolean) {
+                throw new RuntimeException("插入中心端异常");
+            }
+            int insert = baseMapper.insert(devicesSoundSensors);
+            if (insert < 0) {
+                throw new RuntimeException("插入边端异常");
+            }
+            RedisUtils.delete(soundFileUUid);
+            if (aBoolean && insert > 0) return true;
+            return false;
+        } catch (RuntimeException e) {
+            log.error("插入数据库失败,进行回滚 e:{}", e);
+            throw new RuntimeException(e);
+        }
 
     }
 

+ 192 - 256
src/main/java/com/example/unusualsounds/project/vox/config/VideoTaskManager.java

@@ -7,12 +7,9 @@ import com.example.unusualsounds.framework.minio.MinioUtil;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
-import okhttp3.ConnectionPool;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.*;
 import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
 
 import java.io.*;
 import java.util.*;
@@ -26,21 +23,39 @@ import java.util.stream.Collectors;
 @Slf4j
 public class VideoTaskManager {
 
+    private final ConcurrentMap<String, VideoTask> taskMap = new ConcurrentHashMap<>();
+    /**
+     * 上传切片音频文件
+     *
+     * @param filePath
+     * @param skillName
+     * @param streamId
+     * @param skillId
+     * @param deviceName
+     * @return
+     */
+    private final ExecutorService uploadExecutor = Executors.newFixedThreadPool(30);
     @Value("${vox.video-dir}")
     private String videoDir;
-
     @Value("${minio.source-dir}")
     private String sourceDir;
-
     @Value("${vox.post-analysis-url}")
     private String postAnalysisUrl;
-
     @Autowired
     private MinioUtil minioUtil;
-
-
-    private final ConcurrentMap<String, VideoTask> taskMap = new ConcurrentHashMap<>();
-
+    // todo 路径。
+    @Value("${voice.commandStr}")
+    private String commandStr;
+    @Value("${voice.commandProbeStr}")
+    private String commandProbeStr;
+    @Value("${voice.commandCopy}")
+    private String commandCopy;
+    @Value("${voice.commandA}")
+    private String commandA;
+    @Value("${voice.commandAC}")
+    private String commandAC;
+    @Value("spring.profiles.active")
+    private String profilesActive;
 
     public boolean startTask(String streamId, String deviceName, String skillID, String rtspUrl, String skillName, String openUuid) {
         String compositeKey = streamId + "_" + skillName;
@@ -79,6 +94,118 @@ public class VideoTaskManager {
                 .collect(Collectors.toList());
     }
 
+    /**
+     * 检查切片文件是否完成
+     *
+     * @param filePath
+     * @return
+     */
+    private CompletableFuture<Boolean> checkUploadFileAsync(String filePath) {
+        return CompletableFuture.supplyAsync(() -> {
+            Process process = null;
+            try {
+                int attempts = 0;
+                int waitTime = 2 * 60 * 1000; //2分钟
+                while (attempts < 5) {
+                    // todo ghjghj
+                    log.info("checkUploadFileAsync() ---> 不通环境切换对应值 profilesActive:{},commandProbeStr:{}", profilesActive, commandProbeStr);
+                    List<String> checkVoxFinish = Arrays.asList(
+                            // todo 本地环境运行时,放开此代码行注释。
+//                            "D:\\file\\ffmpeg\\ffprobe.exe",
+                            // todo 正式环境运行时,放开此代码行注释。
+//                            "ffprobe",
+                            commandProbeStr,
+                            "-v", "error",
+                            "-i", filePath,
+                            "-show_entries", "format=duration",
+                            "-of", "default=noprint_wrappers=1:nokey=1"
+                    );
+
+                    process = new ProcessBuilder(checkVoxFinish).start();
+                    StringBuilder errorOutput = new StringBuilder();
+
+                    // 读取错误输出
+                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
+                        String line;
+                        while ((line = reader.readLine()) != null) {
+                            errorOutput.append(line).append("\n");
+                        }
+                    }
+
+                    int exitCode = process.waitFor();
+                    if (exitCode != 0 || !errorOutput.toString().trim().isEmpty()) {
+                        log.error("checkUploadFile:[{}]文件未完成,错误信息:{}", filePath, errorOutput.toString());
+                        Thread.sleep(waitTime);
+                        attempts++;
+                    } else {
+                        log.info("checkUploadFile:[{}]文件已完成", filePath);
+                        return true;
+                    }
+                }
+                return false; // 超过最大尝试次数,返回 false
+            } catch (InterruptedException | IOException e) {
+                log.error("checkUploadFile:检查文件[{}]失败", filePath, e);
+                throw new RuntimeException(e);
+            } finally {
+                if (process != null) {
+                    process.destroy();
+                }
+            }
+        });
+    }
+
+    private CompletableFuture<Void> uploadFileAsync(String filePath, String skillName, String streamId, String skillId, String deviceName) {
+        return CompletableFuture.runAsync(() -> {
+            int maxRetries = 4; // 最大重试次数
+            int retryCount = 0; // 当前重试次数
+            boolean uploadSuccess = false; // 标记上传是否成功
+            while (retryCount < maxRetries && !uploadSuccess) {
+                try {
+                    // 上传文件
+                    File file = new File(filePath);
+                    FileToMultipartFile fileToMultipartFile = new FileToMultipartFile(file);
+                    String upload = minioUtil.upload(fileToMultipartFile, sourceDir);
+                    log.info("上传文件:{}", upload);
+                    if (upload == null || upload.isEmpty()) {
+                        // 手动抛出异常
+                        throw new Exception();
+                    } else {
+                        // 发送消息
+                        Map<String, Object> map = new HashMap<>();
+                        map.put("filePath", upload);
+                        map.put("skillName", skillName);
+                        map.put("streamId", streamId);
+                        map.put("deviceName", deviceName);
+                        map.put("skillId", skillId);
+
+
+                        log.info(VoiceAnalysisUtils.postVoxAnalysis(map, postAnalysisUrl));
+                        // 标记上传成功
+                        uploadSuccess = true;
+                    }
+                } catch (Exception e) {
+                    // 记录错误日志
+                    log.error("上传文件{}或发送消息失败,重试次数: {}/{},错误信息: {}", filePath, retryCount + 1, maxRetries, e.getMessage(), e);
+                    // 增加重试计数
+                    retryCount++;
+
+
+                    // 如果达到最大重试次数,抛出异常
+                    if (retryCount >= maxRetries) {
+                        log.error("已达到最大重试次数,上传{}失败", filePath);
+                        break;
+                    }
+                    try {
+                        Thread.sleep(20000); // 等待 20 秒
+                    } catch (InterruptedException interruptedException) {
+                        log.error("线程等待中断: {}", interruptedException.getMessage());
+                        Thread.currentThread().interrupt(); // 恢复中断状态
+                    }
+                }
+            }
+        }, uploadExecutor);
+    }
+
     @Data
     @AllArgsConstructor
     public static class TaskStatus {
@@ -109,13 +236,43 @@ public class VideoTaskManager {
         }
 
         void start() {
+            // todo ghjghj
+            log.info("start() ---> 不通环境切换对应值 profilesActive:{},commandProbeStr:{}", profilesActive, commandProbeStr);
+            List<String> command = new ArrayList<>();
+            List<String> commandAnother = Arrays.asList("-f", "segment",
+                    "-segment_time", "300", //100秒
+                    "-segment_format", "mp4",
+                    "-reset_timestamps", "1",
+                    "-force_key_frames", "expr:gte(t,n_floor(t/100)*100)",
+                    "-write_empty_segments", "1",
+                    "-segment_atclocktime", "1",
+                    "-strftime", "1",
+                    videoDir + streamId + "-%Y-%m-%d_%H-%M-%S" + ".mp4");
+            profilesActive = "prod";
+            if (profilesActive.equals("dev")) {
+                command = new ArrayList<>(Arrays.asList(
+                        commandStr,
+                        "-rtsp_transport", "tcp",
+                        "-i", rtspUrl,
+                        "-vn",
+                        commandCopy, "copy"));
+            } else {
+                command = new ArrayList<>(Arrays.asList(
+                        commandStr,
+                        "-rtsp_transport", "tcp",
+                        "-i", rtspUrl,
+                        "-vn",
+                        commandCopy, "copy",
+                        commandA, commandAC));  // 现场音频为pcm_alaw转mp4不兼容,需要先转aac
+            }
+            command.addAll(commandAnother);
+//            // todo 本地环境运行时,执行此部分代码行。即需要放开注释。
 //            List<String> command = Arrays.asList(
-////                    "D:\\file\\ffmpeg\\ffmpeg.exe",
-//                    "ffmpeg",
+//                    commandStr,
 //                    "-rtsp_transport", "tcp",
 //                    "-i", rtspUrl,
 //                    "-vn",
-//                    "-c", "copy",
+//                    commandCopy, "copy",
 //                    "-f", "segment",
 //                    "-segment_time", "300", //100秒
 //                    "-segment_format", "mp4",
@@ -126,26 +283,25 @@ public class VideoTaskManager {
 //                    "-strftime", "1",
 //                    videoDir+streamId+"-%Y-%m-%d_%H-%M-%S"+".mp4"
 //            );
-
-            //现场环境内ffmpeg commandList
-            List<String> command = Arrays.asList(
-                    "ffmpeg",
-                    "-rtsp_transport", "tcp",
-                    "-i", rtspUrl,
-                    "-vn",
-                    "-c:v", "copy",
-                    "-c:a", "aac",   // 现场音频为pcm_alaw转mp4不兼容,需要先转aac
-                    "-f", "segment",
-                    "-segment_time", "300", //5分钟
-                    "-segment_format", "mp4",
-                    "-reset_timestamps", "1",
-                    "-force_key_frames", "expr:gte(t,n_floor(t/100)*100)",
-                    "-write_empty_segments", "1",
-                    "-segment_atclocktime", "1",
-                    "-strftime", "1",
-                    videoDir + streamId + "-%Y-%m-%d_%H-%M-%S" + ".mp4"
-
-            );
+//            // todo 打包项目时,执行此部分代码行。即需要放开注释。
+//            //现场环境内ffmpeg commandList
+////            List<String> command = Arrays.asList(
+////                    commandStr,
+////                    "-rtsp_transport", "tcp",
+////                    "-i", rtspUrl,
+////                    "-vn",
+////                    commandCopy, "copy",
+////                   commandA, commandAC,   // 现场音频为pcm_alaw转mp4不兼容,需要先转aac
+////                    "-f", "segment",
+////                    "-segment_time", "300", //5分钟
+////                    "-segment_format", "mp4",
+////                    "-reset_timestamps", "1",
+////                    "-force_key_frames", "expr:gte(t,n_floor(t/100)*100)",
+////                    "-write_empty_segments", "1",
+////                    "-segment_atclocktime", "1",
+////                    "-strftime", "1",
+////                    videoDir + streamId + "-%Y-%m-%d_%H-%M-%S" + ".mp4"
+////            );
 
             ProcessBuilder pb = new ProcessBuilder(command)
                     .redirectErrorStream(true);
@@ -159,8 +315,6 @@ public class VideoTaskManager {
         }
 
         void stop() throws InterruptedException {
-
-
             if (future != null && !future.isDone()) {
                 future.cancel(true);
             }
@@ -172,7 +326,6 @@ public class VideoTaskManager {
 
                 int exitCode = process.waitFor();  // 等待FFmpeg进程正常结束
                 log.info("[{}] 进程退出状态: {}", streamId, exitCode);
-
                 // 如果进程没有在合理时间内响应,可以考虑强制销毁
                 if (exitCode != 0) {
                     process.destroyForcibly();
@@ -180,7 +333,10 @@ public class VideoTaskManager {
                 } else {
                     log.info("[{}] 进程顺利结束", streamId);
                 }
+
             }
+
+
         }
 
 
@@ -246,226 +402,6 @@ public class VideoTaskManager {
         }
 
     }
-
-    /**
-     * 检查切片文件是否完成
-     * @param filePath
-     * @return
-     */
-    private CompletableFuture<Boolean> checkUploadFileAsync(String filePath) {
-        return CompletableFuture.supplyAsync(() -> {
-            Process process = null;
-            try {
-                int attempts = 0;
-                int waitTime = 2*60*1000; //2分钟
-                while (attempts < 5) {
-                    List<String> checkVoxFinish = Arrays.asList(
-                            "ffprobe",
-                            "-v", "error",
-                            "-i", filePath,
-                            "-show_entries", "format=duration",
-                            "-of", "default=noprint_wrappers=1:nokey=1"
-                    );
-
-                    process = new ProcessBuilder(checkVoxFinish).start();
-                    StringBuilder errorOutput = new StringBuilder();
-
-                    // 读取错误输出
-                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
-                        String line;
-                        while ((line = reader.readLine()) != null) {
-                            errorOutput.append(line).append("\n");
-                        }
-                    }
-
-                    int exitCode = process.waitFor();
-                    if (exitCode != 0 || !errorOutput.toString().trim().isEmpty()) {
-                        log.error("checkUploadFile:[{}]文件未完成,错误信息:{}", filePath, errorOutput.toString());
-                        Thread.sleep(waitTime);
-                        attempts++;
-                    } else {
-                        log.info("checkUploadFile:[{}]文件已完成", filePath);
-                        return true;
-                    }
-                }
-                return false; // 超过最大尝试次数,返回 false
-            } catch (InterruptedException | IOException e) {
-                log.error("checkUploadFile:检查文件[{}]失败", filePath, e);
-                throw new RuntimeException(e);
-            } finally {
-                if (process != null) {
-                    process.destroy();
-                }
-            }
-        });
-    }
-
-    /**
-     *  上传切片音频文件
-     * @param filePath
-     * @param skillName
-     * @param streamId
-     * @param skillId
-     * @param deviceName
-     * @return
-     */
-    private CompletableFuture<Void> uploadFileAsync(String filePath, String skillName, String streamId, String skillId, String deviceName) {
-        return CompletableFuture.runAsync(() -> {
-            int maxRetries = 4; // 最大重试次数
-            int retryCount = 0; // 当前重试次数
-            boolean uploadSuccess = false; // 标记上传是否成功
-            while (retryCount < maxRetries && !uploadSuccess) {
-                try {
-                    // 上传文件
-                    File file = new File(filePath);
-                    FileToMultipartFile fileToMultipartFile = new FileToMultipartFile(file);
-                    String upload = minioUtil.upload(fileToMultipartFile, sourceDir);
-                    log.info("上传文件:{}", upload);
-                    if (upload == null || upload.isEmpty()) {
-                        // 手动抛出异常
-                        throw new Exception();
-                    } else {
-                        // 发送消息
-                        Map<String, Object> map = new HashMap<>();
-                        map.put("filePath", upload);
-                        map.put("skillName", skillName);
-                        map.put("streamId", streamId);
-                        map.put("deviceName", deviceName);
-                        map.put("skillId", skillId);
-
-                        log.info(VoiceAnalysisUtils.postVoxAnalysis(map, postAnalysisUrl));
-                        // 标记上传成功
-                        uploadSuccess = true;
-                    }
-                } catch (Exception e) {
-                    // 记录错误日志
-                    log.error("上传文件{}或发送消息失败,重试次数: {}/{},错误信息: {}", filePath, retryCount + 1, maxRetries, e.getMessage(), e);
-                    // 增加重试计数
-                    retryCount++;
-                    // 如果达到最大重试次数,抛出异常
-                    if (retryCount >= maxRetries) {
-                        log.error("已达到最大重试次数,上传{}失败", filePath);
-                        break;
-                    }
-                    try {
-                        Thread.sleep(20000); // 等待 20 秒
-                    } catch (InterruptedException interruptedException) {
-                        log.error("线程等待中断: {}", interruptedException.getMessage());
-                        Thread.currentThread().interrupt(); // 恢复中断状态
-                    }
-                }
-            }
-        });
-    }
 }
 
 
-//    /**
-//     * 只检查文件是否完成
-//     *
-//     * @param filePath
-//     * @return
-//     */
-//    private CompletableFuture<Void> checkUploadFile(String filePath,String skillName,String streamId,String skillId, String deviceName){
-//
-//        return CompletableFuture.runAsync(()->{
-//            Process process  = null;
-//            BufferedReader reader = null;
-//            try {
-//                //不能无限检查3*5 15分钟
-//                int isNum=0;
-//                boolean isFlag =false;
-//                while (isNum<5){
-//                //检查文件是否完成
-//                    List<String> checkVoxFinish = Arrays.asList(
-////                            "D:\\file\\ffmpeg\\ffmpeg.exe",
-//                            "ffmpeg",
-//                            "-v","error",
-//                            "-i", filePath,
-//                            "-f", "null",
-//                            "-"
-//                    );
-//                    process = new ProcessBuilder(checkVoxFinish).start();
-//                    reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
-//                    StringBuilder errorOutput = new StringBuilder();
-//
-//                    String line;
-//                    while ((line = reader.readLine()) != null) {
-//                        errorOutput.append(line).append("\n");
-//                    }
-//                    int exitCode = process.waitFor();
-//                    if (exitCode != 0 || !errorOutput.toString().trim().isEmpty()) {
-//                        log.error("checkVoxFinish:[{}]文件未完成",filePath);
-//                        //重置状态errorOutput状态
-//                        errorOutput.delete(0, errorOutput.length());
-//                        //等待3分钟后再次检查
-//                        Thread.sleep(180000);
-//                        isNum++;
-//                    }else {
-//                        //跳出循环,上传文件
-//                        isFlag =true;
-//                        break;
-//                    }
-//                }
-//                if (isFlag) {
-//                    int maxRetries = 4; // 最大重试次数
-//                    int retryCount = 0; // 当前重试次数
-//                    boolean uploadSuccess = false; // 标记上传是否成功
-//                    while (retryCount < maxRetries && !uploadSuccess) {
-//                        try {
-//                            // 上传文件
-//                            File file = new File(filePath);
-//                            FileToMultipartFile fileToMultipartFile = new FileToMultipartFile(file);
-//                            String upload = minioUtil.upload(fileToMultipartFile, sourceDir);
-//                            log.info("上传文件:{}", upload);
-//                            // 发送消息
-//                            Map<String, Object> map = new HashMap<>();
-//                            map.put("filePath", upload);
-//                            map.put("skillName", skillName);
-//                            map.put("streamId", streamId);
-//                            map.put("deviceName", deviceName);
-//                            map.put("skillId", skillId);
-//                            log.info(VoiceAnalysisUtils.postVoxAnalysis(map, postAnalysisUrl));
-//                            // 标记上传成功
-//                            uploadSuccess = true;
-//                        } catch (Exception e) {
-//                            // 记录错误日志
-//                            log.error("上传文件或发送消息失败,重试次数: {}/{},错误信息: {}", retryCount + 1, maxRetries, e.getMessage(), e);
-//                            // 增加重试计数
-//                            retryCount++;
-//                            // 如果达到最大重试次数,抛出异常
-//                            if (retryCount >= maxRetries) {
-//                                log.error("已达到最大重试次数,上传失败");
-//                                throw new RuntimeException("上传文件失败,已达到最大重试次数", e);
-//                            }
-//                            // 可选:等待一段时间再重试(例如 2 秒)
-//                            try {
-//                                Thread.sleep(2000); // 等待 2 秒
-//                            } catch (InterruptedException interruptedException) {
-//                                log.error("线程等待中断: {}", interruptedException.getMessage());
-//                                Thread.currentThread().interrupt(); // 恢复中断状态
-//                            }
-//                        }
-//                    }
-//                }
-//
-//            } catch (InterruptedException e) {
-//                throw new RuntimeException(e);
-//            } catch (IOException e) {
-//                throw new RuntimeException(e);
-//            } finally {
-//                if(reader !=null){
-//                    try {
-//                        reader.close();
-//                    } catch (IOException e) {
-//                        log.error("reader关闭失败{}",e.getMessage());
-//                    }
-//                }
-//                if(process !=null){
-//                    process.destroy();
-//                }
-//
-//            }
-//        });
-//
-//    }

+ 2 - 2
src/main/java/com/example/unusualsounds/project/vox/controller/CheckVoxController.java

@@ -50,8 +50,8 @@ public class CheckVoxController {
         //校验设备是否开启(包含传感器、摄像头),当前只做摄像头校验
         CameraDTO camera  = voxServiceImpl.checkDevice(device.getDeviceId());
         //-----测试(云环境的是mp4文件,不是rtsp流)
-//        camera.setSrcURL("rtsp://192.168.1.112:8554/video");
-//        camera.setVideoType("");
+        camera.setSrcURL("rtsp://192.168.1.112:8554/video");
+        camera.setVideoType("");
         //-----测试
         if(camera == null || "offline".equals(camera.getStatus()) || "error".equals(camera.getStatus())){
             //保存启停接口的设备信息到数据库,便于后续定时任务调用

+ 2 - 2
src/main/java/com/example/unusualsounds/project/vox/entity/Alarms.java

@@ -426,8 +426,8 @@ public class Alarms implements Serializable {
         private String status = "created";
         private String displayStatus = "pending";
         private Integer level = 4;
-        private String imageUrl = "s3://windmill/store/abnormal-sound/source/2025-03-20/aafdfd09-0f41-4942-9414-10061f8f674e.jpeg";
-        private String thumbnailUrl = "s3://windmill/store/abnormal-sound/source/2025-03-20/d4a6fa31-0404-486e-997d-9fd9a89f87bd.jpg";
+        private String imageUrl = "";
+        private String thumbnailUrl = "";
         private String imageDrawUrl = "";
         private String videoUrl = "";
         private String deviceUuid = "";

+ 17 - 0
src/main/java/com/example/unusualsounds/project/vox/entity/DevicesSoundSensorsList.java

@@ -0,0 +1,17 @@
+package com.example.unusualsounds.project.vox.entity;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.unusualsounds.project.device.entity.DevicesSoundSensors;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class DevicesSoundSensorsList {
+    private String edgeName; // 场站名称。
+    private IPage<DevicesSoundSensors> soundSensors;
+}

+ 3 - 0
src/main/java/com/example/unusualsounds/project/vox/service/impl/AlarmReportsServiceImpl.java

@@ -6,6 +6,7 @@ import com.example.unusualsounds.project.vox.entity.AlarmReports;
 import com.example.unusualsounds.project.vox.entity.Alarms;
 import com.example.unusualsounds.project.vox.service.AlarmReportsService;
 import com.example.unusualsounds.project.vox.mapper.AlarmReportsMapper;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.Date;
@@ -19,6 +20,7 @@ import java.util.Date;
 public class AlarmReportsServiceImpl extends ServiceImpl<AlarmReportsMapper, AlarmReports>
     implements AlarmReportsService{
 
+
     @Override
     public boolean saveAlarmReport(Alarms alarms) {
 
@@ -33,6 +35,7 @@ public class AlarmReportsServiceImpl extends ServiceImpl<AlarmReportsMapper, Ala
         alarmReports.setDisplayStatus("pending");
         alarmReports.setAlarmUuid(alarms.getUuid());
 
+
         boolean save = this.save(alarmReports);
         return save;
     }

+ 13 - 3
src/main/java/com/example/unusualsounds/project/vox/service/impl/AlarmsServiceImpl.java

@@ -8,6 +8,7 @@ import com.example.unusualsounds.project.vox.entity.Alarms;
 import com.example.unusualsounds.project.vox.service.AlarmsService;
 import com.example.unusualsounds.project.vox.mapper.AlarmsMapper;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.Date;
@@ -29,10 +30,16 @@ public class AlarmsServiceImpl extends ServiceImpl<AlarmsMapper, Alarms>
     @Autowired
     private EdgeOrganizationServiceImpl edgeOrganizationServiceImpl;
 
+    @Value("${Alarms.imageUrl}")
+    private String imageUrl;
+
+    @Value("${Alarms.thumbnailUrl}")
+    private String thumbnailUrl;
+
+
 
     @Override
     public boolean  saveResultAnalysis(HashMap<String, String> resultAnalysis) {
-
         String deviceId = resultAnalysis.get("deviceId");
         String deviceName = resultAnalysis.get("deviceName");
         String skillName = resultAnalysis.get("skillName");
@@ -45,8 +52,7 @@ public class AlarmsServiceImpl extends ServiceImpl<AlarmsMapper, Alarms>
             o = RedisUtils.get(deviceId);
             alarms = JSON.parseObject(o.toString(), Alarms.class);
         }else {
-            Alarms build = new Alarms.Builder().build();
-            alarms=build;
+            alarms= new Alarms.Builder().build();
             HashMap<String, String> organizations = edgeOrganizationServiceImpl.getOrganizations();
             alarms.setName(skillName);
             alarms.setDescription(deviceName+","+skillName);
@@ -61,6 +67,10 @@ public class AlarmsServiceImpl extends ServiceImpl<AlarmsMapper, Alarms>
         alarms.setUuid(alarmUUID);
         alarms.setCreatedAt(new Date());
         alarms.setUpdatedAt(new Date());
+        alarms.setImageUrl(imageUrl);
+        alarms.setThumbnailUrl(thumbnailUrl);
+
+
         boolean save = this.save(alarms);
         boolean reportSave = alarmReportsService.saveAlarmReport(alarms);
         return reportSave;

+ 11 - 8
src/main/java/com/example/unusualsounds/project/vox/service/impl/EdgeOrganizationServiceImpl.java

@@ -63,14 +63,17 @@ public class EdgeOrganizationServiceImpl extends ServiceImpl<EdgeOrganizationMap
                 String deptID = jsonObject.get("deptID").toString();
                 stringStringHashMap.put("deptUuid", deptID.toString());
 
-                QueryWrapper<EdgeOrganization> queryWrapper = new QueryWrapper<>();
-                queryWrapper.eq("dept_uuid", deptID)
-                        .last("limit 1");
-
-                EdgeOrganization deptUuid = this.baseMapper.selectOne(queryWrapper);
-                if (deptUuid != null) {
-                    stringStringHashMap.put("orgUuid", deptUuid.getOrgUuid());
-                }
+                //受现场环境影响,不进行查询org_id,发现平台预警的deptID=orgID
+//                QueryWrapper<EdgeOrganization> queryWrapper = new QueryWrapper<>();
+//                queryWrapper.eq("dept_uuid", deptID)
+//                        .last("limit 1");
+//
+//                EdgeOrganization deptUuid = this.baseMapper.selectOne(queryWrapper);
+//                if (deptUuid != null) {
+//                    stringStringHashMap.put("orgUuid", deptUuid.getOrgUuid());
+//                }
+
+                stringStringHashMap.put("orgUuid", deptID.toString());
                 return stringStringHashMap;
             } else {
                 //请求失败,抛出异常

+ 2 - 5
src/main/java/com/example/unusualsounds/project/vox/service/impl/VideoServiceImpl.java

@@ -23,10 +23,7 @@ import java.io.File;
 import java.io.InputStreamReader;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.concurrent.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -99,7 +96,7 @@ public class VideoServiceImpl implements VideoService {
         alarms.setOrgUuid(organizations.get("orgUuid"));
         alarms.setDeviceUuid(deviceId);
         alarms.setSkillUuid(skillId);
-        RedisUtils.setForeverKey(deviceId+"_"+skillName, alarms);
+        RedisUtils.set(deviceId+"_"+skillName, alarms, 6, TimeUnit.HOURS);
     }
 
     @Override

+ 1 - 1
src/main/java/com/example/unusualsounds/project/vox/task/TicketsTask.java

@@ -84,7 +84,7 @@ public class TicketsTask {
 
 
     /**
-     * 每两小时检查一次-->每天凌晨两点进行检测
+     * 每天凌晨两点进行检测
      * @throws IOException
      */
     @Scheduled(cron = "0 0 2 * * ?")

+ 20 - 13
src/main/resources/application-dev.yml

@@ -19,17 +19,9 @@ minio:
 spring:
   datasource:
     dynamic:
-      primary: slave
+      primary: master
       datasource:
-        #中心测
         master:
-          type: com.alibaba.druid.pool.DruidDataSource
-          driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://10.68.204.52:8639/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
-          username: root
-          password: fbLfJZ1sFMAw
-        #边缘测
-        slave:
           type: com.alibaba.druid.pool.DruidDataSource
           driver-class-name: com.mysql.cj.jdbc.Driver
           url: jdbc:mysql://10.68.208.94:8639/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
@@ -53,8 +45,8 @@ spring:
       max-request-size: 100MB
   data:
     redis:
-      host: 192.168.1.112
-      port: 6390
+      host: 192.168.1.202
+      port: 6380
       password:
       database: 0
       timeout: 6000ms
@@ -93,7 +85,22 @@ yijian-interface:
 Camera:
   num: 60
 
-
+#minio线程池
 OkHttp:
   num: 30
-  KeepLive: 13
+  #当前分片时间是5分钟,保活取两倍+1
+  KeepLive: 2
+
+#alarms配置
+Alarms:
+  imageUrl: s3://windmill/store/abnormal-sound/source/2025-03-21/aafdfd09-0f41-4942-9414-10061f8f674e.jpeg
+  thumbnailUrl: s3://windmill/store/abnormal-sound/source/2025-03-21/d4a6fa31-0404-486e-997d-9fd9a89f87bd.jpg
+
+voice:
+  commandStr: "D:\\file\\ffmpeg\\ffmpeg.exe"
+  commandProbeStr: "D:\file\ffmpeg\ffprobe.exe"
+  commandCopy: "-c"
+  commandA: "-c:a"
+  commandAC: "aac"
+
+

+ 6 - 7
src/main/resources/application-edge.yml

@@ -27,13 +27,6 @@ spring:
           url: jdbc:mysql://mysql.jxfdc004.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
           username: root
           password: fbLfJZ1sFMAw
-        #边缘测
-        slave:
-          type: com.alibaba.druid.pool.DruidDataSource
-          driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://mysql.jxfdc004.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
-          username: root
-          password: fbLfJZ1sFMAw
     druid:
       initial-size: 5
       min-idle: 5
@@ -90,7 +83,13 @@ yijian-interface:
 Camera:
   num: 60
 
+#minio线程池
 OkHttp:
   num: 30
   #当前分片时间是5分钟,保活取两倍+1
   KeepLive: 13
+
+#alarms配置
+Alarms:
+  imageUrl: s3://windmill/store/abnormal-sound/source/2025-03-20/aafdfd09-0f41-4942-9414-10061f8f674e.jpeg
+  thumbnailUrl: s3://windmill/store/abnormal-sound/source/2025-03-20/d4a6fa31-0404-486e-997d-9fd9a89f87bd.jpg

+ 15 - 8
src/main/resources/application-prod.yml

@@ -28,13 +28,6 @@ spring:
           url: jdbc:mysql://xdbmysql57-leader.middleware.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
           username: root
           password: fbLfJZ1sFMAw
-        #边缘测
-        slave:
-          type: com.alibaba.druid.pool.DruidDataSource
-          driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://xdbmysql57-leader.middleware.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
-          username: root
-          password: fbLfJZ1sFMAw
     druid:
       initial-size: 5
       min-idle: 5
@@ -92,6 +85,20 @@ yijian-interface:
 Camera:
   num: 60
 
+#minio线程池
 OkHttp:
   num: 30
-  KeepLive: 13
+  #当前分片时间是5分钟,保活取两倍+1
+  KeepLive: 13
+
+#alarms配置
+Alarms:
+  imageUrl: s3://windmill/store/abnormal-sound/source/2025-03-20/aafdfd09-0f41-4942-9414-10061f8f674e.jpeg
+  thumbnailUrl: s3://windmill/store/abnormal-sound/source/2025-03-20/d4a6fa31-0404-486e-997d-9fd9a89f87bd.jpg
+voice:
+  commandStr: "ffmpeg"
+  commandProbeStr: "ffprobe"
+  commandCopy: "-c:v"
+  commandA: "-c:a"
+  commandAC: "aac"
+

+ 9 - 10
src/main/resources/application-test.yml

@@ -28,13 +28,6 @@ spring:
           url: jdbc:mysql://xdbmysql57-leader.middleware.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
           username: root
           password: fbLfJZ1sFMAw
-        #边缘测
-        slave:
-          type: com.alibaba.druid.pool.DruidDataSource
-          driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://xdbmysql57-leader.middleware.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
-          username: root
-          password: fbLfJZ1sFMAw
     druid:
       initial-size: 5
       min-idle: 5
@@ -80,8 +73,6 @@ yijian-interface:
       ak: fd01ec4de8724d71bb764190f202929c
       sk: f44a391cadcc42f98167e7e42086514f
       endpoint: http://10.68.204.52:8412
-
-
   #接口地址前缀配置
   uri-path-prefix: /api/spi
   #设备信息接口地址 GET /v1/devices/{deviceID}
@@ -93,6 +84,14 @@ yijian-interface:
 Camera:
   num: 60
 
+#minio线程池
 OkHttp:
   num: 30
-  KeepLive: 13
+  #当前分片时间是5分钟,保活取两倍+1
+  KeepLive: 13
+
+#alarms配置
+Alarms:
+  imageUrl: s3://windmill/store/abnormal-sound/source/2025-03-20/aafdfd09-0f41-4942-9414-10061f8f674e.jpeg
+  thumbnailUrl: s3://windmill/store/abnormal-sound/source/2025-03-20/d4a6fa31-0404-486e-997d-9fd9a89f87bd.jpg
+

+ 34 - 8
src/test/java/com/example/unusualsounds/UnusualSoundsApplicationTests.java

@@ -4,6 +4,7 @@ import static com.baidubce.auth.SignOptions.DEFAULT;
 
 import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
 import com.baidubce.http.HttpMethodName;
 import com.example.unusualsounds.common.utils.*;
 import com.example.unusualsounds.common.utils.UUID;
@@ -17,8 +18,11 @@ import com.example.unusualsounds.web.jsonobj.CameraDTO;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.ResponseEntity;
 
@@ -282,14 +286,14 @@ class UnusualSoundsApplicationTests {
     void testMinioDownload(){
 
 
-        String url = "http://10.68.208.94:8412/spi/minio/windmill/store/video-stream/2025-02-21/6DbTa7S709testVideo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20250305%2Fbj%2Fs3%2Faws4_request&X-Amz-Date=20250305T055218Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=0199c107bd76e1aab9c54ab3083a7d9216df28a196c12abcedf3e91a8f4f7d84";
-        String save = "D:\\tmp\\6DbTa7S709testVideo.mp4";
-        String regex = "^.*/([^/?]+)(?:\\\\?.*)?$";
-        Pattern pattern = Pattern.compile(regex);
-        Matcher matcher = pattern.matcher(url);
-        if (matcher.find()) {
-            System.out.println(matcher.group(1));
-        }
+//        String url = "http://10.68.208.94:8412/spi/minio/windmill/store/video-stream/2025-02-21/6DbTa7S709testVideo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20250305%2Fbj%2Fs3%2Faws4_request&X-Amz-Date=20250305T055218Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=0199c107bd76e1aab9c54ab3083a7d9216df28a196c12abcedf3e91a8f4f7d84";
+//        String save = "D:\\tmp\\6DbTa7S709testVideo.mp4";
+//        String regex = "^.*/([^/?]+)(?:\\\\?.*)?$";
+//        Pattern pattern = Pattern.compile(regex);
+//        Matcher matcher = pattern.matcher(url);
+//        if (matcher.find()) {
+//            System.out.println(matcher.group(1));
+//        }
 
 
 //        File file = HttpUtil.downloadFileFromUrl(url, new File(save));
@@ -299,6 +303,28 @@ class UnusualSoundsApplicationTests {
 //            System.out.println("下载失败");
 //        }
 
+    }
+
+
+
+    @Test
+    public void testJSonMap(){
+//        Alarms build = new Alarms.Builder().build();
+//
+//        String s = JSONObject.toJSONString(build);
+//
+//        Map<String,Object> alarmsMap = JSONObject.parseObject(s);
+//
+//        alarmsMap.forEach(
+//                (k,v) -> {
+//                    System.out.println(k+":"+v);
+//                }
+//        );
+
+        List<String> strings = Arrays.asList("123", "abc", "qqa");
+        String str = JSONObject.toJSONString(strings);
+        System.out.println("str:"+str);
+
 
     }