package com.bizmatics.service.impl; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.bizmatics.common.core.bean.UnifiedUser; import com.bizmatics.common.core.constants.CommonConst; import com.bizmatics.common.core.exception.BusinessException; import com.bizmatics.common.core.util.*; import com.bizmatics.common.mvc.base.AbstractCrudService; import com.bizmatics.common.spring.injectself.BeanSelfAware; import com.bizmatics.common.spring.util.GlobalUtils; import com.bizmatics.model.SysFile; import com.bizmatics.persistence.mapper.FileMapper; import com.bizmatics.service.FileSerivce; import com.bizmatics.service.dto.SysFileDTO; import com.bizmatics.service.dto.SysFileQueryRequest; import com.bizmatics.service.dto.SysFileUploadRequest; import com.bizmatics.service.enums.UploadType; import com.bizmatics.service.expcetion.FileErrorCode; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.commons.CommonsMultipartFile; import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.*; import static java.util.stream.Collectors.toList; /** * @author barry chen */ @Service @Slf4j public class FileServiceImpl extends AbstractCrudService implements FileSerivce, BeanSelfAware { public static final String OSS_KEY_FILE_NAME_DATE_PATTERN = "yyyy-MM"; public static final String SYS_FILE_TEMP_DIR = "file"; public static final String DOT = "."; private final Logger logger = LoggerFactory.getLogger(FileServiceImpl.class); private FileSerivce self; @Override public void setSelf(Object bean) { this.self = (FileSerivce) bean; } @Override public String generateBatchNo() { return UUIDUtils.shortUUID(); } @Override public List getFile(SysFileQueryRequest req) { if(StringUtils.isBlank(req.getBatchNo()) && CollectionUtils.isEmpty(req.getFileIds())){ throw new BusinessException(FileErrorCode.FILE_GET_ERROR, "At least one of batchNo and fileIds is required."); } return this.list(Wrappers.lambdaQuery(SysFile.class) .eq(StringUtils.isNotBlank(req.getBatchNo()), SysFile::getBatchNo, req.getBatchNo()) .eq(SysFile::getActiveFlag, CommonConst.TRUE_NUM) .in(CollectionUtils.isNotEmpty(req.getFileIds()), SysFile::getId, req.getFileIds())); } @Override @Nullable public List addFile(SysFileUploadRequest sysFileUploadRequest) { if (StringUtils.isNotBlank(sysFileUploadRequest.getKey())) { throw new BusinessException(FileErrorCode.FILE_UPLOAD_FILE_ERROR, "V1 upload api doesn't support [key]"); } if (Objects.isNull(sysFileUploadRequest.getUploadType())) { sysFileUploadRequest.setUploadType(UploadType.FILE); } switch (sysFileUploadRequest.getUploadType()) { case FILE: return sysFileUploadRequest.getMultipartFiles().stream().map(m -> self.uploadMultipartFile(m, sysFileUploadRequest)).collect(toList()); case URL: return sysFileUploadRequest.getUrls().stream().map(m -> self.addExternalLink(m, sysFileUploadRequest)).collect(toList()); case URLBYOSS: return sysFileUploadRequest.getUrls().stream().map(m -> self.uploadExternalFile(m, sysFileUploadRequest)).collect(toList()); default: break; } return null; } @Override @Nullable public SysFileDTO addFileV2(SysFileUploadRequest sysFileUploadRequest) { if (CollectionUtils.isNotEmpty(sysFileUploadRequest.getMultipartFiles()) && sysFileUploadRequest.getMultipartFiles().size() > 1) { throw new BusinessException(FileErrorCode.FILE_UPLOAD_FILE_ERROR, "V2 upload api only support single file"); } if (CollectionUtils.isNotEmpty(sysFileUploadRequest.getUrls()) && sysFileUploadRequest.getUrls().size() > 1) { throw new BusinessException(FileErrorCode.FILE_UPLOAD_FILE_ERROR, "V2 upload api only support single file"); } if (Objects.isNull(sysFileUploadRequest.getUploadType())) { sysFileUploadRequest.setUploadType(UploadType.FILE); } //如果key以"/"开头, 则去掉 String key = sysFileUploadRequest.getKey(); if (StringUtils.isNotBlank(key) && StringUtils.startsWith(key, File.separator)) { sysFileUploadRequest.setKey(key.substring(1)); } switch (sysFileUploadRequest.getUploadType()) { case FILE: return self.uploadMultipartFile(sysFileUploadRequest.getMultipartFiles().get(0), sysFileUploadRequest); case URL: String u = sysFileUploadRequest.getUrls().get(0); return self.addExternalLink(u, sysFileUploadRequest); case URLBYOSS: return self.uploadExternalFile(sysFileUploadRequest.getUrls().get(0), sysFileUploadRequest); default: break; } return null; } @Override @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) public SysFileDTO uploadMultipartFile(CommonsMultipartFile multipartFile, SysFileUploadRequest sysFileUploadRequest) { SysFileDTO sysFileDTO = new SysFileDTO(); File file = FileUtils.getFile(GlobalUtils.getTempBaseDir(), SYS_FILE_TEMP_DIR, multipartFile.getOriginalFilename()); try { try { multipartFile.transferTo(file); } catch (IOException e) { throw new BusinessException(FileErrorCode.FILE_TRANSFER_TO_LOCAL_ERROR, e); } sysFileDTO = uploadToOss(file, sysFileDTO, sysFileUploadRequest); } catch (Exception e) { sysFileDTO.setSuccess(false); sysFileDTO.setMessage(e.getMessage()); } return sysFileDTO; } @Override public SysFileDTO uploadExternalFile(String u, SysFileUploadRequest sysFileUploadRequest) { SysFileDTO sysFileDTO = new SysFileDTO(); try { URL url = URLUtils.url(u); File file = FileUtils.downloadRemoteFile(url.toString(), FileUtils.getFile(GlobalUtils.getTempBaseDir(), SYS_FILE_TEMP_DIR).getAbsolutePath()); if (file == null || !file.exists()) { throw new BusinessException(FileErrorCode.FILE_DOWNLOAD_ERROR); } uploadToOss(file, sysFileDTO, sysFileUploadRequest); } catch (Exception e) { sysFileDTO.setSuccess(false); sysFileDTO.setMessage(e.getMessage()); } return sysFileDTO; } @Override public SysFileDTO addExternalLink(String u, SysFileUploadRequest sysFileUploadRequest) { SysFileDTO sysFileDTO = BeanMapperUtils.map(sysFileUploadRequest, SysFileDTO.class); sysFileDTO.setUrl(u); try { URL url = URLUtils.url(u); SysFile sysFile = new SysFile(); sysFile.setId(UUIDUtils.shortUUID()); sysFile.setBatchNo(sysFileUploadRequest.getBatchNo()); sysFile.setBusinessType(sysFileUploadRequest.getBusinessType()); sysFile.setUrl(url.toString()); fillNecessaryOperatorProperty(sysFile, null, false); if (save(sysFile)) { sysFileDTO.setSuccess(true); sysFileDTO.setId(sysFile.getId()); } } catch (Exception e) { sysFileDTO.setSuccess(false); sysFileDTO.setMessage(e.getMessage()); } return sysFileDTO; } public SysFileDTO uploadToOss(File file, SysFileDTO sysFileDTO, SysFileUploadRequest sysFileUploadRequest) { try { prepareMetadata(file, sysFileDTO, sysFileUploadRequest); if (sysFileDTO.getSuccess()) { sysFileDTO.setId(UUIDUtils.shortUUID()); SysFile sysfile = BeanMapperUtils.map(sysFileDTO, SysFile.class); fillNecessaryOperatorProperty(sysfile, null, false); save(sysfile); } } catch (Exception e) { logger.error("增加文件失败,error: {}", e.getMessage()); sysFileDTO.setSuccess(false); sysFileDTO.setMessage(e.getMessage()); } boolean delete = file.delete(); return sysFileDTO; } @Override @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) public Boolean active(String batchNo, List fileIds) { if (CollectionUtils.isEmpty(fileIds)) { return false; } this.update(Wrappers.lambdaUpdate(SysFile.class) .set(SysFile::getActiveFlag, CommonConst.FALSE_NUM) .eq(SysFile::getBatchNo, batchNo)); return this.update(Wrappers.lambdaUpdate(SysFile.class) .set(SysFile::getActiveFlag, CommonConst.TRUE_NUM) .eq(SysFile::getBatchNo, batchNo) .in(SysFile::getId, fileIds)); } @Override public List getFileByExpireAt(Date expireAt) { return baseMapper.selectByExpireAt(expireAt); } @Transactional(rollbackFor = Exception.class) @Override public Integer deleteFiles(List sysFiles) { Date now = new Date(); sysFiles = sysFiles.stream().peek(s -> { s.setDelFlag(CommonConst.TRUE_NUM.toString()); s.setActiveFlag(CommonConst.FALSE_NUM); s.setExpireAt(now); }).collect(toList()); return updateBatchById(sysFiles) ? sysFiles.size() : 0; } @Override public Integer clearFiles(List fileList) { return null; } @Override public Integer removeByBatchNo(String batchNo) { List sysFileList = list(Wrappers.lambdaQuery(SysFile.class).eq(SysFile::getBatchNo, batchNo)); return this.deleteFiles(sysFileList); } private SysFileDTO prepareMetadata(File file, SysFileDTO sysFileDTO, SysFileUploadRequest sysFileUploadRequest) { String ossKey; if (StringUtils.isNotBlank(sysFileUploadRequest.getKey())) { ossKey = sysFileUploadRequest.getKey(); } else { ossKey = generateKey(file, sysFileUploadRequest.getBusinessType()); } sysFileDTO.setOssKey(ossKey); sysFileDTO.setOriName(file.getName()); sysFileDTO.setBatchNo(sysFileUploadRequest.getBatchNo()); sysFileDTO.setBusinessType(sysFileUploadRequest.getBusinessType()); sysFileDTO.setActiveFlag(0); sysFileDTO.setFileSize((int) file.length()); sysFileDTO.setFileType((StringUtils.isNotBlank(ossKey) && ossKey.lastIndexOf(".") > 0) ? ossKey.substring(ossKey.lastIndexOf(".") + 1) : ""); sysFileDTO.setExpireAt(sysFileUploadRequest.getExpireAt()); return sysFileDTO; } private String generateKey(File file, String businessType) { String newFileName; String dateTimeStr = DateUtils.format(new Date(), OSS_KEY_FILE_NAME_DATE_PATTERN); String fileName = file.getName(); String random = UUIDUtils.shortUUID(); if (fileName.indexOf(DOT) > 0) { String name = StringUtils.substring(fileName, 0, fileName.indexOf(DOT)); String suffix = StringUtils.substring(fileName, fileName.indexOf(DOT) + 1, fileName.length()); newFileName = String.format("%s-%s.%s", name, random, suffix); } else { newFileName = String.format("%s-%s", fileName, random); } return String.format("%s/%s/%s", businessType, dateTimeStr, newFileName); } }