java秒传和分片上传
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 文件上传的依赖-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
package com.demo.zhk.entity;
import lombok.Data;
@Data
public class FileDTO {
private Integer id;
private String path;
private String name;
private String suffix;
private Integer size;
private Integer shardIndex;
private Integer shardSize;
private Integer shardTotal;
private String fileKey;
}
package com.demo.zhk.utils;
import lombok.Data;
@Data
public class Result {
public static final int SUCCESS_CODE = 200;
public static final int FAIL_CODE = 500;
public static final int NOTF_FOUNT_CODE = 404;
public static final int ACCESS_DINE_CODE = 403;
private int code;
private String msg;
private Object data;
public static Result ok() {
Result r = new Result();
r.setCode(SUCCESS_CODE);
r.setMsg("请求成功!");
r.setData(null);
return r;
}
public static Result fail() {
Result r = new Result();
r.setCode(FAIL_CODE);
r.setMsg("请求失败!");
r.setData(null);
return r;
}
public static Result ok(String msg) {
Result r = new Result();
r.setCode(SUCCESS_CODE);
r.setMsg(msg);
r.setData(null);
return r;
}
public static Result fail(String msg) {
Result r = new Result();
r.setCode(FAIL_CODE);
r.setMsg(msg);
r.setData(null);
return r;
}
public static Result ok(String msg, Object data) {
Result r = new Result();
r.setCode(SUCCESS_CODE);
r.setMsg(msg);
r.setData(data);
return r;
}
public static Result fail(String msg, Object data) {
Result r = new Result();
r.setCode(FAIL_CODE);
r.setMsg(msg);
r.setData(data);
return r;
}
public Result code(Integer code){
this.setCode(code);
return this;
}
public Result data(Object data){
this.setData(data);
return this;
}
public Result msg(String msg){
this.setMsg(msg);
return this;
}
}
package com.demo.zhk.service;
import com.alibaba.fastjson.JSON;
import com.demo.zhk.entity.FileDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class FileService {
private final RedisTemplate redisTemplate;
public void save(FileDTO file1) {
String fileKey = file1.getFileKey();
Boolean aBoolean = redisTemplate.hasKey(fileKey);
if (aBoolean) {
redisTemplate.opsForValue().set(fileKey,file1);
}
redisTemplate.opsForValue().set(fileKey,file1);
}
public FileDTO check(String key){
FileDTO fileDTO = JSON.parseObject(redisTemplate.opsForValue().get(key).toString(), FileDTO.class);
return fileDTO;
}
}
package com.demo.zhk.controller;
import com.demo.zhk.entity.FileDTO;
import com.demo.zhk.service.FileService;
import com.demo.zhk.utils.Result;
import io.netty.util.internal.ObjectUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@Controller
@RequestMapping("/file")
@Slf4j
public class FileController {
@Autowired
private FileService fileService;
@Autowired
private RedisTemplate redisTemplate;
public static final String BUSINESS_NAME = "普通分片上传";
@Value("${file.basepath}")
private String basePath;
@RequestMapping("/show")
public String show(){
return "file";
}
@RequestMapping("/upload")
@ResponseBody
public String upload(MultipartFile file,
String suffix,
Integer shardIndex,
Integer shardSize,
Integer shardTotal,
Integer size,
String key) throws IOException, InterruptedException {
log.info("上传文件开始");
String name = UUID.randomUUID().toString().replaceAll("-", "");
String ext = FilenameUtils.getExtension(file.getOriginalFilename());
String fileName = new StringBuffer().append(key).append(".").append(suffix).toString();
String localfileName = new StringBuffer(fileName).append(".").append(shardIndex).toString();
File targeFile=new File(basePath,localfileName);
if(!targeFile.exists()){
targeFile.mkdirs();
}
file.transferTo(targeFile);
FileDTO file1=new FileDTO();
file1.setPath(basePath+localfileName);
file1.setSuffix(suffix);
file1.setName(name);
file1.setSuffix(ext);
file1.setSize(size);
file1.setShardIndex(shardIndex);
file1.setShardSize(shardSize);
file1.setShardTotal(shardTotal);
file1.setFileKey(key);
redisTemplate.opsForValue().set(key,file1);
if(shardIndex.equals(shardTotal) ){
file1.setPath(basePath+fileName);
this.merge(file1);
}
return "上传成功";
}
@RequestMapping("/check")
@ResponseBody
public Result check(String key){
FileDTO check = fileService.check(key);
if(!Objects.isNull(check)){
return Result.ok("查询成功",check);
}
return Result.fail("查询失败,可以添加");
}
private void merge(FileDTO fileDTO) throws FileNotFoundException, InterruptedException {
log.info("分页合并开始");
String path = fileDTO.getPath();
path = path.replace(basePath, "");
Integer shardTotal= fileDTO.getShardTotal();
File newFile = new File(basePath + path);
FileOutputStream outputStream = new FileOutputStream(newFile,true);
FileInputStream fileInputStream = null;
byte[] byt = new byte[10 * 1024 * 1024];
int len;
try {
for (int i = 0; i < shardTotal; i++) {
fileInputStream = new FileInputStream(new File(basePath + path + "." + (i + 1)));
while ((len = fileInputStream.read(byt)) != -1) {
outputStream.write(byt, 0, len);
}
}
} catch (IOException e){
log.error("分片合并异常", e);
} finally {
try {
if (fileInputStream != null) {
fileInputStream.close();
}
outputStream.close();
log.info("IO流关闭");
} catch (Exception e) {
log.error("IO流关闭", e);
}
log.info("分片结束了");
System.gc();
Thread.sleep(100);
log.info("删除分片开始");
for (int i = 0; i < shardTotal; i++) {
String filePath = basePath + path + "." + (i + 1);
File file = new File(filePath);
boolean result = file.delete();
log.info("删除{},{}", filePath, result ? "成功" : "失败");
}
log.info("删除分片结束");
}
}
}
spring:
redis:
host: localhost
port: 6379
#spring.resources.static-locations=classpath:/static
server.port=8000
#文件上传路径
file.basepath=E:/BaiduNetdiskDownload/
spring.servlet.multipart.max-file-size= 50MB
spring.servlet.multipart.max-request-size= 50MB
# templates文件夹的路径
spring.thymeleaf.prefix=classpath:/templates/
# templates中的所有文件后缀名,如/templates/main.html
spring.thymeleaf.suffix=.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/md5.js"></script>
<script type="text/javascript" src="/tool.js"></script>
<body>
<table border="1px solid red">
<tr>
<td>文件1</td>
<td>
<input name="file" type="file" id="inputfile"/>
</td>
</tr>
<tr>
<td></td>
<td>
<button onclick="check()">提交</button>
</td>
</tr>
</table>
</body>
<script type="text/javascript">
function test1(shardIndex) {
console.log(shardIndex);
var fd = new FormData();
var file = $('#inputfile').get(0).files[0];
var shardSize = 20 * 1024 * 1024;
var shardIndex = shardIndex;
var start = (shardIndex - 1) * shardSize;
var end = Math.min(file.size, start + shardSize);
var fileShard = file.slice(start, end);
var size = file.size;
var shardTotal = Math.ceil(size / shardSize);
var fileName = file.name;
var suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length).toLowerCase();
var filedetails = file.name + file.size + file.type + file.lastModifiedDate;
var key = hex_md5(filedetails);
var key10 = parseInt(key, 16);
var key62 = Tool._10to62(key10);
fd.append('file', fileShard);
fd.append('suffix', suffix);
fd.append('shardIndex', shardIndex);
fd.append('shardSize', shardSize);
fd.append('shardTotal', shardTotal);
fd.append('size', size);
fd.append("key", key62)
$.ajax({
url: "/file/upload",
type: "post",
cache: false,
data: fd,
processData: false,
contentType: false,
success: function (data) {
if (shardIndex < shardTotal) {
var index = shardIndex + 1;
test1(index);
} else {
alert(data)
}
},
error: function () {
}
})
}
function check() {
var file = $('#inputfile').get(0).files[0];
var filedetails = file.name + file.size + file.type + file.lastModifiedDate;
var key = hex_md5(filedetails);
var key10 = parseInt(key, 16);
var key62 = Tool._10to62(key10);
$.ajax({
url: "/file/check",
type: "post",
data: {'key': key62},
success: function (data) {
console.log(data);
if (data.code == 500) {
test1(1);
} else {
if (data.data.shardIndex == data.data.shardTotal) {
alert("极速上传成功");
} else {
test1(parseInt(data.data.shardIndex));
}
}
}
})
}
</script>
</html>
本人比较懒没测,原因就是看别人csdn代码发现少了js,懒得去改html,可以自己模仿数据列如文件文件key不用MD5就随机一个key,其他看样子改就行,道理就是大概意思中的。