1.4.第3部分-EventManager web application
一个Hibernate也像一个独立的应用那样使用会话和事务,然而,一些常见的模式是有用的,我们现在写一个EventManagerServlet,这个Servlet可列出数据库中所有的events,并且提供一个表单用以增加新的event。
1.4.1.编写基本的Servlet
在源代码目录新建一个Servlet,隶属events包:
package
events;
// Imports
public class EventManagerServlet extends HttpServlet {
// Servlet code
}
// Imports
public class EventManagerServlet extends HttpServlet {
// Servlet code
}
此Servlet仅仅处理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);
}
}
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-per-request)。当一个请求抵达Servlet的时候,通过首次对SessionFactory上的getCurrentSession()的调用,打开一个新的Hibernate会话,然后一个数据库事务就开始了——所有的数据访问都在这一个事务中进行,不管是读还是写(在实际应用中我们不使用自动提交的模式)。
不要为每个数据库操作都创建一个新的Hibernate会话,在一个请求范围内使用一个会话,使用getCurrentSession()会自动的将会话绑定到当前Java线程。
接下来,请求可能的动作处理并且输出渲染(render)好的HTML数据,我们稍后讨论这块。
最后,处理和渲染(render)完毕工作就结束了,如果在处理中有任何错误发生,一个异常就会被抛出,事务就会回滚。session-per-request模式就完成了。与其在每个Servlet中编写事务分割代码,不如写一个Servlet Filter(过滤器),关于这个模式,可以查阅Hibernate的网站和Wiki站点,叫做在视图中打开会话(Open Session in View)——如果你打算通过JSP处理视图而不是Servlet,你就需要阅读下它。
1.4.2.处理和渲染
我们来实现请求处理代码以及页面渲染的代码:
//
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();
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();
private
void
printEventForm(PrintWriter out) {
out.println( " <h2>Add new event:</h2> " );
out.println( " <form> " );
out.println( " Title: <input name='eventTitle' length='50'/><br/> " );
out.println( " Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/> " );
out.println( " <input type='submit' name='action' value='store'/> " );
out.println( " </form> " );
}
out.println( " <h2>Add new event:</h2> " );
out.println( " <form> " );
out.println( " Title: <input name='eventTitle' length='50'/><br/> " );
out.println( " Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/> " );
out.println( " <input type='submit' name='action' value='store'/> " );
out.println( " </form> " );
}
listEvents()方法绑定到当前Java线程的Hibernate会话去执行一个查询:
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> " );
}
}
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> " );
}
}
protected
void
createAndStoreEvent(String title, Date theDate) {
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);
HibernateUtil.getSessionFactory()
.getCurrentSession().save(theEvent);
}
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);
HibernateUtil.getSessionFactory()
.getCurrentSession().save(theEvent);
}
现在,Servlet就写完了,一个向Servlet的请求会被一个单独的会话和事务处理。像以前的独立应用那样,Hibernate也可以自动的将对象绑定到当前执行线程,这给了你充分的自由去做代码分层,并以任何你喜欢的方式访问SessionFactory。通常,你最好使用一个更好的设计,把数据访问的代码放进数据访问对象(DAO模式)中,可以看Hibernate wiki来获得更多的示例。
1.4.3.部署并测试
为了部署这个应用,我们需要创建一个Web档案,一个WAR包,将以下内容加入你的Ant脚本:
<
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 >
< war destfile ="hibernate-tutorial.war" webxml ="web.xml" >
< lib dir ="${librarydir}" >
< exclude name ="jsdk*.jar" />
</ lib >
< classes dir ="${targetdir}" />
</ war >
</ target >
这个target在工程目录创建了一个hibernate-tutorial.jar文件,它将依赖的类库以及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-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网站下载并放在lib目录,然而它只在编译期间会使用到,在打war包的时候要排除在外。
执行ant war命令来编译并部署,将生成的hibernate-tutorial.jar文件复制到tomcat的webapp目录,如果你还没安装tomcat,下载并根据说明进行安装,不用做任何设置即可进行使用。
部署以后,启动tomcat,并通过以下地址访问:
http://localhost:8080/hibernate-tutorial/eventmanager,当首个请求抵达servlet以后(HibernateUtil静态初始化方法被调用),注意查看tomcat的日志观察Hibernate初始化情况,并在出错的时候查看详细的日志输出。
1.5.总结
本教程涵盖了编写一个基本的独立应用程序,以及一个小型web应用的基础知识。
如果你对Hibernate学习建立起了自信,继续通过本参考文档内容目录查看你感兴趣的内容、主题——经常被问及的是事务处理(
Chapter 11, Transactions And Concurrency),查询性能(fetch performance)(
Chapter 19, Improving performance),或者API的用法(
Chapter 10, Working with objects)),以及关于查询特性(
Section 10.4, “Querying”)。
最后,别忘记多检查Hibernate网站以得到专门的教程。
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
英文原文版权归原作者所有, 本译文转载请注明出处!
译者:abigfrog 联系:QQ:800736, MSN:J2EE@HOTMAIL.COM
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※