数据识别导出下载
This commit is contained in:
parent
62b8f1c934
commit
a579dd6418
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.bonus.web.controller.data;
|
||||||
|
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import com.bonus.common.domain.data.dto.ParamsDto;
|
||||||
|
import com.bonus.common.domain.data.vo.ExportTask;
|
||||||
|
import com.bonus.web.service.data.ExportExcelService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @className:ExportExcelController
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-12-30-17:02
|
||||||
|
* @version:1.0
|
||||||
|
* @description:识别数据导出-web层
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/device/data-recognition")
|
||||||
|
public class ExportExcelController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ExportExcelService exportService;
|
||||||
|
|
||||||
|
// 1. 启动导出任务
|
||||||
|
@GetMapping("/export")
|
||||||
|
public Map<String, Object> startExport(ParamsDto dto) {
|
||||||
|
// 启动异步任务,获取TaskId
|
||||||
|
String taskId = exportService.createExportTask(dto);
|
||||||
|
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
data.put("taskId", taskId);
|
||||||
|
return MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("code", 200)
|
||||||
|
.put("msg", "操作成功")
|
||||||
|
.put("data", data)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 轮询进度
|
||||||
|
@GetMapping("/progress") // 注意:如果前端封装是POST,这里改为PostMapping
|
||||||
|
public Map<String, Object> getProgress(@RequestParam("taskId") String taskId) {
|
||||||
|
ExportTask task = exportService.getTask(taskId);
|
||||||
|
if (task == null) {
|
||||||
|
return MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("code", 500)
|
||||||
|
.put("msg", "任务不存在")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("code", 200)
|
||||||
|
.put("data", task)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 下载文件
|
||||||
|
@GetMapping("/download")
|
||||||
|
public ResponseEntity<FileSystemResource> download(@RequestParam(required = false) String taskId) throws Exception {
|
||||||
|
ExportTask task = exportService.getTask(taskId);
|
||||||
|
|
||||||
|
if (task == null || !"completed".equals(task.getStatus())) {
|
||||||
|
throw new RuntimeException("文件未准备好");
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(task.getFilePath());
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new RuntimeException("文件已过期");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理中文文件名乱码
|
||||||
|
String encodedFileName = URLEncoder.encode(task.getFileName(), StandardCharsets.UTF_8.toString());
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add("Content-Disposition", "attachment; filename=" + encodedFileName);
|
||||||
|
headers.add("Access-Control-Expose-Headers", "Content-Disposition"); // 允许前端获取文件名
|
||||||
|
|
||||||
|
MediaType mediaType = task.getFileName().endsWith(".zip")
|
||||||
|
? MediaType.APPLICATION_OCTET_STREAM
|
||||||
|
: MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.headers(headers)
|
||||||
|
.contentLength(file.length())
|
||||||
|
.contentType(mediaType)
|
||||||
|
.body(new FileSystemResource(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,236 @@
|
||||||
|
package com.bonus.web.service.data;
|
||||||
|
|
||||||
|
import com.alibaba.excel.write.handler.SheetWriteHandler;
|
||||||
|
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||||
|
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
|
||||||
|
import com.bonus.common.domain.data.dto.ParamsDto;
|
||||||
|
import com.bonus.common.domain.data.vo.DataRecognitionExportVO;
|
||||||
|
import com.bonus.common.domain.data.vo.ExportTask;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.DateUnit;
|
||||||
|
import cn.hutool.core.util.ZipUtil;
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.alibaba.excel.ExcelWriter;
|
||||||
|
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别数据导出-业务逻辑层 (已修复 IO 关闭异常)
|
||||||
|
*/
|
||||||
|
@Service(value = "ExportExcelService")
|
||||||
|
@Slf4j
|
||||||
|
public class ExportExcelService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public String createExportTask(ParamsDto dto) {
|
||||||
|
String taskId = UUID.randomUUID().toString();
|
||||||
|
ExportTask task = new ExportTask();
|
||||||
|
task.setTaskId(taskId);
|
||||||
|
task.setStatus("running");
|
||||||
|
task.setProgress(0);
|
||||||
|
redisTemplate.opsForValue().set(REDIS_KEY_PREFIX + taskId, task, 24, TimeUnit.HOURS);
|
||||||
|
this.runAsyncExport(taskId, dto);
|
||||||
|
return taskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportTask getTask(String taskId) {
|
||||||
|
return (ExportTask) redisTemplate.opsForValue().get(REDIS_KEY_PREFIX + taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTaskInRedis(ExportTask task) {
|
||||||
|
redisTemplate.opsForValue().set(REDIS_KEY_PREFIX + task.getTaskId(), task, 24, TimeUnit.HOURS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async("taskExecutor")
|
||||||
|
public void runAsyncExport(String taskId, ParamsDto dto) {
|
||||||
|
try {
|
||||||
|
Date start = dto.getStartTime();
|
||||||
|
Date end = dto.getEndTime();
|
||||||
|
long dayDiff = DateUtil.between(start, end, DateUnit.DAY);
|
||||||
|
log.info("临时文件地址:{}", TEMP_PATH);
|
||||||
|
File tempDir = new File(TEMP_PATH);
|
||||||
|
if (!tempDir.exists()) tempDir.mkdirs();
|
||||||
|
|
||||||
|
File finalResultFile;
|
||||||
|
String downloadFileName;
|
||||||
|
|
||||||
|
if (dayDiff <= 0) {
|
||||||
|
downloadFileName = "数据识别_" + DateUtil.formatDate(start) + ".xlsx";
|
||||||
|
finalResultFile = new File(TEMP_PATH + taskId + "_" + downloadFileName);
|
||||||
|
generateExcel(finalResultFile, start, taskId, 0, 100);
|
||||||
|
} else {
|
||||||
|
List<File> subFiles = new ArrayList<>();
|
||||||
|
List<Date> dateRange = getDatesBetween(start, end);
|
||||||
|
int totalDays = dateRange.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < totalDays; i++) {
|
||||||
|
Date currentDate = dateRange.get(i);
|
||||||
|
File subFile = new File(TEMP_PATH + taskId + "_" + i + ".xlsx");
|
||||||
|
int startPct = (int) ((double) i / totalDays * 95);
|
||||||
|
int endPct = (int) ((double) (i + 1) / totalDays * 95);
|
||||||
|
generateExcel(subFile, currentDate, taskId, startPct, endPct);
|
||||||
|
subFiles.add(subFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatusProgress(taskId, 98, "running");
|
||||||
|
downloadFileName = "批量数据识别_" + DateUtil.formatDate(new Date()) + ".zip";
|
||||||
|
finalResultFile = new File(TEMP_PATH + taskId + ".zip");
|
||||||
|
ZipUtil.zip(finalResultFile, false, subFiles.toArray(new File[0]));
|
||||||
|
subFiles.forEach(File::delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportTask task = getTask(taskId);
|
||||||
|
if (task != null) {
|
||||||
|
task.setFilePath(finalResultFile.getAbsolutePath());
|
||||||
|
task.setFileName(downloadFileName);
|
||||||
|
task.setProgress(100);
|
||||||
|
task.setStatus("completed");
|
||||||
|
updateTaskInRedis(task);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("导出异步任务失败", e);
|
||||||
|
ExportTask task = getTask(taskId);
|
||||||
|
if (task != null) {
|
||||||
|
task.setStatus("failed");
|
||||||
|
task.setMessage("导出异常: " + e.getMessage());
|
||||||
|
updateTaskInRedis(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateExcel(File file, Date date, String taskId, int baseProgress, int maxProgress) {
|
||||||
|
// 定义冻结表头的拦截器
|
||||||
|
SheetWriteHandler freezePaneHandler = new SheetWriteHandler() {
|
||||||
|
@Override
|
||||||
|
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
|
||||||
|
// 参数说明:(列数冻结, 行数冻结, 右侧起始列, 下方起始行)
|
||||||
|
// 冻结第一行(表头):
|
||||||
|
writeSheetHolder.getSheet().createFreezePane(0, 1, 0, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ExcelWriter excelWriter = null;
|
||||||
|
try {
|
||||||
|
// 修复点1: 显式构建并管理 ExcelWriter,不完全依赖外部 try-with-resources
|
||||||
|
excelWriter = EasyExcel.write(file, DataRecognitionExportVO.class).registerWriteHandler(freezePaneHandler).build();
|
||||||
|
WriteSheet writeSheet = EasyExcel.writerSheet("识别数据").build();
|
||||||
|
|
||||||
|
int pageNo = 1;
|
||||||
|
int pageSize = 200; // 修复点2: 有图片时减小 pageSize (建议200),降低 IO 负载
|
||||||
|
long totalCount = mockDbCount(date);
|
||||||
|
int totalPages = (int) Math.ceil((double) totalCount / pageSize);
|
||||||
|
|
||||||
|
if (totalCount == 0) {
|
||||||
|
excelWriter.write(new ArrayList<>(), writeSheet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pageNo <= totalPages) {
|
||||||
|
List<DataRecognitionExportVO> dbDataList = mockDbQuery(date, pageNo, pageSize);
|
||||||
|
List<DataRecognitionExportVO> voList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < dbDataList.size(); i++) {
|
||||||
|
DataRecognitionExportVO entity = dbDataList.get(i);
|
||||||
|
DataRecognitionExportVO vo = new DataRecognitionExportVO();
|
||||||
|
|
||||||
|
// 属性映射
|
||||||
|
vo.setIndex((pageNo - 1) * pageSize + i + 1);
|
||||||
|
vo.setLocation(entity.getLocation());
|
||||||
|
vo.setRecognitionTime(entity.getRecognitionTime());
|
||||||
|
vo.setPlateColor(entity.getPlateColor());
|
||||||
|
vo.setVehicleType(entity.getVehicleType());
|
||||||
|
|
||||||
|
// 修复点3: 图片路径防御性处理,防止读取流失败中断整个写入
|
||||||
|
try {
|
||||||
|
String absolutePath = entity.getPhotoPath();
|
||||||
|
if (absolutePath != null && !absolutePath.isEmpty()) {
|
||||||
|
File imageFile = new File(absolutePath);
|
||||||
|
if (imageFile.exists() && imageFile.canRead() && imageFile.isFile()) {
|
||||||
|
vo.setPhotoFile(imageFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception imgEx) {
|
||||||
|
log.warn("行 {} 图片读取失败,跳过图片插入: {}", vo.getIndex(), imgEx.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
voList.add(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
excelWriter.write(voList, writeSheet);
|
||||||
|
|
||||||
|
// 更新进度
|
||||||
|
double fileRatio = (double) pageNo / totalPages;
|
||||||
|
int currentProgress = baseProgress + (int) (fileRatio * (maxProgress - baseProgress));
|
||||||
|
if (currentProgress >= 100) currentProgress = 99;
|
||||||
|
updateStatusProgress(taskId, currentProgress, "running");
|
||||||
|
|
||||||
|
voList.clear();
|
||||||
|
pageNo++;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Excel 生成核心逻辑失败: ", e);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
// 修复点4: 确保在 finally 中安全关闭,并捕获关闭时的异常
|
||||||
|
if (excelWriter != null) {
|
||||||
|
try {
|
||||||
|
excelWriter.finish(); // finish 内部会调用 close() 并清理 IO
|
||||||
|
} catch (Exception closeEx) {
|
||||||
|
log.error("关闭 ExcelWriter IO 失败: ", closeEx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatusProgress(String taskId, int progress, String status) {
|
||||||
|
ExportTask task = getTask(taskId);
|
||||||
|
if (task != null) {
|
||||||
|
task.setProgress(progress);
|
||||||
|
task.setStatus(status);
|
||||||
|
updateTaskInRedis(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Date> getDatesBetween(Date start, Date end) {
|
||||||
|
List<Date> list = new ArrayList<>();
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTime(start);
|
||||||
|
while (cal.getTime().getTime() <= end.getTime()) {
|
||||||
|
list.add(cal.getTime());
|
||||||
|
cal.add(Calendar.DATE, 1);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long mockDbCount(Date date) {
|
||||||
|
return 1000; // 模拟少量数据测试
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DataRecognitionExportVO> mockDbQuery(Date date, int pageNo, int pageSize) {
|
||||||
|
List<DataRecognitionExportVO> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < pageSize; i++) {
|
||||||
|
DataRecognitionExportVO vo = new DataRecognitionExportVO();
|
||||||
|
vo.setIndex((pageNo - 1) * pageSize + i + 1);
|
||||||
|
vo.setLocation("地点-" + i);
|
||||||
|
vo.setRecognitionTime(date);
|
||||||
|
vo.setPlateColor("蓝色");
|
||||||
|
vo.setVehicleType("轿车");
|
||||||
|
// 生产环境下确保此路径存在
|
||||||
|
vo.setPhotoPath("C:\\Users\\10488\\Desktop\\test_image.png");
|
||||||
|
list.add(vo);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,7 +40,7 @@ public class ExportService {
|
||||||
private static final long EXPIRE_TIME = 24;
|
private static final long EXPIRE_TIME = 24;
|
||||||
|
|
||||||
// 临时文件存放目录
|
// 临时文件存放目录
|
||||||
private static final String TEMP_DIR = System.getProperty("java.io.tmpdir") + "/export_tasks/";
|
private static final String TEMP_DIR = System.getProperty("java.io.tmpdir") + "/export_task/";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建任务并立即返回 TaskID
|
* 创建任务并立即返回 TaskID
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.bonus.web.task;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
/**
|
||||||
|
* @className:FileCleanupTask
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-12-30-17:07
|
||||||
|
* @version:1.0
|
||||||
|
* @description:文件清理任务类
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FileCleanupTask {
|
||||||
|
|
||||||
|
// 使用之前定义的临时目录路径
|
||||||
|
private static final String TEMP_PATH = System.getProperty("java.io.tmpdir") + File.separator + "export_task" + File.separator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每天凌晨 2 点执行清理任务
|
||||||
|
* cron 表达式: 秒 分 时 日 月 周
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 2 * * ?")
|
||||||
|
public void cleanupTempFiles() {
|
||||||
|
log.info("开始执行导出临时文件清理任务...");
|
||||||
|
File directory = new File(TEMP_PATH);
|
||||||
|
|
||||||
|
if (!directory.exists() || !directory.isDirectory()) {
|
||||||
|
log.info("临时目录不存在,跳过清理。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File[] files = directory.listFiles();
|
||||||
|
if (files == null || files.length == 0) {
|
||||||
|
log.info("临时目录为空,无需清理。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long currentTimeMillis = System.currentTimeMillis();
|
||||||
|
long twentyFourHoursMillis = TimeUnit.HOURS.toMillis(24);
|
||||||
|
int deleteCount = 0;
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
try {
|
||||||
|
// 获取文件属性中的创建时间
|
||||||
|
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||||
|
long creationTime = attr.creationTime().toMillis();
|
||||||
|
|
||||||
|
// 如果当前时间 - 创建时间 > 24小时,则删除
|
||||||
|
if (currentTimeMillis - creationTime > twentyFourHoursMillis) {
|
||||||
|
if (file.delete()) {
|
||||||
|
deleteCount++;
|
||||||
|
log.debug("已删除过期临时文件: {}", file.getName());
|
||||||
|
} else {
|
||||||
|
log.warn("无法删除文件: {}", file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理文件时出错: {}, 错误: {}", file.getName(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("清理任务完成,共删除 {} 个过期文件。", deleteCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -216,6 +216,13 @@
|
||||||
<version>5.8.11</version>
|
<version>5.8.11</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>easyexcel</artifactId>
|
||||||
|
<version>${easyexcel.version}</version>
|
||||||
|
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 连接池 -->
|
<!-- 连接池 -->
|
||||||
<!--<dependency>
|
<!--<dependency>
|
||||||
<groupId>com.rabbitmq</groupId>
|
<groupId>com.rabbitmq</groupId>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.bonus.common.domain.data.vo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||||
|
import com.alibaba.excel.annotation.write.style.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
|
||||||
|
import com.alibaba.excel.enums.poi.VerticalAlignmentEnum;
|
||||||
|
/**
|
||||||
|
* @className:DataRecognitionExportVO
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-12-30-17:10
|
||||||
|
* @version:1.0
|
||||||
|
* @description:识别数据导出-vo
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ContentRowHeight(80)
|
||||||
|
@HeadRowHeight(40) // 设置表头行高
|
||||||
|
// 设置表头居中
|
||||||
|
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER)
|
||||||
|
// 设置内容居中
|
||||||
|
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER)
|
||||||
|
public class DataRecognitionExportVO {
|
||||||
|
|
||||||
|
@ExcelProperty("序号")
|
||||||
|
@ColumnWidth(10)
|
||||||
|
private Integer index;
|
||||||
|
|
||||||
|
@ExcelProperty("识别地点")
|
||||||
|
@ColumnWidth(25)
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
@ExcelProperty("识别时间")
|
||||||
|
@ColumnWidth(20)
|
||||||
|
private Date recognitionTime;
|
||||||
|
|
||||||
|
@ExcelProperty("车牌颜色")
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private String plateColor;
|
||||||
|
|
||||||
|
@ExcelProperty("车辆类型")
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private String vehicleType;
|
||||||
|
|
||||||
|
@ExcelProperty("识别照片")
|
||||||
|
@ColumnWidth(25)
|
||||||
|
private File photoFile;
|
||||||
|
|
||||||
|
@ExcelIgnore
|
||||||
|
private String photoPath;
|
||||||
|
}
|
||||||
|
|
@ -18,4 +18,5 @@ public class ExportTask {
|
||||||
private String downloadUrl;
|
private String downloadUrl;
|
||||||
private String fileName;
|
private String fileName;
|
||||||
private String finalFilePath; // 服务器本地存储路径
|
private String finalFilePath; // 服务器本地存储路径
|
||||||
|
private String filePath; // 服务器本地临时文件路径
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
pom.xml
1
pom.xml
|
|
@ -42,6 +42,7 @@
|
||||||
<commons-fileupload.version>1.4</commons-fileupload.version>
|
<commons-fileupload.version>1.4</commons-fileupload.version>
|
||||||
<io.jsonwebtoken.version>0.9.1</io.jsonwebtoken.version>
|
<io.jsonwebtoken.version>0.9.1</io.jsonwebtoken.version>
|
||||||
<amqp-client.version>5.16.0</amqp-client.version>
|
<amqp-client.version>5.16.0</amqp-client.version>
|
||||||
|
<easyexcel.version>3.3.2</easyexcel.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<!-- 依赖声明 -->
|
<!-- 依赖声明 -->
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue