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导入获取实时进度相关推荐

  1. Java操作百万数据量Excel导入导出工具类(程序代码教程)

    Java操作百万数据量Excel导入导出工具类(程序代码教程): # 功能实现1.自定义导入数据格式,支持配置时间.小数点类型(支持单/多sheet)(2种方式:本地文件路径导入(只支持xls.xls ...

  2. Java操作大数据量Excel导入导出万能工具类(完整版)

    Java操作大数据量Excel导入导出万能工具类(完整版) 转载自:https://blog.csdn.net/JavaWebRookie/article/details/80843653 更新日志: ...

  3. tiptop使用java的poi包实现EXCEL导入导出功能

    4gl可以调用java的poi包实现EXCEL的导入导出,今天分享一个EXCEL导入的功能!  一:环境搭建  1:poi文件导入  首先下载POI文件(找不到的可以私信我),解压后上传到ERP的服务 ...

  4. java:用HSSFWorkbook实现excel导入(xls、xlsx兼容)

    业务:批量导入不同用户的档案信息,excel格式为:信息用户(独一无二)- 姓名 - 性别 - - 数据库档案字段值表为:信息用户id-档案字段id-档案字段值 已有插入方法:add(String u ...

  5. php excel 导入 显示,php Excel 导入

    php Excel 导入 public function storeSql() { $file = input('file.excel'); $path = ROOT_PATH . 'public' ...

  6. 大数据量高效导入数据库(以excel导入sqlserver为例)

    本人文章陆续转向本人微信公账号发布 公众号:搬砖码农SmallNNN,期望您要是搬砖码农,一起学习探讨,祝您阅读愉快. 最近正在做一个项目,要把excel中的数据导入到sqlserver数据库中,首先 ...

  7. 如何把excel导入python_如何将Excel导入Python之中呢?

    如何将Excel导入Python之中呢?很简单!做法如下: 首先我们要读取excel要用到xlrd模块,官网安装先上官网安装. 然后就可以跟着里面的例子稍微试一下就知道怎么用了.大概的流程是这样的: ...

  8. mysql 导入日期 0000_解决Excel导入MySQL日期为0000-00-00

    最近在为客户做一个库存升级改造的项目,之前客户的数据管理全部是在Excel中操作,估计以前也是没有意识到数据量变大以后,工作会变得如此困难,基本上处于一个无法操作的程度了.于是我们将旧版本的Excel ...

  9. oracle 导入excel时间格式,excel表格导入时间数据库中-excel导入数据库,我的日期是datatime()自动生成......

    如何将excel表格数据导入到oracle数据库对应的表中? 假定a1是你的mysql中的时间戳,要在B1取得普通的时间表示,则b1= =25569 A1*0.0000115743621516652 ...

最新文章

  1. 英特尔10nm至强CPU发布,对标AMD“米兰”EPYC,然而结果尴尬了
  2. debian linux修改语言,Debian Linux系统下英文系统切换为中文
  3. ST17H26之aes模块测试程序
  4. virtualBox下安装Linux6.4
  5. 文本模式下的分辨率对照表
  6. LiveVideoStack线上交流分享 (十七) —— AV1编码器优化与实用落地演进之路
  7. Python操作文件,报FileNotFoundError: [Error 2] No such file or directory错误
  8. 阿里云服务器内核编译升级
  9. 倒计时 2 天!「2019 嵌入式智能国际大会」全日程大公开!
  10. java gui 布局 旋转_JAVA GUI编程之布局管理器
  11. Xftp6-连接Linux传输文件---干货!!!(无私奉献无需积分)
  12. 国家集训队 种树 题解
  13. FRM P1B3笔记:Introduction to Financial Markets and Products
  14. 管理系统里用户角色与权限的设计
  15. 已知某分页系统,主存容量为 64K 字节,页面大小为 1K,对一个 4 页大的作 业,其 0、1、2、3 页分别被分配到主存的 2、4、6、7 块中,试:将十进制的逻 辑地址 1023、2500、35
  16. 浙大版《C语言程序设计(第3版)》题目集(编程题q41-q50)
  17. jFinal 使用slf4j打印sql及其它相关日志
  18. 小程序容器助力车企抢滩智慧车载新生态
  19. 足不出户,一探古今,打造线上3D数字博物馆!
  20. 自定义view-滑动刻度尺计算金额

热门文章

  1. iPhone 4S电池续航力低 位置服务是头号杀手
  2. 我真太卷了,抖音程序员用代码写圣诞树层出不穷,8年开发经验老码侬都整懵了
  3. 访谈李开复:谁主宰微软未来
  4. 【Bulk Crap Uninstaller】最重量级Windows卸载器
  5. 35岁程序员连续被2家公司裁掉,网友酸了。。。
  6. 7-14 大小写转换 (10 分)(PTA题目)
  7. AC-DMIS 5.3 叶片基础知识
  8. 虚拟vpc服务器搭建,vpc虚拟机搭建
  9. java基本微信小程序的高校科研管理系统 uniapp小程序
  10. unity中实现3d物体的颜色随时间渐渐消失