外协人员,批量上传附件

This commit is contained in:
2025-11-19 14:38:32 +08:00
parent 7b9aadc020
commit 5ac9d5ed0a
7 changed files with 1917 additions and 5 deletions

View File

@@ -5,25 +5,37 @@ import cn.hutool.json.JSONUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.jeelowcode.core.framework.controller.BaseController;
import com.jeelowcode.core.framework.service.IFormService;
import com.jeelowcode.core.framework.service.IFrameSqlService;
import com.jeelowcode.framework.exception.JeeLowCodeException;
import com.jeelowcode.framework.global.JeeLowCodeBaseConstant;
import com.jeelowcode.framework.plus.SqlHelper;
import com.jeelowcode.framework.plus.build.buildmodel.wrapper.SqlInfoQueryWrapper;
import com.jeelowcode.framework.tenant.annotation.JeeLowCodeTenantIgnore;
import com.jeelowcode.framework.utils.model.ResultDataModel;
import com.jeelowcode.framework.utils.tool.CollectionUtil;
import com.jeelowcode.service.infra.service.IFileService;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.io.FileUtil;
import com.jeelowcode.tool.framework.security.core.LoginUser;
import com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
@Slf4j
@JeeLowCodeTenantIgnore
@Tag(name = "低代码框架 - 自定义外协人员接口")
@RestController
@@ -34,6 +46,12 @@ public class OutSidePersonController extends BaseController {
@Autowired
private IFormService dbFormService;
@Autowired
private IFileService fileService;
@Autowired
private IFrameSqlService sqlService;
@GetMapping({"/importOutside"})
@ApiOperationSupport(order = 5)
@Operation(summary = "引入外协人员")
@@ -71,4 +89,351 @@ public class OutSidePersonController extends BaseController {
super.addJsonData( Long.valueOf(tableId), licenses);
return success("引入成功");
}
public Map<String, Object> getOutSideByCardNo(String cardNo) {
SqlInfoQueryWrapper.Wrapper wrapper = SqlHelper.getQueryWrapper();
wrapper.setTableName("lc_outside_person");
wrapper.setWhere(where -> {
where.eq("cardNo", cardNo);
});
return sqlService.getDataOneByPlus(wrapper);
}
/**
* 根据压缩文件地址下载、解压文件,并根据文件名(身份证号)更新数据库
*
* 功能说明:
* 1. 根据文件地址支持URL或本地路径下载/读取压缩文件
* 2. 解压缩文件支持zip、rar、7z格式得到文件列表
* 3. 遍历文件列表,每个文件的文件名作为身份证号
* 4. 根据身份证号查询lc_risk_hazard_manage表的cardID字段
* 5. 如果匹配到数据,将文件上传到服务器指定目录
* 6. 更新lc_risk_hazard_manage表的actual_corrective_Attachment字段为文件地址
*
* 使用示例:
* <pre>
* // 方式1使用MyBatis Mapper
* &#64;Autowired
* private RiskHazardManageMapper mapper;
*
* String fileUrl = "http://example.com/files.zip";
* String uploadPath = "/data/uploads";
* int count = FileUtil.processCompressedFileByCardId(fileUrl, uploadPath, mapper);
*
* // 方式2使用JPA Repository需要实现接口
* RiskHazardManageMapper mapper = new RiskHazardManageMapper() {
* &#64;Autowired
* private RiskHazardManageRepository repository;
*
* public RiskHazardManage findByCardId(String cardId) {
* return repository.findByCardId(cardId);
* }
*
* public void updateActualCorrectiveAttachment(String cardId, String fileUrl) {
* RiskHazardManage entity = repository.findByCardId(cardId);
* if (entity != null) {
* entity.setActualCorrectiveAttachment(fileUrl);
* repository.save(entity);
* }
* }
* };
* </pre>
*
* @param fileUrl 压缩文件的地址可以是URL如"http://example.com/file.zip"或本地路径如"/path/to/file.zip"
* @return 处理结果:成功处理的文件数量
* @throws IOException IO异常
*/
public int processCompressedFileByCardId( @RequestBody JSONObject jsonObject) throws IOException {
String fileUrl=jsonObject.get("commitmentAttchment").toString();
if(fileUrl.isEmpty()){
return 0;
}
int successCount = 0;
File tempZipFile = null;
File tempDir = null;
String tableName = "lc_outside_person";
Long detailFormId = dbFormService.getDbFormIdByTableName(tableName);
try {
// 1. 下载文件如果是URL或直接使用本地文件
if (fileUrl.startsWith("http://") || fileUrl.startsWith("https://")) {
// 从URL下载文件
tempZipFile = FileUtil.downloadFileFromUrl(fileUrl);
} else {
// 本地文件路径
tempZipFile = new File(fileUrl);
if (!tempZipFile.exists()) {
throw new FileNotFoundException("文件不存在: " + fileUrl);
}
}
// 2. 创建临时解压目录
String tempDirPath = System.getProperty("java.io.tmpdir") + File.separator +
"unzip_" + System.currentTimeMillis();
tempDir = new File(tempDirPath);
if (!tempDir.exists()) {
tempDir.mkdirs();
}
// 3. 解压缩文件
List<File> fileList = FileUtil.unzipFile(tempZipFile, tempDir);
log.info("解压文件成功,共 {} 个文件", fileList.size());
List<JSONObject> editDataList = new ArrayList<>();
// 4. 遍历文件列表,处理每个文件
for (File file : fileList) {
try {
// 4.1 获取文件名(身份证号),去掉扩展名
String fileName = file.getName();
String cardId = fileName;
// 如果文件名包含扩展名,去掉扩展名
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex > 0) {
cardId = fileName.substring(0, lastDotIndex);
}
// 4.2 根据身份证号查询数据库
Map<String, Object> entity = getOutSideByCardNo(cardId);
if (entity.isEmpty()) {
log.warn("未找到身份证号对应的记录: {}", cardId);
continue;
}
// 4.3 上传文件到服务器
String uploadPath = uploadFile(file);
entity.put("commitmentAttchment", uploadPath);
editDataList.add(JSONUtil.parseObj(entity));
log.info("处理成功 - 身份证号: {}, 文件: {}", cardId, uploadPath);
successCount++;
} catch (Exception e) {
log.error("处理文件失败: {}", file.getName(), e);
}
}
// 更新数据
super.editJsonData(detailFormId, editDataList);
} finally {
// 清理临时文件
if (tempZipFile != null && tempZipFile.exists() &&
(fileUrl.startsWith("http://") || fileUrl.startsWith("https://"))) {
tempZipFile.delete();
}
if (tempDir != null && tempDir.exists()) {
FileUtil.deleteDirectory(tempDir);
}
}
return successCount;
}
public String uploadFile(File file) throws Exception {
String fileName = file.getName();
//微信图片_20230905094700.png
Long tenantId = -1L;
Long userId = -1L;
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
if (loginUser != null) {
tenantId = loginUser.getTenantId();
userId = loginUser.getId();
}
//每个文件放一个文件夹,防止乱码后找不到正确文件
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HHmmssSSS");
String timeString = now.format(formatter);
String publicPath = "upload/" + tenantId + "/" + userId + "/" + timeString + "/";
String path = publicPath + fileName;
fileName = fileService.getUniqueFileName(fileName, path);
// 解决信创环境下文件名中文乱码导致附件错乱的问题
//path = publicPath + IdUtil.simpleUUID() + (StrUtil.isEmpty(FileUtil.extName(fileName)) ? "" : ("." + FileUtil.extName(fileName)));
String fileUrl = fileService.createFile(fileName, path, FileUtil.toByteArray(file));
return fileUrl;
}
/**
* 根据压缩文件地址下载、解压文件,并根据文件名(身份证号)更新数据库
*
* 功能说明:
* 1. 根据文件地址支持URL或本地路径下载/读取压缩文件
* 2. 解压缩文件支持zip、rar、7z格式得到文件列表
* 3. 遍历文件列表,每个文件的文件名作为身份证号
* 4. 根据身份证号查询lc_risk_hazard_manage表的cardID字段
* 5. 如果匹配到数据,将文件上传到服务器指定目录
* 6. 更新lc_risk_hazard_manage表的actual_corrective_Attachment字段为文件地址
*
* 使用示例:
* <pre>
* // 方式1使用MyBatis Mapper
* &#64;Autowired
* private RiskHazardManageMapper mapper;
*
* String fileUrl = "http://example.com/files.zip";
* String uploadPath = "/data/uploads";
* int count = FileUtil.processCompressedFileByCardId(fileUrl, uploadPath, mapper);
*
* // 方式2使用JPA Repository需要实现接口
* RiskHazardManageMapper mapper = new RiskHazardManageMapper() {
* &#64;Autowired
* private RiskHazardManageRepository repository;
*
* public RiskHazardManage findByCardId(String cardId) {
* return repository.findByCardId(cardId);
* }
*
* public void updateActualCorrectiveAttachment(String cardId, String fileUrl) {
* RiskHazardManage entity = repository.findByCardId(cardId);
* if (entity != null) {
* entity.setActualCorrectiveAttachment(fileUrl);
* repository.save(entity);
* }
* }
* };
* </pre>
*
* @param fileUrl 压缩文件的地址可以是URL如"http://example.com/file.zip"或本地路径如"/path/to/file.zip"
* @return 处理结果:成功处理的文件数量
* @throws IOException IO异常
*/
@PutMapping({"/batchAttachments"})
@ApiOperationSupport(order = 5)
@Operation(summary = "批量上传附件")
public int batchAttachments(@RequestBody JSONObject jsonObject) throws IOException {
String commitmentFileUrl = jsonObject.get("commitmentAttchment") != null ?
jsonObject.get("commitmentAttchment").toString() : "";
String secretFileUrl = jsonObject.get("secretAttchment") != null ?
jsonObject.get("secretAttchment").toString() : "";
if (commitmentFileUrl.isEmpty() && secretFileUrl.isEmpty()) {
return 0;
}
int successCount = 0;
String tableName = "lc_outside_person";
Long detailFormId = dbFormService.getDbFormIdByTableName(tableName);
// 用于存储所有需要更新的数据key为身份证号value为需要更新的字段
Map<String, JSONObject> updateDataMap = new HashMap<>();
// 处理 commitmentAttchment 压缩包
if (!commitmentFileUrl.isEmpty()) {
processCompressedFile(commitmentFileUrl, "commitmentAttchment", updateDataMap);
}
// 处理 secretAttchment 压缩包
if (!secretFileUrl.isEmpty()) {
processCompressedFile(secretFileUrl, "secretAttchment", updateDataMap);
}
// 将Map转换为List用于批量更新
List<JSONObject> editDataList = new ArrayList<>(updateDataMap.values());
if (!editDataList.isEmpty()) {
// 更新数据
super.editJsonData(detailFormId, editDataList);
successCount = editDataList.size();
}
return successCount;
}
/**
* 处理压缩文件的通用方法
* @param fileUrl 压缩文件地址
* @param fieldName 要更新的字段名commitmentAttchment 或 secretAttchment
* @param updateDataMap 用于存储更新数据的Mapkey为身份证号
*/
private void processCompressedFile(String fileUrl, String fieldName,
Map<String, JSONObject> updateDataMap) {
File tempZipFile = null;
File tempDir = null;
try {
// 1. 下载文件如果是URL或直接使用本地文件
if (fileUrl.startsWith("http://") || fileUrl.startsWith("https://")) {
// 从URL下载文件
tempZipFile = FileUtil.downloadFileFromUrl(fileUrl);
} else {
// 本地文件路径
tempZipFile = new File(fileUrl);
if (!tempZipFile.exists()) {
log.warn("文件不存在: {}", fileUrl);
return;
}
}
// 2. 创建临时解压目录
String tempDirPath = System.getProperty("java.io.tmpdir") + File.separator +
"unzip_" + System.currentTimeMillis() + "_" + fieldName;
tempDir = new File(tempDirPath);
if (!tempDir.exists()) {
tempDir.mkdirs();
}
// 3. 解压缩文件
List<File> fileList = FileUtil.unzipFile(tempZipFile, tempDir);
log.info("解压文件成功 [{}],共 {} 个文件", fieldName, fileList.size());
// 4. 遍历文件列表,处理每个文件
for (File file : fileList) {
try {
// 4.1 获取文件名(身份证号),去掉扩展名
String fileName = file.getName();
String cardId = fileName;
// 如果文件名包含扩展名,去掉扩展名
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex > 0) {
cardId = fileName.substring(0, lastDotIndex);
}
// 4.2 根据身份证号查询数据库
Map<String, Object> entity = getOutSideByCardNo(cardId);
if (entity.isEmpty()) {
log.warn("未找到身份证号对应的记录: {}", cardId);
continue;
}
// 4.3 上传文件到服务器
String uploadPath = uploadFile(file);
// 4.4 更新或添加到更新数据Map中
String cardIdKey = cardId;
JSONObject updateData = updateDataMap.get(cardIdKey);
if (updateData == null) {
// 如果Map中还没有这个身份证号的记录创建新记录
updateData = JSONUtil.parseObj(entity);
updateDataMap.put(cardIdKey, updateData);
}
// 更新对应的字段
updateData.put(fieldName, uploadPath);
log.info("处理成功 [{}] - 身份证号: {}, 文件: {}", fieldName, cardId, uploadPath);
} catch (Exception e) {
log.error("处理文件失败 [{}]: {}", fieldName, file.getName(), e);
}
}
} catch (Exception e) {
log.error("处理压缩文件失败 [{}]: {}", fieldName, fileUrl, e);
} finally {
// 清理临时文件
if (tempZipFile != null && tempZipFile.exists() &&
(fileUrl.startsWith("http://") || fileUrl.startsWith("https://"))) {
tempZipFile.delete();
}
if (tempDir != null && tempDir.exists()) {
FileUtil.deleteDirectory(tempDir);
}
}
}
}

