Zimo 4 часов назад
Родитель
Сommit
8576bdab6a

+ 16 - 5
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/alarm/IotVideoAlarmController.java

@@ -9,6 +9,10 @@ import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.sip.device.channel.YfSipDevi
 import cn.iocoder.yudao.module.pms.hik.HikIsapiService;
 import cn.iocoder.yudao.module.pms.service.alarm.IotVideoAlarmService;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -120,7 +124,7 @@ public class IotVideoAlarmController {
     @GetMapping("/pic/{id}")
     @Operation(summary = "获得视频告警图片")
     @PreAuthorize("@ss.hasPermission('rq:iot-video-alarm:query')")
-    public CommonResult<String> getAlarmPic(@PathVariable Long id) throws IOException {
+    public ResponseEntity<byte[]> getAlarmPic(@PathVariable Long id) throws IOException {
         IotVideoAlarmDO iotVideoAlarm = iotVideoAlarmService.getIotVideoAlarm(id);
         String url = "";
         if (iotVideoAlarm != null) {
@@ -134,7 +138,7 @@ public class IotVideoAlarmController {
         if (StringUtils.isNotBlank(url)) {
             picInfo = hikIsapiService.getPicInfo("nvr-001", url);
         }
-//        // 2. 设置响应头,告诉前端这是图片流
+        // 2. 设置响应头,告诉前端这是图片流
 //        HttpHeaders headers = new HttpHeaders();
 //        // 根据实际图片格式调整(海康通常返回jpeg)
 //        headers.setContentType(MediaType.IMAGE_JPEG);
@@ -145,9 +149,16 @@ public class IotVideoAlarmController {
 //
 //        // 3. 返回二进制流和响应头
 //        return success(new ByteArrayInputStream(picInfo));
-        String base64Pic = Base64.getEncoder().encodeToString(picInfo);
+//        return success(picInfo);
 
-        // 4. 用CommonResult封装返回
-        return success(base64Pic);
+
+
+        // 4. 设置响应头,返回纯图片流
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.IMAGE_JPEG); // 海康默认jpeg,可根据实际调整
+        headers.setContentLength(picInfo.length);
+        headers.setCacheControl("no-cache, no-store, must-revalidate");
+
+        return new ResponseEntity<>(picInfo, headers, HttpStatus.OK);
     }
 }

+ 38 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/hik/HikHttpClient.java

@@ -58,13 +58,25 @@ public class HikHttpClient {
             return handleResponse(response);
         }
     }
-    
+    public byte[] executeRequestByte(HttpRequestBase request, String username,
+                                     String password, int timeout) throws IOException {
+        CloseableHttpClient client = getHttpClient(username, password, timeout);
+        try (CloseableHttpResponse response = client.execute(request)) {
+            return handleResponseByte(response);
+        }
+    }
     public String doGet(String url, String username, String password, 
                        int timeout, Map<String, String> headers) throws IOException {
         HttpGet httpGet = new HttpGet(url);
         setHeaders(httpGet, headers);
         return executeRequest(httpGet, username, password, timeout);
     }
+    public byte[] doGetByte(String url, String username, String password,
+                        int timeout, Map<String, String> headers) throws IOException {
+        HttpGet httpGet = new HttpGet(url);
+        setHeaders(httpGet, headers);
+        return executeRequestByte(httpGet, username, password, timeout);
+    }
     
     public String doPost(String url, String body, String username, String password,
                         int timeout, Map<String, String> headers) throws IOException {
@@ -110,7 +122,31 @@ public class HikHttpClient {
             throw new IOException("HTTP Error: " + statusCode);
         }
     }
-    
+
+    private byte[] handleResponseByte(HttpResponse response) throws IOException {
+        // 1. 获取响应状态码和响应体
+        int statusCode = response.getStatusLine().getStatusCode();
+        HttpEntity entity = response.getEntity();
+
+        // 2. 直接读取二进制数据(核心改动:不再转String)
+        byte[] responseBytes = entity != null ? EntityUtils.toByteArray(entity) : new byte[0];
+
+        // 3. 日志打印优化:二进制数据不直接打印(避免乱码/日志过大),仅打印长度
+        log.debug("HTTP Status: {}, Response Byte Length: {}", statusCode, responseBytes.length);
+
+        // 4. 状态码校验
+        if (statusCode >= 200 && statusCode < 300) {
+            return responseBytes; // 直接返回byte[]
+        } else {
+            // 异常时:若有文本响应(如错误信息),可转String打印;无则打印长度
+            String errorMsg = entity != null ?
+                    EntityUtils.toString(entity, StandardCharsets.UTF_8) :
+                    "No response body (byte length: " + responseBytes.length + ")";
+            log.error("HTTP Error: {} - {}", statusCode, errorMsg);
+            throw new IOException("HTTP Error: " + statusCode + ", Message: " + errorMsg);
+        }
+    }
+
     @PreDestroy
     public void destroy() {
         clientCache.values().forEach(client -> {

+ 3 - 3
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/hik/HikIsapiService.java

@@ -85,14 +85,14 @@ public class HikIsapiService {
         headers.put("Accept", "image/jpeg,image/png");
 
         // 调用httpClient的doGet方法获取String响应
-        String response = httpClient.doGet(url, device.getUsername(), device.getPassword(),
+        byte[] response = httpClient.doGetByte(url, device.getUsername(), device.getPassword(),
                 device.getTimeout(), headers);
 
         // 核心:将String转换为byte[](指定编码,推荐UTF-8)
         // !!重要提醒:如果response是图片二进制的字符乱码,转换后也无法恢复!!
-        byte[] resultBytes = response.getBytes("UTF-8");
+//        byte[] resultBytes = response.getBytes();
 
-        return resultBytes;
+        return response;
 
 //        Map<String, String> headers = new HashMap<>();
 //        headers.put("Content-Type", "application/json");