1.3. 第三部分 - EventManager web 应用程序

优质
小牛编辑
133浏览
2023-12-01

Hibernate web 应用程序使用 SessionTransaction 的方式几乎和独立应用程序是一样的。但是,有一些常见的模式(pattern)非常有用。现在我们编写一个 EventManagerServlet。这个 servlet 可以列出数据库中保存的所有的 events,还提供一个 HTML 表单来增加新的 events。

1.3.1. 编写基本的 servlet

这个 servlet 只处理 HTTP GET 请求,因此,我们要实现的是 doGet() 方法:

package org.hibernate.tutorial.web;

// Imports

public class EventManagerServlet extends HttpServlet {

    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();
            if ( ServletException.class.isInstance( ex ) ) {
                throw ( ServletException ) ex;
            }
            else {
                throw new ServletException( ex );
            }
        }
    }

}

把这个 servlet 保存为 src/main/java/org/hibernate/tutorial/web/EventManagerServlet.java

我们称这里应用的模式为每次请求一个 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中,你就会很快用到它。

1.3.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();

必 须承认,这种编码风格把 Java 和 HTML 混在一起,在更复杂的应用程序里不应该大量使用 — 记住,在本章里我们仅仅是展示了 Hibernate 的基本概念。这段代码打印出了 HTML 页眉和页脚,在这个页面里,还打印了一个输入 events 条目的表单单并列出了数据库里的有的 events。第一个方法微不足道,仅仅是输出 HTML:

    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
>");
    }

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
>");
            Iterator it = result.iterator();
            while (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 会在单一的 SessionTransaction 中处理到达的 servlet 请求。如同在前面的独立应用程序中那样,Hibernate 可以自动的把这些对象绑定到当前运行的线程中。这给了你用任何你喜欢的方式来对代码分层及访问 SessionFactory 的自由。通常,你会用更加完备的设计,把数据访问代码转移到数据访问对象中(DAO 模式)。请参见 Hibernate Wiki,那里有更多的例子。

1.3.3. 部署与测试

要部署这个应用程序以进行测试,我们必须出具一个 Web ARchive (WAR)。首先我们必须定义 WAR 描述符为 src/main/webapp/WEB-INF/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
>org.hibernate.tutorial.web.EventManagerServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name
>Event Manager</servlet-name>
        <url-pattern
>/eventmanager</url-pattern>
    </servlet-mapping>
</web-app
>

在你的开发目录中,调用 ant war 来构建、打包,然后把 hibernate-tutorial.war 文件拷贝到你的 tomcat 的 webapps 目录下。假若你还没安装 Tomcat,就去下载一个,按照指南来安装。对此应用的发布,你不需要修改任何 Tomcat 的配置。

注意

If you do not have Tomcat installed, download it from http://tomcat.apache.org/ and follow the installation instructions. Our application requires no changes to the standard Tomcat configuration.

在部署完,启动 Tomcat 之后,通过 http://localhost:8080/hibernate-tutorial/eventmanager 进行访问你的应用,在第一次 servlet 请求发生时,请在 Tomcat log 中确认你看到 Hibernate 被初始化了(HibernateUtil 的静态初始化器被调用),假若有任何异常抛出,也可以看到详细的输出。