You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

344 lines
11 KiB

package com.alibaba.excel.write.metadata.holder;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.excel.enums.HolderEnum;
import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.data.DataFormatData;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.IoUtils;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.write.metadata.WriteWorkbook;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* Workbook holder
*
* @author Jiaju Zhuang
*/
@Data
@Slf4j
public class WriteWorkbookHolder extends AbstractWriteHolder {
/***
* Current poi Workbook.This is only for writing, and there may be no data in version 07 when template data needs to
* be read.
* <ul>
* <li>03:{@link HSSFWorkbook}</li>
* <li>07:{@link SXSSFWorkbook}</li>
* </ul>
*/
private Workbook workbook;
/***
* Current poi Workbook.Be sure to use and this method when reading template data.
* <ul>
* <li>03:{@link HSSFWorkbook}</li>
* <li>07:{@link XSSFWorkbook}</li>
* </ul>
*/
private Workbook cachedWorkbook;
/**
* current param
*/
private WriteWorkbook writeWorkbook;
/**
* Final output file
* <p>
* If 'outputStream' and 'file' all not empty, file first
*/
private File file;
/**
* Final output stream
*/
private OutputStream outputStream;
/**
* output charset
*/
private Charset charset;
/**
* Template input stream
* <p>
* If 'inputStream' and 'file' all not empty, file first
*/
private InputStream templateInputStream;
/**
* Template file
* <p>
* If 'inputStream' and 'file' all not empty, file first
*/
private File templateFile;
/**
* Temporary template file stream.
* <p>
* A temporary file stream needs to be created in order not to modify the original template file.
*/
private InputStream tempTemplateInputStream;
/**
* Default true
*/
private Boolean autoCloseStream;
/**
* Excel type
*/
private ExcelTypeEnum excelType;
/**
* Mandatory use 'inputStream'
*/
private Boolean mandatoryUseInputStream;
/**
* prevent duplicate creation of sheet objects
*/
private Map<Integer, WriteSheetHolder> hasBeenInitializedSheetIndexMap;
/**
* prevent duplicate creation of sheet objects
*/
private Map<String, WriteSheetHolder> hasBeenInitializedSheetNameMap;
/**
* Whether the encryption
*/
private String password;
/**
* Write excel in memory. Default false, the cache file is created and finally written to excel.
* <p>
* Comment and RichTextString are only supported in memory mode.
*/
private Boolean inMemory;
/**
* Excel is also written in the event of an exception being thrown.The default false.
*/
private Boolean writeExcelOnException;
/**
* Used to cell style.
*/
private Map<Short, Map<WriteCellStyle, CellStyle>> cellStyleIndexMap;
/**
* Used to font.
*/
private Map<WriteFont, Font> fontMap;
/**
* Used to data format.
*/
private Map<DataFormatData, Short> dataFormatMap;
public WriteWorkbookHolder(WriteWorkbook writeWorkbook) {
super(writeWorkbook, null);
this.writeWorkbook = writeWorkbook;
this.file = writeWorkbook.getFile();
if (file != null) {
try {
this.outputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
throw new ExcelGenerateException("Can not found file.", e);
}
} else {
this.outputStream = writeWorkbook.getOutputStream();
}
if (writeWorkbook.getCharset() == null) {
this.charset = Charset.defaultCharset();
} else {
this.charset = writeWorkbook.getCharset();
}
if (writeWorkbook.getAutoCloseStream() == null) {
this.autoCloseStream = Boolean.TRUE;
} else {
this.autoCloseStream = writeWorkbook.getAutoCloseStream();
}
if (writeWorkbook.getExcelType() == null) {
boolean isXls = (file != null && file.getName().endsWith(ExcelTypeEnum.XLS.getValue()))
|| (writeWorkbook.getTemplateFile() != null
&& writeWorkbook.getTemplateFile().getName().endsWith(ExcelTypeEnum.XLS.getValue()));
if (isXls) {
this.excelType = ExcelTypeEnum.XLS;
} else {
boolean isCsv = (file != null && file.getName().endsWith(ExcelTypeEnum.CSV.getValue()))
|| (writeWorkbook.getTemplateFile() != null
&& writeWorkbook.getTemplateFile().getName().endsWith(ExcelTypeEnum.CSV.getValue()));
if (isCsv) {
this.excelType = ExcelTypeEnum.CSV;
} else {
this.excelType = ExcelTypeEnum.XLSX;
}
}
} else {
this.excelType = writeWorkbook.getExcelType();
}
try {
copyTemplate();
} catch (IOException e) {
throw new ExcelGenerateException("Copy template failure.", e);
}
if (writeWorkbook.getMandatoryUseInputStream() == null) {
this.mandatoryUseInputStream = Boolean.FALSE;
} else {
this.mandatoryUseInputStream = writeWorkbook.getMandatoryUseInputStream();
}
this.hasBeenInitializedSheetIndexMap = new HashMap<>();
this.hasBeenInitializedSheetNameMap = new HashMap<>();
this.password = writeWorkbook.getPassword();
if (writeWorkbook.getInMemory() == null) {
this.inMemory = Boolean.FALSE;
} else {
this.inMemory = writeWorkbook.getInMemory();
}
if (writeWorkbook.getWriteExcelOnException() == null) {
this.writeExcelOnException = Boolean.FALSE;
} else {
this.writeExcelOnException = writeWorkbook.getWriteExcelOnException();
}
this.cellStyleIndexMap = MapUtils.newHashMap();
this.fontMap = MapUtils.newHashMap();
this.dataFormatMap = MapUtils.newHashMap();
}
private void copyTemplate() throws IOException {
if (writeWorkbook.getTemplateFile() == null && writeWorkbook.getTemplateInputStream() == null) {
return;
}
if (this.excelType == ExcelTypeEnum.CSV) {
throw new ExcelGenerateException("csv cannot use template.");
}
byte[] templateFileByte = null;
if (writeWorkbook.getTemplateFile() != null) {
templateFileByte = FileUtils.readFileToByteArray(writeWorkbook.getTemplateFile());
} else if (writeWorkbook.getTemplateInputStream() != null) {
try {
templateFileByte = IoUtils.toByteArray(writeWorkbook.getTemplateInputStream());
} finally {
if (autoCloseStream) {
writeWorkbook.getTemplateInputStream().close();
}
}
}
this.tempTemplateInputStream = new ByteArrayInputStream(templateFileByte);
}
@Override
public HolderEnum holderType() {
return HolderEnum.WORKBOOK;
}
/**
* create a cell style.
*
* @param writeCellStyle
* @param originCellStyle
* @return
*/
public CellStyle createCellStyle(WriteCellStyle writeCellStyle, CellStyle originCellStyle) {
if (writeCellStyle == null) {
return originCellStyle;
}
WriteCellStyle tempWriteCellStyle = new WriteCellStyle();
WriteCellStyle.merge(writeCellStyle, tempWriteCellStyle);
short styleIndex = -1;
Font originFont = null;
boolean useCache = true;
if (originCellStyle != null) {
styleIndex = originCellStyle.getIndex();
if (originCellStyle instanceof XSSFCellStyle) {
originFont = ((XSSFCellStyle)originCellStyle).getFont();
} else if (originCellStyle instanceof HSSFCellStyle) {
originFont = ((HSSFCellStyle)originCellStyle).getFont(workbook);
}
useCache = false;
}
Map<WriteCellStyle, CellStyle> cellStyleMap = cellStyleIndexMap.computeIfAbsent(styleIndex,
key -> MapUtils.newHashMap());
CellStyle cellStyle = cellStyleMap.get(tempWriteCellStyle);
if (cellStyle != null) {
return cellStyle;
}
if (log.isDebugEnabled()) {
log.info("create new style:{},{}", tempWriteCellStyle, originCellStyle);
}
cellStyle = StyleUtil.buildCellStyle(workbook, originCellStyle, writeCellStyle);
Short dataFormat = createDataFormat(tempWriteCellStyle.getDataFormatData(), useCache);
if (dataFormat != null) {
cellStyle.setDataFormat(dataFormat);
}
Font font = createFont(tempWriteCellStyle.getWriteFont(), originFont, useCache);
if (font != null) {
cellStyle.setFont(font);
}
cellStyleMap.put(tempWriteCellStyle, cellStyle);
return cellStyle;
}
/**
* create a font.
*
* @param writeFont
* @param originFont
* @param useCache
* @return
*/
public Font createFont(WriteFont writeFont, Font originFont, boolean useCache) {
if (!useCache) {
return StyleUtil.buildFont(workbook, originFont, writeFont);
}
WriteFont tempWriteFont = new WriteFont();
WriteFont.merge(writeFont, tempWriteFont);
Font font = fontMap.get(tempWriteFont);
if (font != null) {
return font;
}
font = StyleUtil.buildFont(workbook, originFont, tempWriteFont);
fontMap.put(tempWriteFont, font);
return font;
}
/**
* create a data format.
*
* @param dataFormatData
* @param useCache
* @return
*/
public Short createDataFormat(DataFormatData dataFormatData, boolean useCache) {
if (dataFormatData == null) {
return null;
}
if (!useCache) {
return StyleUtil.buildDataFormat(workbook, dataFormatData);
}
DataFormatData tempDataFormatData = new DataFormatData();
DataFormatData.merge(dataFormatData, tempDataFormatData);
Short dataFormat = dataFormatMap.get(tempDataFormatData);
if (dataFormat != null) {
return dataFormat;
}
dataFormat = StyleUtil.buildDataFormat(workbook, tempDataFormatData);
dataFormatMap.put(tempDataFormatData, dataFormat);
return dataFormat;
}
}