1. EasyPoi注解基础入门
EasyPoi是一款基于Apache POI封装的Java Excel操作工具,它通过注解的方式简化了Excel导入导出的开发流程。与原生POI相比,EasyPoi最大的特点就是"约定优于配置"的设计理念,开发者只需在实体类上添加注解,就能自动完成复杂的Excel读写操作。
1.1 核心注解 @Excel 详解
@Excel是EasyPoi最基础的注解,用于标记需要与Excel列映射的字段。让我们通过一个用户实体类来理解它的核心属性:
java复制@Data
public class User {
@Excel(name = "用户ID", orderNum = "0", width = 15)
private Long id;
@Excel(name = "用户名", orderNum = "1", width = 20,
replace = {"匿名用户_null", "测试用户_test"})
private String username;
@Excel(name = "注册时间", orderNum = "2", width = 20,
format = "yyyy-MM-dd HH:mm:ss")
private Date registerTime;
@Excel(name = "手机号", orderNum = "3", width = 15,
desensitizationRule = "3_4")
private String phone;
}
关键属性解析:
- name:指定Excel中的列标题
- orderNum:控制列的顺序(从0开始)
- width:设置列宽(单位是字符)
- format:日期类型格式化(支持SimpleDateFormat格式)
- replace:值替换规则(格式:"替换值_原值")
- desensitizationRule:数据脱敏规则("3_4"表示保留前3后4位)
实际开发中,width设置建议比预计内容多2-3个字符,避免内容显示不全
1.2 基础导入导出实现
导出Excel示例
java复制@GetMapping("/export")
public void exportUsers(HttpServletResponse response) {
List<User> userList = userService.list();
ExportParams params = new ExportParams("用户列表", "用户数据");
Workbook workbook = ExcelExportUtil.exportExcel(params, User.class, userList);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename=users.xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
导入Excel示例
java复制@PostMapping("/import")
public Result importUsers(@RequestParam("file") MultipartFile file) {
ImportParams params = new ImportParams();
params.setTitleRows(1); // 标题行数
params.setHeadRows(1); // 表头行数
List<User> userList = ExcelImportUtil.importExcel(
file.getInputStream(),
User.class,
params
);
userService.saveBatch(userList);
return Result.success(userList.size());
}
2. 高级注解应用场景
2.1 复杂对象处理 @ExcelEntity
当需要处理嵌套对象时,可以使用@ExcelEntity注解。例如订单中包含用户信息:
java复制@Data
public class Order {
@Excel(name = "订单ID")
private String orderId;
@Excel(name = "订单金额")
private BigDecimal amount;
@ExcelEntity
private User user;
}
对应的Excel结构:
code复制订单ID | 订单金额 | 用户ID | 用户名 | 注册时间 | 手机号
-----|-------|-----|-----|------|-----
1001 | 299.00 | 1 | 张三 | 2023-01-01 | 138****1234
注意:被@ExcelEntity标记的对象内部字段也需要有@Excel注解
2.2 集合类型处理 @ExcelCollection
处理一对多关系时,使用@ExcelCollection注解。例如订单包含多个商品:
java复制@Data
public class Order {
@Excel(name = "订单ID")
private String orderId;
@ExcelCollection(name = "商品列表")
private List<Product> products;
}
@Data
public class Product {
@Excel(name = "商品名称")
private String name;
@Excel(name = "商品价格")
private BigDecimal price;
}
导出的Excel会生成多级表头:
code复制订单ID | 商品列表.商品名称 | 商品列表.商品价格
-----|------------|------------
1001 | iPhone 13 | 5999.00
| AirPods Pro | 1499.00
2.3 图片处理 @ExcelImage
EasyPoi支持直接在Excel中嵌入图片:
java复制@Data
public class Product {
@Excel(name = "商品ID")
private Long id;
@ExcelImage(name = "商品图片",
imageType = ExcelImage.ImageType.JPEG,
width = 20, height = 20)
private byte[] image;
}
图片处理注意事项:
- 图片数据需要转换为byte数组
- width/height单位是Excel的行高/列宽单位
- 建议图片大小不超过100KB,避免Excel文件过大
3. 高级功能与自定义处理
3.1 动态列处理
通过实现IExcelDataHandler接口,可以实现动态列处理:
java复制public class UserDataHandler implements IExcelDataHandler<User> {
@Override
public Object exportHandler(User obj, String name, Object value) {
if("phone".equals(name) && value != null) {
return value.toString().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
}
return value;
}
@Override
public Object importHandler(User obj, String name, Object value) {
return value;
}
}
使用方式:
java复制ExportParams params = new ExportParams();
params.setDataHandler(new UserDataHandler());
3.2 自定义样式处理器
继承ExcelExportStylerDefaultImpl实现自定义样式:
java复制public class CustomExcelStyle extends ExcelExportStylerDefaultImpl {
public CustomExcelStyle(Workbook workbook) {
super(workbook);
}
@Override
public CellStyle getTitleStyle(short color) {
CellStyle style = super.getTitleStyle(color);
style.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
return style;
}
}
应用自定义样式:
java复制ExportParams params = new ExportParams();
params.setStyle(CustomExcelStyle.class);
4. 实战问题排查指南
4.1 常见报错与解决方案
-
@Excel注解不生效
- 检查是否使用了@Data或提供了getter方法
- 确认字段不是static或final修饰
- 检查导入导出时传入的Class对象是否正确
-
日期格式处理异常
- 确保format格式与数据实际格式一致
- 时区问题建议在format中加入时区信息,如:"yyyy-MM-dd HH:mm:ss Z"
-
大数据量导出内存溢出
- 使用SXSSFWorkbook模式:
java复制ExportParams params = new ExportParams(); params.setType(ExcelType.XSSF); params.setStyle(ExcelStyle.XSSF);
- 使用SXSSFWorkbook模式:
-
复杂模板导入失败
- 使用模板导出再导入确保格式一致
- 设置setNeedVerfiy(true)开启校验模式
4.2 性能优化建议
-
批量导入数据时:
java复制ImportParams params = new ImportParams(); params.setReadRows(500); // 分批读取 params.setNeedVerfiy(true); // 开启校验 -
导出大量数据时:
java复制ExportParams params = new ExportParams(); params.setMaxNum(10000); // 单Sheet最大行数 params.setSheetName("数据_"); // 自动分Sheet -
缓存样式对象:
java复制// 在自定义样式中添加缓存 private Map<String, CellStyle> styleCache = new ConcurrentHashMap<>();
4.3 最佳实践总结
-
实体类设计原则:
- 保持字段与业务需求一致
- 避免过度使用嵌套关系
- 敏感字段一定要加脱敏处理
-
生产环境建议:
- 添加操作日志记录
- 实现断点续传功能
- 对大文件采用分片处理
-
扩展性考虑:
- 封装统一的导入导出组件
- 提供模板下载接口
- 支持多种数据源导出
在实际项目中,我们通过EasyPoi将原本需要2-3天开发的报表功能缩短到2-3小时。特别是在处理复杂中国式报表时,配合自定义注解和处理器,可以轻松实现多级表头、动态列、单元格合并等复杂需求。
