使用Easyexcel實現(xiàn)不同場景的數(shù)據(jù)導(dǎo)出功能
導(dǎo)出的數(shù)據(jù)包含有圖片
導(dǎo)出excel表格的數(shù)據(jù)包含有圖片,這種場景比較少。通Easyexcel實現(xiàn)這樣的需求,我認為最簡便的方法就是使用前面提到的自定義轉(zhuǎn)換器(com.alibaba.excel.converters.Converter);假如有這樣一個場景,導(dǎo)出員工的信息,還要包括員工的一寸照。通常情況下,數(shù)據(jù)庫并不會真的存一張圖片,而是圖片存儲位置的相對路徑。
1、新建一個類EmpHeadPhotoConverter,實現(xiàn)com.alibaba.excel.converters.Converter接口,并重寫convertToExcelData()方法;
2、在重寫convertToExcelData()方法中,根據(jù)圖片的相同路徑或網(wǎng)絡(luò)地址讀取出圖片的字節(jié)流作為構(gòu)建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)絡(luò)地址讀取圖片到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ù)構(gòu)建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è)務(wù)開發(fā)過程中,這里應(yīng)該是圖片的相對路徑或網(wǎng)絡(luò)地址 employee.setHeadPhoto("zhangsan.jpeg"); list.add(employee); } EasyExcel.write(exportFile,Employee.class).sheet().doWrite(list); }
導(dǎo)出表格指定列寬行高
上面其實是已經(jīng)說過了,通過注解可以簡單的指定導(dǎo)出Excel表格的行、列的高度和寬度:
@ContentRowHeight()用于指定數(shù)據(jù)行的高度;
@HeadRowHeight()用于指定表頭行的高度;
@ColumnWidth()用于指定數(shù)據(jù)列的寬度;
導(dǎo)出表格自定義樣式
我比較喜歡使用easyexcel的一個很重要的原因就是,easyexcel在poi的基礎(chǔ)上,封裝的比較友好。就比如,在導(dǎo)出的時候,很多情況下需要自定義表格的樣式,easyexcel就提供了多種的實現(xiàn)方式。主要有三種:
1、通過注解;
2、編程式;
3、自定義類型轉(zhuǎn)換器。
不同的方式,側(cè)重的場景也有所不同,下面通過示例梳理一下使用方法:
編程式自定義樣式
通過編程式來自定義導(dǎo)出表格的樣式中,有一個非常關(guān)鍵類HorizontalCellStyleStrategy。
1、通過HorizontalCellStyleStrategy可以配置好表頭的樣式和數(shù)據(jù)行的樣式;
2、使用Easyexcel的工廠方法寫出數(shù)據(jù)前,把通過HorizontalCellStyleStrategy構(gòu)建好的樣式策略注冊到表格寫出構(gòu)建器里;
3、使用使用Easyexcel的工廠方法寫出數(shù)據(jù);
總結(jié):這種方法的優(yōu)點就是比較簡單,且容易理解構(gòu)建樣式的過程;缺點就是不太靈活;比較適合那些導(dǎo)出表格前可以明確知道導(dǎo)出的表格的樣式特點;
@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(); // 背景設(shè)置為紅色 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,名字為模板 然后文件流會自動關(guān)閉 EasyExcel.write(exportFile, Employee.class) .registerWriteHandler(horizontalCellStyleStrategy) .sheet() .doWrite(list); }
注解形式自定義樣式
通過注解的形式來自定義導(dǎo)出表格的樣式,和編程式的比較類似,明顯的區(qū)別是一個需要通過在編寫代碼來定義樣式并應(yīng)用這個樣式;另一個是需要 使用注解定義好表格樣式,應(yīng)用樣式的過程easyexcel內(nèi)部已經(jīng)實現(xiàn)了,不用自己編寫代碼來實現(xiàn)??傮w上特點是一樣的:使用簡單,且比較好理解,缺點就是不靈活,不能動態(tài)的設(shè)置導(dǎo)出表格內(nèi)單元格的樣式。比較常用的注解有以下(有的是作用在類上,有的是作用在屬性上,注解需要設(shè)置哪些屬性可以點以注解的源里一看就很清楚):
作用在類上:
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10) // 頭字體設(shè)置成20 @HeadFontStyle(fontHeightInPoints = 20) // 內(nèi)容的背景設(shè)置成綠色 IndexedColors.GREEN.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17) // 內(nèi)容字體設(shè)置成20 @ContentFontStyle(fontHeightInPoints = 20)
作用在屬性上
// 字符串的頭背景設(shè)置成粉紅 IndexedColors.PINK.getIndex() @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14) // 字符串的頭字體設(shè)置成20 @HeadFontStyle(fontHeightInPoints = 30) // 字符串的內(nèi)容的背景設(shè)置成天藍 IndexedColors.SKY_BLUE.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40) // 字符串的內(nèi)容字體設(shè)置成20 @ContentFontStyle(fontHeightInPoints = 30)
自定義類型轉(zhuǎn)換器形式定義樣式
前兩種的樣式定義方法,都比較固定,不能根據(jù)導(dǎo)出數(shù)據(jù)的規(guī)則來動態(tài)設(shè)置表格內(nèi)單元格的樣式,如導(dǎo)出員工信息表格里如果性別是女的員工數(shù)據(jù)行,則使用紅色字體,如果是男性,則是使用藍色;因為導(dǎo)出數(shù)據(jù)通常是從數(shù)據(jù)源里動態(tài)取出的,在導(dǎo)出前沒辦法確定哪些行是男性,哪些員工是女性,所以需要動態(tài)的設(shè)置導(dǎo)出表格的樣式,自定義類型轉(zhuǎn)換器就可以很好的解決這個問題。
1、新建一個類SexColourConverter,實現(xiàn)com.alibaba.excel.converters.Converter接口,并重寫convertToExcelData()方法;
2、重寫convertToExcelData()方法中,根據(jù)單元格的內(nèi)容設(shè)置不同的樣式,示例中:如果性別是男,則字體為藍色;如果性別是女,則字體顏色是紅色;
3、在員工信息的實體類Employee的性別(sex)屬性上,通過@ExcelProperty()引入自定義的類型轉(zhuǎn)換器SexColourConverter;
4、使用Easyexcel的工廠方法實現(xiàn)表格數(shù)據(jù)的寫出;
總結(jié):這種方法很靈活,非常適合一些報表中,要求導(dǎo)出表格中數(shù)據(jù)達到在不同規(guī)則就要求有不同的樣式的場景。在我做過的項目里,有不少導(dǎo)出都有類似的規(guī)則:某個屬性達到預(yù)警閾值時,要導(dǎo)出數(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); }
在設(shè)置單元格背景或字體的顏色的時候,顏色會對應(yīng)一個short類型的數(shù)據(jù)
復(fù)雜表頭的導(dǎo)出
特別是一些財務(wù)類型的報表導(dǎo)出,表頭往往是復(fù)合表頭,比較復(fù)雜
easyexcel對于這種場景提供了兩種方法,一種是注解;另外一種是通過一種特殊的數(shù)據(jù)結(jié)構(gòu)List<list>;根據(jù)我的感受,我是推薦使用注解的;
第一種:
如果是所在列是復(fù)合表頭,則使用@ExcelProperty()注解,從上到下標明表頭組成;如果是普通表頭,按普通的用法標明表頭名稱即可;是不是很簡單?
@Data public class EmpSalary { @ExcelProperty({"基本信息","姓名"}) private String realName; @ExcelProperty({"基本信息","員工編號"}) private String empNo; //,converter = SalaryDateConverter.class @ExcelProperty(value = "工資日期") private String salaryDate; @ExcelProperty({"工資構(gòu)成","基本工資"}) private Float baseAmount; @ExcelProperty({"工資構(gòu)成","全勤獎"}) private Float fullAttendAmount; @ExcelProperty({"工資構(gòu)成","五險一金"}) 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>結(jié)構(gòu)來組織表頭數(shù)據(jù),開始的時候還不是很理解表頭的數(shù)據(jù)結(jié)構(gòu)為什么這么奇怪,到這里是不是明白了。對于普通表頭List肯定就可以了,但是在一些復(fù)雜的場景就不行了。這么制定的話,什么場景都不在話下,關(guān)鍵還可以動態(tài)生成表頭,這一點確實比注解的方式要靈活一些;所以具體使用哪種,要根據(jù)業(yè)務(wù)場景決定了。
@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("工資構(gòu)成"); head4.add("基本工資"); headList.add(head4); List<String> head5 = new ArrayList<>(); head5.add("工資構(gòu)成"); head5.add("全勤獎"); headList.add(head5); List<String> head6 = new ArrayList<>(); head6.add("工資構(gòu)成"); head6.add("保險"); headList.add(head6); EasyExcel.write(exportFile).head(headList).sheet().doWrite(this.empSalaryData(10)); }
日期、數(shù)字、自定義格式的導(dǎo)出
自定義格式的導(dǎo)出可以參考上一篇《Spring Boot:基于Easyexcel實現(xiàn)導(dǎo)入功能》中的日期、數(shù)字及其他自定義格式的轉(zhuǎn)換部分,SalaryDateConverter#convertToExcelData(),導(dǎo)出時候的數(shù)據(jù)格式轉(zhuǎn)換邏輯可以寫在這里面;SalaryDateConverter#convertToJavaData()導(dǎo)入時候的數(shù)據(jù)格式轉(zhuǎn)換的實現(xiàn)邏輯可以寫在這里;SalaryDateConverter是com.alibaba.excel.converters.Converter的實現(xiàn)類;
除了實現(xiàn)com.alibaba.excel.converters.Converterr接口,easyexcel也預(yù)置了一些常用的注解來實現(xiàn)格式轉(zhuǎn)換,導(dǎo)入導(dǎo)出的時候都能用,如@DateTimeFormat、@NumberFormat;
這里特別注意別導(dǎo)錯類了:
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({"工資構(gòu)成","基本工資"}) private Float baseAmount; @ExcelProperty({"工資構(gòu)成","全勤獎"}) private Float fullAttendAmount; @ExcelProperty({"工資構(gòu)成","五險一金"}) 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ù)結(jié)構(gòu)是一樣的;2、excel的列與接收數(shù)據(jù)類的屬性是一一對應(yīng)的,如果不對應(yīng),可參考讀取到指定列部分,使用@ExcelProperty(index=xx)顯性的指定對應(yīng)關(guān)系;
@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 + "學(xué)生信息表.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)換
在導(dǎo)入或者導(dǎo)出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,導(dǎo)出的時候想要的是xxxx年xx月xx日,然后你就可以實現(xiàn)一個類型轉(zhuǎn)換器(Converter)主動完成這個事。下面舉個被動的例子,excel中關(guān)于日期的一個坑,繞不過的坑,所以是“被動”滴。
excel中單元格式格式是日期的,easyexcel解析后是一個數(shù)字,這不是解析錯誤了,而是excel中對于日期存儲的格式就是數(shù)字,這個數(shù)字代表的是1900年1月1日,到單元格式內(nèi)日期的天數(shù),所以解析結(jié)果中是一個數(shù)字并不難理解,但是這不是我我們想要的結(jié)果呀。更惡心的是,java中的Date的時間起點1970年1月1日,所以被動的需求就產(chǎn)生了,需要把一個以1900-1-1為起天的天數(shù)代表的日期,轉(zhuǎn)換為以1970-1-1為起點的java.util.Date。標準的不統(tǒng)一,產(chǎn)生的結(jié)果就是這么惡心。
public class SalaryDateConverter implements Converter<String> { @Override public Class<?> supportJavaTypeKey() { return String.class; } @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.STRING; } //導(dǎo)入的時候會走這個方法,導(dǎo)入的轉(zhuǎn)換邏輯可以在這個方法里實現(xiàn) @Override public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { BigDecimal numberValue = cellData.getNumberValue(); //平時不要動不動就搞個util工具類,我曾經(jīng)目睹一個新同事,用上用不上的也不管,上來在工程里導(dǎo)入了幾十個工具類,搞得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; } //導(dǎo)出的時候會走這個方法,導(dǎo)出的轉(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)容的時候,默認是從第二行開始讀的,因為第一行通常是表頭,所以上面沒有指定從第幾行開始讀也沒有問題。但是遇到下圖樣式的復(fù)合表頭的時候,表頭是占了兩行,數(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()),表頭信息結(jié)果是存儲在一個map中,map的key為excel表格列上的索引,value是表頭信息。對于多行合并單元格后,合并單元格后的內(nèi)容在第一個格里,其他單元格也會占一個位置但是是空的;
以上就是使用Easyexcel實現(xiàn)不同場景的數(shù)據(jù)導(dǎo)出功能的詳細內(nèi)容,更多關(guān)于Easyexcel數(shù)據(jù)導(dǎo)出的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
從0到1學(xué)SpringCloud之SpringCloud?gateway網(wǎng)關(guān)路由配置示例詳解
Spring?Cloud?Gateway的目標提供統(tǒng)一的路由方式且基于Filter?鏈的方式提供了網(wǎng)關(guān)基本的功能,?例如:安全、監(jiān)控、指標和限流?,這篇文章主要介紹了從0到1學(xué)SpringCloud之SpringCloud?gateway網(wǎng)關(guān)路由配置示例詳解,需要的朋友可以參考下2023-04-04SpringBoot實現(xiàn)文件斷點續(xù)傳功能詳解
在處理大文件傳輸或網(wǎng)絡(luò)不穩(wěn)定的情況下,文件斷點續(xù)傳功能顯得尤為重要,本文將詳細介紹如何使用Spring Boot實現(xiàn)文件的斷點續(xù)傳功能,需要的可以了解下2025-04-04新建Maven工程出現(xiàn)Process?Terminated的問題解決
當Maven出現(xiàn)"Process terminated"錯誤時,這通常是由于配置文件或路徑錯誤導(dǎo)致的,本文主要介紹了新建Maven工程出現(xiàn)Process?Terminated的問題解決,感興趣的可以了解一下2024-04-04Springboot Mybatis Plus自動生成工具類詳解代碼
mybatis-plus 是一個 Mybatis 的增強工具,在 Mybatis 的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生,這篇文章帶你使用Springboot Mybatis Plus自動生成工具類2021-11-11