SpringBoot如何實現(xiàn)一個實時更新的進度條的示例代碼
前言
博主近期接到一個任務,大概內(nèi)容是:導入excel表格批量修改狀態(tài),期間如果發(fā)生錯誤則所有數(shù)據(jù)不成功,為了防止重復提交,做一個類似進度條的東東。
那么下面我會結(jié)合實際業(yè)務對這個功能進行分析和記錄。
正文
思路
前端使用bootstrap,后端使用SpringBoot分布式到注冊中心,原先的想法是導入表格后異步調(diào)用修改數(shù)據(jù)狀態(tài)的方法,然后每次計算修改的進度然后存放在session中,前臺jquery寫定時任務訪問獲取session中的進度,更新進度條進度和百分比。但是這存在session在服務間不共享,跨域問題。那么換一個方式存放,存放在redis中,前臺定時任務直接操作獲取redis的數(shù)據(jù)。
實施
進度條
先來看一下bootstrap的進度條
<div class="progress progress-striped active"> <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 40%;"> 40% </div> </div>
進度條更新主要更新style="width: 40%;"的值即可,div里面的40%可以省略,無非時看著明確。
可以考慮將進度條放入彈出層。
定時任務
//點擊確認導入執(zhí)行此方法 function bulkImportChanges() { //獲取批量操作狀態(tài)文件 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); //這里更新進度條的進度和數(shù)據(jù) $(".progress-bar").width(parseFloat(date)+"%"); $(".progress-bar").text(parseFloat(date)+"%"); } } }); //導入修改完成或異常(停止定時任務) if (parseInt(progress)==100 || progress == "error") { //清除定時執(zhí)行 clearInterval(timingTask); $.ajax({ type: 'post', url: "/risk/de***ess", dataType : 'json', success: function(result) { $("#bulkImportChangesProcessor").hide(); if (parseInt(progress) == 100) { alert("批量導入修改狀態(tài)成功"); } if (progress == "error") { alert("批量導入修改狀態(tài)失敗"); } //獲取最新數(shù)據(jù) 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存放的進度,返回更新進度條,如果更新完成或者更新失敗(根據(jù)后臺返回的數(shù)據(jù)決定)則停止定時任務顯示相應的信息并刷新頁面。獲取最新數(shù)據(jù)。
后臺控制層
/** * 退單管理批量修改狀態(tài)導入文件 * @param importFile * @return */ @ResponseBody @RequestMapping("/bulk***es") public Map<String,Object> bulk***es(MultipartFile importFile){ log.info("退單管理批量修改狀態(tài)導入文件,傳入?yún)?shù):"+importFile); Map<String,Object> map = new HashMap<>(); List<Bulk***esEntity> fromExcel = null; try{ //使用工具類導入轉(zhuǎn)成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","導入數(shù)據(jù)不能為空"); return map; } }catch (Exception e){ map.put("rspCode","99"); map.put("rspMsg","導入操作表失敗,請注意數(shù)據(jù)列格式"); return map; } try { //這里會對list集合中的數(shù)據(jù)進行處理 log.info("調(diào)用服務開始,參數(shù):"+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("調(diào)用服務結(jié)束,返回數(shù)據(jù):"+result); if (result != null){ map = JSONObject.parseObject(result, Map.class); log.info("批量修改狀態(tài)導入:"+JSON.toJSONString(map)); } }catch (Exception e){ map.put("rspCode","99"); map.put("rspMsg","導入操作表失敗"); log.info("bu***es exception",e); return map; } return map; } /** * 獲取退單管理批量修改狀態(tài)導入文件進度條進度 * @return */ @ResponseBody @RequestMapping("/t***sk") public Map<String,Object> t***sk(){ Map<String,Object> 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<String,Object> de***ess(){ Map<String,Object> 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("返回數(shù)據(jù):"+JSON.toJSONString(map)); } return map; }
導入時調(diào)用第一個bulk***es方法,定時任務調(diào)用t***sk方法,導入完成或發(fā)生錯誤調(diào)用de***ess方法刪除redis數(shù)據(jù),避免占用資源。
服務層
@Async//開啟異步 @Transactional(rollbackFor = Exception.class)//事務回滾級別 @Override public void bulkImportChanges(List<BulkImportChangesParam> 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){ //查詢結(jié)果為空直接進行下次循環(huán)不拋出 continue; } //實體封裝 ··· //更新 riskRetreatMapper.updateRetreatByImport(entity); //計算修改進度并存放redis保存(1.0 / list.size())為一條數(shù)據(jù)進度 progressBarSchedule = (1.0 / list.size()) * i*100; redisClient.set("progressSchedule", progressBarSchedule+""); if (i==list.size()){ redisClient.set("progressSchedule", "100"); } } }catch (Exception e){ //當發(fā)生錯誤則清除緩存直接拋出回滾 redisClient.set("progressSchedule","error"); log.info("導入更新錯誤,回滾"); log.info("bulkImportChanges exception:",e); throw e; } }
每更新一條數(shù)據(jù)存放進度,當發(fā)生錯誤則進行回滾。如果開啟異步則需要在啟動類添加注解@EnableAsync。
@EnableAsync ···//其他注解 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
結(jié)果樣式
結(jié)尾
這次結(jié)合了前端的定時任務,后臺事務以及異步,總的來說還是一次🙅不錯的體驗。
到此這篇關于SpringBoot如何實現(xiàn)一個實時更新的進度條的示例代碼的文章就介紹到這了,更多相關SpringBoot實時更新進度條內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot@Aspect 打印訪問請求和返回數(shù)據(jù)方式
這篇文章主要介紹了SpringBoot@Aspect 打印訪問請求和返回數(shù)據(jù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09Java數(shù)據(jù)結(jié)構(gòu)--時間和空間復雜度
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)的時間和空間復雜度,小編覺得這篇文寫的不錯,感興趣的朋友可以了解下,希望能夠給你帶來幫助2021-08-08IDEA創(chuàng)建SpringBoot項目整合mybatis時mysql-connector-java報錯異常的詳細分析
最近工作中發(fā)現(xiàn)了個錯誤,分享給同樣遇到這個問題的朋友,這篇文章主要給大家介紹了關于IDEA創(chuàng)建SpringBoot項目整合mybatis時mysql-connector-j報錯異常的詳細分析,需要的朋友可以參考下2023-02-02