許多開發者抱怨 Java EE 配置繁瑣,實則源於缺乏 OO 思維。表現層與持久層的本質是映射配置,而非業務邏輯。唯有以領域模型為核心,才能構建清晰、可維護的系統。
| 層 | 核心任務 | 映射方向 |
|---|---|---|
| 表現層 | 離散表單欄位 ↔ 領域模型 | Struts ActionForm/標籤庫封裝 |
| 業務層 | 純領域模型運算(無技術細節) | 核心價值所在 |
| 持久層 | 領域模型 ↔ 關係表 | Hibernate/EJB CMP O-R Mapping |
表現層與持久層如同「打包與拆封」:將離散數據封裝為對象傳遞給業務層,業務層處理完畢再拆解為關係數據持久化。業務層始終面向對象,而非面向字段。
原則:緊扣需求,領域模型不妥協。映射配置是「紅娘」,雙方是領域模型與技術實體(表單/資料表)。若為配置方便而修改模型,必導致偏離需求。
hbm2ddl.auto=update)Order (聚合根)
├── Customer (聚合關聯,多對一)
└── List<OrderLine> (組合關聯,一對多,強生命週期綁定)
└── Product (關聯)
└── quantity
組合意味著部分不能獨立於整體存在(OrderLine 無 Order 無意義),映射時用 cascade="all-delete-orphan"。
子對象主鍵必須由 Hibernate 自動生成(如 uuid.hex),絕不可用 assigned。否則 session.update(parent) 無法正確判斷子對象是新增還是修改,導致 SQL 錯誤或資料不一致。
<class name="UserProperty" table="userprops">
<id name="propId" type="string">
<generator class="uuid.hex"/> <!-- 關鍵 -->
</id>
<many-to-one name="user" column="userId" not-null="true"/> <!-- 雙向關聯提升效能 -->
</class>
<class name="User" table="testuser">
<bag name="userProps" inverse="true" cascade="all-delete-orphan"> <!-- inverse="true" 由關係維護端控制 -->
<key column="userId"/>
<one-to-many class="UserProperty"/>
</bag>
</class>
<id> 加 unsaved-value="null",H3 不需要lazy 預設 false,H3 預設 true → 需 Hibernate.initialize() 或 Open Session in View(違背分層,易洩漏連線)使用索引屬性綁定集合:
<html:form action="/userSaveAction.do">
<html:select property="dept.deptId"> <!-- 多對一 -->
<html:optionsCollection name="deptListForm" property="list" value="deptId" label="name"/>
</html:select>
<html:text property="userId"/>
<html:text property="username"/>
<table>
<tr><td><html:hidden property="userProp[0].propId"/></td>
<td><html:text property="userProp[0].name"/></td>
<td><html:text property="userProp[0].value"/></td></tr>
<tr><td><html:hidden property="userProp[1].propId"/></td> ... </tr>
</table>
</html:form>
Form 中提供索引存取器:
public UserProperty getUserProp(int index) {
return (UserProperty) ((List) userProps).get(index);
}
真正的 Java EE 面向對象系統 = 領域建模(DDD)+ 框架配置映射。以 OO 思維提煉領域模型,再以 OO 思維配置表現/持久層映射,才是 Java 專案快速、高質量交付的正道。