一、说明
最近公司开发一个财务使用的系统,报表比较多。 以前用过POI,JXL,也遇到过OOM问题, 所以学习一下阿里的Excel工具:https://github.com/alibaba/easyexcel
开发中主要用到:
① 简单数据导出,也就是查询实体导出(这里一般会自定义导出某些字段)
②自定义单元格样式,比如高亮显示"小计","总计"行等
③合并单元格
那就先来试试简单数据导出吧
二、pom引入
从官方文档上,目前版本2.2.0-beta1,那我们随便选一个2.X的版本,网上资料一般是1.1.1版本的,1.X和2.X版本个人感觉差别是有点大的~~
<!-- 阿里开源EXCEL -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<!-- <version>1.1.1</version>-->
<version>2.1.6</version>
</dependency>
三、准备工作
这里准备两个实体,一个是官方文档的实体 DemoData类(带注解),一个是自定义的User类
@Data
public class DemoData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/**
* 忽略这个字段
*/
@ExcelIgnore
private String ignore;
}
@Data
public class User {
private String uid;
private String name;
private Integer age;
private Date birthday;
}
准备模拟数据
/**
* 模拟实体数据
*
* @return
*/
private List<DemoData> getDemoDataList() {
List<DemoData> list = new ArrayList<DemoData>();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
data.setString("字符串" + i);
//data.setDate(new Date());
//设置属性一部分为空值
if (i % 2 == 0) {
data.setDoubleData(null);
} else {
data.setDate(new Date());
}
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
/**
* 模拟实体数据
*
* @return
*/
private List<User> getUserList() {
List<User> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUid("识别码" + i);
user.setAge(i * 10);
//设置属性一部分为空值
if (i % 2 == 0) {
user.setBirthday(new Date());
} else {
user.setBirthday(null);
}
user.setName("用户名" + i);
list.add(user);
}
return list;
}
I:\\temp\\writeDemo1.xlsx 和 I:\\temp\\writeDemo2.xlsx
设置表头和内容的策略,这个是官方文档复制过来的。
/**
* 获取策略,这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
*
* @return
*/
private HorizontalCellStyleStrategy getHorizontalCellStyleStrategy() {
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色
headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 10);
headWriteCellStyle.setWriteFont(headWriteFont);
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
//contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 背景绿色
//contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
//WriteFont contentWriteFont = new WriteFont();
// 字体大小
//contentWriteFont.setFontHeightInPoints((short)20);
//contentWriteCellStyle.setWriteFont(contentWriteFont);
// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
return horizontalCellStyleStrategy;
}
四、设置列宽
1.X的版本是通过生成sheet,使用sheet设置宽度,2.X版本后大部分方法已经过期,不推荐使用了,而大部分都是使用EasyExcel类直接构造并实现大部分功能;
根据官方文档的提示只需要注册写入处理器就可以了(WriteHandler),我这里直接复制一份过来修修改改~红色代码部分主要是关键部分
/**
* 自定义拦截器
*
* @author
*/
public class CustomSheetWriteHandler implements SheetWriteHandler {
//列宽集合
private List<Integer> columnWidths;
//构造
public CustomSheetWriteHandler(List<Integer> columnWidths) {
this.columnWidths = columnWidths;
}
private static final Logger LOGGER = LoggerFactory.getLogger(CustomSheetWriteHandler.class);
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
LOGGER.info("第{}个Sheet写入成功。", writeSheetHolder.getSheetNo());
// 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行
/* CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 2, 0, 0);
DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper();
DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"测试1", "测试2"});
DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
writeSheetHolder.getSheet().addValidationData(dataValidation);*/
LOGGER.info("普通策略设置setColumnWidth开始~");
if(CollectionUtils.isNotEmpty(columnWidths)){
for (int i = 0; i < columnWidths.size(); i++) {
writeSheetHolder.getSheet().setColumnWidth(i, columnWidths.get(i));
}
}
LOGGER.info("普通策略设置setColumnWidth结束~");
}
}
五、根据注解导出数据到Excel文件中
/**
* 写入到固定文件中
*
* @throws IOException
*/
@Test
public void writeToExcelFile() {
//写入的文excel文件
String fileName = "I:\\temp\\writeDemo1.xlsx";
//获取头和内容的策略
HorizontalCellStyleStrategy horizontalCellStyleStrategy = getHorizontalCellStyleStrategy();
//列宽的策略,宽度是小单位
Integer columnWidthArr[] = {3000, 6000};
List<Integer> columnWidths = Arrays.asList(columnWidthArr);
CustomSheetWriteHandler customSheetWriteHandler = new CustomSheetWriteHandler(columnWidths);
// 根据用户传入字段 假设我们只要导出 string date
String[] filds = {"string", "date"};
//获取模拟的实体数据集合
List<DemoData> demoDataList = getDemoDataList();
//这里需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class)
.registerWriteHandler(horizontalCellStyleStrategy)
.registerWriteHandler(customSheetWriteHandler)
//这个是导出需要展示的列
.includeColumnFiledNames(Arrays.asList(filds))
.sheet("模板")
.doWrite(demoDataList);
}
效果:
六、自定义导出列数据到Excel文件中
/**
* 写入到固定文件中,这里不使用注解的方式写入列和对应的属性
*
* @throws IOException
*/
@Test
public void writeToExcelFile2() {
//写入的文excel文件
String fileName = "I:\\temp\\writeDemo2.xlsx";
//获取头和内容的策略
HorizontalCellStyleStrategy horizontalCellStyleStrategy = getHorizontalCellStyleStrategy();
//列宽的策略,宽度是小单位
Integer columnWidthArr[] = {3000, 3000, 2000, 6000};
List<Integer> columnWidths = Arrays.asList(columnWidthArr);
CustomSheetWriteHandler customSheetWriteHandler = new CustomSheetWriteHandler(columnWidths);
// 根据用户传入字段 假设我们只要导出 string date
String[] filds = {"uid", "name", "age", "birthday"};
String[] headers = {"唯一识别码", "姓名", "年龄", "生日"};
List head = getHeadByFilds(headers);
//获取模拟的实体数据集合
List<User> userList = getUserList();
//这里指定头的名字去写入,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName)
.head(head)
.registerWriteHandler(horizontalCellStyleStrategy)
.registerWriteHandler(customSheetWriteHandler)
.includeColumnFiledNames(Arrays.asList(filds))
.sheet("模板")
.doWrite(userList);
}
效果:
六、总结
后面继续实现合并单元格、自定义单元格、web导出和导入等功能~