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

利用 Java 反射機制簡化 Struts 應用開發:通用 ResultSet → ActionForm 轉換

     編輯:Java 相關知識

Struts 1.x 開發中,ActionForm 屬性手工映射極其繁瑣。本文展示如何利用 Java 反射 實現 ResultSet 到任意 ActionForm 的通用自動映射,消除重複 setXxx() 代碼,大幅提升開發效率。

傳統痛點

每個查詢方法都需手寫:


while (rs.next()) {
    UserForm form = new UserForm();
    form.setId(rs.getInt("id"));
    form.setName(rs.getString("name"));
    form.setEmail(rs.getString("email"));
    // ... 幾十行 setXxx()
    list.add(form);
}

新增欄位 → 修改 Form → 修改查詢代碼 → 修改 JSP,四處同步。

通用反射映射工具類


public class BeanUtil {
    /**
     * 將 ResultSet 當前行映射到指定類別實例 (支援基本類型、String、Date 等)
     * @param rs ResultSet (游標已定位到有效行)
     * @param clazz 目標類別 (需有無參建構子、標準 setter)
     * @return 填充好屬性的實例
     */
    public static  T mapRow(ResultSet rs, Class clazz) throws Exception {
        T bean = clazz.getDeclaredConstructor().newInstance();
        ResultSetMetaData meta = rs.getMetaData();
        int cols = meta.getColumnCount();
        for (int i = 1; i <= cols; i++) {
            String colName = meta.getColumnName(i);
            Object value = rs.getObject(i);
            if (value == null) continue;
            // 欄位名轉 setter 方法名: user_id → setUserId
            String setterName = "set" + toCamelCase(colName);
            try {
                Method setter = clazz.getMethod(setterName, value.getClass());
                setter.invoke(bean, value);
            } catch (NoSuchMethodException e) {
                // 嘗試常見類型兼容 (如 RS 返回 Timestamp, setter 要 Date)
                Method setter = findCompatibleSetter(clazz, setterName, value);
                if (setter != null) setter.invoke(bean, value);
            }
        }
        return bean;
    }

    private static String toCamelCase(String underscore) {
        StringBuilder sb = new StringBuilder();
        boolean upper = false;
        for (char c : underscore.toLowerCase().toCharArray()) {
            if (c == '_') { upper = true; continue; }
            sb.append(upper ? Character.toUpperCase(c) : c);
            upper = false;
        }
        return sb.toString();
    }

    private static Method findCompatibleSetter(Class clazz, String name, Object value) {
        // 可擴展:Timestamp→Date, BigDecimal→Double 等
        return null; // 簡化略
    }
}

DAO 層極簡調用


public ArrayList findAllUsers() {
    String sql = "SELECT usr_id, usr_name, usr_email FROM users";
    return query(sql, UserForm.class);
}

public  ArrayList query(String sql, Class clazz) {
    ArrayList list = new ArrayList<>();
    try (Connection conn = getConnection();
         PreparedStatement ps = conn.prepareStatement(sql);
         ResultSet rs = ps.executeQuery()) {
        while (rs.next()) {
            list.add(BeanUtil.mapRow(rs, clazz));
        }
    } catch (Exception e) { throw new RuntimeException(e); }
    return list;
}

ActionForm 定義 (僅需標準 setter)


public class UsersActionForm extends ActionForm {
    private String usrId;
    private String usrName;
    private String usrEmail;
    // 標準 setter/getter
    public void setUsrId(String usrId) { this.usrId = usrId; }
    public String getUsrId() { return usrId; }
    // ... 其他同理
}

Action 中調用


public ActionForward execute(ActionMapping mapping, ActionForm form,
                             HttpServletRequest req, HttpServletResponse res) {
    UserService service = new UserService();
    ArrayList list = service.findAllUsers();
    req.setAttribute("userList", list);
    return mapping.findForward("success");
}

JSP 頁面顯示 (邏輯標簽)




  
    
    
  


優缺點與改進方向

優點缺點/風險
消除 90% 手工映射代碼反射效能略低 (可緩存 Method 對象優化)
新增欄位只需加 setter,零修改 DAO/Action欄位名與屬性名需遵循命名規約 (下劃線→駝峰)
統一異常處理、資源關閉複雜類型 (Blob, Clob, 自定義類) 需額外處理

進階優化

  • Method 緩存:ConcurrentMap, Map> 緩存 setter 反射對象,避免重複 getMethod。
  • 類型轉換器:引入 ConversionService 處理 Timestamp→Date、String→Enum 等跨類型賦值。
  • 列名別名:SQL 用 AS 指定別名匹配屬性名,解決數據庫命名規範不一致問題。
  • 遷移建議:新專案直接使用 MyBatis / JPA / JdbcTemplate 內建映射功能,無需手寫反射。

本技巧適用於存量 Struts 1.x 專案快速重構,亦可作為理解 ORM 映射原理的教學範例。

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