package com.alibaba.easyexcel.test.demo.write; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.write.merge.LoopMergeStrategy; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteTable; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.junit.Ignore; import org.junit.Test; import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * 寫的常見寫法 * * @author Jiaju Zhuang */ @Ignore public class WriteTest { /** * 最簡單的寫 * <p> * 1. 創建excel對應的實體對象 參照{@link DemoData} * <p> * 2. 直接寫即可 */ @Test public void simpleWrite() { // 寫法1 String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 // 如果這里想使用03 則 傳入excelType參數即可 EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); // 寫法2 fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀 ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); excelWriter.write(data(), writeSheet); /// 千萬別忘記finish 會幫忙關閉流 excelWriter.finish(); } /** * 指定寫入的列 * <p> * 1. 創建excel對應的實體對象 參照{@link IndexData} * <p> * 2. 使用{@link ExcelProperty}注解指定寫入的列 * <p> * 3. 直接寫即可 */ @Test public void indexWrite() { String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data()); } /** * 復雜頭寫入 * <p> * 1. 創建excel對應的實體對象 參照{@link ComplexHeadData} * <p> * 2. 使用{@link ExcelProperty}注解指定復雜的頭 * <p> * 3. 直接寫即可 */ @Test public void complexHeadWrite() { String fileName = TestFileUtil.getPath() + "complexHeadWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data()); } /** * 重復多次寫入 * <p> * 1. 創建excel對應的實體對象 參照{@link ComplexHeadData} * <p> * 2. 使用{@link ExcelProperty}注解指定復雜的頭 * <p> * 3. 直接調用二次寫入即可 */ @Test public void repeatedWrite() { // 方法1 如果寫到同一個sheet String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀 ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); // 這里注意 如果同一個sheet只要創建一次 WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); // 去調用寫入,這里我調用了五次,實際使用時根據數據庫分頁的總的頁數來 for (int i = 0; i < 5; i++) { // 分頁去數據庫查詢數據 這里可以去數據庫查詢每一頁的數據 List<DemoData> data = data(); excelWriter.write(data, writeSheet); } /// 千萬別忘記finish 會幫忙關閉流 excelWriter.finish(); // 方法2 如果寫到不同的sheet 同一個對象 fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 指定文件 excelWriter = EasyExcel.write(fileName, DemoData.class).build(); // 去調用寫入,這里我調用了五次,實際使用時根據數據庫分頁的總的頁數來。這里最終會寫到5個sheet里面 for (int i = 0; i < 5; i++) { // 每次都要創建writeSheet 這里注意必須指定sheetNo writeSheet = EasyExcel.writerSheet(i, "模板").build(); // 分頁去數據庫查詢數據 這里可以去數據庫查詢每一頁的數據 List<DemoData> data = data(); excelWriter.write(data, writeSheet); } /// 千萬別忘記finish 會幫忙關閉流 excelWriter.finish(); // 方法3 如果寫到不同的sheet 不同的對象 fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 指定文件 excelWriter = EasyExcel.write(fileName).build(); // 去調用寫入,這里我調用了五次,實際使用時根據數據庫分頁的總的頁數來。這里最終會寫到5個sheet里面 for (int i = 0; i < 5; i++) { // 每次都要創建writeSheet 這里注意必須指定sheetNo。這里注意DemoData.class 可以每次都變,我這里為了方便 所以用的同一個class 實際上可以一直變 writeSheet = EasyExcel.writerSheet(i, "模板").head(DemoData.class).build(); // 分頁去數據庫查詢數據 這里可以去數據庫查詢每一頁的數據 List<DemoData> data = data(); excelWriter.write(data, writeSheet); } /// 千萬別忘記finish 會幫忙關閉流 excelWriter.finish(); } /** * 日期、數字或者自定義格式轉換 * <p> * 1. 創建excel對應的實體對象 參照{@link ConverterData} * <p> * 2. 使用{@link ExcelProperty}配合使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定義注解 * <p> * 3. 直接寫即可 */ @Test public void converterWrite() { String fileName = TestFileUtil.getPath() + "converterWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, ConverterData.class).sheet("模板").doWrite(data()); } /** * 圖片導出 * <p> * 1. 創建excel對應的實體對象 參照{@link ImageData} * <p> * 2. 直接寫即可 */ @Test public void imageWrite() throws Exception { String fileName = TestFileUtil.getPath() + "imageWrite" + System.currentTimeMillis() + ".xlsx"; // 如果使用流 記得關閉 InputStream inputStream = null; try { List<ImageData> list = new ArrayList<ImageData>(); ImageData imageData = new ImageData(); list.add(imageData); String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg"; // 放入四種類型的圖片 實際使用只要選一種即可 imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath))); imageData.setFile(new File(imagePath)); imageData.setString(imagePath); inputStream = FileUtils.openInputStream(new File(imagePath)); imageData.setInputStream(inputStream); EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list); } finally { if (inputStream != null) { inputStream.close(); } } } /** * 根據模板寫入 * <p> * 1. 創建excel對應的實體對象 參照{@link IndexData} * <p> * 2. 使用{@link ExcelProperty}注解指定寫入的列 * <p> * 3. 使用withTemplate 讀取模板 * <p> * 4. 直接寫即可 */ @Test public void templateWrite() { String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; String fileName = TestFileUtil.getPath() + "templateWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, DemoData.class).withTemplate(templateFileName).sheet().doWrite(data()); } /** * 列寬、行高 * <p> * 1. 創建excel對應的實體對象 參照{@link WidthAndHeightData} * <p> * 2. 使用注解{@link ColumnWidth}、{@link HeadRowHeight}、{@link ContentRowHeight}指定寬度或高度 * <p> * 3. 直接寫即可 */ @Test public void widthAndHeightWrite() { String fileName = TestFileUtil.getPath() + "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, WidthAndHeightData.class).sheet("模板").doWrite(data()); } /** * 自定義樣式 * <p> * 1. 創建excel對應的實體對象 參照{@link DemoData} * <p> * 2. 創建一個style策略 並注冊 * <p> * 3. 直接寫即可 */ @Test public void styleWrite() { String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; // 頭的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景設置為紅色 headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); WriteFont headWriteFont = new WriteFont(); headWriteFont.setFontHeightInPoints((short) 10); headWriteFont.setBold(true); headWriteFont.setFontName("宋體"); headWriteCellStyle.setWriteFont(headWriteFont); // 內容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); WriteFont contentWriteFont = new WriteFont(); // 字體大小 contentWriteFont.setFontHeightInPoints((short) 10); contentWriteFont.setFontName("宋體"); contentWriteCellStyle.setWriteFont(contentWriteFont); // 這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現 HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 List<Object> data = new ArrayList<Object>(); DownFastInquiryBO bo = new DownFastInquiryBO(); bo.setId(1); bo.setProSkuNo("AA0193"); bo.setProSkuProductName("ABB Emax2框架斷路器 E1N 800 T LSIG 4P WMP NST 10146488 1個"); bo.setProBrandName("LOCTITE/樂泰"); bo.setProMaterialNo("E1N 800 T LSIG 4P WMP NST"); bo.setManuDirectoryNo("10146488"); bo.setProSkuUnit("個"); bo.setProSkuMinOrderNum(1); bo.setTotalQty("10"); bo.setOriginPrice((double) 55596); bo.setSellingPrice(25305.91); bo.setDiscountAmount("0.00"); bo.setTaxRate("16.00%"); bo.setTotalQty("46"); bo.setSellingPriceSum(1164071.86); bo.setProSkuLeadTime("241個工作日"); data.add(bo); EasyExcel.write(fileName, DownFastInquiryBO.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板") .doWrite(data); System.out.println(fileName); } /** * 合並單元格 * <p> * 1. 創建excel對應的實體對象 參照{@link DemoData} * <p> * 2. 創建一個merge策略 並注冊 * <p> * 3. 直接寫即可 */ @Test public void mergeWrite() { String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; // 每隔2行會合並 把eachColumn 設置成 3 也就是我們數據的長度,所以就第一列會合並。當然其他合並策略也可以自己寫 LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data()); } /** * 使用table去寫入 * <p> * 1. 創建excel對應的實體對象 參照{@link DemoData} * <p> * 2. 然后寫入table即可 */ @Test public void tableWrite() { String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx"; // 這里直接寫多個table的案例了,如果只有一個 也可以直一行代碼搞定,參照其他案例 // 這里 需要指定寫用哪個class去讀 ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); // 把sheet設置為不需要頭 不然會輸出sheet的頭 這樣看起來第一個table 就有2個頭了 WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build(); // 這里必須指定需要頭,table 會繼承sheet的配置,sheet配置了不需要,table 默認也是不需要 WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build(); WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build(); // 第一次寫入會創建頭 excelWriter.write(data(), writeSheet, writeTable0); // 第二次寫如也會創建頭,然后在第一次的后面寫入數據 excelWriter.write(data(), writeSheet, writeTable1); /// 千萬別忘記finish 會幫忙關閉流 excelWriter.finish(); } /** * 動態頭,實時生成頭寫入 * <p> * 思路是這樣子的,先創建List<String>頭格式的sheet僅僅寫入頭,然后通過table 不寫入頭的方式 去寫入數據 * * <p> * 1. 創建excel對應的實體對象 參照{@link DemoData} * <p> * 2. 然后寫入table即可 */ @Test public void dynamicHeadWrite() { String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx"; EasyExcel.write(fileName) // 這里放入動態頭 .head(head()).sheet("模板") // 當然這里數據也可以用 List<List<String>> 去傳入 .doWrite(data()); } /** * 自動列寬(不太精確) * <p> * 這個目前不是很好用,比如有數字就會導致換行。而且長度也不是剛好和實際長度一致。 所以需要精確到剛好列寬的慎用。 當然也可以自己參照 * {@link LongestMatchColumnWidthStyleStrategy}重新實現. * <p> * poi 自帶{@link SXSSFSheet#autoSizeColumn(int)} 對中文支持也不太好。目前沒找到很好的算法。 有的話可以推薦下。 * * <p> * 1. 創建excel對應的實體對象 參照{@link LongestMatchColumnWidthData} * <p> * 2. 注冊策略{@link LongestMatchColumnWidthStyleStrategy} * <p> * 3. 直接寫即可 */ @Test public void longestMatchColumnWidthWrite() { String fileName = TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, LongestMatchColumnWidthData.class) .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong()); } /** * 下拉,超鏈接等自定義攔截器(上面幾點都不符合但是要對單元格進行操作的參照這個) * <p> * demo這里實現2點。1. 對第一行第一列的頭超鏈接到:https://github.com/alibaba/easyexcel 2. 對第一列第一行和第二行的數據新增下拉框,顯示 測試1 測試2 * <p> * 1. 創建excel對應的實體對象 參照{@link DemoData} * <p> * 2. 注冊攔截器 {@link CustomCellWriteHandler} {@link CustomSheetWriteHandler} * <p> * 2. 直接寫即可 */ @Test public void customHandlerWrite() { String fileName = TestFileUtil.getPath() + "customHandlerWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉 EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new CustomSheetWriteHandler()) .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); } private List<LongestMatchColumnWidthData> dataLong() { List<LongestMatchColumnWidthData> list = new ArrayList<LongestMatchColumnWidthData>(); for (int i = 0; i < 10; i++) { LongestMatchColumnWidthData data = new LongestMatchColumnWidthData(); data.setString("測試很長的字符串測試很長的字符串測試很長的字符串" + i); data.setDate(new Date()); data.setDoubleData(1000000000000.0); list.add(data); } return list; } private List<List<String>> head() { List<List<String>> list = new ArrayList<List<String>>(); List<String> head0 = new ArrayList<String>(); head0.add("字符串" + System.currentTimeMillis()); List<String> head1 = new ArrayList<String>(); head1.add("數字" + System.currentTimeMillis()); List<String> head2 = new ArrayList<String>(); head2.add("日期" + System.currentTimeMillis()); list.add(head0); list.add(head1); list.add(head2); return list; } private List<DemoData> data() { List<DemoData> list = new ArrayList<DemoData>(); for (int i = 0; i < 10; i++) { DemoData data = new DemoData(); data.setString("字符串" + i); data.setDate(new Date()); data.setDoubleData(0.56); list.add(data); } return list; } }
package com.alibaba.easyexcel.test.demo.write; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import lombok.Data; /** * @author: cheng.tang * @date: 2019/10/21 * @see * @since */ @Data public class DownFastInquiryBO { @ExcelProperty("序號") private Integer id; @ExcelProperty("SKU編碼") @ColumnWidth(15) private String proSkuNo; @ExcelProperty("產品描述") @ColumnWidth(20) private String proSkuProductName; @ExcelProperty("品牌") @ColumnWidth(10) private String proBrandName; @ColumnWidth(15) @ExcelProperty("制造商型號") private String proMaterialNo; @ColumnWidth(20) @ExcelProperty("制造商訂貨號") private String manuDirectoryNo; @ExcelProperty("單位") private String proSkuUnit; @ColumnWidth(15) @ExcelProperty("最小起訂量") private Integer proSkuMinOrderNum; @ExcelProperty("庫存") private String totalQty; @ExcelProperty("面價") private Double originPrice; @ColumnWidth(15) @ExcelProperty("含稅單價") private Double sellingPrice; @ColumnWidth(15) @ExcelProperty("優惠金額") private String discountAmount; @ExcelProperty("稅率") private String taxRate; @ExcelProperty("數量") private Integer proSkuQty; @ColumnWidth(15) @ExcelProperty("含稅小計") private Double sellingPriceSum; @ColumnWidth(20) @ExcelProperty("發貨日") private String proSkuLeadTime; }
