package com.zc.business.controller; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.system.service.ISysConfigService; import com.zc.business.domain.DcWarning; import com.zc.business.service.IDcWarningService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.springframework.stereotype.Component; import java.io.BufferedInputStream; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.time.Duration; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * */ @Component() @Slf4j public class RadarController { ISysConfigService configService = SpringUtils.getBean(ISysConfigService.class); IDcWarningService dcWarningService = SpringUtils.getBean(IDcWarningService.class); public void radarDownload() { // 获取当前时间 LocalDateTime now = LocalDateTime.now(); // 定义格式 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 获取当前时间前5分钟的时间点 LocalDateTime fifteenMinutesAgo = now.minus(Duration.ofMinutes(5)); String FifteenMinutesAgo = fifteenMinutesAgo.format(formatter); // 获取当前时间前25分钟的时间点 LocalDateTime twentyMinutesAgo = now.minus(Duration.ofMinutes(25)); String TwentyMinutesAgo = twentyMinutesAgo.format(formatter); DcWarning dcWarning = new DcWarning(); dcWarning.setStartDate(TwentyMinutesAgo); dcWarning.setEndDate(FifteenMinutesAgo); List radarList = dcWarningService.radarList(dcWarning); // 创建一个固定大小的线程池 ExecutorService executor = Executors.newFixedThreadPool(3); // 线程池大小 try { radarList.forEach(radar -> { if (radar != null && radar.getId() != null) { executor.submit(() -> processRadarEvent(radar, now)); } }); // 关闭线程池,并等待所有任务完成 executor.shutdown(); executor.awaitTermination(1, TimeUnit.HOURS); // 设置超时时间 } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 log.error("线程池关闭过程中发生中断", e); } finally { if (!executor.isTerminated()) { executor.shutdownNow(); // 强制关闭未完成的任务 } } } private void processRadarEvent(DcWarning radar, LocalDateTime now) { try { // 获取雷达事件视频 String baseUrl = dcWarningService.getRadarIncidentVideo(radar.getId()); System.out.println("雷达视频地址:" + baseUrl); if (baseUrl == null || baseUrl.isEmpty()) { log.warn("雷达事件ID {} 没有对应的视频URL", radar.getId()); return; } String ftpServer= configService.selectConfigByKey("FTP-IP");//密钥 int port= Integer.parseInt(configService.selectConfigByKey("FTP-PORT")); String username= configService.selectConfigByKey("FTP-USER");//密钥 String password= configService.selectConfigByKey("FPT-PASSWORD");//密钥 // String ftpServer = "192.168.3.1"; // int port = 21; // String username = "1911390090@qq.com"; // String password = "989878wxl"; String[] split = StringUtils.split(baseUrl, "/"); // 拼接文件名 String fileName = split[split.length - 1]; DateTimeFormatter dirFormatter = DateTimeFormatter.ofPattern("yyyyMMdd"); DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("HH"); String datePart = now.format(dirFormatter); String hourPart = now.format(hourFormatter); // 文件路径 String remoteFilePath = "/radar/" + datePart + "/" + hourPart; String download = directDownloadToFtp(baseUrl, ftpServer, port, username, password, remoteFilePath, fileName); DcWarning dcWarning1 = new DcWarning(); dcWarning1.setId(radar.getId()); dcWarning1.setRadarUrl(download); int i = dcWarningService.updateDcWarning(dcWarning1); if (i <= 0) { log.error("更新数据库失败,ID: {}", radar.getId()); } } catch (Exception e) { log.error("处理雷达事件ID {} 时发生异常", radar.getId(), e); } } public static String directDownloadToFtp(String baseUrl, String ftpServer, int port, String user, String pass, String remotePath, String fileName) throws IOException, URISyntaxException, InterruptedException { FTPClient ftpClient = new FTPClient(); HttpURLConnection httpConn = null; InputStream inputStream = null; String URL = "https://10.0.111.11/eventAi"; try { // 空格编码并构建URL String encodedUrl = encodeUriComponent(baseUrl); System.out.println("encodedUrl: " + encodedUrl); URI uri = new URI(encodedUrl); URL url = uri.toURL(); httpConn = (HttpURLConnection) url.openConnection(); int responseCode = httpConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { log.info("成功连接到HTTP服务器"); // 连接到FTP服务器 ftpClient.connect(ftpServer, port); boolean loginResult = ftpClient.login(user, pass); if (!loginResult) { log.info("FTP登录失败"); } log.info("成功登录到FTP服务器"); // 设置为二进制传输模式和被动模式 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); // 使用被动模式 // 创建输入流 inputStream = new BufferedInputStream(httpConn.getInputStream()); // 创建远程目录 if (!remotePath.isEmpty()) { // 将路径拆分为各个部分,逐级创建目录 for (String part : remotePath.split("/")) { if (!part.isEmpty()) { if (!ftpClient.changeWorkingDirectory(part)) { if (ftpClient.makeDirectory(part)) { log.info("成功创建远程目录: " + part); if (!ftpClient.changeWorkingDirectory(part)) { log.info("无法切换到新创建的远程目录: " + part); } } else { log.info("无法创建远程目录: " + part); } } } } // 确认最终工作目录 log.info("最终工作目录: " + ftpClient.printWorkingDirectory()); } // 上传文件到FTP服务器 boolean done = ftpClient.storeFile(new String(fileName.getBytes("GBK"),"ISO-8859-1"), inputStream); if (done) { log.info("文件上传成功"); return URL+ftpClient.printWorkingDirectory()+"/" + fileName; } else {// 文件上传失败 return null; } } else { throw new IOException("无法从HTTP服务器获取文件,响应码:" + responseCode); } } finally { // 关闭资源 closeQuietly(inputStream); if (httpConn != null) { httpConn.disconnect(); } if (ftpClient.isConnected()) { try { ftpClient.logout(); ftpClient.disconnect(); } catch (IOException ignored) { } } } } // 安全关闭流的方法 private static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (IOException ignored) { } } } // /* private static String encodeUriComponent(String component, java.nio.charset.Charset charset) { try { return java.net.URLEncoder.encode(component, charset.toString()) .replaceAll("\\+", "%20") // 将空格替换为 %20 .replaceAll("%2F", "/"); // 保留斜杠 } catch (Exception e) { throw new RuntimeException(e); } } */ //保留 URL 中的特殊字符如 : / 等 private static String encodeUriComponent(String component) { try { URI uri = new URI(null, null, component, null); return uri.toASCIIString(); } catch (URISyntaxException e) { throw new RuntimeException("URI编码错误", e); } } }