- 浏览: 1059906 次
- 性别:
- 来自: 广州
-
文章分类
最新评论
-
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 6284配置文件中映射元素详解 对象关系的映射是用一个XML ... -
另类查询 Hibernate HQL 深度历险
2006-12-03 04:37 8224... -
MyEclipse+struts+Hibernate配置开发
2006-11-11 23:55 3599说明: 这个手册只是为初学者制作的环境配置和快速开发的一些基 ... -
一个hibernate错误
2006-11-11 23:32 6463在设置成assigned时报:ids for this cla ... -
用hibernate常犯错误
2006-11-11 23:23 22391、hql 里用的是 类名 属性名 而不是数据库的表名字段名 ... -
如何用 Hibernate 实现分页查询
2006-11-10 11:30 1903例如: 从第2万条开始取出100条记录 ... -
Java开源项目Hibernate包作用详解
2006-11-10 11:28 1599Hibernate一共包括了23个jar包,令人眼花缭乱。 ... -
利用Eclipse开发Hibernate应用程序
2006-11-10 11:24 2924Eclipse是目前非常流行的开发平台,开放扩展的架构让很 ... -
如何在Eclipse中用Hibernate插件(组图)
2006-11-10 11:19 5635编辑映射文件 Hibernate Synchro ... -
Java学习之hibernate配置要点详谈
2006-11-10 11:09 21181.两种配置文件: A.hibernate.cfg.x ... -
方便的HQL: Hibernate查询语言
2006-11-10 11:08 2292HQL: Hibernate查询语言 Hibernate配 ... -
Java基础知识:简单Hibernate入门
2006-11-10 11:06 1924Hibernate简介 Hibernate寓意: ... -
Java开源项目Hibernate快速入门
2006-11-10 11:05 1586其实Hibernate本身是个独立的框架,它不需要任何we ... -
从头到脚跟你解释什么是Hibernate
2006-11-10 11:04 2121Hibernate Hi ...
相关推荐
- **Struts和Hibernate之间搭起桥梁.doc**:解释如何在Struts或Struts2框架下整合Hibernate,实现数据持久化。 - **hibernate 主键生成器解释.doc**:详细解释了Hibernate中的主键生成策略。 - **Eclipse配置...
Struts 控制器搭起了 Model 和 View 之间的桥梁,帮助开发人员将分散的材料,如数据库和页面,结合成一个整体的应用系统。 Spring Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。框架的主要...
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
8c71b76fb2ec10cf50fc6b0308d3dcfc_9545878e2b97a84b2e089ece58da9e82
Android逆向过程学习
内容概要:本文详细介绍了基于西门子S7-200 PLC的糖果包装控制系统的设计与实现。首先阐述了PLC在工业自动化领域的优势及其在糖果包装生产线中的重要性。接着深入探讨了系统的硬件连接方式,包括传感器、执行机构与PLC的具体接口配置。随后展示了关键的编程实现部分,如糖果计数、包装执行、送膜控制、称重判断以及热封温度控制等具体梯形图代码片段。此外,还分享了一些实用的经验技巧,如防止信号抖动、PID参数优化、故障诊断方法等。最后总结了该系统的优势,强调其对提高生产效率和产品质量的重要作用。 适合人群:从事工业自动化控制、PLC编程的技术人员,尤其是对小型PLC系统感兴趣的工程师。 使用场景及目标:适用于糖果制造企业,旨在提升包装生产线的自动化程度,确保高效稳定的生产过程,同时降低维护成本并提高产品一致性。 其他说明:文中不仅提供了详细的理论讲解和技术指导,还结合实际案例进行了经验分享,有助于读者更好地理解和掌握相关知识。
内容概要:本文详细介绍了参与西门子杯比赛中关于三部十层电梯系统的博图V15.1程序设计及其WinCC画面展示的内容。文中不仅展示了电梯系统的基本架构,如抢单逻辑、方向决策、状态机管理等核心算法(采用SCL语言编写),还分享了许多实际调试过程中遇到的问题及解决方案,例如未初始化变量导致的异常行为、状态机遗漏空闲状态、WinCC画面动态显示的挑战以及通信配置中的ASCII码解析错误等问题。此外,作者还特别提到一些创意性的设计,如电梯同时到达同一层时楼层显示器变为闪烁爱心的效果,以及节能模式下电梯自动停靠中间楼层的功能。 适合人群:对PLC编程、工业自动化控制、电梯调度算法感兴趣的工程技术人员,尤其是准备参加类似竞赛的学生和技术爱好者。 使用场景及目标:适用于希望深入了解PLC编程实践、掌握电梯群控系统的设计思路和技术要点的人士。通过学习本文可以更好地理解如何利用PLC进行复杂的机电一体化项目的开发,提高解决实际问题的能力。 其他说明:文章风格幽默诙谐,将严肃的技术话题融入轻松的生活化比喻之中,使得原本枯燥的专业知识变得生动有趣。同时,文中提供的经验教训对于从事相关领域的工作者来说非常宝贵,能够帮助他们少走弯路并激发更多创新思维。
慧荣量产工具合集.zip
内容概要:本文详细介绍了永磁同步电机(PMSM)的FOC(磁场定向控制)和SVPWM(空间矢量脉宽调制)算法的仿真模型。首先解释了FOC的基本原理及其核心的坐标变换(Clark变换和Park变换),并给出了相应的Python代码实现。接下来探讨了SVPWM算法的工作机制,包括扇区判断和占空比计算的方法。此外,文章还讨论了电机的PI双闭环控制结构,即速度环和电流环的设计与实现。文中不仅提供了详细的理论背景,还分享了一些实用的编程技巧和注意事项,帮助读者更好地理解和应用这些算法。 适合人群:电气工程专业学生、从事电机控制系统开发的技术人员以及对永磁同步电机控制感兴趣的科研人员。 使用场景及目标:① 学习和掌握永磁同步电机的FOC控制和SVPWM算法的具体实现;② 提供丰富的代码示例和实践经验,便于快速搭建和调试仿真模型;③ 探讨不同参数设置对电机性能的影响,提高系统的稳定性和效率。 其他说明:文章强调了在实际应用中需要注意的一些细节问题,如坐标变换中的系数选择、SVPWM算法中的扇区判断优化以及PI控制器的参数调整等。同时,鼓励读者通过动手实验来加深对各个模块的理解。
# 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;
Android逆向过程学习
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
3dmax插件
# 【spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7.jar中文文档.zip】 中包含: 中文文档:【spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7.jar中文文档.zip,java,spring-ai-autoconfigure-vector-store-qdrant-1.0.0-M7.jar,org.springframework.ai,spring-ai-autoconfigure-vector-store-qdrant,1.0.0-M7,org.springframework.ai.vectorstore.qdr
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
内容概要:本文详细介绍了平方根容积卡尔曼滤波(SRCKF)在永磁同步电机(PMSM)控制系统中的应用及其相对于传统CKF的优势。文章首先指出传统CKF在处理协方差矩阵时存在的数值不稳定性和非正定问题,导致系统性能下降。接着,作者通过引入SRCKF,利用Cholesky分解和QR分解来确保协方差矩阵的正定性,从而提高状态估计的精度和稳定性。文中展示了具体的电机模型和状态方程,并提供了详细的代码实现,包括状态预测、容积点生成以及观测更新等关键步骤。此外,文章还分享了实际调试过程中遇到的问题及解决方案,如选择合适的矩阵分解库和处理电机参数敏感性。最终,通过实验数据对比,证明了SRCKF在突加负载情况下的优越表现。 适合人群:从事永磁同步电机控制研究的技术人员、研究生及以上学历的研究者。 使用场景及目标:适用于需要高精度状态估计的永磁同步电机控制系统的设计与优化,特别是在处理非线性问题和提高数值稳定性方面。 其他说明:文章引用了相关领域的权威文献,如Arasaratnam的TAC论文和Zhong的《PMSM无传感器控制综述》,并强调了实际工程实践中代码调试的重要性。
# 【tokenizers-***.jar***文档.zip】 中包含: ***文档:【tokenizers-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【tokenizers-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【tokenizers-***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【tokenizers-***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【tokenizers-***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: tokenizers-***.jar***文档.zip,java,tokenizers-***.jar,ai.djl.huggingface,tokenizers,***,ai.djl.engine.rust,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,djl,huggingface,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【tokenizers-***.jar***文档.zip】,再解压其中的 【tokenizers-***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件; # Maven依赖: ``` <dependency> <groupId>ai.djl.huggingface</groupId> <artifactId>tokenizers</artifactId> <version>***</version> </dependency> ``` # Gradle依赖: ``` Gradle: implementation group: 'ai.djl.huggingface', name: 'tokenizers', version: '***' Gradle (Short): implementation 'ai.djl.huggingface:tokenizers:***' Gradle (Kotlin): implementation("ai.djl.huggingface:tokenizers:***") ``` # 含有的 Java package(包): ``` ai.djl.engine.rust ai.djl.engine.rust.zoo ai.djl.huggingface.tokenizers ai.djl.huggingface.tokenizers.jni ai.djl.huggingface.translator ai.djl.huggingface.zoo ``` # 含有的 Java class(类): ``` ai.djl.engine.rust.RsEngine ai.djl.engine.rust.RsEngineProvider ai.djl.engine.rust.RsModel ai.djl.engine.rust.RsNDArray ai.djl.engine.rust.RsNDArrayEx ai.djl.engine.rust.RsNDArrayIndexer ai.djl.engine.rust.RsNDManager ai.djl.engine.rust.RsSymbolBlock ai.djl.engine.rust.RustLibrary ai.djl.engine.rust.zoo.RsModelZoo ai.djl.engine.rust.zoo.RsZooProvider ai.djl.huggingface.tokenizers.Encoding ai.djl.huggingface.tokenizers.HuggingFaceTokenizer ai.djl.huggingface.tokenizers.HuggingFaceTokenizer.Builder ai.djl.hu
3
pchook源码纯源码不是dll
# 【spring-ai-azure-store-1.0.0-M7.jar中文-英文对照文档.zip】 中包含: 中文-英文对照文档:【spring-ai-azure-store-1.0.0-M7-javadoc-API文档-中文(简体)-英语-对照版.zip】 jar包下载地址:【spring-ai-azure-store-1.0.0-M7.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-azure-store-1.0.0-M7.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-azure-store-1.0.0-M7.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-azure-store-1.0.0-M7-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-azure-store-1.0.0-M7.jar中文-英文对照文档.zip,java,spring-ai-azure-store-1.0.0-M7.jar,org.springframework.ai,spring-ai-azure-store,1.0.0-M7,org.springframework.ai.vectorstore.azure,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,springframework,spring,ai,azure,store,中文-英文对照API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【spring-ai-azure-store-1.0.0-M7.jar中文-英文对照文档.zip】,再解