使用Easyexcel實現(xiàn)不同場景的數(shù)據(jù)導出功能
導出的數(shù)據(jù)包含有圖片
導出excel表格的數(shù)據(jù)包含有圖片,這種場景比較少。通Easyexcel實現(xiàn)這樣的需求,我認為最簡便的方法就是使用前面提到的自定義轉(zhuǎn)換器(com.alibaba.excel.converters.Converter);假如有這樣一個場景,導出員工的信息,還要包括員工的一寸照。通常情況下,數(shù)據(jù)庫并不會真的存一張圖片,而是圖片存儲位置的相對路徑。
1、新建一個類EmpHeadPhotoConverter,實現(xiàn)com.alibaba.excel.converters.Converter接口,并重寫convertToExcelData()方法;
2、在重寫convertToExcelData()方法中,根據(jù)圖片的相同路徑或網(wǎng)絡地址讀取出圖片的字節(jié)流作為構建WriteCellData對象的參數(shù)然后返回;
3、在員工信息的實體類Employee的照片列引入自定義的類型轉(zhuǎn)換器(EmpHeadPhotoConverter)
4、使用EasyExcel的工廠方法把數(shù)據(jù)寫出到excel表格中;
注:這里是使用默認的樣式,所以看起來可能點丑;@ContentRowHeight()用于調(diào)節(jié)數(shù)據(jù)行的高度;@ColumnWidth用于調(diào)節(jié)數(shù)據(jù)列的寬度;
public class EmpHeadPhotoConverter implements Converter<String> {
@Override
public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
//根據(jù)圖片的相對路徑或網(wǎng)絡地址讀取圖片到byte輸出流(ByteArrayOutputStream)
ByteArrayOutputStream byteArrayOutputStream = null;
InputStream inputStream=null;
try {
inputStream = ClassLoader.getSystemResourceAsStream(value);
byteArrayOutputStream = new ByteArrayOutputStream();
int len=-1;
byte[] bytes = new byte[1024];
while ((len=inputStream.read(bytes))!=-1){
byteArrayOutputStream.write(bytes);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (byteArrayOutputStream != null) {
byteArrayOutputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}
//把輸出流中的圖片字節(jié)數(shù)組作為參數(shù)構建writeCellData對象并返回
//WriteCellData是EasyExcel對單元格數(shù)據(jù)的封裝
return new WriteCellData<>(byteArrayOutputStream.toByteArray());
}
}
@Data
@ContentRowHeight(50)//數(shù)據(jù)行的高度
public class Employee implements Serializable {
@ExcelProperty("姓名")
private String realName;
@ExcelProperty("員工編號")
private String empNo;
@ExcelProperty("性別")
private String sex;
@ExcelProperty("家庭地址")
private String address;
@ExcelProperty("聯(lián)系電話")
private String phone;
@ExcelProperty("電子郵箱")
private String email;
@ExcelProperty(value = "照片",converter = EmpHeadPhotoConverter.class)
@ColumnWidth(10)//列寬
private String headPhoto;
}
@Test
public void writeImage(){
String exportPath=this.getExportPath();
String exportFile=exportPath+File.separator+"員工基本信息(包含照片).xlsx";
List<Employee> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Employee employee = new Employee();
employee.setRealName("張三"+i);
employee.setEmpNo("CH"+(i+1));
employee.setAddress("北京");
employee.setEmpNo("zhangsan@163.com");
employee.setSex("女");
employee.setPhone("17777xxxxxx");
//這里是示例,因為我把示例圖片放在了classpath下,后面可以根據(jù)圖片名字在classpath下找到
//在實際的業(yè)務開發(fā)過程中,這里應該是圖片的相對路徑或網(wǎng)絡地址
employee.setHeadPhoto("zhangsan.jpeg");
list.add(employee);
}
EasyExcel.write(exportFile,Employee.class).sheet().doWrite(list);
}

