| | |
| | | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import io.minio.GetObjectArgs; |
| | | import io.minio.MinioClient; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.ibatis.annotations.Param; |
| | |
| | | import org.sxkj.common.enums.AttachResultTypeEnum; |
| | | import org.sxkj.common.enums.TypeOfOutcome; |
| | | import org.sxkj.common.func.Streams; |
| | | import org.sxkj.common.model.ResponseResult; |
| | | import org.sxkj.common.query.PaginationUtils; |
| | | import org.sxkj.common.redis.RedisOpsUtils; |
| | | import org.sxkj.common.utils.*; |
| | |
| | | import org.sxkj.tools.model.TifConvertResult; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.time.ZoneId; |
| | |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.stream.Collectors; |
| | | import java.util.zip.Deflater; |
| | | import java.util.zip.ZipEntry; |
| | | import java.util.zip.ZipOutputStream; |
| | | |
| | | /** |
| | | * 附件表 服务实现类 |
| | |
| | | return attachTypeStatisticsVOS; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean downloadByByte(AttachmentDownloadParam param, OutputStream outputStream) throws IOException { |
| | | // 如果附件id集合并且任务id集合参数都为空,就判断起止时间是否都有为空,如果都为空,则返回错误 |
| | | param.setAreaCode(HeaderUtils.formatAreaCode(param.getAreaCode())); |
| | | if (CollectionUtils.isEmpty(param.getAttachIds()) && CollectionUtils.isEmpty(param.getWayLineJobIds())) { |
| | | // 判断起止时间是否为空 |
| | | if (StringUtils.isEmpty(param.getStartTime()) || StringUtils.isEmpty(param.getEndTime())) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // 获取附件列表 |
| | | List<AttachVO> attachList = getAttachList(param); |
| | | if (CollectionUtils.isEmpty(attachList)) { |
| | | return false; |
| | | } |
| | | |
| | | try { |
| | | // 直接使用传入的输出流创建ZipOutputStream |
| | | ZipOutputStream zos = new ZipOutputStream(outputStream); |
| | | // 使用BEST_SPEED而不是BEST_COMPRESSION,提高速度 |
| | | zos.setLevel(Deflater.BEST_SPEED); |
| | | |
| | | // 使用较小的缓冲区,减少内存使用 |
| | | final int BUFFER_SIZE = 1024 * 1024; // 1MB |
| | | byte[] buffer = new byte[BUFFER_SIZE]; |
| | | |
| | | // 创建Minio客户端 |
| | | MinioClient minioClient = MinioClient.builder() |
| | | .endpoint(minioPojo.getPath()) |
| | | .credentials(minioPojo.getAccessKey(), minioPojo.getSecretKey()) |
| | | .build(); |
| | | |
| | | // 创建一个Set来跟踪已经使用的文件名,避免重名 |
| | | Set<String> usedFileNames = new HashSet<>(); |
| | | |
| | | // 直接遍历所有附件,不再按任务分组 |
| | | for (AttachVO attachVO : attachList) { |
| | | String objectName = attachVO.getName(); |
| | | try { |
| | | // 从MinIO获取文件流 |
| | | InputStream is = minioClient.getObject( |
| | | GetObjectArgs.builder() |
| | | .bucket(minioPojo.getBucket()) |
| | | .object(objectName) |
| | | .build()); |
| | | |
| | | // 提取文件名(不包含路径) |
| | | String fileName = objectName.substring(objectName.lastIndexOf("/") + 1); |
| | | |
| | | // 处理文件名冲突 |
| | | String uniqueFileName = fileName; |
| | | int counter = 1; |
| | | while (usedFileNames.contains(uniqueFileName)) { |
| | | // 如果文件名已存在,在文件名和扩展名之间添加计数器 |
| | | int dotIndex = fileName.lastIndexOf("."); |
| | | if (dotIndex > 0) { |
| | | uniqueFileName = fileName.substring(0, dotIndex) + "_" + counter + fileName.substring(dotIndex); |
| | | } else { |
| | | uniqueFileName = fileName + "_" + counter; |
| | | } |
| | | counter++; |
| | | } |
| | | |
| | | // 将文件名添加到已使用集合中 |
| | | usedFileNames.add(uniqueFileName); |
| | | |
| | | // 创建zip条目(直接放在根目录下) |
| | | ZipEntry zipEntry = new ZipEntry(uniqueFileName); |
| | | zos.putNextEntry(zipEntry); |
| | | |
| | | // 将文件内容写入zip |
| | | int length; |
| | | while ((length = is.read(buffer)) > 0) { |
| | | zos.write(buffer, 0, length); |
| | | // 每写入一块数据后刷新,确保数据及时发送到客户端 |
| | | zos.flush(); |
| | | } |
| | | |
| | | // 关闭资源 |
| | | zos.closeEntry(); |
| | | is.close(); |
| | | } catch (Exception e) { |
| | | log.error("处理文件 {} 失败: {}", objectName, e.getMessage()); |
| | | } |
| | | } |
| | | // 确保所有数据都被写入 |
| | | zos.finish(); |
| | | zos.flush(); |
| | | // 注意:不要关闭ZipOutputStream,因为它会关闭底层的OutputStream |
| | | // 让调用者负责关闭输出流 |
| | | |
| | | return true; |
| | | |
| | | } catch (Exception e) { |
| | | log.error("创建zip文件失败", e); |
| | | return false; |
| | | }finally { |
| | | if (outputStream != null) { |
| | | try { |
| | | outputStream.flush(); |
| | | } catch (IOException e) { |
| | | log.error("Error flushing output stream: {}", e.getMessage()); |
| | | } |
| | | try { |
| | | outputStream.close(); |
| | | } catch (IOException e) { |
| | | log.error("Error closing output stream: {}", e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |