荐 EasyPoi导入导出Excel最全案例
程序员文章站
2022-07-10 21:24:30
现在有这样一个需求:1) 批量导入用户,需要校验用户的信息2) 如果有错误的数据支持导出,有错误信息的单元格用特殊颜色标出,并将错误信息设置在单元格批注里针对以上需求,笔者对EasyPoi进行了封装,下面将依次介绍1 导入EasyPoi支持hibernate-validator注解式校验,如下图如果要获取校验没通过的错误信息及行号需要实现IExcelDataModel和IExcelModel接口。这些都是基本校验,在实际开发过程中可能会遇到需要写代码来校验,比如校验用户名是否重复,EasyPo...
假设现在有这样一个需求:
1) 批量导入用户,需要校验用户的信息
2) 如果有错误的数据支持导出,有错误信息的单元格用特殊颜色标出,并将错误信息设置在单元格批注里
针对以上需求,笔者对EasyPoi进行了封装,下面将依次介绍
1 导入
excel导入数据如下图
EasyPoi支持hibernate-validator注解式校验,如下图
如果要获取校验没通过的错误信息及行号需要实现IExcelDataModel和IExcelModel接口。这些都是基本校验,在实际开发过程中可能会遇到需要写代码来校验,比如校验用户名是否重复,EasyPoi给出了校验处理器,可以实现自定义校验。
@Component
public class UserImportVerifyHandler implements IExcelVerifyHandler<UserExcel> {
@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<T> {
@Resource
private TransactionalHelper transactionalHelper;
/**
* 导入excel
* @param file 文件
* @param pojoClass excel模板类
* @param params excel导入参数
*/
public void importExcel(MultipartFile file, Class<?> pojoClass, ImportParams params) {
ExcelImportResult<T> 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<T> result, int titleRows, int titleCells) {
Row row = result.getWorkbook().getSheetAt(0).getRow(titleRows);
if (row.getLastCellNum() < titleCells) {
//此处抛异常
}
for (int i=0; i<row.getLastCellNum(); i++) {
Cell cell = row.getCell(i);
if (cell == null || StringUtils.isBlank(cell.getStringCellValue())) {
//此处抛异常
}
}
}
//该抽象方法主要是为了找出excel中重复的数据,重复的数据放在failList里
protected abstract void findDuplicate(List<T> importBos, List<T> failList);
//该抽象方法保存解析出来的数据
protected abstract void saveData(ExcelImportResult<T> result);
}
代码中简化了很多东西,读者可以自己去细化。代码中用了一个TransactionalHelper,参见解决事务失效的工具类
2 导出
导出采用模板方式导出,实体类还是用上文中的UserExcel。导出只介绍封装的抽象类
public abstract class AbstractExportService<T> {
/**
* 导出excel
* @param dataList 需要导出的数据,继承该抽象类后自行获取
* @param templateUrl 模板路径
* @param fileName 文件名
* @param startRows 存放实际数据的开始行,添加批注时需要传该值
* @param hasComment 是否有批注
*/
protected void exportExcel(List<T> dataList, String templateUrl, String fileName, int startRows, boolean hasComment) {
Map<String, Object> 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<T> 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<Integer, String> commentMap = this.getCommentMap(commentStr);
for (Map.Entry<Integer, String> 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<Integer, String> getCommentMap(String commentStr) {
//每行的所有单元格的批注都在commentStr里,并用”,”分隔
String[] split = commentStr.split(",");
Map<Integer, String> 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
推荐阅读
-
建议收藏:.net core 使用EPPlus导入导出Excel详细案例,精心整理源码已更新至开源模板
-
【springboot+easypoi】一行代码搞定excel导入导出
-
荐 EasyPoi导入导出Excel最全案例
-
有史以来功能最全,使用最简单的excel导入/导出工具
-
Easypoi实现excel多sheet表导入导出功能
-
使用easypoi 将数据库数据导出 以及将Excel表格数据导入数据库 第五版
-
Springboot2整合easypoi实现导入导出、OSS图片导出到Excel
-
建议收藏:.net core 使用EPPlus导入导出Excel详细案例,精心整理源码已更新至开源模板
-
【easypoi】 实现excel导入导出(多sheet)
-
荐 EasyPoi实现动态模板导入导出