1 $(); 2 功能:相当于document.getElementById(id); 3 参数: id或name属性值; 4 例: 5 <input type=”text” name=”txt_test”></input> 6 <script> 7 Var ele=$(txt_test); 8 Var str=DWRUtil.toDescriptiveString(ele,1) 9 DWRUtil.debug(str); 10 </script> 11 12 DWRUtil.getValue(); 13 功能:获得指定元素value值 14 参数: id或name属性值; 15 注意:该函数只能用于有value属性的元素 16 例: 17 <input type=”text” name=”txt_test”></input> 18 <script> 19 var val=DWRUtil.getValue(“txt_test”); 20 DWRUtil.debug(val); 21 </script> 22 23 DWRUtil.getValues(); 24 功能:获得一组指定元素的value值; 25 参数:id或name构成的数组对象 26 例: 27 <input type=”text” name=”txt_name” value=”wiley”></input> 28 <input type=”text” name=”txt_pswd” value=”wiley”></input> 29 <script> 30 Var arr_=DWRUtil.getValues({“txt_name”:null,”txt_pswd”:null}); 31 Var str=DWRUtil.toDescriptiveString(arr,1) 32 DWRUtil.debug(str); 33 </script> 34 35 DWRUtil.setValue(); 36 功能:设置指定元素的value值 37 参数: id或name属性值 38 <input type=”text” name=”txt_test” value=””></input> 39 <script> 40 DWRUtil.setValue(“txt_test”,”wiley”); 41 </script> 42 43 44 DWRUtil.setValues(); 45 功能:设置一组指定元素的值 46 参数: id或name构成的数组对象 47 例: 48 <input type=”text” name=”txt_name” value=””></input> 49 <input type=”text” name=”txt_pswd” value=””></input> 50 <script> 51 DWRUtil.setValues({“txt_name”:”wiley”,”txt_pswd”:”wiley”}); 52 </script> 53 54 DWRUtil.getText(); 55 功能:获得select元素的文本值 56 参数: id或name属性值 57 例: 58 <select name=”sel_test”> 59 <option value=” wiley-cn.com” selected>wiley中国</option> 60 </select> 61 <script> 62 Var txt=DWRUtil.getText (“sel_test”); 63 Var val=DWRUtil.getValue(“sel_test”); 64 DWRUtil.debug(“Text:”+txt+”\tValue:”+val); 65 </script> 66 67 DWRUtil.addRows(); 68 功能:指定表格添加行 69 格式:DWRUtil.addRows(id,items, functions); 70 参数: 71 第一个参数:table或tbody的id属性值 72 第二个参数:数组或链表(可能用词不是很适合) 73 第三个参数:函数链表 74 75 例1: 76 <table> 77 <tr> 78 <td>主题</td> 79 <tr> 80 <tbody id=”tby_test”> 81 </tbody> 82 </table> 83 <script> 84 Var arr_={“wiley’s blog”,”wiley中国”}; 85 DWRUtil.addRows(“tby_test”,arr_,[function(arr_){return arr_}]); 86 </script> 87 88 89 例2: 90 91 <table> 92 <tr> 93 <td>名称</td> 94 <td>网址</td> 95 <tr> 96 <tbody id=”tby_test”> 97 </tbody> 98 </table> 99 <script> 100 Var items=[{“name”:”wiley中国”,”add”:”wiley-cn.com”}]; 101 DWRUtil.addRows(“tby_test”,items,[function(item){return item.name}, function(item){return item.add}]); 102 </script> 103 104 DWRUtil.romoveAllRows(); 105 功能:删除指定表格行 106 参数:table或tbody的id属性值 107 例 108 <table> 109 <tr> 110 <td>名称</td> 111 <td>网址</td> 112 <tr> 113 <tbody id=”tby_test”> 114 </tbody> 115 </table> 116 <script> 117 DWRUtil.romoveAllRows(“tby_test”);//每次添加前将原有数据行删除,防止数据重叠 118 Var items=[{“name”:”wiley中国”,”add”:”wiley-cn.com”}]; 119 DWRUtil.addRows(“tby_test”,items,[function(item){return item.name}, function(item){return item.add}]); 120 </script> 121 122 DWRUtil.addOptions(); 123 功能:添加select元素的option子元素 124 格式:DWRUtil.addOption(id,items)或DWRUtil.addOption(id,items,valueProp,textProp); 125 参数: 126 第一个参数:select的id或name属性值 127 第二个参数:数组或链表(填充数据) 128 第三、四个参数:链表节点的属性,第三个填充value值,第四个填充text值 129 130 例: 131 <select name=”sel_test”> 132 </select> 133 <script> 134 Var arr_={“wiley”,”wiley中国”}; 135 DWRUtil.addRows(“sel_test”,arr_);//此时value与text值相同 136 DWRUtil.romoveAllOptions(“sel_test”); 137 Var items=[{“name”:”wiley中国”,”add”:”wiley-cn.com”}]; 138 DWRUtil.addRows(“sel_test”,”add”,”name”);//此时value与text不相同 139 </script> 140 141 DWRUtil.romoveAllOptions(); 142 功能:删除指定select元素的option子元素 143 参数:select元素的id或name属性值 144 例:前面例子有用到 145 146 DWRUtil.debug(); 147 功能:等价于alert() 148 例:前面例子有用到 149 150 DWRUtil.toDescriptiveString(); 151 功能:将对象序列化成字符串,主要用于调试 152 例:前面的例子有用到 153 154 第7章. util.js 功能 155 util.js包含了一些工具函数来帮助你用JavaScript数据(例如从服务器返回的数据)来更新你的web页面。 你可以在DWR以外使用它,因为它不依赖于DWR的其他部分。你可以下载整个DWR或者单独下载. 4个基本的操作页面的函数:getValue[s]()和setValue[s]()可以操作大部分HTML元素除了table,list和image。getText()可以操作select list。 要修改table可以用addRows()和removeAllRows()。要修改列表(select列表和ul,ol列表)可以用addOptions()和removeAllOptions()。 还有一些其他功能不是DWRUtil的一部分。但它们也很有用,它们可以用来解决一些小问题,但是它们不是对于所有任都通用的。 156 7.1 $() 157 $() 函数(它是合法的Javascript名字) 是从Protoype偷来的主意。 大略上的讲: $ = document.getElementById。 因为在Ajax程序中,你会需要写很多这样的语句,所以使用 $() 会更简洁。 通过指定的id来查找当前HTML文档中的元素,如果传递给它多个参数,它会返回找到的元素的数组。所有非String类型的参数会被原封不动的返回。这个函数的灵感来至于prototype库,但是它可以在更多的浏览器上运行。 可以看看DWRUtil.toDescriptiveString的演示。 从技术角度来讲他在IE5.0中是不能使用的,因为它使用了Array.push,尽管如此通常它只是用来同engine.js一起工作。如果你不想要engine.js并且在IE5.0中使用,那么你最好为Array.push找个替代品。 158 7.2 addOptions and removeAllOptions 159 DWR的一个常遇到的任务就是根据选项填充选择列表。下面的例子就是根据输入填充列表。 下面将介绍 DWRUtil.addOptions() 的几种是用方法。 如果你希望在你更新了select以后,它仍然保持运来的选择,你要像下面这样做: var sel = DWRUtil.getValue(id); DWRUtil.removeAllOptions(id); DWRUtil.addOptions(id, ...); DWRUtil.setValue(id, sel); 160 55 / 92 161 如果你想加入一个初始的"Please select..." 选项那么你可以直接加入下面的语句: DWRUtil.addOptions(id, /["Please select ..."]); 162 DWRUtil.addOptions有5种模式 163 数组: DWRUtil.addOptions(selectid, array) 会创建一堆option,每个option的文字和值都是数组元素中的值。 164 对象数组 (指定text): DWRUtil.addOptions(selectid, data, prop) 用每个数组元素创造一个option,option的值和文字都是在prop中指定的对象的属性。 165 对象数组 (指定text和value值): DWRUtil.addOptions(selectid, array, valueprop, textprop) 用每个数组元素创造一个option,option的值是对象的valueprop属性,option的文字是对象的textprop属性。 166 对象: DWRUtil.addOptions(selectid, map, reverse)用每个属性创建一个option。对象属性名用来作为option的值,对象属性值用来作为属性的文字,这听上去有些不对。但是事实上却是正确的方式。如果reverse参数被设置为true,那么对象属性值用来作为选项的值。 167 对象的Map: DWRUtil.addOptions(selectid, map, valueprop, textprop) 用map中的每一个对象创建一个option。用对象的valueprop属性做为option的value,用对象的textprop属性做为option的文字。 168 ol 或 ul 列表: DWRUtil.addOptions(ulid, array) 用数组中的元素创建一堆li元素,他们的innerHTML是数组元素中的值。这种模式可以用来创建ul和ol列表。 169 这是网上的例子 170 7.3 addRows and removeAllRows 171 DWR通过这两个函数来帮你操作table: DWRUtil.addRows() 和 DWRUtil.removeAllRows() 。这个函数的第一个参数都是table、tbody、thead、tfoot的id。一般来说最好使用tbody,因为这样可以保持你的header和footer行不变,并且可以防止Internet Explorer的bug。 172 DWRUtil.removeAllRows() 173 DWRUtil.removeAllRows(id); 174 描述: 通过id删除table中所有行。 参数: id: table元素的id(最好是tbody元素的id) 175 DWRUtil.addRows() 176 DWRUtil.addRows(id, array, cellfuncs, [options]); 177 描述: 向指定id的table元素添加行。它使用数组中的每一个元素在table中创建一行。然后用cellfuncs数组中的没有函数创建一个列。单元格是依次用cellfunc根据没有数组中的元素创建出来的。 DWR1.1开始,addRows()也可以用对象做为数据。如果你用一个对象代替一个数组来创建单元格,这个对象会被传递给cell函数。 参数: id: table元素的id(最好是tbody元素的id) array: 数组(DWR1.1以后可以是对象),做为更新表格数据。 cellfuncs: 函数数组,从传递过来的行数据中提取单元格数据。 options: 一个包含选项的对象(见下面) 选项包括: rowCreator: 一个用来创建行的函数(例如,你希望个tr加个css). 默认是返回一个document.createElement("tr") cellCreator: 一个用来创建单元格的函数(例如,用th代替td). 默认返回一个document.createElement("td") 178 这是网上的例子 179 7.4 getText 180 getText(id)和getValue(id)很相似。出了它是为select列表设计的。你可能需要取得显示的文字,而不是当前选项的值。 181 这是网上的例子 182 7.5 getValue 183 DWRUtil.getValue(id)是 setValue()对应的"读版本"。它可以从HTML元素中取出其中的值,而你不用管这个元素是select列表还是一个div。 这个函数能操作大多数HTML元素包括select(去处当前选项的值而不是文字)、input元素(包括textarea)、div和span。 184 这是网上的例子 185 7.6 getValues 186 getValues()和getValue()非常相似,除了输入的是包含name/value对的javascript对象。name是HTML元素的ID,value会被更改为这些ID对象元素的内容。这个函数不会返回对象,它只更改传递给它的值。 从DWR1.1开始getValues()可以传入一个HTML元素(一个DOM对象或者id字符串),然后从它生成一个reply对象。 187 这是网上的例子 188 7.7 onReturn 189 当按下return键时,得到通知。 当表单中有input元素,触发return键会导致表单被提交。当使用Ajax时,这往往不是你想要的。而通常你需要的触发一些Javscript。 不幸的是不同的浏览器处理这个事件的方式不一样。所以DWRUtil.onReturn修复了这个差异。如果你需要一个同表单元素中按回车相同的特性,你可以用这样代码实现: <input type="text" onkeypress="DWRUtil.onReturn(event,submitFunction)"/> <input type="button" onclick="submitFunction()"/> 190 你也可以使用onkeypress事件或者onkeydown事件,他们做同样的事情。 一般来说DWR不是一个Javascript类库,所以它应该试图满足这个需求。不管怎样,这是在使用Ajax过程中一个很有用函数。 这个函数的工作原理是onSubmit()事件只存在于<FORM ...>元素上 191 这是网上的例子 192 7.8 selectRange 193 选择一个输入框中的一定范围的文字。 你可能为了实现类似"Google suggest"类型的功能而需要选择输入框中的一定范围的文字,但是不同浏览器间选择的模型不一样。这DWRUtil函数可以帮你实现。 DWRUtil.selectRange(ele, start, end) 194 这是网上的例子 195 7.9 setValue 196 DWRUtil.setValue(id, value)根据第一个参数中指定的id找到相应元素,并根据第二个参数改变其中的值。 这个函数能操作大多数HTML元素包括select(去处当前选项的值而不是文字)、input元素(包括textarea)、div和span。 197 这是网上的例子 198 7.10 setValues 199 setValues()和setValue()非常相似,除了输入的是包含name/value对的javascript对象。name是HTML元素的ID,value是你想要设置给相应的元素的值。 200 这是网上的例子 201 7.11 toDescriptiveString 202 DWRUtil.toDescriptiveString()函数比默认的toString()更好。第一个参数是要调试的对象,第二个参数是可选的,用来指定内容深入的层次: 0: 单行调试 1: 多行调试,但不深入到子对象。 2: 多行调试,深入到第二层子对象 以此类推。一般调试到第二级是最佳的。 还有第三个参数,定义初始缩进。这个函数不应该被用于调式程序之外,因为以后可能会有变化。 203 这是网上的例子 204 7.12 useLoadingMessage 205 这个方法将来可能被废弃,因为这个实现实在太专断了。为什么是红色,为什么在右上角,等等。唯一的真正答案就是:抄袭GMail。这里的建议是以本页面中的代码为模板,根据你的需求自定义。 你必须在页面加载以后调用这个方法(例如,不要在onload()事件触发之前调用),因为它要创建一个隐藏的div来容纳消息。 206 最简单的做法时在onload事件中调用DWRUtil.useLoadingMessage,像这样: <head> <script> function init() { DWRUtil.useLoadingMessage(); } </script> ... </head> <body onload="init();"> ... 207 可能有些情况下你是不能容易的编辑header和body标签(如果你在使用CMS,这很正常),在这样的情况下你可以这样做: <script> function init() { DWRUtil.useLoadingMessage(); } if (window.addEventListener) { window.addEventListener("load", init, false); } else if (window.attachEvent) { window.attachEvent("onload", init); } else { window.onload = init; } </script> 208 下面这些是这个函数的代码,它对于你要实现自己的加载消息很有用。这个函数的主要内容是动态创建一个div(id是disabledZone)来容纳消息。重要的代码是当远程调用时使它显示和隐藏: DWREngine.setPreHook(function() { $('disabledZone').style.visibility = 'visible'; }); DWREngine.setPostHook(function() { $('disabledZone').style.visibility = 'hidden'; }); This is fairly simple and makes it quite easy to implement your own "loading" message. 209 function useLoadingImage(imageSrc) { var loadingImage; if (imageSrc) loadingImage = imageSrc; else loadingImage = "ajax-loader.gif"; DWREngine.setPreHook(function() { var disabledImageZone = $('disabledImageZone'); if (!disabledImageZone) { disabledImageZone = document.createElement('div'); disabledImageZone.setAttribute('id', 'disabledImageZone'); disabledImageZone.style.position = "absolute"; disabledImageZone.style.zIndex = "1000"; disabledImageZone.style.left = "0px"; disabledImageZone.style.top = "0px"; disabledImageZone.style.width = "100%"; disabledImageZone.style.height = "100%"; var imageZone = document.createElement('img'); imageZone.setAttribute('id','imageZone'); imageZone.setAttribute('src',imageSrc); imageZone.style.position = "absolute"; imageZone.style.top = "0px"; imageZone.style.right = "0px"; disabledImageZone.appendChild(imageZone); document.body.appendChild(disabledImageZone); } else { $('imageZone').src = imageSrc; disabledImageZone.style.visibility = 'visible'; } }); DWREngine.setPostHook(function() { $('disabledImageZone').style.visibility = 'hidden'; }); } 210 然后你就可以这样使用:useLoadingImage("images/loader.gif"); 211 7.13 Submission box 212 h1 非util.js中的功能 这里有一些功能不适合加入到DWRUtil中。它们在解决一下特殊问题是很有用,但是他们还不够通用以适用任何场合。 213 62 / 92 214 修补浏览器事件 如果你创建了一个DOM元素,然后用addAttribute在这个元素上创建了一个事件,那么他们不能被正常的触发。你可以使用下面的脚本来遍历一个DOM树,并重新为他们绑定事件,这样他们就能正常的触发了。 把'click'改成你希望的事件。 DWREngine._fixExplorerEvents = function(obj) { for (var i = 0; i < obj.childNodes.length; i++) { var childObj = obj.childNodes [i]; if (childObj.nodeValue == null) { var onclickHandler = childObj.getAttribute('onclick'); if (onclickHandler != null) { childObj.removeAttribute('onclick'); // If using prototype: // Event.observe(childObj, 'click', new Function(onclickHandler)); // Otherwise (but watch out for memory leaks): if (element.attachEvent) { element.attachEvent("onclick", onclickHandler); } else { element.addEventListener("click", onclickHandler, useCapture); } } DWREngine._fixExplorerEvents(childObj); } } 215 8.5 安全 216 我们很谨慎的对待DWR的安全问题,并且认为有必要解释一下避免错误要做的事情。 首先DWR让你明确哪些是被远程调用的,是如何被远程调用。原则就是DWR必须调用那些你明确允许的代码。 dwr.xml要求你为每一个远程类定义一个'create'项。你还可以通过指定include和exclude元素来更精确的控制远程调用Bean中可以被调用的方法。 除此之外如果你希望允许DWR在转换你的JavaBean到Javascript或者从Javascript转换到JavaBean时有一定的许可限制,同样可以精确控制哪些Bean的属性可以被转换。 一个很明显但又必须指出的 – 不要在生产环境中打开test/debug模式控制台。如何打开或关闭debug控制台在配置web.xml部分可以找到详细描述。 217 审查 - DWR带来的最大好处 218 很值得对比一下DWR和Servlet、JSP或周围的其他web框架。 如果你要审查基于DWR的功能,那是非常简单的。看看dwr.xml你就能得到一个哪些方法被暴露到外面的描述了。你也可以俯视全局用DWR可以访问哪些资源。 但是要在其他系统里做这件事可不是这么容易。如果是Servlet你需要检查WEB-INF/web.xml文件,然后检查写在Servlet中的request.getParameter(...)。如果是Struts和其他Framework你需要检查配置文件,然后顺着流程检查代码,看请求信息出了什么问题。 219 访问控制 220 DWR允许你通过两种基于J2EE的机制来进行访问控制。首先你可以基于J2EE角色定义DWR的访问。其次你可以在DWR里面定义访问方法的角色。 221 其他方面 222 DWR不允许你定义任何内部类的create和convert。这样设计是为了不出现意外的攻击来操作DWR的核心文件以提升访问权限。 223 风险 224 有什么机会可以让攻击者窥视你的系统呢?使用DWR你攻击者可以使服务器创建任何你在dwr.xml中指定的Java对象的实例。并且(如果你用BeanConverter)Java类的任何方法、以及方法任何参数都是可见的。这些类的任何一个属性都有可能是攻击者需要的。 如果你知道DWR是怎么工作的,这些都是很显而易见的结论,但是往往粗心会造成问题。如果你创建了一个有appendStringToFile()方法的FileBean的类,而且用DWR把它暴露出去,那么你就给了攻击者一个机会来填满你的文件系统。 225 69 / 92 226 你必须时刻注意用了DWR以后,有没有给攻击者什么机会。 一般来说这样的情景让人感觉使用DWR是有风险的,但是这样的问题在所有的传统web架构中都存在,只是在那些架构中这些不明显,所以就很难被修复。 227 保证更加安全 228 这已经很安全了,那么你还能做什么来保证更加安全了?首先记住上面这些关于审查的内容,当web应用的其他地方不安全时,即使它看上去很安全,过多的关注DWR是很愚蠢的。如果DWR让人感觉恐惧,那是因为它的问题都在明处。所以第一步是多检查几遍传统架构的问题。 你可以通过把可远程访问的类放到不同的包里,并且使用代理来防止DWR访问机制出问题。如果你愿意还可以再次检查基于角色的安全控制。这些内容只是在检查DWR已经为你做的事情。 比多检查几次更好的方法是检查DWR的源码,保证它是在正确的工作。这些代码已经被很多人检查过了,但多双眼睛总是有好处的。 229 整合Acegi 230 DWR可以整合Acegi security framework。更多的信息见整合DWR和Acegi.