tinystruct 開發模式
使用 tinystruct Java 框架建構模組的架構與實作模式——這是一個輕量級且高效能的框架,將 CLI 與 HTTP 視為平等的公民,無需 main() 方法且配置極少。
核心原則
CLI 與 HTTP 是平等的公民。 每一個使用 @Action 註解的方法理想上應能同時在終端機與網頁瀏覽器中執行而無需修改。這種「雙模式」能力是 tinystruct 的核心設計哲學。
何時啟用
使用時機
- 透過繼承
AbstractApplication建立新的Application模組。 - 使用
@Action定義路由與命令列動作。 - 透過
Context處理每個請求的狀態。 - 使用原生
Builder與Builders元件執行 JSON 序列化。 - 透過
AbstractDataPOJO 處理資料庫持久化。 - 使用
generate命令從資料庫表格生成 POJO。 - 實作伺服器傳送事件(SSE)進行即時推送。
- 透過多部分資料處理檔案上傳。
- 使用
URLRequest和HTTPHandler發起對外 HTTP 請求。 - 在
application.properties中配置資料庫連線或系統設定。 - 除錯路由衝突(Actions)或 CLI 參數解析。
如何運作
tinystruct 框架會將任何使用 @Action 註解的方法視為可路由的端點,同時支援終端機與網頁環境。應用程式透過繼承 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 或 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", "一個用於示範 MCP 的自訂工具");
}
@Action(
value = "custom/hello",
description = "向某人打招呼",
arguments = {
@Argument(key = "name", description = "要打招呼的名字", 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("提供的名稱無效");
}
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";
}
}
透過分配器執行伺服器:
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
# Session(叢集環境使用 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。 |
對 JSON 陣列使用 List<Builder> | 使用 Builders 以避免泛型型別擦除問題。 |
ApplicationRuntimeException: template not found | 在僅供 API 使用的應用程式中,於 init() 呼叫 setTemplateRequired(false)。 |
對 private 方法使用 @Action 註解 | Action 必須是 public 才能被框架註冊。 |
在應用程式中硬編碼 main(String[] args) | 所有模組都使用 bin/dispatcher 作為進入點。 |
手動 ActionRegistry 註冊 | 優先使用 @Action 註解進行自動發現。 |
| 執行時期找不到 Action | 確保類別已透過 --import 匯入或在 application.properties 中列出。 |
| CLI 參數不可見 | 使用 --key value 傳遞;透過 getContext().getAttribute("--key") 存取。 |
| 兩個方法路徑相同,觸發了錯誤的那個 | 設定明確的 mode(例如 HTTP_GET vs HTTP_POST)以進行消歧義。 |
最佳實踐
- 粒度化的應用程式:將邏輯拆分為較小、專注的應用程式,而非單一的龐大類別。
- 在
init()中設定:利用init()進行設定(配置、資料庫),而非使用建構函式。不要呼叫setAction()——請使用@Action註解。 - 模式感知:在
@Action中使用Mode參數,將敏感操作限制為僅CLI或特定的 HTTP 方法。 - Context 優先於參數:對於可選的 CLI 標記,使用
getContext().getAttribute("--flag")而非在方法簽章中加入參數。 - 非同步事件:對於由事件觸發的繁重任務,請在事件處理器內部使用
CompletableFuture.runAsync()。
技術參考
詳細指南位於 references/ 目錄中:
- 架構與配置 — 抽象化、套件地圖、屬性
- 路由與 @Action — 註解細節、模式、參數
- 資料處理 — Builder、Builders、JSON 序列化與解析
- 資料庫持久化 — AbstractData POJO、CRUD、映射 XML、POJO 生成
- 系統與用法 — Context、Session、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 整合測試模式