这篇文章主要为大家详细介绍了如何利用Java语言实现文件分片上传的功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
java后端分片上传接口
文件上传工具--FileUtil
package com.youmejava.chun.util;
import lombok.Data;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 文件工具
*/
@Data
public class FileUtil {
private List<File> filelist;//文件列表
private String strPath;//路径
public FileUtil() {
}
public FileUtil(List<File> filelist, String strPath) {
this.filelist = filelist;
this.strPath = strPath;
getFileList(this.strPath);
}
/**
* 获取文件列表
* @param strPath
* @return
*/
public List<File> getFileList(String strPath) {
File dir = new File(strPath);
File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
if (files != null) {
for (int i = 0; i < files.length; i++) {
String fileName = files[i].getName();
if (files[i].isDirectory()) { // 判断是文件还是文件夹
getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径
} else { // 判断文件名
String strFileName = files[i].getAbsolutePath();
// System.out.println("---" + strFileName);
filelist.add(files[i]);
}
}
}
return filelist;
}
/**
* 合并文件
* @param from
* @param to
* @throws IOException
*/
public static void mergeFile(String from, String to) throws IOException {
File t = new File(to);
FileInputStream in = null;
FileChannel inChannel = null;
System.out.println("t "+t);
FileOutputStream out = new FileOutputStream(t,true);
FileChannel outChannel = out.getChannel();
File f = new File(from);
System.out.println("f "+f.isDirectory());
// 获取目录下的每一个文件名,再将每个文件一次写入目标文件
if (f.isDirectory()) {
List<File> list = getAllFileAndSort(from);
System.out.println("sortlist "+list);
// 记录新文件最后一个数据的位置
long start = 0;
for (File file : list) {
in = new FileInputStream(file);
inChannel = in.getChannel();
// 从inChannel中读取file.length()长度的数据,写入outChannel的start处
outChannel.transferFrom(inChannel, start, file.length());
start += file.length();
in.close();
inChannel.close();
}
}
out.close();
outChannel.close();
}
/**
* 所有文件排序
* @param dirPath 文件根目录路径
* @return
*/
public static List<File> getAllFileAndSort(String dirPath) {
File dirFile = new File(dirPath);
File[] listFiles = dirFile.listFiles();
List<File> list = Arrays.asList(listFiles);
Collections.sort(list, (o1, o2) -> {
String _str=o1.getName().split("\\.")[0];
String _num=_str.split("_")[1];
String _str2=o2.getName().split("\\.")[0];
String _num2=_str2.split("_")[1];
return Integer.parseInt(_num) - Integer.parseInt(_num2);
});
return list;
}
/**
* 删除文件夹
* 删除文件夹需要把包含的文件及文件夹先删除,才能成功
* https://blog.csdn.net/m0_57640408/article/details/120774050
* @param directory 文件夹名
* @return 删除成功返回true,失败返回false
*/
public static boolean deleteDirectory(String directory) {
// directory不以文件分隔符(/或\)结尾时,自动添加文件分隔符,不同系统下File.separator方法会自动添加相应的分隔符
if (!directory.endsWith(File.separator)) {
directory = directory + File.separator;
}
File directoryFile = new File(directory);
// 判断directory对应的文件是否存在,或者是否是一个文件夹
if (!directoryFile.exists() || !directoryFile.isDirectory()) {
System.out.println("文件夹删除失败,文件夹不存在" + directory);
return false;
}
boolean flag = true;
// 删除文件夹下的所有文件和文件夹
File[] files = directoryFile.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) {
System.out.println("删除失败");
return false;
}
// 最后删除当前文件夹
if (directoryFile.delete()) {
System.out.println("删除成功:" + directory);
return true;
} else {
System.out.println("删除失败:" + directory);
return false;
}
}
/**
* 删除文件
*
* @param fileName 文件名
* @return 删除成功返回true,失败返回false
*/
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
if (file.isFile() && file.exists()) {
file.delete();
System.out.println("删除文件成功:" + fileName);
return true;
} else {
System.out.println("删除文件失败:" + fileName);
return false;
}
}
}
分片上传文件接口
package com.youmejava.chun.commoninterface;
import com.youmejava.chun.util.FileUtil;
import com.youmejava.chun.util.ResultVo;
import com.youmejava.chun.util.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/apiSystem/upload")
@Api(value = "文件上传", tags = "文件上传")
public class UploadController {
@Value("${filePath1}")
private String filePath;
@PostMapping("/register")
@ApiOperation(value = "文件注册", notes = "文件注册")
@ApiImplicitParams({@ApiImplicitParam(value = "哈希值", name = "hash", required = true, paramType = "body")})
public ResultVo register(@RequestBody Map<String, Object> map) {
System.out.println("hash: " + map.get("hash"));
if (!StringUtil.isNotBlankAndNull(map.get("hash").toString())) {
// return ResultVo.failure("哈希值不可为空");
throw new ExpiredCredentialsException("哈希值不可为空!");
}
String _filePath=filePath;
if (!_filePath.endsWith("/")) {
_filePath+="/";
}
// String _pathStr = "C:\\Users\\JH-rent\\Desktop\\java启动文件\\test" + "\\" + map.get("hash");
String _pathStr=_filePath+map.get("hash");
//创建不同的文件夹目录
File file = new File(_pathStr);
//判断文件夹是否存在
if (!file.exists()) {
//如果文件夹不存在,则创建新的的文件夹
file.mkdirs();
}
File f = new File(_pathStr);
// 检查目录是否已上传过文件,如果上传过,返回上传个数
if (f.isDirectory()) {
File dirFile = new File(_pathStr);
File[] listFiles = dirFile.listFiles();
List<File> list = Arrays.asList(listFiles);
if (list == null&&list.size()>0) {
Map<String, Object>map1=new HashMap<>();
map1.put("number",list.size());
return ResultVo.success(map1);
}
}
return ResultVo.success();
}
@PostMapping("/uploadFile")
@ResponseBody
@ApiOperation(value = "上传文件", notes = "上传文件")
@ApiImplicitParams({@ApiImplicitParam(value = "哈希值", name = "hash", required = true, paramType = "body"), @ApiImplicitParam(value = "文件流", name = "file", required = true, paramType = "body"), @ApiImplicitParam(value = "文件名称", name = "fileName", required = true, paramType = "body"),})
public ResultVo uploadFile(HttpServletRequest request) {
MultipartHttpServletRequest params = ((MultipartHttpServletRequest) request);
List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
String _fileName = params.getParameter("fileName");
String _hash = params.getParameter("hash");
if (!StringUtil.isNotBlankAndNull(_hash)) {
throw new ExpiredCredentialsException("哈希值不可为空!");
}
if (!StringUtil.isNotBlankAndNull(_fileName)) {
throw new ExpiredCredentialsException("文件名称不可为空!");
}
// System.out.println("_fileName: " + _fileName);
// System.out.println("_hash: " + _hash);
// System.out.println("files: " + files);
// System.out.println(params.getParameter("file"));
// String _pathStr = "C:\\Users\\JH-rent\\Desktop\\java启动文件\\test" + "\\" + _hash + "\\";
String _filePath=filePath;
if (!_filePath.endsWith("/")) {
_filePath+="/";
}
String _pathStr =_filePath+_hash+"/";
FileOutputStream fileOut = null;
//写入到文件(注意文件保存路径的后面一定要加上文件的名称)
try {
fileOut = new FileOutputStream(_pathStr + _fileName);
BufferedOutputStream bos = new BufferedOutputStream(fileOut);
BufferedInputStream bis = null;
for (MultipartFile file : files) {
// file.transferTo(new File(_pathStr + file.getOriginalFilename()));
// System.out.println(file.getInputStream());
bis = new BufferedInputStream(file.getInputStream());
}
byte[] buf = new byte[4096];
int length = bis.read(buf);
//保存文件
while (length != -1) {
bos.write(buf, 0, length);
length = bis.read(buf);
}
bos.close();
bis.close();
return ResultVo.success();
} catch (Exception e) {
e.printStackTrace();
return ResultVo.failure(e.getMessage());
}
}
@GetMapping("/getMergeFile")
@ApiOperation(value = "获取合并文件", notes = "获取合并文件")
@ApiImplicitParams({@ApiImplicitParam(value = "哈希值", name = "hash", required = true, dataType = "String"), @ApiImplicitParam(value = "文件名称", name = "fileName", required = true, dataType = "String")})
public ResultVo getMergeFile(@RequestParam(value = "hash") String hash, @RequestParam(value = "fileName") String fileName) {
// String _pathStr = "C:\\Users\\JH-rent\\Desktop\\java启动文件\\test" + "\\" + hash + "\\";
// String _pathStr1 = "C:\\Users\\JH-rent\\Desktop\\java启动文件\\test";
String _filePath=filePath;
if (!_filePath.endsWith("/")) {
_filePath+="/";
}
String _pathStr = _filePath + hash + "/";
String _pathStr1 = _filePath;
try {
// if (!_pathStr1.endsWith("\\")) {
// _pathStr1 += "\\";
// }
_pathStr1 += fileName;
FileUtil.mergeFile(_pathStr, _pathStr1);
//合并成功删除加密文件
FileUtil.deleteDirectory(_pathStr);
} catch (IOException e) {
e.printStackTrace();
}
Map<String, Object>map=new HashMap<>();
map.put("fileUrl",_pathStr1);
return ResultVo.success(map);
}
}
前端分片
单个文件下载或者分批压缩多个文件下载
import JSZip from "jszip";
import fileSaver from "file-saver";
import axios from 'axios'
import {
Message,
Notification
} from "element-ui";
//下载单个文件
export const downloadSingleFile = (url, filename) => {
filename = filename || "文件名";
let suffix = /\.([0-9a-zA-Z]+)$/i.exec(url)[1];
const file_type = {
'doc': 'application/msword',
'bin': 'application/octet-stream',
'exe': 'application/octet-stream',
'so': 'application/octet-stream',
'dll': 'application/octet-stream',
'pdf': 'application/pdf',
'ai': 'application/postscript',
'xls': 'application/vnd.ms-excel',
'ppt': 'application/vnd.ms-powerpoint',
'dir': 'application/x-director',
'js': 'application/x-javascript',
'swf': 'application/x-shockwave-flash',
'xhtml': 'application/xhtml+xml',
'xht': 'application/xhtml+xml',
'zip': 'application/zip',
'mid': 'audio/midi',
'midi': 'audio/midi',
'mp3': 'audio/mpeg',
'rm': 'audio/x-pn-realaudio',
'rpm': 'audio/x-pn-realaudio-plugin',
'wav': 'audio/x-wav',
'bmp': 'image/bmp',
'gif': 'image/gif',
'jpeg': 'image/jpeg',
'jpg': 'image/jpeg',
'png': 'image/png',
'css': 'text/css',
'html': 'text/html',
'htm': 'text/html',
'txt': 'text/plain',
'xsl': 'text/xml',
'xml': 'text/xml',
'mpeg': 'video/mpeg',
'mpg': 'video/mpeg',
'avi': 'video/x-msvideo',
'movie': 'video/x-sgi-movie',
}
return new Promise((resolve, reject) => {
console.log(url, "url");
axios
.get(url, {
responseType: 'blob',
})
.then((res) => {
const blob = new Blob([res.data], {
type: file_type[suffix]
}) // 构造一个blob对象来处理数据,并设置文件类型
if (window.navigator.msSaveOrOpenBlob) {
// 兼容IE10
navigator.msSaveBlob(blob, filename)
} else {
const href = URL.createObjectURL(blob) // 创建新的URL表示指定的blob对象
const a = document.createElement('a')
a.style.display = 'none'
a.href = href // 指定下载链接
a.download = filename // 指定下载文件名
a.click()
URL.revokeObjectURL(a.href) // 释放URL对象
a.remove();
}
resolve("下载成功!")
})
})
}
let file_num = 0;
const zip = new JSZip();
let zip_obj = [];
let floder_obj = [];
let file_order = 0;
let file_floder = null;
let file_data = [];
let file_title = "";
let cur_title = "";
let breakpoint_num = 500; //断点数据
let allowZipFile = true; //等待压缩完成
/**
* [链接数组]
* @param {[type]} paths [{"name":"初三排课班级课表","path":""}]
* @return {[type]} 下载压缩文件 [description]
*/
export const downloadCompressedFiles = ({
paths = [],
title = "文件批量下载",
percentCallback = () => {},
}) => {
allowZipFile = true;
file_order = 0;
cur_title = (title && title) || "文件批量下载";
file_title = paths.length > breakpoint_num ? title ? `${title}文件第1~${breakpoint_num}个` : `文件批量下载文件1~${breakpoint_num}个` : (title && title) || "文件批量下载";
zip_obj[file_order] = new JSZip();
floder_obj[file_order] = zip_obj[file_order].folder(file_title);
// file_floder = zip.folder((title && title) || "文件批量下载");
file_num = 0;
if (paths.length) {
file_data = paths;
if (file_num < paths.length) {
getUrlBlod(paths[file_num].path, paths[file_num].name, percentCallback);
}
}
}
const getUrlBlod = (url, name, percentCallback = () => {}) => {
// 从url获取文件后缀
let suffix = /\.([0-9a-zA-Z]+)$/i.exec(url)[1];
let promise = httpPost({
url
}).then((data) => {
console.log(file_order, "data123");
// console.log(floder_obj[file_order]);
floder_obj[file_order].file(`${name}.${suffix}`, data, {
binary: true
}); //逐个添加文件
file_num = file_num + 1;
if (file_num != file_data.length) {
if (file_num % breakpoint_num == 0) {
let _temp = file_order;
file_order = file_order + 1;
// file_title = (breakpoint_num + file_num) <= file_data.length ? `${cur_title}文件第${breakpoint_num*_temp}~${file_num}个` : `${cur_title}文件第${file_num}~${file_data.length}个`;
file_title=`${cur_title}文件第${breakpoint_num*_temp}~${file_num}个`;
zip_obj[file_order] = new JSZip();
floder_obj[file_order] = zip_obj[file_order].folder((file_title && file_title) || "文件批量下载");
Notification({
title: '提示',
message: file_title + '开始压缩文件中!请等待',
type: 'info',
duration: 0
});
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
percentCallback(file_num)
if (allowZipFile) {
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
}
} else {
if (file_num >= file_data.length) {
file_title = `${cur_title}文件第${breakpoint_num * file_order}~${file_data.length}个`;
}
let _temp = file_order;
Notification({
title: '提示',
message: file_title + '开始压缩文件中!请等待',
type: 'info',
duration: 0
});
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
return file_num;
}).catch(err => {
// console.log(err, "err123");
// Message.error(`${name}文件下载失败!`);
file_num = file_num + 1;
if (file_num != file_data.length) {
if (file_num % breakpoint_num == 0) {
let _temp = file_order;
file_order = file_order + 1;
// file_title = (breakpoint_num + file_num) <= file_data.length ? `${cur_title}文件第${breakpoint_num*_temp}~${file_num}个` : `${cur_title}文件第${file_num}~${file_data.length}个`;
file_title=`${cur_title}文件第${breakpoint_num*_temp}~${file_num}个`;
zip_obj[file_order] = new JSZip();
floder_obj[file_order] = zip_obj[file_order].folder(file_title);
Notification({
title: '提示',
message: file_title + '开始压缩文件中!请等待',
type: 'info',
duration: 0
});
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
percentCallback(file_num)
if (allowZipFile) {
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
}
} else {
if (file_num >= file_data.length) {
file_title = `${cur_title}文件第${breakpoint_num * file_order}~${file_data.length}个`;
}
Notification({
title: '提示',
message: file_title + '开始压缩文件中!请等待',
type: 'info',
duration: 0
});
let _temp = file_order;
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
});
}
const zipGenerateAsync = (num, percentCallback = () => {}) => {
zip_obj[num].generateAsync({
type: "blob"
}).then((content) => {
Notification({
title: '成功',
message: file_title + '压缩文件下载成功',
type: 'success',
duration: 0
});
// 生成二进制流
fileSaver.saveAs(
content,
(file_title && `${file_title}.zip`) || "文件批量下载.zip"
); // 利用file-saver保存文件
// Message.error(`压缩文件下载成功!`);
if (file_num == file_data.length) {
file_num = file_num + 1;
}
percentCallback(file_num);
zip_obj[num] = "";
floder_obj[num] = "";
if (file_num < file_data.length) {
allowZipFile = true;
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
}
// Message({
// message: '压缩包文件下载成功!',
// type: 'success'
// });
}).catch(err => {
console.log(err, "压缩下载失败");
zip_obj[num] = "";
floder_obj[num] = "";
allowZipFile = true;
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
Notification.error({
title: '错误',
message: file_title + '压缩下载失败',
duration: 0
});
});
}
const getInPath = (url, name = "") => {
return new Promise(async (resolve, reject) => {
// let result = await axiosDownload(url);
// if (result) {
// resolve(result.data);
// } else {
// reject();
// }
await axiosDownload(url).then(res => {
resolve(res.data)
}).catch(err => {
reject(err)
})
});
};
const axiosDownload = (url, resOpts = {}) => {
const {
type = "get", data = ""
} = resOpts;
const queryArgs = {
url,
method: type,
data,
responseType: "blob",
// headers: {//这个地方看情况而定,如果打开会存在跨域问题
// Accept: "application/json",
// "Content-Type": "application/json; charset=utf-8",
// withCredentials: true,
// },
};
// tips: 这里直接返回的是response整体!
return new Promise((resolve, reject) =>
axios
.request(queryArgs)
.then((res) => resolve(res))
.catch((err) => reject(err))
);
};
const axiosConfig = {
// headers: {
// 'Content-Type': 'application/json;charset=UTF-8',
// },
// timeout: 60000,
responseType: 'blob',
}
const request = axios.create(axiosConfig);
let isRefreshing = false;
let queue = [];
let runQueue = () => {
isRefreshing = true
let first = queue.shift();
first.request()
}
//请求拦截
//所有的网络请求都会先走这个方法
// 添加请求拦截器,所有的网络请求都会先走这个方法,我们可以在它里面为请求添加一些自定义的内容
request.interceptors.request.use((config) => {
// 在发送请求之前做些什么
return config;
}, function (error) {
return Promise.reject(error);
});
// 添加响应拦截器
request.interceptors.response.use(function (response) {
isRefreshing = false
if (!(queue.length === 0)) runQueue()
return response.data
}, function (error) {
console.log(error, 2343);
isRefreshing = false
if (!(queue.length === 0)) runQueue()
// 对响应错误做点什么
return Promise.reject(error);
});
const httpPost = async ({
url,
method = 'get',
data = "",
}) => {
return new Promise((resolve, reject) => {
queue.push({
request: () => {
request({
method,
url,
data,
}).then(res => {
resolve(res)
}).catch(e => {
reject(e)
})
}
})
if (!isRefreshing) runQueue()
})
}
以上就是Java实现文件分片上传接口的示例代码的详细内容,更多关于Java文件分片上传的资料请关注编程学习网其它相关文章!
沃梦达教程
本文标题为:Java实现文件分片上传接口的示例代码
基础教程推荐
猜你喜欢
- java实现多人聊天系统 2023-05-19
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- Java并发编程进阶之线程控制篇 2023-03-07
- springboot自定义starter方法及注解实例 2023-03-31
- Java实现线程插队的示例代码 2022-09-03
- java基础知识之FileInputStream流的使用 2023-08-11
- Java数据结构之对象比较详解 2023-03-07
- Java实现查找文件和替换文件内容 2023-04-06
- Java文件管理操作的知识点整理 2023-05-19
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02