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
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;
|
|
}
|
|
}
|