Hibernate web应用程序使用Session
和Transaction
的方式几乎和独立应用程序是一样的。但是,有一些常见的模式(pattern)非常有用。现在我们编写一个EventManagerServlet
。这个servlet可以列出数据库中保存的所有的events,还提供一个HTML表单来增加新的events。
在你的源代码目录的events
包中创建一个新的类:
package events; // Imports public class EventManagerServlet extends HttpServlet { // Servlet code }
我们后面会用到dateFormatter
的工具, 它把Date
对象转换为字符串。只要一个formatter作为servlet的成员就可以了。
这个servlet只处理 HTTP GET
请求,因此,我们要实现的是doGet()
方法:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy"); try { // Begin unit of work HibernateUtil.getSessionFactory() .getCurrentSession().beginTransaction(); // Process request and render page... // End unit of work HibernateUtil.getSessionFactory() .getCurrentSession().getTransaction().commit(); } catch (Exception ex) { HibernateUtil.getSessionFactory() .getCurrentSession().getTransaction().rollback(); throw new ServletException(ex); } }
我们称这里应用的模式为每次请求一个session(session-per-request)。当有请求到达这个servlet的时候,通过对SessionFactory
的第一次调用,打开一个新的Hibernate Session
。然后启动一个数据库事务—所有的数据访问都是在事务中进行,不管是读还是写(我们在应用程序中不使用auto-commit模式)。
不要为每次数据库操作都使用一个新的Hibernate Session
。将Hibernate Session
的范围设置为整个请求。要用getCurrentSession()
,这样它自动会绑定到当前Java线程。
下一步,对请求的可能动作进行处理,渲染出反馈的HTML。我们很快就会涉及到那部分。
最后,当处理与渲染都结束的时候,这个工作单元就结束了。假若在处理或渲染的时候有任何错误发生,会抛出一个异常,回滚数据库事务。这样,session-per-request
模式就完成了。为了避免在每个servlet中都编写事务边界界定的代码,可以考虑写一个servlet 过滤器(filter)来更好地解决。关于这一模式的更多信息,请参阅Hibernate网站和Wiki,这一模式叫做Open Session in View—只要你考虑用JSP来渲染你的视图(view),而不是在servlet中,你就会很快用到它。
我们来实现处理请求以及渲染页面的工作。
// Write HTML header PrintWriter out = response.getWriter(); out.println("<html><head><title>Event Manager</title></head><body>"); // Handle actions if ( "store".equals(request.getParameter("action")) ) { String eventTitle = request.getParameter("eventTitle"); String eventDate = request.getParameter("eventDate"); if ( "".equals(eventTitle) || "".equals(eventDate) ) { out.println("<b><i>Please enter event title and date.</i></b>"); } else { createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate)); out.println("<b><i>Added event.</i></b>"); } } // Print page printEventForm(out); listEvents(out, dateFormatter); // Write HTML footer out.println("</body></html>"); out.flush(); out.close();
listEvents()
方法使用绑定到当前线程的Hibernate Session
来执行查询:
private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) { List result = HibernateUtil.getSessionFactory() .getCurrentSession().createCriteria(Event.class).list(); if (result.size() > 0) { out.println("<h2>Events in database:</h2>"); out.println("<table border='1'>"); out.println("<tr>"); out.println("<th>Event title</th>"); out.println("<th>Event date</th>"); out.println("</tr>"); for (Iterator it = result.iterator(); it.hasNext();) { Event event = (Event) it.next(); out.println("<tr>"); out.println("<td>" + event.getTitle() + "</td>"); out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>"); out.println("</tr>"); } out.println("</table>"); } }
最后,store
动作会被导向到createAndStoreEvent()
方法,它也使用当前线程的Session
:
protected void createAndStoreEvent(String title, Date theDate) { Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); HibernateUtil.getSessionFactory() .getCurrentSession().save(theEvent); }
大功告成,这个servlet写完了。Hibernate会在单一的Session
和Transaction
中处理到达的servlet请求。如同在前面的独立应用程序中那样,Hibernate可以自动的把这些对象绑定到当前运行的线程中。这给了你用任何你喜欢的方式来对代码分层及访问SessionFactory
的自由。通常,你会用更加完备的设计,把数据访问代码转移到数据访问对象中(DAO模式)。请参见Hibernate Wiki,那里有更多的例子。
要发布这个程序,你得把它打成web发布包:WAR文件。把下面的脚本加入到你的build.xml
中:
<target name="war" depends="compile"> <war destfile="hibernate-tutorial.war" webxml="web.xml"> <lib dir="${librarydir}"> <exclude name="jsdk*.jar"/> </lib> <classes dir="${targetdir}"/> </war> </target>
这段代码在你的开发目录中创建一个hibernate-tutorial.war
的文件。它把所有的类库和web.xml
描述文件都打包进去,web.xml 文件应该位于你的开发根目录中:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Event Manager</servlet-name> <servlet-class>events.EventManagerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Event Manager</servlet-name> <url-pattern>/eventmanager</url-pattern> </servlet-mapping> </web-app>
请注意在你编译和部署web应用程之前,需要一个附加的类库:jsdk.jar
。这是Java Servlet开发包,假若你还没有,可以从Sun网站上下载,把它copy到你的lib目录。但是,它仅仅是在编译时需要,不会被打入WAR包。
在你的开发目录中,调用ant war
来构建、打包,然后把hibernate-tutorial.war
文件拷贝到你的tomcat的webapps
目录下。假若你还没安装Tomcat,就去下载一个,按照指南来安装。对此应用的发布,你不需要修改任何Tomcat的配置。
在部署完,启动Tomcat之后,通过http://localhost:8080/hibernate-tutorial/eventmanager
进行访问你的应用,在第一次servlet 请求发生时,请在Tomcat log中确认你看到Hibernate被初始化了(HibernateUtil
的静态初始化器被调用),假若有任何异常抛出,也可以看到详细的输出。