使用springboot+easyexcel實現導出excel并合并指定單元格

1:準備一個單元格合并策略類代碼:

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
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 final int[] mergeColumnIndex;// 合并開始的行索引private final int mergeRowIndex;/*** 構造函數** @param mergeRowIndex     合并開始的行索引* @param mergeColumnIndex  要合并的列索引數組*/public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {this.mergeRowIndex = mergeRowIndex;this.mergeColumnIndex = mergeColumnIndex;}@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {// 單元格創建前的處理(這里不需要處理)}@Overridepublic void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 單元格創建后的處理(這里不需要處理)}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 當前行索引int curRowIndex = cell.getRowIndex();// 當前列索引int curColIndex = cell.getColumnIndex();// 如果當前行大于合并開始行且當前列在需要合并的列中if (curRowIndex > mergeRowIndex && isMergeColumn(curColIndex)) {// 進行合并操作mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);}}/*** 檢查當前列是否在需要合并的列中** @param curColIndex 當前列索引* @return 如果是需要合并的列返回true,否則返回false*/private boolean isMergeColumn(int curColIndex) {for (int columnIndex : mergeColumnIndex) {if (curColIndex == columnIndex) {return true;}}return false;}/*** 當前單元格向上合并** @param writeSheetHolder 當前工作表持有者* @param cell             當前單元格* @param curRowIndex      當前行索引* @param curColIndex      當前列索引*/private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {// 獲取當前單元格的數據Object curData = getCellData(cell);// 獲取前一個單元格的數據Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);Object preData = getCellData(preCell);// 判斷當前單元格和前一個單元格的數據以及主鍵是否相同if (curData.equals(preData) && isSamePrimaryKey(cell, curRowIndex)) {// 獲取工作表Sheet sheet = writeSheetHolder.getSheet();// 合并單元格mergeCells(sheet, curRowIndex, curColIndex);}}/*** 獲取單元格的數據** @param cell 單元格* @return 單元格數據*/private Object getCellData(Cell cell) {return cell.getCellType() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();}/*** 判斷當前單元格和前一個單元格的主鍵是否相同** @param cell         當前單元格* @param curRowIndex  當前行索引* @return 如果主鍵相同返回true,否則返回false*/private boolean isSamePrimaryKey(Cell cell, int curRowIndex) {String currentPrimaryKey = cell.getRow().getCell(0).getStringCellValue();String previousPrimaryKey = cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue();return currentPrimaryKey.equals(previousPrimaryKey);}/*** 合并單元格** @param sheet        工作表* @param curRowIndex  當前行索引* @param curColIndex  當前列索引*/private void mergeCells(Sheet sheet, int curRowIndex, int curColIndex) {// 獲取已合并的區域List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();boolean isMerged = false;// 檢查前一個單元格是否已經被合并for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {CellRangeAddress cellRangeAddr = mergeRegions.get(i);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);}}
}


2:業務類實現代碼:
?

    //從第2行開始合并private static final int mergeRowIndex=1;//需要合并的單元格列private static final int[] mergeCols={0,1,2,3,4,5,6,7,8,9,10,11,12};@Overridepublic void exportBillOfQuantity(BillOfQuantityExportDto exportDto, HttpServletResponse response) {// 設置響應參數setResponseHeader(response, "export-bill-quantities.xlsx_");// 整理需要導出的數據List<ExportBillQuantitiesVo> exportBillQuantitiesVoList = getExportBillQuantitiesVoList(exportDto);try {// 獲取模板文件輸入流InputStream templateStream = new ClassPathResource(GlobalConstants.TEMPLATE_PATH + File.separator + GlobalConstants.EXPORT_BILL_QUANTITIES_FILE_NAME).getInputStream();// 使用EasyExcel寫入數據到HttpServletResponseEasyExcel.write(response.getOutputStream()).registerWriteHandler(setStyle()).registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeCols)).withTemplate(templateStream).sheet().doWrite(exportBillQuantitiesVoList);} catch (IOException e) {log.error("export productCoreParamList data is filed", e);throw new BusinessException(StatusCode.FAILED);}}// 設置響應頭通用方法private void setResponseHeader(HttpServletResponse response, String fileName) {try {String fileNameStr = fileName + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".xls";String encodedFileName = URLEncoder.encode(fileNameStr, StandardCharsets.UTF_8.toString());response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("UTF-8");response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);} catch (Exception e) {log.error("set response header error", e);throw new BusinessException(StatusCode.SYSTEM_ERROR);}}// 設置導出excel文件部分內容樣式private HorizontalCellStyleStrategy setStyle() {// 定義樣式:自動換行WriteCellStyle contentWriteCellStyle = new WriteCellStyle();contentWriteCellStyle.setWrapped(true); // 關鍵:開啟自動換行WriteFont writeFont = new WriteFont();writeFont.setFontName("Microsoft YaHei"); // 字體writeFont.setFontHeightInPoints((short) 12); // 字體大小contentWriteCellStyle.setWriteFont(writeFont);// 注冊樣式策略(全局生效)HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(null, // 頭樣式(默認)contentWriteCellStyle // 內容樣式(自動換行));return styleStrategy;}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78805.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78805.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78805.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python三大Web框架對比:Django、Flask、Tornado的異步實現方式詳解

