前言

博主近期接到一个任务,大概内容是:导入excel表格批量修改状态,期间如果发生错误则所有数据不成功,为了防止重复提交,做一个类似进度条的东东。

那么下面我会结合实际业务对这个功能进行分析和记录。

正文

思路

前端使用bootstrap,后端使用SpringBoot分布式到注册中心,原先的想法是导入表格后异步调用修改数据状态的方法,然后每次计算修改的进度然后存放在session中,前台jquery写定时任务访问获取session中的进度,更新进度条进度和百分比。但是这存在session在服务间不共享,跨域问题。那么换一个方式存放,存放在redis中,前台定时任务直接操作获取redis的数据。

实施

进度条

先来看一下bootstrap的进度条

aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"

style="width: 40%;">

40%

进度条更新主要更新style="width: 40%;"的值即可,div里面的40%可以省略,无非时看着明确。

可以考虑将进度条放入弹出层。

定时任务

//点击确认导入执行此方法

function bulkImportChanges() {

//获取批量操作状态文件

var files = $("#importChanges").prop("files");

var changesFile = files[0];

var formData = new FormData();

formData.append("importFile",changesFile);

$.ajax({

type : 'post',

url : "/risk/bulk***es",

data : formData,

processData : false, //文件ajax上传要加这两个的,要不然上传不了

contentType : false, //

success : function(obj) {

//导入成功

if (obj.rspCode == "00") {

//定时任务获取redis导入修改进度

var progress = "";

var timingTask = setInterval(function(){

$.ajax({

type: 'post',

url: "/risk/t***k",

dataType : 'json',

success: function(result) {

progress = result.value;

if (progress != "error"){

var date = progress.substring(0,6);

//这里更新进度条的进度和数据

$(".progress-bar").width(parseFloat(date)+"%");

$(".progress-bar").text(parseFloat(date)+"%");

}

}

});

//导入修改完成或异常(停止定时任务)

if (parseInt(progress)==100 || progress == "error") {

//清除定时执行

clearInterval(timingTask);

$.ajax({

type: 'post',

url: "/risk/de***ess",

dataType : 'json',

success: function(result) {

$("#bulkImportChangesProcessor").hide();

if (parseInt(progress) == 100) {

alert("批量导入修改状态成功");

}

if (progress == "error") {

alert("批量导入修改状态失败");

}

//获取最新数据

window.location.href="/risk/re***ByParam" rel="external nofollow" rel="external nofollow" ;

}

});

}

}, 1000)

}else {

$("#bulkImportChangesProcessor").hide();

alert(obj.rspMsg);

window.location.href="/risk/re***ByParam" rel="external nofollow" rel="external nofollow" ;

}

}

});

}

解释:点击确认导入文件后成功后开启定时任务每一秒(一千毫秒)访问一次后台获取redis存放的进度,返回更新进度条,如果更新完成或者更新失败(根据后台返回的数据决定)则停止定时任务显示相应的信息并刷新页面。获取最新数据。

后台控制层

/**

* 退单管理批量修改状态导入文件

* @param importFile

* @return

*/

@ResponseBody

@RequestMapping("/bulk***es")

public Map bulk***es(MultipartFile importFile){

log.info("退单管理批量修改状态导入文件,传入参数:"+importFile);

Map map = new HashMap<>();

List fromExcel = null;

try{

//使用工具类导入转成list

String[] header = {"sy***um","t***mt","ha***ult","re***nd","sy***nd","r**k"};

fromExcel = importExcelUtil.importDataFromExcel(importFile, header, BulkImportChangesEntity.class);

if (fromExcel.size()==0){

map.put("rspCode","99");

map.put("rspMsg","导入数据不能为空");

return map;

}

}catch (Exception e){

map.put("rspCode","99");

map.put("rspMsg","导入操作表失败,请注意数据列格式");

return map;

}

try {

//这里会对list集合中的数据进行处理

log.info("调用服务开始,参数:"+JSON.toJSONString(fromExcel));

//String url = p4_zuul_url+"/***/ri***eat/bu***nges";

String url = p4_zuul_url+"/***-surpass/ri***eat/bu***nges";

String result = HttpClientUtil.doPost(url,JSON.toJSONString(fromExcel));

log.info("调用服务结束,返回数据:"+result);

if (result != null){

map = JSONObject.parseObject(result, Map.class);

log.info("批量修改状态导入:"+JSON.toJSONString(map));

}

}catch (Exception e){

map.put("rspCode","99");

map.put("rspMsg","导入操作表失败");

log.info("bu***es exception",e);

return map;

}

return map;

}

