poi导出excel同一单元格不同内容不同颜色
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);
}
}
}