赞
踩
由于java天生缺陷 但是项目需要上传大文件,所以做了一个分片上传,话不多说.............................
UploadFileUtil.java 工具包 utils层
- /**
- * 分片上传与断点续传
- *
- * @param multipartFileParam 分片实体
- * @param targetPath 目标路径
- * @return 待定
- */
- public ApiResult uploadAppendFile(MultipartFileParam multipartFileParam, String targetPath) {
- String[] bin=multipartFileParam.getFileName ().split ("\\.");
- Map<String, String> map = new HashMap<>();
- if(!bin[1].equals ("bin")){
- map.put("result", "文件格式错误");
- log.error ("文件格式不对,请检查升级文件");
- return ResultUtil.error (map);
- }
-
-
-
- long chunk = multipartFileParam.getChunkNumber();
- long totalChunks = multipartFileParam.getTotalChunks();
- long fileSize = multipartFileParam.getFileSize();
- String taskId = multipartFileParam.getTaskId();
- MultipartFile file = multipartFileParam.getFile();
- String fileName = multipartFileParam.getFileName();
- // String extName = FileUtil.extName(fileName);
- // String separator = FileUtil.FILE_SEPARATOR;
- String localPath = targetPath + separator;
- File tempFile = null;
- RandomAccessFile raf = null;
- InputStream is = null;
- try {
- if (chunk == 1) {
- String tempFileName = taskId + fileName.substring(fileName.lastIndexOf(".")) + "_tmp";
- File fileDir = new File(localPath);
- if (!fileDir.exists()) {
- fileDir.mkdirs();
- }
- tempFile = new File(localPath, tempFileName);
- if (!tempFile.exists()) {
- tempFile.createNewFile();
-
- }
- raf = new RandomAccessFile(tempFile, "rw");
- is = file.getInputStream();
- raf.seek(0);
- int len = 0;
- byte[] bytes = new byte[1024 * 10];
- while ((len = is.read(bytes)) != -1) {
- raf.write(bytes, 0, len);
- }
- raf.close();
- is.close();
- redisUtil.setObject(UpLoadConstant.chunkNum + taskId, chunk, cacheTime);
- redisUtil.setObject(UpLoadConstant.fastDfsPath + taskId, tempFile.getPath(), cacheTime);
- map.put("result", "上传成功");
- } else {
- String path = (String) redisUtil.getObject(UpLoadConstant.fastDfsPath + taskId);
- is = file.getInputStream();
- raf = new RandomAccessFile(path, "rw");
- raf.seek(fileSize);
- int len = 0;
- byte[] bytes = new byte[1024 * 10];
- while ((len = is.read(bytes)) != -1) {
- raf.write(bytes, 0, len);
- }
- redisUtil.setObject(UpLoadConstant.chunkNum + taskId, chunk, cacheTime);
- raf.close();
- is.close();
- }
- String md5 = (String) redisUtil.getObject(UpLoadConstant.task + taskId);
- HashMap<String, String> redisMap = new HashMap<>();
- redisMap.put("fileSize", fileSize + "");
- redisMap.put("taskId", taskId);
-
- redisUtil.setHashAsMap(UpLoadConstant.fileMd5 + md5, redisMap, cacheTime);
- if (chunk == totalChunks) {
- String path = (String) redisUtil.getObject(UpLoadConstant.fastDfsPath + taskId);
- // FileUtil.rename(new File(path), fileName, true);//改文件名称 原名
- FileUtil.rename(new File(path), "upgrade.bin", true);//指定名称 upgrade.bin
- map.put("result", "上传完毕");
- redisUtil.del(UpLoadConstant.fileMd5 + md5);
- redisUtil.del(UpLoadConstant.task + taskId);
- redisUtil.del(UpLoadConstant.chunkNum + taskId);
- redisUtil.del(UpLoadConstant.fastDfsPath + taskId);
- }
- } catch (IOException e) {
- e.printStackTrace();
- String md5 = (String) redisUtil.getObject(UpLoadConstant.task + taskId);
- redisUtil.del(UpLoadConstant.fileMd5 + md5);
- redisUtil.del(UpLoadConstant.task + taskId);
- redisUtil.del(UpLoadConstant.chunkNum + taskId);
- redisUtil.del(UpLoadConstant.fastDfsPath + taskId);
- map.put("result", "上传异常");
- } finally {
- try {
- if (raf != null) {
- raf.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- try {
- if (is != null) {
- is.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return ResultUtil.success(map);
- }
-
- /**
- * 校验md5值
- *
- * @param md5 md5
- * @return map
- */
- public Map<String, Object> checkMd5(String md5) {
- Map<String, Object> map = new HashMap<>();
-
- String fileSize = "";
- String taskId = "";
- md5 = SecureUtil.md5(md5);
- Map redisMap = redisUtil.getMap(UpLoadConstant.fileMd5 + md5);
- if (MapUtil.isNotEmpty(redisMap)) {
- fileSize = ( redisMap.get("fileSize").toString ());
- taskId = ( redisMap.get("taskId").toString ());
- }
- if (StrUtil.isNotEmpty(fileSize)) {
- map.put("fileSize", Long.parseLong(fileSize));
- } else {
- Map<String, Object> map1 = new HashMap<>();
- taskId = IdUtil.simpleUUID();
- map1.put("fileSize", 0);
- map1.put("taskId", taskId);
- redisUtil.setHashAsMap(UpLoadConstant.fileMd5 + md5, map1, cacheTime);
- redisUtil.setObject(UpLoadConstant.task + taskId, md5, cacheTime);
- map.put("fileSize", 0);
- }
- map.put("taskId", taskId);
- return map;
- }
RedisUtil.java 同为utils层
- package vip.xiaonuo.sys.modular.upgrade.utils;
-
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.stereotype.Component;
- import org.springframework.util.CollectionUtils;
-
- import javax.annotation.Resource;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.TimeUnit;
-
- /**
- * @Author: geng
- * @Date: 2022/9/23 21:49
- * @Description:
- */
- @Component
- public class RedisUtil {
-
- @Resource
- private RedisTemplate<String, Object> redisTemplate;
-
- //写入对象
- public boolean setObject(final String key, Object value, Integer expireTime) {
- try {
-
- redisTemplate.opsForValue().set(key, value);
- redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
- //获取对象
- public Object getObject(final String key) {
- return key == null ? null : redisTemplate.opsForValue().get(key);
- }
-
-
- //写入集合
- public boolean setList(final String key, Object value, Integer expireTime) {
- try {
- redisTemplate.opsForList().rightPush(key, value);
- redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
- //获取集合
- public List<Object> getList(final String key) {
- try {
- return redisTemplate.opsForList().range(key, 0, -1);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- public boolean setHashAsKV(String key, Object hk, Object hv, Integer expireTime) {
- try {
- redisTemplate.opsForHash().put(key, hk, hv);
- redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
-
- public boolean setHashAsMap(String key, Map map, Integer expireTime) {
- try {
- redisTemplate.opsForHash().putAll(key, map);
- redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
-
- public Map getMap(String key) {
- Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
- if (CollectionUtils.isEmpty(map)) {
- return null;
- }
- return map;
- }
-
- public Object getHashObject(String k1, String k2) {
- return redisTemplate.opsForHash().get(k1, k2);
- }
-
- /**
- * 判断是否存在key
- *
- * @param key key
- * @return
- */
- public boolean hasKey(final String key) {
- try {
- return redisTemplate.hasKey(key);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
-
- /**
- * 删除key
- *
- * @param key key
- * @return
- */
- public void del(final String key) {
- if (hasKey(key)) {
- redisTemplate.delete(key);
- }
- }
-
- /**
- * 批量删除key
- *
- * @param keys keys
- * @return
- */
- public boolean delKeys(String... keys) {
- for (String key : keys) {
- if (hasKey(key)) {
- Boolean flag = redisTemplate.delete(key);
- if (flag == null) {
- continue;
- }
- if (!flag) {
- return false;
- }
- }
- }
- return true;
- }
- }
entity层
- package vip.xiaonuo.sys.modular.upgrade.entity;
-
- import lombok.Data;
- import org.springframework.web.multipart.MultipartFile;
-
- import java.io.Serializable;
-
- @Data
- public class MultipartFileParam implements Serializable {
- private static final long serialVersionUID = 3238600879053243080L;
- private String taskId;//文件传输任务ID
- private long chunkNumber;//当前为第几分片
- private long chunkSize;//每个分块的大小
- private long totalChunks;//分片总数
- private long fileSize;
- private String fileName;
- private String identifier;//文件唯一标识
- private MultipartFile file;//分块文件传输对象
-
- }
UpLoadConstant.java constant层
- package vip.xiaonuo.sys.modular.upgrade.constant;
-
- /**
- * @Author: geng
- * @Date: 2022/9/23 22:00
- * @Description:
- */
- public class UpLoadConstant {
- private final static String uploading = "Uploading:";
- private final static String file = uploading + "file:";
- //当前文件传输到第几块
- public final static String chunkNum = file + "chunkNum:";
- //当前文件上传到fastdfs路径
- public final static String fastDfsPath = file + "fastDfsPath:";
- public final static String task = uploading + "task:";
- public final static String fileMd5 = file + "md5:";
-
- }
param层
- package vip.xiaonuo.sys.modular.upgrade.param;
-
- /**
- * @Author: geng
- * @Date: 2022/9/23 22:27
- * @Description:
- */
- public class ApiResult {
- /**
- * 错误码.
- */
- private Integer code;
-
- /**
- * 提示信息.
- */
- private String msg;
-
- /**
- * 具体的内容.
- */
- private Object data;
-
- public Integer getCode() {
- return code;
- }
-
- public void setCode(Integer code) {
- this.code = code;
- }
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-
- public Object getData() {
- return data;
- }
-
- public void setData(Object data) {
- this.data = data;
- }
- }
- package vip.xiaonuo.sys.modular.upgrade.param;
-
- public enum CustomResponse {
- SUCCESS(10000, "响应成功"),
- FAILURE(10001, "响应失败");
- private Integer code;
- private String msg;
-
- CustomResponse(Integer code, String msg) {
- this.code = code;
- this.msg = msg;
- }
-
- public Integer getCode() {
- return code;
- }
-
- public String getMsg() {
- return msg;
- }
- }
- package vip.xiaonuo.sys.modular.upgrade.param;
-
- /**
- * @Author: geng
- * @Date: 2022/9/23 22:28
- * @Description:
- */
- public class ResultUtil {
- public static ApiResult success(Object object) {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode(CustomResponse.SUCCESS.getCode());
- apiResult.setMsg(CustomResponse.SUCCESS.getMsg());
- apiResult.setData(object);
- return apiResult;
- }
-
- public static ApiResult success() {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode(CustomResponse.SUCCESS.getCode());
- apiResult.setMsg(CustomResponse.SUCCESS.getMsg());
- return apiResult;
- }
-
- public static ApiResult success(Integer code, String msg, Object obj) {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode(code);
- apiResult.setMsg(msg);
- apiResult.setData(obj);
- return apiResult;
- }
-
- public static ApiResult error(Object object) {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode(CustomResponse.FAILURE.getCode());
- apiResult.setMsg(CustomResponse.FAILURE.getMsg());
- apiResult.setData(object);
- return apiResult;
- }
-
- public static ApiResult errMsg(String msg) {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode(CustomResponse.FAILURE.getCode());
- apiResult.setMsg(msg);
- return apiResult;
- }
-
- public static ApiResult error() {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode(CustomResponse.FAILURE.getCode());
- apiResult.setMsg(CustomResponse.FAILURE.getMsg());
- return apiResult;
- }
-
- public static ApiResult error(Integer code, String msg, Object obj) {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode(code);
- apiResult.setMsg(msg);
- apiResult.setData(obj);
- return apiResult;
- }
- }
- @GetMapping("/checkMd5")
- public ApiResult checkMd5(@Param ("md5") String md5) {
- Map<String, Object> map = uploadFileUtil.checkMd5(md5);
- return ResultUtil.success(map);
- }
-
- @PostMapping(value = "/chunkUpload")
- public ApiResult chunkUpload(MultipartFileParam multipartFileParam) {
- return uploadFileUtil.uploadAppendFile(multipartFileParam, "D:\\klp");
- }
前端代码
- chunkUpload() {
-
- const file = this.fileList[0]
- const md5 = file.name + file.size + file.lastModified
-
- chunkUploaMess(md5).then((res)=>{
- if (res) {
- console.log(res)
- const start = Number(res.data.fileSize)
- const taskId = res.data.taskId
- if (res.data) {
-
- this.upload(start, taskId, file)
- } else {
- this.upload(0, taskId, file)
- }
-
- })
-
- }
- upload(start, taskId, file) {
- // 分片大小 5M
- const bytePercent = 1024 * 1024 * 5
- // 通过文件大小除以分片大小得出总片数
- const totalChunks = Math.ceil(file.size / bytePercent)
- // 起始位置+分片数 如果大于文件大小,那么终点位置就是文件大小,反之就是前者
- const end = (start + bytePercent) > file.size ? file.size : (start + bytePercent)
- const fileName = file.name
- // 分片文件
- const chunkFile = file.slice(start, end)
- // 当前分片数
- const currChunkNum =parseInt (start / bytePercent) + 1
- const formData = new FormData()
- formData.append('file', chunkFile)
- formData.append('fileName', fileName)
- formData.append('fileSize', start)
- formData.append('taskId', taskId)
- formData.append('chunkNumber', currChunkNum)
- formData.append('chunkSize', bytePercent)
- formData.append('totalChunks', totalChunks)
-
- uploadsMess(formData).then((res)=>{
- if (res.data.result === '上传完毕') {
- alert('成功')
- } else {
-
- this.upload(end, taskId, file)
- }
- })
-
-
- },
api
- /**
- * 分片
- * @returns {AxiosPromise}
- * @param md5
- */
- export function chunkUpload(md5) {
- return axios({
- url: '/main/checkMd5',
- method: 'get',
- data: md5,
- })
- }
- /**
- * 分片
- * @returns {AxiosPromise}
- * @param formData
- */
- export function uploads(formData) {
- return axios({
- url: '/main/chunkUpload',
- method: 'POST',
- data: formData,
- contentType: false,//很重要,指定为false才能形成正确的Content-Type
- processData: false, //加入这属性 processData默认为true,为true时,提交不会序列化data。
- })
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。