首先,我们清晰一下思路
1)先实现文件上传,我们应该清楚,文件上传和进度走的是两条路线,即异步;
2)再使用文件上传解析器去获取文件进度信息,这个信息是保存在一个session域里的,会被实时刷新;
3)websocket定时遍历,实现点对点发送上传进度信息;
很简单,就这三步
接下来开始实现
所需的maven依赖
commons-fileupload
commons-fileupload
1.3.3
commons-io
commons-io
2.5
org.springframework.boot
spring-boot-starter-websocket
实现第一步和第二步
后台主要有下面几个类
1.FileuploadClass 文件上传配置信息,继承了CommonsMultipartResolver
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* @ClassName FileUpload
* @Description TODO
* @Author fzj
* @Date 2020-3-26 13:21
* @Version 1.0.0
**/
public class FileUploadClass extends CommonsMultipartResolver {
private UploadProgressListener progressListener = new UploadProgressListener();
public void setFileUploadProgressListener(
UploadProgressListener progressListener) {
this.progressListener = progressListener;
}
public MultipartParsingResult parseRequest(HttpServletRequest request)
throws MultipartException {
String encoding = determineEncoding(request);
FileUpload fileUpload = prepareFileUpload(encoding);
progressListener.setSession(request.getSession());
fileUpload.setProgressListener(progressListener);
try {
@SuppressWarnings("unchecked")
List fileItems = ((ServletFileUpload) fileUpload)
.parseRequest(request);
return parseFileItems(fileItems, encoding);
} catch (FileUploadBase.SizeLimitExceededException ex) {
throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(),
ex);
} catch (FileUploadException ex) {
throw new MultipartException(
"Could not parse multipart servlet request", ex);
}
}
}
2.FileUploadConfig 配置类 用于springboot项目加载时注入文件上传配置文件的bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName FileUPDConfig
* @Description TODO
* @Author fzj
* @Date 2020-4-1 8:19
* @Version 1.0.0
**/
@Configuration
public class FileUploadConfig {
@Bean
public FileUploadClass fileUploadConfig(){
return new FileUploadClass();
}
}
3.UploadProgressListener 文件上传状态监听器 实现了ProgressListener
import com.fzj.model.ProgressEntity;
import org.apache.commons.fileupload.ProgressListener;
import javax.servlet.http.HttpSession;
/**
* @ClassName UploadProgressListener
* @Description TODO
* @Author fzj
* @Date 2020-4-1 8:15
* @Version 1.0.0
**/
public class UploadProgressListener implements ProgressListener {
private HttpSession session;
public void setSession(HttpSession session) {
this.session = session;
ProgressEntity status = new ProgressEntity();// 保存上传状态
session.setAttribute("status", status);
}
@Override
public void update(long bytesRead, long contentLength, int items) {
ProgressEntity status = (ProgressEntity) session.getAttribute("status");
status.setBytesRead(bytesRead);// 已读取数据长度
status.setContentLength(contentLength);// 文件总长度
status.setItems(items);// 正在保存第几个文件
}
}
4.ProgressEntity 进度实体类
/**
* @ClassName ProgressEntity
* @Description TODO
* @Author fzj
* @Date 2020-3-26 12:56
* @Version 1.0.0
**/
public class ProgressEntity {
private long bytesRead;
private long contentLength;
private long items;
private long startTime = System.currentTimeMillis(); // 开始上传时间,用于计算上传速率
public ProgressEntity() {
}
public long getBytesRead() {
return bytesRead;
}
public void setBytesRead(long bytesRead) {
this.bytesRead = bytesRead;
}
public long getContentLength() {
return contentLength;
}
public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
public long getItems() {
return items;
}
public void setItems(long items) {
this.items = items;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
}
5.FileUploadCommonTool 文件上传通用操作类
import com.fzj.model.ProgressEntity;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName FileUploadCommonTool
* @Description TODO
* @Author fzj
* @Date 2020-4-9 10:05
* @Version 1.0.0
**/
public class FileUploadCommonTool {
public static Map upload(MultipartFile Fdata, String Sid, HttpServletRequest request) {
String infilename = Fdata.getOriginalFilename();
String endstring = infilename.substring(infilename.lastIndexOf("."));
//这里写自己的文件名和文件夹即可
String fromstring = SystemDateFormat.SdfForTimeString.format(new Date());
String path = "C:\\Users\\Administrator\\Desktop\\_11_4_1临时文件夹\\20200326\\" + fromstring + endstring;
Map map = new HashMap<>(1);
InputStream fis = null;
FileOutputStream fos = null;
try {
File fileo = new File(path);
if (!fileo.exists()) {
fileo.createNewFile();
}
fos = new FileOutputStream(fileo);
fis = Fdata.getInputStream();
byte[] bytes = new byte[1024];
int aa = 0;
while (true) {
aa = fis.read(bytes, 0, bytes.length);
if (aa == -1) {
break;
}
fos.write(bytes, 0, aa);
}
} catch (Exception e) {
map.put("issuccess", false);
} finally {
try {
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return map;
}
public static Map getUploadInfo(HttpServletRequest request) {
Map result = new HashMap<>();
ProgressEntity status = (ProgressEntity) request.getSession(true)
.getAttribute("status");// 从session中读取上传信息
if (status == null) {
result.put("error", "没发现上传文件!");
return result;
}
long startTime = status.getStartTime(); // 上传开始时间
long currentTime = System.currentTimeMillis(); // 现在时间
long time = (currentTime - startTime) / 1000 + 1;// 已经传顺的时间 单位:s
double velocity = status.getBytesRead() / time; // 传输速度:byte/s
double totalTime = status.getContentLength() / velocity; // 估计总时间
double timeLeft = totalTime - time; // 估计剩余时间
int percent = (int) (100 * (double) status.getBytesRead() / (double) status
.getContentLength()); // 百分比
double length = status.getBytesRead() / 1024 / 1024; // 已完成数
double totalLength = status.getContentLength() / 1024 / 1024; // 总长度 M
result.put("startTime", startTime);
result.put("currentTime", currentTime);
result.put("time", time);
result.put("velocity", velocity);
result.put("totalTime", totalTime);
result.put("timeLeft", timeLeft);
result.put("percent", percent);
result.put("length", length);
result.put("totalLength", totalLength);
if (length >= totalLength) {
result.put("isfinish", 1);
}
return result;
}
}
到这里,文件上传后端的所有工作已经做完了,现在你可以通过Controller里调用FileUploadCommonTool里的upload就可以实现页面上传文件了,同时可以通过页面轮训FileUploadCommonTool里的getUploadInfo获得文件上传的进度信息,当然了,所用的前端框架各不相同,我这里以miniui做个页面示例
<%@ include file="head.jsp" %>