电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

使用Springboot+poi上傳并處理百萬級數據EXCEL

瀏覽:114日期:2022-06-16 14:23:09

1 Excel上傳

針對Excel的上傳,采用的是比較常規的方法,其實和文件上傳是相同的。具體源碼如下:

@PostMapping(value = '', consumes = 'multipart/*', headers = 'content-type=multipart/form-data') public Map<String, Object> addBlacklist( @RequestParam('file') MultipartFile multipartFile, HttpServletRequest request ) { //判斷上傳內容是否符合要求 String fileName = multipartFile.getOriginalFilename(); if (!fileName.matches('^.+.(?i)(xls)$') && !fileName.matches('^.+.(?i)(xlsx)$')) { return returnError(0,'上傳的文件格式不正確'); } String file = saveFile(multipartFile, request); int result = 0; try { result = blacklistServcice.addBlackLists(file); } catch (Exception e) { e.printStackTrace(); } return returnData(result); } private String saveFile(MultipartFile multipartFile, HttpServletRequest request) { String path; String fileName = multipartFile.getOriginalFilename(); // 判斷文件類型 String realPath = request.getSession().getServletContext().getRealPath('/'); String trueFileName = fileName; // 設置存放Excel文件的路徑 path = realPath + trueFileName; File file = new File(path); if (file.exists() && file.isFile()) { file.delete(); } try { multipartFile.transferTo(new File(path)); } catch (IOException e) { e.printStackTrace(); } return path; }

上面的源碼我們可以看見有一個saveFile方法,這個方法是將文件存在服務器本地,這樣方便后續文件內容的讀取,用不著一次讀取所有的內容從而導致消耗大量的內存。當然這里大家如果有更好的方法希望能留言告知哈。

2 Excel處理工具源碼

import org.apache.poi.openxml4j.opc.OPCPackage;import org.apache.poi.xssf.eventusermodel.XSSFReader;import org.apache.poi.xssf.model.SharedStringsTable;import org.apache.poi.xssf.usermodel.XSSFRichTextString;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.DefaultHandler;import org.xml.sax.helpers.XMLReaderFactory; import java.io.InputStream;import java.sql.SQLException;import java.util.*; /** * XSSF and SAX (Event API) */public abstract class XxlsAbstract extends DefaultHandler { private SharedStringsTable sst; private String lastContents; private int sheetIndex = -1; private List<String> rowlist = new ArrayList<>(); public List<Map<String, Object>> dataMap = new LinkedList<>(); //即將進行批量插入的數據 public int willSaveAmount; //將要插入的數據量 public int totalSavedAmount; //總共插入了多少數據 private int curRow = 0; //當前行 private int curCol = 0; //當前列索引 private int preCol = 0; //上一列列索引 private int titleRow = 0; //標題行,一般情況下為0 public int rowsize = 0; //列數 //excel記錄行操作方法,以sheet索引,行索引和行元素列表為參數,對sheet的一行元素進行操作,元素為String類型 public abstract void optRows(int sheetIndex, int curRow, List<String> rowlist) throws SQLException; //只遍歷一個sheet,其中sheetId為要遍歷的sheet索引,從1開始,1-3 /** * @param filename * @param sheetId sheetId為要遍歷的sheet索引,從1開始,1-3 * @throws Exception */ public void processOneSheet(String filename, int sheetId) throws Exception { OPCPackage pkg = OPCPackage.open(filename); XSSFReader r = new XSSFReader(pkg); SharedStringsTable sst = r.getSharedStringsTable(); XMLReader parser = fetchSheetParser(sst); // rId2 found by processing the Workbook // 根據 rId# 或 rSheet# 查找sheet InputStream sheet2 = r.getSheet('rId' + sheetId); sheetIndex++; InputSource sheetSource = new InputSource(sheet2); parser.parse(sheetSource); sheet2.close(); } public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException { XMLReader parser = XMLReaderFactory.createXMLReader(); this.sst = sst; parser.setContentHandler(this); return parser; } public void endElement(String uri, String localName, String name) { // 根據SST的索引值的到單元格的真正要存儲的字符串 try { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)) .toString(); } catch (Exception e) { } // v => 單元格的值,如果單元格是字符串則v標簽的值為該字符串在SST中的索引 // 將單元格內容加入rowlist中,在這之前先去掉字符串前后的空白符 if (name.equals('v')) { String value = lastContents.trim(); value = value.equals('') ? ' ' : value; int cols = curCol - preCol; if (cols > 1) {for (int i = 0; i < cols - 1; i++) { rowlist.add(preCol, '');} } preCol = curCol; rowlist.add(curCol - 1, value); } else { //如果標簽名稱為 row ,這說明已到行尾,調用 optRows() 方法 if (name.equals('row')) {int tmpCols = rowlist.size();if (curRow > this.titleRow && tmpCols < this.rowsize) { for (int i = 0; i < this.rowsize - tmpCols; i++) { rowlist.add(rowlist.size(), ''); }}try { optRows(sheetIndex, curRow, rowlist);} catch (SQLException e) { e.printStackTrace();}if (curRow == this.titleRow) { this.rowsize = rowlist.size();}rowlist.clear();curRow++;curCol = 0;preCol = 0; } } }}

3 解析成功后的數據處理

首先我們將源碼展示出來,然后再具體說明

public int addBlackLists(String file) throws ExecutionException, InterruptedException { ArrayList<Future<Integer>> resultList = new ArrayList<>(); XxlsAbstract xxlsAbstract = new XxlsAbstract() { //針對數據的具體處理 @Override public void optRows(int sheetIndex, int curRow, List<String> rowlist) { /** * 判斷即將插入的數據是否已經到達8000,如果到達8000, * 進行數據插入 */if (this.willSaveAmount == 5000) { //插入數據 List<Map<String, Object>> list = new LinkedList<>(this.dataMap); Callable<Integer> callable = () -> { int count = blacklistMasterDao.addBlackLists(list); blacklistRecordMasterDao.addBlackListRecords(list); return count; }; this.willSaveAmount = 0; this.dataMap = new LinkedList<>(); Future<Integer> future = executor.submit(callable); resultList.add(future);} //匯總數據Map<String, Object> map = new HashMap<>();map.put('uid', rowlist.get(0));map.put('createTime', rowlist.get(1));map.put('regGame', rowlist.get(2)); map.put('banGame', rowlist.get(2));this.dataMap.add(map);this.willSaveAmount++;this.totalSavedAmount++; } }; try { xxlsAbstract.processOneSheet(file, 1); } catch (Exception e) { e.printStackTrace(); } //針對沒有存入的數據進行處理 if(xxlsAbstract.willSaveAmount != 0){ List<Map<String, Object>> list = new LinkedList<>(xxlsAbstract.dataMap); Callable<Integer> callable = () -> {int count = blacklistMasterDao.addBlackLists(list);blacklistRecordMasterDao.addBlackListRecords(list);return count; }; Future<Integer> future = executor.submit(callable); resultList.add(future); } executor.shutdown(); int total = 0; for (Future<Integer> future : resultList) { while (true) {if (future.isDone() && !future.isCancelled()) { int sum = future.get(); total += sum; break;} else { Thread.sleep(100);} } } return total; }

針對上面的源碼,我們可以發現,我們需要將讀取到的EXCEL數據插入到數據庫中,這里為了減小數據庫的IO和提高插入的效率,我們采用5000一批的批量插入(注意:如果數據量過大會導致組成的SQL語句無法執行)。

這里需要獲取到一個最終執行成功的插入結果,并且插入執行很慢。所有采用了Java多線程的Future模式,采用異步的方式最終來獲取J執行結果。

通過上面的實現,樓主測試得到最終一百萬條數據需要四分鐘左右的時間就可以搞定。如果大家有更好的方法,歡迎留言。

補充知識:Java API SXSSFWorkbook導出Excel大批量數據(百萬級)解決導出超時

之前使用簡單的HSSFWorkbook,導出的數據不能超過

使用Springboot+poi上傳并處理百萬級數據EXCEL

后來改成SXSSFWorkbook之后可以導出更多,但是

而且我之前的代碼是一次性查出所有數據,幾十萬條,直接就超時了。

之前的代碼是一次性查出所有的結果,list里面存了幾十萬條數據。因為功能設計的問題,我這一個接口要同時處理三個功能:

使用Springboot+poi上傳并處理百萬級數據EXCEL

再加上查詢SQL的效率問題,導致請求超時。

現在為了做到處更大量的數據只能選擇優化。優化查詢的sql這里就不講了,只講導出功能的優化。

其實就是分批次處理查詢結果:

使用Springboot+poi上傳并處理百萬級數據EXCEL

這樣做的好處是查詢速度變快,封裝速度也變快,整體速度變快就不會出現超時,而且,每次分頁查出的結果放到list中不會出現占用JVM內存過大的情況。避免出現內存溢出導致系統崩潰。

再次優化:

上面這樣做雖然可以導出,但是代碼看起來不美觀:

使用Springboot+poi上傳并處理百萬級數據EXCEL

這樣看起來就簡潔很多了。

經驗證,查詢加封裝EXCEL7000條數據處理只需要1秒

使用Springboot+poi上傳并處理百萬級數據EXCEL

使用Springboot+poi上傳并處理百萬級數據EXCEL

使用Springboot+poi上傳并處理百萬級數據EXCEL

以上這篇使用Springboot+poi上傳并處理百萬級數據EXCEL就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: excel
相關文章:
主站蜘蛛池模板: 上海单片机培训|重庆曙海培训分支机构—CortexM3+uC/OS培训班,北京linux培训,Windows驱动开发培训|上海IC版图设计,西安linux培训,北京汽车电子EMC培训,ARM培训,MTK培训,Android培训 | 抖音短视频运营_企业网站建设_网络推广_全网自媒体营销-东莞市凌天信息科技有限公司 | 微型气泵-真空-蠕动-水泵-厂家-深圳市品亚科技有限公司 | 质检报告_CE认证_FCC认证_SRRC认证_PSE认证_第三方检测机构-深圳市环测威检测技术有限公司 | 蓝米云-专注于高性价比香港/美国VPS云服务器及海外公益型免费虚拟主机 | 翅片管散热器价格_钢制暖气片报价_钢制板式散热器厂家「河北冀春暖气片有限公司」 | 集菌仪_智能集菌仪_全封闭集菌仪_无菌检查集菌仪厂家-那艾 | 溶氧传感器-pH传感器|哈美顿(hamilton)| 月嫂_保姆_育婴_催乳_母婴护理_产后康复_养老护理-吉祥到家家政 硫酸亚铁-聚合硫酸铁-除氟除磷剂-复合碳源-污水处理药剂厂家—长隆科技 | 防火卷帘门价格-聊城一维工贸特级防火卷帘门厂家▲ | 北京印刷厂_北京印刷_北京印刷公司_北京印刷厂家_北京东爵盛世印刷有限公司 | 北京租车公司_汽车/客车/班车/大巴车租赁_商务会议/展会用车/旅游大巴出租_北京桐顺创业租车公司 | 桑茶-七彩贝壳桑叶茶 长寿茶| 压片机_高速_单冲_双层_花篮式_多功能旋转压片机-上海天九压片机厂家 | 北京网站建设首页,做网站选【优站网】,专注北京网站建设,北京网站推广,天津网站建设,天津网站推广,小程序,手机APP的开发。 | nalgene洗瓶,nalgene量筒,nalgene窄口瓶,nalgene放水口大瓶,浙江省nalgene代理-杭州雷琪实验器材有限公司 | 【电子厂招聘_普工招工网_工厂招聘信息平台】-工立方打工网 | 学校用栓剂模,玻璃瓶轧盖钳,小型安瓿熔封机,实验室安瓿熔封机-长沙中亚制药设备有限公司 | 济南ISO9000认证咨询代理公司,ISO9001认证,CMA实验室认证,ISO/TS16949认证,服务体系认证,资产管理体系认证,SC食品生产许可证- 济南创远企业管理咨询有限公司 郑州电线电缆厂家-防火|低压|低烟无卤电缆-河南明星电缆 | 模型公司_模型制作_沙盘模型报价-中国模型网 | 镀锌钢格栅_热镀锌格栅板_钢格栅板_热镀锌钢格板-安平县昊泽丝网制品有限公司 | 不锈钢法兰-碳钢法兰-法兰盘生产加工厂家-[鼎捷峰]-不锈钢法兰-碳钢法兰-法兰盘生产加工厂家-[鼎捷峰] | 神超官网_焊接圆锯片_高速钢锯片_硬质合金锯片_浙江神超锯业制造有限公司 | 集菌仪厂家_全封闭_封闭式_智能智能集菌仪厂家-上海郓曹 | 铣床|万能铣床|立式铣床|数控铣床|山东滕州万友机床有限公司 | 北京翻译公司_同传翻译_字幕翻译_合同翻译_英语陪同翻译_影视翻译_翻译盖章-译铭信息 | 深圳法律咨询【24小时在线】深圳律师咨询免费 | 粉丝机械,粉丝烘干机,粉丝生产线-招远市远东粉丝机械有限公司 | 英国公司注册-新加坡公司注册-香港公司开户-离岸公司账户-杭州商标注册-杭州优创企业 | 精密光学实验平台-红外粉末压片机模具-天津博君 | 中医中药治疗血小板减少-石家庄血液病肿瘤门诊部 | 北京康百特科技有限公司-分子蒸馏-短程分子蒸馏设备-实验室分子蒸馏设备 | 控显科技 - 工控一体机、工业显示器、工业平板电脑源头厂家 | MVE振动电机_MVE震动电机_MVE卧式振打电机-河南新乡德诚生产厂家 | 钢制暖气片散热器_天津钢制暖气片_卡麦罗散热器厂家 | 北京中创汇安科贸有限公司| 5nd音乐网|最新流行歌曲|MP3歌曲免费下载|好听的歌|音乐下载 免费听mp3音乐 | 低粘度纤维素|混凝土灌浆料|有机硅憎水粉|聚羧酸减水剂-南京斯泰宝 | 玉米深加工设备|玉米加工机械|玉米加工设备|玉米深加工机械-河南成立粮油机械有限公司 | 杭州ROHS检测仪-XRF测试仪价格-百科 | 物联网卡_物联网卡购买平台_移动物联网卡办理_移动联通电信流量卡通信模组采购平台? |