單一框架解決單一層面問題,企業級應用需表現層、業務層、持久層協同。整合目標:
// com.meagle.bo.Order.java
public class Order implements Serializable {
private Integer id;
private String username;
private BigDecimal total;
private Set lineItems = new HashSet<>(); // 一對多
// 標準 Getter/Setter、equals/hashCode
}
// com.meagle.bo.OrderLineItem.java
public class OrderLineItem implements Serializable {
private Integer id;
private Order order; // 多對一反向引用
private Product product;
private Integer quantity;
private BigDecimal price;
// Getter/Setter
}
包命名規範:com.meagle.bo (領域對象)、com.meagle.service (業務接口/實現)、com.meagle.service.dao.hibernate (DAO 實現)、com.meagle.action/forms (表現層)。
com/meagle/bo/Order.hbm.xml
com/meagle/bo/OrderLineItem.hbm.xml
org.hibernate.dialect.MySQLDialect
false
update
// 接口
public interface IOrderDAO {
Order findById(Integer id);
List findByUsername(String username);
Order save(Order order);
}
// 實現 (繼承 HibernateDaoSupport 獲得 getHibernateTemplate())
public class OrderHibernateDAO extends HibernateDaoSupport implements IOrderDAO {
public Order findById(Integer id) {
return (Order) getHibernateTemplate().get(Order.class, id);
}
public List findByUsername(String username) {
return getHibernateTemplate().find("FROM Order o WHERE o.username=?", username);
}
public Order save(Order order) {
getHibernateTemplate().saveOrUpdate(order);
return order;
}
}
// 接口
public interface IOrderService {
Order saveNewOrder(Order order) throws OrderException, OrderMinimumAmountException;
List findOrdersByUser(String user) throws OrderException;
Order findOrderById(Integer id) throws OrderException;
void setOrderDAO(IOrderDAO orderDAO); // Setter 注入
}
// 實現
public class OrderServiceSpringImpl implements IOrderService {
private IOrderDAO orderDAO;
public void setOrderDAO(IOrderDAO orderDAO) { this.orderDAO = orderDAO; }
public Order saveNewOrder(Order order) throws OrderException, OrderMinimumAmountException {
// 業務驗證
if (order.getTotal().compareTo(new BigDecimal("100")) < 0) {
throw new OrderMinimumAmountException("訂單金額不足 100 元");
}
return orderDAO.save(order);
}
// 其他方法委託 DAO...
}
// 目標業務 Bean
PROPAGATION_REQUIRED,readOnly,-OrderException
PROPAGATION_REQUIRED,-OrderException
// 注入 DAO
事務屬性解讀:PROPAGATION_REQUIRED (支持當前事務/新建)、readOnly (優化標記)、-OrderException (遇到此異常回滾,繼承 RuntimeException 的異常默認回滾,Checked Exception 需顯式指定)。
public abstract class BaseAction extends Action {
private IOrderService orderService;
public void setServlet(ActionServlet actionServlet) {
super.setServlet(actionServlet);
ServletContext sc = actionServlet.getServletContext();
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
this.orderService = (IOrderService) wac.getBean("orderService"); // 從 Spring 容器獲取
}
protected IOrderService getOrderService() { return orderService; }
}
public class SaveNewOrderAction extends BaseAction {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
OrderForm oForm = (OrderForm) form;
// Form → Domain Object 轉換 (Action 職責)
Order order = new Order();
order.setUsername(oForm.getUsername());
order.setTotal(oForm.getTotal());
// lineItems 轉換...
// 委託業務層
getOrderService().saveNewOrder(order);
// 結果傳遞
oForm.setOrder(order);
ActionMessages msgs = new ActionMessages();
msgs.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("message.order.saved.successfully"));
saveMessages(request, msgs);
return mapping.findForward("success");
}
}
異常映射:業務層拋出的 Checked Exception 直接在 Struts 配置中映射到錯誤頁,Action 代碼零 try-catch,極其乾淨。
+------------------+ +--------------------------+ +--------------------------+ +--------------------------+
| Struts Action |---->| Spring Service (Tx) |---->| Hibernate DAO |---->| Database |
| (Presentation) | | (Business Logic/Valid) | | (Persistence/O-R Map) | | (MySQL/Oracle) |
+------------------+ +--------------------------+ +--------------------------+ +--------------------------+
| | | |
| Form Bean | Domain Object (POJO) | Domain Object (POJO) | Tables
| Validation | Transaction Boundary | HibernateTemplate |
| Forward/Redirect | Exception Translation | Session Management |
+-------------------------+------------------------------+------------------------------+
|
Spring Container (IoC/AOP)
- Bean Wiring
- Transaction Proxy
- Resource Management
| 替換場景 | 影響範圍 | 操作步驟 |
|---|---|---|
| Hibernate → iBATIS/MyBatis | 僅 DAO 實現 | 1. 實現 IOrderDAO 接口 2. Spring 配置替換 orderDAO Bean 3. 移除 Hibernate 依賴 |
| Struts → Spring MVC | 表現層 | 1. Controller 替換 Action 2. 服務定位器改為 @Autowired 3. 移除 Struts 依賴 |
| Spring 事務 → JTA (WebLogic) | 事務配置 | 1. 替換 transactionManager Bean 為 JtaTransactionManager 2. 移除 HibernateTransactionManager |
| MySQL → Oracle | 數據源/方言 | 1. 修改 dataSource URL/驅動 2. 修改 hibernate.dialect 3. 調整映射類型 |
TransactionProxyFactoryBean / @Transactional 聲明式事務ContextLoaderListener / ContextLoaderPlugin 整合 Web 與 Spring 容器「整合不是疊加,而是邊界的精確劃分與契約的嚴格遵守。Struts 做表現、Spring 做業務編排與事務、Hibernate 做對象持久化——各司其職,鬆耦合,高內聚,這才是框架整合的藝術。」