Java EasyExcel實(shí)現(xiàn)導(dǎo)出多sheet并設(shè)置單元格樣式
前言
最近在做項目時遇到了特殊的Excel導(dǎo)出需求,需要對不同sheet設(shè)置不同樣式,但網(wǎng)上找了很多方法都有問題。在經(jīng)歷一段時間的爬坑之后,終于解決,于是寫這篇文章把他分享出來。
EasyExcel簡介
EasyExcel
是一個基于Java的、快速、簡潔、解決大文件內(nèi)存溢出的Excel處理工具。他能讓你在不用考慮性能、內(nèi)存的等因素的情況下,快速完成Excel的讀、寫等功能。也是目前比較常用的Excel處理工具。
關(guān)于如何讀取和寫入Excel文件,官網(wǎng)教程已經(jīng)很全面,這里不做過多贅述。
需求
假設(shè)我們遇到了這樣一個需求:
現(xiàn)在要導(dǎo)出一個數(shù)碼產(chǎn)品的報表,有手機(jī)和電腦兩大類,需要在表頭統(tǒng)計總價、均價、最高價、最低價,并需要按指標(biāo)對數(shù)據(jù)進(jìn)行特殊處理。
手機(jī):
- 價格 > 5000,字體為紅色;
- CPU 為 曉龍8 Gen3時,單元格高亮為黃色。
電腦:
- 價格 > 10000,字體為紅色;
- 顯卡為4090時,單元格高亮為藍(lán)色。
開始
導(dǎo)入依賴
SpringBoot
依賴自行導(dǎo)入
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency> <!-- hutool 工具集,為了構(gòu)造模擬數(shù)據(jù),具體項目請根據(jù)實(shí)際情況引入 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.22</version> </dependency>
接口
注:為了閱讀簡潔,這里簡化了部分代碼
/** * 導(dǎo)出Excel 接口 * * @param response */ @PostMapping("export") public void exportExcel(HttpServletResponse response) { digitalProductService.exportExcel(response); }
服務(wù)實(shí)現(xiàn)類
首先模擬一部分?jǐn)?shù)據(jù)
package com.penga.demo.service.impl; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.StrUtil; import com.penga.demo.service.IDigitalProductService; import com.penga.demo.util.DigitalProductCellWriteHandler; import com.penga.demo.util.EasyExcelUtils; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @Service public class DigitalProductServiceImpl implements IDigitalProductService { @Override public void exportExcel(HttpServletResponse response) { // 初始化多個sheet List<String> sheetNames = ListUtil.toList("手機(jī)", "電腦"); // 初始化數(shù)據(jù)集 List<List<List<Object>>> dataLists = getDatas(); // 統(tǒng)計數(shù)據(jù) List<BigDecimal> phonePriceList = dataLists.get(0).stream().map(dl -> Convert.toBigDecimal(dl.get(3))).collect(Collectors.toList()); List<BigDecimal> pcPriceList = dataLists.get(1).stream().map(dl -> Convert.toBigDecimal(dl.get(2))).collect(Collectors.toList()); String phoneTotalHeader = getTotalHeader(phonePriceList); String pcTotalHeader = getTotalHeader(pcPriceList); // 初始化每個sheet里面的header List<List<List<String>>> headerLists = getHeaders(phoneTotalHeader, pcTotalHeader); EasyExcelUtils.writeExcelSheets(response, "數(shù)碼產(chǎn)品報表", sheetNames, headerLists, dataLists, new DigitalProductCellWriteHandler()); } private List<List<List<String>>> getHeaders(String phoneTotalHeader, String pcTotalHeader) { String phoneTitle = "手機(jī)-統(tǒng)計報表"; String pcTitle = "電腦-統(tǒng)計報表"; List<List<List<String>>> headerLists = new ArrayList<>(); List<List<String>> headerList1 = new ArrayList<>(); headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "序號")); headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "型號")); headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "上市日期")); headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "價格")); headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "CPU")); headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "RAM容量")); headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "ROM容量")); List<List<String>> headerList2 = new ArrayList<>(); headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "序號")); headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "配置")); headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "價格")); headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "CPU")); headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "顯卡")); headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "內(nèi)存")); headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "硬盤容量")); headerLists.add(headerList1); headerLists.add(headerList2); return headerLists; } private String getTotalHeader(List<BigDecimal> priceList) { BigDecimal sum = priceList.stream().reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal avg = sum.divide(new BigDecimal(priceList.size()), 2, RoundingMode.HALF_UP); BigDecimal max = priceList.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ZERO); BigDecimal min = priceList.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ZERO); return StrUtil.format("總價:{} 均價:{}\n最高價:{} 最低價:{}", sum, avg, max, min); } private List<List<List<Object>>> getDatas() { List<List<List<Object>>> dataLists = new ArrayList<>(); // dataList 的順序一定要與 headerList 的順序一一對應(yīng) List<List<Object>> dataList1 = new ArrayList<>(); dataList1.add(ListUtil.toList(1, "iQOO 12 Pro", "2023年11月7日", new BigDecimal("4999.00"), "高通 驍龍8 Gen3", "16GB", "256GB")); dataList1.add(ListUtil.toList(2, "小米14 Pro", "2023年10月31日", new BigDecimal("5499.00"), "高通 驍龍8 Gen3", "16GB", "512GB")); dataList1.add(ListUtil.toList(3, "HUAWEI Mate 60 Pro", "2023年8月29日", new BigDecimal("6999.00"), "海思 麒麟 9000s", "12GB", "512GB")); dataList1.add(ListUtil.toList(4, "蘋果iPhone 15 Pro", "2023年09月22日", new BigDecimal("10999.00"), "蘋果 A17 Pro", "8GB", "256GB")); dataList1.add(ListUtil.toList(5, "vivo X90s", "2023年06月30日", new BigDecimal("4099.00"), "聯(lián)發(fā)科 天璣9200+", "12GB", "512GB")); dataLists.add(dataList1); List<List<Object>> dataList2 = new ArrayList<>(); dataList2.add(ListUtil.toList(1, "配置1", new BigDecimal("5199.00"), "Intel 酷睿 i5 13400F", "RTX 4060", "16GB", "固態(tài)硬盤 1TB")); dataList2.add(ListUtil.toList(2, "配置2", new BigDecimal("17599.00"), "Intel 酷睿 i9 14900KF", "RTX 4080", "32GB", "機(jī)械硬盤 1TB")); dataList2.add(ListUtil.toList(3, "配置3", new BigDecimal("30999.00"), "Intel 酷睿 i9 14900KF", "RTX 4090", "32GB", "固態(tài)硬盤 2TB")); dataLists.add(dataList2); return dataLists; } }
這里針對幾個list
進(jìn)行說明
List<String> sheetNames
顯而易見,就是創(chuàng)建多個 sheetList<List<List<String>>> headerLists
最外層 list 代表每個 sheet 創(chuàng)建一個 header,第二層 list 代表橫向的 header,第三層 list 代表縱向的。EasyExcel
會將第二層 list 中的每個三層 list 元素同序(index)相等的字符進(jìn)行合并,利用這個特性可以很方便的創(chuàng)建多級表頭。List<List<List<Object>>> dataLists
同樣的,最外層 list 代表每個 sheet 里的數(shù)據(jù),第二層 list 代表縱向每行的數(shù)據(jù),第三層 list 代表單元格的數(shù)據(jù)
Excel導(dǎo)出工具
package com.penga.demo.util; import cn.hutool.core.collection.CollectionUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; import com.alibaba.excel.write.handler.WriteHandler; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import org.apache.poi.ss.usermodel.*; import org.springframework.http.MediaType; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; public class EasyExcelUtils { /** * @param response 返回 * @param fileName 文件名 * @param sheetNames sheet集合 * @param headerLists 表頭集合 * @param dataLists 數(shù)據(jù)集合 * @param writeHandler 自定義樣式 */ public static void writeExcelSheets(HttpServletResponse response, String fileName, List<String> sheetNames, List<List<List<String>>> headerLists, List<List<List<Object>>> dataLists, WriteHandler writeHandler) { ServletOutputStream out = null; try { out = getOut(response, fileName); sheetNames = sheetNames.stream().distinct().collect(Collectors.toList()); int num = sheetNames.size(); // 設(shè)置基礎(chǔ)樣式 HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(getHeadStyle(), getContentStyle()); ExcelWriter excelWriter = EasyExcel.write(out).build(); for (int i = 0; i < num; i++) { ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(i, sheetNames.get(i)).head(headerLists.get(i)) // 自動列寬(按實(shí)際情況加入) .registerWriteHandler(new CustomHandler()) .registerWriteHandler(horizontalCellStyleStrategy); if (Objects.nonNull(writeHandler)) { // 自定義樣式設(shè)置 sheetBuilder.registerWriteHandler(writeHandler); } WriteSheet writeSheet = sheetBuilder.build(); if (CollectionUtil.isEmpty(dataLists)) { excelWriter.write(new ArrayList<>(), writeSheet); } else { excelWriter.write(dataLists.get(i), writeSheet); } } excelWriter.finish(); } catch (Exception e) { e.printStackTrace(); } finally { if (Objects.nonNull(out)) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } private static ServletOutputStream getOut(HttpServletResponse response, String fileName) throws Exception { fileName = fileName + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ExcelTypeEnum.XLSX.getValue(); setAttachmentResponseHeader(response, fileName); response.setCharacterEncoding("utf-8"); response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE); response.setContentType("application/vnd.ms-excel;charset=utf-8"); return response.getOutputStream(); } /** * 下載文件名重新編碼 * * @param response 響應(yīng)對象 * @param realFileName 真實(shí)文件名 * @return */ public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException { String percentEncodedFileName = percentEncode(realFileName); String contentDispositionValue = "attachment; filename=" + percentEncodedFileName + ";filename*=utf-8''" + percentEncodedFileName; response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); response.setHeader("Content-Disposition", contentDispositionValue); } /** * 百分號編碼工具方法 * * @param s 需要百分號編碼的字符串 * @return 百分號編碼后的字符串 */ public static String percentEncode(String s) throws UnsupportedEncodingException { String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); return encode.replaceAll("\+", "%20"); } /** * 頭部樣式 */ private static WriteCellStyle getHeadStyle() { // 頭的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景顏色 headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); headWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); // 字體 WriteFont headWriteFont = new WriteFont(); //設(shè)置字體名字 headWriteFont.setFontName("微軟雅黑"); //設(shè)置字體大小 headWriteFont.setFontHeightInPoints((short) 10); //字體加粗 headWriteFont.setBold(false); //在樣式用應(yīng)用設(shè)置的字體 headWriteCellStyle.setWriteFont(headWriteFont); // 邊框樣式 setBorderStyle(headWriteCellStyle); //設(shè)置自動換行 headWriteCellStyle.setWrapped(true); //設(shè)置水平對齊的樣式為居中對齊 headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); //設(shè)置垂直對齊的樣式為居中對齊 headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //設(shè)置文本收縮至合適 // headWriteCellStyle.setShrinkToFit(true); return headWriteCellStyle; } /** * 內(nèi)容樣式 */ private static WriteCellStyle getContentStyle() { // 內(nèi)容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); // 背景白色 // 這里需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無法顯示背景顏色.頭默認(rèn)了 FillPatternType所以可以不指定 contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); // 設(shè)置字體 WriteFont contentWriteFont = new WriteFont(); //設(shè)置字體大小 contentWriteFont.setFontHeightInPoints((short) 10); //設(shè)置字體名字 contentWriteFont.setFontName("宋體"); //在樣式用應(yīng)用設(shè)置的字體 contentWriteCellStyle.setWriteFont(contentWriteFont); //設(shè)置樣式 setBorderStyle(contentWriteCellStyle); // 水平居中 contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); // 垂直居中 contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //設(shè)置自動換行 contentWriteCellStyle.setWrapped(true); //設(shè)置單元格格式是:文本格式,方式長數(shù)字文本科學(xué)計數(shù)法 // contentWriteCellStyle.setDataFormatData(); //設(shè)置文本收縮至合適 // contentWriteCellStyle.setShrinkToFit(true); return contentWriteCellStyle; } /** * 邊框樣式 */ private static void setBorderStyle(WriteCellStyle cellStyle) { //設(shè)置底邊框 cellStyle.setBorderBottom(BorderStyle.THIN); //設(shè)置底邊框顏色 cellStyle.setBottomBorderColor(IndexedColors.BLACK1.getIndex()); //設(shè)置左邊框 cellStyle.setBorderLeft(BorderStyle.THIN); //設(shè)置左邊框顏色 cellStyle.setLeftBorderColor(IndexedColors.BLACK1.getIndex()); //設(shè)置右邊框 cellStyle.setBorderRight(BorderStyle.THIN); //設(shè)置右邊框顏色 cellStyle.setRightBorderColor(IndexedColors.BLACK1.getIndex()); //設(shè)置頂邊框 cellStyle.setBorderTop(BorderStyle.THIN); //設(shè)置頂邊框顏色 cellStyle.setTopBorderColor(IndexedColors.BLACK1.getIndex()); } }
自定義樣式
如果要設(shè)置其他樣式,可以在評論區(qū)提出來,或閱讀源碼。
package com.penga.demo.util; 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.*; import java.util.List; public class DigitalProductCellWriteHandler implements CellWriteHandler { @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { int rowIndex = cell.getRowIndex(); int columnIndex = cell.getColumnIndex(); String sheetName = cell.getSheet().getSheetName(); if (rowIndex == 1 && columnIndex == 0) { // 設(shè)置表頭統(tǒng)計的樣式,由于單元格是合并的,只設(shè)置第一列就行了 setTotalStyle(writeSheetHolder, cellDataList, cell); return; } if (!isHead) { // 內(nèi)容樣式處理 Workbook workbook = cell.getSheet().getWorkbook(); if (sheetName.equals("手機(jī)")) { // 判斷是否為”手機(jī)“sheet if (columnIndex == 3) { // 判斷價格 // 注意,這里的 cell.get**Value 有多個方法,一定要準(zhǔn)確,否則會報錯,報錯后不會再進(jìn)入這個攔截器,直接導(dǎo)出了 // 如果無法準(zhǔn)確判斷應(yīng)該用哪個 getValue,可以 debug 測試 double value = cell.getNumericCellValue(); if (value > 5000.00) { // 字體樣式改為紅色 CellStyle cellStyle = getContentCellStyle(workbook, IndexedColors.WHITE.getIndex(), IndexedColors.RED.getIndex()); //設(shè)置當(dāng)前單元格樣式 cell.setCellStyle(cellStyle); // 這里要把 WriteCellData的樣式清空 // 不然后面還有一個攔截器 FillStyleCellWriteHandler 默認(rèn)會將 WriteCellStyle 設(shè)置到cell里面去 會導(dǎo)致自己設(shè)置的不一樣 cellDataList.get(0).setWriteCellStyle(null); } } else if (columnIndex == 4) { // 判斷CPU String value = cell.getStringCellValue(); if (value.contains("驍龍8 Gen3")) { // 背景改為黃色 CellStyle cellStyle = getContentCellStyle(workbook, IndexedColors.YELLOW.getIndex(), IndexedColors.BLACK.getIndex()); cell.setCellStyle(cellStyle); cellDataList.get(0).setWriteCellStyle(null); } } } else { // ”電腦“sheet if (columnIndex == 2) { // 判斷價格 double value = cell.getNumericCellValue(); if (value > 10000.00) { // 字體樣式改為紅色 CellStyle cellStyle = getContentCellStyle(workbook, IndexedColors.WHITE.getIndex(), IndexedColors.RED.getIndex()); cell.setCellStyle(cellStyle); cellDataList.get(0).setWriteCellStyle(null); } } else if (columnIndex == 4) { String value = cell.getStringCellValue(); if (value.contains("RTX 4090")) { // 背景改為藍(lán)色 CellStyle cellStyle = getContentCellStyle(workbook, IndexedColors.LIGHT_BLUE.getIndex(), IndexedColors.BLACK.getIndex()); cell.setCellStyle(cellStyle); cellDataList.get(0).setWriteCellStyle(null); } } } } } private CellStyle getContentCellStyle(Workbook workbook, short ffColorIndex, short fontColorIndex) { // 單元格策略 CellStyle cellStyle = workbook.createCellStyle(); // 設(shè)置背景顏色 cellStyle.setFillForegroundColor(ffColorIndex); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 設(shè)置垂直居中為居中對齊 cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 設(shè)置左右對齊為居中對齊 cellStyle.setAlignment(HorizontalAlignment.CENTER); // 自動換行 cellStyle.setWrapText(true); // 設(shè)置邊框 setBorderStyle(cellStyle); // 字體 Font font = workbook.createFont(); //設(shè)置字體名字 font.setFontName("宋體"); //設(shè)置字體大小 font.setFontHeightInPoints((short) 10); // 設(shè)置字體顏色 font.setColor(fontColorIndex); //字體加粗 font.setBold(false); //在樣式用應(yīng)用設(shè)置的字體 cellStyle.setFont(font); return cellStyle; } private void setTotalStyle(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell) { Workbook workbook = cell.getSheet().getWorkbook(); //設(shè)置行高 writeSheetHolder.getSheet().getRow(cell.getRowIndex()).setHeight((short) (1.4 * 256 * 2)); // 單元格策略 CellStyle cellStyle = workbook.createCellStyle(); // 設(shè)置背景顏色灰色 cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 設(shè)置垂直居中為居中對齊 cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 設(shè)置左右對齊為靠右對齊 cellStyle.setAlignment(HorizontalAlignment.RIGHT); // 自動換行 cellStyle.setWrapText(true); // 設(shè)置邊框 setBorderStyle(cellStyle); // 字體 Font font = workbook.createFont(); //設(shè)置字體名字 font.setFontName("微軟雅黑"); //設(shè)置字體大小 font.setFontHeightInPoints((short) 10); //字體加粗 font.setBold(false); //在樣式用應(yīng)用設(shè)置的字體 cellStyle.setFont(font); //設(shè)置當(dāng)前單元格樣式 cell.setCellStyle(cellStyle); // 這里要把 WriteCellData的樣式清空 // 不然后面還有一個攔截器 FillStyleCellWriteHandler 默認(rèn)會將 WriteCellStyle 設(shè)置到cell里面去 會導(dǎo)致自己設(shè)置的不一樣 cellDataList.get(0).setWriteCellStyle(null); } /** * 邊框樣式 */ private static void setBorderStyle(CellStyle cellStyle) { //設(shè)置底邊框 cellStyle.setBorderBottom(BorderStyle.THIN); //設(shè)置底邊框顏色 cellStyle.setBottomBorderColor(IndexedColors.BLACK1.getIndex()); //設(shè)置左邊框 cellStyle.setBorderLeft(BorderStyle.THIN); //設(shè)置左邊框顏色 cellStyle.setLeftBorderColor(IndexedColors.BLACK1.getIndex()); //設(shè)置右邊框 cellStyle.setBorderRight(BorderStyle.THIN); //設(shè)置右邊框顏色 cellStyle.setRightBorderColor(IndexedColors.BLACK1.getIndex()); //設(shè)置頂邊框 cellStyle.setBorderTop(BorderStyle.THIN); //設(shè)置頂邊框顏色 cellStyle.setTopBorderColor(IndexedColors.BLACK1.getIndex()); } }
設(shè)置自定義樣式后,一定要將原來的樣式清空(cellDataList.get(0).setWriteCellStyle(null);
),否則會導(dǎo)致自定義的樣式設(shè)置不進(jìn)去
自動列寬
這個方法也不太準(zhǔn)確,有的情況下列會特別寬,如果有更好的方法,歡迎在評論區(qū)指出
package com.penga.demo.util; import cn.hutool.core.collection.CollectionUtil; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy; import org.apache.poi.ss.usermodel.Cell; import java.util.HashMap; import java.util.List; import java.util.Map; public class CustomHandler extends AbstractColumnWidthStyleStrategy { /** * 最大列寬 */ private static final int MAX_COLUMN_WIDTH = 255; private static final Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>(8); public CustomHandler() { } @Override protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { boolean needSetWidth = isHead || !CollectionUtil.isEmpty(cellDataList); if (isHead) { // 如果不是最后一個表頭,則不改變列寬 List<String> headNameList = head.getHeadNameList(); if (CollectionUtil.isNotEmpty(headNameList)) { int size = headNameList.size(); if (!cell.getStringCellValue().equals(headNameList.get(size - 1))) { return; } } } if (needSetWidth) { Map<Integer, Integer> maxColumnWidthMap = CACHE.computeIfAbsent(writeSheetHolder.getSheetNo(), k -> new HashMap<>(16)); Integer columnWidth = this.dataLength(cellDataList, cell, isHead); if (columnWidth >= 0) { if (columnWidth > MAX_COLUMN_WIDTH) { columnWidth = MAX_COLUMN_WIDTH; } Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex()); if (maxColumnWidth == null || columnWidth > maxColumnWidth) { maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth); writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256); } } } } private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) { if (isHead) { return cell.getStringCellValue().getBytes().length; } else { WriteCellData<?> cellData = cellDataList.get(0); CellDataTypeEnum type = cellData.getType(); if (type == null) { return -1; } else { switch (type) { case STRING: return cellData.getStringValue().getBytes().length; case BOOLEAN: return cellData.getBooleanValue().toString().getBytes().length; case NUMBER: return cellData.getNumberValue().toString().getBytes().length; case DATE: return cellData.getDateValue().toString().getBytes().length; default: return -1; } } } } }
導(dǎo)出
使用API調(diào)試工具發(fā)送請求:
最終的導(dǎo)出效果如下:
以上就是Java EasyExcel實(shí)現(xiàn)導(dǎo)出多sheet并設(shè)置單元格樣式的詳細(xì)內(nèi)容,更多關(guān)于Java EasyExcel導(dǎo)出sheet的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
mybatis實(shí)現(xiàn)動態(tài)升降序的問題小結(jié)
文章介紹了如何在MyBatis的XML文件中實(shí)現(xiàn)動態(tài)排序,使用$符號而不是#符號來引用變量,以避免SQL注入,同時,強(qiáng)調(diào)了在Java代碼中進(jìn)行防注入處理的重要性,感興趣的朋友一起看看吧2025-02-02徹底解決IDEA中SpringBoot熱部署無效的問題(推薦)
這篇文章主要介紹了徹底解決IDEA中SpringBoot熱部署無效的問題,本文給大家?guī)韱栴}原因分析通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-09-09Java多線程實(shí)現(xiàn)模擬12306火車站售票系統(tǒng)
12360火車票售票系統(tǒng)基本上大家都用過,那你知道是怎么實(shí)現(xiàn)的嗎,今天我們就模擬12306火車站售票系統(tǒng)來實(shí)現(xiàn),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05Spring Security自定義登錄原理及實(shí)現(xiàn)詳解
這篇文章主要介紹了Spring Security自定義登錄原理及實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09SpringSecurity實(shí)現(xiàn)前后端分離登錄token認(rèn)證詳解
目前市面上比較流行的權(quán)限框架主要實(shí)Shiro和Spring Security,這兩個框架各自側(cè)重點(diǎn)不同,各有各的優(yōu)劣,本文將給大家詳細(xì)介紹SpringSecurity如何實(shí)現(xiàn)前后端分離登錄token認(rèn)證2023-06-06Spring BPP中如何優(yōu)雅的創(chuàng)建動態(tài)代理Bean詳解
這篇文章主要給大家介紹了關(guān)于Spring BPP中如何優(yōu)雅的創(chuàng)建動態(tài)代理Bean的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03SpringBoot高級配置之臨時屬性、配置文件、日志、多環(huán)境配置詳解
這篇文章主要介紹了SpringBoot高級配置之臨時屬性、配置文件、日志、多環(huán)境配置,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-02-02