採用 **Struts PlugIn 機制**,在應用啟動時初始化 Hibernate SessionFactory,存入 ServletContext,Action 中透過 JNDI 或直接從 Context 取用。優點:配置集中、生命週期由容器管理、不依賴 Spring 等額外框架。
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">org.gjt.mm.mysql.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.pool.size">20</property>
<property name="session_factory_name">hibernate/session_factory</property> <!-- JNDI 名稱 -->
<mapping resource="/homepage/Article.hbm.xml"/>
</session-factory>
</hibernate-configuration>
package homepage;
import org.apache.struts.action.*;
import javax.servlet.*;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
public class HibernatePlugIn implements PlugIn {
@Override
public void init(ActionServlet servlet, ModuleConfig config) throws ServletException {
try {
ServletContext context = servlet.getServletContext();
// 載入配置、建立 SessionFactory
SessionFactory sf = new Configuration()
.configure() // 預設載入 classpath:hibernate.cfg.xml
.buildSessionFactory();
// 存入 ServletContext,供 Action 取用
context.setAttribute("net.sf.hibernate.SessionFactory", sf);
} catch (Exception ex) {
ex.printStackTrace();
throw new ServletException("Hibernate 初始化失敗", ex);
}
}
@Override
public void destroy() {
// 應用關閉時可在這裡關閉 SessionFactory
}
}
<plug-in className="homepage.HibernatePlugIn">
<set-property property="configFilePath" value="/WEB-INF/classes/hibernate.cfg.xml"/>
<set-property property="storeInServletContext" value="true"/>
</plug-in>
configFilePath 指定配置檔路徑 (相對 Web 應用根目錄);storeInServletContext=true 觸發 context.setAttribute()。
public class ArticleAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
try {
// 方式一:從 ServletContext 直接取 (推薦,簡單)
ServletContext ctx = getServlet().getServletContext();
SessionFactory sf = (SessionFactory) ctx.getAttribute("net.sf.hibernate.SessionFactory");
// 方式二:JNDI 查找 (若配置了 session_factory_name)
// Context initCtx = new InitialContext();
// SessionFactory sf = (SessionFactory) initCtx.lookup("hibernate/session_factory");
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
// ... 業務邏輯
tx.commit();
session.close();
return mapping.findForward("success");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
| 優點 | 缺點 |
|---|---|
|
|
getSession(), closeSession() 減少重複碼。Open Session in View 模式,避免 LazyInitializationException。SessionFactory、HibernateTemplate、聲明式交易。Struts + Hibernate 整合,**PlugIn 方式是輕量、原生、易掌控的選擇**,適合中小專案或不想引入 Spring 的團隊。隨著專案複雜度提升,平滑遷移至 Spring 管理是自然演進。