前言
前端进行文件大小分割 ,按10M分割进行分片上传,使用的项目还是前面文档介绍的poi同一个项目
另一篇poi导出文章,使用的同一个项目
开发
1、maven依赖
<!--文件分片上传使用到依赖 start --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>16.0.1</version> </dependency> <dependency> <groupId>com.twmacinta</groupId> <artifactId>fast-md5</artifactId> <version>2.7.1</version> </dependency> <!--文件分片上传使用到依赖 end -->
配置文件
server: port: 9001 # rootdir文件上传根路径 linux:/xxx/xx/ window D:\Download\ # tempdir: 分片临时目录 # isDelTempFile 和片后是否删除临时目录 spring: uploader: rootdir: D:\Download\ tempdir: temp isDelTempFile: true
controller
package com.shan.controller;
import com.shan.service.UploaderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 分片上传
* 思想
* 1. 先 checkUpload() 文件上传前校验 根据自己公司需求校验
*2. checkChunk() 检测指定分片是否存在 否 走uploadChunk()分片上传方法 是走merge()合成分片
* 3. 分片上传时,会生成临时文件 必成分片是会把临时文件合成上传的真正文件,并删除临时文件
*
*/
@RestController
@RequestMapping("uploader")
public class TestUploader {
@Autowired
private UploaderService uploaderService;
/**
* 文件上传前校验
*
* @param fileName 文件名称
* @param size 文件大小 byte字节长度
* @return
*/
@PostMapping("/checkUpload")
public String checkUpload(String fileName, String size) {
//根据公司自己业务 做校验 如文件名是否喊特殊字符 是否为空 等
return "SUCCESS";
}
/**
* 检查指定分片是否存在
*
* @param md5Value 文件MD5值
* @param chunk 第几片
* @param moduleName 上传文件所在模块名称
* @param fileTypeKey 文件类别 公司自己业务需求 会根据 模块名称+文件类别 定义上传目录
* @return
*/
@PostMapping("/checkChunk")
public Boolean checkChunk(String md5Value, Integer chunk, String moduleName, String fileTypeKey) {
Boolean bool = uploaderService.checkChunk(md5Value, chunk, moduleName, fileTypeKey);
return bool;
}
/**
* 分片上传
*
* @param file 文件对象
* @param md5Value 文件MD5值
* @param chunk 第几片
* @param moduleName 上传文件所在模块名称
* @param fileTypeKey 文件类别
* @return
*/
@PostMapping("/uploadChunk")
public String uploadChunk(MultipartFile file, String md5Value, Integer chunk, String moduleName, String fileTypeKey) {
System.out.println("------------开始上传:" + file.getOriginalFilename());
Boolean bool = uploaderService.uploadChunk(file, md5Value, chunk, moduleName, fileTypeKey);
if (!bool) {
return "FAILRE";
}
return "SUCCESS";
}
/**
* 合成分片
*
* @param chunkCount 总片数
* @param md5Value 文件MD5值
* @param fileName 文件名称
* @param moduleName 上传文件所在模块名称
* @param fileTypeKey 文件类别
* @return
*/
@PostMapping("/merge")
public String merge(Integer chunkCount, String md5Value, String fileName, String moduleName, String fileTypeKey) {
String fileId = uploaderService.merge(chunkCount, md5Value, fileName, moduleName, fileTypeKey);
if (StringUtils.isBlank(fileId)) {
return "FAILRE";
}
return "SUCCESS";
}
}
service
package com.shan.service;
import org.springframework.web.multipart.MultipartFile;
public interface UploaderService {
Boolean checkChunk(String md5Value, Integer chunk, String moduleName, String fileTypeKey);
Boolean uploadChunk(MultipartFile file, String md5Value, Integer chunk, String moduleName, String fileTypeKey);
String merge(Integer chunkCount, String md5Value, String fileName, String moduleName, String fileTypeKey);
String specifiedDirectory(String fileTypeKey);
}
package com.shan.service.impl;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.shan.entity.po.CloudFile;
import com.shan.file.ResumeUploader;
import com.shan.service.UploaderService;
import com.shan.utils.ConstantUtils;
import com.shan.utils.Md5Util;
import com.shan.utils.UUIDGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.Date;
import java.util.Map;
@Service
public class UploaderServiceImpl implements UploaderService {
@Value("${spring.uploader.rootdir}")
private String fileUploadPath;
@Autowired
private ResumeUploader fileOperation;
@Override
public Boolean checkChunk(String md5Value, Integer chunk, String moduleName, String fileTypeKey) {
String path = specifiedDirectory(fileTypeKey) + moduleName + File.separator + fileTypeKey + File.separator;
return fileOperation.checkChunk(path, md5Value, chunk);
}
@Override
public Boolean uploadChunk(MultipartFile file, String md5Value, Integer chunk, String moduleName, String fileTypeKey) {
String path = specifiedDirectory(fileTypeKey) + moduleName + File.separator + fileTypeKey + File.separator;
return fileOperation.upload(file, path, md5Value, chunk);
}
@Override
public String merge(Integer chunkCount, String md5Value, String fileName, String moduleName, String fileTypeKey) {
String path = specifiedDirectory(fileTypeKey) + moduleName + File.separator + fileTypeKey + File.separator;
// 目录下如果存在相同名称的文件,对文件名称做修改 xxx(1).txt xxx(2).txt
fileName = this.verifyRepeatFile(path, fileName, 0);
Boolean merge = fileOperation.merge(path, path, md5Value, chunkCount, fileName);
if (merge) {
String filePath = path + fileName;
CloudFile cloudFile = new CloudFile();
cloudFile.setId(UUIDGenerator.getUUID());
cloudFile.setMd5(Md5Util.fastMD5(new File(filePath)));
cloudFile.setName(fileName.substring(0, fileName.lastIndexOf(".")));
cloudFile.setType(fileName.substring(fileName.lastIndexOf(".")));
cloudFile.setPath(filePath);
cloudFile.setFileSize(new File(filePath).length());
cloudFile.setGmtCreate(new Date());
//存数据库
// int save = cloudFileMapper.save(cloudFile);
int save =1;
if (save > 0) {
return cloudFile.getId();
}
}
return null;
}
/**
* 根据文件类型指定文件目录
*
* @param fileTypeKey 文件类型
*/
@Override
public String specifiedDirectory(String fileTypeKey) {
// 一、通用管理文件根路径
String fPath = fileUploadPath;
return fPath.endsWith("/") ? fPath : fPath + "/";
}
private String verifyRepeatFile(String path, String fileName, int i) {
String name = fileName.substring(0, fileName.lastIndexOf("."));
String suffix = fileName.substring(fileName.lastIndexOf("."));
String tempFileName;
if (i != 0) {
tempFileName = String.format("%s%s%d%s", name, "(", i, ")");
} else {
tempFileName = name;
}
File file = new File(path + tempFileName + suffix);
if (file.exists()) {
return verifyRepeatFile(path, name + suffix, ++i);
}
return tempFileName + suffix;
}
}
工具类 上传相关封装
ResumeUploader、CommonUploader、UploaderUtils 、UploaderUtils
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.shan.file;
import java.io.InputStream;
import java.util.List;
import com.shan.entity.bean.FileInfo;
import org.springframework.web.multipart.MultipartFile;
public interface ResumeUploader {
Boolean checkChunk(String var1, String var2, Integer var3);
Boolean compress(List<String> var1, String var2);
Boolean copy(String var1, String var2);
Boolean delete(String var1);
InputStream download(String var1);
Boolean exists(String var1);
Long getDiskSize(String var1);
List<FileInfo> listFiles(String var1, boolean var2);
Boolean merge(String var1, String var2, String var3, Integer var4, String var5);
Boolean mkDir(String var1);
Boolean move(String var1, String var2);
Boolean rename(String var1, String var2);
Boolean upload(MultipartFile var1, String var2, String var3, Integer var4);
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.shan.file;
import com.google.common.collect.Lists;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import com.shan.entity.bean.FileInfo;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Component
public class CommonUploader implements ResumeUploader {
@Value("${spring.uploader.tempdir}")
private String tempDir;
@Value("${spring.uploader.isDelTempFile}")
private Boolean isDelTempFile;
public Boolean checkChunk(String sharePath, String md5File, Integer chunk) {
Boolean isExisted = false;
String filePath = String.format("%s/%s/%s/%s.tmp", sharePath, this.tempDir, md5File, chunk);
File file = new File(filePath);
if (file.exists()) {
isExisted = true;
}
return isExisted;
}
public Boolean compress(List<String> inputFilename, String zipFilename) {
Boolean result = false;
try {
this.mkDir(zipFilename.substring(0, zipFilename.lastIndexOf("/") + 1));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFilename));
try {
String item;
String base;
for(Iterator var5 = inputFilename.iterator(); var5.hasNext(); this.zip(out, item, base)) {
item = (String)var5.next();
base = "";
String[] items = item.split("/");
if (item.lastIndexOf("/") + 1 == item.length()) {
base = items[items.length - 1] + "/";
} else {
base = items[items.length - 1];
}
}
result = true;
} catch (Throwable var10) {
try {
out.close();
} catch (Throwable var9) {
var10.addSuppressed(var9);
}
throw var10;
}
out.close();
} catch (Exception var11) {
var11.printStackTrace();
result = false;
}
return result;
}
public Boolean copy(String fromPath, String tofilePath) {
Boolean result = false;
try {
File fromFile = new File(fromPath);
File toFile = new File(tofilePath);
if (fromFile.exists()) {
if (fromFile.isDirectory()) {
FileUtils.copyDirectory(fromFile, toFile);
} else {
FileUtils.copyFile(fromFile, toFile);
}
result = toFile.exists();
}
} catch (Exception var6) {
var6.printStackTrace();
result = false;
}
return result;
}
public Boolean delete(String path) {
Boolean result = false;
try {
File remoteFile = new File(path);
if (!remoteFile.exists()) {
return false;
}
if (remoteFile.isFile()) {
result = remoteFile.delete();
} else {
FileUtils.deleteDirectory(remoteFile);
result = true;
}
} catch (Exception var4) {
var4.printStackTrace();
result = false;
}
return result;
}
public InputStream download(String fromPath) {
FileInputStream inputStream = null;
try {
File file = new File(fromPath);
if (file.exists()) {
inputStream = new FileInputStream(file);
}
} catch (Exception var4) {
var4.printStackTrace();
}
return inputStream;
}
public Boolean exists(String path) {
return (new File(path)).exists();
}
public Long getDiskSize(String path) {
return this.getDiskSizeByte(path) / 1024L;
}
private Long getDiskSizeByte(String path) {
long result = 0L;
try {
File file = new File(path);
if (file.isFile()) {
result += file.length();
} else {
File[] files = file.listFiles();
File[] var6 = files;
int var7 = files.length;
for(int var8 = 0; var8 < var7; ++var8) {
File f = var6[var8];
if (f.isFile()) {
result += f.length();
}
if (f.isDirectory()) {
result += this.getDiskSizeByte(f.getPath().substring(f.getPath().indexOf("@") + 1));
}
}
}
} catch (Exception var10) {
var10.printStackTrace();
return 0L;
}
return result;
}
public List<FileInfo> listFiles(String path, boolean calculateFolderSize) {
ArrayList result = Lists.newArrayList();
try {
File file = new File(path);
if (file.exists() && file.isDirectory()) {
File[] files = file.listFiles();
File[] var6 = files;
int var7 = files.length;
for(int var8 = 0; var8 < var7; ++var8) {
File f = var6[var8];
Boolean isFile = f.isFile();
String filePath = f.getPath();
String fileName = isFile ? f.getName() : "";
Long size = 0L;
if (isFile) {
size = f.length() / 1024L;
} else if (calculateFolderSize) {
size = this.getDiskSize(filePath.substring(filePath.indexOf("@") + 1));
}
result.add(new FileInfo(f.getName(), isFile, f.getPath(), fileName.substring(fileName.lastIndexOf(".") + 1), size));
}
}
} catch (Exception var14) {
var14.printStackTrace();
}
return result;
}
public Boolean merge(String uploadPath, String temPath, String md5File, Integer chunks, String name) {
Boolean result = false;
this.mkDir(uploadPath);
this.mkDir(temPath);
try {
FileOutputStream fileOutputStream = new FileOutputStream(String.format("%s/%s", uploadPath, name));
try {
byte[] buf = new byte[104857600];
long i = 0L;
while(true) {
if (i >= (long)chunks) {
if (this.isDelTempFile) {
this.delete(String.format("%s/%s/%s/", temPath, this.tempDir, md5File));
}
result = true;
break;
}
File file = new File(String.format("%s/%s/%s/%s.tmp", temPath, this.tempDir, md5File, i));
FileInputStream inputStream = new FileInputStream(file);
try {
boolean var13 = false;
int len;
while((len = inputStream.read(buf)) != -1) {
fileOutputStream.write(buf, 0, len);
}
} catch (Throwable var17) {
try {
inputStream.close();
} catch (Throwable var16) {
var17.addSuppressed(var16);
}
throw var17;
}
inputStream.close();
++i;
}
} catch (Throwable var18) {
try {
fileOutputStream.close();
} catch (Throwable var15) {
var18.addSuppressed(var15);
}
throw var18;
}
fileOutputStream.close();
} catch (Exception var19) {
result = false;
}
return result;
}
public Boolean mkDir(String path) {
Boolean result = false;
try {
File file = new File(path);
if (!file.exists()) {
result = file.mkdirs();
}
} catch (Exception var4) {
var4.printStackTrace();
result = false;
}
return result;
}
public Boolean move(String fromPath, String toPath) {
Boolean result = false;
try {
Boolean isCopy = this.copy(fromPath, toPath);
Boolean isDel = false;
if (isCopy) {
isDel = this.delete(fromPath);
}
result = isCopy && isDel;
} catch (Exception var6) {
var6.printStackTrace();
result = false;
}
return result;
}
public Boolean rename(String oldName, String newName) {
Boolean result = false;
try {
File oldFile = new File(oldName);
File newFile = new File(newName);
oldFile.renameTo(newFile);
result = newFile.exists();
} catch (Exception var6) {
var6.printStackTrace();
result = false;
}
return result;
}
public Boolean upload(MultipartFile file, String sharePath, String md5File, Integer chunk) {
try {
String path = String.format("%s/%s/%s/", sharePath, this.tempDir, md5File);
FileUtils.forceMkdir(new File(path));
String chunkName = chunk == null ? "0.tmp" : chunk.toString().concat(".tmp");
File savefile = new File(path.concat(chunkName));
if (!savefile.exists()) {
savefile.createNewFile();
}
file.transferTo(savefile);
} catch (IOException var8) {
return false;
}
return true;
}
private void zip(ZipOutputStream out, String inputFilename, String base) throws Exception {
File file = new File(inputFilename);
if (file.exists()) {
if (file.isDirectory()) {
File[] files = file.listFiles();
base = base.length() == 0 ? "" : base;
for(int i = 0; i < files.length; ++i) {
String filePath = files[i].getPath();
this.zip(out, filePath.substring(filePath.indexOf("@") + 1), base + files[i].getName());
}
} else {
out.putNextEntry(new ZipEntry(base));
int len = 0;
byte[] buf = new byte[104857600];
FileInputStream inputStream = new FileInputStream(file);
try {
while((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
}
} catch (Throwable var11) {
try {
inputStream.close();
} catch (Throwable var10) {
var11.addSuppressed(var10);
}
throw var11;
}
inputStream.close();
}
}
}
public String getTempDir() {
return this.tempDir;
}
public Boolean getIsDelTempFile() {
return this.isDelTempFile;
}
public void setTempDir(String tempDir) {
this.tempDir = tempDir;
}
public void setIsDelTempFile(Boolean isDelTempFile) {
this.isDelTempFile = isDelTempFile;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof CommonUploader)) {
return false;
} else {
CommonUploader other = (CommonUploader)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$isDelTempFile = this.getIsDelTempFile();
Object other$isDelTempFile = other.getIsDelTempFile();
if (this$isDelTempFile == null) {
if (other$isDelTempFile != null) {
return false;
}
} else if (!this$isDelTempFile.equals(other$isDelTempFile)) {
return false;
}
Object this$tempDir = this.getTempDir();
Object other$tempDir = other.getTempDir();
if (this$tempDir == null) {
if (other$tempDir != null) {
return false;
}
} else if (!this$tempDir.equals(other$tempDir)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof CommonUploader;
}
public int hashCode() {
int PRIME = 59;
int result = 1;
Object $isDelTempFile = this.getIsDelTempFile();
result = result * 59 + ($isDelTempFile == null ? 43 : $isDelTempFile.hashCode());
Object $tempDir = this.getTempDir();
result = result * 59 + ($tempDir == null ? 43 : $tempDir.hashCode());
return result;
}
public String toString() {
return "CommonUploader(tempDir=" + this.getTempDir() + ", isDelTempFile=" + this.getIsDelTempFile() + ")";
}
public CommonUploader() {
}
public CommonUploader(String tempDir, Boolean isDelTempFile) {
this.tempDir = tempDir;
this.isDelTempFile = isDelTempFile;
}
}
package com.shan.utils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Util {
private static final char[] hexCode = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public static String calcMD5(File file) {
try (InputStream stream = Files.newInputStream(file.toPath(), StandardOpenOption.READ)) {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] buf = new byte[8192];
int len;
while ((len = stream.read(buf)) > 0) {
digest.update(buf, 0, len);
}
return toHexString(digest.digest());
} catch (IOException | NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
private static String toHexString(byte[] data) {
StringBuilder r = new StringBuilder(data.length * 2);
for (byte b : data) {
r.append(hexCode[(b >> 4) & 0xF]);
r.append(hexCode[(b & 0xF)]);
}
return r.toString().toLowerCase();
}
public static String calcMd5(String s) {
if (s == null || "".equals(s)) {
return "";
}
try {
byte[] strTemp = s.getBytes();
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(strTemp);
byte[] md = mdTemp.digest();
int j = md.length;
char[] str = new char[j * 2];
int k = 0;
for (byte byte0 : md) {
str[k++] = hexCode[byte0 >>> 4 & 0xf];
str[k++] = hexCode[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* Fast MD5 PLUS
*/
public static String fastMD5(File file) {
int len = 10000;
try {
if(file.length() < 10000000){
return com.twmacinta.util.MD5.asHex(com.twmacinta.util.MD5.getHash(file));
}
byte pond[] =new byte [len];
RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(file.length() - len);
raf.read(pond, 0, len);
return calcMd5(toHexString(pond));
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
public static void main(String[] args) {
File file = new File("D:\\软件\\360极速浏览器.zip");
String s = Md5Util.fastMD5(file);
System.out.println(s);
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.shan.utils;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
public class UploaderUtils {
private static final Logger logger = LoggerFactory.getLogger(UploaderUtils.class);
public UploaderUtils() {
}
public static String uploadFile(MultipartFile file, String filePath) {
String fileName = file.getOriginalFilename();
String newFileName = DateUtils.getInstance().dateFormat(new Date(System.currentTimeMillis()));
String ext = "";
if (!StringUtils.isEmpty(fileName)) {
ext = fileName.substring(fileName.lastIndexOf("."), fileName.length());
}
//目标路径+当时时间 yyyy-MM-dd
String targetFilePath = filePath + File.separator + DateUtils.getInstance().dateFormat10(System.currentTimeMillis());
logger.info("上传路径{}", targetFilePath);
System.out.println();
File targetFile = new File(targetFilePath, newFileName + ext);
if (!targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
try {
file.transferTo(targetFile);
} catch (IllegalStateException var7) {
var7.printStackTrace();
} catch (IOException var8) {
var8.printStackTrace();
}
return targetFile.getPath();
}
}
前端代码 先不放了 因公司保密性 参数放上了可以直接调用
测试
1、检查分片是否存在
chunk 0
md5Value e80c5740b90c9366d0ab0b271f8a10c8
moduleName
fileTypeKey 3D/DCV/v1
2、上传分片
file 选择文件
chunk 0
md5Value e80c5740b90c9366d0ab0b271f8a10c8
moduleName
fileTypeKey 3D/DCV/v1
上传后看上传的位置 会生成分片文件
3、合并分片
fileName test2.xls
chunkCount 1
md5Value e80c5740b90c9366d0ab0b271f8a10c8
moduleName
fileTypeKey 3D/DCV/v1
合并分片后会删除 临时分片文件 并生成原文件
文件夹上传
前台分为点击上传文件夹和拖拽文件夹
思路:
* 文件夹上传 前台分为点击上传文件夹和拖拽上传文件夹
* 1. 对文件夹中的文件循环校验 /uploader/beforeUpload方法
* 2. 上传文件夹 /uploader/uploadFolder方法
/**
* 文件夹上传 前台分为点击上传文件夹和拖拽上传文件夹
* 1. 对文件夹中的文件循环校验 /uploader/beforeUpload方法
* 2. 上传文件夹 /uploader/uploadFolder方法
* @param request
* fileId = 在非第一级上传文件时,fileId有值-为所在文件夹的id,上传的路径为 云盘的根路径+上文件的路径
* file 上传的文件夹 多个文件
* names 前台分为点击上传文件夹和拖拽上传文件夹
* 点击上传文件夹时,文件的名称中不包含层级关系
* 拖拽上传文件夹,文件的名称中包含层级关系,names参数为拖拽上传时使用,里面包含所有文件的层级关系
* 如 names: /360驱动大师目录/下载保存目录/audio_conexant_8.66.83.51_w1064.zip.mem,/360驱动大师目录/下载保存目录/audio_conexant_8.66.83.51_w1064.zip.trt
* @return
*/
@PostMapping("uploadFolder")
public Boolean uploadFolder(HttpServletRequest request) {
try {
MultipartHttpServletRequest params = ((MultipartHttpServletRequest) request);
// 在非第一级上传文件时,fileId有值-为所在文件夹的id,上传的路径为 根路径+上文件的路径
String fileId = params.getParameter("fileId");
fileId = StringUtils.isBlank(fileId) ? "0" : fileId;
String filePath = "0".equals(fileId) ? "" : uploaderService.getFilePathByFileId(fileId);
String targetDirectoryPath = uploaderService.rootPath() + filePath;
List<MultipartFile> files = params.getFiles("file");
String fileParentPaths = params.getParameter("names");
String[] fileParentPathArr = null;
if (StringUtils.isNoneBlank(fileParentPaths)) {
fileParentPathArr = fileParentPaths.split(",");
}
//上传人 用户名 用于给上传文件夹赋权限 实际取此处写死模拟
String userName ="SHANC";
for (int i = 0; files.size() > i; i++) {
MultipartFile multipartFile = files.get(i);
String originalFilename = "/" + multipartFile.getOriginalFilename();
originalFilename = StringUtils.isNotBlank(fileParentPaths) && fileParentPathArr != null ? fileParentPathArr[i] : originalFilename;
System.out.println("文件上传路径为:" + targetDirectoryPath + originalFilename);
File file = new File(targetDirectoryPath + originalFilename);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
try {
multipartFile.transferTo(file);
} catch (Exception e) {
e.printStackTrace();
}
}
if (StringUtils.isNoneBlank(userName)) {
new Thread(() -> FileUploadUtils.chown(userName, targetDirectoryPath)).start();
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
用的工具类FileUploadUtils
package com.cloud.user.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.system.OsInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DecimalFormat;
@Slf4j
public class FileUploadUtils {
/**
* 点
*/
public static final String DOT = ".";
/**
* 直接预览的文件类型(不通过LibreOffice转换)
*/
public static final String PDF = "pdf";
private static String transfer(MultipartFile file, File targetFile) {
try {
file.transferTo(targetFile);
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
return targetFile.getPath();
}
private static void mkParentFile(File targetFile) {
if (!targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
}
public static String readableFileSize(long size) {
if (size <= 0) {
return "0";
}
final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
/**
* 文件上传
*
* @param file 文件
* @param filePath 文件路径
* @return 文件路径
*/
public static String upload(MultipartFile file, String filePath) {
File targetFile = new File(filePath, file.getOriginalFilename().replaceAll(" ", ""));
mkParentFile(targetFile);
return transfer(file, targetFile);
}
/**
* 处理文件上传
*
* @param file 上传的文件
* @param targetFile 目标文件
* @return 上传文件目录
*/
public static String upload(MultipartFile file, File targetFile) {
mkParentFile(targetFile);
return transfer(file, targetFile);
}
/**
* 批量删除文件或文件夹
*
* @param filePaths 文件路径
*/
public static void deletes(String[] filePaths) {
for (String path : filePaths) {
delete(path);
}
}
/**
* 删除文件或文件夹
*
* @param filePath 文件路径
* @return 成功与否
*/
public static boolean delete(String filePath) {
return FileUtil.del(new File(filePath));
}
/**
* 处理文件上传
*
* @param file 文件
* @param filePath 文件路径
* @param newFileName 新文件名称
* @return 文件大小
*/
public static Long uploadFileContinue(MultipartFile file, String filePath, String newFileName) {
// 记录当前文件大小,用于判断文件是否上传完成
long currentFileLength = 0;
try {
String fileName = file.getOriginalFilename();
RandomAccessFile randomAccessfile;
// 获取文件的扩展名
String ext = "";
if (!StringUtils.isEmpty(fileName)) {
ext = fileName.substring(fileName.lastIndexOf(DOT));
}
File newFile = new File(filePath + newFileName + ext);
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
// 存在文件
if (newFile.exists()) {
randomAccessfile = new RandomAccessFile(newFile, "rw");
} else {
// 不存在文件,根据文件标识创建文件
randomAccessfile = new RandomAccessFile(filePath + newFileName + ext, "rw");
}
// 开始文件传输
InputStream in = file.getInputStream();
if (randomAccessfile.length() < file.getInputStream().available()) {
randomAccessfile.seek(randomAccessfile.length());
in.skip(randomAccessfile.length());
byte[] b = new byte[1024];
int n;
while ((n = in.read(b)) != -1) {
randomAccessfile.write(b, 0, n);
}
}
currentFileLength = randomAccessfile.length();
// 关闭文件
closeRandomAccessFile(randomAccessfile);
} catch (Exception e) {
e.printStackTrace();
}
return currentFileLength;
}
/**
* 关闭随机访问文件
*
* @param randomAccessFile 随机访问的文件
*/
private static void closeRandomAccessFile(RandomAccessFile randomAccessFile) {
if (null != randomAccessFile) {
try {
randomAccessFile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 转换PDF文件
*
* @param filePath 当前文件路径
* @return PDF文件转换的全路径
*/
public static String convertToPDF(String filePath, String targetPath) {
log.info("filePath:{}", filePath);
log.info("targetPath:{}", targetPath);
String windowsPath = "D:/apache-tomcat-8.5.64/webapps/upload/";
String command = null;
String pdfPath = null;
if (isLinux()) {
command = "/usr/bin/libreoffice6.1 --headless --invisible --convert-to pdf " + filePath + " --outdir " + targetPath;
pdfPath = targetPath + "/" + changeSuffix(filePath, PDF);
} else if (isWindows()) {
command = "cmd /c start soffice --headless --invisible --convert-to pdf:writer_pdf_Export " + filePath + " --outdir " + windowsPath;
pdfPath = windowsPath + changeSuffix(filePath, PDF);
}
System.out.println("pdf command: " + command);
Process exec = RuntimeUtil.exec(command);
try {
long startTime = System.currentTimeMillis();
exec.waitFor();
System.out.println("等待时长:" + (System.currentTimeMillis() - startTime));
} catch (InterruptedException e) {
e.printStackTrace();
}
return pdfPath;
}
/**
* 更改文件后缀
*
* @param filePath 当前文件路径
* @param suffix 后缀
* @return 更改后的文件名
*/
public static String changeSuffix(String filePath, String suffix) {
return getPrefix(filePath) + DOT + suffix;
}
/**
* 判断当前OS的类型
*
* @return boolean
*/
public static boolean isWindows() {
return new OsInfo().isWindows();
}
/**
* 判断当前OS的类型
*
* @return boolean
*/
public static boolean isLinux() {
return new OsInfo().isLinux();
}
/**
* 根据文件名检查文件类型,忽略大小写
*
* @param fileName 文件名,例如hutool.png
* @param extNames 被检查的扩展名数组,同一文件类型可能有多种扩展名,扩展名不带“.”
* @return 是否是指定扩展名的类型
*/
public static boolean isType(String fileName, String... extNames) {
return FileNameUtil.isType(fileName, extNames);
}
/**
* 获取文件名(包含后缀名)
*
* @return 文件名
*/
public static String getName(String filePath) {
return FileNameUtil.getName(filePath);
}
/**
* 获取前缀名
*
* @return 文件前缀名
*/
public static String getPrefix(String filePath) {
return FileNameUtil.getPrefix(filePath);
}
/**
* 获取后缀名(不包括 ".")
*
* @return 文件后缀名
*/
public static String getSuffix(String filePath) {
return FileNameUtil.getSuffix(filePath);
}
/**
* 文件复制(不覆盖目标文件)
*
* @param srcPath 源文件
* @param destPath 目标文件
*/
public static File copy(String srcPath, String destPath) {
return FileUtil.copy(srcPath, destPath, false);
}
// public static void main(String[] args) {
// copy("C:\\Users\\lenovo\\Desktop\\123","C:\\Users\\lenovo\\Desktop\\456");
// }
/**
* 取得OS的文件路径的分隔符(取自系统属性:<code>file.separator</code>)。
*
* <p>
* 例如:Unix为<code>"/"</code>,Windows为<code>"\\"</code>。
* </p>
*
* @return 属性值,如果不能取得(因为Java安全限制)或值不存在,则返回<code>null</code>。
*/
public static String getFileSeparator() {
return new OsInfo().getFileSeparator();
}
public static void downloadFile(HttpServletRequest request, HttpServletResponse response, InputStream inputStream, String fileName) {
try (OutputStream os = response.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(inputStream);
BufferedOutputStream bos = new BufferedOutputStream(os)) {
// 处理下载文件名的乱码问题(根据浏览器的不同进行处理)
if (request.getHeader("User-Agent").toLowerCase().indexOf("firefox") > 0) {
fileName = new String(fileName.getBytes("GB2312"), "ISO-8859-1");
} else {
// 对文件名进行编码处理中文问题
fileName = java.net.URLEncoder.encode(fileName, "UTF-8");// 处理中文文件名的问题
fileName = new String(fileName.getBytes("UTF-8"), "GBK");// 处理中文文件名的问题
}
response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/x-msdownload");// 不同类型的文件对应不同的MIME类型
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
int bytesRead = 0;
byte[] buffer = new byte[4096];
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
bos.flush();
}
} catch (Exception ex) {
throw new RuntimeException(ex.getMessage());
}
}
/**
* 删除单个文件
*
* @param sPath 被删除文件的文件名
* @return 单个文件删除成功返回true,否则返回false
*/
public static boolean deleteFile(String sPath) {
boolean flag = false;
File file = new File(sPath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
flag = true;
}
return flag;
}
/**
* 删除目录(文件夹)以及目录下的文件
*
* @param path 被删除目录的文件路径
* @return 目录删除成功返回true,否则返回false
*/
public static boolean deleteDirectory(String path) {
File dirFile = new File(path);
// 如果dir对应的文件不存在,或者不是一个目录,则退出
if (!dirFile.exists() || !dirFile.isDirectory()) {
return false;
}
boolean flag = true;
// 删除文件夹下的所有文件(包括子目录)
File[] files = dirFile.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {// 删除子文件
flag = deleteFile(files[i].getAbsolutePath());
if (!flag) {
break;
}
} else {// 删除子目录
flag = deleteDirectory(files[i].getAbsolutePath());
if (!flag) {
break;
}
}
}
if (!flag) {
return false;
}
if (dirFile.delete()) {// 删除当前目录
return true;
} else {
return false;
}
}
public static void chown(String userName, String path) {
String run = RuntimeUtils.execute("id -u " + userName);
String run2 = RuntimeUtils.execute("id -g " + userName);
RuntimeUtils.execute("chown -R " + run + ":" + run2 + " " + path);
}
}
此处用Apipost模拟下