Skip to content

Commit 455141a

Browse files
committed
[app-builder] add text concatenation tool
1 parent 6141ae9 commit 455141a

14 files changed

Lines changed: 512 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>modelengine.fit.jade</groupId>
8+
<artifactId>app-builder-plugin-parent</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<groupId>modelengine.fit.jade.plugin</groupId>
13+
<artifactId>aipp-template-render</artifactId>
14+
15+
<properties>
16+
<maven.compiler.source>17</maven.compiler.source>
17+
<maven.compiler.target>17</maven.compiler.target>
18+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19+
</properties>
20+
21+
<dependencies>
22+
<!-- Services -->
23+
<dependency>
24+
<groupId>modelengine.jade.service</groupId>
25+
<artifactId>aipp-template-render-service</artifactId>
26+
</dependency>
27+
28+
<!-- Test -->
29+
<dependency>
30+
<groupId>org.junit.jupiter</groupId>
31+
<artifactId>junit-jupiter</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.assertj</groupId>
35+
<artifactId>assertj-core</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.mockito</groupId>
39+
<artifactId>mockito-core</artifactId>
40+
</dependency>
41+
<dependency>
42+
<groupId>modelengine.fit.jade</groupId>
43+
<artifactId>aipp-service</artifactId>
44+
</dependency>
45+
</dependencies>
46+
47+
<build>
48+
<plugins>
49+
<plugin>
50+
<groupId>org.fitframework</groupId>
51+
<artifactId>fit-build-maven-plugin</artifactId>
52+
<version>${fit.version}</version>
53+
<executions>
54+
<execution>
55+
<id>build-plugin</id>
56+
<goals>
57+
<goal>build-plugin</goal>
58+
</goals>
59+
</execution>
60+
<execution>
61+
<id>package-plugin</id>
62+
<goals>
63+
<goal>package-plugin</goal>
64+
</goals>
65+
</execution>
66+
</executions>
67+
</plugin>
68+
<plugin>
69+
<groupId>org.apache.maven.plugins</groupId>
70+
<artifactId>maven-antrun-plugin</artifactId>
71+
<version>${maven.antrun.version}</version>
72+
<executions>
73+
<execution>
74+
<phase>install</phase>
75+
<configuration>
76+
<target>
77+
<copy file="${project.build.directory}/${project.build.finalName}.jar"
78+
todir="../../../build/plugins"/>
79+
</target>
80+
</configuration>
81+
<goals>
82+
<goal>run</goal>
83+
</goals>
84+
</execution>
85+
</executions>
86+
</plugin>
87+
</plugins>
88+
</build>
89+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
package modelengine.fit.jade.aipp.template.render;
8+
9+
import modelengine.fitframework.annotation.Component;
10+
11+
import java.util.Map;
12+
import java.util.regex.Matcher;
13+
import java.util.regex.Pattern;
14+
15+
/**
16+
* {@link TemplateService} 的实现类。
17+
*
18+
* @author 孙怡菲
19+
* @since 2025-08-29
20+
*/
21+
@Component
22+
public class TemplateServiceImpl implements TemplateService {
23+
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{\\{\\s*(\\w+)\\s*}}");
24+
25+
@Override
26+
public String renderTemplate(String template, Map<String, Object> args) {
27+
if (template == null) {
28+
return null;
29+
}
30+
31+
if (args == null) {
32+
args = Map.of();
33+
}
34+
35+
Matcher matcher = PLACEHOLDER_PATTERN.matcher(template);
36+
StringBuilder sb = new StringBuilder();
37+
38+
while (matcher.find()) {
39+
String key = matcher.group(1);
40+
Object value = args.getOrDefault(key, "");
41+
matcher.appendReplacement(sb, Matcher.quoteReplacement(String.valueOf(value)));
42+
}
43+
matcher.appendTail(sb);
44+
45+
return sb.toString();
46+
}
47+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fit:
2+
beans:
3+
packages:
4+
- 'modelengine.fit.jade.aipp.template.render'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
package modelengine.fit.jade.aipp.template.render;
8+
9+
import static org.junit.jupiter.api.Assertions.*;
10+
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.DisplayName;
13+
import org.junit.jupiter.api.Test;
14+
15+
import java.util.Arrays;
16+
import java.util.HashMap;
17+
import java.util.LinkedHashMap;
18+
import java.util.Map;
19+
20+
/**
21+
* {@link TemplateServiceImpl} 的测试类。
22+
*
23+
* @author 孙怡菲
24+
* @since 2025-08-28
25+
*/
26+
class TemplateServiceImplTest {
27+
private TemplateServiceImpl textTool;
28+
29+
@BeforeEach
30+
void setUp() {
31+
this.textTool = new TemplateServiceImpl();
32+
}
33+
34+
@Test
35+
@DisplayName("基础模板变量替换成功")
36+
void shouldReplaceBasicVariables() {
37+
String template = "Hello {{name}}, your score is {{score}}.";
38+
Map<String, Object> args = new HashMap<>();
39+
args.put("name", "Tom");
40+
args.put("score", 95);
41+
42+
String result = this.textTool.renderTemplate(template, args);
43+
assertEquals("Hello Tom, your score is 95.", result);
44+
}
45+
46+
@Test
47+
@DisplayName("缺失变量时置为空字符串")
48+
void shouldReplaceMissingVariableWithEmpty() {
49+
String template = "Hello {{name}}, your score is {{score}}.";
50+
Map<String, Object> args = new HashMap<>();
51+
args.put("name", "Tom");
52+
53+
String result = this.textTool.renderTemplate(template, args);
54+
assertEquals("Hello Tom, your score is .", result);
55+
}
56+
57+
@Test
58+
@DisplayName("空参数Map时模板变量置为空")
59+
void shouldHandleEmptyArgsMap() {
60+
String template = "Hello {{name}}!";
61+
Map<String, Object> args = new HashMap<>();
62+
63+
String result = this.textTool.renderTemplate(template, args);
64+
assertEquals("Hello !", result);
65+
}
66+
67+
@Test
68+
@DisplayName("参数为null时模板变量置为空")
69+
void shouldHandleNullArgs() {
70+
String template = "Hello {{name}}!";
71+
72+
String result = this.textTool.renderTemplate(template, null);
73+
assertEquals("Hello !", result);
74+
}
75+
76+
@Test
77+
@DisplayName("模板无占位符时内容保持不变")
78+
void shouldHandleTemplateWithoutPlaceholders() {
79+
String template = "Hello world!";
80+
81+
String result = this.textTool.renderTemplate(template, Map.of("name", "Tom"));
82+
assertEquals("Hello world!", result);
83+
}
84+
85+
@Test
86+
@DisplayName("变量中包含占位符内容保持不变")
87+
void shouldHandleVariableWithPlaceholders() {
88+
String template = "Hello {{name}}!";
89+
90+
String result = this.textTool.renderTemplate(template, Map.of("name", "{{Tom}}"));
91+
assertEquals("Hello {{Tom}}!", result);
92+
}
93+
94+
@Test
95+
@DisplayName("变量为 List 时正常替换")
96+
void shouldReplaceListVariableCorrectly() {
97+
String template = "Items: {{items}}";
98+
Map<String, Object> args = new HashMap<>();
99+
args.put("items", Arrays.asList("apple", "banana", "cherry"));
100+
101+
String result = this.textTool.renderTemplate(template, args);
102+
assertEquals("Items: [apple, banana, cherry]", result);
103+
}
104+
105+
@Test
106+
@DisplayName("变量为 Map 时正常替换")
107+
void shouldReplaceMapVariableCorrectly() {
108+
String template = "Map data: {{data}}";
109+
Map<String, Object> args = new HashMap<>();
110+
Map<String, Object> mapValue = new LinkedHashMap<>();
111+
mapValue.put("a", 1);
112+
mapValue.put("b", 2);
113+
args.put("data", mapValue);
114+
115+
String result = this.textTool.renderTemplate(template, args);
116+
assertEquals("Map data: {a=1, b=2}", result);
117+
}
118+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>modelengine.fit.jade</groupId>
8+
<artifactId>app-builder-plugin-parent</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<groupId>modelengine.fit.jade.plugin</groupId>
13+
<artifactId>aipp-text-concatenation</artifactId>
14+
15+
<properties>
16+
<maven.compiler.source>17</maven.compiler.source>
17+
<maven.compiler.target>17</maven.compiler.target>
18+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19+
</properties>
20+
21+
<dependencies>
22+
<!-- FIT -->
23+
<dependency>
24+
<groupId>org.fitframework</groupId>
25+
<artifactId>fit-api</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.fitframework</groupId>
29+
<artifactId>fit-util</artifactId>
30+
</dependency>
31+
32+
<!-- Services -->
33+
<dependency>
34+
<groupId>org.fitframework.fel</groupId>
35+
<artifactId>tool-service</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>modelengine.jade.service</groupId>
39+
<artifactId>aipp-template-render-service</artifactId>
40+
</dependency>
41+
</dependencies>
42+
43+
<build>
44+
<plugins>
45+
<plugin>
46+
<groupId>org.fitframework</groupId>
47+
<artifactId>fit-build-maven-plugin</artifactId>
48+
<version>${fit.version}</version>
49+
<executions>
50+
<execution>
51+
<id>build-plugin</id>
52+
<goals>
53+
<goal>build-plugin</goal>
54+
</goals>
55+
</execution>
56+
<execution>
57+
<id>package-plugin</id>
58+
<goals>
59+
<goal>package-plugin</goal>
60+
</goals>
61+
</execution>
62+
</executions>
63+
</plugin>
64+
<plugin>
65+
<groupId>org.fitframework.fel</groupId>
66+
<artifactId>tool-maven-plugin</artifactId>
67+
<version>3.5.0-M6</version>
68+
<executions>
69+
<execution>
70+
<id>build-tool</id>
71+
<goals>
72+
<goal>build-tool</goal>
73+
</goals>
74+
</execution>
75+
</executions>
76+
</plugin>
77+
<plugin>
78+
<groupId>org.apache.maven.plugins</groupId>
79+
<artifactId>maven-antrun-plugin</artifactId>
80+
<version>${maven.antrun.version}</version>
81+
<executions>
82+
<execution>
83+
<phase>install</phase>
84+
<configuration>
85+
<target>
86+
<copy file="${project.build.directory}/${project.build.finalName}.jar"
87+
todir="../../../build/plugins"/>
88+
</target>
89+
</configuration>
90+
<goals>
91+
<goal>run</goal>
92+
</goals>
93+
</execution>
94+
</executions>
95+
</plugin>
96+
</plugins>
97+
</build>
98+
99+
</project>

0 commit comments

Comments
 (0)