最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

前后端實(shí)現(xiàn) excel 導(dǎo)入功能

2021-05-07 17:54 作者:匯智知了堂  | 我要投稿

前言

在Java領(lǐng)域解析中、生成excel 比較有名的框架有Apache poi、jxl等。但他們都有一個(gè)缺點(diǎn)就是非常的耗內(nèi)存。如果說(shuō)系統(tǒng)的并發(fā)不高還行,若是并發(fā)來(lái)了后一定會(huì)內(nèi)存溢出或者JVM頻繁的垃圾回收。 EasyExcel是阿里巴巴開源的一個(gè)excel處理框架,以使用簡(jiǎn)單、節(jié)省內(nèi)存著稱。EasyExcel能很大的減少占用內(nèi)存的主要原因是在解析文件時(shí)沒(méi)有將數(shù)據(jù)一次性全部加載到內(nèi)存中,而是從磁盤上一行行讀取數(shù)據(jù),逐個(gè)解析。 EasyExcel采用一行一行的解析模式,并將一行的解析結(jié)果以觀察者的模式通知處理(AnalysisEventListener)。

1、前端實(shí)現(xiàn)

<a-upload ? ?

accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" ? ?

:customRequest="customRequest" ? ?

@change="customChange" ? ?

:disabled="uploadDisabled"> ? ?<a-button type="primary"?:icon="uploadIcon"?:disabled="uploadDisabled">導(dǎo)入</a-button>?

</a-upload>


這段代碼中 a-upload 標(biāo)簽表示是在頁(yè)面中引入了導(dǎo)入組件`?

`accept 中這段代碼表示導(dǎo)入的文件只能是 excel 導(dǎo)入[.xlsx 或 .xls 都支持]` `customRequest 表示自定義方法代替默認(rèn)方法去實(shí)現(xiàn)文件導(dǎo)入/上傳操作`?

`@change 事件是在文件上傳中、完成、失敗都會(huì)調(diào)用這個(gè)函數(shù)`?

`disabled 是否禁用上傳組件`?

`a-button 創(chuàng)建一個(gè)操作按鈕,type 為 primary 表示這是一個(gè)主要按鈕,icon 表示為按鈕設(shè)置一個(gè)圖標(biāo)`?

`disabled是否禁用此按鈕


2、屬性定義

將上面自定義的屬性在data中定義好?to-top 的樣式為這個(gè):這個(gè)樣式也是用的 Ant Design Vue 中的 icon圖標(biāo)庫(kù)

export default { ? ?

data() { ? ? ? ?

return { ? ? ? ?

// 導(dǎo)入excel時(shí)的icon圖標(biāo) ? ? ? ?

uploadIcon: 'to-top', ? ? ? ?

// 導(dǎo)入excel時(shí)是否禁用上傳按鈕 ? ? ? ?

uploadDisabled: false ? ? ? ?

} ? ?

}?

}

3、方法實(shí)現(xiàn)

?/**

* 自定義導(dǎo)入文件方法 ? ? ? ??

* @param data 上傳的 excel 文件 ? ? ? ??

*/ customRequest(data) { ? ? ? ? ?

const file = data.file; // 需要上傳的 excel 文件 ? ? ? ? ?

const formData = new FormData(); ? ? ? ? ?

formData.append('file', file); ? ? ? ? ?

data.onProgress(); ? ? ? ? ?

batchImportGetRecord(formData).then(res => { ? ? ? ? ? ?

if (res) { ? ? ? ? ? ? ?

this.$message.success('導(dǎo)入成功'); ? ? ? ? ? ?

}?

else { ? ? ? ? ? ? ?

this.$message.error('導(dǎo)入失敗'); ? ? ? ? ? ?} ? ? ? ? ?

}).finally(() => { ? ? ? ? ? ?

this.switchIconAndStatus(false); ? ? ? ? ?

}); ? ? ? ?

}


上傳中、完成、失敗都會(huì)調(diào)用這個(gè)函數(shù)`?

`data.file.status 是文件上傳的一些狀態(tài)


/** ? ? ? ??

* 導(dǎo)入功能的 change 事件 ? ? ? ??

* @param data 上傳文件過(guò)程中的文件狀態(tài)信息 ? ? ? ??

*/ customChange(data) { ? ? ? ? ?

if (data.file.status === 'uploading') { ? ? ? ? ? ?this.switchIconAndStatus(true); ? ? ? ? ?

}?

else if?

(data.file.status === 'done') { ? ? ? ? ? ?this.switchIconAndStatus(false); ? ? ? ? ?

}?

else if (data.file.status === 'error') { ? ? ? ? ? ?this.switchIconAndStatus(false); ? ? ? ? ?

} ? ? ? ?}


