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.
 
 
 
 
 
 

422 lines
19 KiB

package com.xujie.sys.common.utils;
import lombok.Setter;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ExcelTemplate {
final private static Pattern PATTERN_HDR_FIELD = Pattern.compile("\\$\\{(.*?)}", Pattern.MULTILINE);
final private static Pattern PATTERN_DTL_FIELD = Pattern.compile("#\\{(.*?)}", Pattern.MULTILINE);
private XSSFWorkbook workbook;
private Map<String, Object> variables = new HashMap<>();
private List<Map<String, Object>> listVariables = new ArrayList<>();
// 是否下移形状格式
@Setter
private boolean moveShape = false;
// 是否下移印章(印章是图片)
@Setter
private boolean moveSeal = false;
// 是否设置单元格样式
@Setter
private boolean cellStyle = false;
// 是否设置单元格样式 针对RFID不需要序号定制
@Setter
private boolean cellStyle2 = false;
// 是否设置合并单元格样式
@Setter
private boolean rangeStyle = false;
// 价格靠右 发票
@Setter
private boolean priceRight = false;
// 数字靠右 箱单
@Setter
private boolean intRight = false;
// 报关单
@Setter
private boolean delRight = false;
private ExcelTemplate(){}
public static ExcelTemplate load(InputStream template) throws IOException {
ExcelTemplate excelTemplate = new ExcelTemplate();
excelTemplate.workbook = new XSSFWorkbook(template);
return excelTemplate;
}
public void addVar(String key, Object value){
variables.put(key, value);
}
public void addVarAll(Map values){
variables.putAll(values);
}
public void addListVar(Map<String, Object> row){
listVariables.add(row);
}
public void addListVarAll(Collection rows){
listVariables.addAll(rows);
}
public void clearAll(){
variables.clear();
listVariables.clear();
moveShape = false;
moveSeal = false;
cellStyle = false;
rangeStyle = false;
priceRight = false;
}
private boolean findAndRemoveMergedRegion(XSSFSheet sheet, int rowIndex) {
for (int mi = 0; mi < sheet.getMergedRegions().size(); mi++) {
if (sheet.getMergedRegions().get(mi).getFirstRow() == rowIndex) {
sheet.removeMergedRegion(mi);
return true;
}
}
return false;
}
public XSSFWorkbook render(int index) throws IOException {
XSSFSheet sheet = workbook.getSheetAt(index);
CellCopyPolicy copyPolicy = new CellCopyPolicy();
int dtlRowIndex = -1;
// find detail rows
for (int i = 0; i < sheet.getLastRowNum(); i++) {
XSSFRow row = sheet.getRow(i);
if (row == null) {
continue;
}
for (int j = 0; j < row.getLastCellNum(); j++) {
XSSFCell c = sheet.getRow(i).getCell(j);
if (c == null) {
continue;
}
String cellValue = c.toString();
Matcher matcherDtl = PATTERN_DTL_FIELD.matcher(cellValue);
if (matcherDtl.find()) {
dtlRowIndex = i;
break;
}
}
if (dtlRowIndex >= 0) {
break;
}
}
if (dtlRowIndex < sheet.getLastRowNum() && listVariables.size() > 1) {
//循环列表以下区域整体下移
int _rows = sheet.getLastRowNum();
for(int i = _rows; i > dtlRowIndex; i--){
sheet.copyRows(i, i, i + listVariables.size() -1 , copyPolicy);
}
for(int i = 0; i < listVariables.size() - 1; i++) {
int destRowIndex = dtlRowIndex + 1 + i;
sheet.createRow(destRowIndex); //clear destination row
while(findAndRemoveMergedRegion(sheet, destRowIndex)){
continue;
}
sheet.copyRows(dtlRowIndex, dtlRowIndex, destRowIndex, copyPolicy);
}
}
// 遍历所有形状 将列表下方的形状坐标也下移
if (moveShape) {
List<POIXMLDocumentPart> relations = sheet.getRelations();
for (POIXMLDocumentPart part : relations) {
if (part instanceof XSSFDrawing) {
XSSFDrawing drawing = (XSSFDrawing) part;
List<XSSFShape> shapes = drawing.getShapes();
for(int i = 0; i < shapes.size(); i++) {
if ((i==3 || i==5) && shapes.get(i) instanceof XSSFSimpleShape) {
XSSFSimpleShape simpleShape = (XSSFSimpleShape) shapes.get(i);
ClientAnchor anchor = (ClientAnchor) simpleShape.getAnchor();
// 调整行坐标实现下移
anchor.setRow1(anchor.getRow1() + listVariables.size() - 1);
anchor.setRow2(anchor.getRow2() + listVariables.size() - 1);
}
if ((i==4 || i==6) && shapes.get(i) instanceof XSSFSimpleShape) {
XSSFSimpleShape simpleShape = (XSSFSimpleShape) shapes.get(i);
ClientAnchor anchor = (ClientAnchor) simpleShape.getAnchor();
// 调整行坐标实现下移 因为只占一行 所以不需要调整row2
anchor.setRow1(anchor.getRow1() + listVariables.size() - 1);
}
}
}
}
}
// 遍历所有图片 将列表下方的形状坐标也下移
if (moveSeal) {
List<POIXMLDocumentPart> relations = sheet.getRelations();
for (POIXMLDocumentPart part : relations) {
if (part instanceof XSSFDrawing) {
XSSFDrawing drawing = (XSSFDrawing) part;
List<XSSFShape> shapes = drawing.getShapes();
for (XSSFShape shape : shapes) {
// 只处理图片类型的形状
if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture) shape;
// 调整行坐标实现下移
ClientAnchor anchor = (ClientAnchor) picture.getAnchor();
if (anchor.getRow1() > 10) { // 只下移位于10行之后的图片
anchor.setRow1(anchor.getRow1() + listVariables.size() - 1);
anchor.setRow2(anchor.getRow2() + listVariables.size() - 1);
}
}
}
}
}
}
List<Integer> dtlRows = new ArrayList<>();
//整体填值
for (int i = 0; i <= sheet.getLastRowNum(); i++) {
XSSFRow row = sheet.getRow(i);
if (row == null) {
continue;
}
for (int j = 0; j < row.getLastCellNum(); j++) {
XSSFCell c = sheet.getRow(i).getCell(j);
if (c == null) {
continue;
}
String cellValue = c.toString();
if ("#{pn}".equals(cellValue)) {
dtlRows.add(i);
}
if ("#{levy}".equals(cellValue)) {
dtlRows.add(i);
}
Matcher matcherHdr = PATTERN_HDR_FIELD.matcher(cellValue);
String result = c.getStringCellValue();
while (matcherHdr.find()) {
for (int ri = 1; ri <= matcherHdr.groupCount(); ri++) {
String field = matcherHdr.group(ri);
Object value = variables.getOrDefault(field, "");
result = result.replace(matcherHdr.group(0), String.valueOf(value));
}
if ("${phone1}".equals(cellValue) || "${phone2}".equals(cellValue) || "${hs_code}".equals(cellValue)) {
c.setCellValue(result); // 字符串
} else {
try {
double num = Double.parseDouble(result.replace(",", ""));
c.setCellValue(num); // 数值
} catch (NumberFormatException e) {
c.setCellValue(result); // 字符串
}
}
}
Matcher matcherDtl = PATTERN_DTL_FIELD.matcher(cellValue);
while (matcherDtl.find()) {
for (int ri = 1; ri <= matcherDtl.groupCount(); ri++) {
String field = matcherDtl.group(ri);
c.setCellValue(cellValue.replace(matcherDtl.group(0), String.valueOf(listVariables.get(i - dtlRowIndex).getOrDefault(field, ""))));
}
// 设置样式
if (cellStyle) {
XSSFCellStyle style = c.getCellStyle();
style.setBorderBottom(BorderStyle.NONE);
style.setBorderTop(BorderStyle.NONE);
style.setWrapText(true);
style.setAlignment(HorizontalAlignment.LEFT);
c.setCellStyle(style);
if (rangeStyle && j < 4) {
for (int mi = 0; mi < 3; mi++) {
XSSFCell nextc = sheet.getRow(i).getCell(c.getColumnIndex()+mi+1);
if (nextc == null) {
continue;
}
nextc.setCellStyle(style);
}
}
}
}
}
}
// 设置明细样式,因为明细是动态添加的,会有样式和模版偏差,此处主要是第2、3列的样式需要设置
if (cellStyle) {
for (Integer dtlRow : dtlRows) {
XSSFCell c1 = sheet.getRow(dtlRow).getCell(cellStyle2?0:1);
if (c1 == null) {
continue;
}
XSSFCellStyle style = workbook.createCellStyle();
style.setBorderRight(BorderStyle.NONE);
style.setBorderLeft(BorderStyle.MEDIUM); // 实线
style.setBorderBottom(BorderStyle.NONE);
style.setBorderTop(BorderStyle.NONE);
Font font = workbook.createFont();
font.setFontName("Arial"); // 设置字体
font.setFontHeightInPoints((short) 10); // 设置字号
style.setFont(font);
style.setVerticalAlignment(VerticalAlignment.TOP);
c1.setCellStyle(style);
XSSFCell c2 = sheet.getRow(dtlRow).getCell(cellStyle2?1:2);
if (c2 == null) {
continue;
}
XSSFCellStyle style2 = workbook.createCellStyle();
style2.setBorderRight(BorderStyle.MEDIUM);
style2.setBorderLeft(BorderStyle.NONE);
style2.setBorderBottom(BorderStyle.NONE);
style2.setBorderTop(BorderStyle.NONE);
Font font2 = workbook.createFont();
font2.setFontName("Arial"); // 设置字体
font2.setFontHeightInPoints((short) 10); // 设置字号
style2.setFont(font2);
style2.setVerticalAlignment(VerticalAlignment.TOP);
style2.setAlignment(HorizontalAlignment.LEFT);
style2.setWrapText(true);
c2.setCellStyle(style2);
if (priceRight) { //仅供发票excel使用,第8、9是价格列居右
for (int i = 6; i < 9; i++) {
XSSFCell c7 = sheet.getRow(dtlRow).getCell(i);
if (c7 == null) {
continue;
}
// 尝试把字符串转成数值
if (c7.getCellType() == CellType.STRING) {
String strVal = c7.getStringCellValue();
if (strVal != null && !strVal.trim().isEmpty()) {
try {
double num = Double.parseDouble(strVal.replace(",", ""));
c7.setCellValue(num); // 转换为数值写回
} catch (NumberFormatException e) {
// 如果不是数字就保留原字符串
System.out.println("非数字,保持原值: " + strVal);
}
}
}
// 创建样式
XSSFCellStyle style7 = workbook.createCellStyle();
style7.setBorderRight(BorderStyle.MEDIUM);
style7.setBorderLeft(BorderStyle.NONE);
style7.setBorderBottom(BorderStyle.NONE);
style7.setBorderTop(BorderStyle.NONE);
Font font7 = workbook.createFont();
font7.setFontName("Arial");
font7.setFontHeightInPoints((short) 10);
style7.setFont(font7);
style7.setVerticalAlignment(VerticalAlignment.TOP);
style7.setAlignment(HorizontalAlignment.RIGHT);
// 设置千分位格式
DataFormat dataFormat = workbook.createDataFormat();
style7.setDataFormat(i==6?dataFormat.getFormat("#,##0"):
i==7?dataFormat.getFormat("#,##0.00000")
:dataFormat.getFormat("#,##0.00"));
c7.setCellStyle(style7);
}
}
if (intRight) { //仅供箱单excel使用
for (int i = 4; i < 9; i++) {
XSSFCell c7 = sheet.getRow(dtlRow).getCell(i);
if (c7 == null) {
continue;
}
// 尝试把字符串转成数值
if (c7.getCellType() == CellType.STRING) {
String strVal = c7.getStringCellValue();
if (strVal != null && !strVal.trim().isEmpty()) {
try {
double num = Double.parseDouble(strVal.replace(",", ""));
c7.setCellValue(num); // 转换为数值写回
} catch (NumberFormatException e) {
// 如果不是数字就保留原字符串
System.out.println("非数字,保持原值: " + strVal);
}
}
}
// 创建样式
XSSFCellStyle style7 = workbook.createCellStyle();
style7.setBorderRight(BorderStyle.MEDIUM);
style7.setBorderLeft(i==4?BorderStyle.MEDIUM:BorderStyle.NONE);
style7.setBorderBottom(BorderStyle.NONE);
style7.setBorderTop(BorderStyle.NONE);
Font font7 = workbook.createFont();
font7.setFontName("Arial");
font7.setFontHeightInPoints((short) 10);
style7.setFont(font7);
style7.setVerticalAlignment(VerticalAlignment.TOP);
style7.setAlignment(HorizontalAlignment.RIGHT);
// 设置千分位格式
if (i==4 || i==5 || i==8) {
DataFormat dataFormat = workbook.createDataFormat();
style7.setDataFormat(dataFormat.getFormat("#,##0"));
} else {
DataFormat dataFormat = workbook.createDataFormat();
style7.setDataFormat(dataFormat.getFormat("#,##0.00"));
}
c7.setCellStyle(style7);
}
}
}
}
if (delRight) {
for (Integer dtlRow : dtlRows) {
for (int i = 6; i < 12; i++) {
if (i==6 || i==11) {
XSSFCell c7 = sheet.getRow(dtlRow).getCell(i);
if (c7 == null) {
continue;
}
// 尝试把字符串转成数值
if (c7.getCellType() == CellType.STRING) {
String strVal = c7.getStringCellValue();
if (strVal != null && !strVal.trim().isEmpty()) {
try {
double num = Double.parseDouble(strVal.replace(",", ""));
c7.setCellValue(num); // 转换为数值写回
} catch (NumberFormatException e) {
// 如果不是数字就保留原字符串
System.out.println("非数字,保持原值: " + strVal);
}
}
}
// 创建样式
XSSFCellStyle style7 = workbook.createCellStyle();
style7.setBorderRight(BorderStyle.NONE);
style7.setBorderLeft(BorderStyle.NONE);
style7.setBorderBottom(BorderStyle.NONE);
style7.setBorderTop(BorderStyle.NONE);
Font font7 = workbook.createFont();
font7.setFontName("Arial");
font7.setFontHeightInPoints((short) 10);
style7.setFont(font7);
style7.setVerticalAlignment(VerticalAlignment.CENTER);
style7.setAlignment(HorizontalAlignment.RIGHT);
// 设置千分位格式
DataFormat dataFormat = workbook.createDataFormat();
style7.setDataFormat(i==6?dataFormat.getFormat("#,##0"):dataFormat.getFormat("#,##0.00"));
c7.setCellStyle(style7);
}
}
}
}
return workbook;
}
}