fix: 导入过鱼数据初版
This commit is contained in:
parent
5854c1b65b
commit
bac8bd9b25
@ -7,8 +7,10 @@ import com.yfd.platform.config.ResponseResult;
|
|||||||
import com.yfd.platform.data.domain.FishDraftData;
|
import com.yfd.platform.data.domain.FishDraftData;
|
||||||
import com.yfd.platform.data.domain.FishImportRequest;
|
import com.yfd.platform.data.domain.FishImportRequest;
|
||||||
import com.yfd.platform.data.domain.FishImportResult;
|
import com.yfd.platform.data.domain.FishImportResult;
|
||||||
|
import com.yfd.platform.data.domain.ImportTask;
|
||||||
import com.yfd.platform.data.service.IFishDraftDataService;
|
import com.yfd.platform.data.service.IFishDraftDataService;
|
||||||
import com.yfd.platform.data.service.IFishImportService;
|
import com.yfd.platform.data.service.IFishImportService;
|
||||||
|
import com.yfd.platform.data.service.IImportTaskService;
|
||||||
import com.yfd.platform.utils.KendoUtil;
|
import com.yfd.platform.utils.KendoUtil;
|
||||||
import com.yfd.platform.utils.QgcQueryWrapperUtil;
|
import com.yfd.platform.utils.QgcQueryWrapperUtil;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@ -20,6 +22,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -37,18 +40,8 @@ public class FishDraftDataController {
|
|||||||
@Resource
|
@Resource
|
||||||
private IFishImportService fishImportService;
|
private IFishImportService fishImportService;
|
||||||
|
|
||||||
// @GetMapping("/page")
|
@Resource
|
||||||
// @Operation(summary = "分页查询过鱼数据")
|
private IImportTaskService importTaskService;
|
||||||
// public ResponseResult queryPageList(
|
|
||||||
// @RequestParam(defaultValue = "1") Integer current,
|
|
||||||
// @RequestParam(defaultValue = "10") Integer size,
|
|
||||||
// @RequestParam(required = false) String stcd,
|
|
||||||
// @RequestParam(required = false) String status,
|
|
||||||
// @RequestParam(required = false) String ftp) {
|
|
||||||
// Page<FishDraftData> page = new Page<>(current, size);
|
|
||||||
// Page<FishDraftData> result = fishDraftDataService.queryPageList(page, stcd, status, ftp);
|
|
||||||
// return ResponseResult.successData(result);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@PostMapping("/page")
|
@PostMapping("/page")
|
||||||
@Operation(summary = "分页查询过鱼数据")
|
@Operation(summary = "分页查询过鱼数据")
|
||||||
@ -71,7 +64,7 @@ public class FishDraftDataController {
|
|||||||
|
|
||||||
@GetMapping("/getById")
|
@GetMapping("/getById")
|
||||||
@Operation(summary = "根据ID查询")
|
@Operation(summary = "根据ID查询")
|
||||||
public ResponseResult getById(@RequestParam Long id) {
|
public ResponseResult getById(@RequestParam String id) {
|
||||||
FishDraftData fishDraftData = fishDraftDataService.getById(id);
|
FishDraftData fishDraftData = fishDraftDataService.getById(id);
|
||||||
return ResponseResult.successData(fishDraftData);
|
return ResponseResult.successData(fishDraftData);
|
||||||
}
|
}
|
||||||
@ -177,38 +170,82 @@ public class FishDraftDataController {
|
|||||||
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
|
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/importExcel")
|
@PostMapping("/importZip")
|
||||||
@Operation(summary = "导入Excel过鱼数据")
|
@Operation(summary = "导入ZIP过鱼数据(每个用户同时只能进行一次导入)")
|
||||||
public ResponseResult importExcel(@RequestParam("file") MultipartFile file,
|
public ResponseResult importZip(@RequestParam("file") MultipartFile file,
|
||||||
@RequestParam(required = false) String importNo,
|
@RequestParam String uploadUserId) {
|
||||||
@RequestParam(required = false) Long uploadUserId) {
|
|
||||||
if (file == null || file.isEmpty()) {
|
if (file == null || file.isEmpty()) {
|
||||||
return ResponseResult.error("请上传文件");
|
return ResponseResult.error("请上传文件");
|
||||||
}
|
}
|
||||||
String fileName = file.getOriginalFilename();
|
String fileName = file.getOriginalFilename();
|
||||||
if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
|
if (fileName == null || (!fileName.endsWith(".zip"))) {
|
||||||
return ResponseResult.error("请上传Excel文件(.xlsx或.xls)");
|
return ResponseResult.error("请上传ZIP文件(.zip)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (importTaskService.hasImportingTask(uploadUserId)) {
|
||||||
|
return ResponseResult.error("您有正在进行的导入任务,请等待完成后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
String importNo = "IMP" + System.currentTimeMillis();
|
||||||
|
String taskId = UUID.randomUUID().toString();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
ImportTask task = new ImportTask();
|
||||||
|
task.setId(taskId);
|
||||||
|
task.setImportNo(importNo);
|
||||||
|
task.setBizType("FISH");
|
||||||
|
task.setFileName(fileName);
|
||||||
|
task.setFileSize(file.getSize());
|
||||||
|
task.setStatus("UPLOADED");
|
||||||
|
task.setUploadUserId(uploadUserId);
|
||||||
|
task.setUploadTime(new Date());
|
||||||
|
importTaskService.save(task);
|
||||||
|
|
||||||
FishImportRequest request = new FishImportRequest();
|
FishImportRequest request = new FishImportRequest();
|
||||||
request.setFilePath(file.getOriginalFilename());
|
|
||||||
request.setImportNo(importNo);
|
request.setImportNo(importNo);
|
||||||
request.setUploadUserId(uploadUserId);
|
request.setUploadUserId(uploadUserId);
|
||||||
request.setBizType("FISH");
|
request.setBizType("FISH");
|
||||||
FishImportResult result = fishImportService.parseAndMapExcel(request, file.getInputStream());
|
|
||||||
|
FishImportResult result = fishImportService.parseAndMapZip(file, uploadUserId);
|
||||||
|
|
||||||
|
importTaskService.updateStatus(taskId, "VALIDATED", null);
|
||||||
|
importTaskService.updateProgress(taskId, result.getTotalCount(), result.getSuccessCount(), result.getFailedCount());
|
||||||
|
|
||||||
return ResponseResult.successData(result);
|
return ResponseResult.successData(result);
|
||||||
} catch (IOException e) {
|
|
||||||
return ResponseResult.error("文件读取失败: " + e.getMessage());
|
} catch (Exception e) {
|
||||||
|
importTaskService.markFailed(taskId, "导入失败: " + e.getMessage());
|
||||||
|
return ResponseResult.error("导入失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/importExcelFromPath")
|
@PostMapping("/cancelImport")
|
||||||
@Operation(summary = "从文件路径导入Excel过鱼数据")
|
@Operation(summary = "取消导入任务")
|
||||||
public ResponseResult importExcelFromPath(@RequestBody FishImportRequest request) {
|
public ResponseResult cancelImport(@RequestParam String taskId,
|
||||||
if (request.getFilePath() == null || request.getFilePath().isEmpty()) {
|
@RequestParam String operatorId) {
|
||||||
return ResponseResult.error("请提供文件路径");
|
boolean result = importTaskService.cancelTask(taskId, operatorId);
|
||||||
|
return result ? ResponseResult.success("取消成功") : ResponseResult.error("取消失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/checkImportStatus")
|
||||||
|
@Operation(summary = "检查用户导入状态")
|
||||||
|
public ResponseResult checkImportStatus(@RequestParam String uploadUserId) {
|
||||||
|
boolean hasTask = importTaskService.hasImportingTask(uploadUserId);
|
||||||
|
ImportTask currentTask = importTaskService.getCurrentTaskByUserId(uploadUserId);
|
||||||
|
return ResponseResult.successData(java.util.Map.of(
|
||||||
|
"hasImportingTask", hasTask,
|
||||||
|
"currentTask", currentTask
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/cleanupTemp")
|
||||||
|
@Operation(summary = "清理临时文件")
|
||||||
|
public ResponseResult cleanupTemp(@RequestParam String tempDir) {
|
||||||
|
try {
|
||||||
|
com.yfd.platform.data.utils.ZipFileUtil.cleanupTempDir(tempDir);
|
||||||
|
return ResponseResult.success("清理成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseResult.error("清理失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
FishImportResult result = fishImportService.parseAndMapExcelFromPath(request);
|
|
||||||
return ResponseResult.successData(result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ public class FishImportRequest implements Serializable {
|
|||||||
|
|
||||||
private String bizType = "FISH";
|
private String bizType = "FISH";
|
||||||
|
|
||||||
private Long uploadUserId;
|
private String uploadUserId;
|
||||||
|
|
||||||
private Map<String, String> columnMapping;
|
private Map<String, String> columnMapping;
|
||||||
}
|
}
|
||||||
@ -3,7 +3,9 @@ package com.yfd.platform.data.domain;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class FishImportResult {
|
public class FishImportResult {
|
||||||
@ -11,6 +13,11 @@ public class FishImportResult {
|
|||||||
private List<FishImportRow> successRows;
|
private List<FishImportRow> successRows;
|
||||||
private List<FishImportRow> failedRows;
|
private List<FishImportRow> failedRows;
|
||||||
private List<String> unrecognizedFields;
|
private List<String> unrecognizedFields;
|
||||||
|
private Map<String, String> imageFiles;
|
||||||
|
private Map<String, String> videoFiles;
|
||||||
|
private String tempDir;
|
||||||
|
private String excelFileName;
|
||||||
|
private String excelFilePath;
|
||||||
private int totalCount;
|
private int totalCount;
|
||||||
private int successCount;
|
private int successCount;
|
||||||
private int failedCount;
|
private int failedCount;
|
||||||
@ -20,6 +27,8 @@ public class FishImportResult {
|
|||||||
this.successRows = new ArrayList<>();
|
this.successRows = new ArrayList<>();
|
||||||
this.failedRows = new ArrayList<>();
|
this.failedRows = new ArrayList<>();
|
||||||
this.unrecognizedFields = new ArrayList<>();
|
this.unrecognizedFields = new ArrayList<>();
|
||||||
|
this.imageFiles = new LinkedHashMap<>();
|
||||||
|
this.videoFiles = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@ -36,7 +36,17 @@ public interface ImportTaskMapper extends BaseMapper<ImportTask> {
|
|||||||
* 根据上传人查询
|
* 根据上传人查询
|
||||||
*/
|
*/
|
||||||
@Select("SELECT * FROM IMPORT_TASK WHERE UPLOAD_USER_ID = #{uploadUserId} ORDER BY CREATED_AT DESC")
|
@Select("SELECT * FROM IMPORT_TASK WHERE UPLOAD_USER_ID = #{uploadUserId} ORDER BY CREATED_AT DESC")
|
||||||
List<ImportTask> selectByUploadUserId(@Param("uploadUserId") Long uploadUserId);
|
List<ImportTask> selectByUploadUserId(@Param("uploadUserId") String uploadUserId);
|
||||||
|
|
||||||
|
@Select("<script>" +
|
||||||
|
"SELECT * FROM IMPORT_TASK WHERE UPLOAD_USER_ID = #{uploadUserId} AND STATUS IN " +
|
||||||
|
"<foreach item='status' collection='statuses' open='(' separator=',' close=')'>" +
|
||||||
|
"#{status}" +
|
||||||
|
"</foreach>" +
|
||||||
|
" ORDER BY CREATED_AT DESC" +
|
||||||
|
"</script>")
|
||||||
|
List<ImportTask> selectByUserIdAndStatuses(@Param("uploadUserId") String uploadUserId,
|
||||||
|
@Param("statuses") List<String> statuses);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询过期的任务
|
* 查询过期的任务
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.yfd.platform.data.service;
|
|||||||
|
|
||||||
import com.yfd.platform.data.domain.FishImportRequest;
|
import com.yfd.platform.data.domain.FishImportRequest;
|
||||||
import com.yfd.platform.data.domain.FishImportResult;
|
import com.yfd.platform.data.domain.FishImportResult;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
@ -12,20 +13,9 @@ import java.io.InputStream;
|
|||||||
*/
|
*/
|
||||||
public interface IFishImportService {
|
public interface IFishImportService {
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析过鱼数据Excel文件并映射字段
|
|
||||||
*
|
|
||||||
* @param request 导入请求
|
|
||||||
* @param inputStream Excel文件输入流
|
|
||||||
* @return 解析结果
|
|
||||||
*/
|
|
||||||
FishImportResult parseAndMapExcel(FishImportRequest request, InputStream inputStream);
|
FishImportResult parseAndMapExcel(FishImportRequest request, InputStream inputStream);
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析过鱼数据Excel文件(从文件路径)
|
|
||||||
*
|
|
||||||
* @param request 导入请求
|
|
||||||
* @return 解析结果
|
|
||||||
*/
|
|
||||||
FishImportResult parseAndMapExcelFromPath(FishImportRequest request);
|
FishImportResult parseAndMapExcelFromPath(FishImportRequest request);
|
||||||
|
|
||||||
|
FishImportResult parseAndMapZip(MultipartFile file, String uploadUserId);
|
||||||
}
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package com.yfd.platform.data.service;
|
||||||
|
|
||||||
|
import com.yfd.platform.data.domain.FishImportResult;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 过鱼数据ZIP导入服务接口
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface IFishZipImportService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析过鱼数据ZIP文件并映射字段
|
||||||
|
*
|
||||||
|
* @param importTaskId 导入任务ID
|
||||||
|
* @param inputStream ZIP文件输入流
|
||||||
|
* @param uploadUserId 上传用户ID
|
||||||
|
* @return 解析结果
|
||||||
|
*/
|
||||||
|
FishImportResult parseAndMapZip(String importTaskId, InputStream inputStream, String uploadUserId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否有正在进行的导入任务
|
||||||
|
*
|
||||||
|
* @param uploadUserId 上传用户ID
|
||||||
|
* @return true表示有任务在进行,false表示可以开始新任务
|
||||||
|
*/
|
||||||
|
boolean hasImportingTask(String uploadUserId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消导入任务
|
||||||
|
*
|
||||||
|
* @param importTaskId 任务ID
|
||||||
|
* @param operatorId 操作人ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean cancelImportTask(String importTaskId, String operatorId);
|
||||||
|
}
|
||||||
@ -62,4 +62,19 @@ public interface IImportTaskService extends IService<ImportTask> {
|
|||||||
* 删除过期任务
|
* 删除过期任务
|
||||||
*/
|
*/
|
||||||
boolean deleteExpiredTasks();
|
boolean deleteExpiredTasks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否有正在进行的导入任务
|
||||||
|
*/
|
||||||
|
boolean hasImportingTask(String uploadUserId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消导入任务
|
||||||
|
*/
|
||||||
|
boolean cancelTask(String taskId, String operatorId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户当前正在进行的导入任务
|
||||||
|
*/
|
||||||
|
ImportTask getCurrentTaskByUserId(String uploadUserId);
|
||||||
}
|
}
|
||||||
@ -4,6 +4,7 @@ import com.yfd.platform.data.domain.FishDraftData;
|
|||||||
import com.yfd.platform.data.domain.FishImportRequest;
|
import com.yfd.platform.data.domain.FishImportRequest;
|
||||||
import com.yfd.platform.data.domain.FishImportResult;
|
import com.yfd.platform.data.domain.FishImportResult;
|
||||||
import com.yfd.platform.data.service.IFishImportService;
|
import com.yfd.platform.data.service.IFishImportService;
|
||||||
|
import com.yfd.platform.data.utils.ZipFileUtil;
|
||||||
import com.yfd.platform.env.domain.SdEngInfoBH;
|
import com.yfd.platform.env.domain.SdEngInfoBH;
|
||||||
import com.yfd.platform.env.domain.SdHydrobase;
|
import com.yfd.platform.env.domain.SdHydrobase;
|
||||||
import com.yfd.platform.env.mapper.SdEngInfoBHMapper;
|
import com.yfd.platform.env.mapper.SdEngInfoBHMapper;
|
||||||
@ -13,7 +14,10 @@ import org.apache.poi.ss.usermodel.*;
|
|||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
@ -400,4 +404,39 @@ public class FishImportServiceImpl implements IFishImportService {
|
|||||||
}
|
}
|
||||||
return "IMPORT";
|
return "IMPORT";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FishImportResult parseAndMapZip(MultipartFile file, String uploadUserId) {
|
||||||
|
FishImportResult result = new FishImportResult();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZipFileUtil.ZipContent zipContent = ZipFileUtil.extractZipToTemp(file);
|
||||||
|
|
||||||
|
if (zipContent.excelFilePath == null) {
|
||||||
|
result.setSummary("ZIP文件中未找到Excel文件");
|
||||||
|
ZipFileUtil.cleanupTempDir(zipContent.tempDir);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Workbook workbook = new XSSFWorkbook(new FileInputStream(zipContent.excelFilePath))) {
|
||||||
|
Sheet sheet = workbook.getSheetAt(0);
|
||||||
|
result = parseSheet(sheet, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setImageFiles(zipContent.images);
|
||||||
|
result.setVideoFiles(zipContent.videos);
|
||||||
|
result.setTempDir(zipContent.tempDir);
|
||||||
|
result.setExcelFileName(zipContent.excelFileName);
|
||||||
|
result.setExcelFilePath(zipContent.excelFilePath);
|
||||||
|
|
||||||
|
result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频, 临时目录: %s",
|
||||||
|
zipContent.images.size(), zipContent.videos.size(), zipContent.tempDir));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setSummary("ZIP文件解析失败: " + e.getMessage());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -137,4 +137,38 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
|
|||||||
List<String> ids = expiredTasks.stream().map(ImportTask::getId).toList();
|
List<String> ids = expiredTasks.stream().map(ImportTask::getId).toList();
|
||||||
return this.removeByIds(ids);
|
return this.removeByIds(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasImportingTask(String uploadUserId) {
|
||||||
|
List<String> activeStatuses = List.of("UPLOADED", "PARSING", "VALIDATING");
|
||||||
|
List<ImportTask> tasks = importTaskMapper.selectByUserIdAndStatuses(uploadUserId, activeStatuses);
|
||||||
|
return tasks != null && !tasks.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean cancelTask(String taskId, String operatorId) {
|
||||||
|
ImportTask importTask = this.getById(taskId);
|
||||||
|
if (importTask == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String currentStatus = importTask.getStatus();
|
||||||
|
if ("CONFIRMED".equals(currentStatus) || "FAILED".equals(currentStatus) || "CANCELLED".equals(currentStatus)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
importTask.setStatus("CANCELLED");
|
||||||
|
importTask.setErrorMsg("用户取消: " + operatorId);
|
||||||
|
importTask.setUpdatedAt(new Date());
|
||||||
|
return this.updateById(importTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportTask getCurrentTaskByUserId(String uploadUserId) {
|
||||||
|
List<String> activeStatuses = List.of("UPLOADED", "PARSING", "VALIDATING");
|
||||||
|
List<ImportTask> tasks = importTaskMapper.selectByUserIdAndStatuses(uploadUserId, activeStatuses);
|
||||||
|
if (tasks == null || tasks.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tasks.get(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,219 @@
|
|||||||
|
package com.yfd.platform.data.utils;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
public class ZipFileUtil {
|
||||||
|
|
||||||
|
public static final String DEFAULT_TEMP_BASE = "D:\\zip_import_temp";
|
||||||
|
|
||||||
|
public static class ZipContent {
|
||||||
|
public String excelFileName;
|
||||||
|
public String excelFilePath;
|
||||||
|
public Map<String, String> images;
|
||||||
|
public Map<String, String> videos;
|
||||||
|
public Map<String, String> otherFiles;
|
||||||
|
public String tempDir;
|
||||||
|
|
||||||
|
public ZipContent() {
|
||||||
|
this.images = new HashMap<>();
|
||||||
|
this.videos = new HashMap<>();
|
||||||
|
this.otherFiles = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getExcelStream() throws IOException {
|
||||||
|
if (excelFilePath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new FileInputStream(excelFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDefaultTempDir() {
|
||||||
|
return DEFAULT_TEMP_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ZipContent extractZipToTemp(MultipartFile file) throws IOException {
|
||||||
|
return extractZipToTemp(file, DEFAULT_TEMP_BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ZipContent extractZipToTemp(MultipartFile file, String baseTempDir) throws IOException {
|
||||||
|
ZipContent content = new ZipContent();
|
||||||
|
|
||||||
|
String taskId = UUID.randomUUID().toString().substring(0, 8);
|
||||||
|
Path tempDirPath = Paths.get(baseTempDir, "zip_" + taskId);
|
||||||
|
Files.createDirectories(tempDirPath);
|
||||||
|
content.tempDir = tempDirPath.toString();
|
||||||
|
|
||||||
|
File zipFile = new File(tempDirPath.toFile(), "upload.zip");
|
||||||
|
file.transferTo(zipFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!isValidZipFile(zipFile)) {
|
||||||
|
throw new IOException("文件不是有效的ZIP格式或已损坏");
|
||||||
|
}
|
||||||
|
|
||||||
|
IOException lastException = null;
|
||||||
|
Charset[] charsets = new Charset[]{
|
||||||
|
StandardCharsets.UTF_8,
|
||||||
|
Charset.forName("GBK"),
|
||||||
|
StandardCharsets.ISO_8859_1,
|
||||||
|
Charset.forName("GB18030")
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Charset charset : charsets) {
|
||||||
|
try {
|
||||||
|
content = extractFromZipFile(zipFile, tempDirPath.toFile(), charset);
|
||||||
|
content.tempDir = tempDirPath.toString();
|
||||||
|
return content;
|
||||||
|
} catch (IOException e) {
|
||||||
|
lastException = e;
|
||||||
|
content = new ZipContent();
|
||||||
|
content.tempDir = tempDirPath.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw lastException != null ? lastException : new IOException("无法解析ZIP文件");
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (zipFile.exists()) {
|
||||||
|
zipFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidZipFile(File file) {
|
||||||
|
if (file == null || file.length() < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
|
byte[] signature = new byte[4];
|
||||||
|
int read = fis.read(signature);
|
||||||
|
if (read != 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return signature[0] == 0x50 && signature[1] == 0x4B &&
|
||||||
|
signature[2] == 0x03 && signature[3] == 0x04;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ZipContent extractFromZipFile(File zipFile, File tempDir, Charset charset) throws IOException {
|
||||||
|
ZipContent content = new ZipContent();
|
||||||
|
|
||||||
|
try (ZipFile zip = new ZipFile(zipFile, charset)) {
|
||||||
|
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
String entryName = entry.getName();
|
||||||
|
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream is = zip.getInputStream(entry)) {
|
||||||
|
String lowerName = entryName.toLowerCase();
|
||||||
|
|
||||||
|
if (lowerName.endsWith(".xlsx") || lowerName.endsWith(".xls")) {
|
||||||
|
String excelPath = saveFileToDir(is, tempDir, "excel", getFileName(entryName));
|
||||||
|
content.excelFileName = getFileName(entryName);
|
||||||
|
content.excelFilePath = excelPath;
|
||||||
|
} else if (isImageFile(lowerName)) {
|
||||||
|
String folder = "images";
|
||||||
|
String path = saveFileToDir(is, tempDir, folder, getFileName(entryName));
|
||||||
|
content.images.put(entryName, path);
|
||||||
|
} else if (isVideoFile(lowerName)) {
|
||||||
|
String folder = "videos";
|
||||||
|
String path = saveFileToDir(is, tempDir, folder, getFileName(entryName));
|
||||||
|
content.videos.put(entryName, path);
|
||||||
|
} else {
|
||||||
|
String folder = "others";
|
||||||
|
String path = saveFileToDir(is, tempDir, folder, getFileName(entryName));
|
||||||
|
content.otherFiles.put(entryName, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getFileName(String entryName) {
|
||||||
|
if (entryName == null) return "";
|
||||||
|
int lastSep = Math.max(entryName.lastIndexOf('/'), entryName.lastIndexOf('\\'));
|
||||||
|
return lastSep >= 0 ? entryName.substring(lastSep + 1) : entryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String saveFileToDir(InputStream is, File tempDir, String subFolder, String fileName) throws IOException {
|
||||||
|
File folder = new File(tempDir, subFolder);
|
||||||
|
if (!folder.exists()) {
|
||||||
|
folder.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(folder, fileName);
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int len;
|
||||||
|
while ((len = is.read(buffer)) > 0) {
|
||||||
|
fos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isImageFile(String fileName) {
|
||||||
|
return fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") ||
|
||||||
|
fileName.endsWith(".png") || fileName.endsWith(".gif") ||
|
||||||
|
fileName.endsWith(".bmp") || fileName.endsWith(".webp");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isVideoFile(String fileName) {
|
||||||
|
return fileName.endsWith(".mp4") || fileName.endsWith(".avi") ||
|
||||||
|
fileName.endsWith(".mov") || fileName.endsWith(".wmv") ||
|
||||||
|
fileName.endsWith(".flv") || fileName.endsWith(".mkv");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void cleanupTempDir(String tempDir) {
|
||||||
|
if (tempDir == null || tempDir.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File dir = new File(tempDir);
|
||||||
|
if (dir.exists()) {
|
||||||
|
deleteDirectory(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteDirectory(File dir) {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
deleteDirectory(file);
|
||||||
|
} else {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFileExtension(String fileName) {
|
||||||
|
if (fileName == null) return "";
|
||||||
|
int lastDot = fileName.lastIndexOf('.');
|
||||||
|
return lastDot >= 0 ? fileName.substring(lastDot + 1).toLowerCase() : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -58,8 +58,8 @@ mybatis-plus:
|
|||||||
configuration:
|
configuration:
|
||||||
map-underscore-to-camel-case: true
|
map-underscore-to-camel-case: true
|
||||||
cache-enabled: false
|
cache-enabled: false
|
||||||
# log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
|
|
||||||
|
|
||||||
# 登录相关配置
|
# 登录相关配置
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user