/**

* 获取退单管理批量修改状态导入文件进度条进度

* @return

*/

@ResponseBody

@RequestMapping("/t***sk")

public Map t***sk(){

Map map = new HashMap<>();

//获取redis值

String progress = HttpClientUtil.doGet(

p4_zuul_url + "/" + p4_redis + "/redis***ler/get?key=progressSchedule");

if (progress != null){

map = JSONObject.parseObject(progress, Map.class);

log.info("进度条进度:"+JSON.toJSONString(map));

map.put("progressSchedule",progress);

}else {

HttpClientUtil.doGet(

p4_zuul_url + "/" + p4_redis + "/redis***ler/del?key=progressSchedule");

}

return map;

}

/**

* 清除redis进度条进度

* @return

*/

@ResponseBody

@RequestMapping("/de***ess")

public Map de***ess(){

Map map = new HashMap<>();

String progress = HttpClientUtil.doGet(

p4_zuul_url + "/" + p4_redis + "/redis***ler/del?key=progressSchedule");

if (progress != null){

map = JSONObject.parseObject(progress, Map.class);

log.info("返回数据:"+JSON.toJSONString(map));

}

return map;

}

导入时调用第一个bulk***es方法,定时任务调用t***sk方法,导入完成或发生错误调用de***ess方法删除redis数据,避免占用资源。

服务层

@Async//开启异步

@Transactional(rollbackFor = Exception.class)//事务回滚级别

@Override

public void bulkImportChanges(List list) {

//初始化进度

Double progressBarSchedule = 0.0;

redisClient.set("progressSchedule", progressBarSchedule + "");//存redis

try {

for (int i = 1; i <= list.size(); i++) {

RiskRetreatEntity entity = riskRetreatMapper.selectRetreatListBySysRefNum(list.get(i-1).getSysRefNum());

if (entity == null){

//查询结果为空直接进行下次循环不抛出

continue;

}

//实体封装

···

//更新

riskRetreatMapper.updateRetreatByImport(entity);

//计算修改进度并存放redis保存(1.0 / list.size())为一条数据进度

progressBarSchedule = (1.0 / list.size()) * i*100;

redisClient.set("progressSchedule", progressBarSchedule+"");

if (i==list.size()){

redisClient.set("progressSchedule", "100");

}

}

}catch (Exception e){

//当发生错误则清除缓存直接抛出回滚

redisClient.set("progressSchedule","error");

log.info("导入更新错误,回滚");

log.info("bulkImportChanges exception:",e);

throw e;

}

}

每更新一条数据存放进度,当发生错误则进行回滚。如果开启异步则需要在启动类添加注解@EnableAsync。

@EnableAsync

···//其他注解

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

结果样式

结尾

这次结合了前端的定时任务,后台事务以及异步,总的来说还是一次

