java导入进度显示_java excel导入获取实时进度

本文介绍如何在Java中实现实时显示Excel导入进度,通过多线程处理,使用静态Map存储进度信息,前端定时请求获取进度更新,提供更好的用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.需求

对于成千上万数据量的excel导入,后台处理耗时长,体验差.需要实时展示当前导入的进度,提高使用体验

2.实现思路

采用多线程进行实现

在导入开始执行前,生成一个uuid和进度对象,储存到静态Map中

使用一个新线程执行导入,导入执行时,将导入的进度信息放到uuid对应的对象里

将uuid返回给前端.请求结束

-前端循环发请求,从后台获取uuid对应的进度对象,将展示到页面上

3.页面实现效果(仅供参考)

de5abd799b27

正在导入

de5abd799b27

导入完成

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给前端,然后跳出导入方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值