- 浏览: 1057554 次
- 性别:
- 来自: 广州
-
文章分类
最新评论
-
wenson:
lzjzy520 写道 求 项目完整元代码已经够清楚了,看不懂 ...
使用Spring JavaMail发送邮件总结 -
lzjzy520:
求 项目完整元代码
使用Spring JavaMail发送邮件总结 -
xiejx618:
能提高多大的性能? 不能用数据来说话吧希望你能用jmeter做 ...
利用APR本地库提高Tomcat性能 -
mrwalter:
学习了,挺好用的,局域网内速度很快
ssh远程文件传输命令scp -
wcily123:
不错
ssh远程文件传输命令scp
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; }}
我们希望一个product可以被更改category,所以我们的HTML提供了一个下拉框列出所有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>
这里我们看出了两者的不一致:在Product领域对象里,category属性是Category类型,但是ProductForm只有一个类型为long的categoryId.这种不匹配不但增加了不一致,而且导致了不必要的代码进行primitive type的标示符和对应的对象之间的转换。
这种不一致部分是由于HTML Form自己引起的:它只代表了一种关系模型,不能代表面向对象的模型。面向对象和关系模型的不一致在存储层由对象关系映射(O/RM)解决。但是类似的问题在表示层(view layer)仍然存在。解决的关键是让他们一起无缝地工作。
Struts的功能和局限
幸运的是,Struts能够生成和解释内嵌的对象属性。Category下拉框可以用Struts page-construction(html) tag library:
<html:select property="category.id"> <option value="">No Category</option> <html:options collection="categories" property="id" labelProperty="name"/></html:select>
我们假设categories是Category对象的一个list.所以现在我们要修改ProductForm,让它变得更加“面向对象”,我们要修改ProductForm的categoryId,改成类型为Category的category.这种改变会导致在Product和ProductForm之间复制属性的工作更加繁琐,因为两者有相同的属性。
public class ProductForm extends ActionForm { private Long id; private Category category; ……}
当我们完成剩余的Struts Action, configuration, validator, jsp, hibernate层后,开始测试,我们马上在访问ProductForm.category.id时遇到了NullPointerException.这是预料中的!因为ProductForm.category还没有被设置,同时,Hibernate也会将多对一所联系的对象引用设为空(如果database field为空指)(译者:这里指Hiberate将product.category为Null,如果该Product没有联系到任何category)。Struts要求所有的对象在显示(生成HTML Form)和传播(提交HTML FORM)之前被建立。
让我们看看如何用ActionForm.reset()来架起桥梁。
(并非如此)臭名昭著的Struts ActionForm
在我第一个星期接触Struts的时候,我最大的一个疑问就是:为什么我必须为Properties, getter方法, setter方法保持几乎完全相同的两份copy, 一份在ActionForm Bean, 一份在DomainObject.这个繁琐的步骤成了Struts社区最主要的抱怨之一。
以我的观点,ActionForm存在有原因的。首先,它们可以区别于Domain Object因为他们但当了不同的角色。在MVC模式下,Domain Object是Model层的一个部分,ActionForm是View层的。因为Webpage的Field和Database的Field可能不一样,某些特制的转换是常见的。第二,ActionForm.validate()方法可以定义非常好用的验证规则。第三,可能有其他的,特定的View行为,但是又不想在domain layer实现,特别当persistence framework来管理domain object的时候。
提交Form
让我们来用ActionForm内有的方法-reset()-来解决view和model之间的不一致。这个reset()方法是在ActionForm在被Struts Controller Servlet处理request时候复制ActionForm属性之前调用的。这个方法最常见的使用是:checkbox必须被显式地设为false,让没有被选中的checkbox被正确识别。Reset()也是一个初始化用于view rending对象的合适地方。代码看起来是这样的:
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(); } }}
Struts在使用用户提交的值填写ProductForm之前,Struts会调用reset(),这样category属性将会被初始化。请注意,你必须检查category看它是不是null,后面我们会讨论这个。
编辑Form
到目前为止,我们已经解决了form提交时候的问题。但是当我们在生成form页面的时候呢?Html:select tag也希望有一个非空的引用,所以我们将在form生成页面之前调用reset()。我们在action类里加入了一行:
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 ); …… }}
我假设读者已经对action类和Jakarta commons Beanutils包非常熟悉了。CreateOrLoadProduct()建立了一个新的Product实例或者从数据库里载入一个已有的实例,具体取决于这个action是建立或者修改Product的。ProductForm被赋值后(译者:也就是调用PropertyUtils.copyProperties后),productForm.category已经从Product.category复制过来了(译者:实际上只是复制了category对象引用,并没有开销),然后,ProductForm就能用来生成页面了。我们同时也必须保证:不覆盖已经被Hibernate载入的对象,所以我们必须检查(category)是不是为null.
因为reset()方法是在ActionForm中定义的,我们可以把上述代码放入一个superclass,比如CommonEditAction,来处理这些事情:
Product product = createOrLoadProduct(); PropertyUtils.copyProperties( form, product ); form.reset( mapping, request );
如果你需要一个只读的Form, 你有两个选择: 第一检查所联系的jsp对象是不是null, 第二复制domain对象到ActionForm之后调用Reset()
保存domain对象
我们解决了提交Form和生成Form页面的问题, 所以Struts可以满足了。但是Hibernate呢?当用户选择了一个null ID option – 在我们的例子中“no category”option- 并且提交form, productForm.category指向一个新建立的hibernate对象,id为null.当category属性从ProductForm复制到Hibernate控制的Product对象并且存储时,Hibernate会抱怨product.category是一个临时对象,需要在Product存储前先被存储。当然,我们知道它是Null,并且不需要被存储。所以我们需要将product.category置为Null,然后Hibernate就能存储Product了(译者:在这种情况下,数据库product.category被设成空值)。我们也不希望改变Hibernate的工作方式,所以我们选择在复制到Domain对象之前清理这些临时对象,我们在ProductForm中加了一个方法:
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; } }}
我们在copyProperties之前清理掉这些临时对象,所以如果ProductForm.category只是用来放Null的,则将ProductForm.category置为Null.然后Domain对象的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 ); …… }}
一对多关系
我还没有解决Category到Product的一对多关系。我们把它加入到Category的Metadata中:
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; }}
注意:Hibernate的cascade属性为all-delete-orphan表明:Hibernate需要在存储包含的Category对象时候,自动存储Product对象。和parent对象一起存储child对象的情况并不常见,常见的是:分别控制child的存储和parent的存储。在我们的例子中,我们可以容易地做到这一点,如果我们允许用户在同一个html page编辑Category和ProductS.用set表示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(); } }}
更进一步我们已经可以察看,编辑,提交forms,并且存储相关的objects,但是为所有的ActionForm类定义CleanupEmptyObjects()和reset()方法是个累赘。我们将用一个抽象的ActionForm来完成协助完成这些工作。
作为通用的实现,我们必须遍历所有的Hibernate管理的domain对象,发现他们的identifier,并且测试id值。幸运的是:org.hibernate.metadata包已经有两个Utility类能取出domain对象的元数据。我们用ClassMetadata类检查这个object是不是Hibernate管理的。如果是:我们把它们的id Value取出来。我们用了Jakarta Commons Beanutils包来协助JavaBean元数据的操作。
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 ); } } } }}
为了让代码可读,我们省略了Exception的处理代码。
我们的新AbstractForm类从Struts的ActionForm类继承,并且提供了通用行为:reset和cleanup多对一关联对象。当这个关系是相反的话(也就是一对多关系),那么每个例子将会有所不同,类似在Abstract类里实现是比较好的办法。
总结
Struts和Hibernate是非常流行和强大的框架,他们可以有效地相互合作,并且弥补domain模型和MVC视图(view)之间的差别。这篇文章讨论一个解决Struts/Hibernate Project的通用的方案,并且不需要大量修改已经有的代码。
在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; }}
我们希望一个product可以被更改category,所以我们的HTML提供了一个下拉框列出所有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>
这里我们看出了两者的不一致:在Product领域对象里,category属性是Category类型,但是ProductForm只有一个类型为long的categoryId.这种不匹配不但增加了不一致,而且导致了不必要的代码进行primitive type的标示符和对应的对象之间的转换。
这种不一致部分是由于HTML Form自己引起的:它只代表了一种关系模型,不能代表面向对象的模型。面向对象和关系模型的不一致在存储层由对象关系映射(O/RM)解决。但是类似的问题在表示层(view layer)仍然存在。解决的关键是让他们一起无缝地工作。
Struts的功能和局限
幸运的是,Struts能够生成和解释内嵌的对象属性。Category下拉框可以用Struts page-construction(html) tag library:
<html:select property="category.id"> <option value="">No Category</option> <html:options collection="categories" property="id" labelProperty="name"/></html:select>
我们假设categories是Category对象的一个list.所以现在我们要修改ProductForm,让它变得更加“面向对象”,我们要修改ProductForm的categoryId,改成类型为Category的category.这种改变会导致在Product和ProductForm之间复制属性的工作更加繁琐,因为两者有相同的属性。
public class ProductForm extends ActionForm { private Long id; private Category category; ……}
当我们完成剩余的Struts Action, configuration, validator, jsp, hibernate层后,开始测试,我们马上在访问ProductForm.category.id时遇到了NullPointerException.这是预料中的!因为ProductForm.category还没有被设置,同时,Hibernate也会将多对一所联系的对象引用设为空(如果database field为空指)(译者:这里指Hiberate将product.category为Null,如果该Product没有联系到任何category)。Struts要求所有的对象在显示(生成HTML Form)和传播(提交HTML FORM)之前被建立。
让我们看看如何用ActionForm.reset()来架起桥梁。
(并非如此)臭名昭著的Struts ActionForm
在我第一个星期接触Struts的时候,我最大的一个疑问就是:为什么我必须为Properties, getter方法, setter方法保持几乎完全相同的两份copy, 一份在ActionForm Bean, 一份在DomainObject.这个繁琐的步骤成了Struts社区最主要的抱怨之一。
以我的观点,ActionForm存在有原因的。首先,它们可以区别于Domain Object因为他们但当了不同的角色。在MVC模式下,Domain Object是Model层的一个部分,ActionForm是View层的。因为Webpage的Field和Database的Field可能不一样,某些特制的转换是常见的。第二,ActionForm.validate()方法可以定义非常好用的验证规则。第三,可能有其他的,特定的View行为,但是又不想在domain layer实现,特别当persistence framework来管理domain object的时候。
提交Form
让我们来用ActionForm内有的方法-reset()-来解决view和model之间的不一致。这个reset()方法是在ActionForm在被Struts Controller Servlet处理request时候复制ActionForm属性之前调用的。这个方法最常见的使用是:checkbox必须被显式地设为false,让没有被选中的checkbox被正确识别。Reset()也是一个初始化用于view rending对象的合适地方。代码看起来是这样的:
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(); } }}
Struts在使用用户提交的值填写ProductForm之前,Struts会调用reset(),这样category属性将会被初始化。请注意,你必须检查category看它是不是null,后面我们会讨论这个。
编辑Form
到目前为止,我们已经解决了form提交时候的问题。但是当我们在生成form页面的时候呢?Html:select tag也希望有一个非空的引用,所以我们将在form生成页面之前调用reset()。我们在action类里加入了一行:
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 ); …… }}
我假设读者已经对action类和Jakarta commons Beanutils包非常熟悉了。CreateOrLoadProduct()建立了一个新的Product实例或者从数据库里载入一个已有的实例,具体取决于这个action是建立或者修改Product的。ProductForm被赋值后(译者:也就是调用PropertyUtils.copyProperties后),productForm.category已经从Product.category复制过来了(译者:实际上只是复制了category对象引用,并没有开销),然后,ProductForm就能用来生成页面了。我们同时也必须保证:不覆盖已经被Hibernate载入的对象,所以我们必须检查(category)是不是为null.
因为reset()方法是在ActionForm中定义的,我们可以把上述代码放入一个superclass,比如CommonEditAction,来处理这些事情:
Product product = createOrLoadProduct(); PropertyUtils.copyProperties( form, product ); form.reset( mapping, request );
如果你需要一个只读的Form, 你有两个选择: 第一检查所联系的jsp对象是不是null, 第二复制domain对象到ActionForm之后调用Reset()
保存domain对象
我们解决了提交Form和生成Form页面的问题, 所以Struts可以满足了。但是Hibernate呢?当用户选择了一个null ID option – 在我们的例子中“no category”option- 并且提交form, productForm.category指向一个新建立的hibernate对象,id为null.当category属性从ProductForm复制到Hibernate控制的Product对象并且存储时,Hibernate会抱怨product.category是一个临时对象,需要在Product存储前先被存储。当然,我们知道它是Null,并且不需要被存储。所以我们需要将product.category置为Null,然后Hibernate就能存储Product了(译者:在这种情况下,数据库product.category被设成空值)。我们也不希望改变Hibernate的工作方式,所以我们选择在复制到Domain对象之前清理这些临时对象,我们在ProductForm中加了一个方法:
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; } }}
我们在copyProperties之前清理掉这些临时对象,所以如果ProductForm.category只是用来放Null的,则将ProductForm.category置为Null.然后Domain对象的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 ); …… }}
一对多关系
我还没有解决Category到Product的一对多关系。我们把它加入到Category的Metadata中:
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; }}
注意:Hibernate的cascade属性为all-delete-orphan表明:Hibernate需要在存储包含的Category对象时候,自动存储Product对象。和parent对象一起存储child对象的情况并不常见,常见的是:分别控制child的存储和parent的存储。在我们的例子中,我们可以容易地做到这一点,如果我们允许用户在同一个html page编辑Category和ProductS.用set表示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(); } }}
更进一步我们已经可以察看,编辑,提交forms,并且存储相关的objects,但是为所有的ActionForm类定义CleanupEmptyObjects()和reset()方法是个累赘。我们将用一个抽象的ActionForm来完成协助完成这些工作。
作为通用的实现,我们必须遍历所有的Hibernate管理的domain对象,发现他们的identifier,并且测试id值。幸运的是:org.hibernate.metadata包已经有两个Utility类能取出domain对象的元数据。我们用ClassMetadata类检查这个object是不是Hibernate管理的。如果是:我们把它们的id Value取出来。我们用了Jakarta Commons Beanutils包来协助JavaBean元数据的操作。
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 ); } } } }}
为了让代码可读,我们省略了Exception的处理代码。
我们的新AbstractForm类从Struts的ActionForm类继承,并且提供了通用行为:reset和cleanup多对一关联对象。当这个关系是相反的话(也就是一对多关系),那么每个例子将会有所不同,类似在Abstract类里实现是比较好的办法。
总结
Struts和Hibernate是非常流行和强大的框架,他们可以有效地相互合作,并且弥补domain模型和MVC视图(view)之间的差别。这篇文章讨论一个解决Struts/Hibernate Project的通用的方案,并且不需要大量修改已经有的代码。
发表评论
-
Hibernate配置文件中映射元素详解
2006-12-05 13:40 6280配置文件中映射元素详解 对象关系的映射是用一个XML ... -
另类查询 Hibernate HQL 深度历险
2006-12-03 04:37 8218... -
MyEclipse+struts+Hibernate配置开发
2006-11-11 23:55 3593说明: 这个手册只是为初学者制作的环境配置和快速开发的一些基 ... -
一个hibernate错误
2006-11-11 23:32 6447在设置成assigned时报:ids for this cla ... -
用hibernate常犯错误
2006-11-11 23:23 22311、hql 里用的是 类名 属性名 而不是数据库的表名字段名 ... -
如何用 Hibernate 实现分页查询
2006-11-10 11:30 1897例如: 从第2万条开始取出100条记录 ... -
Java开源项目Hibernate包作用详解
2006-11-10 11:28 1592Hibernate一共包括了23个jar包,令人眼花缭乱。 ... -
利用Eclipse开发Hibernate应用程序
2006-11-10 11:24 2918Eclipse是目前非常流行的开发平台,开放扩展的架构让很 ... -
如何在Eclipse中用Hibernate插件(组图)
2006-11-10 11:19 5626编辑映射文件 Hibernate Synchro ... -
Java学习之hibernate配置要点详谈
2006-11-10 11:09 21121.两种配置文件: A.hibernate.cfg.x ... -
方便的HQL: Hibernate查询语言
2006-11-10 11:08 2287HQL: Hibernate查询语言 Hibernate配 ... -
Java基础知识:简单Hibernate入门
2006-11-10 11:06 1919Hibernate简介 Hibernate寓意: ... -
Java开源项目Hibernate快速入门
2006-11-10 11:05 1575其实Hibernate本身是个独立的框架,它不需要任何we ... -
从头到脚跟你解释什么是Hibernate
2006-11-10 11:04 2114Hibernate Hi ...
相关推荐
- **Struts和Hibernate之间搭起桥梁.doc**:解释如何在Struts或Struts2框架下整合Hibernate,实现数据持久化。 - **hibernate 主键生成器解释.doc**:详细解释了Hibernate中的主键生成策略。 - **Eclipse配置...
Struts 控制器搭起了 Model 和 View 之间的桥梁,帮助开发人员将分散的材料,如数据库和页面,结合成一个整体的应用系统。 Spring Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。框架的主要...
uniapp实战商城类app和小程序源码,包含后端API源码和交互完整源码。
本课程是 PHP 进阶系列之 Swoole 入门精讲,系统讲解 Swoole 在 PHP 高性能开发中的应用,涵盖 协程、异步编程、WebSocket、TCP/UDP 通信、任务投递、定时器等核心功能。通过理论解析和实战案例相结合,帮助开发者掌握 Swoole 的基本使用方法及其在高并发场景下的应用。 适用人群: 适合 有一定 PHP 基础的开发者、希望提升后端性能优化能力的工程师,以及 对高并发、异步编程感兴趣的学习者。 能学到什么: 掌握 Swoole 基础——理解 Swoole 的核心概念,如协程、异步编程、事件驱动等。 高并发处理——学习如何使用 Swoole 构建高并发的 Web 服务器、TCP/UDP 服务器。 实战项目经验——通过案例实践,掌握 Swoole 在 WebSocket、消息队列、微服务等场景的应用。 阅读建议: 建议先掌握 PHP 基础,了解 HTTP 服务器和并发处理相关概念。学习过程中,结合 官方文档和实际项目 进行实践,加深理解,逐步提升 Swoole 开发能力。
matlab齿轮-轴-轴承系统含间隙非线性动力学 基于matlab的齿轮-轴-轴承系统的含间隙非线性动力学模型,根据牛顿第二定律,建立齿轮系统啮合的非线性动力学方程,同时也主要应用修正Capone模型的滑动轴承无量纲化雷诺方程,利用这些方程推到公式建模;用MATLAB求解画出位移-速度图像,从而得到系统在不同转速下的混沌特性,分析齿轮-滑动轴承系统的动态特性 程序已调通,可直接运行 ,关键词:Matlab;齿轮-轴-轴承系统;含间隙非线性动力学;牛顿第二定律;动力学方程;修正Capone模型;无量纲化雷诺方程;位移-速度图像;混沌特性;动态特性。,基于Matlab的齿轮-轴-轴承系统非线性动力学建模与混沌特性分析
2024年移动应用隐私安全观测报告.pdf
本电影评论网站管理员和用户。管理员功能有个人中心,用户管理,电影类别管理,电影信息管理,留言板管理,论坛交流,系统管理等。用户可以对电影进行评论。因而具有一定的实用性。本站是一个B/S模式系统,采用SSM框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得电影评论网站管理工作系统化、规范化。 本系统的使用使管理人员从繁重的工作中解脱出来,实现无纸化办公,能够有效的提高电影评论网站管理效率。 关键词:电影评论网站;SSM框架;MYSQL数据库 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关技术 2 2.1 MYSQL数据库 2 2.2 B/S结构 3 2.3 Spring Boot框架简介 4 3系统分析 4 3.1可行性分析 4 3.1.1技术可行性 4 3.1.2经济可行性 5 3.1.3操作可行性 5 3.2系统性能分析 5 3.2.1 系统安全性 5 3.2.2 数据完整性 6 3.3系统界面分析 6 3.4系统流程和逻辑 7 4系统概要设计 8 4.1概述 8 4.2系统结构 9 4.
2023-04-06-项目笔记-第四百三十六阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.434局变量的作用域_434- 2025-03-13
基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动 1100027-基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动、阈值设置、LCD1602、超阈值报警、proteus) 功能描述: 基于STM32F103C8单片机实现的智能流速、流量,流量计设计 实现的功能是通过信号发生器模拟齿轮传感器,检测流量的大小,同时计算流过液体的总容量 可以设置最大流过的总容量,当超过设定值后通过蜂鸣器与LED灯指示 当没有超过则启动水泵控制电路带动液体流动 1、流速检测 2、流量统计 3、阈值显示与设置(通过按键实现阈值的调节或清零) 4、水泵启动 5、超阈值报警 有哪些资料: 1、仿真工程文件 2、PCB工程文件 3、原理图工程文件 4、源代码 ,核心关键词: 基于STM32的流量计; 智能流速流量监测; 水泵报警系统; 阈值设置; LCD1602; 超阈值报警; Proteus仿真; STM32F103C8单片机; 齿轮传感器; 信号发生器; 流量统计; 蜂鸣器与LED灯指示; 水泵控制电路。,基于STM32的智能流量监测与报警系统(阈值可调、流速与流量监
(灰度场景下的平面、海底、船、受害者)图像分类数据集【已标注,约1100张数据】 数据经过预处理,可以直接作为分类网络输入使用 分类个数【4】:平面、海底、船、受害者【具体查看json文件】 划分了训练集、测试集。存放各自的同一类数据图片。如果想可视化数据集,可以运行资源中的show脚本。 图像分类、分割网络改进:https://blog.csdn.net/qq_44886601/category_12858320.html 计算机视觉完整项目:https://blog.csdn.net/qq_44886601/category_12816068.html
arkime无geo下的oui文件
人脸识别项目实战
人脸识别项目实战
CAD 2025 二次开发dll
人脸识别项目源码实战
c语言学习
基于扩张状态观测器eso扰动补偿和权重因子调节的电流预测控制,相比传统方法,增加了参数鲁棒性 降低电流脉动,和误差 基于扩张状态观测器eso补偿的三矢量模型预测控制 ,基于扩张状态观测器; 扰动补偿; 权重因子调节; 电流预测控制; 参数鲁棒性; 电流脉动降低; 误差降低; 三矢量模型预测控制,基于鲁棒性增强和扰动补偿的电流预测控制方法
c语言学习
UE开发教程与学习方法记录.zip
在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。