AJF(Agile Java Framework)是一個極簡 MVC 框架,設計靈感融合 Struts、WebWork、Spring MVC 精華,核心目標是「約定優於配置、零配置可用、單一 Action 多操作、輕量級 AOP 能力」。框架整合 Command、Template、Proxy、Decorator、Filter、Chain 等設計模式,實現類 AOP 功能,輕鬆解決日誌、權限、連線、事務等橫切關注點。
BaseAction extends Action
XXXAction extends BaseAction
// 一個 Action 多個操作,透過 method 參數反射調用 execute_{method}
preHandler()、postHandler()、exceptionHandler() 三大擴充點,源自 Spring MVC 設計start() 開啟事務容器,後續資料庫操作自動提交/回滾/關閉連線(非分散式事務,滿足一般專案需求)run(request, response, "method")! 前綴:redirect(如 return "!query")forward(如 return "edit")ajf.xml 極簡映射/pages/commons/error.jsp
/pages/commons/ajf_home.jsp
/pages/commons/no_object.jsp
user.do
user_query.jsp
user_input.jsp
user_edit.jsp
user_view.jsp
public class BaseAction extends Action {
String action = null;
String actionClassName = null;
long start = 0, end = 0, diff = 0;
Map ajf_system_request_map = null;
public String preHandler() throws Exception {
ajf_system_request_map = JSPUtil.getRequestModel(request);
start = StringUtil.getNowMs();
return null; // 非 null 將中斷執行流程
}
public String postHandler() throws Exception {
end = StringUtil.getNowMs();
diff = end - start;
LogUtil.info(diff + "," + JSPUtil.getUrl(request) + "," + ajf_system_request_map);
return null;
}
public void exceptionHandler(Exception e) throws Exception {
LogUtil.error(actionClassName + ",exception handler," + e + "," + StringUtil.getNowTime());
}
}
設計亮點:請求模型提取、效能計時、結構化日誌記錄、異常統一捕獲,零業務邏輯耦合。
public class UserAction extends BaseAction {
public String execute() throws Exception { return execute_query(); }
public String execute_query() throws Exception {
createTable(); // 示範用,實際應由遷移腳本管理
String sql = "select * from t_user";
conn = DBUtil.getConn();
Map map = PagedUtil.queryString(conn, sql, 1, 1, request); // 分頁查詢
add(map); // 將資料放入 Action 內部 Map,供 JSP 取用
return "q"; // forward 到 user_query.jsp
}
public String execute_input() throws Exception { return "input"; }
public String execute_insert() throws Exception {
String table = "t_user";
String cols = "id,name,hh,ww,birth_day";
int autoPK = 1;
conn = DBUtil.getConn();
DBUtil.insert(conn, table, cols, autoPK, model); // model 為請求參數綁定 Map
return "!query"; // redirect 到 query 操作
}
public String execute_edit() throws Exception {
String objectid = (String) model.get("objectid");
String sql = "select * from t_user where id='" + objectid + "'";
conn = DBUtil.getConn();
Map user = DBUtil.queryOne(conn, sql, null);
if (user == null) return "no_object";
model.put("user", user);
return "edit";
}
public String execute_view() throws Exception { /* 同 edit 邏輯 */ }
public String execute_update() throws Exception {
String table = "t_user";
String cols = "id,name,hh,ww,birth_day";
int autoPK = 1;
conn = DBUtil.getConn();
DBUtil.updateRow(conn, table, cols, 1, model);
return "!query";
}
public String execute_delete() throws Exception {
String sql = "delete from t_user where id ";
DBUtil.batchDelById(sql, request); // 批次刪除支援
return "!query";
}
private void createTable() { /* 建表示例 SQL */ }
}
| 模式 | AJF 應用場景 | 效益 |
|---|---|---|
| Template Method | Action 執行流程:preHandler → execute_xxx → postHandler | 固定骨架,子類擴充業務邏輯 |
| Proxy | DBUtil 封裝 JDBC,事務管理透明化 | 業務碼無感知連線/事務細節 |
| Chain of Responsibility | 攔截器鏈處理請求預處理、後處理、異常 | 橫切關注點模組化、可組合 |
| Command | 每個 execute_xxx 方法封裝單一業務操作 | 參數化請求、支援撤銷/重做擴充 |
| Decorator | Action 基類裝飾日誌、計時、事務功能 | 動態組合行為、不修改核心邏輯 |
AJF 1.2 用不到 500 行核心代碼,展示了 MVC、AOP、事務管理、攔截器鏈的精髓實現。它不是企業級框架的替代品,而是一個「教科書級」的極簡參考實作——讓開發者看清大型框架底層運作本質,也為資源受限、快速交付場景提供可落地的輕量選擇。若你正在造輪子、讀源碼、或維護十年前的 JSP 專案,AJF 值得收藏研讀。