主要思路是用线程池池去处理上传任务,并计算上传进度,将进度保存到session中。前端通过一个定时器按固定时间调用获取进度条的百分比,更新进度条进度。
前端相关代码:
//展示进度条
var timerId;
function showCheckProgress(){
$('#progressDlg').dialog('open');
//想要修改进度条的颜色去css文件中去修改
$('#p').progressbar({
value : 0, //设置进度条值 默认0
text : '{value}%' //设置进度条百分比模板 默认 {value}%
//在value改变的时候触发
/*onChange : function (newValue, oldValue) {
console.log('新:' + newValue + ',旧:' + oldValue);
}, */
});
timerId = window.setInterval(getCheckProgress,1000);
}
//通过post请求得到进度
function getCheckProgress(){
var progressUrl = $('#getProgressUrl').val();
//使用JQuery从后台获取JSON格式的数据
$.ajax({
type:"post",//请求方式
url:progressUrl,//发送请求地址
timeout:3000,//超时时间:30秒
dataType:"json",//设置返回数据的格式
//请求成功后的回调函数 data为json格式
success:function(data){
if(data.progressValue>=100){
window.clearInterval(timerId);
$('#dg').datagrid('load');
$('#importBtn').css('display','inline-block');
$('#showProgress').css('display','none');
}
$('#p').progressbar('setValue',data.progressValue);
},
//请求出错的处理
error:function(){
window.clearInterval(timerId);
//alert("请求出错");
}
});
}
文件上传界面:enctype="multipart/form-data"
springmvc中对上传文件的通用属性配置:
2097152
UTF-8
/**
* 批量导入贷中记录
*/
@RequestMapping(value = "/action/import")
@ResponseBody
public Result importList(HttpServletRequest request, HttpServletResponse response, @RequestParam MultipartFile uploadFile) {
HttpSession session = request.getSession();
session.setAttribute("progressValue", 0.0);
Result result = new Result();
try {
String fileName = uploadFile.getOriginalFilename();
long size = uploadFile.getSize();//文件大小,字节
long maxSize = 2048000;//2M
String fileType = StringUtils.split(fileName,".")[1];
if(!StringUtils.equals(fileType, "xlsx") && !StringUtils.equals(fileType, "xls")){
result.setCode(0);
result.setMsg("请选择xlsx或xls格式的文件");
return result;
}
if(size > maxSize){
result.setCode(0);
result.setMsg("批量导入的文件大小不能超过2M");
return result;
}
String batchNo = "DZ" + DateUtil.getCurrentDateTime();
List jobList = parseExcel( uploadFile.getInputStream(),session,batchNo);
if(jobList!=null && jobList.size()>3000){
result.setCode(0);
result.setMsg("单次校验记录数不能超过3000");
return result;
}
//先全部批量插入数据库
rcsCreditManageJobServiceImpl.batchAdd(jobList);
result = rcsCreditManageJobServiceImpl.batchCheckCreditIn(session,jobList,batchNo);
} catch (Exception e) {
result.setCode(0);
result.setMsg("批量校验操作失败!");
log.error("【批量校验操作异常】:"+ e.getMessage(),e);
}
return result;
}
/**
* 批量校验
*/
@Override
public Result batchCheckCreditIn(HttpSession session,List jobList,String batchNo) {
Result result = new Result();
try {
int totalSize = jobList.size();
TaskProgress progress = new TaskProgress(totalSize,batchNo);
for (RcsCreditManageJob job : jobList) {
taskExecutor.execute(new dzCheckTask(progress,job,session));
}
result.setCode(1);
result.setMsg("批量校验申请提交完毕!");
} catch (Exception e) {
e.printStackTrace();
result.setCode(0);
result.setMsg("批量校验申请提交失败!");
}
return result;
}
/**
* 执行校验的任务
*/
private class dzCheckTask implements Runnable {
private RcsCreditManageJob job;
private TaskProgress progress;
private HttpSession session;
public dzCheckTask(TaskProgress progress,RcsCreditManageJob job,HttpSession session) {
this.job = job;
this.progress = progress;
this.session=session;
}
public void run() {
try {
EngineCreditInDto ec = new EngineCreditInDto();
ec.setName(job.getUserName());//用户名称
ec.setMobile(job.getMobile());//手机号
ec.setIdCard(job.getCertid());//身份证号
ec.setCurrTime(DateUtil.getCurrentPrettyDateTime());//当前时间
ec.setCallType(job.getCallType());
riskServiceFacade.evaluateCreditInCheck(ec);
//根据表数据
Map paramMap = new HashMap();
paramMap.put("execTime", DateUtil.getCurrentDateTime());
paramMap.put("certid", ec.getIdCard());
paramMap.put("batchNo", progress.getTaskNo());
rcsCreditManageJobMapper.updateExcuTimeByMap(paramMap);
//更新进度
session.setAttribute("progressValue", progress.computeProgress());
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 任务进度实体
*/
public class TaskProgress {
private int totalSize;//任务总数
private int completeSize;//任务完成数
private String taskNo;//任务批次
public double taskProgress;//任务进度
public TaskProgress(int totalSize, String taskNo) {
this.totalSize = totalSize;
this.taskNo = taskNo;
}
/**
* 用同步代码块实现
*
* @param money
*/
public double computeProgress() {
synchronized (this) {
BigDecimal b1 = new BigDecimal(Double.toString(this.getTotalSize()));
//没调用一次,完成一笔
int newCompleteSize = this.getCompleteSize() + 1;
this.setCompleteSize(newCompleteSize);
BigDecimal b2 = new BigDecimal(Double.toString(newCompleteSize));
double taskProgress = b2.divide(b1,2,RoundingMode.HALF_UP).multiply(new BigDecimal("100")).doubleValue();
this.setTaskProgress(taskProgress);
return taskProgress;
}
}
public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public int getCompleteSize() {
return completeSize;
}
public void setCompleteSize(int completeSize) {
this.completeSize = completeSize;
}
public String getTaskNo() {
return taskNo;
}
public void setTaskNo(String taskNo) {
this.taskNo = taskNo;
}
public double getTaskProgress() {
return taskProgress;
}
public void setTaskProgress(double taskProgress) {
this.taskProgress = taskProgress;
}
}
最后是相应获取进度的请求,从session中获取最新的进度:
/**
* 得到处理进度
*/
@RequestMapping(value = "/action/getProgressValue")
@ResponseBody
public Map getProgressValue( HttpSession session) {
double progress = (double) session.getAttribute("progressValue");
Map map = new HashMap();
map.put("progressValue", progress);
return map;
}
比较粗糙的实现,但是能跑能跳,本博客只是自己的工作记录之用,实现方式未必优雅。
如你有更好的方法,欢迎指教。