目录
依赖:
ExcelReader(Excel读取):
1.从文件中读取Excel为ExcelReader
2.从流中读取Excel为ExcelReader
3.读取指定的sheet
4.读取Excel中所有行和列,都用列表表示
5.读取为Map列表,默认第一行为标题行,Map中的key为标题,value为标题对应的单元格值
6.读取为Bean列表,Bean中的字段名为标题,字段值为标题对应的单元格值
ExcelWriter(Excel写入):
(1)将List写入到Excel
(2)Map数据写入到Excel
(3)Bean数据写入到Excel
(4)常用方法
1.标题别名
addHeaderAlias示例:
setHeaderAlias示例:
2.增加下拉列表
3.增加单元格控制(如下拉列表、日期验证、数字范围验证等)
4.设置自动宽度
5.样式
6.关闭
工具类:
自适应列宽工具类
ExcelUtil 是一种处理 Excel 表格的工具库,可以很方便的进行表格的读取、写入、处理等操作。
cn.hutool
hutool-all
5.4.5
ExcelReader reader = ExcelUtil.getReader(FileUtil.file("1.xlsx"));
ExcelReader reader = ExcelUtil.getReader(ResourceUtil.getStream("1.xlsx"));
ExcelReader reader;
//通过sheet编号获取
reader = ExcelUtil.getReader(FileUtil.file("1.xlsx"), 0);
//通过sheet名获取
reader = ExcelUtil.getReader(FileUtil.file("1.xlsx"), "sheet1");
ExcelReader reader = ExcelUtil.getReader("d:/1.xlsx");
List> readAll = reader.read();
ExcelReader reader = ExcelUtil.getReader("d:/1.xlsx");
List
ExcelReader reader = ExcelUtil.getReader("d:/aaa.xlsx");
List all = reader.readAll(Person.class);
Hutool将Excel写出封装为ExcelWriter,原理为包装了Workbook对象,每次调用merge(合并单元格)或者write(写出数据)方法后只是将数据写入到Workbook,并不写出文件,只有调用flush或者close方法后才会真正写出文件。
由于机制原因,在写出结束后需要关闭ExcelWriter对象,调用close方法即可关闭,此时才会释放Workbook对象资源,否则带有数据的Workbook一直会常驻内存
List row1 = List.of("aa", "bb", "cc", "dd");
List row2 = List.of("aa1", "bb1", "cc1", "dd1");
List row3 = List.of("aa2", "bb2", "cc2", "dd2");
List row4 = List.of("aa3", "bb3", "cc3", "dd3");
List row5 = List.of("aa4", "bb4", "cc4", "dd4");
List> rows = List.of(row1, row2, row3, row4, row5);
//通过工具类创建writer
ExcelWriter writer = ExcelUtil.getWriter("d:/1.xlsx");
//一次性写出内容,强制输出标题
writer.write(rows, true);
//关闭writer,释放内存
writer.close();
Map row1 = new LinkedHashMap<>(){{
put("姓名", "张三");
put("年龄", 23);
put("成绩", 88.32);
put("是否合格", true);
put("考试日期", DateUtil.date());
}};
Map row2 = new LinkedHashMap<>(){{
put("姓名", "李四");
put("年龄", 22);
put("成绩", 80.32);
put("是否合格", true);
put("考试日期", DateUtil.date());
}};
List
@Data
public class TestBean {
private String name;
private int age;
private double score;
private boolean isPass;
private Date examDate;
public static void main(String[] args) {
TestBean bean1 = new TestBean();
bean1.setName("张三");
bean1.setAge(22);
bean1.setPass(true);
bean1.setScore(66.30);
bean1.setExamDate(DateUtil.date());
TestBean bean2 = new TestBean();
bean2.setName("李四");
bean2.setAge(28);
bean2.setPass(false);
bean2.setScore(38.50);
bean2.setExamDate(DateUtil.date());
List rows = CollUtil.newArrayList(bean1, bean2);
// 通过工具类创建writer
ExcelWriter writer = ExcelUtil.getWriter("d:/1.xlsx");
// 合并单元格后的标题行,使用默认标题样式
writer.merge(4, "成绩单");
// 一次性写出内容,使用默认样式,强制输出标题
writer.write(rows, true);
// 关闭writer,释放内存
writer.close();
}
}
自定义标题别名时,如果数据中有6个字段,而你只想导出四个字段并设置别名时,需要设置writer.setOnlyAlias(true)。如果不设置setOnlyAlias,则导出的excel中可能会多出几列你不需要的数据。
方法名称 | 参数 | 返回 | 作用 |
addHeaderAlias(String name, String alias) |
name:字段名称 alias:Excel展示的标题别名 |
this |
|
setHeaderAlias(Map |
headerAlias:别名字典 |
this | |
clearHeaderAlias() | this | 清空标题别名,key为Map中的key,value为别名 |
Map row1 = new LinkedHashMap<>(){{
put("name", "张三");
put("age", 23);
put("score", 88.32);
put("isPass", true);
put("examDate", DateUtil.date());
}};
Map row2 = new LinkedHashMap<>(){{
put("name", "李四");
put("age", 22);
put("score", 80.32);
put("isPass", true);
put("examDate", DateUtil.date());
}};
List
Map row1 = new LinkedHashMap<>(){{
put("name", "张三");
put("age", 23);
put("score", 88.32);
put("isPass", true);
put("examDate", DateUtil.date());
}};
Map row2 = new LinkedHashMap<>(){{
put("name", "李四");
put("age", 22);
put("score", 80.32);
put("isPass", true);
put("examDate", DateUtil.date());
}};
List
方法名称 | 参数 | 返回 | 作用 | 备注 |
addSelect(CellRangeAddressList regions,String... selectList) | regions:指定下拉列表所占的单元格范围
|
this | 增加下拉列表 | 从以下版本开始: 4.6.2 |
addSelect(int x, int y, String... selectList) | x: x坐标,列号,从0开始 y: y坐标,行号,从0开始 selectList :下拉列表 |
this | 增加下拉列表 | 从以下版本开始: 4.6.2 |
方法名称 | 参数 | 返回 | 作用 | 备注 |
addValidationData(DataValidation dataValidation) | dataValidation:DataValidation |
this | 增加单元格控制,比如下拉列表、日期验证、数字范围验证等 |
从以下版本开始: 4.6.2 |
方法名称 | 参数 | 返回 | 作用 | 备注 |
autoSizeColumn(int columnIndex) | columnIndex: 第几列,从0计数 | this | 设置某列为自动宽度,此方法必须在指定列数据完全写出后调用才有效。 |
从以下版本开始: 4.0.12 |
autoSizeColumn(int columnIndex, boolean useMergedCells) | columnIndex: 第几列,从0计数 useMergedCells: 是否适用于合并单元格 |
this | 设置某列为自动宽度,此方法必须在指定列数据完全写出后调用才有效。 |
从以下版本开始: 3.3.0 |
autoSizeColumnAll() | this | 设置某列为自动宽度,不考虑合并单元格。此方法必须在指定列数据完全写出后调用才有效。 |
方法名称 | 参数 | 返回 | 作用 | 备注 |
disableDefaultStyle() | this | 禁用默认样式 | ||
setStyleSet(StyleSet styleSet) | styleSet:样式集,null表示无样式 | this | 设置样式集,如果不使用样式,传入null |
|
getStyleSet() | StyleSet样式集 | 获取样式集,样式集可以自定义包括: 1. 头部样式 2. 一般单元格样式 3. 默认数字样式 4. 默认日期样式 |
||
getCellStyle() | CellStyle | 获取单元格样式,获取样式后可自定义样式 | ||
getHeadCellStyle() | CellStyle | |||
createFont() | Font | 创建字体 | ||
setColumnStyle(int x,CellStyle style) | x: 列号,从0开始 style: 样式 |
this | 设置列的默认样式 | 这个方法加的样式会使整列没有数据的单元格也有样式 特别是加背景色时很不美观 且有数据的单元格样式会被StyleSet中的样式覆盖掉。从以下版本开始: 5.6.4 |
setColumnStyleIfHasData(int x, int y, CellStyle style) | this | 设置整个列的样式 仅对数据单元格设置 write后调用 | ||
setRowStyle(int y,CellStyle style) | y:Y坐标,从0计数,即行号 style:样式 |
this | 设置行样式 | |
setStyle(CellStyle style,String locationRef) | style:单元格样式 locationRef:单元格地址标识符,例如A11,B5 |
this | 设置某个单元格的样式, 此方法用于多个单元格共享样式的情况 | 需要注意的是,共享样式会共享同一个CellStyle,一个单元格样式改变,全部改变。 |
setStyle(CellStyle style, int x, int y) | style:单元格样式 x:X坐标,从0计数,即列号 y:Y坐标,从0计数,即行号 |
this | 设置某个单元格的样式, 此方法用于多个单元格共享样式的情况 | 需要注意的是,共享样式会共享同一个CellStyle,一个单元格样式改变,全部改变。 |
setColumnWidth(int columnIndex, int width) | columnIndex: 列号(从0开始计数,-1表示所有列的默认宽度) width: 宽度(单位1~256个字符宽度) |
this | 设置列宽(单位为一个字符的宽度,例如传入width为10,表示10个字符的宽度) | |
setDefaultRowHeight(int height) | height: 高度 |
this | 设置默认行高,值为一个点的高度 |
|
setRowHeight(int rownum, int height) | rownum : 行号(从0开始计数,-1表示所有行的默认高度) height: 高度 |
this | 设置行高,值为一个点的高度 |
方法名称 | 参数 | 返回 | 作用 | 备注 |
close() | void | 关闭工作簿, 如果用户设定了目标文件,先写出目标文件后给关闭工作簿 | ||
closeWithoutFlush() | void | 关闭工作簿但是不写出 |
public class ExcelAdaptiveWidthUtils {
/**
* 自适应宽度(中文支持)
*
* @param sheet sheet
* @param size 因为for循环从0开始,size值为 列数-1
*/
public static void setSizeColumn(Sheet sheet, int size) {
for (int columnNum = 0; columnNum <= size; columnNum++) {
int columnWidth = sheet.getColumnWidth(columnNum) / 256;
for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
Row currentRow;
//当前行未被使用过
if (sheet.getRow(rowNum) == null) {
currentRow = sheet.createRow(rowNum);
} else {
currentRow = sheet.getRow(rowNum);
}
if (currentRow.getCell(columnNum) != null) {
Cell currentCell = currentRow.getCell(columnNum);
if (currentCell.getCellType() == CellType.STRING) {
int length = currentCell.getStringCellValue().getBytes().length;
if (columnWidth < length) {
columnWidth = length;
}
}
}
}
sheet.setColumnWidth(columnNum, columnWidth * 256);
}
}
}