/** ? ? ? ??

* 導(dǎo)入按鈕的圖片和狀態(tài)切換 ? ? ? ??

* @param flag 根據(jù)此標(biāo)識(shí)來(lái)區(qū)分正在導(dǎo)入還是導(dǎo)入成功或未導(dǎo)入的圖標(biāo)及禁用情況? ? ? */ switchIconAndStatus(flag) { ? ? ? ? ?

if (flag) { ? ? ? ? ? ?this.uploadIcon = 'loading'; ? ? ? ? ? ?this.uploadDisabled = true; ? ? ? ? ?}?

else { ? ? ? ? ? ?

this.uploadIcon = 'to-top'; ? ? ? ? ? ?

this.uploadDisabled = false; ? ? ? ? ?

} ? ? ? ?}


4、后端實(shí)現(xiàn)

4.1、控制層 Controller 實(shí)現(xiàn)

后臺(tái)接口,圖片上傳請(qǐng)求默認(rèn)為 post 請(qǐng)求,通過(guò) MultipartFile 類型接收上傳的文件,注意這里的?@RequestParam("file")?括號(hào)中的參數(shù)要和前端上傳的參數(shù)名稱一致,不一致后臺(tái)就接收不到這個(gè)參數(shù)

@PostMapping(value = "import") ? ?

public Boolean importExcelData(@RequestParam("file") MultipartFile file)?

{ ? ? ? ?return studentService.importExcelData(file); ? ?}

4.2、務(wù)層 Service 實(shí)現(xiàn)

這里舉例導(dǎo)入一個(gè)學(xué)生信息表 excel 文件

@Override ? ?

@Transactional(rollbackFor = Exception.class) ? ?

public boolean importExcelData(MultipartFile file) { ? ? ? ?

List<Student> list = new ArrayList<Student>(); ? ? ? ?

Student student = null; ? ? ? ?

try { ? ? ? ? ? ?

// 通過(guò)文件輸入流讀取到對(duì)應(yīng)的 workbook 工作簿 ? ? ? ? ? ?

XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream()); ? ? ? ? ? ?// 只解析第一張 sheet 工作表 ? ? ? ? ? ?

XSSFSheet sheet = workbook.getSheetAt(0); ? ? ? ? ? ?

// 遍歷第一個(gè)工作表的所有行 ? ? ? ? ? ?

for (int i = 0; i < sheet.getPhysicalNumberOfRows(); i++) { ? ? ? ? ? ? ? ?if (i == 0) continue;?

// 跳過(guò)標(biāo)題行 ? ? ? ? ? ? ? ?

XSSFRow row = sheet.getRow(i);?

// 獲取工作表中的某一行,通過(guò)下標(biāo)獲取 ? ? ? ? ? ? ? ?

if (row == null) continue;?

// 跳過(guò)空行 ? ? ? ? ? ? ? ?

// 構(gòu)造要批量插入的Student對(duì)象 ? ? ? ? ? ? ? ?

student = new Student(); ? ? ? ? ? ? ? ?

// 遍歷一個(gè)行中的所有列 ? ? ? ? ? ? ? ?

for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) { ? ? ? ? ? ? ? ? ? ?XSSFCell cell = row.getCell(j);?

// 獲取一行中的某個(gè)單元格,通過(guò)下標(biāo)獲取 ? ? ? ? ? ? ? ? ? ?

if (cell == null) continue;?

// 跳過(guò)空單元格 ? ? ? ? ? ? ? ? ? ?

// 獲取單元格中的字符串內(nèi)容 ? ? ? ? ? ? ? ? ? ?

String cellValue = cell.getStringCellValue(); ? ? ? ? ? ? ? ? ? ?

// 獲取單元格中的數(shù)字內(nèi)容 ? ? ? ? ? ? ? ? ? ?

double cellValue2 = cell.getNumericCellValue(); ? ? ? ? ? ? ? ? ? ?

// 判斷單元格是第幾個(gè),從零開始 ? ? ? ? ? ? ? ? ? ?

switch (j) { ? ? ? ? ? ? ? ? ? ? ? ?

case 0: // 第一列就是姓名 ? ? ? ? ? ? ? ? ? ? ? ? ? ?student.setName(cellValue);?

// 給實(shí)體類的setter屬性賦值 ? ? ? ? ? ? ? ? ? ? ? ? ? ?

break; ? ? ? ? ? ? ? ? ? ? ? ?

case 1:?

// 年齡 ? ? ? ? ? ? ? ? ? ? ? ? ? ?

student.setAge(cellValue2); ? ? ? ? ? ? ? ? ? ? ? ? ? ?

break; ? ? ? ? ? ? ? ? ? ? ? ?

case 2:?

// 愛好 ? ? ? ? ? ? ? ? ? ? ? ? ? ?

student.setHobby(cellValue); ? ? ? ? ? ? ? ? ? ? ? ? ? ?

break; ? ? ? ? ? ? ? ? ? ? ? ?

case 3:?

// 家庭地址 ? ? ? ? ? ? ? ? ? ? ? ? ? ?

student.setAddress(cellValue); ? ? ? ? ? ? ? ? ? ? ? ? ? ?

break; ? ? ? ? ? ? ? ? ? ? ? ?

case 4:?

// 出生日期 ? ? ? ? ? ? ? ? ? ? ? ? ? ?

// 如果沒(méi)有特意去定義 excel 中的日期,那么獲取到的日期就是字符串類型? ? ? ? ? // 這里將字符串日期轉(zhuǎn)換為日期格式 LocalDateTime 或 Date ? ? ? ? ? ? ? ? ? ? ? // 1. 將日期轉(zhuǎn)換為 LocalDateTime ? ? ? ? ? ? ? ? ? ? ? ? ? ?

// LocalDateTime time = LocalDateTime.parse(cellValue, DateTimeFormatter.ofPattern("yyyy年M月d日HH:mm:ss")); ? ? ? ? ? ? ? ? ? ? ? // 2. 將日期轉(zhuǎn)換為 Date ? ? ? ? ? ? ? ? ? ? ? ? ? ?

SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日HH:mm:ss"); ? ? ? Date date = sdf.parse(cellValue); ? ? ? ? ? ? ? ? ? ? ? ? ? student.setBirthday(date); ? ? ? ? ? ? ? ? ? ? ? ? ? ?

break; ? ? ? ? ? ? ? ? ? ?

} ? ? ? ? ? ? ? ?

} ? ? ? ? ? ? ? ?

list.add(student); ? ? ? ? ? ?

} ? ? ? ? ? ?

