205 lines
7.7 KiB
Java
205 lines
7.7 KiB
Java
package com.engine.salary.util.excel;
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
import com.engine.salary.util.FileUtils;
|
|
import org.apache.poi.ss.usermodel.*;
|
|
import org.apache.poi.ss.util.CellUtil;
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.regex.Pattern;
|
|
|
|
public class ExcelFillUtils {
|
|
|
|
// public static final String FILL_EXPRESSION_REGEX = "\\{\\.\\w+\\}";
|
|
private static final String FILL_EXPRESSION_REGEX = "\\{\\.[\\p{L}\\p{M}\\S]+\\}";
|
|
|
|
|
|
/**
|
|
* 给定模板,指定某个页签,将数据填充到模板中的指定页签,并将数据导入到指定文件上。
|
|
*
|
|
* @param template 模板文件地址
|
|
* @param sheetIndex 页签下标
|
|
* @param data 待填充的数据,数据格式如下
|
|
* [
|
|
* {"colName1":v1 ,"colName2":v2...},
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* ,...
|
|
* ]
|
|
* @return 新生成的副本文件
|
|
*/
|
|
public static XSSFWorkbook fillOneSheet(String template, Integer sheetIndex, List<Map<String, Object>> data) {
|
|
|
|
try {
|
|
XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(template));
|
|
fill(workbook, sheetIndex, data);//填充数据
|
|
return workbook;
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 给定模板,指定某个页签,将数据填充到模板中的指定页签,并将数据导入到指定文件上。
|
|
*
|
|
* @param template 模板文件流
|
|
* @param sheetIndex 页签名称
|
|
* @param data 待填充的数据,数据格式如下
|
|
* [
|
|
* {"colName1":v1 ,"colName2":v2...},
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* ,...
|
|
* ]
|
|
* @return 新生成的副本文件
|
|
*/
|
|
public static XSSFWorkbook fillOneSheet(InputStream template, Integer sheetIndex, List<Map<String, Object>> data) {
|
|
|
|
try{
|
|
XSSFWorkbook workbook = new XSSFWorkbook(template);
|
|
fill(workbook, sheetIndex, data);//填充数据
|
|
return workbook;
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 给定模板,将数据填充到模板中的多个页签,并在模板所在目录生成新的副本文件。
|
|
*
|
|
* @param template 模板文件地址
|
|
* @param datas 待填充的数据集,数据格式如下
|
|
* {
|
|
* "SheetName1":[
|
|
* {"colName1":v1 ,"colName2":v2...},
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* ,...
|
|
* ],
|
|
* "SheetName2":[
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* ,...
|
|
* ],
|
|
* ...
|
|
* }
|
|
*/
|
|
public static String fillMultipleSheet(String template, Map<Integer, List<Map<String, Object>>> datas) {
|
|
return fillMultipleSheet(template, FileUtils.getAvailableFullName(template), datas);
|
|
}
|
|
|
|
/**
|
|
* 给定模板,将数据填充到模板中的多个页签,并将数据导入到指定文件上。
|
|
*
|
|
* @param template 模板文件地址
|
|
* @param datas 待填充的数据集,数据格式如下
|
|
* {
|
|
* "SheetName1":[
|
|
* {"colName1":v1 ,"colName2":v2...},
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* ,...
|
|
* ],
|
|
* "SheetName2":[
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* {"colName1":v1 ,"colName2":v2...}
|
|
* ,...
|
|
* ],
|
|
* ...
|
|
* }
|
|
*/
|
|
public static String fillMultipleSheet(String template, String outputFile, Map<Integer, List<Map<String, Object>>> datas) {
|
|
|
|
try (Workbook workbook = new XSSFWorkbook(new FileInputStream(template))) {
|
|
|
|
datas.forEach((sheetIndex, data) -> fill(workbook, sheetIndex, data));//填充数据
|
|
refreshFormula(workbook);//刷新公式
|
|
|
|
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
|
|
workbook.write(outputStream);
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
|
|
return outputFile;
|
|
}
|
|
|
|
private static Workbook fill(Workbook workbook, int sheetIndex, List<Map<String, Object>> data) {
|
|
|
|
Sheet sheet = workbook.getSheetAt(sheetIndex);
|
|
if (sheet == null) {
|
|
throw new RuntimeException(String.format("sheet [%s] does not exist.", sheetIndex));
|
|
}
|
|
|
|
//找到所有的表达式单元格
|
|
Map<String, Cell> expressionCellMap = new HashMap<>();
|
|
for (int i = 0; i < sheet.getPhysicalNumberOfRows(); i++) {
|
|
Row row = sheet.getRow(i);
|
|
for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {
|
|
Cell cell = row.getCell(j);
|
|
if (!Objects.isNull(cell) && isFillExpression(cell.getStringCellValue())) {//判断该单元格是否是填充公式
|
|
expressionCellMap.put(getColNameFromEx(cell.getStringCellValue()), cell);
|
|
}
|
|
}
|
|
}
|
|
|
|
//填充数据
|
|
for (int i = 0; i < data.size(); i++) {
|
|
Map<String, Object> dataRow = data.get(i);
|
|
for (Map.Entry<String, Object> entry : dataRow.entrySet()) {
|
|
String colName = entry.getKey();
|
|
Object value = entry.getValue();
|
|
if (expressionCellMap.containsKey(colName)) {
|
|
|
|
Cell cell = expressionCellMap.get(colName);//公式所在的单元格
|
|
int rowID = cell.getRowIndex() + i;
|
|
int colId = cell.getColumnIndex();
|
|
|
|
Row fillRow = sheet.getRow(rowID);
|
|
fillRow = Objects.isNull(fillRow) ? sheet.createRow(rowID) : fillRow;
|
|
Cell fillCell = fillRow.getCell(colId);
|
|
//创建的新单元格需要复制公式单元格的格式
|
|
fillCell = Objects.isNull(fillCell) ? CellUtil.createCell(fillRow, colId, "", cell.getCellStyle()) : fillCell;
|
|
|
|
if (value instanceof String) {
|
|
fillCell.setCellValue(String.valueOf(value));
|
|
} else if (value instanceof Number) {
|
|
fillCell.setCellValue(((Number) value).doubleValue());
|
|
} else {
|
|
throw new RuntimeException(String.format("Unsupported data type [%s].", value.getClass().toString()));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return workbook;
|
|
}
|
|
|
|
private static void refreshFormula(Workbook workbook) {
|
|
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
|
evaluator.evaluateAll();
|
|
}
|
|
|
|
private static boolean isFillExpression(String ex) {
|
|
if (StrUtil.isBlank(ex)) {
|
|
return false;
|
|
}
|
|
;
|
|
return Pattern.matches(FILL_EXPRESSION_REGEX, ex);
|
|
}
|
|
|
|
private static String getColNameFromEx(String ex) {
|
|
if (!isFillExpression(ex)) throw new RuntimeException("Illegal expression " + ex);
|
|
return ex.substring(2, ex.length() - 1);
|
|
}
|
|
}
|