導出表格指定列寬行高
上面其實是已經(jīng)說過了,通過注解可以簡單的指定導出Excel表格的行、列的高度和寬度:
@ContentRowHeight()用于指定數(shù)據(jù)行的高度;
@HeadRowHeight()用于指定表頭行的高度;
@ColumnWidth()用于指定數(shù)據(jù)列的寬度;
導出表格自定義樣式
我比較喜歡使用easyexcel的一個很重要的原因就是,easyexcel在poi的基礎上,封裝的比較友好。就比如,在導出的時候,很多情況下需要自定義表格的樣式,easyexcel就提供了多種的實現(xiàn)方式。主要有三種:
1、通過注解;
2、編程式;
3、自定義類型轉(zhuǎn)換器。
不同的方式,側重的場景也有所不同,下面通過示例梳理一下使用方法:
編程式自定義樣式
通過編程式來自定義導出表格的樣式中,有一個非常關鍵類HorizontalCellStyleStrategy。
1、通過HorizontalCellStyleStrategy可以配置好表頭的樣式和數(shù)據(jù)行的樣式;
2、使用Easyexcel的工廠方法寫出數(shù)據(jù)前,把通過HorizontalCellStyleStrategy構建好的樣式策略注冊到表格寫出構建器里;
3、使用使用Easyexcel的工廠方法寫出數(shù)據(jù);
總結:這種方法的優(yōu)點就是比較簡單,且容易理解構建樣式的過程;缺點就是不太靈活;比較適合那些導出表格前可以明確知道導出的表格的樣式特點;
@Test
public void writeWithStyle2() {
String exportPath = this.getExportPath();
String exportFile = exportPath + File.separator + "員工基本信息v2.xlsx";
List<Employee> list = new ArrayList<>();
Employee employee = new Employee();
employee.setRealName("張三");
employee.setEmpNo("CH001");
employee.setSex("女");
Employee employee2 = new Employee();
employee2.setRealName("李四");
employee2.setEmpNo("CH002");
employee2.setSex("男");
list.add(employee);
list.add(employee2);
// 頭的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景設置為紅色
headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short)20);
headWriteCellStyle.setWriteFont(headWriteFont);
// 內(nèi)容的策略
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);
// 這個策略是 頭是頭的樣式 內(nèi)容是內(nèi)容的樣式 其他的策略可以自己實現(xiàn)
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
// 這里 需要指定寫用哪個class去寫,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉
EasyExcel.write(exportFile, Employee.class)
.registerWriteHandler(horizontalCellStyleStrategy)
.sheet()
.doWrite(list);
}
注解形式自定義樣式
通過注解的形式來自定義導出表格的樣式,和編程式的比較類似,明顯的區(qū)別是一個需要通過在編寫代碼來定義樣式并應用這個樣式;另一個是需要 使用注解定義好表格樣式,應用樣式的過程easyexcel內(nèi)部已經(jīng)實現(xiàn)了,不用自己編寫代碼來實現(xiàn)??傮w上特點是一樣的:使用簡單,且比較好理解,缺點就是不靈活,不能動態(tài)的設置導出表格內(nèi)單元格的樣式。比較常用的注解有以下(有的是作用在類上,有的是作用在屬性上,注解需要設置哪些屬性可以點以注解的源里一看就很清楚):
作用在類上:
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10) // 頭字體設置成20 @HeadFontStyle(fontHeightInPoints = 20) // 內(nèi)容的背景設置成綠色 IndexedColors.GREEN.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17) // 內(nèi)容字體設置成20 @ContentFontStyle(fontHeightInPoints = 20)
作用在屬性上
// 字符串的頭背景設置成粉紅 IndexedColors.PINK.getIndex() @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14) // 字符串的頭字體設置成20 @HeadFontStyle(fontHeightInPoints = 30) // 字符串的內(nèi)容的背景設置成天藍 IndexedColors.SKY_BLUE.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40) // 字符串的內(nèi)容字體設置成20 @ContentFontStyle(fontHeightInPoints = 30)
自定義類型轉(zhuǎn)換器形式定義樣式
前兩種的樣式定義方法,都比較固定,不能根據(jù)導出數(shù)據(jù)的規(guī)則來動態(tài)設置表格內(nèi)單元格的樣式,如導出員工信息表格里如果性別是女的員工數(shù)據(jù)行,則使用紅色字體,如果是男性,則是使用藍色;因為導出數(shù)據(jù)通常是從數(shù)據(jù)源里動態(tài)取出的,在導出前沒辦法確定哪些行是男性,哪些員工是女性,所以需要動態(tài)的設置導出表格的樣式,自定義類型轉(zhuǎn)換器就可以很好的解決這個問題。
1、新建一個類SexColourConverter,實現(xiàn)com.alibaba.excel.converters.Converter接口,并重寫convertToExcelData()方法;
2、重寫convertToExcelData()方法中,根據(jù)單元格的內(nèi)容設置不同的樣式,示例中:如果性別是男,則字體為藍色;如果性別是女,則字體顏色是紅色;
3、在員工信息的實體類Employee的性別(sex)屬性上,通過@ExcelProperty()引入自定義的類型轉(zhuǎn)換器SexColourConverter;
4、使用Easyexcel的工廠方法實現(xiàn)表格數(shù)據(jù)的寫出;
總結:這種方法很靈活,非常適合一些報表中,要求導出表格中數(shù)據(jù)達到在不同規(guī)則就要求有不同的樣式的場景。在我做過的項目里,有不少導出都有類似的規(guī)則:某個屬性達到預警閾值時,要導出數(shù)據(jù)的單元格格式標成紅色。
public class SexColourConverter implements Converter<String> {
@Override
public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
WriteCellStyle writeCellStyle = new WriteCellStyle();
WriteFont writeFont = new WriteFont();
if ("男".equals(value)) {
writeFont.setColor((short) 12);
}
if ("女".equals(value)) {
writeFont.setColor((short) 10);
}
writeCellStyle.setWriteFont(writeFont);
WriteCellData<Object> cellData = new WriteCellData<>();
cellData.setWriteCellStyle(writeCellStyle);
cellData.setType(CellDataTypeEnum.STRING);
cellData.setStringValue(value);
return cellData;
}
}@Data
public class Employee implements Serializable {
@ExcelProperty("姓名")
private String realName;
@ExcelProperty("員工編號")
private String empNo;
@ExcelProperty(value = "性別",converter = SexColourConverter.class)
private String sex;
}
@Test
public void writeWithStyle() {
String exportPath = this.getExportPath();
String exportFile = exportPath + File.separator + "員工基本信息v2.xlsx";
List<Employee> list = new ArrayList<>();
Employee employee = new Employee();
employee.setRealName("張三");
employee.setEmpNo("CH001");
employee.setSex("女");
Employee employee2 = new Employee();
employee2.setRealName("李四");
employee2.setEmpNo("CH002");
employee2.setSex("男");
list.add(employee);
list.add(employee2);
EasyExcel.write(exportFile, Employee.class).sheet().doWrite(list);
}在設置單元格背景或字體的顏色的時候,顏色會對應一個short類型的數(shù)據(jù)
復雜表頭的導出
特別是一些財務類型的報表導出,表頭往往是復合表頭,比較復雜
easyexcel對于這種場景提供了兩種方法,一種是注解;另外一種是通過一種特殊的數(shù)據(jù)結構List<list>;根據(jù)我的感受,我是推薦使用注解的;
第一種:
如果是所在列是復合表頭,則使用@ExcelProperty()注解,從上到下標明表頭組成;如果是普通表頭,按普通的用法標明表頭名稱即可;是不是很簡單?
@Data
public class EmpSalary {
@ExcelProperty({"基本信息","姓名"})
private String realName;
@ExcelProperty({"基本信息","員工編號"})
private String empNo;
//,converter = SalaryDateConverter.class
@ExcelProperty(value = "工資日期")
private String salaryDate;
@ExcelProperty({"工資構成","基本工資"})
private Float baseAmount;
@ExcelProperty({"工資構成","全勤獎"})
private Float fullAttendAmount;
@ExcelProperty({"工資構成","五險一金"})
private Float insurance;
//特別資金
@ExcelIgnore
private Float specialAmount;
}@Test
public void writeHead() {
String exportPath = this.getExportPath();
String exportFile = exportPath + File.separator + "員工工資表v3.xlsx";
EasyExcel.write(exportFile, EmpSalary.class).sheet().doWrite(this.empSalaryData(10));
}
第二種:
使用List<list>結構來組織表頭數(shù)據(jù),開始的時候還不是很理解表頭的數(shù)據(jù)結構為什么這么奇怪,到這里是不是明白了。對于普通表頭List肯定就可以了,但是在一些復雜的場景就不行了。這么制定的話,什么場景都不在話下,關鍵還可以動態(tài)生成表頭,這一點確實比注解的方式要靈活一些;所以具體使用哪種,要根據(jù)業(yè)務場景決定了。
@Test
public void writeHead() {
String exportPath = this.getExportPath();
String exportFile = exportPath + File.separator + "員工工資表v4.xlsx";
List<List<String>> headList = new ArrayList<>();
List<String> head1 = new ArrayList<>();
head1.add("基本信息");
head1.add("姓名");
headList.add(head1);
List<String> head2 = new ArrayList<>();
head2.add("基本信息");
head2.add("員工編號");
headList.add(head2);
List<String> head3 = new ArrayList<>();
head3.add("工資日期");
headList.add(head3);
List<String> head4 = new ArrayList<>();
head4.add("工資構成");
head4.add("基本工資");
headList.add(head4);
List<String> head5 = new ArrayList<>();
head5.add("工資構成");
head5.add("全勤獎");
headList.add(head5);
List<String> head6 = new ArrayList<>();
head6.add("工資構成");
head6.add("保險");
headList.add(head6);
EasyExcel.write(exportFile).head(headList).sheet().doWrite(this.empSalaryData(10));
}日期、數(shù)字、自定義格式的導出
自定義格式的導出可以參考上一篇《Spring Boot:基于Easyexcel實現(xiàn)導入功能》中的日期、數(shù)字及其他自定義格式的轉(zhuǎn)換部分,SalaryDateConverter#convertToExcelData(),導出時候的數(shù)據(jù)格式轉(zhuǎn)換邏輯可以寫在這里面;SalaryDateConverter#convertToJavaData()導入時候的數(shù)據(jù)格式轉(zhuǎn)換的實現(xiàn)邏輯可以寫在這里;SalaryDateConverter是com.alibaba.excel.converters.Converter的實現(xiàn)類;
除了實現(xiàn)com.alibaba.excel.converters.Converterr接口,easyexcel也預置了一些常用的注解來實現(xiàn)格式轉(zhuǎn)換,導入導出的時候都能用,如@DateTimeFormat、@NumberFormat;
這里特別注意別導錯類了:
com.alibaba.excel.annotation.format.DateTimeFormat;
com.alibaba.excel.annotation.format.NumberFormat;
@Data
public class EmpSalary {
@ExcelProperty({"基本信息","姓名"})
private String realName;
@ExcelProperty({"基本信息","員工編號"})
private String empNo;
@DateTimeFormat("yyyy年MM月")
@ExcelProperty(value = "工資日期")
private Date salaryDate;
@ExcelProperty({"工資構成","基本工資"})
private Float baseAmount;
@ExcelProperty({"工資構成","全勤獎"})
private Float fullAttendAmount;
@ExcelProperty({"工資構成","五險一金"})
private Float insurance;
//特別資金
@ExcelIgnore
@NumberFormat
private Float specialAmount;
@NumberFormat("#.##%")
@ExcelProperty("績效完成百分比")
private Double jixiao;
}@Test
public void writeByConverter(){
String exportPath = this.getExportPath();
String exportFile = exportPath + File.separator + "員工工資表v5.xlsx";
List<EmpSalary> list=new ArrayList<>();
EmpSalary empSalary = new EmpSalary();
empSalary.setEmpNo("CH" + ( 1));
empSalary.setRealName("張三" + ( 1));
empSalary.setSalaryDate(new Date());
empSalary.setBaseAmount(5000f);
empSalary.setFullAttendAmount(500f);
empSalary.setInsurance(300f);
empSalary.setJixiao(0.9877);
list.add(empSalary);
EasyExcel.write(exportFile, EmpSalary.class).sheet("12月").doWrite(list);
}讀取全部的sheet頁
這里需要注意兩個地方:1、讀取shee頁的數(shù)據(jù)結構是一樣的;2、excel的列與接收數(shù)據(jù)類的屬性是一一對應的,如果不對應,可參考讀取到指定列部分,使用@ExcelProperty(index=xx)顯性的指定對應關系;
@Data
public class Student implements Serializable {
private Integer id;
private String stuCode;
private String stuName;
private String sex;
private String born;
private Integer age;
private String address;
private String motherName;
private String fatherName;
private Integer grade;
private Integer classNum;
}
@Test
public void readAllSheet(){
String userDir = System.getProperty("user.dir");
String importPath = userDir + File.separator + "import";
File dir = new File(importPath);
if (!dir.exists()) {
dir.mkdirs();
}
String importFile = importPath + File.separator + "學生信息表.xlsx";
StudentReadListener studentReadListener = new StudentReadListener();
EasyExcel.read(importFile, Student.class, studentReadListener).doReadAll();
List<Student> students = studentReadListener.getStudents();
for (Student student : students) {
System.out.println(student.getStuName());
}
}日期、數(shù)字及其他自定義格式的轉(zhuǎn)換
在導入或者導出excel的時候,如果想對某一列的數(shù)據(jù)格式作調(diào)整轉(zhuǎn)換,可以自定義一個轉(zhuǎn)換器(com.alibaba.excel.converters.Converter),然后這個個轉(zhuǎn)換器通過@ExcelProperty(converter=xxxxx.class)標記在接收參數(shù)的類型的屬性上;
這種轉(zhuǎn)換數(shù)據(jù)格式的需求,有時候是主動的,有時候是被動的。什么是主動的的呢?假如前數(shù)據(jù)為庫存儲的日期格式是yyyyMMdd,導出的時候想要的是xxxx年xx月xx日,然后你就可以實現(xiàn)一個類型轉(zhuǎn)換器(Converter)主動完成這個事。下面舉個被動的例子,excel中關于日期的一個坑,繞不過的坑,所以是“被動”滴。
excel中單元格式格式是日期的,easyexcel解析后是一個數(shù)字,這不是解析錯誤了,而是excel中對于日期存儲的格式就是數(shù)字,這個數(shù)字代表的是1900年1月1日,到單元格式內(nèi)日期的天數(shù),所以解析結果中是一個數(shù)字并不難理解,但是這不是我我們想要的結果呀。更惡心的是,java中的Date的時間起點1970年1月1日,所以被動的需求就產(chǎn)生了,需要把一個以1900-1-1為起天的天數(shù)代表的日期,轉(zhuǎn)換為以1970-1-1為起點的java.util.Date。標準的不統(tǒng)一,產(chǎn)生的結果就是這么惡心。
public class SalaryDateConverter implements Converter<String> {
@Override
public Class<?> supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
//導入的時候會走這個方法,導入的轉(zhuǎn)換邏輯可以在這個方法里實現(xiàn)
@Override
public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
BigDecimal numberValue = cellData.getNumberValue();
//平時不要動不動就搞個util工具類,我曾經(jīng)目睹一個新同事,用上用不上的也不管,上來在工程里導入了幾十個工具類,搞得maven依賴沖突
// org.apache.poi.ss.usermodel.DateUtil是POI的工具類,
// DateUtil.getJavaDate()的功能就是把以1900-1-1為起點的日期天數(shù)轉(zhuǎn)換成java.util.Date,直接拿來用就好了,基本不用擔心里面有bug
Date javaDate = DateUtil.getJavaDate(numberValue.doubleValue());
//com.alibaba.excel.util.DateUtils是easyexcel封裝的日期轉(zhuǎn)換工具類,能用就用上唄,基本也不用擔心有bug
String format = DateUtils.format(javaDate, DateUtils.DATE_FORMAT_10);
return format;
}
//導出的時候會走這個方法,導出的轉(zhuǎn)換邏輯可以在這個方法里實現(xiàn)
@Override
public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return null;
}
}@Data
public class EmpSalary {
@ExcelProperty("姓名")
private String realName;
@ExcelProperty("員工編號")
private String empNo;
@ExcelProperty(value = "工資日期",converter = SalaryDateConverter.class)
private String salaryDate;
@ExcelProperty("工資數(shù)額")
private Float amount;
}
@Test
public void readByConvert(){
String userDir = System.getProperty("user.dir");
String importPath = userDir + File.separator + "import";
File dir = new File(importPath);
if (!dir.exists()) {
dir.mkdirs();
}
String importFile = importPath + File.separator + "員工工資表.xlsx";
EmpSalaryReadListener empSalaryReadListener = new EmpSalaryReadListener();
EasyExcel.read(importFile, EmpSalary.class, empSalaryReadListener).sheet().doRead();
List<EmpSalary> empSalaries = empSalaryReadListener.getEmpSalaries();
System.out.println(empSalaries.size());
}表頭有多行的讀取
easyexcel在讀取表格內(nèi)容的時候,默認是從第二行開始讀的,因為第一行通常是表頭,所以上面沒有指定從第幾行開始讀也沒有問題。但是遇到下圖樣式的復合表頭的時候,表頭是占了兩行,數(shù)據(jù)是從第三行開始的,那么在讀取的時候讀取監(jiān)聽器、接收數(shù)據(jù)的類沒有變化,而是在讀取的時候要顯性指定從第幾行開始讀,實際指定的時候是索引,從0開始,第三行的索引就是2;