java httpclient 进度条_SpringBoot如何实现一个实时更新的进度条的示例代码相关推荐

  1. php上传完没进度条_php使用APC实现实时上传进度条功能

    这篇文章主要介绍了php使用APC实现实时上传进度条功能,php本身不具备可以带有实时上传进度条功能,但是php提供了一个apc,它可以与php配置实现上传进度条,感兴趣的小伙伴们可以参考一下 php ...

  2. JAVA三维可视化组件:Matplot 3D for JAVA(V3.0) 一个纯JAVA开发的科学数据可视化组件包 类似 Python 的matplotlib(含示例代码)

    目录 概述 组件下载及项目地址 效果展示和示例代码 概述 Matplot3D for JAVA(V3.0) 是一个基于JAVA SE 1.8环境开发的三维图形图表组件. 组件由纯JAVA SE 实现( ...

  3. java for遍历hashmap_Java 使用for和while循环遍历HashMap的方法及示例代码

    1、使用entrySet()遍历 1) 使用while实现public static void printMap(Map mp) { Iterator it = mp.entrySet().itera ...

  4. python tkinter进度条_在python3.7中更新tkinter进度条

    抱歉,花了一段时间,但我能搞定.在 我不知道你遇到了什么与Python3.x不兼容的地方,但我找到了我跟踪的这个更新的视频.在 除了"停止"命令之外,它几乎完美地工作了,我无法开始 ...

  5. JAVA 集合Null 初始化_springboot使用mybatis-plus表单更新null值问题通用解决方案

    public class BaseModelMethodArgumentResolver implementsHandlerMethodArgumentResolver { @Overridepubl ...

  6. dropzone java实例_Java实现拖拽文件上传dropzone.js的简单使用示例代码

    Java实习生一枚,前端知识薄弱,最近因为工作需要,做了一个拖拽文件上传的功能,发现dropzone.js挺不错的,特地做个笔记. 自己写的拖拽文件至一个按钮上传的功能,前端及java代码如下: js ...

  7. java数据库易错程序题_JAVA程序改错 (易错题)(示例代码)

    1 JAVA程序改错2 1.3 abstract className {4 privateString name;5 public abstract booleanisStupidName(Strin ...

  8. java 输出字符集合里的字_Java基础 -- 字符串(格式化输出、正则表达式)(示例代码)...

    一 字符串 1.不可变String String对象是不可变的,查看JDK文档你就会发现,String类中每一个看起来会修改String值的方法,实际上都是创建一个全新的String对象,以包含修改后 ...

  9. java爬去指定网页的内容_JAVA使用Gecco爬虫 抓取网页内容(示例代码)

    JAVA 爬虫工具有挺多的,但是Gecco是一个挺轻量方便的工具. 先上项目结构图. 这是一个 JAVASE的 MAVEN 项目,要添加包依赖,其他就四个文件.log4j.properties 加上三 ...

最新文章

  1. vue里面_Vue中如何使用自定义插件(plugin)
  2. Nodejs教程14:querystring模块
  3. des 向量 java_在JAVA中使用DES算法
  4. 推荐sqlLite管理工具.
  5. Nginx 的 Echo 模块 —— echo-nginx-module(转)
  6. 定时锁屏 android,Android定时锁屏功能实现(AlarmManager定时部分)
  7. OpenCV2.3.1+VS2005配置方法
  8. 地学计算方法/地统计学(5第五章 空间插值与克里格法)
  9. Element ui Switch 开关二次确认弹窗后再更改开关状态
  10. IEC61850缩略语一览表
  11. 计算机毕业设计系列基于SSM的养老保险管理系统
  12. Java分解整型质因数
  13. 项目经理如何做好项目管理PMP - 持续更新
  14. 脉冲噪声及其消除算法(DPC)
  15. HR吐槽某博士程序员:简历写了12页,是不是读书读傻了
  16. DC/DC电路自举电容作用
  17. [ahk]解析大智慧自选股blk文件中的股票代码
  18. C/C++ printf 输入16进制文本数据 多出许多ffffff的问题
  19. vue两个按钮切换_vue点击循环 添加列表 点击来回切换
  20. 基于单片机的水壶自动加热系统_基于单片机智能电水壶控制系统设计毕业设计(论文).doc...

热门文章

  1. IntelliJ IDEA提示忽略大小写
  2. 第一次冲刺-团队开发(第六天)
  3. MyEclipse取消验证Js的两种方法
  4. MyEclipse8.5破解方法
  5. VMware Workstation Pro 虚拟机做RAID
  6. 初学者必备Linux指令
  7. 压缩文件后,每次的HASH值(MD5)都不相同的原因
  8. 开关电源测试系统用哪个软件,开关电源测试系统
  9. 层次聚类分析代码_4个步骤,用聚类分析法实现用户分析!
  10. XPath匹配标签使用text()判断获取结果失败/为空的问题及解决方法