目錄 引言 一、框架基礎概覽 1.1 Django 1.2 Flask 1.3 Tornado 二、異步編程基礎 2.1 同步 vs 異步 2.2 Python異步演進 三、框架異步實現對比 3.1 Django的異步進化 3.2 Flask的異步擴展 3.3 Tornado的異步范式 四、異步實現差異對比 4.1 實現機制對比 4.2 性…

深入理解Spring AI框架的核心概念

深入理解Spring AI框架的核心概念 前言 在當今人工智能飛速發展的時代&#xff0c;將AI技術集成到應用程序中已成為眾多開發者關注的焦點。Spring AI框架為Java開發者提供了便捷的途徑來實現這一目標。理解其核心概念對于充分發揮框架的潛力至關重要。本文將詳細探討Spring A…

LabVIEW基于VI Server的控件引用操作

本 VI 通過展示控件引用&#xff08;Control References&#xff09;的使用&#xff0c;借助 VI Server 實現對前面板對象的編程操作。 ? 詳細說明 隱式屬性節點&#xff08;Implicitly Linked Property Node&#xff09;&#xff1a;通過右鍵單擊控件&#xff08;或其控件終…

AI 邊緣計算網關十大品牌

引言 在物聯網與人工智能技術飛速發展的當下&#xff0c;數據量呈爆發式增長&#xff0c;對數據處理的實時性、準確性和安全性要求不斷提高。AI邊緣計算網關應運而生&#xff0c;它融合了人工智能、邊緣計算與物聯網技術&#xff0c;在靠近數據源或物理設備的網絡邊緣側&#…

基于深度學習的視頻目標跟蹤算法研究

標題:基于深度學習的視頻目標跟蹤算法研究 內容:1.摘要 隨著視頻數據的爆炸式增長&#xff0c;視頻目標跟蹤在智能監控、自動駕駛、人機交互等領域有著廣泛的應用需求。本文的目的是研究基于深度學習的視頻目標跟蹤算法&#xff0c;以提高跟蹤的準確性和實時性。方法上&#x…

C++代碼隨想錄刷題知識分享-----面試題鏈表相交

一、題目要求 題目&#xff1a;給定兩條單鏈表 headA、headB&#xff0c;找出它們相交的起始節點&#xff08;節點對象相同而非數值相等&#xff09;。若無交點返回 null。 限制&#xff1a;鏈表無環&#xff1b;函數返回后鏈表結構不能被破壞。 圖示兩個鏈表在節點 c1 開始相…

修改輸入框選擇框顏色

項目場景&#xff1a; 提示&#xff1a;這里簡述項目相關背景&#xff1a; 有時候需要改寫element原來輸入框/選擇框的顏色 問題描述 提示&#xff1a;這里描述項目中遇到的問題&#xff1a; 輸入框的話需要hover時邊框顏色修改&#xff0c;選擇值的時候邊框顏色修改以及選…

8.學習筆記-Maven進階(P82-P89)

&#xff08;一&#xff09;Maven-08-配置文件加載屬性 通過maven可以做版本的集中管理&#xff0c;所以能不能通過maven進行配置文件&#xff08;jdbc.properties&#xff09;的集中管理。 &#xff08;1&#xff09;resource-》jdbc.properties 可以識別$符號 因為只能…

基于Springboot+Mysql的漢服推廣網站(含LW+PPT+源碼+系統演示視頻+安裝說明)

