天天看點

easypoi導出excel 效率_薦 EasyPoi導入導出Excel最全案例...

假設現在有這樣一個需求:

1) 批量導入使用者,需要校驗使用者的資訊

2) 如果有錯誤的資料支援導出,有錯誤資訊的單元格用特殊顔色标出,并将錯誤資訊設定在單元格批注裡

針對以上需求,筆者對EasyPoi進行了封裝,下面将依次介紹

1 導入

excel導入資料如下圖

easypoi導出excel 效率_薦 EasyPoi導入導出Excel最全案例...

EasyPoi支援hibernate-validator注解式校驗,如下圖

easypoi導出excel 效率_薦 EasyPoi導入導出Excel最全案例...

如果要擷取校驗沒通過的錯誤資訊及行号需要實作IExcelDataModel和IExcelModel接口。這些都是基本校驗,在實際開發過程中可能會遇到需要寫代碼來校驗,比如校驗使用者名是否重複,EasyPoi給出了校驗處理器,可以實作自定義校驗。

@Component

public class UserImportVerifyHandler implements IExcelVerifyHandler {

@Resource

private UserMapper userMapper;

@Override

public ExcelVerifyHandlerResult verifyHandler(UserExcel excelBo) {

StringJoiner joiner = new StringJoiner(",");

UserInfo userInfo = userMapper.findByName(excelBo.getUserName());

if (userInfo != null) {

joiner.add("使用者名不允許重複#0");

}

return new ExcelVerifyHandlerResult(false, joiner.toString());

}

}

以上校驗需要在導入參數裡開啟

public void importUser(MultipartFile file) {

//導入參數

ImportParams params = new ImportParams();

//開啟校驗

params.setNeedVerify(true);

//校驗處理器

params.setVerifyHandler(verifyHandler);

//調用模闆方法導入excel

this.importExcel(file, UserExcel.class, params);

}

在上面的校驗資訊裡面加了字尾,比如使用者名不允許重複#0,這裡面的#0是用來辨別錯誤資訊所在的列,0就表示列,#是友善将0截取出來,在導出的時候會用到。讀者可以采用其它的方式,比如将錯誤資訊與列做個映射。一整行的錯誤資訊都會存到errorMsg這個字段裡,并用“,”分隔。

下面看下封裝的抽象類

public abstract class AbstractImportService {

@Resource

private TransactionalHelper transactionalHelper;

public void importExcel(MultipartFile file, Class> pojoClass, ImportParams params) {

ExcelImportResult result = null;

try {

//調用EasyPoi的導入接口

result = ExcelImportUtil.importExcelMore(file.getInputStream(), pojoClass, params);

} catch (Exception e) {

//此處抛異常

}

if (result != null) {

this.checkTitleCell(result, params.getTitleRows(), reqDto.getTitleCells());

if (!CollectionUtils.isEmpty(result.getList())) {

this.findDuplicate(result.getList(), result.getFailList());

}

//開啟事務儲存資料,這種用法主要是為了解決事務失效的問題,見下面描述

transactionalHelper.apply(this::saveData, result);

}

}

//校驗标題格式是否正确

private void checkTitleCell(ExcelImportResult result, int titleRows, int titleCells) {

Row row = result.getWorkbook().getSheetAt(0).getRow(titleRows);

if (row.getLastCellNum() < titleCells) {

//此處抛異常

}

for (int i=0; i

Cell cell = row.getCell(i);

if (cell == null || StringUtils.isBlank(cell.getStringCellValue())) {

//此處抛異常

}

}

}

//該抽象方法主要是為了找出excel中重複的資料,重複的資料放在failList裡

protected abstract void findDuplicate(List importBos, List failList);

//該抽象方法儲存解析出來的資料

protected abstract void saveData(ExcelImportResult result);

}

代碼中簡化了很多東西,讀者可以自己去細化。代碼中用了一個TransactionalHelper,參見解決事務失效的工具類

2 導出

導出采用模闆方式導出,實體類還是用上文中的UserExcel。導出隻介紹封裝的抽象類

public abstract class AbstractExportService {

protected void exportExcel(List dataList, String templateUrl, String fileName, int startRows, boolean hasComment) {

Map resMap = new HashMap<>();

resMap.put("mapList", dataList);

try {

ClassPathResource classPathResource = new ClassPathResource(

templateUrl);

TemplateExportParams params = new TemplateExportParams(

classPathResource.getPath(), true);

Workbook workbook = ExcelExportUtil.exportExcel(params,resMap);

this.buildComment(dataList, workbook, startRows, hasComment);

//将workbook寫入到response裡,讀者自行實作

}catch (Exception e){

//此處抛異常

}

}

private void buildComment(List dataList, Workbook workbook, int startRows, boolean hasComment) {

if (!hasComment) return;

Sheet sheet = workbook.getSheetAt(0);

//建立一個圖畫工具

Drawing> drawing = sheet.createDrawingPatriarch();

for (T fail : dataList) {

Row row = sheet.getRow(startRows);

//擷取批注資訊

String commentStr = this.getCommentStr(fail);

if (StringUtils.isNotBlank(commentStr)) {

//解析批注,并傳換成map

Map commentMap = this.getCommentMap(commentStr);

for (Map.Entry entry : commentMap.entrySet()) {

Cell cell = row.getCell(entry.getKey());

//建立批注

Comment comment = drawing.createCellComment(this.newClientAnchor(workbook));

//輸入批注資訊

comment.setString(this.newRichTextString(workbook, entry.getValue()));

//将批注添加到單元格對象中

cell.setCellComment(comment);

//設定單元格背景顔色

CellStyle cellStyle = workbook.createCellStyle();

//設定顔色

cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());

//設定實心填充

cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

cell.setCellStyle(cellStyle);

}

}

startRows++;

}

}

protected Map getCommentMap(String commentStr) {

//每行的所有單元格的批注都在commentStr裡,并用”,”分隔

String[] split = commentStr.split(",");

Map commentMap = new HashMap<>();

for (String msg : split) {

String[] cellMsg = msg.split("#");

//如果目前列沒有批注,會将該列的索引作為key存到map裡;已有批注,以“,“分隔繼續拼接

int cellIndex = Integer.parseInt(cellMsg[1]);

if (commentMap.get(cellIndex) == null) {

commentMap.put(cellIndex, cellMsg[0]);

} else {

commentMap.replace(cellIndex, commentMap.get(cellIndex) + "," + cellMsg[0]);

}

}

return commentMap;

}

private ClientAnchor newClientAnchor(Workbook workbook) {

//xls

if (workbook instanceof HSSFWorkbook) {

return new HSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);

}

//xlsx

else {

return new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);

}

}

private RichTextString newRichTextString(Workbook workbook, String msg) {

//xls

if (workbook instanceof HSSFWorkbook) {

return new HSSFRichTextString(msg);

}

//xlsx

else {

return new XSSFRichTextString(msg);

}

}

protected abstract String getCommentStr(T data);

導出模闆如下圖

easypoi導出excel 效率_薦 EasyPoi導入導出Excel最全案例...

excel中

$fe:表示循環插入

mapList是傳入map的key

本文位址:https://blog.csdn.net/weixin_45497155/article/details/107341472

如您對本文有疑問或者有任何想說的,請點選進行留言回複,萬千網友為您解惑!