// 做一下批量添加學(xué)生信息的操作即可,這里使用 MyBatis-Plus 提供的方法進(jìn)行批量新增 ? ? ? ? ? ?

studentService.saveBatch(list); ? ? ? ? ? ?

return true; ? ? ? ?}?

catch (Exception e) {? ? ? ? ? ??

?e.printStackTrace(); ? ? ? ? ? ?

System.err.println("導(dǎo)入失敗"); ? ? ? ? ? ?TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();?

// 手動(dòng)回滾代碼 ? ? ? ? ? ?

return false; ? ? ? ?

} ? ?}


代碼解讀:

  • 通過(guò)?file.getInputStream()?構(gòu)建一個(gè) workbook

  • work.getSheetAt(index)?通過(guò)此方法獲取工作表,通過(guò)索引來(lái)獲取,索引從零開始

  • sheet.getPhysicalNumberOfRows()?方法可以獲取 sheet 工作表中的所有行的數(shù)量

  • sheet.getRow(index)?通過(guò)下標(biāo)獲取對(duì)應(yīng)的行,下標(biāo)都是從零開始

  • row.getPhysicalNumberOfCells()?方法可以獲取到一行中所有單元格的數(shù)量

  • row.getCell(index)?通過(guò)下標(biāo)獲取對(duì)應(yīng)的單元格,下標(biāo)都是從零開始

  • cell.getStringCellValue()?此方法用于獲取單元格中為字符串類型的內(nèi)容值,相關(guān)的方法有多種,可以獲取 Boolean,日期類型,數(shù)字類型等….

最后經(jīng)過(guò)讀取所有內(nèi)容后將單元格內(nèi)容一行行的讀取設(shè)置到 實(shí)體類中,并將實(shí)體類經(jīng)過(guò)每次循環(huán)都添加到 list 集合中,最后通過(guò)批量插入表的操作給插入到數(shù)據(jù)庫(kù)中,比起來(lái)一條條的插入,批量插入明顯效率更高,因?yàn)楹笈_(tái)請(qǐng)求數(shù)據(jù)庫(kù)也是在消耗網(wǎng)絡(luò)資源,中間一去一回也是浪費(fèi)時(shí)間,而批量插入明顯網(wǎng)絡(luò)資源消耗的更少。

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()?添加事務(wù)后,當(dāng)導(dǎo)入失敗時(shí),可以進(jìn)行代碼回滾操作`

4.3、測(cè)試

導(dǎo)入成功!

前后端實(shí)現(xiàn) excel 導(dǎo)入功能的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
瑞昌市| 黄龙县| 丁青县| 泽库县| 秭归县| 博白县| 承德市| 陵水| 龙陵县| 涟源市| 大足县| 赤壁市| 岳西县| 琼海市| 丁青县| 菏泽市| 孝义市| 东乌| 鹤峰县| 清河县| 新干县| 农安县| 乐昌市| 卢氏县| 渑池县| 河北省| 伊春市| 界首市| 营山县| 北流市| 洪江市| 虹口区| 武川县| 博客| 石河子市| 隆德县| 剑川县| 阳春市| 固镇县| 玉树县| 剑河县|