超簡(jiǎn)潔!利用easyExcel導(dǎo)出導(dǎo)入Excel

? 深夜,在東莞,7天酒店,打開(kāi)電腦,訪問(wèn)國(guó)內(nèi)最大的同性交友網(wǎng)站。

?? ? ? ? 日常開(kāi)發(fā)中,導(dǎo)出導(dǎo)入場(chǎng)景非常多,尤其是對(duì)于后臺(tái)管理更是一個(gè)列表一個(gè)導(dǎo)出,如果從導(dǎo)出的業(yè)務(wù)中抽離出復(fù)用代碼,專注于邏輯開(kāi)發(fā),對(duì)于開(kāi)發(fā)者而言非常重要。前有使用POI,但作者還是更喜EasyExcel的簡(jiǎn)潔高效不拖沓,所以特意寫(xiě)篇文章記錄下。

# 準(zhǔn)備工作

?? ? ? ? 準(zhǔn)備工作是看文檔了解EasyExcel嗎?不,我們直接上手吧!我發(fā)現(xiàn)最近的業(yè)務(wù)里面,最簡(jiǎn)單的例子已經(jīng)應(yīng)付下來(lái)了!所以準(zhǔn)備工作自然只需導(dǎo)入EasyExcel的jar包,這里我們由于是springboot項(xiàng)目,所以直接使用maven。直接上最新的版本了!pom.xml給它加上:

```java

<dependency>

? ? ? ? ? ? <groupId>com.alibaba</groupId>

? ? ? ? ? ? <artifactId>easyexcel</artifactId>

? ? ? ? ? ? <version>2.2.5</version>

</dependency>

```

# 導(dǎo)出

?? ? ? ? 準(zhǔn)備工作已經(jīng)完成,導(dǎo)出開(kāi)始,首先需要一個(gè)Bean類,導(dǎo)出的字段和Excel文件的字段一樣即可。@Data是用了lombok,@ExcelProperty則包含了Excel首行的名稱和字段所在位置,從0開(kāi)始,不能重復(fù)。

```java

@Data

public class ExportVo {


? @ExcelProperty(value = "名稱", index = 0)

? private String name;

? @ExcelProperty(value = "時(shí)間", index = 1)

? private Date time;


? @NumberFormat("#.##%")

? @ExcelProperty(value = "完成率", index = 2)

? private Float rate;


}

```

?? ? ? ? 接下來(lái)是邏輯實(shí)現(xiàn):

```java

? @PostMapping("/export")

? public void export(@RequestBody ExportDto dto, HttpServletResponse response)

? ? ? ? ? throws IOException {

? ? String fileName = "統(tǒng)計(jì)表";

? ? ExcelUtil.download(response, fileName, ExportVo.class,

? ? ? ? ? ? getExportVoList());

? }

? private List getExportVoList() {

? ? //? 這里主要是獲取List<ExportVo>內(nèi)容,不提供實(shí)現(xiàn)了,需要說(shuō)下注意點(diǎn)。

? ? ? 1、導(dǎo)出列表應(yīng)該有時(shí)間之類的限制(例如最近一個(gè)月),避免導(dǎo)出Excel過(guò)大,過(guò)大Excel一般采用分sheet導(dǎo)出(尤其xls文件,有65535條數(shù)限制)、分文件打包導(dǎo)出,上傳文件服務(wù)器異步導(dǎo)出,不可突破的最大導(dǎo)出(限死5w條)。

? ? ? 2、一來(lái)考慮數(shù)據(jù)庫(kù)查詢和內(nèi)存壓力,二來(lái)分頁(yè)插件可能存在最大頁(yè)數(shù)限制,所以較多條數(shù)時(shí)必須做分頁(yè)查詢,再組合List對(duì)象。

? ? ? 3、一般從數(shù)據(jù)庫(kù)直接查出數(shù)據(jù)不滿足導(dǎo)出字段需要,有必要時(shí)需要做字段轉(zhuǎn)換。

? }

```

?? ? ? 導(dǎo)出的處理類:

```java

public class ExcelUtil {

? public static void download(HttpServletResponse response, String fileName,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Class cls, List dataList)

? ? ? ? ? throws IOException {

? ? response.setContentType("application/vnd.ms-excel");

? ? response.setCharacterEncoding("utf-8");

? ? String fname = URLEncoder.encode(fileName, "utf-8");

? ? response.setHeader("Content-disposition",

? ? ? ? ? ? "attachment;filename=" + fname + ExcelTypeEnum.XLSX.getValue());

? ? LongestMatchColumnWidthStyleStrategy longestMatchColumnWidthStyleStrategy =

? ? ? ? ? ? new LongestMatchColumnWidthStyleStrategy();

? ? EasyExcel.write(response.getOutputStream(), cls)

? ? ? ? ? ? .sheet("sheet1")

? ? ? ? ? ? .registerWriteHandler(longestMatchColumnWidthStyleStrategy)

? ? ? ? ? ? .doWrite(dataList);

? ? response.flushBuffer();

? }

```

?? ? ? ? 啟動(dòng)程序,使用postman試下,直接點(diǎn)Send的話會(huì)返回一堆亂碼,選擇Send and Download則可導(dǎo)出Excel,不過(guò)文件名是URL編碼過(guò)的,這個(gè)文件名編碼問(wèn)題在瀏覽器則不會(huì)存在。

![image-20200702002721411](C:\Users\lin\AppData\Roaming\Typora\typora-user-images\image-20200702002721411.png)

# 導(dǎo)入

?? ? ? ? 導(dǎo)入是為了減少人工錄入大量數(shù)據(jù)的煩惱,挺好的。

```java

? @Autowired

? private ImportService importService;

? @PostMapping("/import")

? public void import(

? ? ? ? ? @RequestParam(value = "file") MultipartFile file,

? ? ? ? ? @Min(1) @RequestParam("type") int type

? ) throws IOException {

? ? ImportQueryDto dto = new ImportQueryDto();

? ? dto.setType(type);

? ? // ImportDto是導(dǎo)入對(duì)應(yīng)類,UploadDataListener是處理類,邏輯處理服務(wù)需要以參數(shù)形式傳入

? ? EasyExcel.read(file.getInputStream(), ImportDto.class,

? ? ? ? ? ? new UploadDataListener(importService)).sheet().doRead();

? }

```

?? ? 導(dǎo)入Excel對(duì)應(yīng)類,ExcelProperty對(duì)應(yīng)導(dǎo)入字段的首部。

```java

@Data

public class ImportDto {

? @ExcelProperty("名稱")

? private String name;

? @ExcelProperty("數(shù)量")

? private Integer num;

}

```

?? ? ? 導(dǎo)入處理:

```java

public class UploadDataListener

? ? ? ? extends AnalysisEventListener<ImportDto> {

? //? 一次導(dǎo)入多少便入庫(kù),避免大量入庫(kù)

? private static final int BATCH_COUNT = 50;

? //? 存放導(dǎo)入列表

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

? private ImportService importService;

? public UploadDataListener(ImportService importService) {

? ? this.importService = importService;

? }

? @Override

? public void invoke(ImportDto importDto, AnalysisContext analysisContext) {

? ? list.add(importDto);

? ? if (list.size() >= BATCH_COUNT) {

? ? ? saveData();

? ? ? list.clear();

? ? }

? }

? @Override

? public void doAfterAllAnalysed(AnalysisContext analysisContext) {

? ? saveData();

? }

? private void saveData() {

? ? List<ImportModel> importModelList = new ArrayList<>();

? ? for (ImportDto dto : list) {

? ? ? ImportModel model = new ImportModel();

? ? ? model.setName(dto.getName());

? ? ? model.setNum(dto.getNum())

? ? ? importModelList.add(model);

? ? }

? ? importService.saveBatch(importModelList);

? }

}

```

?? ? ? ? 實(shí)際上,導(dǎo)入文件的內(nèi)容是需要校驗(yàn)的,數(shù)據(jù)格式校驗(yàn)等,需要詢問(wèn)產(chǎn)品是否忽略錯(cuò)誤的數(shù)據(jù),只導(dǎo)入正常的數(shù)據(jù),然后怎么友好提示錯(cuò)誤的內(nèi)容,通過(guò)返回一個(gè)包含錯(cuò)誤信息Excel或提示框,更進(jìn)一步的提示,則是提示到哪一個(gè)格子有問(wèn)題。

?? ? ? 睡覺(jué)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容