系統功能 管理員功能&#xff1a;首頁、個人中心、漢服知識管理、服裝展示管理、服裝類別管理、用戶相冊管理、論壇交流、系統管理、訂單管理&#xff1b;用戶功能&#xff1a;首頁、個人中心、用戶相冊管理、論壇交流、我的收藏管理、訂單管理。 作者&#xff1a;計算機搬磚家…

Missashe考研日記-day30

Missashe考研日記-day30 0 寫在前面 日記也是寫到第30篇了哈哈&#xff0c;滿月了&#xff0c;雖然過了不止30天中間有斷更&#xff0c;但還是表揚一下自己堅持下來了。&#xff1a;&#xff09; 1 專業課408 學習時間&#xff1a;2h30min學習內容&#xff1a; 今天有其他事…

HHsuite同源序列搜索數據庫構建

HHsuite 可用的數據庫格式簡介 HHsuite 是用于蛋白質序列比對和同源性檢測的工具套件,它使用特定的數據庫格式以實現高效的數據存儲和快速的檢索。HHsuite 常用的數據庫格式主要基于 FFINDEX(Flat-File Index),這是一種簡單而高效的文件索引系統,它將數據文件(如蛋白質序…

基于HTML CANVAS和EXCEL的xlsx文件展示工具websheet

什么是WEBSHEET websheet基于HTML5的CANVAS和JAVASCRIPT開發的純前端xlsx文件展示控件&#xff0c;該控件著重的頁面展示&#xff0c;主要完成了文件導入、導出、文本展示、格式化文本、合并單元格、邊框、底色、設置行列寬度高度&#xff0c;行列隱藏、視圖鎖定、基礎表格、撤…

Android Studio for Platform(ASFP)真機調試

連接設備 由于ubuntu連接adb設備每次都需要配置usb權限&#xff0c;很麻煩。并且每次換設備還要重新配置&#xff0c;我多數設備都是用wifi的adb方式連接。 開發板顯示 連接顯示器配合usb鼠標或者遙控器操作&#xff08;因為開發板默認開啟了adb&#xff0c;我這里是使用有線…

基于springboot+vue的健康健身追蹤系統

開發語言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服務器&#xff1a;tomcat7數據庫&#xff1a;mysql 5.7數據庫工具&#xff1a;Navicat11開發軟件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.3.9 系統展示 用戶信息管理 健…

Ubuntu下安裝vsode+qt搭建開發框架(一)

Ubuntu下安裝vsode+qt搭建開發框架(一) g++的編譯環境,這里不介紹,可點擊這里查看 查看一下當前的g++環境 g++ --version g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copyin…

php 需要學會哪些技術棧,掌握哪些框架

作為一個「野生」程序員&#xff0c;我的學習過程比較急功近利。 我記得自己寫的第一個 PHP 程序是留言本。一上來對 PHP 一竅不通&#xff0c;所以直接去網上找了個留言本的源碼&#xff0c;下載下來后先想辦法讓它在自己電腦上運行起來。通過這個過程掌握了 PHP 開發環境的搭…

近期實踐總結

一、計算機二級考試到底教會了我們什么&#xff1f; 1、概況 根據本人復習、考試的經驗&#xff0c;不難發現里面的試題或多或少有些死板&#xff08;甚至可以說落后于時代&#xff09;&#xff0c;當今時代已經不是二十年前什么都需要手搓的時代了&#xff0c;引擎、集成類軟…

js day8

事件綁定 事件&#xff1a;發生在html元素上的特定動作&#xff0c;鼠標點擊&#xff0c;鍵盤按下&#xff0c;鼠標移入 事件三要素&#xff1a;事件源&#xff08;觸發事件的元素&#xff09; 事件類型&#xff0c;事件觸發后執行的函數 通過html觸發事件&#xff08;不建議…

3.3 Spring Boot文件上傳

在 Spring Boot 項目中實現文件上傳功能&#xff0c;首先創建項目并添加依賴&#xff0c;包括 Commons IO 用于文件操作。接著&#xff0c;創建文件上傳控制器 FileUploadController&#xff0c;定義上傳目錄并實現文件上傳邏輯&#xff0c;通過生成唯一文件名避免文件沖突。創…

Spring的xxxAware接口工作原理-筆記

1.Aware 接口的工作原理 Spring 提供了多個 XXXAware 接口&#xff08;如 ApplicationEventPublisherAware、ApplicationContextAware、BeanFactoryAware 等&#xff09;&#xff0c;這些接口的核心作用是讓 Bean 在初始化過程中自動獲取特定的依賴。 實現 Aware 接口的 Bean…