FolderAttachmentServiceImpl.java 11.6 KB
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<String,Object> 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) {}
}