将struts扩展到面向对象的hibernate
译者按:
在看这篇文章之前: 如果你还不清楚hibernate的or/m工作机制, hibernate注释,以及一对多,多对一的机制,请先看hibernate文档
如果你不清楚struts的mvc,请先看struts文档,
你也要大概了解javabean和jakarta commons beanutil是干什么的)
版权声明:任何获得matrix授权的网站,转载时请务必保留以下作者信息和链接
作者:ted he;alilo(作者的blog:http://blog.matrix.org.cn/page/alilo)
原文:http://www.matrix.org.cn/resource/article/44/44391_struts+hibernate.html
关键字:struts;hibernate
摘要
hibernate和struts是当前市面上几个最流行的开源的库之一。它们很有效率,是程序员在开发java企业应用,挑选几个竞争的库的首选。虽然它们经常被一起应用,但是hibernate的设计目标并不是和struts一起使用,而struts在hibernate诞生好多年之前就发布了。为了让它们在一起工作,仍然有很多挑战。这篇文章点明了struts和hibernate之间的一些鸿沟,尤其关系到面向对象建模方面。文章也描述了如何在两者间搭起桥梁,给出了一个基于扩展struts的解决方案。所有的基于struts和hibernate构建的web应用都能从这个通用的扩展中获益。
在hibernate in action(manning,2004十月)这本书里,作者christian bauer和gavin king揭示了面向对象世界的模型和关系数据模型,两个世界的范例是不一致的。hibernate非常成功地在存储层(persistence layer)将两者粘合在一起。但是领域模型(domain model)(也就是model-view-controller的model layer)和html页面(mvc的view layer)仍然存在不一致。在这篇文章中,我们将检查这种不一致,并且探索解决的方案。
范例不一致的再发现
让我们先看一个经典的parent-child关系例子(看下面的代码):product和category。category类定义了一个类型为long的标示符id和一个类型为string的属性name。product类也有一个类型为long的标示符id和一个类型为category的属性category,表示了多对一的关系(也就是说很多product可以属于一个category)
/**
* @hibernate.class table="category"
*/
public class category {
private long id;
private string name;
/**
* @hibernate.id generator-class="native" column="category_id"
*/
public long getid() {
return id;
}
public void setid(long id) {
this.id = id;
}
/**
* @hibernate.property column="name"
*/
public string getname() {
return name;
}
public void setname(long name) {
this.name = name;
}
}
/**
* @hibernate.class table="product"
*/
public class product {
private long id;
private category category;
/**
* @hibernate.id generator-class="native" column="product_id"
*/
public long getid() {
return id;
}
public void setid(long id) {
this.id = id;
}
/**
* @hibernate.many-to-one
* column="category_id"
* class="category"
* cascade="none"
* not-null="false"
*/
public category getcategory() {
return category;
}
public void setcategory(category category) {
this.category = category;
}
}
<select name="categoryid">
<option value="">no category</option>
<option value="1">category 1</option>
<option value="2">category 2</option>
<option value="3">category 3</option>
</select>
<html:select property="category.id">
<option value="">no category</option>
<html:options collection="categories" property="id" labelproperty="name"/>
</html:select>
public class productform extends actionform {
private long id;
private category category;
...
} public class productform extends actionform {
private long id;
private category category;
...
public void reset(actionmapping mapping, httpservletrequest request)
{
super.reset( mapping, request );
if ( category == null ) { category = new category(); }
}
} public class editproductaction extends action {
public final actionforward execute( actionmapping mapping, actionform form,
httpservletrequest request, httpservletresponse response ) throws exception
{
...
product product = createorloadproduct();
productform productform = (productform)form;
propertyutils.copyproperties( productform, product );
productform.reset( mapping, request );
...
}
} product product = createorloadproduct();
propertyutils.copyproperties( form, product );
form.reset( mapping, request );
public class productform extends actionform {
private long id;
private category category;
...
public void reset(actionmapping mapping, httpservletrequest request) {
super.reset( mapping, request );
if ( category == null ) { category = new category(); }
}
public void cleanupemptyobjects() {
if ( category.getid() == null ) { category = null; }
}
}public class saveproductaction extends action {
public final actionforward execute( actionmapping mapping, actionform form,
httpservletrequest request, httpservletresponse response ) throws exception
{
...
product product = new product();
((productform)form).cleanupemptyobjects();
propertyutils.copyproperties( product, form );
saveproduct( product );
...
}
} public class category {
...
private set products;
...
/**
* @hibernate.set
* table="product"
* lazy="true"
* outer-join="auto"
* inverse="true"
* cascade="all-delete-orphan"
*
* @hibernate.collection-key
* column="category_id"
*
* @hibernate.collection-one-to-many
* class="product"
*/
public set getproducts() {
return products;
}
public void setproducts(set products) {
this.products = products;
}
} public class categoryform extends actionform {
private set productforms;
...
public void reset(actionmapping mapping, httpservletrequest request) {
super.reset( mapping, request );
for ( int i = 0; i < max_product_num_on_page; i++ ) {
productform productform = new productform();
productform.reset( mapping, request );
productforms.add( productform );
}
}
public void cleanupemptyobjects() {
for ( iterator i = productforms.iterator(); i.hasnext(); ) {
productform productform = (productform) i.next();
productform.cleanupemptyobjects();
}
}
} import java.beans.propertydescriptor;
import org.apache.commons.beanutils.propertyutils;
import org.hibernate.metadata.classmetadata;
public abstract class abstractform extends actionform {
public void reset(actionmapping mapping, httpservletrequest request) {
super.reset( mapping, request );
// get propertydescriptor of all bean properties
propertydescriptor descriptors[] =
propertyutils.getpropertydescriptors( this );
for ( int i = 0; i < descriptors.length; i++ ) {
class propclass = descriptors[i].getpropertytype();
classmetadata classmetadata = hibernateutil.getsessionfactory()
.getclassmetadata( propclass );
if ( classmetadata != null ) { // this is a hibernate object
string propname = descriptors[i].getname();
object propvalue = propertyutils.getproperty( this, propname );
// evaluate property, create new instance if it is null
if ( propvalue == null ) {
propertyutils.setproperty( this, propname, propclass.newinstance() );
}
}
}
}
public void cleanupemptyobjects() {
// get propertydescriptor of all bean properties
propertydescriptor descriptors[] =
propertyutils.getpropertydescriptors( this );
for ( int i = 0; i < descriptors.length; i++ ) {
class propclass = descriptors[i].getpropertytype();
classmetadata classmetadata = hibernateutil.getsessionfactory()
.getclassmetadata( propclass );
if ( classmetadata != null ) { // this is a hibernate object
serializable id = classmetadata.getidentifier( this, entitymode.pojo );
// if the object id has not been set, release the object.
// define application specific rules of not-set id here,
// e.g. id == null, id == 0, etc.
if ( id == null ) {
string propname = descriptors[i].getname();
propertyutils.setproperty( this, propname, null );
}
}
}
}
}
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器