springboot 大文件分片上传
- constant
- entity
- vo
- controller
- utils
大文件分片上传是一种将大文件分割成多个小文件片段,然后分别上传这些小文件片段的方法。这种方法的好处包括:
-
减少重新上传开销:如果网络传输中断,只需重传未上传的部分,而不是整个文件。
-
提高灵活性:分片大小可以根据实际情况调整,以平衡上传速度和请求次数。
-
支持断点续传:服务器可以记录已经上传的文件块,以便在中断后继续上传。
分片上传的流程大致如下:
-
文件分片:首先,对文件进行分片,每个分片的大小可以根据实际情况设定,例如,一个100MB的文件可以分成每个5MB的分片,共20个分片。
-
计算MD5值:对每个分片计算MD5值,这有助于文件的完整性校验和唯一标识。(这里使用【文件名+文件后缀+文件大小+时间戳】的方式,对当前文件生成了MD5,用来区分不同的文件,保证文件的唯一性。)
-
上传分片:将每个分片和它的MD5值一起上传到服务器。
-
服务器校验:服务器接收每个分片并进行校验,确保分片的完整性和正确性。(这里只在文件合并的时候,对文件片数的完整性进行校验。)
-
文件合并:当所有分片都成功上传后,服务器将它们合并成完整的文件。
在选择分片大小时,需要权衡请求次数和灵活性。分片太小会增加请求次数和开销,而分片太大则可能减少灵活性。通常,服务器端会有一个固定大小的接收Buffer,分片的大小最好是这个值的整数倍。
此外,前端在开始上传前需要对文件名进行校验,确保文件名不超过最大长度,否则禁止发送请求。
constant
/**
* 文件上传类型常量类
**/
public interface FileUploadTypeConstant
{
/**
* 单文件上传
*/
String SINGLE = "single";
/**
* 分片上传
*/
String CHUNKS = "chunks";
/**
* 文件合并
*/
String MERGE = "merge";
}
entity
/**
* @Description 前端统一返回类
**/
public class ResResult<D>
{
/**
* 0 为成功,1为失败
*/
public static final String SUCCESS = "0";
public static final String FAIL = "1";
private String code;
private D data;
private String msg;
private ResResult(String code)
{
this.code = code;
}
public static <T> ResResult<T> get(String code)
{
return new ResResult<>(code);
}
public static <T> ResResult<T> success()
{
return new ResResult<T>(SUCCESS).setMsg("操作成功");
}
public static <T> ResResult<T> success(T data)
{
return new ResResult<T>(SUCCESS).setMsg("操作成功").setData(data);
}
public static <T> ResResult<T> success(String msg)
{
return new ResResult<T>(SUCCESS).setMsg(msg);
}
public static <T> ResResult<T> success(String msg, T data)
{
return new ResResult<T>(SUCCESS).setMsg(msg).setData(data);
}
public static <T> ResResult<T> fail()
{
return new ResResult<T>(FAIL).setMsg("操作失败");
}
public static <T> ResResult<T> fail(String msg)
{
return new ResResult<T>(FAIL).setMsg(msg);
}
public static <T> ResResult<T> fail(String msg, T data)
{
return new ResResult<T>(FAIL).setMsg(msg).setData(data);
}
public static <T> ResResult<T> fail(T data)
{
return new ResResult<T>(FAIL).setMsg("操作失败").setData(data);
}
public D getData()
{
return this.data;
}
public ResResult<D> setData(D data)
{
this.data = data;
return this;
}
public String getCode()
{
return code;
}
public ResResult<D> setCode(String code)
{
this.code = code;
return this;
}
public String getMsg()
{
return msg;
}
public ResResult<D> setMsg(String msg)
{
this.msg = msg;
return this;
}
/**
* 重载空参for 跨服务调用实例化该类用的构造函数
*/
private ResResult()
{
}
}
vo
/**
* 分片文件对象
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FileChunkVO
{
/**
* 文件MD5校验值
*/
String md5Check;
/**
* 当前分片编号
*/
int chunkNumber;
/**
* 总分片数
*/
int totalChunks;
/**
* 文件名称
*/
String fileName;
/**
* single:单文件;
* chunks:分片;
* marge:合并
*/
String type;
}
controller
包括三个方法,分别是:单文件上传,文件分片上传,文件合并。
/**
* 文件上传
*
* @param fileChunkVO 分片文件对象
* @return ResResult对象,表示上传结果
*/
@ApiOperation(value = "文件上传")
@PostMapping("/upload")
public ResResult<?> upload(MultipartFile file, FileChunkVO fileChunkVO)
{
try
{
switch (fileChunkVO.getType())
{
case FileUploadTypeConstant.SINGLE:
List<Map<String, Object>> list = FileUtils.uploadFiles(new MultipartFile[]
{
file },