??xml version="1.0" encoding="utf-8" standalone="yes"?> 当我们需要编辑某行数据的时候,可以该行的数据讄C个已l设计好的单行编辑框中进行编辑。在~辑完成以后Q点?#8220;保存”按钮Q?/span>DWR可以采用ajax的方式访问服务器Q将数据保存到数据库中。怎样设计一个单行编辑框呢?让我们一步一步来完成吧?/span> 另外一个关键的问题我想特别提一下,是值对象的主键。我在设?/span>hibernate的值对象的时候倡导的是使用无意义的主键。既然是无意义的主键Q那么我们不应当主键值展C给用户。因此我在设计页面的时候通常是将主键对应的标{设计成一?/span>hidden标签。如果主键标{ؓ(f)I,在提交数据保存的时候,hibernate执行插入操作;如果不ؓ(f)I,执行的将是更新操作。因此,通常不需要分别设计插入页面和更新面Q可以将它们合二ZQ一些因Ҏ(gu)原因必须插入页面和更新面拆开来编写的情况应当另当别论Q?/span> W一行生一个空值对象,W二行?/span>setValues()页面清I?/span> 当我们在列表昄框中选择?jin)某行ƈ点?#8220;~辑”按钮以后Q需要一个编辑函数将该行的数据设|到单行~辑框中。用DWR怎样设计~辑函数呢?前面提到Q在列表昄框装载查询结果集的时候,我们同时也将l果集放|到?jin)一个叫objCache面端数据缓存中。当用户点击“~辑”按钮Ӟ需要将该行的行好以参数的Ş式传递给~辑函数Q然后编辑函数将?/span>objCache中取得该行的值对象,最后?/span>setValues()该值对象设|到单行~辑框中?/span> 回顾保存函数Q我们可以抽象出部分代码Q以便简化保存函数的~写q提高代码复用度。代码中的第2?/span>3?/span>5?/span>6行都可以抽象成一个通用的函数进行编写。而代码中?/span>1?/span>4行则是个性化的代码,应当在具体编写每个功能的时候分别去实现。也是说保存函数被我分成了(jin)通用函数和具体实现函C部分Q具体的实现见我的示例?/span> 当我们在列表昄框中选择?jin)某行ƈ点?#8220;删除”按钮的时候,我们需要设计一个删除函数来删除该行数据。删除函数的设计与保存函数的设计比较q似Q这里我׃再篏赘了(jin)Q朋友们自己思考吧?/span>1、设计页面?/span>
设计好一个单行编辑框的页面,为值对象中的每一个属性设计一个数据输入框Q如单行文本框、多行编辑框、下拉框、单选框{等。设计这些数据输入框的同时应当将它们?/span>id讄成与值对象对应的属性名相同的名U。这里我想特别说明的是下拉框Q因Z拉框中的下拉部分应当是一个从数据库中查出来的下拉列表?/span>DWRZ拉框设计?jin)一个非怾利的函数addOptions()Q函?/span>addOptions的完整写法如?/span>Q?/span>
在该函数中,eleid是下拉框?/span>id?/span>data是下拉框需要显C的下拉列表的数据集Q它通常需要包含至两行数据,一行是下拉?/span>value部分的数据,即需要存数据库的数据Q另一行是下拉?/span>text部分的数据,即仅仅用于在下拉列表中显C的数据。比如,我们有一个选择部门的下拉框Q?/span>value部分对应的应当部门编P?/span>text部分应当是部门名U。清楚了(jin)dataQ?/span>valueprop?/span>textprop好说了(jin)Q?/span>valueprop是value部分的属性名Q?/span>textprop是text部分的属性名。因此,写一个选择部门的下拉框应当q样写:(x)
2、设计清除函?/span>
如果你需要设计一个添加功能,则需要显CZ个没有显CZQ何值的I单行编辑框。然而?/span>DWR设计面Q我们的思维需要发生一个{变,那就是不要随便刷新页面。什么意思呢Q当你打开一个单行编辑框d一条数据ƈ保存以后Q又需要添加另一条数据。如果不h面Q则该页面此时还依然昄的是上一条数据的内容Q我们就需要设计一个页面清除函数。如果我们在dwr.xml文g中是一个一个注册值对象,那么写清除函数就非常单了(jin)。具体编辑如下:(x)
3、设计编辑函?/span>
4、设计保存函?/span>
当编辑数据完成以后,点击“保存”按钮以后Q需要执行一个保存函数来执行保存。在设计保存函数的时候,首先需要从面中取出数据ƈ攄到值对象中。ؓ(f)?jin)完成该功能Q?/span>DWR提供?/span>getValues()函数。在使用该函数的时候,我们必须写生一个空值对象,然后该对象作ؓ(f)参数传递给getValues()Q则面中的数据植入到?jin)该对象中。最后,使用DWR的特有方式,调用服务器端?/span>java对象中的函数Q执行保存。在执行保存的过E这Q?/span>DWRq专门提供了(jin)事务处理的功能,当然我从来没有测试过该事务处理的能力。ȝ保存函数应当如下~写Q?/span>
5、设计删除函?/span>
]]>
org.
仔细查看和跟t源码,我发现这个问题出?/span>AbstractOutboundVariablecȝgetReferenceVariableҎ(gu)中,它的源码是这样写的:(x)
q个问题我同样在?/span>》一文中提到q,是dwr在{换一对一值对象关pL出现d@环的问题。假?/span>Employee值对象存在一个且最多一?/span>Address值对象的时候,Employee有一?/span>Address属性指向一?/span>Address值对象,?/span>Address值对象也同样?x)有一?/span>Employee属性指向这?/span>Employee值对象。我们知?/span>hibernate对于一对一兌是不q行延迟加蝲的,所?/span>dwr在装载和转换Employee值对象的时候会(x)d载它?/span>Address值对象,然后在加载这?/span>Address值对象的时候会(x)又去加蝲那个Employee值对象。如此反复加载就形成?jin)死循环。解册个问题的办法是?/span>dwr.xml配置Address的时候,使用exclude用它对Employee的加载。详l说明见?/span>》,q里׃再罗嗦了(jin)?/span>
在?/span>dwr执行插入和更新操作的时候,有时?x)出C下的警告Q?/span>
Missing java bean property to match javascript property:[属性名]. For causes see debug level logs:如果?/span>log4j?/span>dwr的别降低ؓ(f)DEBUGU别Q你q可以在控制C看到一下提C:(x)
You may be missing the correct setter: setXXX()The property may be excluded using include or exclude rules.其实你ƈ没有?/span>dwr中禁用这个属性,同时也正地在值对象中~写?jin)一?/span>setXXX()Ҏ(gu)的,q个问题到底出在哪里呢?我查看了(jin)dwr的源码发玎ͼdwr是如何获得一个值对象的所有属性及(qing)其各自的get?/span>setҎ(gu)呢?是采?/span>Java的反向机制。如果你通过自己ȝ写或修改某个属性及(qing)其它?/span>get?/span>setҎ(gu)Q而不是通过工具生成Q那么反向机制就可能找不到这个属性的get?/span>setҎ(gu)Q注意,是可能而ƈ不Lq样Q。这个问题解决的办法是删除该属性的get?/span>setҎ(gu)Q然后?/span>MyEclipse?/span>get?/span>setҎ(gu)生成工具自动生成?/span>
在?/span>dwr执行插入和更新操作的时候,有时?x)抛样一个离q异常Q?/span>
java.lang.
之所以说q个异常比较谱Q是因ؓ(f)它似乎就没有dwr什么事。事实上它也是没?/span>dwr什么事Q而是hibernate出错?jin)。查?/span>hibernate的官方网站你可以发现q个bug的发布,q在hibernate3.2.0.rc4以后的版本这解决q个问题?jin)。将hibernate3换成最新版本后果然p册个问题了(jin)?/span>
q个q是hibernate3的问题。在执行查询的时候在控制台显C样一个错误:(x)
CharScanner; panic: ClassNotFoundException: org.hibernate.hql.ast.HqlToken
遇到q个问题不要怕,其实解决的方法很单,是?/span>spring的配|文?/span>ApplicationContext-hibernate.xml中,?/span>sessionFactory?/span>hibernateProperties属性中增加q样一D话Q?/span>
?/span>DWR2.0中提供了(jin)一?/span>JDK5中才能用的annotations的功能。然而,q个功能?/span>JDK1.4的环境中q行启动或者部|会(x)发生错误。抱歉的是这个错误信息我没有?qing)时记录Q日后补上。这个错误在|上可以L地搜索到解决Ҏ(gu)Q即?/span>dwr.jar中删除掉org.directwebremoting.annotations.AnnotationsConfiguratorq个cd重新部v可以了(jin)?/span>
同样的问题出现在hibernate3中,hibernate3?/span>annotations的支持在JDK1.4中也可能出现异常Q解决的办法是在部|文件中删除?/span>hibernate-annotations.jar可以了(jin)?/span>
另外值得说明的是Q以?/span>2个问题ƈ不是每次都会(x)出现的。它们就如同q灵一h时出现有时不出现Q因此我们ƈ不需要L删除q个cdjar包,只是在发生错误时才删除?/span>
要理?/span>dwr.xml的配|首先要理解DWR的基本功能?/span>DWR其功能的强大在于它可以用一U前所未有的便利方式将前端面中的js与后端服务器中的javaE序q行直接的{换。比如,它可以将javaE序中的某个XxxBus转换?/span>js中的一个对象,q将XxxBus中的某个Ҏ(gu)?/span>getXXX()转换?/span>js中的一个名?/span>XxxBus.getXXX()?/span>function。同Ӟ它可以将java中的值对象或其它数据包{换成js中的对象。理解这一炚w帔R要。配|文?/span>dwr.xml是让你告诉DWR哪些Bus你需要在面中调用,以及(qing)你需要调用这?/span>Bus中的哪些Ҏ(gu)Q哪些方法你不需要调用。一旦告诉了(jin)DWRq些信息Q你g可以在面中像?/span>javaE序一L(fng)直接调用BusQ而蟩q了(jin)MVC层(?/span>struts中的action?/span>actionformQ以?/span>MVC层的J琐配置与编E。ؓ(f)?jin)帮助你理解q一Ҏ(gu)举一个例子,已经清楚的朋友可以蟩q?/span>
假如我在目?/span>BUS层写?jin)一个类?/span>DepartmentBusq在q个cM定义?jin)一个方?/span>getDepartment(String id)Q那么我们先把这个类和它的方法配|到dwr.xml中(如何配置我后面再Ԍ(j)。当DWR启动的时候,它会(x)?/span>java中的DepartmentBus?qing)其?gu)getDepartment(String id)转换?/span>js中的DepartmentBus?qing)其?gu)getDepartment(String id)。更具体地说Q它?x)动态生一个叫DepartmentBus.js的文Ӟq个文g可以在测试状态下?#8220;目地址端口/dwr/test/DepartmentBus”中看刎ͼ(j)。在q个文g中,?x)创Z?/span>DepartmentBus的对象,一个叫DepartmentBus.fincDepartment(p0, callback)的函数。如果你在页面中引入?/span>DepartmentBus.js文gQ你可以在该页面的中调?/span>DepartmentBus.fincDepartment(p0, callback)Ҏ(gu)Q?/span>DWR可以通过Ajax的方式直接去调用服务器端?/span>DepartmentBus中的fincDepartment(String id)。同理,如果DepartmentBus中还有其它的函数Q如createDepartment(Department vo)?/span>updateDepartment(Department vo){,DWR也会(x)做如此的转换?/span>
前面我们提到Q?/span>DWR可以服务器?/span>java中的对象?qing)其?gu)转换成客L(fng)?/span>js中的对象?qing)其?gu)Q一个棘手的问题出C(jin)。在java中的许多Ҏ(gu)都是某个对象作为它参数或返回倹{这些对象往往都是一个个?/span>JOPOQ即它们有许多的属性,其中包含?jin)需要传递的数据Q最典型的就是值对象)(j)。当js在调?/span>java的某个方法时需要提供这个对象参敎ͼ同时在调用完成时需要将对象q回gjs可以接受的方式返回。怎样做到q一点呢Q最单的方式当然是让DWR再做一ơ{换,这?/span>java对象转换?/span>js的对象,或者将js的对象{换成java对象?/span>OkQ经q?/span>DWRq样的两ơ{换,我们可以在面与后台间自由地进行函数调用和数据交换?/span>
讲到q里Q我们现在重新回?/span>dwr.xml文g。前面我们提刎ͼ如果你需要在面中调用服务器端的某个cM的方法,你需要在dwr.xml中注册这个类?qing)其?gu)Q注册方法如下:(x)
Creator是创个对象所使用的构建器Q如果你希望使用传统?/span>newҎ(gu)写?/span>newQ如果你希望使用spring来创建则写成spring。当然也有其它的创徏Ҏ(gu)Q有哪些Ҏ(gu)呢?你可以打开dwr.jarQ在org.directwebremoting包中扑ֈ一?/span>dwr.xml的文件。在该文?/span>init下的create中可以看到?/span>
Javascript是用于你?/span>js中调用这个对象时使用什么名Uͼ强烈你用首字母大写Q这样在面中很Ҏ(gu)看出q是一个与后台对应的对象?/span>如果你用了(jin)springq且?/span>creator中选择?/span>springQ那么你需要一个叫beanName的参敎ͼ而其值就是在spring配置文g中配|的beanNameQ如departmentBus?/span>另外2个非常有用的参数?/span>exclude?/span>includeQ?/span>exclude可以止面调用后台的某个或某些Ҏ(gu)Q具体的写法是在create中加入:(x)method部分写的是这些方法不带括L(fng)Ҏ(gu)名,如果有多个就写多?/span>excludeQ?/span>include则规定页面只能调用某些方法?/span>
?/span>dwr.xml中注册了(jin)需要调用的对象?qing)其?gu)以后Q你应当注册其所有方法的参数和返回值所涉及(qing)的对象,注册Ҏ(gu)如下Q?/span>
match用于告诉DWR你将需要把java中的哪些c{换成js。你可以写成com.htxx.demo.model.*Q但我ƈ不推荐大家这样用。ؓ(f)什么呢Q如果你像前面那样一个一个地注册对象Q则可以在面使用q个的语句初始化一个对象:(x)
var dep = new Department();
如果你用后一U方法去扚w注册对象Q那么你׃能这样初始化q个对象而只能这h动注册:(x)
Var dep = {departmentId:null, departmentName:null, ……};
我推荐大安用第一U方法的好处可以在我后面写的?a title="怹链接QDWR帮助说明Q如何编写通用的单行编辑框" >DWR帮助说明Q如何编写通用的单行编辑框》充分展现出来。但采用q种Ҏ(gu)?/span>DWR的现有版本中gq有点儿BUGQ如何解册?/span>BUG我也在后面的?a title="怹链接QDWR帮助说明Qdwr的bug?qing)其解决?gu)" >DWR帮助说明Qdwr的bug?qing)其解决?gu)》中解答?/span>
Javascript用于说明你在面中用这个对象的名称Q也强烈大家使用首字母大写?/span>Converter用于告诉DWR用什?/span>DWR的类来执行{换,常用的{换器?/span>bean?/span>object?/span>hibernate2?/span>hibernate3{?/span>DWR有哪些{换器可以?/span>dwr.jar?/span>dwr.xmlQ该文g的位|见前文Q中扑ֈ。我需要强调的是,如果朋友们用了(jin)hibernateQ那么你需要将需要用的所有值对象都通过转换器注册。但是我在网上看见很多朋友都使用bean转换器来注册。如果你使用bean来{换值对象,在运行程序的时候会(x)出现很多问题Q这些问题我׃详述?jin)?j)Q同时还?x)出现效率的问题Q因?/span>DWR?x)将该值对象的所有属性,?qing)其q些属性的所有属性,所有属性的属性,都以ID的方式取出来。熟(zhn)?/span>hibernate的朋友应当马上明白这样将是数据库操作的一个灾难。如果你使用hibernate2?/span>hibernate3作ؓ(f)转换器将不会(x)发生q样的事Q同Ӟhibernate3q较好地解决?jin)gq查询的问题Q但DWR官方我们使用hibernate?/span>openSessionInViewFilterQ这我也不再详述Q不清楚的朋友可以查?/span>hibernate3的帮助文档。但另一个问题我不得不提Q?/span>DWR在用gq查询的时候其实还是有问题的。譬如有一个值对?/span>Employee包含一?/span>Department的属性,Ҏ(gu)延迟查询的规则,?/span>get某个EmployeeӞ属?/span>Department不会(x)马上装蝲Q即使执?/span>getDepartment()也不?x)装载。必d真正对这?/span>Department操作的时候才?x)装载。既然如此,问题来?jin),我们使?/span>DWR执行查询的时候,常常是真正到面才会(x)dDepartmentQ这时已l是q服务器端到页面端?jin)而不能再得到Department。这个问题怎么办呢Q最好的办法是在服务器端提前装载页面需要用的属性,因ؓ(f)作ؓ(f)开发者他肯定知道哪些属性要在客L(fng)使用Q哪些属性不需要。至于如何在服务器端提前装载,感兴的朋友在我的示例中看到?/span>另外一个需要提的是Q与creator一P转换器也可以一样地讄exclude?/span>include参数。但是与creator不同的是Q它们说?/span>DWR在{换对象的时候需要{换或不{换某些属性。这个参数对?/span>hibernate的一对一兌非常重要。在hibernate中一对一兌是不做gq查询的Q假如有一个值对?/span>Employee与值对?/span>Address是一对一兌Q那?/span>Employee中有Address的属性,?/span>Address中有Employee的属性。由于一对一兌不做延迟查询Q当DWR在{换一?/span>Employee是会(x)装蝲它的属?/span>AddressQ然后在装蝲Address的时候,又会(x)去装?/span>Address中的Employee属性。如此这P׃(x)形成一个死循环Q最后以堆栈溢出告终。解册个问题的办法是掉Address中的Employee属性,避免产生d@环。具体写法如下:(x)
Value部分是需要{换的属性,如果有多个则用逗号隔开可以了(jin)?/span>