x 深夜,在東莞,7天酒店,打開電腦,訪問國內最大的同性交友網站。 日常開發中,導出導入場景非常多,尤其是對於後臺管理更是一個列表一個導出,如果從導出的業務中抽離出復用代碼,專註於邏輯開發,對於開發者而言非常重要。前有使用POI,但作者還是更喜EasyExcel的簡潔高效不拖沓,所以特意寫篇文章記錄 ...
x
深夜,在東莞,7天酒店,打開電腦,訪問國內最大的同性交友網站。
日常開發中,導出導入場景非常多,尤其是對於後臺管理更是一個列表一個導出,如果從導出的業務中抽離出復用代碼,專註於邏輯開發,對於開發者而言非常重要。前有使用POI,但作者還是更喜EasyExcel的簡潔高效不拖沓,所以特意寫篇文章記錄下。
準備工作
準備工作是看文檔瞭解EasyExcel嗎?不,我們直接上手吧!我發現最近的業務裡面,最簡單的例子已經應付下來了!所以準備工作自然只需導入EasyExcel的jar包,這裡我們由於是springboot項目,所以直接使用maven。直接上最新的版本了!pom.xml給它加上:
xxxxxxxxxx
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.5</version>
</dependency>
導出
準備工作已經完成,導出開始,首先需要一個Bean類,導出的欄位和Excel文件的欄位一樣即可。@Data是用了lombok,@ExcelProperty則包含了Excel首行的名稱和欄位所在位置,從0開始,不能重覆。
x
public class ExportVo {
value = "名稱", index = 0) (
private String name;
value = "時間", index = 1) (
private Date time;
"#.##%") (
value = "完成率", index = 2) (
private Float rate;
}
接下來是邏輯實現:
xxxxxxxxxx
"/export") (
public void export( ExportDto dto, HttpServletResponse response)
throws IOException {
String fileName = "統計表";
ExcelUtil.download(response, fileName, ExportVo.class,
getExportVoList());
}
private List getExportVoList() {
// 這裡主要是獲取List<ExportVo>內容,不提供實現了,需要說下註意點。
1、導出列表應該有時間之類的限制(例如最近一個月),避免導出Excel過大,過大Excel一般採用分sheet導出(尤其xls文件,有65535條數限制)、分文件打包導出,上傳文件伺服器非同步導出,不可突破的最大導出(限死5w條)。
2、一來考慮資料庫查詢和記憶體壓力,二來分頁插件可能存在最大頁數限制,所以較多條數時必須做分頁查詢,再組合List對象。
3、一般從資料庫直接查出數據不滿足導出欄位需要,有必要時需要做欄位轉換。
}
導出的處理類:
xxxxxxxxxx
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();
}
啟動程式,使用postman試下,直接點Send的話會返回一堆亂碼,選擇Send and Download則可導出Excel,不過文件名是URL編碼過的,這個文件名編碼問題在瀏覽器則不會存在。
導入
導入是為了減少人工錄入大量數據的煩惱,挺好的。
xxxxxxxxxx
private ImportService importService;
"/import") (
public void import(
value = "file") MultipartFile file, (
1) ("type") int type (
) throws IOException {
ImportQueryDto dto = new ImportQueryDto();
dto.setType(type);
// ImportDto是導入對應類,UploadDataListener是處理類,邏輯處理服務需要以參數形式傳入
EasyExcel.read(file.getInputStream(), ImportDto.class,
new UploadDataListener(importService)).sheet().doRead();
}
導入Excel對應類,ExcelProperty對應導入欄位的首部。
xxxxxxxxxx
public class ImportDto {
"名稱") (
private String name;
"數量") (
private Integer num;
}
導入處理:
xxxxxxxxxx
public class UploadDataListener
extends AnalysisEventListener<ImportDto> {
// 一次導入多少便入庫,避免大量入庫
private static final int BATCH_COUNT = 50;
// 存放導入列表
List<ImportDto> list = new ArrayList<>();
private ImportService importService;
public UploadDataListener(ImportService importService) {
this.importService = importService;
}
public void invoke(ImportDto importDto, AnalysisContext analysisContext) {
list.add(importDto);
if (list.size() >= BATCH_COUNT) {
saveData();
list.clear();
}
}
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);
}
}
實際上,導入文件的內容是需要校驗的,數據格式校驗等,需要詢問產品是否忽略錯誤的數據,只導入正常的數據,然後怎麼友好提示錯誤的內容,通過返回一個包含錯誤信息Excel或提示框,更進一步的提示,則是提示到哪一個格子有問題。
睡覺。