easypoi导出excel 效率_荐 EasyPoi导入导出Excel最全案例...

假设现在有这样一个需求:

1) 批量导入用户,需要校验用户的信息

2) 如果有错误的数据支持导出,有错误信息的单元格用特殊颜色标出,并将错误信息设置在单元格批注里

针对以上需求,笔者对EasyPoi进行了封装,下面将依次介绍

1 导入

excel导入数据如下图

EasyPoi支持hibernate-validator注解式校验,如下图

如果要获取校验没通过的错误信息及行号需要实现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;

/**

* 导入excel

* @param file 文件

* @param pojoClass excel模板类

* @param params excel导入参数

*/

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 {

/**

* 导出excel

* @param dataList 需要导出的数据,继承该抽象类后自行获取

* @param templateUrl 模板路径

* @param fileName 文件名

* @param startRows 存放实际数据的开始行,添加批注时需要传该值

* @param hasComment 是否有批注

*/

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++;

}

}

/**

* 批注信息,默认解析:批注#列索引,比如用户名不允许重复#0。可覆盖此方法,解析自定义的批注格式

* @param commentStr 当前行的所有批注信息

* @return key:列索引,value:对应列的所有批注信息

*/

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);

}

}

/**

* 获取批注信息

* @param data

* @return

*/

protected abstract String getCommentStr(T data);

导出模板如下图

excel中

$fe:表示循环插入

mapList是传入map的key

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值