package com.loan.system.service.Impl; import cn.hutool.core.bean.BeanUtil; import com.aliyun.oss.model.OSSObject; import com.loan.system.controller.wechat.OssFileController; import com.loan.system.domain.dto.BatchDownloadDTO; import com.loan.system.domain.dto.DocumentDTO; import com.loan.system.domain.dto.query.DocumentQueryDTO; import com.loan.system.domain.entity.Customer; import com.loan.system.domain.entity.Document; import com.loan.system.domain.enums.ExceptionEnum; import com.loan.system.domain.pojo.Result; import com.loan.system.domain.vo.CustomerVO; import com.loan.system.domain.vo.DocumentVO; import com.loan.system.domain.vo.LoanCaseSimpleVO; import com.loan.system.repository.DocumentRepository; import com.loan.system.service.CustomerService; import com.loan.system.service.DocumentService; import com.loan.system.service.LoanCaseService; import com.loan.system.service.LoanService; import com.loan.system.utils.ResultUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @Service @RequiredArgsConstructor @Slf4j public class DocumentServiceImpl implements DocumentService { private final DocumentRepository documentRepository; private final OssService ossService; Map dictTypeMap = new HashMap() {{ put("idCard", "借款人身份证"); put("customers1IdCard", "共同借款人1身份证"); put("customers2IdCard", "共同借款人2身份证"); put("householdRegister", "户口本照片"); put("marriageCertificate", "婚姻证明"); put("propertyCertificate", "房产证"); put("ownershipCertificate", "产调证明"); put("microCourtInquiry", "微法院查询"); put("businessLicense", "营业执照"); put("personalCredit", "个人征信"); put("contract", "合同"); put("receipt", "当票"); put("otherCertificates", "他项权证"); put("contractAttachment", "合同其他附件"); put("otherAttachments", "其他附件"); put("bankReceipt", "银行回单"); put("settlementCertificate", "借款结清证明"); put("evidenceCollectionConfirm", "押品入库证明"); put("deliveryConfirm", "押品出库证明"); }}; @Override public List findByCaseId(Long caseId) { return BeanUtil.copyToList(documentRepository.findByCaseId(caseId), DocumentVO.class); } @Override public DocumentVO uploadFile(Document document) { return BeanUtil.copyProperties(documentRepository.save(document), DocumentVO.class); } @Override public Document findById(Long signId) { return documentRepository.findByDocumentIdAndIsDelete(signId, false); } @Override public void updateDocumentByCaseIdAndDicType(Long caseId, String dictType, DocumentDTO documentDTO) { Document document = BeanUtil.copyProperties(documentDTO, Document.class); document.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); documentRepository.updateByCaseIdAndDictType(caseId, dictType, document); } @Override public void deleteFileByCaseIdAndDictType(Long caseId, String fileType) { documentRepository.deleteFileByCaseIdAndDictType(caseId, fileType); } @Override public void deleteFileById(Long id) { documentRepository.deleteById(id); } @Override public void deleteFileByIds(List ids) { documentRepository.deleteByIds(ids); } @Override public Result findAll(Integer pageNum, Integer pageSize) { Pageable pageable = PageRequest.of(pageNum-1, pageSize); Page data = documentRepository.findAllAndIdDelete(false, pageable); return ResultUtil.success(data.getTotalElements(),BeanUtil.copyToList(data.getContent(), DocumentVO.class)); } @Override public List findByFileTypesAndCaseId(List fileTypes, Long caseId) { return BeanUtil.copyToList(documentRepository.findByFileTypesAndCaseIdAndIsDelete(fileTypes, caseId, false), DocumentVO.class); } @Override public Result uploadFileToOss(MultipartFile file, Long caseId, String fileType, Map isDelete) { // 处理待删除的文件 Iterator> iterator = isDelete.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); Long id = Long.parseLong(entry.getKey()); Integer value = Integer.parseInt(entry.getValue()); Document document = findById(id); if (ObjectUtils.isEmpty(document)) break; if (value != 0) { log.info("删除文件: {}", id); deleteFileById(id); // 从OSS删除文件 ossService.deleteFile(document.getFileName()); } } if (file == null) return ResultUtil.success("success"); String originalName = file.getOriginalFilename(); String ext = FilenameUtils.getExtension(originalName).toLowerCase(Locale.ROOT); // 生成新的文件名 String randomUUID = UUID.randomUUID().toString(); String newFileName = String.format("%d/%s/%s.%s", caseId, fileType, randomUUID, ext); // 上传到OSS String fileUrl=""; try { fileUrl = ossService.uploadFile(file.getInputStream(), newFileName); }catch (Exception e){ return ResultUtil.error(ExceptionEnum.DIRECTORY_CREATE_ERROR); } Document document = new Document(); document.setCaseId(caseId); document.setFileName(randomUUID+"."+ext); document.setOriginName(originalName); document.setFilePath(fileUrl); // 存储OSS文件URL document.setFileSize(file.getSize()); document.setDocType(ext); document.setDictType(fileType); document.setIsDelete(false); document.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); document.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); DocumentVO documentVO = uploadFile(document); return ResultUtil.success("上传成功", documentVO); } @Override public void downloadFileFromOss(Long caseId, String fileType, String filename, HttpServletResponse response) { try { String fullFileName = String.format("%d/%s/%s", caseId, fileType, filename); // 从OSS获取文件 OSSObject ossObject = ossService.downloadFile(fullFileName); if (ossObject == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在"); return; } // 设置响应头 response.setContentType(ossObject.getObjectMetadata().getContentType()); response.setContentLength((int) ossObject.getObjectMetadata().getContentLength()); // 如果需要浏览器直接显示文件而不是下载,可以设置inline // 如果需要强制下载,可以设置attachment String disposition = "inline; filename=\"" + URLEncoder.encode(dictTypeMap.get(fileType) +"-"+ filename, "UTF-8") + "\""; response.setHeader("Content-Disposition", disposition); // 将文件内容写入响应流 try (InputStream inputStream = ossObject.getObjectContent(); OutputStream outputStream = response.getOutputStream()) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.flush(); } } catch (Exception e) { try { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "文件读取失败: " + e.getMessage()); } catch (IOException ioException) { // 处理发送错误响应时的异常 } } } @Override public void batchDownloadFilesFromOss(BatchDownloadDTO batchDownloadDTO, HttpServletResponse response) throws IOException{ List documentDTOList = batchDownloadDTO.getDocumentDTOList(); // 设置响应头 String zipFilename = "批量下载_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + ".zip"; response.setContentType("application/zip"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(zipFilename, "UTF-8") + "\""); try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) { byte[] buffer = new byte[8192]; int bytesRead; for (int i = 0; i < documentDTOList.size(); i++) { DocumentDTO documentDTO = documentDTOList.get(i); String filename = documentDTO.getFileName(); Long caseId = documentDTO.getCaseId(); String fileType = documentDTO.getDictType(); try { String fullFileName = String.format("%d/%s/%s", caseId, fileType, filename); OSSObject ossObject = ossService.downloadFile(fullFileName); if (ossObject == null) { // 文件不存在,可以记录日志或添加错误文件到ZIP continue; } // 创建ZIP条目 ZipEntry zipEntry = new ZipEntry(dictTypeMap.get(fileType) +"-"+ documentDTO.getOriginName()); // 可选:设置条目的创建时间 zipEntry.setTime(ossObject.getObjectMetadata().getLastModified().getTime()); zipOut.putNextEntry(zipEntry); // 将文件内容写入ZIP try (InputStream inputStream = ossObject.getObjectContent()) { while ((bytesRead = inputStream.read(buffer)) != -1) { zipOut.write(buffer, 0, bytesRead); } } zipOut.closeEntry(); } catch (Exception e) { // 记录单个文件下载失败,继续处理其他文件 // 可以在这里添加错误日志 e.printStackTrace(); } } zipOut.finish(); zipOut.flush(); } catch (Exception e) { try { response.reset(); // 重置响应 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "打包文件失败: " + e.getMessage()); } catch (IOException ioException) { // 处理发送错误响应时的异常 } } } @Override public Result queryFiles(Integer pageNum, Integer pageSize, DocumentQueryDTO documentQueryDTO) { Pageable pageable = PageRequest.of(pageNum-1, pageSize); Page data = documentRepository.findByQuery(documentQueryDTO, pageable); return ResultUtil.success(data.getTotalElements(), data.getContent()); } }