poi匯出excel同一單元格不同內容不同顏色
阿新 • • 發佈:2022-03-08
poi
匯出excel
同一單元格不同內容不同顏色
今天做匯出報告功能,產品要求同一個單元格,不同內容顯示不同的顏色。百度找了下,還真發現有這樣的實現。
要求效果如下:
其實實現起來也很簡單,和我們正常使用excel去編輯文字類似,我們給指定的文字設定一個字型樣式就行了。
// 建立一個富文字 XSSFRichTextString xssfRichTextString = new XSSFRichTextString(realText); // 建立一個字型樣式 XSSFFont font = (XSSFFont)workbook.createFont(); // 建立一個預設顏色下標 DefaultIndexedColorMap defaultIndexedColorMap = new DefaultIndexedColorMap(); // 建立一個顏色 XSSFColor xssfColor = new XSSFColor(new java.awt.Color(Integer.parseInt(color.substring(1), 16)),defaultIndexedColorMap); // 給字型樣式設定顏色 font.setColor(xssfColor); // 給部分字型應用顏色 xssfRichTextString.applyFont(startIndex, endIndex, font); // 給單元格賦值 cell.setCellValue(xssfRichTextString);
是不是很簡單,但是要注意,這裡我只是提供了2007版的excel的程式碼,如果你要相容2003版,需要自己修改生成顏色color的程式碼了,其原理都是一樣的。
完整工具類程式碼:
import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.RichTextString; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.poi.xssf.usermodel.XSSFColor; import org.apache.poi.xssf.usermodel.XSSFFont; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 生成excel工具類 */ public class ExcelUtil { /** * 測試 */ public static void main(String[] args) throws IOException { File file; OutputStream outputStream = new FileOutputStream("D:\\Desktop\\1.xlsx"); Map<String, List<Object[]>> sheetDataMap = new HashMap<>(); Map<String, Integer> dataBeginIndexMap = new HashMap<>(); Map<String, List<String[]>> mergeConfigs = new HashMap<>(); boolean b = true; String sheetName = "第一個sheet表"; sheetDataMap.put(sheetName,Arrays.asList(new Object[]{"序號", "統計結果"}, new Object[]{"1", "###$#27bb15$正常(1)$$###、###$#de0de1$異常(3)$$###"})); dataBeginIndexMap.put(sheetName, 2); mergeConfigs.put(sheetName, Arrays.asList(new String[]{"0","1","0","0","廣東省","l"},new String[]{"0","1","1","1","廣州市","c"})); ExcelUtil.exportExcelXLSX(outputStream,sheetDataMap,dataBeginIndexMap,mergeConfigs,b); } /** * 匯出excel,可以有多個sheet工作表 * @param outputStream 輸出流,用於接收excel * @param sheetDataMap 資料集,key為sheet的名字,value為sheet的資料列表。 * 單元格內容有這種格式:###$顏色$內容文字$$###,例如:###$#9922ff$這裡是單元格的值$$###,則這段文字會被加上指定顏色。 * @param dataBeginIndexMap sheetDataMap從excel的哪一行開始填充,從0開始,key為sheet的名字,與sheetDataMap的key對應 * @param mergeConfigs 合併單元格配置,key為sheet的名字,與sheetDataMap的key對應。value為合併單元格配置。 * 例如[["0","2","0","2","第一個合併單元格"], ["3","5","0","2","第二個合併單元格","l"]] * ,表示第一個單元格合併(A1,A2,A3,B1,B2,B3,C1,C2,C3)9個單元格,預設內容居中。第二個單元格合併(D1,D2,D3,E1,E2,E3,F1,F2,F3)9個單元格,內容居左。 * ["0","2","0","2","第一個合併單元格","內容對齊方式"]對應[起始列, 終止列,起始行, 終止行, 單元格內容, 內容對齊方式(c-居中,l-居左,r-居右)] * 內容對齊方式可以不填,只有5個元素 * @param isFlushAndCloseStream 是否重新整理和關閉輸出流,如果是false,需要外層自己關閉 */ public static void exportExcelXLSX(OutputStream outputStream, Map<String, List<Object[]>> sheetDataMap, Map<String, Integer> dataBeginIndexMap , Map<String, List<String[]>> mergeConfigs, boolean isFlushAndCloseStream) throws IOException { // 建立工作簿物件 XSSFWorkbook workbook = new XSSFWorkbook(); // 遍歷建立每個工作表 Set<Map.Entry<String, List<Object[]>>> entrySet = sheetDataMap.entrySet(); int sheetIndex = 0; for (Map.Entry<String, List<Object[]>> sheetData : entrySet) { int dataBeginIndex = dataBeginIndexMap.getOrDefault(sheetData.getKey(), 0); // 建立工作表物件 XSSFSheet sheet = workbook.createSheet(); short height = 18; sheet.setDefaultRowHeightInPoints(height); workbook.setSheetName(sheetIndex++, sheetData.getKey()); // 建立資料行 XSSFCellStyle cellStyle = workbook.createCellStyle(); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 放資料 for (Object[] datas : sheetData.getValue()) { XSSFRow newRow = sheet.createRow(dataBeginIndex++); for (int j = 0; j < datas.length; j++) { String cellValue = datas[j] == null ? "" : datas[j].toString(); XSSFRichTextString xssfRichTextString = setColor(cellValue, workbook); newRow.createCell(j).setCellValue(xssfRichTextString); newRow.getCell(j).setCellStyle(cellStyle); } } // 設定表格頭,合併單元格 List<String[]> mergeCellList = mergeConfigs.getOrDefault(sheetData.getKey(), new LinkedList<>()); for (String[] mergeCell : mergeCellList) { String cellValue = mergeCell[4] == null ? "" : mergeCell[4].toString(); XSSFRichTextString xssfRichTextString = setColor(cellValue, workbook); mergeCell(sheet, Integer.valueOf(mergeCell[0]), Integer.valueOf(mergeCell[1]) , Integer.valueOf(mergeCell[2]), Integer.valueOf(mergeCell[3]), cellValue, xssfRichTextString, mergeCell.length <= 5 ? null : mergeCell[5]); } //設定自動列寬 if (!sheetData.getValue().isEmpty()) { for (int i = 0, size = sheetData.getValue().size(); i < size; i++) { sheet.autoSizeColumn(i); sheet.autoSizeColumn(i, true); sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 15 / 10); } } } // 寫Excel workbook.write(outputStream); // 關閉流 if (isFlushAndCloseStream) { outputStream.flush(); outputStream.close(); } } /** * 設定單元格文字顏色,可以實現一個單元格內多種顏色,只針對2007版的xlsx,不相容2003版的xls * @param cellValue 單元格文字,###$顏色$內容文字$$###,例如:###$#9922ff$這裡是單元格的值$$###,則這段文字會被加上指定顏色。 * @param workbook * @return * @author chc * @date 2022-02-18 */ private static XSSFRichTextString setColor(String cellValue, XSSFWorkbook workbook){ // 捕獲顏色和文字內容 Pattern colorTextPattern = Pattern.compile("###\\$(#[0-9a-fA-F]{6})\\$([\\s\\S]+?)\\$\\$###"); // 捕獲顏色 Pattern colorPattern = Pattern.compile("###\\$(#[0-9a-fA-F]{6})\\$"); if (!colorTextPattern.matcher(cellValue).find()) { return new XSSFRichTextString(cellValue); } // 真實文字 String realText = colorPattern.matcher(cellValue).replaceAll("").replaceAll("\\$\\$###", ""); XSSFRichTextString xssfRichTextString = new XSSFRichTextString(realText); // 判斷顏色 Matcher matcher = colorTextPattern.matcher(cellValue); int startIndex = 0, endIndex = 0; while (matcher.find( )) { String color = matcher.group(1); String text = matcher.group(2); XSSFFont font = (XSSFFont)workbook.createFont(); DefaultIndexedColorMap defaultIndexedColorMap = new DefaultIndexedColorMap(); XSSFColor xssfColor = new XSSFColor(new java.awt.Color(Integer.parseInt(color.substring(1), 16)),defaultIndexedColorMap); font.setColor(xssfColor); // 文字位置 startIndex = realText.indexOf( text, startIndex); endIndex = startIndex + text.length(); xssfRichTextString.applyFont(startIndex, endIndex, font); } return xssfRichTextString; } /** * 合併單元格 * @param sheet * @param startCol 起始列,下標從0開始 * @param endCol 終止列 * @param startRow 起始行,行下標從0開始 * @param endRow 終止行 * @param text 合併後的單元格文字 * @param richTextString 富文字,如果不為空,單元格就填充richTextString。如果為空,單元格就填充text * @param align 文字對齊方式(c-居中,l-居左,r-居右),大小寫不區分,預設居中 * @author chc * @date 2020-12-22 */ @SuppressWarnings("unused") private static void mergeCell(Sheet sheet, int startCol, int endCol, int startRow, int endRow, String text, RichTextString richTextString, String align) { boolean isMerged = false; if (startRow == endRow && startCol == endCol) { // 如果只是一個單元格,沒必要合併 isMerged = false; } else { // 建立合併單元格 CellRangeAddress cra = new CellRangeAddress(startRow, endRow, startCol, endCol); sheet.addMergedRegion(cra); isMerged = true; } // 設定單元格文字 Row row = sheet.getRow(startRow) == null ? sheet.createRow(startRow) : sheet.getRow(startRow); Cell cell = row.getCell(startCol) == null ? row.createCell(startCol) : row.getCell(startCol); if (isMerged) { //合併的單元格樣式 CellStyle style = sheet.getWorkbook().createCellStyle(); //設定居中 style.setVerticalAlignment(VerticalAlignment.CENTER); if (StringUtils.isNotBlank(align)) { if ("l".equalsIgnoreCase(align)) { style.setAlignment(HorizontalAlignment.LEFT); } else if ("r".equalsIgnoreCase(align)) { style.setAlignment(HorizontalAlignment.RIGHT); } else { style.setAlignment(HorizontalAlignment.CENTER); } } else { style.setAlignment(HorizontalAlignment.CENTER); } cell.setCellStyle(style); } // 填單元格內容 if (Objects.nonNull(richTextString)){ cell.setCellValue(richTextString); }else{ cell.setCellValue(text); } } }