Java?EasyExcel實現(xiàn)合并相同內(nèi)容單元格與動態(tài)標(biāo)題功能
一、最初版本
導(dǎo)出的結(jié)果:
對應(yīng)實體類代碼:
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentLoopMerge; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; import lombok.*; import java.io.Serializable; @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Data @ContentRowHeight(30) @HeadRowHeight(40) @ColumnWidth(25) public class StudentExportVo implements Serializable { private static final long serialVersionUID = -5809782578272943999L; @ExcelProperty(value = "學(xué)校", order = 1) @ContentLoopMerge(eachRow = 3) private String school; @ExcelProperty(value = "姓名", order = 2) private String name; @ExcelProperty(value = "性別", order = 3) private String sex; @ExcelProperty(value = "年齡", order = 4) private String age; @ExcelProperty(value = "城市", order = 5) private String city; @ExcelProperty(value = "備注", order = 6) private String remarks; }
對應(yīng)業(yè)務(wù)代碼:
@ApiOperation(value = "導(dǎo)出學(xué)生信息", notes = "導(dǎo)出學(xué)生信息") @PostMapping("/exportStudent") public void exportStudent(@RequestBody String str, HttpServletResponse response) { List<StudentExportVo> list = this.getStudentExportVos(); ExcelUtils.writeExcel(response, StudentExportVo.class, list, "導(dǎo)出學(xué)生信息", "sheet1"); } //數(shù)據(jù)制造 private List<StudentExportVo> getStudentExportVos() { List<StudentExportVo> list = new ArrayList<>(); StudentExportVo v1 = new StudentExportVo(); v1.setSchool("北京大學(xué)"); v1.setName("張三"); v1.setSex("男"); v1.setAge("20"); v1.setCity("北京"); v1.setRemarks("無"); list.add(v1); StudentExportVo v2 = new StudentExportVo(); v2.setSchool("北京大學(xué)"); v2.setName("李四"); v2.setSex("男"); v2.setAge("22"); v2.setCity("上海"); v2.setRemarks("無"); list.add(v2); StudentExportVo v3 = new StudentExportVo(); v3.setSchool("北京大學(xué)"); v3.setName("王五"); v3.setSex("女"); v3.setAge("22"); v3.setCity("青島"); v3.setRemarks("無"); list.add(v3); StudentExportVo v4 = new StudentExportVo(); v4.setSchool("清華大學(xué)"); v4.setName("趙六"); v4.setSex("女"); v4.setAge("21"); v4.setCity("重慶"); v4.setRemarks("無"); list.add(v4); StudentExportVo v5 = new StudentExportVo(); v5.setSchool("武漢大學(xué)"); v5.setName("王強(qiáng)"); v5.setSex("男"); v5.setAge("24"); v5.setCity("長沙"); v5.setRemarks("無"); list.add(v5); StudentExportVo v6 = new StudentExportVo(); v6.setSchool("武漢大學(xué)"); v6.setName("趙燕"); v6.setSex("女"); v6.setAge("21"); v6.setCity("深圳"); v6.setRemarks("無"); list.add(v6); StudentExportVo v7 = new StudentExportVo(); v7.setSchool("廈門大學(xué)"); v7.setName("陸仟"); v7.setSex("女"); v7.setAge("21"); v7.setCity("廣州"); v7.setRemarks("無"); list.add(v7); return list; }
二、使用注解的版本
導(dǎo)出的結(jié)果:
對應(yīng)實體類代碼:
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Data @ContentRowHeight(30) @HeadRowHeight(40) @ColumnWidth(25) public class StudentExportVo implements Serializable { private static final long serialVersionUID = -5809782578272943999L; @ExcelProperty(value = {"學(xué)生信息","學(xué)校"}, order = 1) @ContentLoopMerge(eachRow = 3) private String school; @ExcelProperty(value = {"學(xué)生信息","姓名"}, order = 2) private String name; @ExcelProperty(value = {"學(xué)生信息","性別"}, order = 3) private String sex; @ExcelProperty(value = {"學(xué)生信息","年齡"}, order = 4) private String age; @ExcelProperty(value = {"學(xué)生信息","城市"}, order = 5) private String city; @ExcelProperty(value = {"學(xué)生信息","備注"}, order = 6) private String remarks; }
對應(yīng)業(yè)務(wù)代碼:同上
@ContentLoopMerge(eachRow = 3) 可以合并單元格,但是他是按指定行數(shù)合并,并不能實現(xiàn)內(nèi)容相同的合并
@ExcelProperty(value = {“學(xué)生信息”,“備注”},能實現(xiàn)多個標(biāo)題,但標(biāo)題是固定的,不是動態(tài)的
三、自定義改造
導(dǎo)出的結(jié)果:
對應(yīng)實體類代碼:
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Data @ContentRowHeight(30) @HeadRowHeight(40) @ColumnWidth(25) public class StudentExportVo implements Serializable { private static final long serialVersionUID = -5809782578272943999L; @ExcelProperty(value = {"學(xué)生信息","學(xué)校"}, order = 1) //@ContentLoopMerge(eachRow = 3) private String school; @ExcelProperty(value = {"學(xué)生信息","姓名"}, order = 2) private String name; @ExcelProperty(value = {"學(xué)生信息","性別"}, order = 3) private String sex; @ExcelProperty(value = {"學(xué)生信息","年齡"}, order = 4) private String age; @ExcelProperty(value = {"學(xué)生信息","城市"}, order = 5) private String city; @ExcelProperty(value = {"學(xué)生信息","備注"}, order = 6) private String remarks; }
對應(yīng)業(yè)務(wù)代碼:
@ApiOperation(value = "導(dǎo)出學(xué)生信息", notes = "導(dǎo)出學(xué)生信息") @PostMapping("/exportStudent") public void exportStudent(@RequestBody String dynamicTitle, HttpServletResponse response) { List<StudentExportVo> list = this.getStudentExportVos(); try { String fileName = "學(xué)生信息"; fileName = URLEncoder.encode(fileName, "UTF-8"); response.setContentType("application/json;charset=utf-8"); response.setCharacterEncoding("utf-8"); response.addHeader("Pargam", "no-cache"); response.addHeader("Cache-Control", "no-cache"); response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx"); ServletOutputStream output = response.getOutputStream(); //需要合并的列 int[] mergeColumeIndex = {0}; // 從第二行后開始合并 int mergeRowIndex = 2; //設(shè)置動態(tài)標(biāo)題 List<List<String>> headers = this.getHeaders("學(xué)生信息" + dynamicTitle); // 頭的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景設(shè)置為白色 headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); /*WriteFont headWriteFont = new WriteFont(); headWriteFont.setFontHeightInPoints((short)20); headWriteCellStyle.setWriteFont(headWriteFont);*/ // 內(nèi)容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); // 這里需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無法顯示背景顏色.頭默認(rèn)了 FillPatternType所以可以不指定 //contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); // 背景綠色 //contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); //設(shè)置 自動換行 contentWriteCellStyle.setWrapped(true); //設(shè)置 垂直居中 contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //設(shè)置 水平居中 contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); /*WriteFont contentWriteFont = new WriteFont(); // 字體大小 contentWriteFont.setFontHeightInPoints((short)20); contentWriteCellStyle.setWriteFont(contentWriteFont);*/ // 這個策略是 頭是頭的樣式 內(nèi)容是內(nèi)容的樣式 其他的策略可以自己實現(xiàn) HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); EasyExcel.write(output, StudentExportVo.class) .sheet("學(xué)生信息") .head(headers) .registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeColumeIndex)) .registerWriteHandler(horizontalCellStyleStrategy) // .registerWriteHandler(new SimpleColumnWidthStyleStrategy(30)) .registerWriteHandler(new AbstractColumnWidthStyleStrategy() { @Override protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) { Sheet sheet = writeSheetHolder.getSheet(); int columnIndex = cell.getColumnIndex(); if(columnIndex == 5){ // 列寬100 sheet.setColumnWidth(columnIndex, 10000); }else { // 列寬50 sheet.setColumnWidth(columnIndex, 5000); } // 行高40 sheet.setDefaultRowHeight((short) 4000); } }) .doWrite(list); output.flush(); } catch (IOException e) { log.error(e.getMessage(), e); } } private List<List<String>> getHeaders(String dynamicTitle) { List<List<String>> headers=new ArrayList<>(); List<String> schoolHead=new ArrayList<>(); schoolHead.add(dynamicTitle); schoolHead.add("學(xué)校"); List<String> nameHead=new ArrayList<>(); nameHead.add(dynamicTitle); nameHead.add("姓名"); List<String> sexHead=new ArrayList<>(); sexHead.add(dynamicTitle); sexHead.add("性別"); List<String> ageHead=new ArrayList<>(); ageHead.add(dynamicTitle); ageHead.add("年齡"); List<String> cityHead=new ArrayList<>(); cityHead.add(dynamicTitle); cityHead.add("城市"); List<String> remarksHead=new ArrayList<>(); remarksHead.add(dynamicTitle); remarksHead.add("備注"); headers.add(schoolHead); headers.add(nameHead); headers.add(sexHead); headers.add(ageHead); headers.add(cityHead); headers.add(remarksHead); return headers; } //數(shù)據(jù)制造 private List<StudentExportVo> getStudentExportVos() { List<StudentExportVo> list = new ArrayList<>(); StudentExportVo v1 = new StudentExportVo(); v1.setSchool("北京大學(xué)"); v1.setName("張三"); v1.setSex("男"); v1.setAge("20"); v1.setCity("北京"); v1.setRemarks("無"); list.add(v1); StudentExportVo v2 = new StudentExportVo(); v2.setSchool("北京大學(xué)"); v2.setName("李四"); v2.setSex("男"); v2.setAge("22"); v2.setCity("上海"); v2.setRemarks("無"); list.add(v2); StudentExportVo v3 = new StudentExportVo(); v3.setSchool("北京大學(xué)"); v3.setName("王五"); v3.setSex("女"); v3.setAge("22"); v3.setCity("青島"); v3.setRemarks("無"); list.add(v3); StudentExportVo v4 = new StudentExportVo(); v4.setSchool("清華大學(xué)"); v4.setName("趙六"); v4.setSex("女"); v4.setAge("21"); v4.setCity("重慶"); v4.setRemarks("無"); list.add(v4); StudentExportVo v5 = new StudentExportVo(); v5.setSchool("武漢大學(xué)"); v5.setName("王強(qiáng)"); v5.setSex("男"); v5.setAge("24"); v5.setCity("長沙"); v5.setRemarks("無"); list.add(v5); StudentExportVo v6 = new StudentExportVo(); v6.setSchool("武漢大學(xué)"); v6.setName("趙燕"); v6.setSex("女"); v6.setAge("21"); v6.setCity("深圳"); v6.setRemarks("無"); list.add(v6); StudentExportVo v7 = new StudentExportVo(); v7.setSchool("廈門大學(xué)"); v7.setName("陸仟"); v7.setSex("女"); v7.setAge("21"); v7.setCity("廣州"); v7.setRemarks("無"); list.add(v7); return list; }
合并單元格相同內(nèi)容處理類:ExcelMergeHandler
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import java.util.List; public class ExcelMergeHandler implements CellWriteHandler { private int[] mergeColumnIndex; private int mergeRowIndex; public ExcelMergeHandler() { } public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) { this.mergeRowIndex = mergeRowIndex; this.mergeColumnIndex = mergeColumnIndex; } @Override public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { } @Override public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { } @Override public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { } @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { //當(dāng)前行 int curRowIndex = cell.getRowIndex(); //當(dāng)前列 int curColIndex = cell.getColumnIndex(); if (curRowIndex > mergeRowIndex) { for (int i = 0; i < mergeColumnIndex.length; i++) { if (curColIndex == mergeColumnIndex[i]) { mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex); break; } } } } /** * 當(dāng)前單元格向上合并 * * @param writeSheetHolder * @param cell 當(dāng)前單元格 * @param curRowIndex 當(dāng)前行 * @param curColIndex 當(dāng)前列 */ private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) { Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue(); Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex); Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue(); // 將當(dāng)前單元格數(shù)據(jù)與上一個單元格數(shù)據(jù)比較 Boolean dataBool = preData.equals(curData); //此處需要注意:因為我是按照工程名稱確定是否需要合并的,所以獲取每一行第二列數(shù)據(jù)和上一行第一列數(shù)據(jù)進(jìn)行比較,如果相等合并,getCell里面的值,是工程名稱所在列的下標(biāo) String s1 = cell.getRow().getCell(0).getStringCellValue(); String s2 = cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue(); /*BigDecimal d1 = new BigDecimal(cell.getRow().getCell(0).getNumericCellValue()); BigDecimal d2 = new BigDecimal(cell.getSheet().getRow(curRowIndex - 1).getCell(0).getNumericCellValue());*/ Boolean bool = s1.compareTo(s2) == 0 ? true:false; // 原始的 // Boolean bool = cell.getRow().getCell(1).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(1).getStringCellValue()); if (dataBool && bool) { Sheet sheet = writeSheetHolder.getSheet(); List<CellRangeAddress> mergeRegions = sheet.getMergedRegions(); boolean isMerged = false; for (int i = 0; i < mergeRegions.size() && !isMerged; i++) { CellRangeAddress cellRangeAddr = mergeRegions.get(i); // 若上一個單元格已經(jīng)被合并,則先移出原有的合并單元,再重新添加合并單元 if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) { sheet.removeMergedRegion(i); cellRangeAddr.setLastRow(curRowIndex); sheet.addMergedRegion(cellRangeAddr); isMerged = true; } } // 若上一個單元格未被合并,則新增合并單元 if (!isMerged) { CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex); sheet.addMergedRegion(cellRangeAddress); } } } }
總結(jié):
1、使用自定義合并相同內(nèi)容單元格時,實體類中的注解@ContentLoopMerge需要去掉,要不然會受到影響
2、該段自定義代碼中如內(nèi)容合并、設(shè)置動態(tài)標(biāo)題、內(nèi)容、以及每個列的寬度及字體都是可以根據(jù)自定義策略來進(jìn)行設(shè)置的,具體用法可以參考代碼注釋說明,根據(jù)需要進(jìn)行使用
以上就是Java EasyExcel實現(xiàn)合并相同內(nèi)容單元格與動態(tài)標(biāo)題功能的詳細(xì)內(nèi)容,更多關(guān)于Java EasyExcel合并單元格的資料請關(guān)注腳本之家其它相關(guān)文章!
- Java使用easyExcel導(dǎo)出excel數(shù)據(jù)案例
- Java使用EasyExcel動態(tài)添加自增序號列
- Java中Easyexcel?實現(xiàn)批量插入圖片功能
- Java利用EasyExcel實現(xiàn)合并單元格
- Java使用EasyExcel進(jìn)行單元格合并的問題詳解
- Java?easyExcel的復(fù)雜表頭多級表頭導(dǎo)入
- Java利用EasyExcel解析動態(tài)表頭及導(dǎo)出實現(xiàn)過程
- Java使用EasyExcel實現(xiàn)Excel的導(dǎo)入導(dǎo)出
- Java EasyExcel實現(xiàn)導(dǎo)出多sheet并設(shè)置單元格樣式
- Java實現(xiàn)讀取Excel文件功能(EasyExcel初使用)
相關(guān)文章
Springboot使用redisson?+?自定義注解實現(xiàn)消息的發(fā)布訂閱(解決方案)
Redisson是一個基于Redis的Java駐留內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory?Data?Grid)和分布式鎖框架,它提供了一系列的分布式Java對象和服務(wù),可以幫助開發(fā)者更方便地使用Redis作為數(shù)據(jù)存儲和分布式鎖的解決方案,感興趣的朋友跟隨小編一起看看吧2024-05-05Java和MySQL數(shù)據(jù)庫中關(guān)于小數(shù)的保存問題詳析
在Java和MySQL中小數(shù)的精度可能會受到限制,如float類型的小數(shù)只能精確到6-7位,double類型也只能精確到15-16位,這篇文章主要給大家介紹了關(guān)于Java和MySQL數(shù)據(jù)庫中關(guān)于小數(shù)的保存問題,需要的朋友可以參考下2024-01-01三道java新手入門面試題,通往自由的道路--鎖+Volatile
這篇文章主要為大家分享了最有價值的3道多線程面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對hashCode方法的設(shè)計、垃圾收集的堆和代進(jìn)行剖析,感興趣的小伙伴們可以參考一下2021-07-07Springboot解決ajax+自定義headers的跨域請求問題
由于瀏覽器同源策略(同源策略,它是由Netscape提出的一個著名的安全策略,現(xiàn)在所有支持JavaScript 的瀏覽器都會使用這個策略。接下來通過本文給大家介紹Springboot如何優(yōu)雅的解決ajax+自定義headers的跨域請求 ,需要的朋友可以參考下2019-05-05Java非阻塞I/O模型之NIO相關(guān)知識總結(jié)
在了解NIO (Non-Block I/O) 非阻塞I/O模型之前,我們可以先了解一下原始的BIO(Block I/O) 阻塞I/O模型,NIO模型能夠以非阻塞的方式更好的利用服務(wù)器資源,需要的朋友可以參考下2021-05-05