diff --git a/bonus-admin/src/main/java/com/bonus/web/controller/system/SysDeptController.java b/bonus-admin/src/main/java/com/bonus/web/controller/system/SysDeptController.java index af861d8..a60d5a0 100644 --- a/bonus-admin/src/main/java/com/bonus/web/controller/system/SysDeptController.java +++ b/bonus-admin/src/main/java/com/bonus/web/controller/system/SysDeptController.java @@ -96,18 +96,11 @@ public class SysDeptController extends BaseController { public AjaxResult edit(@Validated @RequestBody SysDept dept) { Long deptId = dept.getDeptId(); // 如果该部门已被使用,则无法修改 - Integer num = deptService.getTransferApplyDeptId(deptId); - if (num > 0) { - return error("该部门或其子部门已被档案申请使用,请勿修改"); - } Integer num1 = deptService.getSysUserDeptId(deptId); if (num1 > 0) { return error("该部门或其子部门已被用户管理使用,请勿修改"); } - Integer num2 = deptService.getTransferIssueDeptId(deptId); - if (num2 > 0) { - return error("该部门或其子部门已被档案移交问题管理,请勿修改"); - } + deptService.checkDeptDataScope(deptId); if (!deptService.checkDeptNameUnique(dept)) { return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); diff --git a/bonus-business/src/main/java/com/bonus/business/controller/ImageCaptionController.java b/bonus-business/src/main/java/com/bonus/business/controller/ImageCaptionController.java index 0c889a5..10cfab7 100644 --- a/bonus-business/src/main/java/com/bonus/business/controller/ImageCaptionController.java +++ b/bonus-business/src/main/java/com/bonus/business/controller/ImageCaptionController.java @@ -7,6 +7,7 @@ import com.bonus.common.core.controller.BaseController; import com.bonus.common.core.domain.AjaxResult; import com.bonus.common.core.page.TableDataInfo; import com.bonus.file.vo.UploadFileVo; +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -94,8 +95,14 @@ public class ImageCaptionController extends BaseController { * @return */ @PostMapping("/addImageInfo") - public AjaxResult addImageInfo(@RequestParam(required = false,name = "files") MultipartFile[] multipartFile, AlgorithmVo vo) { - return service.addImageInfo(multipartFile,vo); + public AjaxResult addImageInfo(@RequestParam(required = false,name = "files") MultipartFile[] multipartFile, @RequestParam("params") String params) { + try{ + ObjectMapper objectMapper = new ObjectMapper(); + AlgorithmVo vo = objectMapper.readValue(params, AlgorithmVo.class); + return service.addImageInfo(multipartFile,vo); + }catch (Exception e){ + return AjaxResult.error("请求参数异常!"); + } } /** @@ -104,8 +111,14 @@ public class ImageCaptionController extends BaseController { * @return */ @PostMapping("/addImageEvaluate") - public AjaxResult addImageEvaluate(@RequestParam(required = false,name = "files") MultipartFile[] multipartFile, AlgorithmVo vo) { - return service.addImageEvaluate(multipartFile,vo); + public AjaxResult addImageEvaluate(@RequestParam(required = false,name = "files") MultipartFile[] multipartFile, @RequestParam("params") String params) { + try{ + ObjectMapper objectMapper = new ObjectMapper(); + AlgorithmVo vo = objectMapper.readValue(params, AlgorithmVo.class); + return service.addImageEvaluate(multipartFile,vo); + }catch (Exception e){ + return AjaxResult.error("请求参数异常!"); + } } } diff --git a/bonus-business/src/main/java/com/bonus/business/domain/AlgorithmVo.java b/bonus-business/src/main/java/com/bonus/business/domain/AlgorithmVo.java index 5f85283..f6d1872 100644 --- a/bonus-business/src/main/java/com/bonus/business/domain/AlgorithmVo.java +++ b/bonus-business/src/main/java/com/bonus/business/domain/AlgorithmVo.java @@ -64,6 +64,8 @@ public class AlgorithmVo { */ private String userId; + private int fileNum; + public static void addSource(AlgorithmVo vo, int length, String operaId, String createTime, String operaType, String userId, String operaName) { vo.setBzNum(0); vo.setWbzNum(0); diff --git a/bonus-business/src/main/java/com/bonus/business/service/ZipImageChecker.java b/bonus-business/src/main/java/com/bonus/business/service/ZipImageChecker.java index 331cf2c..c8f18d4 100644 --- a/bonus-business/src/main/java/com/bonus/business/service/ZipImageChecker.java +++ b/bonus-business/src/main/java/com/bonus/business/service/ZipImageChecker.java @@ -9,6 +9,7 @@ import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import com.bonus.business.domain.AlgorithmVo; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; @@ -41,8 +42,9 @@ public class ZipImageChecker { * @param charset 压缩包文件名编码(如GBK、UTF-8,根据实际情况传入) * @return 存在图片返回true,否则返回false */ - public boolean hasImageInZip(InputStream zipInputStream, String charset) { + public boolean hasImageInZip(AlgorithmVo vo, InputStream zipInputStream, String charset) { // 使用Apache Commons Compress的ZipArchiveInputStream,支持JDK 1.8和指定编码 + int num=0; try (ZipArchiveInputStream zis = new ZipArchiveInputStream(zipInputStream, charset, false)) { ZipArchiveEntry entry; while ((entry = zis.getNextZipEntry()) != null) { @@ -56,10 +58,12 @@ public class ZipImageChecker { if (!isImage(entryName)) { return true; // 找到第一个图片即返回 } + num++; } } catch (IOException e) { throw new RuntimeException("解析ZIP文件失败:" + e.getMessage(), e); } + vo.setFileNum(num); // 遍历完所有条目未找到图片 return false; } diff --git a/bonus-business/src/main/java/com/bonus/business/service/impl/ImageCaptionServiceImpl.java b/bonus-business/src/main/java/com/bonus/business/service/impl/ImageCaptionServiceImpl.java index 6b5a945..daffdb4 100644 --- a/bonus-business/src/main/java/com/bonus/business/service/impl/ImageCaptionServiceImpl.java +++ b/bonus-business/src/main/java/com/bonus/business/service/impl/ImageCaptionServiceImpl.java @@ -77,8 +77,7 @@ public class ImageCaptionServiceImpl implements ImageCaptionService { if(result0.isError()){ return result0; } - String userId="1"; - // String userId= SecurityUtils.getUserId().toString(); + String userId= SecurityUtils.getUserId().toString(); String operaName=vo.getParam(); //操作日期 List fileList=new ArrayList<>(); @@ -146,42 +145,82 @@ public class ImageCaptionServiceImpl implements ImageCaptionService { } public AjaxResult isZip(MultipartFile[] multipartFile, AlgorithmVo vo) { - boolean isZip = false; - if(multipartFile.length==1) { - MultipartFile file = multipartFile[0]; - String fileName = file.getOriginalFilename(); - if (StringUtils.isNotEmpty(fileName)) { - for (String extension : compressedExtensions) { - if (fileName.toLowerCase().endsWith(extension)) { - isZip =true; - } - } - } - } - //压缩包 获取压缩包里面文件路径 - if(isZip){ - try (InputStream is = multipartFile[0].getInputStream()) { - ZipImageChecker checker = new ZipImageChecker(); - boolean isImage= checker.hasImageInZip(is,"GBK"); - if(isImage){ - return AjaxResult.error("压缩包里面不能包含非图片文件!"); - } - } catch (IOException e) { - throw new RuntimeException("获取ZIP文件输入流失败", e); - } + try{ + boolean isZip = false; + if(multipartFile.length==1) { + MultipartFile file = multipartFile[0]; + String fileName = file.getOriginalFilename(); + if (StringUtils.isNotEmpty(fileName)) { + for (String extension : compressedExtensions) { + if (fileName.toLowerCase().endsWith(extension)) { + isZip =true; + } + } + } + } + //压缩包 获取压缩包里面文件路径 + if(isZip){ + try (InputStream is = multipartFile[0].getInputStream()) { + ZipImageChecker checker = new ZipImageChecker(); + boolean isImage= checker.hasImageInZip(vo,is,"GBK"); + if(isImage){ + return AjaxResult.error("压缩包里面不能包含非图片文件!"); + } + } catch (IOException e) { + throw new RuntimeException("获取ZIP文件输入流失败", e); + } - }else{ - //检查上传是否只能是图片 - for (MultipartFile file : multipartFile) { - // 非压缩包上传 - String fileName = file.getOriginalFilename(); - boolean isImage = isImage(fileName); - if (isImage) { - return AjaxResult.error("附件只能上传图片!"); - } - } - } - return AjaxResult.success(isZip); + }else{ + //检查上传是否只能是图片 + for (MultipartFile file : multipartFile) { + // 非压缩包上传 + String fileName = file.getOriginalFilename(); + boolean isImage = isImage(fileName); + if (isImage) { + return AjaxResult.error("附件只能上传图片!"); + } + } + } + return AjaxResult.success(isZip); + }catch (Exception e){ + boolean isZip = false; + if(multipartFile.length==1) { + MultipartFile file = multipartFile[0]; + String fileName = file.getOriginalFilename(); + if (StringUtils.isNotEmpty(fileName)) { + for (String extension : compressedExtensions) { + if (fileName.toLowerCase().endsWith(extension)) { + isZip =true; + } + } + } + } + //压缩包 获取压缩包里面文件路径 + if(isZip){ + try (InputStream is = multipartFile[0].getInputStream()) { + ZipImageChecker checker = new ZipImageChecker(); + boolean isImage= checker.hasImageInZip(vo,is,"UTF-8"); + if(isImage){ + return AjaxResult.error("压缩包里面不能包含非图片文件!"); + } + } catch (IOException ee) { + throw new RuntimeException("获取ZIP文件输入流失败", ee); + } + + }else{ + //检查上传是否只能是图片 + for (MultipartFile file : multipartFile) { + // 非压缩包上传 + String fileName = file.getOriginalFilename(); + boolean isImage = isImage(fileName); + if (isImage) { + return AjaxResult.error("附件只能上传图片!"); + } + } + } + return AjaxResult.success(isZip); + + } } @@ -208,7 +247,13 @@ public class ImageCaptionServiceImpl implements ImageCaptionService { }else{ userOperaVo.setId(vo.getId()); } - AlgorithmVo.addSource(vo,multipartFile.length,userOperaVo.getId(),createTime,operaType,userId,operaName); + if (isZip){ + AlgorithmVo.addSource(vo,vo.getFileNum(),userOperaVo.getId(),createTime,operaType,userId,operaName); + }else{ + AlgorithmVo.addSource(vo,multipartFile.length,userOperaVo.getId(),createTime,operaType,userId,operaName); + } + + //操作记录 Integer addedAlgorithmNum= mapper.addAlgorithm(vo); if(addedAlgorithmNum==null || addedAlgorithmNum==0){ @@ -397,8 +442,11 @@ public AjaxResult uploadZip(){ } //查询 历史确认的图片 List fileList=mapper.getFileList(vo); - //添加图片到标记 - mapper.addSureFile(fileList); + if(!fileList.isEmpty()){ + //添加图片到标记 + mapper.addSureFile(fileList); + } + return AjaxResult.success("操作成功"); }catch (Exception e){ log.error(e.getMessage(),e); @@ -493,27 +541,7 @@ public AjaxResult uploadZip(){ } - /** - * 判断压缩包里面是不是图片 - * @param zipFile - * @return - */ - public boolean isImage(MultipartFile zipFile){ - try (InputStream inputStream = zipFile.getInputStream(); - ZipInputStream zipInputStream = new ZipInputStream(inputStream)) { - ZipEntry zipEntry; - while ((zipEntry = zipInputStream.getNextEntry()) != null) { - boolean isImage = isImage( zipEntry.getName()); - if(isImage){ - return isImage; - } - zipInputStream.closeEntry(); // 关闭当前条目,准备下一个条目 - } - } catch (IOException e) { - throw new RuntimeException(e); - } - return false; - } + /** * 判断文件后缀是不是图片 diff --git a/bonus-business/src/main/resources/mapper/business/ImageCaptionMapper.xml b/bonus-business/src/main/resources/mapper/business/ImageCaptionMapper.xml index c16cc95..1cbae18 100644 --- a/bonus-business/src/main/resources/mapper/business/ImageCaptionMapper.xml +++ b/bonus-business/src/main/resources/mapper/business/ImageCaptionMapper.xml @@ -224,7 +224,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" left join tb_algorithm ta on ta.id=file.algorithm_id WHERE file.is_active=0 and ta.id=#{id} - diff --git a/bonus-file/src/main/java/com/bonus/file/minio/MinioUtil.java b/bonus-file/src/main/java/com/bonus/file/minio/MinioUtil.java index e02991d..7daa1e7 100644 --- a/bonus-file/src/main/java/com/bonus/file/minio/MinioUtil.java +++ b/bonus-file/src/main/java/com/bonus/file/minio/MinioUtil.java @@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -48,6 +49,9 @@ public class MinioUtil { * 分片大小 */ private static final long PART_SIZE = 5*1024*1024; + + private static final int PART_SIZE1 = 5 * 1024 * 1024; + /** * 初始化默认存储桶 * 在 Spring 容器启动后自动调用,检查默认存储桶是否存在,若不存在则创建 @@ -93,17 +97,82 @@ public class MinioUtil { public SysFile uploadFile(File file, String folderPath) throws Exception { - minioClient.uploadObject(UploadObjectArgs.builder() - .bucket(minioConfig.getBucketName()) - .object(folderPath) - .filename(file.getAbsolutePath()) - .build()); + if (file.length() < 10 * 1024 * 1024L) { + minioClient.uploadObject(UploadObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(folderPath) + .filename(file.getAbsolutePath()) + .build()); + } else { + uploadLargeFile(file, folderPath); + } return SysFile.builder() .name(file.getName()) .bucketName(minioConfig.getBucketName()) .url(folderPath).build(); } + public void uploadLargeFile(File file, String folderPath) throws Exception { + System.err.println("--------------分区------"); + // 初始化 MinIO 客户端 + String shardPrefix = "temp-shards/" + UUID.randomUUID() + "/part-"; + // 1. 分割文件并上传所有分片(作为独立对象) + List shardSources = new ArrayList<>(); + long fileSize = file.length(); + int partCount = (int) (fileSize / PART_SIZE1 + (fileSize % PART_SIZE1 != 0 ? 1 : 0)); + + try (FileInputStream fis = new FileInputStream(file)) { + byte[] buffer = new byte[PART_SIZE1]; + int bytesRead; + for (int i = 0; i < partCount; i++) { + bytesRead = fis.read(buffer); + // 处理最后一个分片(可能小于 PART_SIZE) + byte[] partData = (bytesRead == buffer.length) + ? buffer + : java.util.Arrays.copyOf(buffer, bytesRead); + InputStream partStream = new ByteArrayInputStream(partData); + + // 上传分片(作为独立对象) + String shardObjectName = shardPrefix + (i + 1); + minioClient.putObject( + PutObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(shardObjectName) + .stream(partStream, partData.length, -1) + .build() + ); + // 记录分片信息(用于后续合并) + shardSources.add( + ComposeSource.builder() + .bucket(minioConfig.getBucketName()) + .object(shardObjectName) + .build() + ); + System.out.println("已上传分片 " + (i + 1) + "/" + partCount); + } + } + // 2. 用 composeObject 合并所有分片为最终文件 + minioClient.composeObject( + ComposeObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(folderPath) + .sources(shardSources) + .build() + ); + System.out.println("文件合并完成,最终路径:" + folderPath); + // 3. (可选)删除临时分片,释放空间 + for (ComposeSource source : shardSources) { + minioClient.removeObject( + io.minio.RemoveObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(source.object()) + .build() + ); + } + + } + + /** * * 上传文件到指定存储桶 diff --git a/bonus-framework/src/main/java/com/bonus/framework/interceptor/ReplayAttackInterceptor.java b/bonus-framework/src/main/java/com/bonus/framework/interceptor/ReplayAttackInterceptor.java index 739ce32..a294e7f 100644 --- a/bonus-framework/src/main/java/com/bonus/framework/interceptor/ReplayAttackInterceptor.java +++ b/bonus-framework/src/main/java/com/bonus/framework/interceptor/ReplayAttackInterceptor.java @@ -135,6 +135,7 @@ public class ReplayAttackInterceptor implements HandlerInterceptor { String requestUrl = request.getRequestURI(); String queryString = request.getQueryString(); if (queryString != null) { + queryString=queryString.split("\\|")[0]; requestUrl += "?" + queryString; } @@ -229,7 +230,7 @@ public class ReplayAttackInterceptor implements HandlerInterceptor { String encryptUserId = Sm4Utils.encrypt(userId); String encryptSecret = Sm4Utils.encrypt(secret); log.debug("Request URL: {}", requestUrl); - + System.err.println(requestUrl); // 构建待签名字符串 String signString = buildSignString(encryptUserId, timestamp, requestUrl, request.getMethod()); // 使用HMAC-SHA256计算签名