Untitled
unknown
plain_text
10 months ago
16 kB
17
Indexable
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.policy.LoopRowTableRenderPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service
public class TemplateRenderService {
@Autowired
private TemplateFieldResolverService fieldResolverService;
public void renderTemplate(EsContract contract, String templatePath, Path outputPath) {
try {
ClassPathResource tpl = new ClassPathResource(templatePath);
try (InputStream templateInputStream = tpl.getInputStream()) {
// Parse template to get configuration
TemplateParseResult parseResult = parseTemplate(templateInputStream);
// Get only the data fields (not table markers or column names)
Set<String> dataFieldPaths = parseResult.getDataFieldPaths();
try (InputStream freshInputStream = tpl.getInputStream()) {
// Resolve data fields from contract
Map<String, Object> resolvedData = fieldResolverService.resolveTemplateFields(contract, dataFieldPaths);
// Prepare render data with proper structure
Map<String, Object> renderData = prepareRenderData(resolvedData, parseResult);
// Configure table policies
Configure.ConfigureBuilder configBuilder = Configure.builder();
for (TableConfig tableConfig : parseResult.getTableConfigs()) {
configBuilder.bind(tableConfig.getTableName(), new LoopRowTableRenderPolicy());
}
Configure config = configBuilder.build();
try (XWPFTemplate template = XWPFTemplate.compile(freshInputStream, config).render(renderData);
OutputStream outputStream = Files.newOutputStream(outputPath)) {
template.write(outputStream);
System.out.println("模板渲染完成: " + outputPath);
}
}
}
} catch (Exception e) {
throw new RuntimeException("模板渲染失败", e);
}
}
/**
* Parse template to extract configuration
*/
private TemplateParseResult parseTemplate(InputStream templateInputStream) {
TemplateParseResult result = new TemplateParseResult();
try (XWPFDocument document = new XWPFDocument(templateInputStream)) {
List<String> allTexts = extractAllTexts(document);
for (String text : allTexts) {
// Parse regular fields
parseRegularFields(text, result);
// Parse table configurations
parseTableConfigurations(text, result);
}
} catch (Exception e) {
throw new RuntimeException("解析模板失败", e);
}
return result;
}
/**
* Extract all texts from document
*/
private List<String> extractAllTexts(XWPFDocument document) {
List<String> texts = new ArrayList<>();
// From paragraphs
for (XWPFParagraph paragraph : document.getParagraphs()) {
texts.add(paragraph.getText());
}
// From tables
for (XWPFTable table : document.getTables()) {
for (XWPFTableRow row : table.getRows()) {
// Store row text as a single unit to preserve context
StringBuilder rowText = new StringBuilder();
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
rowText.append(paragraph.getText()).append(" ");
}
}
texts.add(rowText.toString());
}
}
return texts;
}
/**
* Parse regular fields like {{contract.id}}
*/
private void parseRegularFields(String text, TemplateParseResult result) {
Pattern pattern = Pattern.compile("\\{\\{([^}#/]+)\\}\\}");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
String field = matcher.group(1).trim();
// Check if this is a table placeholder or column field
if (!isTableRelatedField(field, result)) {
result.addDataField(field);
}
}
}
/**
* Parse table configurations
*/
private void parseTableConfigurations(String text, TemplateParseResult result) {
// Pattern 1: {{#tableName}}...{{/tableName}} with column fields
Pattern loopPattern = Pattern.compile("\\{\\{#(\\w+)\\}\\}(.*?)\\{\\{/\\1\\}\\}");
Matcher loopMatcher = loopPattern.matcher(text);
while (loopMatcher.find()) {
String tableName = loopMatcher.group(1);
String content = loopMatcher.group(2);
TableConfig config = new TableConfig(tableName);
// Extract column fields from content
Pattern columnPattern = Pattern.compile("\\{\\{([^}]+)\\}\\}");
Matcher columnMatcher = columnPattern.matcher(content);
while (columnMatcher.find()) {
String columnField = columnMatcher.group(1).trim();
config.addColumnField(columnField);
}
// Infer data path from table name
String dataPath = inferDataPath(tableName);
config.setDataPath(dataPath);
result.addTableConfig(config);
}
// Pattern 2: Simple {{tableName}} in table cell
Pattern simpleTablePattern = Pattern.compile("\\{\\{(\\w+Table)\\}\\}");
Matcher simpleTableMatcher = simpleTablePattern.matcher(text);
while (simpleTableMatcher.find()) {
String tableName = simpleTableMatcher.group(1);
// Check if this table is already configured
if (!result.hasTableConfig(tableName)) {
TableConfig config = new TableConfig(tableName);
// For simple table markers, infer columns from context or configuration
String dataPath = inferDataPath(tableName);
config.setDataPath(dataPath);
// Infer columns based on table name
inferTableColumns(tableName, config);
result.addTableConfig(config);
}
}
}
/**
* Check if a field is table-related (should not be resolved from contract)
*/
private boolean isTableRelatedField(String field, TemplateParseResult result) {
// Check if it's a table name
if (field.endsWith("Table")) {
return true;
}
// Check if it's a column field in any table configuration
for (TableConfig config : result.getTableConfigs()) {
if (config.getColumnFields().contains(field)) {
return true;
}
}
// Check common table column patterns
return isCommonTableColumn(field);
}
/**
* Check if field is a common table column name
*/
private boolean isCommonTableColumn(String field) {
Set<String> commonColumns = new HashSet<>(Arrays.asList(
"paymentDate", "barrierPct", "barrierPrice", "observationDate",
"date", "value", "price", "amount", "rate", "percentage"
));
return commonColumns.contains(field);
}
/**
* Infer data path from table name
*/
private String inferDataPath(String tableName) {
// This can be configured via properties or database
Map<String, String> pathMappings = new HashMap<>();
pathMappings.put("observationTable", "contractLeg.leg.modelVo.observation.value.records");
// Remove "Table" suffix to get base name
String baseName = tableName.replace("Table", "");
// Try exact match first
if (pathMappings.containsKey(tableName)) {
return pathMappings.get(tableName) + "[]";
}
// Try base name
if (pathMappings.containsKey(baseName)) {
return pathMappings.get(baseName) + "[]";
}
// Default: assume it's a direct field
return tableName + "[]";
}
/**
* Infer table columns based on table name
*/
private void inferTableColumns(String tableName, TableConfig config) {
// This can be configured via properties or database
if ("observationTable".equals(tableName)) {
config.addColumnField("paymentDate");
config.addColumnField("barrierPct");
config.addColumnField("barrierPrice");
}
// Add more table configurations as needed
}
/**
* Prepare render data
*/
private Map<String, Object> prepareRenderData(Map<String, Object> resolvedData, TemplateParseResult parseResult) {
Map<String, Object> renderData = new HashMap<>();
// Process each resolved field
for (Map.Entry<String, Object> entry : resolvedData.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// Check if this is table data
TableConfig tableConfig = findTableConfigByDataPath(key, parseResult);
if (tableConfig != null && value instanceof List) {
// Process table data
List<Map<String, Object>> tableData = (List<Map<String, Object>>) value;
List<Map<String, Object>> convertedData = convertTableData(tableData, tableConfig);
renderData.put(tableConfig.getTableName(), convertedData);
} else {
// Process regular field
if (key.contains(".")) {
buildNestedMap(renderData, key, value);
} else {
renderData.put(key, value);
}
}
}
return renderData;
}
/**
* Find table configuration by data path
*/
private TableConfig findTableConfigByDataPath(String dataPath, TemplateParseResult parseResult) {
for (TableConfig config : parseResult.getTableConfigs()) {
String configPath = config.getDataPath().replace("[]", "");
if (dataPath.equals(configPath) || dataPath.startsWith(configPath)) {
return config;
}
}
return null;
}
/**
* Convert table data based on configuration
*/
private List<Map<String, Object>> convertTableData(List<Map<String, Object>> tableData, TableConfig config) {
List<Map<String, Object>> convertedData = new ArrayList<>();
for (Map<String, Object> row : tableData) {
Map<String, Object> convertedRow = new HashMap<>();
// Map data fields to template fields
for (Map.Entry<String, Object> entry : row.entrySet()) {
String dataField = entry.getKey();
Object value = entry.getValue();
// Get template field name
String templateField = config.getTemplateField(dataField);
if (templateField != null) {
convertedRow.put(templateField, value);
} else {
// Keep original if no mapping
convertedRow.put(dataField, value);
}
}
convertedData.add(convertedRow);
}
return convertedData;
}
/**
* Build nested map for dot notation fields
*/
private void buildNestedMap(Map<String, Object> rootMap, String dottedPath, Object value) {
String[] parts = dottedPath.split("\\.");
Map<String, Object> currentMap = rootMap;
for (int i = 0; i < parts.length - 1; i++) {
String part = parts[i];
if (!currentMap.containsKey(part)) {
currentMap.put(part, new HashMap<String, Object>());
}
Object nextLevel = currentMap.get(part);
if (nextLevel instanceof Map) {
currentMap = (Map<String, Object>) nextLevel;
} else {
return;
}
}
currentMap.put(parts[parts.length - 1], value);
}
/**
* Template parse result
*/
private static class TemplateParseResult {
private Set<String> dataFieldPaths = new HashSet<>();
private List<TableConfig> tableConfigs = new ArrayList<>();
public void addDataField(String field) {
dataFieldPaths.add(field);
}
public void addTableConfig(TableConfig config) {
tableConfigs.add(config);
// Add the data path to fields that need to be resolved
if (config.getDataPath() != null) {
// Convert path with [] to indicate table data
String dataPath = config.getDataPath();
for (String columnField : config.getColumnFields()) {
dataFieldPaths.add(dataPath + "." + mapTemplateFieldToDataField(columnField));
}
}
}
private String mapTemplateFieldToDataField(String templateField) {
// Default field mappings
Map<String, String> mappings = new HashMap<>();
mappings.put("paymentDate", "p.date");
mappings.put("barrierPct", "b.pct");
mappings.put("barrierPrice", "b.price");
mappings.put("observationDate", "value");
return mappings.getOrDefault(templateField, templateField);
}
public boolean hasTableConfig(String tableName) {
return tableConfigs.stream().anyMatch(c -> c.getTableName().equals(tableName));
}
public Set<String> getDataFieldPaths() {
return dataFieldPaths;
}
public List<TableConfig> getTableConfigs() {
return tableConfigs;
}
}
/**
* Table configuration
*/
private static class TableConfig {
private String tableName;
private String dataPath;
private List<String> columnFields = new ArrayList<>();
private Map<String, String> fieldMappings = new HashMap<>();
public TableConfig(String tableName) {
this.tableName = tableName;
initializeDefaultMappings();
}
private void initializeDefaultMappings() {
// Default mappings - can be externalized to configuration
fieldMappings.put("p.date", "paymentDate");
fieldMappings.put("b.pct", "barrierPct");
fieldMappings.put("b.price", "barrierPrice");
fieldMappings.put("value", "observationDate");
}
public void addColumnField(String field) {
columnFields.add(field);
}
public String getTemplateField(String dataField) {
return fieldMappings.get(dataField);
}
// Getters and setters
public String getTableName() {
return tableName;
}
public String getDataPath() {
return dataPath;
}
public void setDataPath(String dataPath) {
this.dataPath = dataPath;
}
public List<String> getColumnFields() {
return columnFields;
}
}
}Editor is loading...
Leave a Comment