- 译者序
- 前言
- 本书怎么使用
- 本书排版字体约定
- 本书网站
- 致谢
- 第一部分 Hibernate 快速入门
- 第 1 章 安装和设置
- 第 2 章 映射简介
- 第 3 章 驾驭 Hibernate
- 第 4 章 集合与关联
- 第 5 章 更复杂的关联
- 第 6 章 自定义值类型
- 第 7 章 映射标注
- 第 8 章 条件查询
- 第 9 章 浅谈 HQL
- 第二部分 与其他工具的集成
- 第 10 章 将 Hibernate 连接到 MySQL
- 第 11 章 Hibernate 与 Eclipse:Hibernate Tools 使用实战
- 第 12 章 Maven 进阶
- 第 13 章 Spring 入门:Hibernate 与 Spring
- 第 14 章 画龙点睛:用 Stripes 集成 Spring 和 Hibernate
- 附录 A Hibernate 类型
- 附录 B Criteria API
- 附录 C Hibernate SQL 方言
- 附录 D Spring 事务支持
- 附录 E 参考资源
- 作者简介
- 封面介绍
增加 Stripes
为了让我们的项目可以在 Web 环境中运行,需要对 compile 构建任务进行一些修改。到现在为止,我们一直在用 Ant 来启动应用程序,所以要为 Ant 提供正确的代码类路径信息。目前一切运行正常,但是 Tomcat 的类加载管理机制要复杂得多,因此,将所有需要的依赖文件直接复制到应用程序的 WEB-INF/lib 目录下是最简单的方法。我们也希望编译任务可以将文件放在 WEB-INF 中,这样 Tomcat 就可以直接找到它们。参见例 14-9。
例 14-9:针对 Web 应用程序而修改 Compile 构建任务
……
<property name="source.root"value="src"/>
<property name="class.root"value="webapp/WEB-INF/classes"/>❶
<property name="data.dir"value="webapp/WEB-INF/data"/>❷
……
<target name="compile"depends="prepare"
description="Compiles all Java classes">
<javac srcdir="${source.root}"
destdir="${class.root}"
debug="on"
optimize="off"
deprecation="on">
<classpath refid="project.class.path"/>
</javac>
<filter token="docroot"value="${basedir}/webapp"/>❸
<copy todir="webapp/WEB-INF"filtering="true"overwrite="true">
<fileset dir="src"includes="applicationContext.xml"/>
</copy>❹
<copy todir="webapp/WEB-INF/lib"flatten="true">
<fileset refid="dependency.fileset"/>
</copy>❺
</target>
……
❶因为我们正在将应用程序移植到 J2EE Web 应用程序,所以需要把 Java 类放到 webapp/WEB-INF/classes 目录下。最简单的实现方法就是修改 class.root 属性值。
❷由于当前的工作目录还不能确定,所以 HSQLDB 也不能够在数据的相对路径中找到数据库。因此,我们需要为 Hibernate 提供数据库的完整路径。为此,创建一个 data.dir 属性,当复制 applicationContext.xml 文件时会用到这个属性。
❸ant 的 filter 构建任务指定当复制 applicationContext.xml 时,需要用 Web 应用程序的实际路径来替换 @docroot@标记。
❹需要将 Spring 的 applicationContext.xml 文件复制到 webapp/WEB-INF 目录下,以便 Tomcat 可以找到它。
❺既然应用程序不再由 Ant 来启动了,我们也就不能再依赖本地 Maven 仓库中找到的 Java 库。J2EE 规范要求把 Web 应用程序的 JAR 文件放到 WEB-INF/lib 目录中,所以这一步就是将我们需要的文件从 Maven 本地仓库复制到 WEB-INF/lib 目录中。
为了让用 docroot 配置的过滤器(filter)对任何目录都有效,我们需要在 src/application-Context.xml(第 13 章中创建的)中添加 @docroot@标记,例 14-10 演示了这一修改。
例 14-10:applicationContext.xml 中数据库配置文件位置的变化
……
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.
transaction.JDBCTransactionFactory</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.connection.release_mode">after_transaction</prop>
<prop key="hibernate.connection.shutdown">true</prop>
<prop key="hibernate.connection.driver_class">org.hsqldb.jdbcDriver
</prop>
<prop key="hibernate.connection.url">jdbc:hsqldb:@docroot@/WEB-INF
/data/music</prop>
<prop key="hibernate.connection.username">sa</prop>
<prop key="hibernate.connection.password"></prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
</props>
</property>
……
现在,我们的构建环境已经修改好,可以开始使用 Stripes 了。为了让 Spring、Hibernate 以及 Stripes 协同工作,还需要对 web.xml 进行多处修改。例 14-11 中演示了很多内容,但每个配置项都有一定的作用。稍后将介绍一下其中重要的配置。
例 14-11:针对 Stripes 集成而修改后的 web.xml
<?xml version="1.0"encoding="UTF-8"?>
<web-app 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"
version="2.4">
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>❶
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<!--Hibernate OpenSession Filter-->
<filter>
<filter-name>hibernateFilter</filter-name>❷
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
<init-param>
<param-name>flushMode</param-name>
<param-value>ALWAYS</param-value>
</init-param>
</filter>
<filter>
<display-name>Stripes Filter</display-name>❸
<filter-name>StripesFilter</filter-name>
<filter-class>
net.sourceforge.stripes.controller.StripesFilter
</filter-class>
<init-param>
<param-name>ActionResolver.PackageFilters</param-name>
<param-value>com.oreilly.*</param-value>
</init-param>
<init-param>
<param-name>ActionResolver.UrlFilters</param-name>
<param-value>WEB-INF/classes</param-value>
</init-param>
<init-param>
<param-name>Interceptor.Classes</param-name>
<param-value>
net.sourceforge.stripes.integration.spring.SpringInterceptor,
net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor
</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.action</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>StripesFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>StripesFilter</filter-name>
<url-pattern>*.action</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>StripesDispatcher</servlet-name>❹
<servlet-class>
net.sourceforge.stripes.controller.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>StripesDispatcher</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
❶ContextLoaderListener 过滤器用于初始化 Web 应用程序的 Spring Framework。
❷hibernateFilter 是由 Spring 提供的,用于获取一个封装了所有请求处理的 Hibernate 会话。使用这个功能,我们就可以不必再自己管理 Hibernate 会话。这一功能之所以精彩,是因为正确的会话管理可能是编写支持 Hibernate 的 Web 应用程序时最具技巧性的处理之一。
❸将 Stripes Filter 映射到*.action 和*.jsp HTTP 请求。它提供了调用 JSP 或 ActionBeans 时所需的一些基本表单处理和配置服务。
❹StripesDispatcher servlet 映射到了*.action,负责决定应该调用哪个 ActionBean 中的哪个方法,以及处理由这些事件方法返回的 Resolution。
图 14-2 Stripes 下载页面
在开始使用 Stripes 以前,为了让它正常运行,还有最后一个需要安装的配置。Stripes-Resources.properties 文件位于 classes 类目录中,它为 Stripes 提供一些必需的格式化字符串。对于这个例子来说,最简单的办法就是用下载的随书示例代码,直接从 examples/ch14/src 目录中复制 StripesResources.properties 文件,不过也可以从 Stripes 下载包( [1] )中得到这个文件。在 Stripes 1.4.3 下载页面的中间,点击"Download"按钮,如图 14-2 所示,继续链接到 SourceForge 下载页面,对 SourceForge 我们都应该很熟悉了。在下载好 stripes-1.4.3.zip 以后,将它进行解压,再把 stripes-1.4.3/lib/StripesResources.properties 复制到你的 src 目录下。如果愿意,你可以看看这个文件的内容,不过它只是本章示例需要的一个依赖文件而已。
最后就应该编写一点代码了。首先,我们来编写两个 JSP 文件,再接着开发一个 ActionBean。如果你最近几年写过些 JSP 代码,那么我们在这儿编写的 JSP 文件也不会令你感到陌生。不过,你可能不认得的是前缀(prefix)为"stripes"的几个标签。Stripes 标签库可以作为 JSTL 的补充,辅助你的应用程序类和视图协同工作。例 14-12 演示了一个用于编辑曲目专辑的页面源代码。
例 14-12:曲目编辑视图:webapp/albums/edit.jsp
<%@page contentType="text/html;charset=UTF-8"language="java"%>
<%@taglib prefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="stripes"uri="http://stripes.sourceforge.net/stripes.tld"%>❶
<stripes:useActionBean
beanclass="com.oreilly.hh.web.AlbumActionBean"
var="actionBean"event="edit"/>❷
<h1>Album Edit Page</h1>
<stripes:form action="/Album.action">❸
<stripes:errors/>
<stripes:hidden name="album.id"></stripes:hidden>❹
<table>
<tr>
<td>Title:</td>
<td><stripes:text name="album.title"/></td>❺
</tr>
<tr>
<td>Discs:</td>
<td><stripes:text name="album.numDiscs"/></td>
</tr>
</table>
<h2>Album Comments</h2>
<c:choose>
<c:when test="${actionBean.album.id!=null}">
<stripes:link href="/albums/edit_comment.jsp">
<stripes:param name="album.id"value="${actionBean.album.id}"/>
Add A Comment
</stripes:link>
<c:if test="${empty actionBean.album.comments}">
There are no album comments yet.
</c:if>
</c:when>
<c:otherwise>
Please add the album before entering comments.
</c:otherwise>
</c:choose>
<ul>
<c:forEach items="${actionBean.album.comments}"var="comment">
<li>${comment}</li>
</c:forEach>
</ul>
<br/>
<stripes:submit name="save"value="Save"></stripes:submit>❻
</stripes:form>
可以看到,这是一个外观界面相当普通的 JSP 页面,不过,也有一些东西值得更仔细地研究一下:
❶taglib 声明用于引入 Stripes 标签库,以便页面上的代码可以通过"stripes:"前缀来使用它们。
❷这里使用 useActionBean 标签来告诉 Stripes 初始化 AlbumActionBean,如果它的 edit 事件没有发生的话(例如,浏览器直接请求 JSP 页面,而不是通过 action URL),就运行这个事件。edit 事件将会从数据库中加载 Album 对象,为生成表单做好准备。
❸Stripes 的 form 标签会输出一个普通的 HTML 表单,以及很多隐藏在幕后的东西。它的 action 属性指定表单将要提交到的 ActionBean。
❹Stripes 的 hidden 标签的作用类似于普通 HTML 的 input 标签。使用 Stripes 版本的标签的好处是:它的值是自动生成的。
❺Stripes 的 text 标签可以创建一个文本输入字段(这和你想到的应该一致)。hidden 标签,它可以自动生成其 value 属性的值。
❻Stripes 的 submit 标签会生成一个典型的提交按钮。这里要注意的是:submit 标签的 name 属性值是当表单提交时要调用的 ActionBean 事件处理方法的名称。在这个例子中,调用的是 AlbumActionBean.save()(本章后面在讨论 ActionBean 时将进一步解释事件和它们的处理器)。
Stripes 也有一个 label 标签,可以帮助设置本地化(localization)配置,让代码保持简洁。我们在这没有使用它,是因为想只关注 Hibernate 的东西。幸好 Stripes 也为这些标签提供了很详细的文档( [2] )。
这个页面写好以后,接下来还要编写一个用于列出数据库中的专辑的页面,可以将这个页面作为一个加载页面,通过它能够看到数据库中有什么信息。例 14-13 中的页面代码看起来比 edit.jsp 页面要少一点,不过,要注意一下结尾处的 Stripes link 标签。
例 14-13:专辑列表视图:webapp/albums/list.jsp
<%@page contentType="text/html;charset=UTF-8"language="java"%>
<%@taglib prefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="stripes"
uri="http://stripes.sourceforge.net/stripes.tld"%>
<stripes:useActionBean beanclass="com.oreilly.hh.web.AlbumActionBean"
var="actionBean"event="list"/>
<table>
<tr>
<th>title</th>
<th>discs</th>
<th>action</th>
</tr>
<c:forEach items="${actionBean.albums}"var="album">
<tr>
<td>${album.title}</td>
<td>${album.numDiscs}</td>
<td><stripes:link href="/albums/edit.jsp">
<stripes:param name="album.id"value="${album.id}"/>
edit
</stripes:link></td>
</tr>
</c:forEach>
</table>
<stripes:link href="/albums/edit.jsp">new</stripes:link>
stripes:link 标签用于将程序和 HTML 锚点(anchor)链接起来,它提供了几个属性,可以构建指向 ActionBean 事件处理器以及 JSP 的 URL。
编写 ActionBean
接下来应该编写一个 ActionBean。可以将 ActionBean 看做是 MVC(Model、View、Controller)模式中的控制器组件。例 14-14 演示了我们的第一个 AlbumActionBean,它可以让你很好地了解编写 ActionBean 需要涉及哪些内容。
这个类中的方法可以分为两大类:属性存取器和事件处理器。属性存取器就像其他 Java Bean 的 setter 和 getter 方法一样,所以它们看起来也差不多。另一方面,那些返回 Resolution 的方法就显得有些陌生了,不过其概念也相当简单。当一个请求到达 StripesDispatcher 时,HTTP 请求中的某个部分就可以指示出一个事件的名称,由该事件的处理器负责处理这个 HTTP 请求。当 Stripes 请求的生命周期经过它的 BindingAndValidation 阶段后,就会调用由请求确定的事件处理器方法(StripesDispatcher 使用反射来查找其名称和事件匹配的方法,该方法返回的就是一个 Resolution)。由事件处理器返回的 Resolution 对象接着再由 StripesDispatcher 进行处理(通常进行转发或重定向)。例 14-14 演示了我们的 AlbumActionBean.java。
例 14-14:专辑控制器:AlbumActionBean.java
package com.oreilly.hh.web;
import java.util.List;
import org.apache.log4j.Logger;
import net.sourceforge.stripes.action.*;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.validation.*;
import com.oreilly.hh.dao.AlbumDAO;
import com.oreilly.hh.data.Album;
/**
*Class that implements the web based front end of our Jukebox.
*
*/
public class AlbumActionBean implements ActionBean{
/**
*Logger
*/
private static Logger log=Logger.getLogger(AlbumActionBean.class);
/**
*The ActionBeanContext provided to this class by Stripes DispatcherServlet.
*/
private ActionBeanContext context;
/**
*The list of Album objects we will display on the Album list page.
*/
private List<Album>albums;
/**
*The Album we are providing a form for on the edit page.
*/
private Album album;
/**
*The Data Access Object for our Albums.
*/
private AlbumDAO albumDAO;
public ActionBeanContext getContext(){❶
return context;
}
public void setContext(ActionBeanContext aContext){
context=aContext;
}
/**
*The default event handler that displays a list of Albums.
*@return a forward to the Album list jsp.
*/
@DefaultHandler
public Resolution list(){❷
albums=albumDAO.list();❸
return new ForwardResolution("/albums/list.jsp");
}
/**
*The event handler for handling edits to an Album
*@return a forward to the Album edit jsp.
*/
public Resolution edit(){
if(album!=null){❹
album=albumDAO.get(album.getId());
}
return new ForwardResolution("/albums/edit.jsp");
}
/**
*The event handler for saving an Album.
*@return a redirect to the Album list jsp.
*/
public Resolution save(){
albumDAO.persist(album);
log.debug("Redirecting to list!");
return new RedirectResolution("/albums/list.jsp");
}
/**
*A getter for the view to retrieve the list of Albums.
*@return a list of Albums
*/
public List<Album>getAlbums(){❺
return albums;
}
/**
*A setter for the DispatcherServlet to call that provides the album to
*save.
*/@param anAlbum
@ValidateNestedProperties({❻
@Validate(field="title",required=true, on={"save"}),
@Validate(field="numDiscs",required=true, on={"save"})
})
public void setAlbum(Album anAlbum){
log.debug("setAlbum");
album=anAlbum;
}
/**
*A getter for the edit view to call.
*@return an Album
*/
public Album getAlbum(){
return album;
}
/**
*A method Spring will call that provides this class with an AlbumDAO
*instance.@param anAlbumDAO The AlbumDAO object
*/
@SpringBean("albumDAO")❼
public void injectAlbumDAO(AlbumDAO albumDAO){
this.albumDAO=albumDAO;
}
}
❶ActionBean 接口惟一要求必须实现的是 setContext()和 getContext()方法,ActionBean 可以通过这两个方法来获取有关它的操作所在的 Stripes 环境的信息。
❷这个返回 Resolution 的 public 的方法在 Stripes 中称为事件处理器。它们被自动绑定到浏览器能够访问的 URL 上。例如,对于访问路径/stripesapp/Album.action?save=,Dispatcher 就会选中这个方法。
❸现在还没有 AlbumDao.list()方法,所以我们需要将它增加到 AlbumDAO 接口(其定义位于第 13 章)和 AlbumHibernateDAO 实现类中。
❹“如果专辑不为 null,那么就加载专辑”似乎有点逆向逻辑的意味,但是真正发生的情况是:当 Stripes 将请求绑定到 ActionBean 中的对象时,它看到的只是一个 album.id 参数,用这个 id 值来创建一个新的 Album 对象,接着再调用这个方法。但是我们真正想知道的是如何从数据库中加载一个 Album 对象,再编辑它,所以这就是我们在这里所做的处理。
❺当在请求中发现表单数据与 bean 属性的命名模型匹配时,Stripes 就会调用 ActionBean 中相应的 public 类型的 getter 和 setter 方法。例如,当请求参数中有 album.id、album.title 以及 album.numDiscs 时,Stripes 就会调用 setAlbum()方法。另一方面,当向浏览器生成表单时,就会使用 getter 方法预生成各个值(这也就是例 14-12 中的那些 stripes:text 之类的标签所完成的作用)。
❻Stripes 提供了验证标注,用于标明当调用事件处理器时应该看到哪些字段。我们在此处不准备深入介绍更详细的内容,你可以在 Stripes 的在线文档( [3] )中找到更多的信息。
❼SpringBean 标注是告诉 Stripes:在 Spring 上下文中查找这个对象值,并插入到这里。我们在这里没有使用 Spring 应用程序中典型的 public 类型的 setter 方法,因为黑客(hacker)可能会调用这样的方法来正确地格式化 Web 请求,出于安全原因,我们应该防止类似的访问。为 Spring 要调用( [4] )的方法采用其他命名规范,通常是个好主意。
如前所述,AlbumDAO 需要有一个 list()方法返回所有的 Album 对象,以及一个 get()方法根据专辑的 id 来取回对应的 Album 对象。为此,我们需要调整一下 AlbumDAO 接口和 AlbumHibernateDAO 实现。例 14-15 演示了更新后的 AlbumDAO.java,修改过的部分以粗体突出显示。
例 14-15:在 AlbumDAO 中增加 list()和 get()方法的定义
package com.oreilly.hh.dao;
import java.util.List;
import com.oreilly.hh.data.Album;
public interface AlbumDAO{
public Album persist(Album album);
public void delete(Album album);
public List<Album>list();
public Album get(Integer id);
}
例 14-16 以粗体突出显示了需要对 AlbumHibernateDAO.java 进行的修改。
例 14-16:在 AlbumHibernateDAO 中增加 list()和 get()方法的实现
package com.oreilly.hh.dao.hibernate;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.oreilly.hh.dao.AlbumDAO;
import com.oreilly.hh.data.Album;
public class AlbumHibernateDAO extends HibernateDaoSupport implements AlbumDAO{
public Album persist(Album album){
album=(Album)getHibernateTemplate().merge(album);
getSession().flush();
return album;
}
public void delete(Album album){
getHibernateTemplate().delete(album);
}
@SuppressWarnings("unchecked")
public List<Album>list(){
return getHibernateTemplate().loadAll(Album.class);
}
public Album get(Integer id){
return(Album)getHibernateTemplate().load(Album.class, id);
}
}
例 14-16 中使用的是 HibernateTemplate.loadAll()方法,它与 Session.loadAll()的功能一样,将返回作为参数提供的类的所有持久化对象的列表。第 13 章已经讨论过使用 HibernateTemplate 类的优点。
现在我们已经有了两个视图,一个 ActionBean,也对 DAO 进行了相应的修改。接下来就可以编译和体验这个 Web 应用程序了。相关命令如例 14-17 所示。
例 14-17:编译我们的 Stripes 应用程序
$ant compile
Buildfile:build.xml
Overriding previous definition of reference to project.class.path
prepare:
compile:
[javac]Compiling 20 source files to
/home/rfowler/Hibernate Book/examples/ch12/webapp/WEB-INF/classes
[copy]Copying 1 file to/home/rfowler/Hibernate Book/examples/ch12/webapp/
WEB-INF
BUILD SUCCESSFUL
Total time:2 seconds
当部署例 14-5 所示的应用程序时,我们将 Context 元素的一个属性设置为:reloadable=true。这样设置以后,当为 Web 应用程序的 WEB-INF/classes 目录提供了新版本的类时,Tomcat 将会自动重新加载程序的 context。假设你让 Tomcat 仍然保持运行,如果稍等片刻,context 就会自动加载完成。在这一处理完成以后,就可以用浏览器来访问 http://localhost:8080/stripesapp/albums/list.jsp,看到的页面应该如图 14-3 所示。
图 14-3 我们的 ActionBean 跑起来了
现在我们的数据库中还没有数据,所以这个页面也不会显示任何专辑信息。但是点击"New"链接,将会打开例 14-12 编写的编辑页面,如图 14-4 所示。
图 14-4 加载 Edit(编辑)页面
可以想象到这个页面的功能,在表单中输入有效的数据,点击"Save"提交表单后,将会把数据保存到数据库中,再返回到列表视图,如图 14-5 所示。如果能够按这个流程走下来的话,就表明你已经成功地集成了 Hibernate、Stripes 以及 Spring!花些时间来思考一下本章进行的数据库处理。令人激动的应该是没有花费多少代码就完成了这么多处理。你在 AlbumDAO 和 AlbumHibernateDAO 中添加了 list()和 edit()两个方法,使用 AlbumDAO 对象来加载和持久化 Album 对象。你也会注意到,整个过程中没有用任何代码来直接处理 HTTPServletResponse 或 HTTPServletRequest 对象—Stripes 已经为你处理好了这些繁琐的工作。
图 14-5 显示了一些内容的列表视图
刚才发生了什么
到目前为止,我们已经用 Stripes、Spring 以及 Hibernate 构建好了一个简单的 Web 应用程序。现在我们可以列出所有的专辑、创建新的专辑、对专辑进行编辑。AlbumActionBean 使用 Stripes 和第 13 章写的 Hibernate DAO 来保存对象,为视图提供对象。
下一步要做什么
既然我们已经讨论了如何实现基本的插入、更新、显示数据的处理,我们就回过头来,看看怎么在程序中处理关联。现在我们还根本没有认真思考过它。
[1] http://www.stripesframework.org/display/stripes/Download. [2] http://www.stripesframework.org/display/stripes/Documentation. [3] http://www.stripesframework.org/display/stripes/Validation+Reference. [4] http://www.stripesframework.org/display/stripes/Spring+with+Stripes.
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论