tinystruct 开发模式 是做什么的?
使用 tinystruct Java 框架构建模块的架构和实现模式——这是一个轻量级、高性能的框架,将 CLI 和 HTTP 视为平等的公民,无需 main() 方法且配置极少。
核心原则
CLI 和 HTTP 是平等的公民。 每个使用 @Action 注解的方法理想情况下应能在不修改的情况下从终端和 Web 浏览器运行。这种“双模式”能力是 tinystruct 的核心设计理念。
何时激活
何时使用
- 通过扩展
AbstractApplication创建新的Application模块。 - 使用
@Action定义路由和命令行操作。 - 通过
Context处理每个请求的状态。 - 使用原生
Builder和Builders组件进行 JSON 序列化。 - 通过
AbstractDataPOJO 进行数据库持久化操作。 - 使用
generate命令从数据库表生成 POJO。 - 实现服务器发送事件 (SSE) 以实现实时推送。
- 通过 multipart 数据处理文件上传。
- 使用
URLRequest和HTTPHandler进行出站 HTTP 请求。 - 在
application.properties中配置数据库连接或系统设置。 - 调试路由冲突 (Actions) 或 CLI 参数解析。
工作原理
tinystruct 框架将任何使用 @Action 注解的方法视为终端和 Web 环境的路由端点。应用程序通过扩展 AbstractApplication 创建,它提供了核心生命周期钩子(如 init())以及对请求 Context 的访问。
路由由 ActionRegistry 处理,它自动将路径段映射到方法参数并注入依赖。对于纯数据服务,应使用原生 Builder 和 Builders 组件进行 JSON 序列化,以保持零依赖的足迹。数据库层使用 AbstractData POJO 配合 XML 映射文件进行 CRUD 操作,无需外部 ORM 库。
示例
基本应用程序 (MyService)
public class MyService extends AbstractApplication {
@Override
public void init() {
this.setTemplateRequired(false); // 对数据/API 应用禁用 .view 查找
}
@Override public String version() { return "1.0.0"; }
@Action("greet")
public String greet() {
return "Hello from tinystruct!";
}
// 路径参数: GET /?q=greet/James OR bin/dispatcher greet/James
@Action("greet")
public String greet(String name) {
return "Hello, " + name + "!";
}
}
HTTP 模式消歧 (login)
@Action(value = "login", mode = Mode.HTTP_POST)
public String doLogin(Request<?, ?> request) throws ApplicationException {
request.getSession().setAttribute("userId", "42");
return "Logged in";
}
原生 JSON 数据处理 (Builder + Builders)
import org.tinystruct.data.component.Builder;
import org.tinystruct.data.component.Builders;
@Action("api/data")
public String getData() throws ApplicationException {
Builders dataList = new Builders();
Builder item = new Builder();
item.put("id", 1);
item.put("name", "James");
dataList.add(item);
Builder response = new Builder();
response.put("status", "success");
response.put("data", dataList);
return response.toString(); // {"status":"success","data":[{"id":1,"name":"James"}]}
}
SSE (服务器发送事件)
import org.tinystruct.http.SSEPushManager;
@Action("sse/connect")
public String connect() {
return "{\"type\":\"connect\",\"message\":\"Connected to SSE\"}";
}
// 推送到特定客户端
String sessionId = getContext().getId();
Builder msg = new Builder();
msg.put("text", "Hello, user!");
SSEPushManager.getInstance().push(sessionId, msg);
// 广播到所有
// 广播到所有
SSEPushManager.getInstance().broadcast(msg);
文件上传
import org.tinystruct.data.FileEntity;
@Action(value = "upload", mode = Mode.HTTP_POST)
public String upload(Request<?, ?> request) throws ApplicationException {
List<FileEntity> files = request.getAttachments();
if (files != null) {
for (FileEntity file : files) {
System.out.println("Uploaded: " + file.getFilename());
}
}
return "Upload OK";
}
MCP 服务器和工具集成
tinystruct 从 SDK 版本 1.7.26 开始提供对模型上下文协议 (MCP) 的原生支持。
MCP API(例如 org.tinystruct.mcp.MCPTool、org.tinystruct.mcp.MCPServer、org.tinystruct.mcp.MCPException)直接包含在核心依赖中:
<dependency>
<groupId>org.tinystruct</groupId>
<artifactId>tinystruct</artifactId>
<version>1.7.26</version>
</dependency>
安全警告 (提示注入): 工具返回值会直接反馈到 AI 模型的上下文窗口中。你必须在将调用者提供的参数包含到工具返回字符串之前对其进行验证和清理。未能清理输入可能导致攻击者注入对抗性指令(提示注入),从而覆盖模型行为。始终验证长度、字符集和空值。
创建 MCP 工具:
- 扩展
org.tinystruct.mcp.MCPTool。 - 使用
@Action注解操作,并通过arguments数组中的@Argument声明参数。 - 接受与
@Argument中键匹配的显式方法参数作为参数。(不要使用getContext().getAttribute(...)来获取工具参数)。
import org.tinystruct.mcp.MCPTool;
import org.tinystruct.mcp.MCPException;
import org.tinystruct.system.annotation.Action;
import org.tinystruct.system.annotation.Argument;
public class MyCustomTool extends MCPTool {
public MyCustomTool() {
super("custom", "A custom tool for demonstrating MCP");
}
@Action(
value = "custom/hello",
description = "Say hello to someone",
arguments = {
@Argument(key = "name", description = "The name to greet", type = "string", optional = false)
}
)
public String hello(String name) throws MCPException {
// 安全性: 在将工具输入返回给模型之前进行验证/清理
// 以防止提示注入漏洞。
if (name == null || name.length() > 50 || !name.matches("^[a-zA-Z0-9 ]+$")) {
throw new MCPException("Invalid name provided");
}
return "Hello, " + name + "!";
}
}
部署 MCP 服务器:
- 扩展
org.tinystruct.mcp.MCPServer。 - 重写
init()并使用this.registerTool()注册你的工具。框架会自动扫描并映射@Action方法。
import org.tinystruct.mcp.MCPServer;
public class MyMCPServer extends MCPServer {
@Override
public void init() {
super.init();
this.registerTool(new MyCustomTool());
}
@Override
public String version() {
return "1.0.0";
}
}
通过 dispatcher 运行服务器:
bin/dispatcher start --import org.tinystruct.system.HttpServer --import com.example.MyMCPServer
配置
设置管理在 src/main/resources/application.properties 中。
# 数据库
driver=org.h2.Driver
database.url=jdbc:h2:~/mydb
database.user=sa
database.password=
# 服务器
default.home.page=hello
server.port=8080
# 区域设置
default.language=en_US
# 会话 (集群环境使用 Redis)
# default.session.repository=org.tinystruct.http.RedisSessionRepository
# redis.host=127.0.0.1
# redis.port=6379
在应用程序中访问配置值:
String port = this.getConfiguration("server.port");
红色标志与反模式
| 症状 | 正确模式 |
|---|---|
导入 com.google.gson 或 com.fasterxml.jackson | 使用 org.tinystruct.data.component.Builder / Builders。 |
使用 List<Builder> 表示 JSON 数组 | 使用 Builders 以避免泛型类型擦除问题。 |
ApplicationRuntimeException: template not found | 对于纯 API 应用,在 init() 中调用 setTemplateRequired(false)。 |
使用 @Action 注解 private 方法 | 动作必须是 public 才能被框架注册。 |
在应用中硬编码 main(String[] args) | 对所有模块使用 bin/dispatcher 作为入口点。 |
手动 ActionRegistry 注册 | 优先使用 @Action 注解进行自动发现。 |
| 运行时未找到动作 | 确保类通过 --import 导入或在 application.properties 中列出。 |
| CLI 参数不可见 | 使用 --key value 传递;通过 getContext().getAttribute("--key") 访问。 |
| 两个方法路径相同,错误的方法被触发 | 设置明确的 mode(例如 HTTP_GET 与 HTTP_POST)以消除歧义。 |
最佳实践
- 粒度应用: 将逻辑拆分成更小、更专注的应用,而不是一个单一的庞大类。
- 在
init()中设置: 利用init()进行设置(配置、数据库),而不是构造函数。不要调用setAction()—— 使用@Action注解。 - 模式感知: 在
@Action中使用Mode参数将敏感操作限制为仅CLI或特定的 HTTP 方法。 - 上下文优于参数: 对于可选的 CLI 标志,使用
getContext().getAttribute("--flag"),而不是向方法签名添加参数。 - 异步事件: 对于由事件触发的繁重任务,在事件处理程序内部使用
CompletableFuture.runAsync()。
技术参考
详细指南可在 references/ 目录中找到:
- 架构与配置 — 抽象、包映射、属性
- 路由与 @Action — 注解详情、模式、参数
- 数据处理 — Builder、Builders、JSON 序列化与解析
- 数据库持久化 — AbstractData POJO、CRUD、映射 XML、POJO 生成
- 系统与使用 — 上下文、会话、SSE、文件上传、事件、网络
- 测试模式 — JUnit 5 单元测试和 HTTP 集成测试
参考源文件 (内部)
src/main/java/org/tinystruct/AbstractApplication.java— 带有生命周期钩子的核心基类src/main/java/org/tinystruct/system/annotation/Action.java— 注解与模式src/main/java/org/tinystruct/application/ActionRegistry.java— 路由引擎src/main/java/org/tinystruct/data/component/Builder.java— JSON 对象序列化器src/main/java/org/tinystruct/data/component/Builders.java— JSON 数组序列化器src/main/java/org/tinystruct/data/component/AbstractData.java— 带有 CRUD 的基础 POJO 类src/main/java/org/tinystruct/data/Mapping.java— 映射 XML 解析器src/main/java/org/tinystruct/data/tools/MySQLGenerator.java— POJO 生成器参考src/main/java/org/tinystruct/data/component/FieldType.java— SQL 到 Java 的类型映射src/main/java/org/tinystruct/data/component/Condition.java— 流畅的 SQL 查询构建器src/main/java/org/tinystruct/http/SSEPushManager.java— SSE 连接管理src/test/java/org/tinystruct/application/ActionRegistryTest.java— 注册表测试示例src/test/java/org/tinystruct/system/HttpServerHttpModeTest.java— HTTP 集成测试模式