Java EasyExcel實(shí)現(xiàn)導(dǎo)出多sheet并設(shè)置單元格樣式
前言
最近在做項(xiàng)目時(shí)遇到了特殊的Excel導(dǎo)出需求,需要對(duì)不同sheet設(shè)置不同樣式,但網(wǎng)上找了很多方法都有問題。在經(jīng)歷一段時(shí)間的爬坑之后,終于解決,于是寫這篇文章把他分享出來(lái)。
EasyExcel簡(jiǎn)介
EasyExcel是一個(gè)基于Java的、快速、簡(jiǎn)潔、解決大文件內(nèi)存溢出的Excel處理工具。他能讓你在不用考慮性能、內(nèi)存的等因素的情況下,快速完成Excel的讀、寫等功能。也是目前比較常用的Excel處理工具。
關(guān)于如何讀取和寫入Excel文件,官網(wǎng)教程已經(jīng)很全面,這里不做過多贅述。
需求
假設(shè)我們遇到了這樣一個(gè)需求:
現(xiàn)在要導(dǎo)出一個(gè)數(shù)碼產(chǎn)品的報(bào)表,有手機(jī)和電腦兩大類,需要在表頭統(tǒng)計(jì)總價(jià)、均價(jià)、最高價(jià)、最低價(jià),并需要按指標(biāo)對(duì)數(shù)據(jù)進(jìn)行特殊處理。
手機(jī):
- 價(jià)格 > 5000,字體為紅色;
- CPU 為 曉龍8 Gen3時(shí),單元格高亮為黃色。
電腦:
- 價(jià)格 > 10000,字體為紅色;
- 顯卡為4090時(shí),單元格高亮為藍(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ù),具體項(xiàng)目請(qǐng)根據(jù)實(shí)際情況引入 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
接口
注:為了閱讀簡(jiǎn)潔,這里簡(jiǎn)化了部分代碼
/**
* 導(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) {
// 初始化多個(gè)sheet
List<String> sheetNames = ListUtil.toList("手機(jī)", "電腦");
// 初始化數(shù)據(jù)集
List<List<List<Object>>> dataLists = getDatas();
// 統(tǒng)計(jì)數(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);
// 初始化每個(gè)sheet里面的header
List<List<List<String>>> headerLists = getHeaders(phoneTotalHeader, pcTotalHeader);
EasyExcelUtils.writeExcelSheets(response, "數(shù)碼產(chǎn)品報(bào)表", sheetNames, headerLists, dataLists, new DigitalProductCellWriteHandler());
}
private List<List<List<String>>> getHeaders(String phoneTotalHeader, String pcTotalHeader) {
String phoneTitle = "手機(jī)-統(tǒng)計(jì)報(bào)表";
String pcTitle = "電腦-統(tǒng)計(jì)報(bào)表";
List<List<List<String>>> headerLists = new ArrayList<>();
List<List<String>> headerList1 = new ArrayList<>();
headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "序號(hào)"));
headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "型號(hào)"));
headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "上市日期"));
headerList1.add(ListUtil.toList(phoneTitle, phoneTotalHeader, "價(jià)格"));
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, "序號(hào)"));
headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "配置"));
headerList2.add(ListUtil.toList(pcTitle, pcTotalHeader, "價(jià)格"));
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("總價(jià):{} 均價(jià):{}\n最高價(jià):{} 最低價(jià):{}", sum, avg, max, min);
}
private List<List<List<Object>>> getDatas() {
List<List<List<Object>>> dataLists = new ArrayList<>();
// dataList 的順序一定要與 headerList 的順序一一對(duì)應(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;
}
}
這里針對(duì)幾個(gè)list進(jìn)行說明
List<String> sheetNames顯而易見,就是創(chuàng)建多個(gè) sheetList<List<List<String>>> headerLists最外層 list 代表每個(gè) sheet 創(chuàng)建一個(gè) header,第二層 list 代表橫向的 header,第三層 list 代表縱向的。EasyExcel會(huì)將第二層 list 中的每個(gè)三層 list 元素同序(index)相等的字符進(jìn)行合并,利用這個(gè)特性可以很方便的創(chuàng)建多級(jí)表頭。List<List<List<Object>>> dataLists同樣的,最外層 list 代表每個(gè) 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))
// 自動(dòng)列寬(按實(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)對(duì)象
* @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);
}
/**
* 百分號(hào)編碼工具方法
*
* @param s 需要百分號(hào)編碼的字符串
* @return 百分號(hào)編碼后的字符串
*/
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è)置自動(dòng)換行
headWriteCellStyle.setWrapped(true);
//設(shè)置水平對(duì)齊的樣式為居中對(duì)齊
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//設(shè)置垂直對(duì)齊的樣式為居中對(duì)齊
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 不然無(wú)法顯示背景顏色.頭默認(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è)置自動(dòng)換行
contentWriteCellStyle.setWrapped(true);
//設(shè)置單元格格式是:文本格式,方式長(zhǎng)數(shù)字文本科學(xué)計(jì)數(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è)置其他樣式,可以在評(píng)論區(qū)提出來(lái),或閱讀源碼。
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)計(jì)的樣式,由于單元格是合并的,只設(shè)置第一列就行了
setTotalStyle(writeSheetHolder, cellDataList, cell);
return;
}
if (!isHead) {
// 內(nèi)容樣式處理
Workbook workbook = cell.getSheet().getWorkbook();
if (sheetName.equals("手機(jī)")) {
// 判斷是否為”手機(jī)“sheet
if (columnIndex == 3) {
// 判斷價(jià)格
// 注意,這里的 cell.get**Value 有多個(gè)方法,一定要準(zhǔn)確,否則會(huì)報(bào)錯(cuò),報(bào)錯(cuò)后不會(huì)再進(jìn)入這個(gè)攔截器,直接導(dǎo)出了
// 如果無(wú)法準(zhǔn)確判斷應(yīng)該用哪個(gè) getValue,可以 debug 測(cè)試
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的樣式清空
// 不然后面還有一個(gè)攔截器 FillStyleCellWriteHandler 默認(rèn)會(huì)將 WriteCellStyle 設(shè)置到cell里面去 會(huì)導(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) {
// 判斷價(jià)格
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è)置垂直居中為居中對(duì)齊
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 設(shè)置左右對(duì)齊為居中對(duì)齊
cellStyle.setAlignment(HorizontalAlignment.CENTER);
// 自動(dòng)換行
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è)置垂直居中為居中對(duì)齊
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 設(shè)置左右對(duì)齊為靠右對(duì)齊
cellStyle.setAlignment(HorizontalAlignment.RIGHT);
// 自動(dòng)換行
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的樣式清空
// 不然后面還有一個(gè)攔截器 FillStyleCellWriteHandler 默認(rèn)會(huì)將 WriteCellStyle 設(shè)置到cell里面去 會(huì)導(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è)置自定義樣式后,一定要將原來(lái)的樣式清空(cellDataList.get(0).setWriteCellStyle(null);),否則會(huì)導(dǎo)致自定義的樣式設(shè)置不進(jìn)去
自動(dòng)列寬
這個(gè)方法也不太準(zhǔn)確,有的情況下列會(huì)特別寬,如果有更好的方法,歡迎在評(píng)論區(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) {
// 如果不是最后一個(gè)表頭,則不改變列寬
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ā)送請(qǐng)求:

最終的導(dǎo)出效果如下:



以上就是Java EasyExcel實(shí)現(xiàn)導(dǎo)出多sheet并設(shè)置單元格樣式的詳細(xì)內(nèi)容,更多關(guān)于Java EasyExcel導(dǎo)出sheet的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)和算法之冒泡排序(動(dòng)力節(jié)點(diǎn)Java學(xué)院整理)
冒泡排序(Bubble Sort)是一種簡(jiǎn)單的排序算法。本文重點(diǎn)給大家介紹java數(shù)據(jù)結(jié)構(gòu)和算法之冒泡排序,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-04-04
使用SpringBoot+Prometheus+Grafana實(shí)現(xiàn)可視化監(jiān)控
本文主要給大家介紹了如何使用Spring?actuator+監(jiān)控組件prometheus+數(shù)據(jù)可視化組件grafana來(lái)實(shí)現(xiàn)對(duì)Spring?Boot應(yīng)用的可視化監(jiān)控,文中有詳細(xì)的代碼供大家參考,具有一定的參考價(jià)值,需要的朋友可以參考下2024-02-02
通過maven給沒有pom文件的jar包生成pom文件,maven項(xiàng)目引入本地jar包方式
這篇文章主要介紹了通過maven給沒有pom文件的jar包生成pom文件,maven項(xiàng)目引入本地jar包方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(10)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧,希望可以幫到你2021-07-07
SpringBoot+React實(shí)現(xiàn)計(jì)算個(gè)人所得稅
本文將以個(gè)人所得稅的計(jì)算為例,使用React+SpringBoot+GcExcel來(lái)實(shí)現(xiàn)這一功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下2023-09-09
Java的動(dòng)態(tài)代理模式之JDK代理詳解
這篇文章主要介紹了Java的動(dòng)態(tài)代理模式之JDK代理詳解,代理對(duì)象,不需要實(shí)現(xiàn)接口,但是目標(biāo)對(duì)象要實(shí)現(xiàn)接口,否則不能用動(dòng)態(tài)代理,JDK?實(shí)現(xiàn)代理只需要使用?newProxyInstance?方法,但是該方法需要接收三個(gè)參數(shù),需要的朋友可以參考下2023-11-11
MyBatis Plus實(shí)現(xiàn)一對(duì)多的查詢場(chǎng)景的三種方法
MyBatis Plus提供了多種簡(jiǎn)便的方式來(lái)進(jìn)行一對(duì)多子查詢,本文主要介紹了MyBatis Plus實(shí)現(xiàn)一對(duì)多的查詢場(chǎng)景的三種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07