View File

@@ -1,6 +1,7 @@
package com.jeelowcode.module.biz.controller;
import cn.hutool.core.io.IoUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
@@ -11,21 +12,41 @@ import com.jeelowcode.framework.global.JeeLowCodeBaseConstant;
import com.jeelowcode.framework.tenant.annotation.JeeLowCodeTenantIgnore;
import com.jeelowcode.framework.utils.model.ResultDataModel;
import com.jeelowcode.framework.utils.tool.CollectionUtil;
import com.jeelowcode.module.biz.service.IRiskService;
import com.jeelowcode.service.infra.controller.vo.file.FileUploadReqVO;
import com.jeelowcode.service.infra.service.IFileService;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.io.FileUtil;
import com.jeelowcode.tool.framework.security.core.LoginUser;
import com.jeelowcode.tool.framework.security.core.util.SecurityFrameworkUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success;
/**
* @author LIFY
* @create 2025-09-126
* @dedescription:
*/
@JeeLowCodeTenantIgnore
@Tag(name = "低代码框架 - 个性化接口")
@RestController
@@ -36,6 +57,11 @@ public class RiskHazardController extends BaseController {
@Autowired
private IFormService formService;
@Autowired
private IRiskService riskService;
@GetMapping({"/syncData2RiskHazard"})
@ApiOperationSupport(order = 1)
@Operation(summary = "同步数据")
@@ -133,4 +159,6 @@ public class RiskHazardController extends BaseController {
super.editJsonData(dbFormId, syncList);
}
}
}

View File

@@ -22,4 +22,5 @@ public interface IRiskService {
* 根据ID获取当前数据
*/
Map<String, Object> getRiskById(long id);
}

View File

@@ -127,5 +127,4 @@ public class RiskServiceImpl implements IRiskService {
});
return sqlService.getDataOneByPlus(wrapper);
}
}