@Test
public void readManyRow(){
String userDir = System.getProperty("user.dir");
String importPath = userDir + File.separator + "import";
File dir = new File(importPath);
if (!dir.exists()) {
dir.mkdirs();
}
String importFile = importPath + File.separator + "員工工資表 - 副本.xlsx";
EmpSalaryReadListener empSalaryReadListener = new EmpSalaryReadListener();
//數(shù)據(jù)從第三行開始,索引是2
EasyExcel.read(importFile, EmpSalary.class, empSalaryReadListener).sheet().headRowNumber(2).doRead();
List<EmpSalary> empSalaries = empSalaryReadListener.getEmpSalaries();
System.out.println(empSalaries.size());
}
@Data
public class EmpSalary {
private String realName;
private String empNo;
@ExcelProperty(value = "工資日期",converter = SalaryDateConverter.class)
private String salaryDate;
private Float baseAmount;
private Float fullAttendAmount;
private Float insurance;
}
表頭的讀取
有時候也會有這樣的需求,就是除了讀取表格的數(shù)據(jù)外,表頭的數(shù)據(jù)也要讀取出來,easyexcel的讀取監(jiān)聽器里的實現(xiàn)類里重寫invokeHead()方法即可,下面以讀取多行表頭,寫一個示例:
public class EmpSalaryReadListener implements ReadListener<EmpSalary> {
private List<EmpSalary> empSalaries=new ArrayList<>();
public List<EmpSalary> getEmpSalaries() {
return empSalaries;
}
@Override
public void invoke(EmpSalary data, AnalysisContext context) {
empSalaries.add(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
@Override
public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
for (Integer key : headMap.keySet()) {
System.out.println("key:"+key+","+headMap.get(key).getStringValue());
}
System.out.println("---------");
}
}表頭信息也是逐行讀取的,即每讀取一行就會回調(diào)一下監(jiān)聽器的表頭讀取回調(diào)方法(invokeHead()),表頭信息結果是存儲在一個map中,map的key為excel表格列上的索引,value是表頭信息。對于多行合并單元格后,合并單元格后的內(nèi)容在第一個格里,其他單元格也會占一個位置但是是空的;
以上就是使用Easyexcel實現(xiàn)不同場景的數(shù)據(jù)導出功能的詳細內(nèi)容,更多關于Easyexcel數(shù)據(jù)導出的資料請關注腳本之家其它相關文章!
相關文章
從0到1學SpringCloud之SpringCloud?gateway網(wǎng)關路由配置示例詳解
Spring?Cloud?Gateway的目標提供統(tǒng)一的路由方式且基于Filter?鏈的方式提供了網(wǎng)關基本的功能,?例如:安全、監(jiān)控、指標和限流?,這篇文章主要介紹了從0到1學SpringCloud之SpringCloud?gateway網(wǎng)關路由配置示例詳解,需要的朋友可以參考下2023-04-04
SpringBoot實現(xiàn)文件斷點續(xù)傳功能詳解
在處理大文件傳輸或網(wǎng)絡不穩(wěn)定的情況下,文件斷點續(xù)傳功能顯得尤為重要,本文將詳細介紹如何使用Spring Boot實現(xiàn)文件的斷點續(xù)傳功能,需要的可以了解下2025-04-04
新建Maven工程出現(xiàn)Process?Terminated的問題解決
當Maven出現(xiàn)"Process terminated"錯誤時,這通常是由于配置文件或路徑錯誤導致的,本文主要介紹了新建Maven工程出現(xiàn)Process?Terminated的問題解決,感興趣的可以了解一下2024-04-04
Springboot Mybatis Plus自動生成工具類詳解代碼
mybatis-plus 是一個 Mybatis 的增強工具,在 Mybatis 的基礎上只做增強不做改變,為簡化開發(fā)、提高效率而生,這篇文章帶你使用Springboot Mybatis Plus自動生成工具類2021-11-11

