diff --git a/bonus-admin/pom.xml b/bonus-admin/pom.xml index 20f9926..261b1c2 100644 --- a/bonus-admin/pom.xml +++ b/bonus-admin/pom.xml @@ -77,6 +77,19 @@ com.bonus bonus-data + + + + com.bonus + bonus-algorithm + + + com.bonus + bonus-algorithm + 3.9.0 + compile + + diff --git a/bonus-admin/src/main/java/com/bonus/web/service/data/DeviceIdentificationService.java b/bonus-admin/src/main/java/com/bonus/web/service/data/DeviceIdentificationService.java index c1013d2..cdea817 100644 --- a/bonus-admin/src/main/java/com/bonus/web/service/data/DeviceIdentificationService.java +++ b/bonus-admin/src/main/java/com/bonus/web/service/data/DeviceIdentificationService.java @@ -2,16 +2,19 @@ package com.bonus.web.service.data; import com.bonus.common.core.domain.AjaxResult; import com.bonus.common.domain.data.dto.ParamsDto; +import com.bonus.common.domain.data.vo.DataRecognitionExportVO; import com.bonus.common.domain.data.vo.DeviceIdentificationDataCountVo; import com.bonus.common.domain.data.vo.DeviceIdentificationDataVo; import com.bonus.common.domain.data.vo.ImageRecord; import com.bonus.data.service.DIDeviceIdentificationService; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; +import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; @@ -35,18 +38,7 @@ public class DeviceIdentificationService { public List getDeviceIdentificationList(ParamsDto dto) { try { - if (dto.getStartTime() == null || dto.getEndTime() == null) { - // 获取今天的日期 - LocalDateTime now = LocalDateTime.now(); - // 设置开始时间为 00:00:00 - LocalDateTime startOfDay = now.with(LocalTime.MIN); - // 设置结束时间为 23:59:59 (也可以使用 LocalTime.MAX) - LocalDateTime endOfDay = now.with(LocalTime.MAX); - // 转换为 Date 赋值给 dto (如果你的字段类型是 Date) - ZoneId zone = ZoneId.systemDefault(); - dto.setStartTime(Date.from(startOfDay.atZone(zone).toInstant())); - dto.setEndTime(Date.from(endOfDay.atZone(zone).toInstant())); - } + dto = setTime(dto); List result = deviceIdentificationService.getDeviceIdentificationList(dto); // 处理图片-待实现 return result != null ? result : Collections.emptyList(); @@ -67,6 +59,7 @@ public class DeviceIdentificationService { public AjaxResult getDeviceIdentificationByDataDetail(ParamsDto dto) { DeviceIdentificationDataCountVo vo = null; try { + dto = setTime(dto); List result = deviceIdentificationService.getDeviceIdentificationList(dto); vo = calculateStatistics(result, dto.getStartTime(), dto.getEndTime()); @@ -117,6 +110,7 @@ public class DeviceIdentificationService { /** * 查询要下载的识别图片 + * * @param dto * @return List * @author cwchen @@ -124,19 +118,101 @@ public class DeviceIdentificationService { */ public List getImageData(ParamsDto dto) { try { - if (dto.getStartTime() == null || dto.getEndTime() == null) { - // 获取今天的日期 - LocalDateTime now = LocalDateTime.now(); - // 设置开始时间为 00:00:00 - LocalDateTime startOfDay = now.with(LocalTime.MIN); - // 设置结束时间为 23:59:59 (也可以使用 LocalTime.MAX) - LocalDateTime endOfDay = now.with(LocalTime.MAX); - // 转换为 Date 赋值给 dto (如果你的字段类型是 Date) - ZoneId zone = ZoneId.systemDefault(); - dto.setStartTime(Date.from(startOfDay.atZone(zone).toInstant())); - dto.setEndTime(Date.from(endOfDay.atZone(zone).toInstant())); - } + dto = setTime(dto); List result = deviceIdentificationService.getImageData(dto); + if(CollectionUtils.isEmpty(result)){ + return Collections.emptyList(); + }else{ + for (ImageRecord vo : result) { + // 1. 获取原始路径并提取最后一个 "_" 之后的部分 + String photoPath = vo.getUrl(); + String suffix = ""; + if (photoPath != null && photoPath.contains("_")) { + suffix = photoPath.substring(photoPath.lastIndexOf("_") + 1); + } + + // 2. 格式化日期(如果是 Date 类型需要格式化,如果是 String 则直接拼接) + // 假设 recognitionTime 是 Date 类型,建议格式化为 yyyyMMddHHmm + String timeStr = ""; + if (vo.getCreateTime() != null) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm"); + timeStr = sdf.format(vo.getCreateTime()); + } + + // 3. 拼接最终文件名:地点 + 时间 + 类型 + 路径后缀 + // 使用 Optional 或 StringUtils 处理 null 以防出现 "null" 字符串 + String fileName = String.format("%s_%s_%s_%s", + vo.getLocation() != null ? vo.getLocation() : "", + timeStr, + vo.getCarType() != null ? vo.getCarType() : "", + suffix); + + vo.setFileName(fileName); + } + return result; + } + + } catch (Exception e) { + log.error(e.toString(), e); + return Collections.emptyList(); + } + } + + /** + * 设置日期时间 + * + * @param dto + * @return ParamsDto + * @author cwchen + * @date 2026/1/8 14:21 + */ + public ParamsDto setTime(ParamsDto dto) { + if (dto.getStartTime() == null || dto.getEndTime() == null) { + // 获取今天的日期 + LocalDateTime now = LocalDateTime.now(); + // 设置开始时间为 00:00:00 + LocalDateTime startOfDay = now.with(LocalTime.MIN); + // 设置结束时间为 23:59:59 (也可以使用 LocalTime.MAX) + LocalDateTime endOfDay = now.with(LocalTime.MAX); + // 转换为 Date 赋值给 dto (如果你的字段类型是 Date) + ZoneId zone = ZoneId.systemDefault(); + dto.setStartTime(Date.from(startOfDay.atZone(zone).toInstant())); + dto.setEndTime(Date.from(endOfDay.atZone(zone).toInstant())); + } + return dto; + } + + /** + * 获取导出数据的数量 + * + * @param date + * @param endDate + * @return long + * @author cwchen + * @date 2026/1/8 15:20 + */ + public long getDataCount(Date date, Date endDate) { + try { + Long result = deviceIdentificationService.getDataCount(date, endDate); + return result != null ? result : 0L; + } catch (Exception e) { + log.error(e.toString(), e); + return 0L; + } + } + + /** + * 获取导出数据 + * + * @param date + * @param endDate + * @return long + * @author cwchen + * @date 2026/1/8 15:20 + */ + public List getExportDataList(Date date, Date endDate, int pageNo, int pageSize) { + try { + List result = deviceIdentificationService.getExportDataList(date, endDate,pageNo,pageSize); return result != null ? result : Collections.emptyList(); } catch (Exception e) { log.error(e.toString(), e); diff --git a/bonus-admin/src/main/java/com/bonus/web/service/data/ExportExcelService.java b/bonus-admin/src/main/java/com/bonus/web/service/data/ExportExcelService.java index 9dd4831..e54ed52 100644 --- a/bonus-admin/src/main/java/com/bonus/web/service/data/ExportExcelService.java +++ b/bonus-admin/src/main/java/com/bonus/web/service/data/ExportExcelService.java @@ -6,6 +6,7 @@ import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import com.bonus.common.config.BonusConfig; import com.bonus.common.domain.data.dto.ParamsDto; import com.bonus.common.domain.data.vo.DataRecognitionExportVO; import com.bonus.common.domain.data.vo.ExportTask; @@ -19,12 +20,16 @@ import org.springframework.scheduling.annotation.Async; import javax.annotation.Resource; import java.io.File; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; /** - * 识别数据导出-业务逻辑层 (多线程+防OOM版本) + * 识别数据导出-业务逻辑层 */ @Service(value = "ExportExcelService") @Slf4j @@ -33,6 +38,9 @@ public class ExportExcelService { @Resource private RedisTemplate redisTemplate; + @Resource(name = "DeviceIdentificationService") + private DeviceIdentificationService deviceIdentificationService; + // 自定义线程池:限制核心并发数为2,最大为3,防止大量图片IO导致内存溢出 private static final ExecutorService exportThreadPool = new ThreadPoolExecutor( 2, 3, 60L, TimeUnit.SECONDS, @@ -41,7 +49,8 @@ public class ExportExcelService { ); private static final String REDIS_KEY_PREFIX = "export:task:"; - private static final String TEMP_PATH = System.getProperty("java.io.tmpdir") + File.separator + "export_task" + File.separator; +// private static final String TEMP_PATH = System.getProperty("java.io.tmpdir") + File.separator + "export_task" + File.separator; + private static final String TEMP_PATH = BonusConfig.getLsFile() + File.separator + "export_task" + File.separator; public String createExportTask(ParamsDto dto) { String taskId = UUID.randomUUID().toString(); @@ -59,6 +68,8 @@ public class ExportExcelService { try { Date start = dto.getStartTime(); Date end = dto.getEndTime(); + LocalDate startLD = toLocalDate(start); + LocalDate endLD = toLocalDate(end); long dayDiff = DateUtil.between(start, end, DateUnit.DAY); File tempDir = new File(TEMP_PATH); @@ -71,7 +82,7 @@ public class ExportExcelService { // 单天任务:直接处理 downloadFileName = "数据识别_" + DateUtil.formatDate(start) + ".xlsx"; finalResultFile = new File(TEMP_PATH + taskId + "_" + downloadFileName); - generateExcel(finalResultFile, start, taskId, 0, 100, true); + generateExcel(finalResultFile, start, end, taskId, 0, 100, true); } else { // 多天任务:多线程处理 List dateRange = getDatesBetween(start, end); @@ -86,7 +97,26 @@ public class ExportExcelService { String subFileName = taskId + "_数据识别_" + DateUtil.formatDate(currentDate) + ".xlsx"; File subFile = new File(TEMP_PATH + subFileName); // 传入 false,表示子线程不直接更新 Redis 整体进度,由主线程负责更新 - generateExcel(subFile, currentDate, taskId, -1, -1, false); + LocalDate currentLD = toLocalDate(end); + // 进行逻辑判断 + boolean isSameAsStart = currentLD.equals(startLD); + boolean isSameAsEnd = currentLD.equals(endLD); + if (isSameAsStart && !isSameAsEnd) { + // 情况 1:仅与开始日期相同 + LocalDateTime endOfDay = currentLD.atTime(LocalTime.MAX); + Date endDate = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()); + generateExcel(subFile, start, endDate, taskId, -1, -1, false); + } else if (!isSameAsStart && isSameAsEnd) { + // 情况 2:仅与结束日期相同 + Date startDate = Date.from(currentLD.atStartOfDay(ZoneId.systemDefault()).toInstant()); + generateExcel(subFile, startDate, end, taskId, -1, -1, false); + } else if (!isSameAsStart && !isSameAsEnd) { + // 情况 3:都不同 + Date startDate = Date.from(currentLD.atStartOfDay(ZoneId.systemDefault()).toInstant()); + LocalDateTime endOfDay = currentLD.atTime(LocalTime.MAX); + Date endDate = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()); + generateExcel(subFile, startDate, endDate, taskId, -1, -1, false); + } subFiles.add(subFile); } catch (Exception e) { log.error("子任务执行失败: {}", currentDate, e); @@ -119,7 +149,7 @@ public class ExportExcelService { } } - private void generateExcel(File file, Date date, String taskId, int basePct, int maxPct, boolean updateRedis) { + private void generateExcel(File file, Date date, Date endDate, String taskId, int basePct, int maxPct, boolean updateRedis) { SheetWriteHandler freezePaneHandler = new SheetWriteHandler() { @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { @@ -138,7 +168,7 @@ public class ExportExcelService { int pageNo = 1; int pageSize = 150; // 多线程下进一步减小 pageSize 降低内存压力 - long totalCount = mockDbCount(date); + long totalCount = mockDbCount(date, endDate); int totalPages = (int) Math.ceil((double) totalCount / pageSize); if (totalCount == 0) { @@ -147,7 +177,7 @@ public class ExportExcelService { } while (pageNo <= totalPages) { - List dbDataList = mockDbQuery(date, pageNo, pageSize); + List dbDataList = mockDbQuery(date,endDate, pageNo, pageSize); List voList = new ArrayList<>(); for (int i = 0; i < dbDataList.size(); i++) { @@ -162,10 +192,11 @@ public class ExportExcelService { try { if (entity.getPhotoPath() != null) { - File img = new File(entity.getPhotoPath()); + File img = new File(BonusConfig.getProfile() + entity.getPhotoPath()); if (img.exists() && img.canRead()) vo.setPhotoFile(img); } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } voList.add(vo); } @@ -183,7 +214,11 @@ public class ExportExcelService { } } finally { if (excelWriter != null) { - try { excelWriter.finish(); } catch (Exception e) { log.error("IO Close Error", e); } + try { + excelWriter.finish(); + } catch (Exception e) { + log.error("IO Close Error", e); + } } } } @@ -238,16 +273,12 @@ public class ExportExcelService { return list; } - /*private long mockDbCount(Date date) { return 500; } - private List mockDbQuery(Date date, int p, int s) { - return new ArrayList<>(); // 替换为实际查询 - }*/ - private long mockDbCount(Date date) { - return 1000; // 模拟少量数据测试 + private long mockDbCount(Date date, Date endDate) { + return deviceIdentificationService.getDataCount(date,endDate); } - private List mockDbQuery(Date date, int pageNo, int pageSize) { - List list = new ArrayList<>(); + private List mockDbQuery(Date date,Date endDate, int pageNo, int pageSize) { + /* List list = new ArrayList<>(); for (int i = 0; i < pageSize; i++) { DataRecognitionExportVO vo = new DataRecognitionExportVO(); vo.setIndex((pageNo - 1) * pageSize + i + 1); @@ -258,7 +289,16 @@ public class ExportExcelService { // 生产环境下确保此路径存在 vo.setPhotoPath("C:\\Users\\10488\\Desktop\\test_image.png"); list.add(vo); + }*/ + List exportDataList = deviceIdentificationService.getExportDataList(date, endDate, pageNo, pageSize); + for (int i = 0; i < exportDataList.size(); i++) { + DataRecognitionExportVO dataRecognitionExportVO = exportDataList.get(i); + dataRecognitionExportVO.setIndex((pageNo - 1) * pageSize + i + 1); } - return list; + return exportDataList; + } + + public static LocalDate toLocalDate(Date date) { + return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); } } \ No newline at end of file diff --git a/bonus-admin/src/main/java/com/bonus/web/service/data/ExportService.java b/bonus-admin/src/main/java/com/bonus/web/service/data/ExportService.java index 1a2acaa..4d530fd 100644 --- a/bonus-admin/src/main/java/com/bonus/web/service/data/ExportService.java +++ b/bonus-admin/src/main/java/com/bonus/web/service/data/ExportService.java @@ -1,5 +1,6 @@ package com.bonus.web.service.data; +import com.bonus.common.config.BonusConfig; import com.bonus.common.domain.data.dto.ParamsDto; import com.bonus.common.domain.data.vo.ExportTask; import com.bonus.common.domain.data.vo.ImageRecord; @@ -40,7 +41,8 @@ public class ExportService { private static final long EXPIRE_TIME = 24; // 临时文件存放目录 - private static final String TEMP_DIR = System.getProperty("java.io.tmpdir") + "/export_task/"; +// private static final String TEMP_DIR = System.getProperty("java.io.tmpdir") + "/export_task/"; + private static final String TEMP_DIR = BonusConfig.getLsFile() + "/export_task/"; /** * 创建任务并立即返回 TaskID @@ -211,7 +213,7 @@ public class ExportService { for (ImageRecord img : images) { // 这里假设你的 ImageRecord.getUrl() 存储的是本地绝对路径,例如 /home/data/images/1.jpg // 如果字段名不同(比如叫 getFilePath),请自行替换 - String localPath = img.getUrl(); + String localPath = BonusConfig.getProfile() + img.getUrl(); if (localPath == null || localPath.isEmpty()) { continue; @@ -229,8 +231,10 @@ public class ExportService { try { // 1. 确定在压缩包内的文件名 (防止重名) - String originalFileName = imageFile.getName(); - String zipEntryName = UUID.randomUUID().toString().substring(0, 8) + "_" + originalFileName; +// String originalFileName = imageFile.getName(); + String originalFileName = img.getFileName(); +// String zipEntryName = UUID.randomUUID().toString().substring(0, 8) + "_" + originalFileName; + String zipEntryName = originalFileName; // 2. 创建 Zip 条目 ZipEntry entry = new ZipEntry(zipEntryName); diff --git a/bonus-admin/src/main/java/com/bonus/web/service/data/LineService.java b/bonus-admin/src/main/java/com/bonus/web/service/data/LineService.java index d2afe9a..c17444e 100644 --- a/bonus-admin/src/main/java/com/bonus/web/service/data/LineService.java +++ b/bonus-admin/src/main/java/com/bonus/web/service/data/LineService.java @@ -1,10 +1,14 @@ package com.bonus.web.service.data; +import com.bonus.algorithm.service.DrawLinesService; import com.bonus.common.core.domain.AjaxResult; +import com.bonus.common.domain.algorithm.dto.DrawLinesRequest; +import com.bonus.common.domain.algorithm.vo.DrawLinesResponse; import com.bonus.common.domain.data.dto.LineDto; import com.bonus.common.domain.data.dto.ParamsDto; import com.bonus.common.domain.data.vo.LineVo; import com.bonus.common.domain.data.vo.StreamVo; +import com.bonus.common.enums.ResultCode; import com.bonus.common.utils.ValidatorsUtils; import com.bonus.data.service.DILineService; import lombok.extern.slf4j.Slf4j; @@ -14,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import javax.annotation.Resource; +import java.util.Objects; /** * @className:LineService @@ -32,6 +37,9 @@ public class LineService { @Resource(name = "ValidatorsUtils") private ValidatorsUtils validatorsUtils; + @Resource(name = "DrawLinesService") + private DrawLinesService drawLinesService; + /** * 查询初始线的位置 * @param dto @@ -43,6 +51,13 @@ public class LineService { LineVo vo = null; try { vo = lineService.getLineDetail(dto); + DrawLinesRequest request = new DrawLinesRequest(); + request.setX1(Double.parseDouble(vo.getStartX())); + request.setY1(Double.parseDouble(vo.getStartY())); + request.setX2(Double.parseDouble(vo.getEndX())); + request.setY2(Double.parseDouble(vo.getEndY())); + log.info("视频流初始加载时设置线的坐标:{}",request); + DrawLinesResponse drawLinesResponse = drawLinesService.callDrawLinesService(request); } catch (Exception e) { log.error(e.toString(),e); } @@ -64,14 +79,30 @@ public class LineService { return AjaxResult.error(validResult); } try { - // 1.添加线的位置 - lineService.addLineData(dto); + DrawLinesRequest request = new DrawLinesRequest(); + request.setX1(Double.parseDouble(dto.getStartX())); + request.setY1(Double.parseDouble(dto.getStartY())); + request.setX2(Double.parseDouble(dto.getEndX())); + request.setY2(Double.parseDouble(dto.getEndY())); + log.info("设置线的坐标:{}",request); + DrawLinesResponse drawLinesResponse = drawLinesService.callDrawLinesService(request); + if (Objects.nonNull(drawLinesResponse)) { + if(drawLinesResponse.isSuccess()){ + // 画线接口调用成功添加线的位置 + lineService.addLineData(dto); + return AjaxResult.success(); + }else{ + return AjaxResult.error(drawLinesResponse.getMessage()); + } + }else{ + return AjaxResult.error(ResultCode.INTERFACE_CALL_FAILED.getMessage()); + } + } catch (Exception e) { log.error(e.toString(), e); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return AjaxResult.error(); } - return AjaxResult.success(); } /** diff --git a/bonus-admin/src/main/resources/application-algorithm.yml b/bonus-admin/src/main/resources/application-algorithm.yml new file mode 100644 index 0000000..de8e10e --- /dev/null +++ b/bonus-admin/src/main/resources/application-algorithm.yml @@ -0,0 +1,5 @@ +algorithm: + service: + url: http://192.168.0.108:8080/api/v1/video/setTripwire # 画线算法接口请求地址 + timeout: 30000 # 画线算法请求超时时间 + max-connections: 100 \ No newline at end of file diff --git a/bonus-algorithm/pom.xml b/bonus-algorithm/pom.xml new file mode 100644 index 0000000..7a37fc5 --- /dev/null +++ b/bonus-algorithm/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + com.bonus + bonus + 3.9.0 + + + bonus-algorithm + + + 算法调用模块 + + + + + + com.bonus + bonus-common + + + + + \ No newline at end of file diff --git a/bonus-algorithm/src/main/java/com/bonus/algorithm/service/DrawLinesService.java b/bonus-algorithm/src/main/java/com/bonus/algorithm/service/DrawLinesService.java new file mode 100644 index 0000000..682c2d6 --- /dev/null +++ b/bonus-algorithm/src/main/java/com/bonus/algorithm/service/DrawLinesService.java @@ -0,0 +1,205 @@ +package com.bonus.algorithm.service; + +import com.bonus.common.domain.algorithm.dto.DrawLinesRequest; +import com.bonus.common.domain.algorithm.vo.DrawLinesResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.IOException; + +/** + * @className: DrawLinesService + * @author: cwchen + * @date: 2026-01-08-9:26 + * @version: 1.0 + * @description: 画线接口调用-业务逻辑层 + */ +@Service(value = "DrawLinesService") +@Slf4j +public class DrawLinesService { + + private static final String UTF_8 = "UTF-8"; + + @Value("${algorithm.service.url}") + private String algorithmServiceUrl; + + @Value("${algorithm.service.timeout}") + private int timeout; + + private final CloseableHttpClient httpClient; + private final ObjectMapper objectMapper; + + public DrawLinesService() { + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(timeout) + .setSocketTimeout(timeout) + .setConnectionRequestTimeout(timeout) + .build(); + + this.httpClient = HttpClients.custom() + .setDefaultRequestConfig(requestConfig) + .build(); + this.objectMapper = new ObjectMapper(); + } + + /** + * 调用画线接口 + * + * @param drawLinesRequest 画线请求参数 + * @return 画线响应结果 + * @throws IOException 当画线服务调用失败时抛出 + */ + public DrawLinesResponse callDrawLinesService(DrawLinesRequest drawLinesRequest) throws IOException { + validateDrawLinesRequest(drawLinesRequest); + + HttpPost httpPost = null; + try { + httpPost = createHttpPost(drawLinesRequest); + return executeOcrRequest(httpPost); + } catch (IOException e) { + log.error("调用画线服务失败", e); + return null; + } finally { + cleanupResources(httpPost); + } + } + + /** + * 验证画线请求参数 + */ + private void validateDrawLinesRequest(DrawLinesRequest drawLinesRequest) { + if (drawLinesRequest == null) { + throw new IllegalArgumentException("画线请求参数不能为空"); + } + } + + /** + * 创建HTTP POST请求 + */ + private HttpPost createHttpPost(DrawLinesRequest drawLinesRequest) { + HttpPost httpPost = new HttpPost(algorithmServiceUrl); + + try { + // 将请求对象转换为JSON字符串 + String jsonRequest = convertToJson(drawLinesRequest); + + // 设置请求体为JSON + StringEntity entity = new StringEntity(jsonRequest, ContentType.APPLICATION_JSON); + httpPost.setEntity(entity); + + // 设置请求头 + httpPost.setHeader("Accept", "application/json"); + httpPost.setHeader("Content-Type", "application/json; charset=UTF-8"); + + } catch (Exception e) { + log.error("创建HTTP POST请求失败,请求参数: {}", drawLinesRequest, e); + throw new RuntimeException("创建HTTP POST请求失败", e); + } + + return httpPost; + } + + /** + * 将请求对象转换为JSON字符串 + */ + private String convertToJson(DrawLinesRequest request) throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.writeValueAsString(request); + } + + /** + * 执行画线请求 + */ + private DrawLinesResponse executeOcrRequest(HttpPost httpPost) throws IOException { + log.info("开始调用画线服务识别"); + + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + return processHttpResponse(response); + } + } + + /** + * 处理HTTP响应 + */ + private DrawLinesResponse processHttpResponse(CloseableHttpResponse response) throws IOException { + log.info("响应内容:{}",response); + int statusCode = response.getStatusLine().getStatusCode(); + String responseBody = getResponseBody(response); + + log.info("画线服务响应状态: {}", statusCode); + log.debug("画线服务响应内容: {}", responseBody); // 改为debug级别,避免日志过大 + + // 检查HTTP状态码 + if (statusCode != 200) { + log.error("画线服务HTTP请求失败,状态码: {}, 响应: {}", statusCode, responseBody); + return null; + } + + DrawLinesResponse drawLinesResponse = parseResponseBody(responseBody); + return drawLinesResponse; + } + + /** + * 获取响应体 + */ + private String getResponseBody(CloseableHttpResponse response) throws IOException { + HttpEntity entity = response.getEntity(); + return EntityUtils.toString(entity, UTF_8); + } + + /** + * 解析响应体 + */ + private DrawLinesResponse parseResponseBody(String responseBody) throws IOException { + try { + return objectMapper.readValue(responseBody, DrawLinesResponse.class); + } catch (IOException e) { + log.error("解析画线请求响应失败,响应内容: {}", responseBody, e); + return null; + } + } + + /** + * 清理资源 + */ + private void cleanupResources(HttpPost httpPost) { + // 清理HTTP连接 + if (httpPost != null) { + httpPost.releaseConnection(); + } + + } + + /** + * 关闭HTTP客户端 + */ + public void close() { + try { + if (httpClient != null) { + httpClient.close(); + log.info("画线服务HTTP客户端已关闭"); + } + } catch (IOException e) { + log.error("关闭HTTP客户端失败", e); + } + } + + /** + * 销毁方法,用于Spring容器关闭时调用 + */ + public void destroy() { + close(); + } +} diff --git a/bonus-common/src/main/java/com/bonus/common/config/BonusConfig.java b/bonus-common/src/main/java/com/bonus/common/config/BonusConfig.java index 3a31931..a6baf18 100644 --- a/bonus-common/src/main/java/com/bonus/common/config/BonusConfig.java +++ b/bonus-common/src/main/java/com/bonus/common/config/BonusConfig.java @@ -24,6 +24,9 @@ public class BonusConfig /** 上传路径 */ private static String profile; + /** 临时文件路径 */ + private static String lsFile; + /** 获取地址开关 */ private static boolean addressEnabled; @@ -119,4 +122,12 @@ public class BonusConfig { return getProfile() + "/upload"; } + + public static String getLsFile() { + return lsFile; + } + + public static void setLsFile(String lsFile) { + BonusConfig.lsFile = lsFile; + } } diff --git a/bonus-common/src/main/java/com/bonus/common/domain/algorithm/dto/DrawLinesRequest.java b/bonus-common/src/main/java/com/bonus/common/domain/algorithm/dto/DrawLinesRequest.java new file mode 100644 index 0000000..0673c01 --- /dev/null +++ b/bonus-common/src/main/java/com/bonus/common/domain/algorithm/dto/DrawLinesRequest.java @@ -0,0 +1,34 @@ +package com.bonus.common.domain.algorithm.dto; + +import lombok.Data; + + +/** + * @className:DrawLinesRequest + * @author:cwchen + * @date:2026-01-08-9:35 + * @version:1.0 + * @description:画线调用请求-实体 + */ +@Data +public class DrawLinesRequest { + + /**起点坐标x*/ + private double x1; + /**起点坐标y*/ + private double y1; + /**终点坐标x*/ + private double x2; + /**终点坐标Y*/ + private double y2; + + public DrawLinesRequest(double x1, double y1, double x2, double y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + public DrawLinesRequest() { + } +} diff --git a/bonus-common/src/main/java/com/bonus/common/domain/algorithm/vo/DrawLinesResponse.java b/bonus-common/src/main/java/com/bonus/common/domain/algorithm/vo/DrawLinesResponse.java new file mode 100644 index 0000000..c618a1b --- /dev/null +++ b/bonus-common/src/main/java/com/bonus/common/domain/algorithm/vo/DrawLinesResponse.java @@ -0,0 +1,33 @@ +package com.bonus.common.domain.algorithm.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + + +/** + * @className: DrawLinesResponse + * @author: cwchen + * @date: 2026-01-08-9:35 + * @version: 1.0 + * @description: 画线调用响应-实体 + */ +@Data +public class DrawLinesResponse { + + @JsonProperty("code") + private Integer code; // 状态码 + + @JsonProperty("message") + private String message; // 消息 + + @JsonProperty("status") + private String status; + + public boolean isSuccess() { + return Objects.equals(status, "success") && code != null && code == 200; + } +} diff --git a/bonus-common/src/main/java/com/bonus/common/domain/data/vo/ImageRecord.java b/bonus-common/src/main/java/com/bonus/common/domain/data/vo/ImageRecord.java index 64c1e26..c33723d 100644 --- a/bonus-common/src/main/java/com/bonus/common/domain/data/vo/ImageRecord.java +++ b/bonus-common/src/main/java/com/bonus/common/domain/data/vo/ImageRecord.java @@ -17,6 +17,10 @@ import java.util.Date; public class ImageRecord { private String url; + private String location; + private String identificationTime; + private String carType; + private String fileName; @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd") private Date createTime; diff --git a/bonus-common/src/main/java/com/bonus/common/enums/ResultCode.java b/bonus-common/src/main/java/com/bonus/common/enums/ResultCode.java new file mode 100644 index 0000000..7949a75 --- /dev/null +++ b/bonus-common/src/main/java/com/bonus/common/enums/ResultCode.java @@ -0,0 +1,34 @@ +package com.bonus.common.enums; + +/** + * @className:ResultCode + * @author:cwchen + * @date:2026-01-08-9:59 + * @version:1.0 + * @description:异常枚举 + */ +public enum ResultCode { + + SUCCESS(200, "操作成功"), + INTERFACE_CALL_FAILED(10001, "接口调用失败"), + SYSTEM_ERROR(500, "系统繁忙,请稍后再试"); + + private final int code; + private final String message; + + // 构造方法 + ResultCode(int code, String message) { + this.code = code; + this.message = message; + } + + // 获取错误码 + public int getCode() { + return code; + } + + // 获取错误信息 + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/bonus-data/src/main/java/com/bonus/data/mapper/DIDeviceIdentificationMapper.java b/bonus-data/src/main/java/com/bonus/data/mapper/DIDeviceIdentificationMapper.java index 61a9fb7..e76a2e0 100644 --- a/bonus-data/src/main/java/com/bonus/data/mapper/DIDeviceIdentificationMapper.java +++ b/bonus-data/src/main/java/com/bonus/data/mapper/DIDeviceIdentificationMapper.java @@ -1,10 +1,13 @@ package com.bonus.data.mapper; import com.bonus.common.domain.data.dto.ParamsDto; +import com.bonus.common.domain.data.vo.DataRecognitionExportVO; import com.bonus.common.domain.data.vo.DeviceIdentificationDataVo; import com.bonus.common.domain.data.vo.ImageRecord; +import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; +import java.util.Date; import java.util.List; /** @@ -19,6 +22,7 @@ public interface DIDeviceIdentificationMapper { /** * 查询识别图片 + * * @param dto * @return List * @author cwchen @@ -28,10 +32,34 @@ public interface DIDeviceIdentificationMapper { /** * 查询要下载的图片 + * * @param dto * @return List * @author cwchen * @date 2025/12/26 10:41 */ List getImageData(ParamsDto dto); + + /** + * 获取导出数据的数量 + * + * @param date + * @param endDate + * @return Long + * @author cwchen + * @date 2026/1/8 15:24 + */ + Long getDataCount(@Param("startDate") Date date,@Param("endDate") Date endDate); + + /** + * 获取导出数据 + * @param date + * @param endDate + * @param pageNo + * @param pageSize + * @return List + * @author cwchen + * @date 2026/1/8 15:24 + */ + List getExportDataList(@Param("startDate") Date date,@Param("endDate") Date endDate,@Param("pageNo") int pageNo,@Param("pageSize") int pageSize); } diff --git a/bonus-data/src/main/java/com/bonus/data/service/DIDeviceIdentificationService.java b/bonus-data/src/main/java/com/bonus/data/service/DIDeviceIdentificationService.java index 4935a7d..c8b52ab 100644 --- a/bonus-data/src/main/java/com/bonus/data/service/DIDeviceIdentificationService.java +++ b/bonus-data/src/main/java/com/bonus/data/service/DIDeviceIdentificationService.java @@ -2,10 +2,12 @@ package com.bonus.data.service; import com.bonus.common.domain.data.dto.ParamsDto; import com.bonus.common.domain.data.vo.AlarmVo; +import com.bonus.common.domain.data.vo.DataRecognitionExportVO; import com.bonus.common.domain.data.vo.DeviceIdentificationDataVo; import com.bonus.common.domain.data.vo.ImageRecord; import org.springframework.stereotype.Service; +import java.util.Date; import java.util.List; /** @@ -34,4 +36,24 @@ public interface DIDeviceIdentificationService { * @date 2025/12/26 10:38 */ List getImageData(ParamsDto dto); + + /** + * 获取导出数据的数量 + * @param date + * @param endDate + * @return Long + * @author cwchen + * @date 2026/1/8 15:22 + */ + Long getDataCount(Date date, Date endDate); + + /** + * 获取导出数据 + * @param date + * @param endDate + * @return List + * @author cwchen + * @date 2026/1/8 15:22 + */ + List getExportDataList(Date date, Date endDate,int pageNo, int pageSize); } diff --git a/bonus-data/src/main/java/com/bonus/data/service/impl/DDeviceIdentificationServiceImpl.java b/bonus-data/src/main/java/com/bonus/data/service/impl/DDeviceIdentificationServiceImpl.java index 6363cca..c3c739e 100644 --- a/bonus-data/src/main/java/com/bonus/data/service/impl/DDeviceIdentificationServiceImpl.java +++ b/bonus-data/src/main/java/com/bonus/data/service/impl/DDeviceIdentificationServiceImpl.java @@ -2,6 +2,7 @@ package com.bonus.data.service.impl; import com.bonus.common.domain.data.dto.ParamsDto; import com.bonus.common.domain.data.vo.AlarmVo; +import com.bonus.common.domain.data.vo.DataRecognitionExportVO; import com.bonus.common.domain.data.vo.DeviceIdentificationDataVo; import com.bonus.common.domain.data.vo.ImageRecord; import com.bonus.data.mapper.DIDeviceIdentificationMapper; @@ -10,6 +11,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Collections; +import java.util.Date; import java.util.List; /** @@ -34,4 +36,14 @@ public class DDeviceIdentificationServiceImpl implements DIDeviceIdentificationS public List getImageData(ParamsDto dto) { return diDeviceIdentificationMapper.getImageData(dto); } + + @Override + public Long getDataCount(Date date, Date endDate) { + return diDeviceIdentificationMapper.getDataCount(date,endDate); + } + + @Override + public List getExportDataList(Date date, Date endDate,int pageNo, int pageSize) { + return diDeviceIdentificationMapper.getExportDataList(date,endDate,pageNo,pageSize); + } } diff --git a/bonus-data/src/main/resources/mapper/DDeviceIdentificationMapper.xml b/bonus-data/src/main/resources/mapper/DDeviceIdentificationMapper.xml index 3b3a668..54eb164 100644 --- a/bonus-data/src/main/resources/mapper/DDeviceIdentificationMapper.xml +++ b/bonus-data/src/main/resources/mapper/DDeviceIdentificationMapper.xml @@ -35,12 +35,14 @@ + + + + + + diff --git a/bonus-framework/pom.xml b/bonus-framework/pom.xml index 4c0be4c..89c261e 100644 --- a/bonus-framework/pom.xml +++ b/bonus-framework/pom.xml @@ -59,10 +59,6 @@ bonus-system - - com.bonus - bonus-file - diff --git a/bonus-quartz/src/main/java/com/bonus/quartz/task/FileCleanupTask.java b/bonus-quartz/src/main/java/com/bonus/quartz/task/FileCleanupTask.java index 3774818..7ed4c90 100644 --- a/bonus-quartz/src/main/java/com/bonus/quartz/task/FileCleanupTask.java +++ b/bonus-quartz/src/main/java/com/bonus/quartz/task/FileCleanupTask.java @@ -1,4 +1,5 @@ package com.bonus.quartz.task; +import com.bonus.common.config.BonusConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -22,7 +23,8 @@ import java.util.concurrent.TimeUnit; public class FileCleanupTask { // 使用之前定义的临时目录路径 - private static final String TEMP_PATH = System.getProperty("java.io.tmpdir") + File.separator + "export_task" + File.separator; +// private static final String TEMP_PATH = System.getProperty("java.io.tmpdir") + File.separator + "export_task" + File.separator; + private static final String TEMP_PATH = BonusConfig.getLsFile() + File.separator + "export_task" + File.separator; /** * 每天凌晨 2 点执行清理任务 diff --git a/pom.xml b/pom.xml index 06b686c..baef741 100644 --- a/pom.xml +++ b/pom.xml @@ -251,6 +251,7 @@ bonus-common bonus-ocr bonus-data + bonus-algorithm pom