首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

J2EE 實戰:基於表單命名規約的 SQL 自動構建器實現

     編輯:Java 程式設計入門

前言:從手工拼接到約定優於配置

INSERT、DELETE、UPDATE 是資料庫操作的三大基石,Web 開發中無處不在。純手工構建 SQL 不僅工作量大,更嚴重限制系統靈活性。本文提出一套基於表單元素命名規約的自動 SQL 構建機制,透過約定優於配置,實現從請求參數到 SQL 語句的零代碼映射。

核心思路:命名規約即元資料

利用 request.getParameterNames() 獲取所有表單欄位名,若約定「欄位名 = 資料庫欄位名」,則只需解決三個未知量:table_name、where 條件、操作類型。進一步透過前綴區分資料類型,自動處理引號轉義,達成完全自動化。

命名規約規格

前綴語義範例處理邏輯
c_公共參數c_table (表名)、c_genre (INSERT/DELETE/UPDATE)、c_where (WHERE 子句)直接提取,不參與欄位映射
s_字串型欄位s_username、s_email自動包單引號,雙引號轉義 (' → '')
i_非字串型欄位i_age、i_salary、i_create_time=now()無引號,支援 NULL、數值、資料庫函數

核心實現:PageUtil JavaBean

package com.river.page;

import java.util.*;
import javax.servlet.http.HttpServletRequest;

public class PageUtil {
    private HttpServletRequest request;

    public void init(HttpServletRequest _request) { this.request = _request; }
    public void clear() { this.request = null; }

    private String get(String name) {
        return (request == null || request.getParameter(name) == null) ? "" : request.getParameter(name);
    }

    public String getSQL() {
        String c_table = get("c_table");
        String c_genre = get("c_genre");
        String c_where = get("c_where");

        // 參數校驗
        if (c_genre == null || c_genre.isEmpty()) return "the action is null/empty";
        if (c_table == null || c_table.isEmpty()) return "unknow table/empty";

        Enumeration names = request.getParameterNames();
        StringBuilder cols = new StringBuilder(), vals = new StringBuilder();

        while (names.hasMoreElements()) {
            String name = names.nextElement();
            if (name.length() < 2) continue;
            String prefix = name.substring(0, 2);
            String colName = name.substring(2);
            String value = get(name);

            if ("i_".equalsIgnoreCase(prefix)) {
                cols.append(',').append(colName);
                vals.append(',').append(value.isEmpty() ? "NULL" : value);
            } else if ("s_".equalsIgnoreCase(prefix)) {
                cols.append(',').append(colName);
                if (value.isEmpty()) vals.append(",NULL");
                else vals.append(",'").append(value.replace("'", "''")).append("'");
            }
            // c_ 開頭參數跳過
        }

        String sql;
        if (cols.length() > 0) {
            cols.deleteCharAt(0);
            vals.deleteCharAt(0);
        }

        switch (c_genre.toUpperCase()) {
            case "INSERT":
                sql = "INSERT INTO " + c_table + " (" + cols + ") VALUES (" + vals + ")";
                break;
            case "UPDATE":
                // UPDATE 邏輯:cols 存放 "col=val" 片段
                // ... 類似迴圈構建 SET 子句 ...
                sql = "UPDATE " + c_table + " SET " + cols;
                if (!c_where.isEmpty()) sql += " WHERE " + c_where;
                break;
            case "DELETE":
                sql = "DELETE FROM " + c_table;
                if (!c_where.isEmpty()) sql += " WHERE " + c_where;
                break;
            default:
                return null;
        }
        return sql;
    }
}

實際應用範例

表單設計(新增用戶)

<form action="saveUser.do" method="post">
    <input type="hidden" name="c_table" value="t_user" />
    <input type="hidden" name="c_genre" value="INSERT" />
    <input type="text" name="s_username" />
    <input type="text" name="s_email" />
    <input type="text" name="i_age" />
    <input type="hidden" name="i_create_time" value="now()" />
    <button type="submit">儲存</button>
</form>

Action 處理

public class SaveUserAction extends Action {
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) {
        PageUtil util = new PageUtil();
        util.init(request);
        String sql = util.getSQL();
        // 執行 SQL(可結合自動執行類映射到通用 Action)
        return mapping.findForward("success");
    }
}

優缺點權衡

顯著優勢

  • 極致減碼:大表單零代碼映射,消除遺漏欄位、拼寫錯誤、引號處理等低級錯誤
  • 層級解耦:表單結構變更只需調整頁面,業務邏輯層完全不動
  • 通用復用:單一 JavaBean 支援所有 CRUD 操作,穩定性高

已知限制

  • 效能開銷:反射遍歷參數、字串拼接,超大表單(百欄位以上)有感知延遲
  • 安全風險:c_where 直接拼接可能導致 SQL 注入,生產環境需加白名單驗證
  • 複雜查詢無力:僅支援單表簡單 CRUD,關聯查詢、子查詢需回歸手寫

結語:在約束中尋找自由

這套機制並非銀彈,但對於「不苛刻」的專案——後台管理、報表系統、快速原型——它以最小代價換取了最大開發效率。核心啟示:命名即契約,約定即框架。當團隊建立共識的命名規範,最簡單的機制往往最有力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved