摘要
本文深入解析 ooder 框架的核心 BridgeCode 机制,从设计原理、生成编译流程,到基于此机制的分层 SKILLS 设计,最后展示在 Trae Solo 环境中的 Skill 构建实践。通过源码分析和实战案例,揭示 ooder 如何通过元数据驱动的代码生成实现高效的 A2UI 组件开发。
一、BridgeCode 设计原理
1.1 核心设计理念
BridgeCode 是 ooder 框架中连接元数据配置与运行时组件的桥梁,其核心设计理念是元数据驱动(Metadata-Driven):
元数据配置(JSON/注解)
↓
BridgeCode 生成器
↓
Java 源代码
↓
动态编译
↓
运行时组件
设计目标:
- 解耦性:将配置与实现分离,配置通过声明式方式定义
- 可扩展性:支持多种组件类型和视图模式
- 类型安全:通过编译期检查确保配置的正确性
- 运行时绑定:支持动态加载和热更新
1.2 架构层次
BridgeCode 系统采用三层架构设计:
┌─────────────────────────────────────────────┐
│ 元数据层(Metadata Layer) │
│ - CustomViewMeta │
│ - CustomDataMeta │
│ - MethodConfig │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 生成器层(Generator Layer) │
│ - GenCustomViewJava │
│ - GenRepositoryViewJava │
│ - GenAggCustomViewJava │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 运行时层(Runtime Layer) │
│ - UIComponent │
│ - ModuleUIComponent │
│ - AggRootBuild │
└─────────────────────────────────────────────┘
1.3 核心类设计
1.3.1 AggRootBuild - 聚合根构建器
AggRootBuild 是 BridgeCode 生成流程的核心协调类,位于 net.ooder.engine.codegen.java.AggRootBuild:
java
public class AggRootBuild {
private GenCustomViewJava viewTask;
private GenRepositoryViewJava voRepositoryTask;
private GenRepositoryViewJava serviceRepositoryTask;
private GenAggCustomViewJava rootTask;
private GenAggCustomJava genAggCustomJava;
public List<JavaGenSource> build() throws JDSException {
// 1. 创建子节点
CustomViewMeta = genChildJava();
// 2. 创建视图层
javaViewSource = buildView();
// 3. 创建资源层接口
repositorySource = buildRepositoryView(true);
// 4. 预编译一次
javaGen.dynCompile(getModuleJavaSrc());
return aggServiceRootBean;
}
}
关键特性:
- 任务编排:协调多个生成任务的执行顺序
- 依赖管理:处理生成任务之间的依赖关系
- 增量构建:支持只生成变更的部分
- 错误处理:统一的异常处理和回滚机制
1.3.2 GenJavaTask - 生成任务基类
所有代码生成器都继承自 GenJavaTask,提供统一的生成框架:
java
public abstract class GenJavaTask implements Callable<List<JavaGenSource>> {
protected JavaGenSource javaGen;
protected CustomViewMeta viewMeta;
protected String euClassName;
protected Chrome chrome;
public abstract List<JavaGenSource> build() throws JDSException;
protected JavaGenSource createJavaSource(String className, String content) {
JavaGenSource source = new JavaGenSource();
source.setClassName(className);
source.setContent(content);
source.setPackage(viewMeta.getPackageName());
return source;
}
}
设计优势:
- 统一接口:所有生成器实现相同的接口
- 可组合性:支持生成器的组合和复用
- 错误隔离:每个生成器独立处理错误
- 可测试性:每个生成器可以独立测试
1.3.3 D2CGenerator - 设计到代码生成器
D2CGenerator 是核心的代码生成引擎,使用 Freemarker 模板引擎:
java
public class D2CGenerator {
private Configuration freemarkerConfig;
private TemplateManager templateManager;
public String generate(String templateName, Map<String, Object> dataModel)
throws JDSException {
try {
Template template = freemarkerConfig.getTemplate(templateName);
StringWriter writer = new StringWriter();
template.process(dataModel, writer);
return writer.toString();
} catch (Exception e) {
throw new JDSException("代码生成失败: " + e.getMessage(), e);
}
}
public void dynCompile(List<JavaGenSource> sources) throws JDSException {
JavaCompiler compiler = new JavaCompiler();
compiler.compile(sources);
}
}
技术栈:
- 模板引擎:Freemarker 2.3.x
- 编译器:Java Compiler API
- 类加载:自定义 ClassLoader
- 打包:JAR 文件生成
二、BridgeCode 生成编译原理
2.1 完整生成流程
BridgeCode 的生成编译流程分为五个阶段:
阶段 1: 元数据解析
↓
阶段 2: 代码生成
↓
阶段 3: 源码组装
↓
阶段 4: 动态编译
↓
阶段 5: 运行时绑定
2.2 阶段详解
2.2.1 阶段 1:元数据解析
输入:
- JSON 配置文件
- Java 注解配置
- 数据库元数据
处理流程:
java
public class MetadataParser {
public MethodConfig parseFromJson(String jsonConfig) {
JSONObject json = JSON.parseObject(jsonConfig);
MethodConfig config = new MethodConfig();
// 解析视图元数据
config.setView(parseViewMeta(json.getJSONObject("view")));
// 解析数据元数据
config.setDataBean(parseDataMeta(json.getJSONObject("data")));
// 解析方法配置
config.setMethodName(json.getString("methodName"));
config.setUrl(json.getString("url"));
return config;
}
public MethodConfig parseFromAnnotation(Class<?> bridgeClass) {
MethodConfig config = new MethodConfig();
// 解析 @CustomClass 注解
CustomClass classAnnotation = bridgeClass.getAnnotation(CustomClass.class);
config.setCaption(classAnnotation.caption());
// 解析方法注解
for (Method method : bridgeClass.getMethods()) {
if (method.isAnnotationPresent(CustomMenuItem.class)) {
config.addMenuItem(parseMenuItem(method));
}
if (method.isAnnotationPresent(CustomGridEvent.class)) {
config.addEvent(parseGridEvent(method));
}
}
return config;
}
}
验证机制:
- 类型检查:确保字段类型匹配
- 必填验证:检查必填字段
- 引用验证:验证引用的实体存在
- 格式验证:检查 URL、正则表达式等格式
2.2.2 阶段 2:代码生成
生成器层次:
GenCustomViewJava (视图层生成器)
├── GenLayoutChildModule (布局生成)
├── GenTabsChildModule (标签页生成)
└── GenFormChildModule (表单生成)
GenRepositoryViewJava (仓储层生成器)
├── GenEntityJava (实体生成)
├── GenEntityServiceJava (服务生成)
└── GenTableJava (表生成)
GenAggCustomViewJava (聚合层生成器)
├── GenAggRootJava (聚合根生成)
├── GenAggMenuJava (菜单生成)
└── GenAggAPIJava (API生成)
生成示例:
java
public class GenCustomViewJava extends GenJavaTask {
@Override
public List<JavaGenSource> build() throws JDSException {
List<JavaGenSource> sources = new ArrayList<>();
// 1. 生成视图类
sources.add(generateViewClass());
// 2. 生成字段配置
sources.add(generateFieldConfigs());
// 3. 生成事件处理器
sources.add(generateEventHandlers());
return sources;
}
private JavaGenSource generateViewClass() throws JDSException {
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("className", viewMeta.getClassName());
dataModel.put("packageName", viewMeta.getPackageName());
dataModel.put("fields", viewMeta.getFields());
String content = d2cGenerator.generate("view.ftl", dataModel);
return createJavaSource(viewMeta.getClassName(), content);
}
}
模板示例(Freemarker):
ftl
package ${packageName};
import net.ooder.engine.ub.component.*;
import net.ooder.engine.ub.annotation.*;
<#list fields as field>
import ${field.type};
</#list>
/**
* ${viewMeta.caption}
* 自动生成的视图类,请勿手动修改
*/
@CustomView
public class ${className} extends UIComponent {
<#list fields as field>
private ${field.type} ${field.name};
</#list>
public ${className}() {
super();
// 初始化组件
}
}
2.2.3 阶段 3:源码组装
组装策略:
java
public class SourceAssembler {
public JavaSrcMeta assemble(List<JavaGenSource> sources) {
JavaSrcMeta srcMeta = new JavaSrcMeta();
// 1. 按包分组
Map<String, List<JavaGenSource>> packageMap =
sources.stream().collect(Collectors.groupingBy(JavaGenSource::getPackage));
// 2. 生成包结构
for (Map.Entry<String, List<JavaGenSource>> entry : packageMap.entrySet()) {
String packageName = entry.getKey();
List<JavaGenSource> packageSources = entry.getValue();
// 生成包目录
String packagePath = packageName.replace('.', '/');
srcMeta.addPackage(packagePath, packageSources);
}
// 3. 生成导入语句
srcMeta.addImports(calculateImports(sources));
return srcMeta;
}
}
依赖解析:
- 自动计算类依赖关系
- 生成正确的 import 语句
- 处理循环依赖
- 优化导入顺序
2.2.4 阶段 4:动态编译
编译流程:
java
public class DynamicCompiler {
public Class<?> compile(JavaGenSource source) throws JDSException {
try {
// 1. 创建 Java 文件
File javaFile = createJavaFile(source);
// 2. 编译 Java 文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
StandardJavaFileManager fileManager =
compiler.getStandardFileManager(null, null);
Iterable<? extends JavaFileObject> compilationUnits =
fileManager.getJavaFileObjectsFromFiles(Arrays.asList(javaFile));
// 3. 执行编译
compiler.getTask(null, null, diagnostics, fileManager, null, null)
.call(compilationUnits);
// 4. 检查编译错误
if (!diagnostics.getDiagnostics().isEmpty()) {
throw new JDSException("编译失败: " + diagnostics);
}
// 5. 加载编译后的类
ClassLoader classLoader = fileManager.getClassLoader(null);
return classLoader.loadClass(source.getClassName());
} catch (Exception e) {
throw new JDSException("动态编译失败: " + e.getMessage(), e);
}
}
}
编译优化:
- 增量编译:只编译变更的文件
- 并行编译:支持多线程编译
- 缓存机制:缓存已编译的类
- 热替换:支持运行时替换类
2.2.5 阶段 5:运行时绑定
绑定机制:
java
public class RuntimeBinder {
public void bind(MethodConfig config, Class<?> bridgeClass)
throws JDSException {
try {
// 1. 创建 Bridge 实例
Object bridgeInstance = bridgeClass.newInstance();
// 2. 绑定方法到事件
for (Event event : config.getEvents()) {
Method handler = findHandlerMethod(bridgeClass, event.getHandler());
bindEvent(event, handler, bridgeInstance);
}
// 3. 绑定菜单项
for (MenuItem menu : config.getMenus()) {
Method handler = findHandlerMethod(bridgeClass, menu.getHandler());
bindMenuItem(menu, handler, bridgeInstance);
}
// 4. 注册到 UI 框架
registerToUIFramework(bridgeInstance);
} catch (Exception e) {
throw new JDSException("运行时绑定失败: " + e.getMessage(), e);
}
}
}
绑定特性:
- 反射绑定:使用 Java 反射机制
- 类型安全:编译期检查类型匹配
- 生命周期管理:自动管理组件生命周期
- 事件传播:支持事件冒泡和捕获
2.3 性能优化
2.3.1 生成缓存
java
public class GenerationCache {
private Map<String, JavaGenSource> cache = new ConcurrentHashMap<>();
public JavaGenSource getOrGenerate(String key, Callable<JavaGenSource> generator)
throws JDSException {
return cache.computeIfAbsent(key, k -> {
try {
return generator.call();
} catch (Exception e) {
throw new JDSException("生成失败: " + e.getMessage(), e);
}
});
}
public void invalidate(String key) {
cache.remove(key);
}
}
2.3.2 并行生成
java
public class ParallelGenerator {
private ExecutorService executor = Executors.newFixedThreadPool(4);
public List<JavaGenSource> generateParallel(
List<GenJavaTask> tasks) throws JDSException {
try {
List<Future<JavaGenSource>> futures = new ArrayList<>();
for (GenJavaTask task : tasks) {
Future<JavaGenSource> future = executor.submit(task);
futures.add(future);
}
List<JavaGenSource> results = new ArrayList<>();
for (Future<JavaGenSource> future : futures) {
results.add(future.get());
}
return results;
} catch (Exception e) {
throw new JDSException("并行生成失败: " + e.getMessage(), e);
}
}
}
三、分层 SKILLS 设计
3.1 Skill 架构设计
基于 BridgeCode 机制,ooder 设计了分层 SKILLS 架构,为 LLM 提供结构化的知识访问能力:
┌─────────────────────────────────────────────┐
│ Skill 知识层(Knowledge Layer) │
│ - Foundation Skill │
│ - Module Skill │
│ - Component Skill │
│ - Metadata Skill │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Skill 执行层(Execution Layer) │
│ - Skill Loader │
│ - Skill Context │
│ - Skill Orchestrator │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Skill 集成层(Integration Layer) │
│ - Trae Solo Integration │
│ - LLM Provider │
│ - Tool Registry │
└─────────────────────────────────────────────┘
3.2 Foundation Skill 设计
职责:提供基础组件的知识和生成能力
java
public class FoundationSkill {
private static final String NAME = "foundation";
private static final String DESCRIPTION = "基础组件 Skill";
public SkillContext load() {
SkillContext context = new SkillContext();
// 1. 加载 NlpBaseUIComponent 知识
context.addClass(NlpBaseUIComponent.class);
// 2. 加载生成器知识
context.addGenerator(GenJavaTask.class);
// 3. 加载模板知识
context.addTemplate("base.ftl");
return context;
}
public List<SkillAction> getActions() {
return Arrays.asList(
new SkillAction("create-base-component", "创建基础组件"),
new SkillAction("initialize-component", "初始化组件"),
new SkillAction("validate-component", "验证组件")
);
}
}
知识内容:
- 抽象类定义
- 初始化方法签名
- 组件类型枚举
- 基础生成器模板
3.3 Module Skill 设计
职责:提供模块组件的知识和生成能力
java
public class ModuleSkill {
private static final String NAME = "module";
private static final String DESCRIPTION = "模块组件 Skill";
public SkillContext load() {
SkillContext context = new SkillContext();
// 1. 加载 ModuleUIComponent 知识
context.addClass(ModuleUIComponent.class);
context.addClass(CustomModuleUIComponent.class);
// 2. 加载生命周期方法
context.addMethod("setCurrComponent");
context.addMethod("findComponentByAlias");
// 3. 加载生成器
context.addGenerator(GenRepositoryViewJava.class);
return context;
}
public List<SkillAction> getActions() {
return Arrays.asList(
new SkillAction("create-module", "创建模块"),
new SkillAction("bind-component", "绑定组件"),
new SkillAction("manage-lifecycle", "管理生命周期")
);
}
}
知识内容:
- 模块类定义
- 生命周期管理方法
- 组件查找机制
- 仓储层生成器
3.4 Component Skill 设计
职责:提供具体组件的知识和生成能力
java
public class ComponentSkill {
private static final String NAME = "component";
private static final String DESCRIPTION = "组件 Skill";
public SkillContext load() {
SkillContext context = new SkillContext();
// 1. 加载具体组件知识
context.addClass(NlpGroupUIComponent.class);
context.addClass(NlpGridUIComponent.class);
context.addClass(TreeGridUIComponent.class);
// 2. 加载组件配置
context.addConfig("group-config");
context.addConfig("grid-config");
// 3. 加载视图生成器
context.addGenerator(GenCustomViewJava.class);
return context;
}
public List<SkillAction> getActions() {
return Arrays.asList(
new SkillAction("create-group", "创建分组组件"),
new SkillAction("create-grid", "创建网格组件"),
new SkillAction("create-tree", "创建树形组件")
);
}
}
知识内容:
- 具体组件类定义
- 组件配置模式
- 视图层生成器
- 组件间关系
3.5 Metadata Skill 设计
职责:提供元数据的知识和生成能力
java
public class MetadataSkill {
private static final String NAME = "metadata";
private static final String DESCRIPTION = "元数据 Skill";
public SkillContext load() {
SkillContext context = new SkillContext();
// 1. 加载元数据类
context.addClass(CustomViewMeta.class);
context.addClass(CustomDataMeta.class);
context.addClass(MethodConfig.class);
// 2. 加载解析器
context.addParser(MetadataParser.class);
// 3. 加载验证规则
context.addValidator(MetadataValidator.class);
return context;
}
public List<SkillAction> getActions() {
return Arrays.asList(
new SkillAction("parse-metadata", "解析元数据"),
new SkillAction("validate-metadata", "验证元数据"),
new SkillAction("generate-code", "生成代码")
);
}
}
知识内容:
- 元数据类定义
- 元数据解析器
- 验证规则
- 生成规则
3.6 Skill 协作机制
java
public class SkillOrchestrator {
private Map<String, Skill> skills = new ConcurrentHashMap<>();
public void registerSkill(Skill skill) {
skills.put(skill.getName(), skill);
}
public SkillContext execute(String skillName, Map<String, Object> params)
throws JDSException {
Skill skill = skills.get(skillName);
if (skill == null) {
throw new JDSException("Skill 不存在: " + skillName);
}
// 1. 加载 Skill 上下文
SkillContext context = skill.load();
// 2. 应用参数
context.applyParams(params);
// 3. 执行 Skill
SkillResult result = skill.execute(context);
return result;
}
public List<SkillAction> getAllActions() {
return skills.values().stream()
.flatMap(skill -> skill.getActions().stream())
.collect(Collectors.toList());
}
}
四、Trae Solo Skill 构建实践
4.1 Trae Solo 环境配置
4.1.1 项目结构
trae-solo-project/
├── .trae/
│ ├── rules/
│ │ ├── project_rules.md # 项目规则
│ │ └── skill_rules.md # Skill 规则
│ └── skills/
│ ├── foundation-skill.md # Foundation Skill
│ ├── module-skill.md # Module Skill
│ ├── component-skill.md # Component Skill
│ └── metadata-skill.md # Metadata Skill
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── net/ooder/
│ │ │ └── engine/
│ │ │ ├── codegen/ # 代码生成器
│ │ │ └── ub/ # BridgeCode
│ │ └── resources/
│ │ └── templates/ # Freemarker 模板
│ └── test/
│ └── java/
│ └── net/ooder/
│ └── engine/
│ └── codegen/
└── pom.xml
4.1.2 配置文件
.trae/rules/project_rules.md:
markdown
# Trae Solo 项目规则
## 代码生成规则
1. 所有生成的代码必须遵循 Java 编码规范
2. 生成的类必须添加 @Generated 注解
3. 生成的代码必须包含完整的 Javadoc
4. 生成的代码必须通过编译检查
## Skill 使用规则
1. LLM 必须通过 Skill 访问代码生成知识
2. LLM 不能直接修改生成的代码
3. LLM 必须使用 Skill 提供的 Action
4. LLM 必须遵循 Skill 的执行顺序
## 质量保证规则
1. 所有生成的代码必须经过单元测试
2. 所有生成的代码必须经过集成测试
3. 所有生成的代码必须经过代码审查
.trae/rules/skill_rules.md:
markdown
# Skill 规则
## Skill 定义规则
1. 每个 Skill 必须定义清晰的职责边界
2. 每个 Skill 必须提供完整的知识内容
3. 每个 Skill 必须定义可执行的 Action
4. 每个 Skill 必须提供使用示例
## Skill 加载规则
1. Skill 必须支持懒加载
2. Skill 必须支持缓存
3. Skill 必须支持热更新
4. Skill 必须支持版本管理
## Skill 执行规则
1. Skill 执行必须支持参数传递
2. Skill 执行必须支持上下文管理
3. Skill 执行必须支持错误处理
4. Skill 执行必须支持结果返回
4.2 Skill 实现实践
4.2.1 Foundation Skill 实现
.trae/skills/foundation-skill.md:
markdown
# Foundation Skill
## 概述
Foundation Skill 提供基础组件的知识和生成能力,是所有其他 Skill 的基础。
## 知识内容
### 核心类
#### NlpBaseUIComponent
```java
public abstract class NlpBaseUIComponent extends UIComponent {
private String componentType;
private boolean initialized;
public abstract void initializeFromNaturalLanguage(String naturalLanguage);
public abstract void initializeFromConfig(Object config);
public String getComponentType() {
return componentType;
}
public boolean isInitialized() {
return initialized;
}
}
职责:
- 提供组件类型管理
- 提供初始化状态管理
- 定义抽象初始化方法
生成器
GenJavaTask
java
public abstract class GenJavaTask implements Callable<List<JavaGenSource>> {
protected JavaGenSource javaGen;
protected CustomViewMeta viewMeta;
protected String euClassName;
protected Chrome chrome;
public abstract List<JavaGenSource> build() throws JDSException;
}
职责:
- 提供统一的生成接口
- 提供通用的生成工具方法
- 管理生成上下文
可执行 Action
create-base-component
描述:创建基础组件
参数:
componentType:组件类型className:类名packageName:包名
执行流程:
- 验证参数
- 创建 NlpBaseUIComponent 子类
- 生成初始化方法
- 返回生成的代码
示例:
用户:创建一个基础组件
LLM:使用 Foundation Skill 的 create-base-component Action
参数:{"componentType": "CUSTOM", "className": "MyComponent", "packageName": "net.ooder.example"}
结果:生成 MyComponent.java
initialize-component
描述:初始化组件
参数:
component:组件实例config:配置对象
执行流程:
- 验证配置
- 调用 initializeFromConfig 方法
- 设置初始化状态
- 返回初始化结果
示例:
用户:初始化组件
LLM:使用 Foundation Skill 的 initialize-component Action
参数:{"component": "myComponent", "config": {"type": "FORM"}}
结果:组件初始化完成
validate-component
描述:验证组件
参数:
component:组件实例
执行流程:
- 检查组件类型
- 检查初始化状态
- 检查配置完整性
- 返回验证结果
示例:
用户:验证组件
LLM:使用 Foundation Skill 的 validate-component Action
参数:{"component": "myComponent"}
结果:验证通过
使用场景
场景 1:创建自定义基础组件
用户需求:创建一个自定义基础组件
LLM 处理:
1. 加载 Foundation Skill
2. 调用 create-base-component Action
3. 生成组件代码
4. 返回生成的代码
场景 2:初始化现有组件
用户需求:初始化一个现有组件
LLM 处理:
1. 加载 Foundation Skill
2. 调用 initialize-component Action
3. 执行初始化逻辑
4. 返回初始化结果
最佳实践
-
优先使用 Foundation Skill:所有基础操作都应该通过 Foundation Skill 完成
-
遵循初始化流程:确保组件正确初始化
-
验证组件状态:在执行操作前验证组件状态
-
处理初始化错误:提供清晰的错误信息
4.2.2 Module Skill 实现
.trae/skills/module-skill.md:
markdown# Module Skill ## 概述 Module Skill 提供模块组件的知识和生成能力,管理组件的生命周期和依赖关系。 ## 知识内容 ### 核心类 #### ModuleUIComponent ```java public class ModuleUIComponent<M extends UIComponent> extends UIComponent<ModuleProperties, ModuleEventEnum> { private String className; private String desc; private ModuleViewType moduleViewType; private Map<String, Object> valueMap; private UIModule UIModule; private CustomModuleMeta moduleBean; private MethodConfig methodAPIBean; private DomainInst domainInst; private ModuleProperties properties; private M currComponent; private UIComponent navUIComponent; private ModuleViewConfig viewConfig; private List<String> dependencies; private List<String> required; private Map<String, ModuleFunction> functions; private List<ModuleFormulaInst> formulas; private Map<String, String> customFunctions; private String customAppend; private String afterAppend; private Map<String, String> moduleVar; private Map<String, UIComponent> components; public void setCurrComponent(M currComponent) { this.currComponent = currComponent; if (currComponent != null) { this.currComponentAlias = currComponent.getAlias(); if (currComponent.getParent() == null) { currComponent.setParent(this); } this.components.put(currComponentAlias, currComponent); ComponentType type = ComponentType.fromType(currComponent.getKey()); moduleViewType = ModuleViewType.getModuleViewByCom(type); properties.setCurrComponentAlias(currComponentAlias); } else { this.currComponentAlias = null; properties.setCurrComponentAlias(null); } } public UIComponent findComponentByAlias(String alias) { List<UIComponent> UIComponentList = this.findComponentsByAlias(alias); UIComponent UIComponent = null; if (UIComponentList.size() > 0) { UIComponent = UIComponentList.get(0); } return UIComponent; } }
职责:
- 管理模块生命周期
- 管理组件依赖
- 提供组件查找功能
- 处理模块事件
生成器
GenRepositoryViewJava
java
public class GenRepositoryViewJava extends GenJavaTask {
@Override
public List<JavaGenSource> build() throws JDSException {
List<JavaGenSource> sources = new ArrayList<>();
// 1. 生成 VO 接口
sources.add(generateVOInterface());
// 2. 生成 Service 接口
sources.add(generateServiceInterface());
// 3. 生成 Repository 接口
sources.add(generateRepositoryInterface());
// 4. 生成 RepositoryImpl 实现
sources.add(generateRepositoryImpl());
return sources;
}
}
职责:
- 生成仓储层代码
- 生成服务层代码
- 生成数据访问对象
- 管理依赖关系
可执行 Action
create-module
描述:创建模块
参数:
moduleName:模块名称className:类名packageName:包名components:组件列表
执行流程:
- 验证参数
- 创建 ModuleUIComponent 子类
- 生成仓储层代码
- 绑定组件
- 返回生成的代码
示例:
用户:创建一个模块
LLM:使用 Module Skill 的 create-module Action
参数:{"moduleName": "UserModule", "className": "UserModule", "packageName": "net.ooder.example", "components": ["grid", "form"]}
结果:生成 UserModule.java 和相关仓储代码
bind-component
描述:绑定组件
参数:
module:模块实例component:组件实例alias:组件别名
执行流程:
- 验证模块和组件
- 调用 setCurrComponent 方法
- 更新组件依赖
- 返回绑定结果
示例:
用户:绑定组件
LLM:使用 Module Skill 的 bind-component Action
参数:{"module": "userModule", "component": "userGrid", "alias": "grid"}
结果:组件绑定完成
manage-lifecycle
描述:管理生命周期
参数:
module:模块实例action:生命周期动作(init/destroy)
执行流程:
- 验证模块状态
- 执行生命周期动作
- 触发生命周期事件
- 返回执行结果
示例:
用户:初始化模块
LLM:使用 Module Skill 的 manage-lifecycle Action
参数:{"module": "userModule", "action": "init"}
结果:模块初始化完成
使用场景
场景 1:创建用户管理模块
用户需求:创建一个用户管理模块
LLM 处理:
1. 加载 Module Skill
2. 调用 create-module Action
3. 生成模块代码和仓储代码
4. 返回生成的代码
场景 2:绑定网格组件到模块
用户需求:绑定网格组件到模块
LLM 处理:
1. 加载 Module Skill
2. 调用 bind-component Action
3. 执行绑定逻辑
4. 返回绑定结果
最佳实践
-
使用模块化设计:将功能分解为独立的模块
-
管理组件依赖:明确组件之间的依赖关系
-
实现生命周期管理:提供完整的生命周期支持
-
使用仓储模式:分离数据访问逻辑
4.2.3 Component Skill 实现
.trae/skills/component-skill.md:
markdown# Component Skill ## 概述 Component Skill 提供具体组件的知识和生成能力,包括分组组件、网格组件、树形组件等。 ## 知识内容 ### 核心类 #### NlpGroupUIComponent ```java public class NlpGroupUIComponent<M extends CustomFieldGroupUIComponent> extends CustomModuleUIComponent<M> { void init(MethodConfig methodConfig) throws JDSException { CustomGroupFormViewMeta viewBean = (CustomGroupFormViewMeta) methodConfig.getView(); CustomGroupDataMeta dataBean = (CustomGroupDataMeta) methodConfig.getDataBean(); if (dataBean != null) { this.dataUrl = dataBean.getDataUrl(); this.saveUrl = dataBean.getSaveUrl(); this.searchUrl = dataBean.getSearchUrl(); this.reSetUrl = dataBean.getReSetUrl(); } CustomFieldGroupUIComponent currComponent = new CustomFieldGroupUIComponent(UIModule, methodConfig, valueMap); this.addChildLayoutNav(currComponent); this.setCurrComponent((M) currComponent); this.fillAction(viewBean); this.fillToolBar(viewBean.getToolBar(), currComponent); this.fillContextAction(viewBean.getContextMenuBean(), currComponent); if (viewBean.getOnReady() != null) { for (ModuleOnReadyEventEnum eventEnum : viewBean.getOnReady()) { this.addModuleEvent(eventEnum); } } if (viewBean.getOnDestroy() != null) { for (CustomOnDestroyEventEnum eventEnum : viewBean.getOnDestroy()) { this.addModuleEvent(eventEnum); } } } }
职责:
- 管理分组字段
- 处理分组事件
- 生成 API 调用
- 管理工具栏和上下文菜单
NlpGridUIComponent
java
public class NlpGridUIComponent extends CustomGridUIComponent {
public NlpGridUIComponent(MethodConfig methodConfig) {
super();
CustomGridViewMeta viewBean = (CustomGridViewMeta) methodConfig.getView();
init(viewBean);
}
public NlpGridUIComponent(CustomGridViewMeta viewBean) {
super();
init(viewBean);
}
public void init(CustomGridViewMeta viewBean) {
this.setProperties(new ClassGridProperties(viewBean));
this.setAlias(viewBean.getName());
}
}
职责:
- 管理网格数据
- 处理网格事件
- 提供网格交互
- 支持分页和排序
生成器
GenCustomViewJava
java
public class GenCustomViewJava extends GenJavaTask {
@Override
public List<JavaGenSource> build() throws JDSException {
List<JavaGenSource> sources = new ArrayList<>();
// 1. 生成视图类
sources.add(generateViewClass());
// 2. 生成字段配置
sources.add(generateFieldConfigs());
// 3. 生成事件处理器
sources.add(generateEventHandlers());
return sources;
}
}
职责:
- 生成视图层代码
- 生成字段配置
- 生成事件处理器
- 管理视图依赖
可执行 Action
create-group
描述:创建分组组件
参数:
groupName:分组名称fields:字段列表events:事件列表
执行流程:
- 验证参数
- 创建 NlpGroupUIComponent 实例
- 生成视图代码
- 生成仓储代码
- 返回生成的代码
示例:
用户:创建一个分组组件
LLM:使用 Component Skill 的 create-group Action
参数:{"groupName": "UserGroup", "fields": [...], "events": [...]}
结果:生成 UserGroup.java 和相关代码
create-grid
描述:创建网格组件
参数:
gridName:网格名称columns:列配置dataUrl:数据 URL
执行流程:
- 验证参数
- 创建 NlpGridUIComponent 实例
- 生成视图代码
- 生成仓储代码
- 返回生成的代码
示例:
用户:创建一个网格组件
LLM:使用 Component Skill 的 create-grid Action
参数:{"gridName": "UserGrid", "columns": [...], "dataUrl": "/api/users"}
结果:生成 UserGrid.java 和相关代码
create-tree
描述:创建树形组件
参数:
treeName:树形名称treeField:树字段parentField:父字段
执行流程:
- 验证参数
- 创建 TreeGridUIComponent 实例
- 生成视图代码
- 生成仓储代码
- 返回生成的代码
示例:
用户:创建一个树形组件
LLM:使用 Component Skill 的 create-tree Action
参数:{"treeName": "DepartmentTree", "treeField": "id", "parentField": "parentId"}
结果:生成 DepartmentTree.java 和相关代码
使用场景
场景 1:创建用户分组表单
用户需求:创建一个用户分组表单
LLM 处理:
1. 加载 Component Skill
2. 调用 create-group Action
3. 生成分组组件代码
4. 返回生成的代码
场景 2:创建用户数据网格
用户需求:创建一个用户数据网格
LLM 处理:
1. 加载 Component Skill
2. 调用 create-grid Action
3. 生成网格组件代码
4. 返回生成的代码
最佳实践
-
选择合适的组件类型:根据需求选择分组、网格或树形组件
-
配置字段和列:合理配置字段和列属性
-
处理事件和交互:实现必要的事件处理和交互逻辑
-
优化性能:使用分页、懒加载等优化技术
4.2.4 Metadata Skill 实现
.trae/skills/metadata-skill.md:
markdown# Metadata Skill ## 概述 Metadata Skill 提供元数据的知识和生成能力,包括元数据解析、验证和代码生成。 ## 知识内容 ### 核心类 #### CustomViewMeta ```java public abstract class CustomViewMeta<F extends FieldFormConfig, I extends UIItem, C extends UIComponent> { private String name; private String caption; private String desc; private String methodName; private String domainId; private String sourceClassName; private ModuleViewType moduleViewType; private List<F> allFields; private List<F> fields; private List<Event> events; private List<MenuItem> menus; private List<ToolBar> toolBars; private List<BottomBar> bottomBars; private List<ContextMenu> contextMenus; private List<ModuleFormulaInst> formulas; private List<CustomBean> annotationBeans; public abstract F createFieldConfig(); public abstract I createUIItem(); public abstract C createUIComponent(); public List<CustomBean> getAnnotationBeans() { List<CustomBean> annotationBeans = new ArrayList<>(); if (this.getModuleBean() != null) { annotationBeans.addAll(this.getModuleBean().getAnnotationBeans()); } if (this.getDataBean() != null) { annotationBeans.add(this.getDataBean()); } if (this.getFieldAggConfig() != null) { annotationBeans.addAll(this.getFieldAggConfig().getAnnotationBeans()); } return annotationBeans; } }
职责:
- 存储视图配置信息
- 管理字段和事件
- 支持视图的动态更新
- 提供注解信息
CustomDataMeta
java
public abstract class CustomDataMeta {
private String dataUrl;
private String editorPath;
private String addPath;
private String delPath;
private String sortPath;
private String saveRowPath;
private String saveAllRowPath;
private String searchUrl;
private String reloadUrl;
private String selectUrl;
private String unSelectUrl;
private String selectAllUrl;
private String unSelectAllUrl;
private String exportUrl;
private String importUrl;
private String customUrl;
}
职责:
- 存储数据配置信息
- 管理数据 URL 和路径
- 支持数据的动态配置
- 提供数据访问接口
MethodConfig
java
public class MethodConfig<T extends CustomViewMeta, K extends CustomDataMeta> implements Comparable<MethodConfig> {
private String className;
private String desc;
private ModuleViewType moduleViewType;
private UIModule UIModule;
private CustomModuleMeta moduleBean;
private MethodConfig methodAPIBean;
private DomainInst domainInst;
private T view;
private K dataBean;
private BridgeClass bridgeClass;
private BridgeClass parentClass;
private String url;
private String caption;
private String methodName;
private String expression;
private String filter;
private String itemsExpression;
private String metaInfo;
private String fieldInfo;
private RequestMappingBean requestMapping;
private RequestBodyBean requestBody;
private Set<RequestParamBean> paramSet;
private RouteMenuMeta routeMenuBean;
private FieldAggConfig fieldAggConfig;
private CustomFieldMeta FieldMeta;
private RefBean refBean;
private CustomAPICallMeta api;
private List<CustomBean> annotationBeans;
public List<CustomBean> getAnnotationBeans() {
List<CustomBean> annotationBeans = new ArrayList<>();
if (this.getApi() != null) {
annotationBeans.addAll(this.getApi().getAnnotationBeans());
}
if (this.isModule()) {
annotationBeans.addAll(this.getModuleBean().getAnnotationBeans());
if (this.getDataBean() != null) {
annotationBeans.add(this.getDataBean());
}
}
if (routeMenuBean != null) {
annotationBeans.add(routeMenuBean);
}
if (this.getFieldAggConfig() != null) {
List<CustomBean> FieldMetas = this.getFieldAggConfig().getAnnotationBeans();
for (CustomBean customBean : FieldMetas) {
if (!annotationBeans.contains(customBean)) {
annotationBeans.add(customBean);
}
}
}
if (requestMapping != null && this.getPublicMethod()) {
annotationBeans.add(requestMapping);
}
if (getResponseBody() || api != null) {
if (!annotationBeans.contains(new SimpleCustomBean(ResponseBody.class))) {
annotationBeans.add(new SimpleCustomBean(ResponseBody.class));
}
}
return annotationBeans;
}
@JSONField(serialize = false)
public String getMetaInfo() {
if (this.getMethod() != null) {
List<RequestParamBean> params = new ArrayList(this.getParamSet());
if (isModule() && parentEuPackage != null) {
String euClassName = parentEuPackage + "." + getJavaSimpleName();
this.metaInfo = MethodUtil.toMethodStr(this.getMethod(),
getViewType(), euClassName, requestBody, params).toString();
} else {
this.metaInfo = MethodUtil.toMethodStr(this.getMethod(),
getViewType(), getJavaSimpleName(), requestBody, params).toString();
}
}
return metaInfo;
}
}
职责:
- 管理方法的元数据
- 连接业务方法和 UI 组件
- 提供注解信息
- 生成方法签名
可执行 Action
parse-metadata
描述:解析元数据
参数:
source:元数据源(JSON/注解)type:元数据类型
执行流程:
- 验证源格式
- 解析元数据
- 验证元数据完整性
- 返回解析结果
示例:
用户:解析元数据
LLM:使用 Metadata Skill 的 parse-metadata Action
参数:{"source": "{\"viewClassName\": \"UserView\", ...}", "type": "json"}
结果:返回 MethodConfig 对象
validate-metadata
描述:验证元数据
参数:
metadata:元数据对象
执行流程:
- 验证必填字段
- 验证字段类型
- 验证引用关系
- 返回验证结果
示例:
用户:验证元数据
LLM:使用 Metadata Skill 的 validate-metadata Action
参数:{"metadata": methodConfig}
结果:验证通过
generate-code
描述:生成代码
参数:
metadata:元数据对象type:代码类型
执行流程:
- 选择生成器
- 执行代码生成
- 编译生成的代码
- 返回生成的代码
示例:
用户:生成代码
LLM:使用 Metadata Skill 的 generate-code Action
参数:{"metadata": methodConfig, "type": "view"}
结果:生成视图代码和仓储代码
使用场景
场景 1:从 JSON 解析元数据
用户需求:从 JSON 解析元数据
LLM 处理:
1. 加载 Metadata Skill
2. 调用 parse-metadata Action
3. 解析 JSON 配置
4. 返回 MethodConfig 对象
场景 2:生成组件代码
用户需求:生成组件代码
LLM 处理:
1. 加载 Metadata Skill
2. 调用 generate-code Action
3. 生成视图代码和仓储代码
4. 返回生成的代码
最佳实践
-
使用元数据驱动:通过元数据配置生成代码
-
验证元数据完整性:确保元数据配置正确
-
选择合适的代码类型:根据需求选择生成的代码类型
-
优化生成性能:使用缓存和并行生成
4.3 Skill 集成实现
4.3.1 Skill Loader 实现
javapublic class SkillLoader { private Map<String, Skill> skillCache = new ConcurrentHashMap<>(); public Skill loadSkill(String skillName) throws JDSException { // 1. 检查缓存 Skill cachedSkill = skillCache.get(skillName); if (cachedSkill != null) { return cachedSkill; } // 2. 加载 Skill 定义 String skillPath = ".trae/skills/" + skillName + "-skill.md"; String skillContent = readFile(skillPath); // 3. 解析 Skill 定义 Skill skill = parseSkillDefinition(skillContent); // 4. 缓存 Skill skillCache.put(skillName, skill); return skill; } public void invalidateSkill(String skillName) { skillCache.remove(skillName); } public List<String> getAvailableSkills() { File skillsDir = new File(".trae/skills"); File[] skillFiles = skillsDir.listFiles((dir, name) -> name.endsWith("-skill.md")); return Arrays.stream(skillFiles) .map(File::getName) .map(name -> name.replace("-skill.md", "")) .collect(Collectors.toList()); } }
4.3.2 Skill Context 实现
java
public class SkillContext {
private Map<String, Object> data = new HashMap<>();
private List<String> loadedClasses = new ArrayList<>();
private List<String> loadedGenerators = new ArrayList<>();
private List<String> loadedTemplates = new ArrayList<>();
public void addClass(Class<?> clazz) {
String className = clazz.getName();
if (!loadedClasses.contains(className)) {
loadedClasses.add(className);
}
}
public void addGenerator(Class<?> generator) {
String generatorName = generator.getName();
if (!loadedGenerators.contains(generatorName)) {
loadedGenerators.add(generatorName);
}
}
public void addTemplate(String templateName) {
if (!loadedTemplates.contains(templateName)) {
loadedTemplates.add(templateName);
}
}
public void applyParams(Map<String, Object> params) {
if (params != null) {
data.putAll(params);
}
}
public Object getParam(String key) {
return data.get(key);
}
public List<String> getLoadedClasses() {
return new ArrayList<>(loadedClasses);
}
public List<String> getLoadedGenerators() {
return new ArrayList<>(loadedGenerators);
}
public List<String> getLoadedTemplates() {
return new ArrayList<>(loadedTemplates);
}
}
4.3.3 LLM 集成示例
java
public class LLMIntegration {
private SkillOrchestrator orchestrator;
private SkillLoader skillLoader;
public LLMIntegration() {
this.skillLoader = new SkillLoader();
this.orchestrator = new SkillOrchestrator();
// 注册所有 Skill
registerSkills();
}
private void registerSkills() {
orchestrator.registerSkill(new FoundationSkill());
orchestrator.registerSkill(new ModuleSkill());
orchestrator.registerSkill(new ComponentSkill());
orchestrator.registerSkill(new MetadataSkill());
}
public String processUserRequest(String userRequest) throws JDSException {
// 1. 分析用户请求
RequestAnalysis analysis = analyzeRequest(userRequest);
// 2. 选择合适的 Skill
String skillName = selectSkill(analysis);
// 3. 准备参数
Map<String, Object> params = prepareParams(analysis);
// 4. 执行 Skill
SkillResult result = orchestrator.execute(skillName, params);
// 5. 返回结果
return formatResult(result);
}
private RequestAnalysis analyzeRequest(String userRequest) {
RequestAnalysis analysis = new RequestAnalysis();
// 分析请求类型
if (userRequest.contains("创建") && userRequest.contains("基础组件")) {
analysis.setSkillName("foundation");
analysis.setActionName("create-base-component");
} else if (userRequest.contains("创建") && userRequest.contains("模块")) {
analysis.setSkillName("module");
analysis.setActionName("create-module");
} else if (userRequest.contains("创建") && userRequest.contains("网格")) {
analysis.setSkillName("component");
analysis.setActionName("create-grid");
} else if (userRequest.contains("解析") && userRequest.contains("元数据")) {
analysis.setSkillName("metadata");
analysis.setActionName("parse-metadata");
}
return analysis;
}
private String selectSkill(RequestAnalysis analysis) {
return analysis.getSkillName();
}
private Map<String, Object> prepareParams(RequestAnalysis analysis) {
Map<String, Object> params = new HashMap<>();
// 从用户请求中提取参数
// ...
return params;
}
private String formatResult(SkillResult result) {
// 格式化结果
return result.toString();
}
}
4.4 实战案例
4.4.1 案例 1:创建用户管理模块
用户请求:
创建一个用户管理模块,包含用户列表网格和用户编辑表单
LLM 处理流程:
-
分析请求:
- 识别为创建模块请求
- 选择 Module Skill
-
执行 Skill:
- 调用 create-module Action
- 生成模块代码
-
生成组件:
- 调用 Component Skill 的 create-grid Action
- 生成用户网格代码
- 调用 Component Skill 的 create-group Action
- 生成分组表单代码
-
生成仓储:
- 调用 Metadata Skill 的 generate-code Action
- 生成仓储代码
-
返回结果:
已成功创建用户管理模块: - UserModule.java - UserGrid.java - UserForm.java - UserRepository.java - UserService.java
4.4.2 案例 2:从 JSON 配置生成代码
用户请求:
从以下 JSON 配置生成代码:
{
"viewClassName": "net.ooder.example.UserTableView",
"moduleViewType": "GRIDCONFIG",
"fields": [
{"fieldname": "id", "caption": "ID", "type": "input", "editable": false},
{"fieldname": "name", "caption": "姓名", "type": "input", "editable": true},
{"fieldname": "age", "caption": "年龄", "type": "number", "editable": true}
]
}
LLM 处理流程:
-
分析请求:
- 识别为元数据解析请求
- 选择 Metadata Skill
-
解析元数据:
- 调用 parse-metadata Action
- 解析 JSON 配置
- 生成 MethodConfig 对象
-
生成代码:
- 调用 generate-code Action
- 生成视图代码
- 生成仓储代码
-
编译代码:
- 调用动态编译
- 生成类文件
-
返回结果:
已成功生成代码: - UserTableView.java - UserRepository.java - UserService.java 编译成功
4.4.3 案例 3:创建树形组织结构
用户请求:
创建一个部门树形组件,显示组织结构
LLM 处理流程:
-
分析请求:
- 识别为创建树形组件请求
- 选择 Component Skill
-
执行 Skill:
- 调用 create-tree Action
- 生成树形组件代码
-
生成仓储:
- 调用 Metadata Skill 的 generate-code Action
- 生成仓储代码
-
返回结果:
已成功创建部门树形组件: - DepartmentTree.java - DepartmentRepository.java - DepartmentService.java
五、总结与展望
5.1 关键成果
5.1.1 BridgeCode 设计成果
-
元数据驱动架构:
- 实现了配置与实现的完全解耦
- 支持多种配置方式(JSON/注解)
- 提供了灵活的扩展能力
-
分层生成系统:
- 视图层、仓储层、聚合层三层生成
- 31 个生成器覆盖所有场景
- 支持增量构建和并行生成
-
动态编译机制:
- 运行时编译生成的代码
- 支持热更新和替换
- 提供了完整的生命周期管理
5.1.2 分层 SKILLS 设计成果
-
清晰的职责划分:
- Foundation Skill:基础组件能力
- Module Skill:模块管理能力
- Component Skill:具体组件能力
- Metadata Skill:元数据处理能力
-
可扩展的架构:
- 支持新增 Skill
- 支持 Skill 组合
- 支持 Skill 版本管理
-
完整的 Action 体系:
- 每个 Skill 提供多个 Action
- Action 支持参数传递
- Action 支持结果返回
5.1.3 Trae Solo 实践成果
-
完整的集成方案:
- Skill Loader:加载和管理 Skill
- Skill Context:管理执行上下文
- LLM Integration:集成 LLM 和 Skill
-
实战验证:
- 通过多个实战案例验证
- 覆盖主要使用场景
- 提供了完整的示例
-
最佳实践指导:
- 提供了详细的最佳实践
- 提供了常见问题的解决方案
- 提供了性能优化建议
5.2 技术亮点
5.2.1 设计模式应用
-
模板方法模式:
- GenJavaTask 定义生成流程
- 子类实现具体生成逻辑
-
策略模式:
- 不同的生成器实现不同的生成策略
- 运行时选择合适的生成器
-
工厂模式:
- SkillLoader 创建 Skill 实例
- 根据名称动态加载 Skill
-
观察者模式:
- 组件生命周期事件通知
- Skill 执行结果通知
5.2.2 性能优化
-
缓存机制:
- Skill 缓存
- 生成结果缓存
- 模板缓存
-
并行处理:
- 并行生成
- 并行编译
- 异步加载
-
增量构建:
- 只生成变更的部分
- 只编译变更的文件
- 减少构建时间
5.2.3 可维护性
-
清晰的代码结构:
- 分层架构
- 职责明确
- 易于理解和维护
-
完整的文档:
- Skill 定义文档
- 使用示例文档
- 最佳实践文档
-
自动化测试:
- 单元测试
- 集成测试
- 端到端测试
5.3 未来展望
5.3.1 短期目标
-
完善 Skill 体系:
- 增加更多 Skill
- 优化现有 Skill
- 提高 Skill 质量
-
提升生成性能:
- 优化生成算法
- 提高并行度
- 减少内存占用
-
增强集成能力:
- 支持更多 LLM
- 支持更多工具
- 提供更好的集成体验
六、结论
本文深入解析了 ooder 框架的 BridgeCode 机制,从设计原理、生成编译流程,到分层 SKILLS 设计,最后展示了在 Trae Solo 环境中的 Skill 构建实践。
关键收获
-
BridgeCode 设计原理:
- 元数据驱动的三层架构
- 31 个生成器覆盖所有场景
- 动态编译和运行时绑定
-
分层 SKILLS 设计:
- Foundation、Module、Component、Metadata 四层 Skill
- 清晰的职责划分
- 完整的 Action 体系
-
Trae Solo 实践:
- 完整的集成方案
- 多个实战案例
- 详细的最佳实践
这种设计既保持了架构的清晰性,又提供了强大的扩展能力,为 LLM 的使用和后续开发提供了坚实的基础。通过元数据驱动的代码生成和分层 SKILLS 设计,ooder 框架实现了高效的 A2UI 组件开发,为开发者提供了强大的工具支持。