java导入进度显示_java excel导入获取实时进度
1.需求
对于成千上万数据量的excel导入,后台处理耗时长,体验差.需要实时展示当前导入的进度,提高使用体验
2.实现思路
采用多线程进行实现
在导入开始执行前,生成一个uuid和进度对象,储存到静态Map中
使用一个新线程执行导入,导入执行时,将导入的进度信息放到uuid对应的对象里
将uuid返回给前端.请求结束
-前端循环发请求,从后台获取uuid对应的进度对象,将展示到页面上
3.页面实现效果(仅供参考)
正在导入
导入完成
4.定义用于存储导入进度的对象
将进度的一些常用信息进行定义,同时声明一个静态Map,用于存储所有进度信息
/**
* 用于存储学生信息导入的进度信息
* @author authstr
* @time 2019年10月24日16:56:21
*/
public class ImportAsynInfo {
//用于存储所有的导入进度信息
public static Map allAsynInfo=new HashMap();
//提示信息或 异常信息
private String msg;
//数据总数
private Integer totality=0;
//已处理的数据条数
private Integer doneSum=0;
//失败的数据条数
private Integer errorSum=0;
//成功的数据条数
private Integer successSum=0;
//错误文件的路径
public String errorFilePath;
//导入是否结束
public Boolean isEnd= false;
/**
* 创建一个进度信息,并获取对应的uuid
* @return
*/
public static String createAsynInfo(){
ImportAsynInfo asynInfo=new ImportAsynInfo();
String uuid=UUID.randomUUID().toString().replace("-","");
allAsynInfo.put(uuid,asynInfo);
return uuid;
}
/**
* 通过uuid获取进度信息
* @param uuid
* @return
*/
public static ImportAsynInfo getAsynInfo(String uuid){
return allAsynInfo.get(uuid);
}
/**
* 通过uuid删除对应的进度信息
* @param uuid
* @return
*/
public static void deleteAsynInfo(String uuid){
allAsynInfo.remove(uuid);
}
/**
* uuid对应的进度 已处理的数据条数+1
* @param uuid
*/
public static void doneSumAddOne(String uuid){
ImportAsynInfo asynInfo= getAsynInfo(uuid);
asynInfo.setDoneSum(asynInfo.getDoneSum()+1);
}
/**
* uuid对应的进度 失败的数据条数+1
* @param uuid
*/
public static void errorSumAddOne(String uuid){
ImportAsynInfo asynInfo= getAsynInfo(uuid);
asynInfo.setErrorSum(asynInfo.getErrorSum()+1);
}
/**
* uuid对应的进度 成功的数据条数+1
* @param uuid
*/
public static void successSumAddOne(String uuid){
ImportAsynInfo asynInfo= getAsynInfo(uuid);
asynInfo.setSuccessSum(asynInfo.getSuccessSum()+1);
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Integer getTotality() {
return totality;
}
public void setTotality(Integer totality) {
this.totality = totality;
}
public Integer getDoneSum() {
return doneSum;
}
public void setDoneSum(Integer doneSum) {
this.doneSum = doneSum;
}
public Integer getErrorSum() {
return errorSum;
}
public void setErrorSum(Integer errorSum) {
this.errorSum = errorSum;
}
public Integer getSuccessSum() {
return successSum;
}
public void setSuccessSum(Integer successSum) {
this.successSum = successSum;
}
public String getErrorFilePath() {
return errorFilePath;
}
public void setErrorFilePath(String errorFilePath) {
this.errorFilePath = errorFilePath;
}
public Boolean getEnd() {
return isEnd;
}
public void setEnd(Boolean end) {
isEnd = end;
}
}
5.Controller层开启线程进行导入
获取线程池,通过线程池来启动线程来执行导入,并将uuid传入
文件需要通过输入流来传入,直接传文件对象,可能无法读取到文件
后面定义一个接口,来向前端返回指定uuid对应的进度对象.并对进度对象进行清理
@RestController
@RequestMapping("student_import/v1")
public class StudentImportController extends AbstractAPIController {
@Autowired
StudentImportServiceImpl studentImportService;
private ExecutorService executor = Executors.newCachedThreadPool() ;
//下载导入模板
@RequestMapping("/excelExport")
public void excelExport(HttpServletResponse response) {
studentImportService.excelExport(response);
}
//数据导入处理
@RequestMapping("/save_excel_auto_studentno")
public Map saveExcelStudentno(HttpServletResponse response, @RequestParam("file") MultipartFile file){
Map m = new HashMap<>();
String uuid=ImportAsynInfo.createAsynInfo();
try {
final InputStream inputStream = file.getInputStream();
executor.submit(new Runnable(){
@Override
public void run() {
try {
studentImportService.saveExcel_auto_studentno(response, inputStream,uuid);
}catch(Exception e) {
e.printStackTrace();
ImportAsynInfo.getAsynInfo(uuid).setMsg(e.getMessage());
ImportAsynInfo.getAsynInfo(uuid).setEnd(true);
throw new Exception("无法进行导入!");
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
m.put("uuid",uuid);
return m;
}
//下载导入的错误文件
@RequestMapping("downloadErrorExcel")
public void downloadErrorExcel(HttpServletResponse response, String fileName){
studentImportService.downloadErrorExcel(response, fileName);
}
//获取导入的进度
@RequestMapping("get_import_plan")
public Map get_import_plan(String uuid) {
Map m = new HashMap<>();
ImportAsynInfo asynInfo=ImportAsynInfo.getAsynInfo(uuid);
//如果导入结束,复制进度对象进行返回,将储存的进度对象删除
if(asynInfo!=null&&asynInfo.getEnd()){
ImportAsynInfo newAsynInfo=new ImportAsynInfo();
newAsynInfo.setEnd(asynInfo.getEnd());
newAsynInfo.setMsg(asynInfo.getMsg());
newAsynInfo.setErrorFilePath(asynInfo.getErrorFilePath());
newAsynInfo.setTotality(asynInfo.getTotality());
newAsynInfo.setDoneSum(asynInfo.getDoneSum());
newAsynInfo.setErrorSum(asynInfo.getErrorSum());
newAsynInfo.setSuccessSum(asynInfo.getSuccessSum());
ImportAsynInfo.deleteAsynInfo(uuid);
asynInfo=newAsynInfo;
}
m.put("data",asynInfo);
return m;
}
6. service进行执行导入
在导入过程中,设置导入进度信息
其他业务相关代码已省略
@Service
public class StudentImportServiceImpl extends AbstractService implements StudentImportService {
@Override
public void excelExport(HttpServletResponse response) {
//导入模板下载 略
}
@Override
public void downloadErrorExcel(HttpServletResponse response, String fileName) {
//下载错误文件 略
}
@Transactional
@Override
public Map saveExcel(HttpServletResponse response, InputStream inputStream,String uuid) {
//其他代码...
//获取excel导入数据数量后
ImportAsynInfo.getAsynInfo(uuid).setTotality( 数量 );
//其他代码...
for (int i = 0; i < 数量; i++) {
//其他代码...
//在一条数据处理结束后
ImportAsynInfo.doneSumAddOne(uuid);
//其他代码...
if(数据有错误){
//其他代码...
ImportAsynInfo.errorSumAddOne(uuid);
}else{
//其他代码...
ImportAsynInfo.successSumAddOne(uuid);
}
}
//其他代码...
//错误文件创建后
ImportAsynInfo.getAsynInfo(uuid).setErrorFilePath(errorFileName);
//其他代码...
//导入完成后
ImportAsynInfo.getAsynInfo(uuid).setEnd(true);
}
}
7.显示进度条页面
在网上没找到方便的可以显示多种颜色的进度条,这里曲线救国,采用ECharts的饼图来显示进度信息(具体样式可以根据需求调整)
一些js与样式 已略过
< 返回
*导入文件
下载导入模板
导入
返回
下载错误文件
取消
window.onload = window.onresize = function() {
$(".J_containerWarp").height($(window).height() - 60);
$(".J_containerWarp").niceScroll({});
}
$.ajaxSettings.async=true;
var uuid=null;
var setInterval_id=null;
var myChart = echarts.init(document.getElementById('main'));
var option = {
title : {
text: '正在进行导入中...',
subtext: '当前进度',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a}
{b} : {c} ({d}%)"
},
legend: {
orient: 'vertical',
left: 'right',
data: ['导入成功','导入失败','未处理']
},
series : [
{
name: '导入进度',
type: 'pie',
// radius : '55%',
radius: ['50%', '70%'],
center: ['50%', '60%'],
data:[
{value:0, name:'导入成功'},
{value:0, name:'导入失败'},
{value:100, name:'未处理'}
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
color: ['#2ECC71','#E67E22','#BDC3C7'],
}
]
};
var E = {
excelExport : function() {
$("form[id=excelExportForm]").attr("action",
"${request.contextPath}/student_import/v1/excelExport");
$("#excelExportForm").submit();
},
saveExcel : function() {
var file = $("#file").val();
if(!file){
Message.error("导入的文件不能为空");
return ;
}
//循环获取进度信息
setInterval_id=setInterval(E.getAsynInfo,500);
myChart.setOption(option);
var index = layer.load(1);
var formData = new FormData();
//隐藏导入区域和错误文件下载区域,显示进度条区域
$("#import_file").hide();
$("#main").show();
$("#downloadErrorExcelA").hide();
formData.append('file', $('#file')[0].files[0]);
$.ajax({
type : "POST",
url : "${request.contextPath}/student_import/v1/save_excel",
data : formData,
async: false,
cache: false,
contentType: false,
processData: false,
success : function(o) {
if(o.code==1){
//设置uuid
uuid=o.uuid;
} else {
Message.error(o.msg);
}
}
});
},
downloadErrorExcel : function() {
$("form[id=downloadErrorExcelForm]").attr("action",
"${request.contextPath}/student_import/v1/downloadErrorExcel");
$("#downloadErrorExcelForm").submit();
},
getAsynInfo:function(){
//如果uuid存在,进行获取数据
if(uuid!=null){
$.post("${request.contextPath}/student_import/v1/get_plan",{"uuid":uuid},function(o){
console.log(o);
//如果获取到了数据
if(o.code==1&&o.data!=null){
// 使用指定的配数据显示图表。
option.title.subtext="当前进度 [共"+o.data.totality+"]条";
option.series[0].data[0].value=o.data.successSum;
option.series[0].data[1].value=o.data.errorSum;
option.series[0].data[2].value=o.data.totality-o.data.doneSum;
myChart.setOption(option);
//如果导入结束了
if(o.data.isEnd){
option.title.text="导入完成";
myChart.setOption(option);
clearInterval(setInterval_id);
//如果有错误数据,展示错误文件的下载
if(o.data.totality>0&&o.data.errorSum>0){
$("#fileName").val(o.data.errorFilePath);
$("#downloadErrorExcelA").show();
}
//如果导入中出现的异常
if(o.data.msg!=null){
$("#import_file").show();
$("#main").hide();
Message.error(o.data.msg);
}else{
Message.success("导入结束,"+o.data.successSum+"条数据导入成功,"+o.data.errorSum+"条数据导入失败");
}
}
}else{
Message.error(o.msg);
}
});
}
},
quxiao:function () {
$("#import_file").show();
$("#main").hide();
$("#downloadErrorExcelA").hide();
uuid=null;
}
}
8.还未完成的功能
对线程进行处理和关闭
增加取消导入功能
导入进度对象中,增加一个 是否取消 的标识
在导入的每次循环中,判断这个标识,如果true,跳出整个导入方法,并回滚事务
增加中断导入功能
导入进度对象中,增加一个 是否中断 的标识
在导入的每次循环中,判断这个标识,如果true,直接提交事务,将之前的错误数据信息和之后还未处理的数据合并成一个excel给前端,然后跳出导入方法
java导入进度显示_java excel导入获取实时进度相关推荐
- Java操作百万数据量Excel导入导出工具类(程序代码教程)
Java操作百万数据量Excel导入导出工具类(程序代码教程): # 功能实现1.自定义导入数据格式,支持配置时间.小数点类型(支持单/多sheet)(2种方式:本地文件路径导入(只支持xls.xls ...
- Java操作大数据量Excel导入导出万能工具类(完整版)
Java操作大数据量Excel导入导出万能工具类(完整版) 转载自:https://blog.csdn.net/JavaWebRookie/article/details/80843653 更新日志: ...
- tiptop使用java的poi包实现EXCEL导入导出功能
4gl可以调用java的poi包实现EXCEL的导入导出,今天分享一个EXCEL导入的功能! 一:环境搭建 1:poi文件导入 首先下载POI文件(找不到的可以私信我),解压后上传到ERP的服务 ...
- java:用HSSFWorkbook实现excel导入(xls、xlsx兼容)
业务:批量导入不同用户的档案信息,excel格式为:信息用户(独一无二)- 姓名 - 性别 - - 数据库档案字段值表为:信息用户id-档案字段id-档案字段值 已有插入方法:add(String u ...
- php excel 导入 显示,php Excel 导入
php Excel 导入 public function storeSql() { $file = input('file.excel'); $path = ROOT_PATH . 'public' ...
- 大数据量高效导入数据库(以excel导入sqlserver为例)
本人文章陆续转向本人微信公账号发布 公众号:搬砖码农SmallNNN,期望您要是搬砖码农,一起学习探讨,祝您阅读愉快. 最近正在做一个项目,要把excel中的数据导入到sqlserver数据库中,首先 ...
- 如何把excel导入python_如何将Excel导入Python之中呢?
如何将Excel导入Python之中呢?很简单!做法如下: 首先我们要读取excel要用到xlrd模块,官网安装先上官网安装. 然后就可以跟着里面的例子稍微试一下就知道怎么用了.大概的流程是这样的: ...
- mysql 导入日期 0000_解决Excel导入MySQL日期为0000-00-00
最近在为客户做一个库存升级改造的项目,之前客户的数据管理全部是在Excel中操作,估计以前也是没有意识到数据量变大以后,工作会变得如此困难,基本上处于一个无法操作的程度了.于是我们将旧版本的Excel ...
- oracle 导入excel时间格式,excel表格导入时间数据库中-excel导入数据库,我的日期是datatime()自动生成......
如何将excel表格数据导入到oracle数据库对应的表中? 假定a1是你的mysql中的时间戳,要在B1取得普通的时间表示,则b1= =25569 A1*0.0000115743621516652 ...
最新文章
- 英特尔10nm至强CPU发布,对标AMD“米兰”EPYC,然而结果尴尬了
- debian linux修改语言,Debian Linux系统下英文系统切换为中文
- ST17H26之aes模块测试程序
- virtualBox下安装Linux6.4
- 文本模式下的分辨率对照表
- LiveVideoStack线上交流分享 (十七) —— AV1编码器优化与实用落地演进之路
- Python操作文件,报FileNotFoundError: [Error 2] No such file or directory错误
- 阿里云服务器内核编译升级
- 倒计时 2 天!「2019 嵌入式智能国际大会」全日程大公开!
- java gui 布局 旋转_JAVA GUI编程之布局管理器
- Xftp6-连接Linux传输文件---干货!!!(无私奉献无需积分)
- 国家集训队 种树 题解
- FRM P1B3笔记:Introduction to Financial Markets and Products
- 管理系统里用户角色与权限的设计
- 已知某分页系统,主存容量为 64K 字节,页面大小为 1K,对一个 4 页大的作 业,其 0、1、2、3 页分别被分配到主存的 2、4、6、7 块中,试:将十进制的逻 辑地址 1023、2500、35
- 浙大版《C语言程序设计(第3版)》题目集(编程题q41-q50)
- jFinal 使用slf4j打印sql及其它相关日志
- 小程序容器助力车企抢滩智慧车载新生态
- 足不出户,一探古今,打造线上3D数字博物馆!
- 自定义view-滑动刻度尺计算金额