package com.hotent.file.attachmentService; import cn.hutool.core.lang.Assert; import com.hotent.base.attachment.Attachment; import com.hotent.base.attachment.AttachmentService; import com.hotent.base.attachment.MultipartFileParam; import com.hotent.base.attachment.UploadShardResult; import com.hotent.base.cache.annotation.*; import com.hotent.base.constants.CacheKeyConst; import com.hotent.base.exception.BaseException; import com.hotent.base.util.BeanUtils; import com.hotent.base.util.FileUtil; import com.hotent.base.util.StringUtil; import com.hotent.base.util.UniqueIdUtil; import com.hotent.file.model.UploadProperties; import com.hotent.file.service.FlowUploadPropertiesService; import com.hotent.file.util.AppFileUtil; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.util.Strings; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Map; import java.util.concurrent.TimeUnit; @Service public class FolderAttachmentServiceImpl implements AttachmentService{ @Resource FlowUploadPropertiesService flowUploadPropertiesService; @Resource FolderAttachmentServiceImpl folderAttachmentService; public FolderAttachmentServiceImpl(){ } public void remove(Attachment attachment,String propertiesId) throws Exception { if(attachment == null){ return; } String attachPath = getAttachPath(propertiesId,attachment); String filePath = attachment.getFilePath(); if(!attachment.getEntryptName()){ filePath = filePath.replace(attachment.getId(), attachment.getFileName()); } String fullPath = attachPath + File.separator + filePath; // 删除文件 FileUtil.deleteFile(fullPath); } @Override public void upload(Attachment attachment, InputStream inputStream,String propertiesId) throws Exception { String filePath = attachment.getFilePath(); String attachPath = getAttachPath(propertiesId,attachment); if(!attachment.getEntryptName()){ filePath = filePath.replace(attachment.getId(), attachment.getFileName()); } filePath=attachPath+File.separator+filePath; FileUtil.createFolderFile(filePath); if(BeanUtils.isNotEmpty(inputStream)) { FileUtil.writeFile(filePath, inputStream); } else { FileUtil.writeByte(filePath, attachment.getBytes()); } } public void download(Attachment attachment, OutputStream outStream,String propertiesId) throws Exception { String filePath = attachment.getFilePath(); String attachPath = getAttachPath(propertiesId,attachment); if(!attachment.getEntryptName()){ filePath = filePath.replace(attachment.getId(), attachment.getFileName()); } filePath=attachPath+File.separator+filePath; String fullPath = filePath.replace("/", File.separator); File file = new File(fullPath); if (file.exists()) { FileInputStream inputStream = null; try{ inputStream = new FileInputStream(fullPath); byte[] b = new byte[1024]; int i = 0; while ((i = inputStream.read(b)) > 0) { outStream.write(b, 0, i); } outStream.flush(); } catch(Exception e){ throw e; } finally{ if (inputStream != null) { inputStream.close(); inputStream = null; } if (outStream != null) { outStream.close(); outStream = null; } } } else { throw new BaseException("该附件不存在"); } } @Override public String getStoreType() { return "folder"; } @Override public boolean chekckFile(Attachment attachment,String propertiesId) { String filePath = attachment.getFilePath(); String attachPath = getAttachPath(propertiesId,attachment); if(!attachment.getEntryptName()){ filePath = filePath.replace(attachment.getId(), attachment.getFileName()); } filePath=attachPath+File.separator+filePath; String fullPath = filePath.replace("/", File.separator); File file = new File(fullPath); return file.exists(); } /** * 获取文件上传根目录 * @param propertiesId * @return */ private String getAttachPath(String propertiesId,Attachment attachment){ UploadProperties uploadProperties = flowUploadPropertiesService.getUploadProperties(propertiesId); String attachPath = ""; if(BeanUtils.isNotEmpty(uploadProperties)){ attachPath = uploadProperties.getLocation(); attachment.setEntryptName(uploadProperties.getEncryptName()== 0 ? false : true); }else{ attachPath = AppFileUtil.getAttachPath(); } return attachPath; } @Override public byte[] getFileBytes(Attachment sysFile) throws Exception { String propertiesId = BeanUtils.isNotEmpty(sysFile)?sysFile.getProp6():""; String location = this.getByUploadProperties(propertiesId); if(StringUtil.isEmpty(location)){ location = AppFileUtil.getAttachPath(); } String fullPath = StringUtil.trimSufffix(location, File.separator) + File.separator + sysFile.getFilePath().replace("/", File.separator); File file = new File(fullPath); if (file.exists()) { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); FileInputStream inputStream = null; try { inputStream = new FileInputStream(fullPath); byte[] b = new byte[1024]; int i = 0; while ((i = inputStream.read(b)) > 0) { outStream.write(b, 0, i); } outStream.flush(); return outStream.toByteArray(); } catch (Exception e) { throw e; } finally { if (inputStream != null) { inputStream.close(); inputStream = null; } if (outStream != null) { outStream.close(); outStream = null; } } } else { throw new RuntimeException("该附件不存在"); } } /** * 根据配置id获取文件上传配置 * @param propertiesId 流程附件配置ID * @return 文件路径 */ private String getByUploadProperties(String propertiesId){ if(StringUtil.isNotEmpty(propertiesId)){ UploadProperties uploadProperties = flowUploadPropertiesService.getUploadProperties(propertiesId); if(BeanUtils.isNotEmpty(uploadProperties)){ String location = uploadProperties.getLocation(); if(StringUtil.isNotEmpty(location)){ return location.replace("/", File.separator); } } } return Strings.EMPTY; } @Override public UploadShardResult uploadByShard(MultipartFileParam multipartFileParam,Attachment attachment, String propertiesId) throws Exception { multipartFileParam.setUniqueKey(multipartFileParam.getIdentifier()+"_"+multipartFileParam.getUniqueIdCard()); UploadShardResult uploadShardResult=new UploadShardResult(); uploadShardResult.setComplete(false); String filePath = attachment.getFilePath(); String attachPath = getAttachPath(propertiesId,attachment); String fileName = multipartFileParam.getFile().getOriginalFilename(); String extensionName=""; if(fileName.indexOf(".")!=-1){ extensionName=fileName.substring(fileName.lastIndexOf(".")+1); } String fileId=folderAttachmentService.getIdentifierIdFromCache(multipartFileParam.getUniqueKey()); if(StringUtil.isEmpty(fileId)){ fileId=UniqueIdUtil.getSuid(); folderAttachmentService.putIdentifierIdCache(multipartFileParam.getUniqueKey(),fileId); } attachment.setId(fileId); String fullFilePath=attachPath+File.separator+filePath; String tempFilePath=fullFilePath.substring(0,fullFilePath.lastIndexOf(File.separator)); String tempFileName=fileId+"."+extensionName+"."+"tmp"; FileUtil.createFolderFile(fullFilePath); File tempFile = new File(tempFilePath, tempFileName); try( //第一步 打开将要写入的文件 RandomAccessFile raf = new RandomAccessFile(tempFile, "rw"); //第二步 打开通道 FileChannel fileChannel = raf.getChannel() ) { //第三步 计算偏移量 long position = (multipartFileParam.getChunkNumber() - 1) * multipartFileParam.getChunkSize(); //第四步 获取分片数据 byte[] fileData = multipartFileParam.getFile().getBytes(); //第五步 写入数据 fileChannel.position(position); fileChannel.write(ByteBuffer.wrap(fileData)); fileChannel.force(true); } //判断是否完成文件的传输并进行校验与重命名 boolean isComplete = checkUploadStatus(multipartFileParam,attachment, tempFilePath); if (!isComplete) { return uploadShardResult; } folderAttachmentService.delIdentifierIdCache(multipartFileParam.getUniqueKey()); try(FileInputStream fileInputStream = new FileInputStream(tempFile.getPath())){ String md5 = DigestUtils.md5Hex(fileInputStream); if (StringUtils.isNotBlank(md5) && !md5.equals(multipartFileParam.getIdentifier())) { throw new IllegalArgumentException("MD5校验失败"); } } attachment.setFilePath(filePath.substring(0,filePath.lastIndexOf(File.separator))+ File.separator+attachment.getId()+"."+extensionName); renameFile(tempFile, attachment.getId()+"."+extensionName); uploadShardResult.setComplete(true); return uploadShardResult; } @Override public Map generatePolicy(Attachment attachment, String propertiesId) { return null; } @Override public String getUrl(Attachment attachment, String propertiesId) throws UnsupportedEncodingException { return null; } @Override public InputStream getFileInputStream(Attachment attachment) throws FileNotFoundException { String filePath = attachment.getFilePath(); String fullPath = StringUtil.trimSufffix(AppFileUtil.getAttachPath(), File.separator) + File.separator + filePath.replace("/", File.separator); File file = new File(fullPath); if (file.exists()) { return new FileInputStream(fullPath); } else { throw new RuntimeException("该附件不存在"); } } @Override public String getFilePath(String account, String fileName) { return AppFileUtil.getFilePath(account,fileName); } public void renameFile(File toBeRenamed, String toFileNewName) { Assert.isTrue(toBeRenamed.exists() && !toBeRenamed.isDirectory(),"文件不存在"); String p = toBeRenamed.getParent(); File newFile = new File(p + File.separatorChar + toFileNewName); toBeRenamed.renameTo(newFile); } @SuppressWarnings("all") public boolean checkUploadStatus(MultipartFileParam param,Attachment attachment, String filePath) throws IOException { File confFile = new File(filePath, attachment.getId() + ".conf"); try(RandomAccessFile confAccessFile = new RandomAccessFile(confFile, "rw")) { //设置文件长度 confAccessFile.setLength(param.getTotalChunks()); //设置起始偏移量 confAccessFile.seek(param.getChunkNumber() - 1); //将指定的一个字节写入文件中 127, confAccessFile.write(Byte.MAX_VALUE); byte[] completeStatusList = FileUtils.readFileToByteArray(confFile); //创建conf文件文件长度为总分片数,每上传一个分块即向conf文件中写入一个127,那么没上传的位置就是默认的0,已上传的就是127 for (int i = 0; i < completeStatusList.length; i++) { if (completeStatusList[i] != Byte.MAX_VALUE) { return false; } } } confFile.delete(); return true; } /** * 缓存分片上传文件id * @param key * @return */ @Cacheable(value = CacheKeyConst.EIP_UPLOAD_ALIYUN_FILE_ID, key="#key", firstCache = @FirstCache(expireTime = 1, timeUnit = TimeUnit.DAYS),secondaryCache = @SecondaryCache(expireTime = 1, timeUnit = TimeUnit.DAYS)) public String getIdentifierIdFromCache(String key) { return null; } @CachePut(value = CacheKeyConst.EIP_UPLOAD_ALIYUN_FILE_ID, key="#key", firstCache = @FirstCache(expireTime = 1, timeUnit = TimeUnit.DAYS),secondaryCache = @SecondaryCache(expireTime = 1, timeUnit = TimeUnit.DAYS)) public String putIdentifierIdCache(String key,String id) { return id; } @CacheEvict(value = CacheKeyConst.EIP_UPLOAD_ALIYUN_FILE_ID, key="#key") public void delIdentifierIdCache(String key) {} }