﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-Kaixinhutu</title><link>http://www.blogjava.net/Kaixinhutu/</link><description>糊涂</description><language>zh-cn</language><lastBuildDate>Wed, 15 Apr 2026 23:21:49 GMT</lastBuildDate><pubDate>Wed, 15 Apr 2026 23:21:49 GMT</pubDate><ttl>60</ttl><item><title>AJAX+J2EE开发组织机构管理系统（摘自天极网）</title><link>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42079.html</link><dc:creator>糊涂</dc:creator><author>糊涂</author><pubDate>Thu, 20 Apr 2006 01:21:00 GMT</pubDate><guid>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42079.html</guid><wfw:comment>http://www.blogjava.net/Kaixinhutu/comments/42079.html</wfw:comment><comments>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42079.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Kaixinhutu/comments/commentRss/42079.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Kaixinhutu/services/trackbacks/42079.html</trackback:ping><description><![CDATA[
		<p>
				<strong>一、 概述<br /><br /></strong>AJAX是今年初才问世的新技术，是Asynchronous JavaScript and XML的缩写。它是一组开发Web应用程序的技术，它使浏览器可以为用户提供更为自然的浏览体验。每当需要更新时，客户端Web页面的修改是异步的和逐步增加的。这样，AJAX在提交Web页面内容时大大提高了用户界面的速度。在基于AJAX的应用程序中没有必要长时间等待整个页面的刷新。页面中需要更新的那部分才进行更改，如果可能的话，更新是在本地完成的，并且是异步的。<br /><br />J2ee是一种用来开发分布式系统的体系结构。它主要是用Java类开发业务实体。通过JSP来连接应用服务器。<br /><br />本文开发一个组织机构管理小系统，通过这个实例来介绍如何用Ajax开发WEB应用程序。本系统具有增加、修改、删除组织机构的功能。同时给机构分配人员，能增加、修改、删除人员。<br /><br /><b>二、 界面设计</b><br /><br />树结构是大多软件系统中常采用的结构形式。由于树型结构层次分明、上下级关系清楚、且展开收缩表达信息方便、界面也较美观，所以是大家热衷于用此结构。组织机构管理是一般软件基本具有的。组织机构是指公司的组织结构。集团公司可包括分公子公司，公司下面又有科室。员工归属于所在的公司。系统运行后的界面如下：<br /><br /></p>
		<p align="center">
				<img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" src="http://java.ccidnet.com/col/attachment/2006/4/663251.jpg" />
		</p>orgManager.htm是组织机构管理的主页面。WEB应用程序界面设计是非常重要的。如何布局、么样组织可直接体现一个人的设计水平。<br /><br />组织机构主要包括树结构、组织机构编辑、人员编辑等三大块，如何分成三块呢，然而一般树型结构的窗体常先二块，树型结构独占一块，另一块又分成上下二部分，上面是机构编码，下面是人员编码。固可以把页面划分成如下图形式：<br /><br /><table cellspacing="0" cellpadding="0" width="51%" align="center" border="1"><tbody><tr><td width="25%" rowspan="2"><div align="center">树结构区1 </div></td><td width="75%"><div align="center">组织编码区2</div></td></tr><tr><td width="75%"><div align="center">人员管理区3 </div></td></tr></tbody></table><br /><br />显然我们是通过表来实现。这是一个二行二列的表，且第一、二行的左边列合并单元格。代码如下：<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜ TABLE border="1" width="100%" height="100%"＞<br /><br />＜TR＞<br /><br />＜TD rowspan="2"＞＜FONT face="宋体"＞＜/FONT＞＜/TD＞<br /><br />＜TD＞＜/TD＞<br /><br />＜/TR＞<br /><br />＜TR＞<br /><br />＜TD＞＜/TD＞<br /><br />＜/TR＞<br /><br />＜/TABLE＞</td></tr></tbody></table><br /><br />我们在1区（单元格）上加上一个DIV，因为DIV可以动态地滚动，并且可以插入其它控件。DIV的id为"divTree"，且风格设置为溢出时自动滚动，宽与高都为100%，及满区域。代码如下：<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜div id="divTree" style="width:100%; height:100%;background-color:#f5f5f5;border :1px solid Silver;overflow:auto;"＞<br /><br />＜/div＞</td></tr></tbody></table><br /><br />我们在2区（单元格）上也加上一个DIV，在DIV里再插入一个表格。表格上放下控件，这很简单，就不详细说了。<br /><br />我们在3区（单元格）上加上一个DIV。此DIV的id为" divContent "，且风格设置为竖直溢出时自动滚动，宽与高都为100%，及满区域，此DIV用来装载人员信息;在DIV里再插入一个表格, 此table的id为" tbList "，是用来输入、显示人员作息，同时在此表中插入一些如checkbox 、text、select等控件。说明，表的第二列是用来放人员唯一编号的，不显示。代码如下：<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜div id="divContent" style="height:100%; overflow-y:auto;" width="100%"＞<br /><br />＜table id="tbList" border="1" width="100%"＞<br /><br />＜tr seqNo="1"＞＜td＞<br /><br />＜table border="1" width="100%"＞<br /><br />＜tr＞<br /><br />＜td width="5%"＞＜input type="checkbox" value="on"＞＜/input＞ ＜/td＞<br /><br />＜td width="0%" style="display:none"＞ ＜input type="text" size="20"＞＜/input＞＜/td＞<br /><br />＜td width="40%"＞＜input type="text" size="20"＞＜/input＞＜/td＞<br /><br />＜td width="25%"＞<br /><br />＜select size="1" name="D1"＞<br /><br />＜option value="0"＞男＜/option＞<br /><br />＜option selected="true" value="1"＞女＜/option＞<br /><br />＜/select＞<br /><br />＜/td＞<br /><br />＜/tr＞<br /><br />＜/table＞ <br /><br />＜/td＞＜/tr＞<br /><br />＜/table＞<br /><br />＜/div＞ </td></tr></tbody></table><p><strong>三、 前端页面的主要编码<br /><br /></strong>1. 树的实现<br /><br />在WEB上实现树结构，同样我们是通过Ajax来实现的。树上可以显示自定义的图标，可以插入、删除、结点。并且结点可任意移动。这里我们不重点讲树的实现技术，我们已经封装好了，你只要按要求去改动就是了。 <br /><br />1) 键接树型文件<br /><br />在＜head＞与＜/head＞之间键接我们的与树有关的文件, 代码如下：<br /><br /></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜link rel="STYLESHEET" type="text/css" href="css/dhtmlXTree.css"＞<br /><br />＜script src="js/dhtmlXCommon.js"＞＜/script＞<br /><br />＜script src="js/dhtmlXTree.js"＞＜/script＞ </td></tr></tbody></table><br /><br />2) 装载方法<br /><br />在页面的文档打开时装载自定义方法, preLoadImages方法实现树控件的图标定义，doOnLoad实现树控件的图标定义代码如下：<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜body onload="preLoadImages();doOnLoad();"＞</td></tr></tbody></table><br /><br />3) 编写方法<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>//doOnLoad实现装载并显示树。设置树属性等。<br /><br />function doOnLoad(){<br /><br />　OrgTree=new dhtmlXTreeObject(document.getElementById('divTree'),"100%","100%",0); <br /><br />　//dhtmlXTreeObject是树对象，通过新建对象，指定树显示的DIV可定义树。<br /><br />　OrgTree.setImagePath("imgs/");//设置树的图片所在位置<br /><br />　OrgTree.setDragHandler();//设置树结点拖动<br /><br />　OrgTree.enableDragAndDrop(true) //设置树结点是否可拖动<br /><br />　OrgTree.setDragHandler(myDragHandler); //设置树结点拖动时所执行的方法<br /><br />　OrgTree.setOnClickHandler(mySelectHandler); //设置树单击时所执行的方法<br /><br />　//OrgTree.setXMLAutoLoading("Org.jsp");//装载树结点数据。数据来源如Org.jsp所返回的XML格式的字符串，数据是动态装载，且当展开时才装载。<br /><br />　OrgTree.loadXML("root.xml?0");//装载树结点数据。数据来源root.xml文件，并且从xml文件的ID号为0处读取数据。<br /><br />　//OrgTree.loadXML("Org.jsp");//装载树结点数据。数据来源如Org.jsp所返回的XML格式的字符串,并且是一次性全部装载数据。 <br /><br />}<br /><br />//preLoadImages方法实现树控件的图标定义<br /><br />function preLoadImages(){<br /><br />　var imSrcAr = new Array("line1.gif","line2.gif","line3.gif","line4.gif","minus2.gif","minus3.gif",<br /><br />"minus4.gif","plus2.gif","plus3.gif","plus4.gif","book.gif","books_open.gif","books_close.gif",<br /><br />"magazine_open.gif","magazine_close.gif","tombs.gif","tombs_mag.gif","book_titel.gif")<br /><br />　var imAr = new Array(0);<br /><br />　for(var i=0;i＜imSrcAr.length;i++){<br /><br />imAr[imAr.length] = new Image();<br /><br />imAr[imAr.length-1].src = "imgs/"+imSrcAr[i]<br /><br />　}<br /><br />}</td></tr></tbody></table><p><br /> 组织管理的实现<br /><br />组织可以增加、删除、编辑。同时当选择树结点时应该把组织显示出来供编辑，查看。为了实现这些功能，你只要按要求去改动就是了。<br /><br />1) 全局变量的定义<br /><br />许多地方我们要用到一些公共变量，我们在＜script＞与＜/script＞之间定义全局变量, 代码如下：<br /><br /></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>var OrgTree = null; //组织树Dom<br /><br />var nextSeq = 0;//人员管理的顺序号（流水号）<br /><br />var personDom;//人员Dom<br /><br />var CurrNodeId;//当前结点Id </td></tr></tbody></table><p><br /><br />2) 初始化<br /><br />当页面打开时我们要控件好那部分该显示，那部分要隐藏。且对全局变量的赋值等,组织类型装载。在页面的文档打开时装载自定义方法init（）, init方法实现初始化。<br /><br /></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜body onload="init();"＞</td></tr></tbody></table><p><br /><br />init方法实现如下：<br /><br /></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>function init(){ <br /><br />　//定义personDom为一个XMLDOM'对象<br /><br />　personDom= new ActiveXObject('Microsoft.XMLDOM');<br /><br />　personDom.async = false; <br /><br />　//定义stylesheet为一个XMLDOM'对象，且stylesheet为personDom确定显示风格 <br /><br />　stylesheet = new ActiveXObject('Microsoft.XMLDOM');<br /><br />　stylesheet.async = false;<br /><br />　stylesheet.load("addOrgPerson.xsl"); //装载stylesheet的风格定义文件<br /><br />　//装载组织类型数据<br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=GetOrgType", false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send(); <br /><br />　retXml=xmlhttp.responseText;<br /><br />　// alert(retXml); <br /><br />　//把组织类型插入下拉列表控件中 <br /><br />　var OrgDoc = new ActiveXObject('Microsoft.XMLDOM');<br /><br />　OrgDoc.async = false;<br /><br />　OrgDoc.loadXML(retXml);<br /><br />　var root = OrgDoc.documentElement;<br /><br />　oNodeList = root.childNodes;<br /><br />　txtType.options.length =oNodeList.length;<br /><br />　for (var i=0; i＜oNodeList.length; i++) <br /><br />　{ <br /><br />Item = oNodeList.item(i); <br /><br />var OrgTypeId=Item.childNodes(0).text;<br /><br />var OrgTypeName=Item.childNodes(1).text;<br /><br />txtType.options[i].value=OrgTypeId;<br /><br />txtType.options[i].text=OrgTypeName;<br /><br />// txtType.options[0]. <br /><br />　}<br /><br />}</td></tr></tbody></table><p><br /><br />3) 编写树拖动及选择结点的方法<br /><br /></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>// myDragHandler实现树结点拖动时重新指定父子关系。<br /><br />function myDragHandler(idFrom,idTo){<br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=moveOrg&amp;orgId=" + idFrom + "&amp;newparentOrgId=" + idTo, false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send();<br /><br />　retXml=xmlhttp.OrgponseText;<br /><br />　return true;<br /><br />}<br /><br />// mySelectHandler实现选择树结点对系统的控制，同时显示组织信息及该组织下的人员。<br /><br />function mySelectHandler(id){ <br /><br />　tbOrg.style.display="block";<br /><br />　divOrgMemo.style.display="none";<br /><br />　divOrgInfo.style.display="none"; <br /><br />　if(id==1)<br /><br />　{<br /><br />divOrgMemo.style.display="block";<br /><br />div1.style.display="none";<br /><br />div2.style.display="none";<br /><br />div3.style.display="none";<br /><br />divContent.style.display="none";<br /><br />div5.style.display="none";<br /><br />　} <br /><br />　else<br /><br />　{<br /><br />divOrgInfo.style.display="block"; <br /><br />div1.style.display="block";<br /><br />div2.style.display="block";<br /><br />div3.style.display="block";<br /><br />divContent.style.display="block";<br /><br />div5.style.display="block";<br /><br />　} <br /><br />　CurrNodeId=id;<br /><br />　//装载组织信息并显示在编码和名称的文本控件上。 <br /><br />　loadOrg(id);<br /><br />　//装载某组织下人员信息 <br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=GetPerson&amp;orgId=" + id, false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send();<br /><br />　retXml=xmlhttp.responseText; <br /><br />　personDom.loadXML (retXml);<br /><br />　//给人员信息的每行加上序号 <br /><br />　for(var i=0; i＜personDom.documentElement.childNodes.length; i++){<br /><br />personDom.documentElement.childNodes[i].setAttribute("seqNo", nextSeq);<br /><br />nextSeq++;<br /><br />　} <br /><br />　//人员信息显示在divContent上面<br /><br />　divContent.innerHTML = personDom.transformNode(stylesheet); <br /><br />};<br /><br />//装载组织信息并显示在编码和名称的文本控件上。<br /><br />function loadOrg(OrgId){ <br /><br />　if(OrgId == null){<br /><br />OrgId = OrgTree.getSelectedItemId();<br /><br />　}<br /><br />　if(OrgId == ""){<br /><br />tbOrg.style.display = "none";<br /><br />return;<br /><br />　}<br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=loadOrg&amp;OrgId=" + OrgId, false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send();<br /><br />　retXml=xmlhttp.responseText;<br /><br />　var OrgDoc = new ActiveXObject('Microsoft.XMLDOM');<br /><br />　OrgDoc.async = false;<br /><br />　OrgDoc.loadXML(retXml);<br /><br />　if(OrgId != 1){<br /><br />txtCode.value = OrgDoc.selectSingleNode("//OrgCode").text;<br /><br />txtName.value = OrgDoc.selectSingleNode("//OrgName").text;<br /><br />　}<br /><br />　tbOrg.style.display = "block"; <br /><br />}</td></tr></tbody></table><p><br /><br />4) 建立组织<br /><br />组织建立主要是通过调用XMLHTTP对象来实现。我们主要学会如何调用XMLHTTP。组织建立应该在后台实现，把组织信息插入数据库中。这里我们通过JSP来实现。我们的Org.jsp 文件中有个createOrg方法，该方法传递一个父ID。<br /><br /></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>function createOrg(parentOrgId){<br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=createOrg&amp;parentOrgId=" + parentOrgId, false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send();<br /><br />　retXml=xmlhttp.responseText;<br /><br />　var orgId = (new Number(retXml)).toString();<br /><br />　return orgId;<br /><br />}</td></tr></tbody></table><p><br /></p><p><span class="top11">5) 删除组织<br /><br />组织删除同样是调用Org.jsp 文件中的deleteOrg方法来实现，该方法传递所删除的结点ID。<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>function deleteOrg(){<br /><br />　var OrgId = OrgTree.getSelectedItemId();<br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=deleteOrg&amp;OrgId=" + OrgId, false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send(); <br /><br />}</td></tr></tbody></table><br /><br />6) 编辑组织<br /><br />组织修改是调用Org.jsp 文件中的modifyOrg方法来实现，该方法传递所修改的结点ID。同时修改的数据通过自定义的XML格式的字符串传送,这时通过send字符串来实现。修改前数据一律要验证其合法性，并提示错误信息。<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>function modifyOrg(){<br /><br />　if(OrgTree.getSelectedItemId() == ""){<br /><br />return "N";<br /><br />　}<br /><br />　if(txtCode.value == ""){<br /><br />alert("请输入编码！");<br /><br />return "N";<br /><br />　}<br /><br />　if(txtName.value == ""){<br /><br />alert("请输入名称！");<br /><br />return"N";<br /><br />　} <br /><br />　var OrgId = OrgTree.getSelectedItemId();<br /><br />　var OrgKind; <br /><br />　//alert(txtType.options[txtType.selectedIndex].value)<br /><br />　var strModify = "＜?xml version='1.0' encoding='gb2312'?＞" +<br /><br />　"＜data＞" + <br /><br />　"＜OrgCode＞＜![CDATA[" + txtCode.value + "]]＞＜/OrgCode＞" +<br /><br />　"＜OrgName＞＜![CDATA[" + txtName.value + "]]＞＜/OrgName＞" +<br /><br />　"＜OrgKind＞＜![CDATA[" + txtType.options[txtType.selectedIndex].value+ "]]＞＜/OrgKind＞" +<br /><br />　"＜/data＞";<br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=modifyOrg&amp;OrgId=" + OrgId, false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send(strModify);<br /><br />　OrgTree.setItemText(OrgTree.getSelectedItemId(),txtName.value);<br /><br />}</td></tr></tbody></table>3. 人员管理的实现<br /><br />人员可以增加、删除、编辑。同时当选择树结点时应该把人员显示出来供编辑、查看......<br /><br />1) 增加人员<br /><br />人员增加实现的原理是在personDom中加入结点peorsone，该结点相当于表的一行，设置属性。同时在peorsone中不继地加入其它结点，代表数据库的字段，且必须与XLT文件的标号同名。这些结点相当该行的列。最后在表中插入一行，行上插入一列，并显示之。<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>function addPerson(){ <br /><br />　var seqNo = nextSeq;<br /><br />　nextSeq++; <br /><br />　var peorsonNode = personDom.createNode("1", "peorsone","");<br /><br />　peorsonNode.setAttribute("isNew", "Y");<br /><br />　peorsonNode.setAttribute("isDelete", "N");<br /><br />　peorsonNode.setAttribute("seqNo", seqNo);<br /><br />　personDom.documentElement.appendChild(peorsonNode);<br /><br />　var PersonId= personDom.createNode("1", "personId", "");<br /><br />　peorsonNode.appendChild(PersonId);<br /><br />　var personCode= personDom.createNode("1", "personCode", "");<br /><br />　peorsonNode.appendChild(personCode);<br /><br />　var PersonName= personDom.createNode("1", "personName", "");<br /><br />　peorsonNode.appendChild(PersonName);<br /><br />　var Sex= personDom.createNode("1", "sex", "");<br /><br />　peorsonNode.appendChild(Sex); <br /><br />　var tr = tbList.insertRow(tbList.rows.length);<br /><br />　tr.setAttribute("seqNo", seqNo);<br /><br />　var td = tr.insertCell(0);<br /><br />　td.innerHTML = peorsonNode.transformNode(stylesheet); <br /><br />}</td></tr></tbody></table><br /><br />2) 删除人员<br /><br />人员删除同样是调用Org.jsp 文件中的deletePerson方法来实现，该方法传递所删除的人员ID。如何确定人员ID是通过读取隐藏的ID，并扫描整个表，看那些被选中。这里我们要注意是提供多项选择的。<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>function deletePerson(){ <br /><br />　for(var i=0; i＜tbList.rows.length; i++){<br /><br />var row=tbList.rows[i].cells[0].children[0].rows[0];<br /><br />if(row.cells[0].children[0].checked)<br /><br />{<br /><br />　var personId=row.cells[1].children[0].value; <br /><br />　if(personId＞0)<br /><br />　{ <br /><br />var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />xmlhttp.open("POST","Org.jsp?mode=deletePerson&amp;personId=" + personId, false);<br /><br />xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />xmlhttp.send(); <br /><br />　}<br /><br />　tbList.deleteRow(i);<br /><br />　i--;<br /><br />}<br /><br />　} <br /><br />}</td></tr></tbody></table><br /><br />3) 编辑人员<br /><br />人员修改我们要判定哪些行被修改了。刚增加但没保存的行应该是新增而不是修改的。<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>function save(){ <br /><br />　if( modifyOrg()=="N")<br /><br />　{<br /><br />return;<br /><br />　}<br /><br />　for(var i=0; i＜tbList.rows.length; i++)<br /><br />　{ <br /><br />var row=tbList.rows[i].cells[0].children[0].rows[0];<br /><br />var personId=row.cells[1].children[0].value;<br /><br />var seqNo = tbList.rows[i].getAttribute("seqNo");<br /><br />var staffNode = personDom.selectSingleNode("//peorsone[@seqNo='" + seqNo + "']");<br /><br />var personCode=row.cells[2].children[0].value; <br /><br />var personName=row.cells[3].children[0].value; <br /><br />var sex=row.cells[4].children[0].value; //alert(staffN;ode ); <br /><br />if(staffNode.getAttribute("isNew") == "Y")<br /><br />{ <br /><br />　createPerson(CurrNodeId,personCode,personName,sex); <br /><br />}<br /><br />else<br /><br />{ <br /><br />　var strXML = "＜?xml version='1.0' encoding='gb2312'?＞" +<br /><br />"＜data＞" + <br /><br />"＜personCode＞＜![CDATA[" + personCode+ "]]＞＜/personCode＞" +<br /><br />"＜personName＞＜![CDATA[" + personName + "]]＞＜/personName＞" +<br /><br />"＜sex＞＜![CDATA[" + sex+ "]]＞＜/sex＞" +<br /><br />"＜personId＞＜![CDATA[" + personId+ "]]＞＜/personId＞" +<br /><br />"＜/data＞"; <br /><br />　//alert(strXML ); <br /><br />　var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");<br /><br />　xmlhttp.open("POST","Org.jsp?mode=modifyPerson", false);<br /><br />　xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");<br /><br />　xmlhttp.send(strXML );<br /><br />}<br /><br />　} <br /><br />}</td></tr></tbody></table></span></p><p><br /></p><p><span class="top11"><strong>四、 XML与XSL文件设计<br /><br /></strong>XML是种可扩展的标记语言，它具有开放的、可扩展的、可自描述的语言结构，它已经成为网上数据和文档传输的标准。XSLT的目的是将信息内容与 Web 显示分离，HTML 通过按抽象概念（如段落、重点和编号列表）定义显示来实现设备独立性。XSLT用来具体显示控件，设置控件风格。<br /><br />Ajax主要使用XML和XSLT进行数据交换与处理。<br /><br />1. 树信息的XML文件(见root.xml文件) <br /><br />XML是标记语言，元素必须成对出现。树结构中以tree为根结点，以item为结点体，属性text指出结点所显示的文本，id指出唯一的所标识号。<br /><br /></span></p><p></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜?xml version='1.0' encoding='gb2312'?＞<br /><br />＜tree id="0"＞<br /><br />＜item child="1" text="组织" id="1" ＞<br /><br />＜/item＞ <br /><br />＜/tree＞</td></tr></tbody></table><br /><br />这文件并不是必要的，只是为了系统能独立运行才加的。事实如果连接了后台数据是不需要的。只要吧OrgTree.loadXML("root.xml?0")改为OrgTree.loadXML("Org.jsp")就可以了。<br /><br />2. 人员信息XML文件(见peorson.xml文件)<br /><br />说明![CDATA[]]可在任何显示任何格式的文本，文本中可插入其它任何字符。这文件也不是必要的。<br /><br />3. 人员信息展现的xsl文件（见addOrgPerson.xsl文件）<br /><br />xsl文件同样是XML格式文件。所以一律遵守XML标准。下面对主要的行讲解：<br /><br /><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜?xml version="1.0" encoding="gb2312"?＞<br /><br />//这是定义xml文件的首行。用来指明版本及字符集<br /><br />＜xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl" language="JavaScript"＞<br /><br />//这里定义了stylesheet 元素。并指出其国际命名的组织及语言。 <br /><br />＜xsl:template match="/"＞<br /><br />＜xsl:apply-templates select="peorsones"/＞<br /><br />＜/xsl:template＞<br /><br />//上面是匹配的规则。"/"表示从根结开始去匹配。匹配到下面的peorsones标记。这是正则表达式有关的学问。我们只要理解就可以。<br /><br />＜xsl:template match="peorsones"＞<br /><br />//当匹配上peorsones时所要做的事情。<br /><br />＜table id="tbList" border="1" width="100%"＞<br /><br />//定义一个id为"tbList的表格。此表格是显示在WEB上的<br /><br />＜xsl:for-each select="peorsone"＞<br /><br />//循环匹配peorsone<br /><br />＜tr＞<br /><br />//定义tbList表格的一行，并在行上增加一个叫seqNo的属性名，值为匹配到的seqNo（序号）<br /><br />＜xsl:attribute name="seqNo"＞＜xsl:value-of select="@seqNo"/＞＜/xsl:attribute＞<br /><br />＜td＞<br /><br />//定义行上的一列，列又去匹配<br /><br />＜xsl:apply-templates select="."/＞<br /><br />＜/td＞<br /><br />＜/tr＞<br /><br />＜/xsl:for-each＞ <br /><br />＜/table＞<br /><br />＜/xsl:template＞<br /><br />＜xsl:template match="peorsone"＞<br /><br />＜table border="1" width="100%"＞<br /><br />＜tr＞<br /><br />//定义宽为5%的一列，在该列上插入一个checkbox控件<br /><br />＜td width="5%"＞<br /><br />＜input type="checkbox" value="on" size="10"＞＜/input＞<br /><br />＜/td＞<br /><br />//定义一个不显示的列，在该列上插入一个text控件，text的值为匹配到的personId（人员Id）<br /><br />＜td style="display:none"＞<br /><br />＜input type="text" size="25"＞<br /><br />＜xsl:attribute name="value"＞＜xsl:value-of select="personId"/＞＜/xsl:attribute＞<br /><br />＜/input＞ <br /><br />＜/td＞<br /><br />＜td width="30%"＞ <br /><br />＜input type="text" size="20"＞ <br /><br />＜xsl:attribute name="value"＞＜xsl:value-of select="personCode"/＞＜/xsl:attribute＞ <br /><br />＜/input＞ <br /><br />＜/td＞ <br /><br />＜td width="40%"＞ <br /><br />＜input type="text" size="40"＞<br /><br />＜xsl:attributename="value"＞＜xsl:value-of select="personName"/＞＜/xsl:attribute＞ <br /><br />＜/input＞<br /><br />＜/td＞<br /><br />//定义一个width为28%的列，在该列上插入一个下拉列表select 控件，select的值如果匹配到为0时则为"男"，1时则为"女"<br /><br />＜td width="28%"＞<br /><br />＜select size="1"＞<br /><br />＜option value="0"＞<br /><br />＜xsl:if test=".[sex=0]"＞<br /><br />＜xsl:attribute name="selected"＞true＜/xsl:attribute＞<br /><br />＜/xsl:if＞<br /><br />男<br /><br />＜/option＞<br /><br />＜option value="1"＞<br /><br />＜xsl:if test=".[sex=1]"＞<br /><br />＜xsl:attribute name="selected"＞true＜/xsl:attribute＞<br /><br />＜/xsl:if＞ <br /><br />女＜/option＞<br /><br />＜/select＞<br /><br />＜/td＞<br /><br />//定义一列，在该列上插入一个button控件，onclick 事件为自定义的方法，该方法传递当前单击的按纽<br /><br />＜td width="*"＞ <br /><br />＜button onclick="openPersonRolePage(this)" style="width: 36; height: 21"＞角色＜/button＞<br /><br />＜/td＞<br /><br />＜/tr＞<br /><br />＜/table＞<br /><br />＜/xsl:template＞<br /><br />＜/xsl:stylesheet＞</td></tr></tbody></table><p><br /></p><p><span class="top11"><strong>五、 数据接口的实现</strong>（见Org.jpg文件）<br /><br />Org.JSP文件用来在服务器上运行Java的类与前台web页之间架起一座桥。取到中间件的接口作用。<br /><br />这里分析部分代码：<br /><br /></span></p><p></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>＜%@ page contentType="text/html; charset=GBK" %＞<br /><br />＜%@ page import="java.sql.*" %＞<br /><br />＜%@ page import="javax.naming.*" %＞<br /><br />＜%@ page import="javax.sql.*" %＞<br /><br />＜%@ page import="tool.*" %＞<br /><br />＜%@ page import="orgNew.*" %＞<br /><br />＜%@ page import="org.w3c.dom.*" %＞<br /><br />//上面主要是引用一些java类<br /><br />＜%<br /><br />try{<br /><br />　//request.setCharacterEncoding("GBK");<br /><br />　Document doc = XmlTool.createDocumentFromRequest(request);<br /><br />　//建立web面文档请求的文档对象<br /><br />　Connection conn = ConnTool.getConnectionFromPool();<br /><br />　//获取请求的方法名<br /><br />　String mode=request.getParameter("mode");<br /><br />　//out.println("ccc");<br /><br />　//如果方法中没有其它参数则读取组织树数据<br /><br />　if(mode == null){ <br /><br />/* int OrgId = Integer.parseInt(request.getParameter("id"));<br /><br />String str = orgManager.getChildOrg(OrgId, conn);<br /><br />out.println(str); <br /><br />*/<br /><br />　String str = orgManager.getTree(conn);<br /><br />　//out.println(str);<br /><br />　out.println(str); <br /><br />}else if(mode.equals("createOrg")){<br /><br />　//如果是createOrg方法则建立一个组织<br /><br />　int parentOrgId = Integer.parseInt(request.getParameter("parentOrgId"));<br /><br />　//取出传递来的第一个参数parentOrgId<br /><br />　int OrgId = orgManager.createOrg(parentOrgId, conn);<br /><br />　//调用orgManager 类的createOrg方法来建立一个组织<br /><br />　out.println(OrgId);<br /><br />　//返回结果<br /><br />} <br /><br />conn.close();<br /><br />} <br /><br />catch(Exception e){<br /><br />　e.printStackTrace();<br /><br />}<br /><br />%＞</td></tr></tbody></table><p><br /><br /><b>六、 后台数据的实现</b><br /><br />1. 数据结构的定义<br /><br />这里，我们主要有三个表。一个是组织结构表，一个是人员表person，一个组织人员关联表orgPerson。组织结构表有OrgCode（组织代码）、OrgName（组织名称）、orgId（组织Id）, parentOrgId（父Id）。人员表有personCode（人员代码）、personName（人员名称）, sex（性别）、personId（人员Id）。orgPerson表有orgId, personId。<br /><br />2. 数据库的连接<br /><br />WEB应用程序常用MySQL作后台数据库，这是因为MySQL简单、高效。这里我们也用MySQL作为数据库。Java中用jdbc连接数据库。下面是连接数据库的CODE：<br /><br /></p><p></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>public static Connection getConnectionFromPool() throws Exception {<br /><br />　Context ctx = new InitialContext();<br /><br />　DataSource ds = (DataSource) ctx.lookup("java:/erpds");<br /><br />　return ds.getConnection();<br /><br />}<br /><br />/**<br /><br />* 取数据库链接对象<br /><br />* @return Connection 数据库链接对象<br /><br />* @throws Exception<br /><br />*/<br /><br />/*<br /><br />public static Connection getDirectConnection() throws Exception {<br /><br />　Class.forName("com.sybase.jdbc2.jdbc.SybDriver");<br /><br />　String url = "jdbc:sybase:Tds:19.64.13.16:4100/wydb?charset=iso_1";<br /><br />　String user = "sa";<br /><br />　String password = "2860008";<br /><br />　Connection conn = DriverManager.getConnection(url, user, password);<br /><br />　return conn;<br /><br />}<br /><br />*/</td></tr></tbody></table><p><br /></p><p>. 业务逻辑层的实现<br /><br />后台开发我们用Java类来实现。这里我们开发了一个orgNew包，类名为orgManager。此类封装了与数据库操作有关的方法。通过main可调试程序的正确性。<br /><br />这里给出了新增加一个组织的全部代码和通过XML取得树结构信息的代码，树结构通过递归实现。<br /><br /></p><table bordercolor="#000000" width="480" align="center" bgcolor="#e6e6e6" border="1"><tbody><tr><td>package orgNew;// Java类所打的包<br /><br />import tool.*;<br /><br />import java.sql.*;<br /><br />import java.util.*; // 引用Java类的<br /><br />public class orgManager {<br /><br />　public orgManager() { }<br /><br />　public static void main(String[] args) throws Exception {<br /><br />Connection conn = tool.ConnTool.getDirectConnection();// 引用数据访问类<br /><br />conn.setAutoCommit(false);<br /><br />orgManager orgManager1 = new orgManager();<br /><br />orgManager1.createOrg(0, conn); //测试建立组织是否正确<br /><br />　}<br /><br />　//建立一个组织<br /><br />　public static int createOrg(int parentOrgId, Connection conn) throws<br /><br />　Exception {<br /><br />String sql = "insert into Org (OrgName, parentOrgId) values('新组织', ?)";<br /><br />PreparedStatement pstat = conn.prepareStatement(sql);<br /><br />pstat.setInt(1, parentOrgId);<br /><br />pstat.executeUpdate();<br /><br />pstat.close();<br /><br />Statement stat = conn.createStatement();<br /><br />String sql2 = "select max(OrgId) from Org";<br /><br />ResultSet rs = stat.executeQuery(sql2);<br /><br />rs.next();<br /><br />int OrgId = rs.getInt(1);<br /><br />rs.close();<br /><br />stat.close();<br /><br />System.out.println(OrgId);<br /><br />return OrgId;<br /><br />　}<br /><br />}<br /><br />//通过递归得到组织信息的XML格式的数据<br /><br />public static String getTree(Connection conn) throws<br /><br />Exception {<br /><br />　StringBuffer ret = new StringBuffer();//定义可缓冲的字符流<br /><br />　ret.append("＜?xml version='1.0' encoding='gb2312'?＞＜tree id='0'＞");//定义XML格式的头信息<br /><br />　ret.append(" ＜item child='1' text='组织' id='1' ＞");//插入结点体。注树结点以item为标记 <br /><br />　ret.append(getChildTree(1, conn));<br /><br />　ret.append("＜/item＞");//结点体结束标记<br /><br />　ret.append("＜/tree＞");//树结束标记<br /><br />　return ret.toString();//返回字符流<br /><br />}<br /><br />public static String getChildTree(int OrgId, Connection conn) throws<br /><br />Exception {<br /><br />　StringBuffer ret = new StringBuffer();<br /><br />　String sql = "select a.OrgId, a.OrgName, a.OrgCode,count(b.parentOrgId) from Org a " +<br /><br />"left join Org b on a.OrgId = b.parentOrgId " +<br /><br />"where a.parentOrgId = ? " +<br /><br />"group by a.OrgId, a.OrgName";<br /><br />　PreparedStatement pstat = conn.prepareStatement(sql);<br /><br />　pstat.setInt(1, OrgId);<br /><br />　ResultSet rs = pstat.executeQuery();<br /><br />　while (rs.next()) {<br /><br />int childOrgId = rs.getInt(1);<br /><br />String childOrgName = rs.getString(2);<br /><br />String childOrgCode = rs.getString(3);<br /><br />if (childOrgCode == null) {<br /><br />　childOrgCode = " ";<br /><br />}<br /><br />if (childOrgName == null) {<br /><br />　childOrgName = "新组织";<br /><br />}<br /><br />int childCount = rs.getInt(3);<br /><br />if (childCount ＞ 0) {<br /><br />　childCount = 1;<br /><br />}<br /><br />ret.append("＜item child='" + childCount + "' text='" + childOrgName +<br /><br />"' id='" +childOrgId + "' code='"+childOrgCode+"'＞");<br /><br />ret.append(getChildTree(childOrgId, conn));<br /><br />ret.append("＜/item＞");<br /><br />　}<br /><br />　rs.close();<br /><br />　pstat.close();<br /><br />　return ret.toString();<br /><br />}</td></tr></tbody></table><p>其它代码见orgManager.java文件。<br /><br /><b>七、 总结</b><br /><br />本文件通过一个实例全面介绍了Ajax开发的各个细节。通过与J2ee的结合来实现三层分布式开发的层次划分，后台与前端的调用。数据的读取、访问及展现。 <br /><br />通过这个实例，我们可见，Ajax使WEB中的界面与应用分离。数据与呈现分离的分离，有利于分工合作、减少非技术人员对页面的修改造成的WEB应用程序错误、提高效率、也更加适用于现在的发布系统。也可以把以前的一些服务器负担的工作转嫁到客户端，利于客户端闲置的处理能力来处理。<br /><br />Ajax是传统WEB应用程序的一个转变。以前是服务器每次生成HTML页面并返回给客户端（浏览器）。Ajax理念的出现，揭开了无刷新更新页面时代的序幕，并有代替传统web开发中采用form(表单)递交方式更新web页面的趋势，可以算是一个里程碑。<br /><br />总之，Ajax适用于交互较多，频繁读数据，数据分类良好的WEB应用。</p><img src ="http://www.blogjava.net/Kaixinhutu/aggbug/42079.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Kaixinhutu/" target="_blank">糊涂</a> 2006-04-20 09:21 <a href="http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42079.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详解XML与J2EE之间组合技术的精髓 --（摘自赛迪网http://www.ccidnet.com/）</title><link>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42077.html</link><dc:creator>糊涂</dc:creator><author>糊涂</author><pubDate>Thu, 20 Apr 2006 01:17:00 GMT</pubDate><guid>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42077.html</guid><wfw:comment>http://www.blogjava.net/Kaixinhutu/comments/42077.html</wfw:comment><comments>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42077.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Kaixinhutu/comments/commentRss/42077.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Kaixinhutu/services/trackbacks/42077.html</trackback:ping><description><![CDATA[
		<span class="top11">当前，Java 2平台企业版（J2EE）架构在厂商市场和开发者社区中倍受推崇。作为一种工具，可扩展标记语言（XML）简化了数据交换、进程间消息交换这一类的事情，因而对开发者逐渐变得有吸引力，并开始流行起来。自然，在J2EE架构中访问或集成XML解决方案的想法也很诱人。因为这将是强大系统架构同高度灵活的数据管理方案的结合。<br />XML的应用似乎是无穷无尽的，但它们大致上可以分为三大类：<br />1、简单数据的表示和交换（针对XML的简单API（SAX）和文档对象模型（DOM）语法解析，不同的文档类型定义（DTDs）和概要（schemas））<br />2、面向消息的计算（XML-RPC（远程过程调用），SOAP协议，电子化业务XML（ebXML））<br />3、用户界面相关、表示相关的上下文（可扩展样式表语言（XSL），可扩展样式表语言转换（XSLT））<br />这几类应用在J2EE架构中恰好有天然的对应：数据表示和交换功能是EJB组件模型中持久化服务（persistence services）的一部分，基于消息的通讯由Java消息服务（JMS）API来处理，而界面表示正是Java服务器页面（JSP）和Java Servlets的拿手好戏。在本文中，我们将看到当今基于J2EE的应用里，XML是如何在上述几个方面进行应用的，以及在相关标准的未来版本中这些应用将会如何发展。<br /><strong>基础：数据的表示和交换</strong><br />修改甚至写入某个XML文档而经常被读入到某个对象模型中。作为例子，假定我们正处理多种类型的媒体（图品、视频、文本文档等等），并且用下面这个简单的XML DTD来描述这些媒体的元数据：<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="90" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><!-- DTD for a hypothetical mediamanagement system --><!-- Media assets are the root of the object hierarchy. Assets are alsohierarchical - they can contain other assets. --><!-- Metadata about the asset --></ccid_code></pre></td></tr></tbody></table><br />以下是一个基于上述媒体DTD的XML文档，描述了与某个课程讲座相关的内容： <br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="90%" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><ccid_code><media-asset><name><br />第14讲</name><desc>与第14讲相关的所有内容</desc><!-- 内容对象"lecture 14"的一套子组件 --><media-asset><name>讲座的幻灯片<br /></name><type><desc>MS PowerPoint</desc><mime-type><br />application/vnd.ms-powerpoint</mime-type></type><urn><br />http://javatraining.org/jaf/E123/lecture-14/slides.ppt<br /></urn></media-asset><media-asset><name>讲座的视频片断<br /></name><type><desc>RealPlayer streaming video</desc><mime-type>video/vnd.rn-realvideo<br /></mime-type></type><urn>http://javatraining.org/jaf/E123/lecture-14/lecture.rv</urn></media-asset><!-- 讲座开始 --><urn><br />http://javatraining.org/jaf/E123/lecture-14/index.jsp</urn></media-asset></ccid_code></ccid_code></pre></td></tr></tbody><p><br />从Web或者企业级应用的角度看，能以这种方式访问数据真是一种福音，因为它体现了高度的可移动性，使我们与元数据的实际资源本身隔离。这些资源可能来自一个关系数据库系统、某种活动媒体服务器或者Web服务器上的一个静态XML文档，等等。 <br />如果想把这些数据加载到Java应用中，我们可以从当前众多的Java语言XML解析器中选用一个，通过它将XML数据装入一个DOM文档，最后遍历文档，将所有这些数据转换到我们应用系统的对象模型中。 <br /></p><p></p><p><span class="top11">下面是个简单的基于DOM的解析程序，可对上述的媒体DTD进行解析。解析器用的是Apache Xerces： <br /></span></p><p></p></table><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="90" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>package jaf.xml;<br /><br />import java.util.*;<br />import java.io.IOException;<br />import org.w3c.dom.*;<br />import org.xml.sax.*;<br />// XML文档解析程序，使用上述媒体<br />DTD.public class MediaParserimplements ErrorHandler<br />{<br />/** 使用Apache Xerces解析器 */<br />org.apache.xerces.parsers.DOMParser mParser<br />  = new org.apache.xerces.parsers.DOMParser();<br />/** 构造函数 */<br />public MediaParser() {<br />// 告诉解析器验证并解析文档<br />try {<br />mParser.setFeature<br /> ( <br /> "http://xml.org/sax/features/validation", true<br />);<br /> } catch (SAXException e)<br /> {System.out.println<br />  ("Error setting validation on parser:");<br />e.printStackTrace();<br />}//<br /> 设置解析器的错误处理句柄mParser.setErrorHandler(this);<br />}<br />/** 解析指定的URL，返回找到的XML文档*/<br />public Document parse(String url)<br />  throws SAXException, IOException {mParser.parse(url);<br />Document mediaDoc = mParser.getDocument();<br />return mediaDoc;<br />}<br />/** 解析指定URL的XML文档，将内容转换成 MediaAsset 对象*/<br />public Collection loadAssets(String url)<br />  throws SAXException, IOException {Document doc = parse(url);<br />Collection assets = new LinkedList();<br />NodeList assetNodes = doc.getElementsByTagName("media-asset");<br />for (int i = 0;<br /> i &lt; assetNodes.getLength();<br /> i++){Node assetNode = assetNodes.item(i);<br />MediaAsset asset = new MediaAsset(assetNode);<br />assets.add(asset);<br />}return assets;<br />}<br />/*** 错误处理代码（为简洁起见省略了）*/<br />}<br />MediaParser类的构造函数初始化了一个Xerces DOM解析器。<br />parse()方法告诉解析器到哪个URL去找XML源，然后得到结果文档并返回。<br />loadAssets()方法调用parse()方法从某个XML源加载文档，<br />然后为文档中找到的每个“media-asset”节点创建一个MediaAsset对象。<br />以下是一个使用MediaAsset类的例子：<br />package jaf.xml;<br />import java.util.*;<br />public class MediaAsset {// 资源元数据private String mName = "";<br />private String mDesc = "";<br />private Collection mChildren = new LinkedList();<br />private Vector mTypes = new Vector();<br />private String mUrn = "";<br />protected MediaAsset(org.w3c.dom.Node assetNode) <br />{// 为简洁起见省略后面代码...}}<br /></ccid_code></pre></td></tr></tbody></table><p><br />因为篇幅的关系省略了MediaAsset类的详细代码，但应用模式依然是清晰的。MediaAsset类遍历文档的节点，<br />当它碰到不同的子节点时，它用子节点的内容填充自己的成员数据。<br />如果它发现了一个嵌套的子资源节点，它只需要创建一个新的MediaAsset对象，<br />然后将子资源节点的数据填充到新对象的成员数据中。<br />实现上述处理的方法数不胜数。我们还可以使用其他的解析器或解析器架构，<br />如Java API for XML Parsing (JAXP)。<br />除了使用DOM模型外，事件驱动的SAX模型也可用于解析XML。<br />类似的程序也可用来产生XML数据——前提是允许产生新的数据对象（在本例中是MediaAsset），它可将其相应的XML实体插入到DOM中，<br />然后将DOM输出到一个流中（诸如一个文件，一个Socket，或者一个HTTP连接...）。<br />还有其他更高层次的标准，可将XML映射到Java对象的过程进一步自动化（或简化）。<br />例如，使用XML概要（Schema）和XML绑定处理引擎，您可以半自动地将满足某个XML概要的XML数据转变成Java数据对象。<br />代表性的引擎是Castor，是由ExoLab小组管理的一个开放源代码项目的产物。<br />上述使用Xerces DOM的简单例子仅仅是演示了这一处理过程的底层模型。<br />上述示例表明，在Java环境中解析或产生XML是非常方便的，这与J2EE没有必然关联。<br />格式化为XML的数据可以从应用程序的任何层次流入或输出，这使得与外部系统的集成性无可限量。<br />但我们能否以一种更为直接的方式将XML数据源集成到J2EE架构中去呢？<br /></p><p><span class="top11"><strong>驾驭消息</strong><br /><br />J2EE架构包含了对JMS（Java消息服务）API的访问，以实现面向消息的通信（J2EE 1.2.1版只需JMS<br />API即可，在J2EE 1.3版中JMS基本定型，此时必须由某个兼容J2EE平台的服务器提供一个JMS API Provider）。<br />这一类的异步交互（与之相对的是：本地或远程方法调用所代表的同步交互）被证明在某些应用环境中是非常有用的。<br />某些时候，交互只需要通过间接的请求或回答来实现，即：在某些情况下，发出消息后不可能立即收到答复，<br />但我们仍希望当消息发出者重新在线时，确保他能收到答复信息。<br />面向消息系统的实际应用之一就是企业之间的松散集成。类似于EDI（电子文档交换）时代的文档交换，<br />两个企业由于业务的需要而交换消息，此时通常不能为了使用RPC或者RMI、CORBA、DCOM之类的远程方法交互而在两者之间进行紧密集成。<br />象JMS API这样的消息系统允许双方交换基于JMS API的消息载荷，<br />前提是双方在会话的时候均能提供兼容的JMS API服务。<br />当前仍然存在的困难是：双方是否能尊从相同的格式或协议。<br />这正是XML大显身手的时候。XML明确地被设计来解决此类数据交换问题<br />——灵丹妙药就是“面向消息的概要表”（Message-Oriented Communication Scheme），<br />实质就是基于一个双方认同的DTD或schema，用XML格式来交换消息载荷。<br />JMS API支持好几种消息，其中的TextMessage代表文本消息载荷。<br />一个简单而有效的XML消息交换方案是，在一端将我们的XML文档插入TextMessage，然后在另一端用自制的XML解析程序（如前面的MediaParser）解开数据并（可选地）将其转换成Java对象。<br />这使得我们既可以用JMS API支持的公开预订的消息模型，也可以用JMS API支持的点对点的消息模型来发送XML消息。<br />上述方法有一些局限，因为对于JMS运行时处理而言，XML的内容基本上是不透明的。<br />例如，JMS API允许使用基于特定消息头的路由。这很容易理解，尤其当我们希望XML消息根据其内容采取不同走向时。<br />例如在我们的MediaAsset例子中，我们希望公开讲座内容，但只想把特定的内容传送给那些预订了课程的人，或传送给那些表明可以接受某些媒体格式（如视频流）的人。<br />为了发挥JMS API的价值，以便实现上述基于内容的消息路由，我们有必要从XML数据中解析出关键信息，<br />然后在构造标准JMS API消息头时插入这些信息。这是可行的，但要实现XML信息我们就得额外地写很多代码（交换消息的双方均如此）。<br />为了在XML和JMS API之间架起桥梁，一些厂商提供了自定义的JMS扩展，以便直接支持XML消息机制。<br />例如，BEA系统公司基于J2EE的WebLogic应用服务器特别为TextMessage提供了XMLMessage子类，允许用XPath表达式来过滤XML消息。<br />不过这是一种专有的扩展，这要求交换消息的双方必须都能处理这类消息。<br />为此，Sun公司目前正在开发用于XML消息的Java API（JAXM）。其目标是提供一个高级别的标准服务，以实现基于ebXML的消息的合成与传送。<br />一个JAXM服务提供程序可以将这类消息映射到适当的物理消息系统（诸如JMS API）中去。<br /><strong>让XML看得见</strong><br />将XML同Web系统的用户界面进行集成显然是一种有益的尝试。绝大多数的界面程序，无论是基于还是不基于Web，都是将数据进行转换，然后用易读的格式展现给用户。<br />用诸如XML这种“易消化”的格式存放数据将简化上述工作，同时它还大大提高了内容的可管理性，接下来我们就可看到这一点。<br />不过首先要大书一笔的是，XML在Web界面层的应用得益于JSP技术的发展。<br />一直以来大家都希望能清晰地区分Web应用程序的表示层与底层对象模型，JSP框架诞生于这些努力之中（包括早期JHTML尝试）。<br />JSP框架允许将Java代码嵌入到HTML内容中，这样既可以实现动态内容，又不必经常修改Java Servlets的代码。<br />在页面中包含Java技术的途径是通过JSP标记（JSP Tags），这些标记以XML风格出现。在JSP中，<br />Java程序以代码片段、服务器端JavaBeans组件、在服务器端触发特定操作的不透明标记（标准的或自定义的）等形式存在。<br />当某个用户通过浏览器请求JSP页面时，一个Java应用服务器解析该JSP页面，将其编译成一个Java Servlet，然后执行该Servlet以产生答复页面。<br />一种直接将XML数据源集成到JSP的界面中去的方法是，将XML加载到JavaBeans组件中（如同我们在MediaAsset例子中所做的），然后在JSP中直接引用这些JavaBeans组件。<br />下面是一个嵌入Java代码片断的例子：<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="90" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><html><head><!-- 引入我们的类 --><![CDATA[<%@ page import="jaf.xml.*" %>]]&gt;<H3><FONT align="left">Media Assets for Lecture 14:<FONT size=+0></FONT></FONT></H3><!-- 定义一个资源对象，以便用于显示 --><?XML:NAMESPACE PREFIX = JSP /><jsp:usebean class=jaf.xml.MediaAsset id=asset></jsp:usebean><!-- 从一个先前定义的位置装载资源 --><![CDATA[<% MediaParser parser = new MediaParser();<br>Collection assets =parser.loadAssets("http://javaschool.org/jaf/E162/lecture14-assets.xml");<BR>Iterator iter = assets.iterator();<BR>%&gt;]]&gt;<TABLE border=0><TBODY><TR><TH>Name</TH><TH>Type</TH><TH>URN</TH></TR><![CDATA[<%while (iter.hasNext()) {asset = (MediaAsset)iter.next();<br>%&gt;]]&gt;<TR><TD><jsp:getproperty name="asset" property="name"></jsp:getproperty></TD><TD><jsp:getproperty name="asset" property="type"></jsp:getproperty></TD><TD><jsp:getproperty name="asset" property="URN"></jsp:getproperty></TD></TR><![CDATA[<%}%>]]&gt;</TBODY></TABLE></CCID_CODE></PRE></TD></TR></TBODY></TABLE><BR>上述程序还有一种更简洁的写法，那就是使用自定义JSP页面标记。这样我们就可以从JSP页面中剔出代码段，只使用JavaBeans组件和自定义的JSP标记即可。比如说，为了去掉创建解析器、加载资源数据到集合中的那段代码，我们可创建一个自己的标记，由它在幕后完成这些工作。 </SPAN></P></TABLE></SPAN></html>]]&gt;</head></html></ccid_code></pre></td></tr></tbody></table></span></p></span>
<img src ="http://www.blogjava.net/Kaixinhutu/aggbug/42077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Kaixinhutu/" target="_blank">糊涂</a> 2006-04-20 09:17 <a href="http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE最佳实践[12个最重要的]--摘自赛迪网(http://www.ccidnet.com/)</title><link>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42074.html</link><dc:creator>糊涂</dc:creator><author>糊涂</author><pubDate>Thu, 20 Apr 2006 01:08:00 GMT</pubDate><guid>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42074.html</guid><wfw:comment>http://www.blogjava.net/Kaixinhutu/comments/42074.html</wfw:comment><comments>http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42074.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Kaixinhutu/comments/commentRss/42074.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Kaixinhutu/services/trackbacks/42074.html</trackback:ping><description><![CDATA[
		<strong>1. 始终使用 MVC 框架。</strong>
		<br />         MVC 框架可以将业务逻辑（Java beans 和 EJB 组件)、控制器逻辑（Servlets/Struts 动作）、表示层（JSP、XML/XSLT）清晰地分离开来。良好的分层可以带来许多好处。 <br /><br />         MVC 框架对于成功使用 J2EE 是如此重要，以致没有其他最佳实践可以与其相提并论。模型-视图-控制器（MVC）是设计 J2EE 应用程序的基础。MVC 将您的程序代码简单地划分下面几个部分： <br /><br />负责业务逻辑的代码（即模型??通常使用 EJB 或者普通的 Java 对象来实现）。 <br /><br />负责用户界面显示的代码（即视图??通常通过 JSP 及标记库来实现，有时也使用 XML 和 XSLT 来实现）。 <br /><br />负责应用程序流程的代码（即控制器??通常使用 Java Servlet 或像 Struts 控制器这样的类来实现）。 <br /><br />如果您不遵循基本的 MVC 框架，在开发过程中就会出现许多的问题。最常见的问题就是在视图部分添加了太多的成分，例如，可能存在使用 JSP 标记来执行数据库访问，或者在 JSP 中进行应用程序的流程控制，这在小规模的应用程序中是比较常见的，但是，随着后期的开发，这样做将会带来问题，因为 JSP 逐步变得越来越难以维护和调试。 <br /><br />类似地，我们也经常看到将视图层构建到业务逻辑的情况。例如，一个常见的问题就是将在构建视图时使用的 XML 解析技术直接应用到业务层。业务层应该对业务对象??而不是绑定到视图的特定数据表示进行操作。 <br /><br />然而，只是具有合适的组件并不一定意味着可以使您的应用程序得到合适的分层。我们常常见到一些应用程序包含 servlet、JSP 和 EJB 组件所有这三项，然而，其主要的业务逻辑却是在 servlet 层实现的，或者应用程序导航是在 JSP 中处理的。您必须进行严格的代码检查并重构您的代码，以确保应用程序的业务逻辑只在模型层（Model layer）进行处理，应用程序导航只通过控制器层（Controller layer）进行处理，而您的视图（Views）只是将传递过来的模型对象以 HTML 及 JavaScript 的形式表示出来。 <br /><br /><strong>2. 在应用程序的每一层都使用自动单元测试和测试管理。</strong><br /><br />不要只是测试您的图形用户界面（GUI)。分层的测试使测试及维护工作变得极其简单。 <br /><br />在过去的几年中，在方法学领域有了相当大的革新，例如新出现的被称为 Agile（例如 SCRUM [Schwaber] 和极限编程 [Beck1]）的轻量级方法现在已经得到了很普遍的应用。几乎所有的这些方法中的一个共同的特征是它们都提倡使用自动的测试工具，这些工具可以帮助开发人员用更少的时间进行回归测试 (regression testing)，并可以帮助他们避免由于不充分的回归测试造成的错误，因此可以用来提高程序员的工作效率。实际上，还有一种被称为 Test-First Development [Beck2] 的方法，这种方法甚至提倡在开发实际的代码之前就先编写单元测试。然而，在您测试代码之前，您需要将代码分割成一些可测试的片断。一个"大泥球"是难以测试的，因为它不是只实现一个简单的易于识别的功能。如果您的每个代码片断实现多个方面的功能，这样的代码将难以保证其完全的正确性。 <br /><br />MVC 框架（以及 J2EE 中的 MVC 实现）的一个优点就是元素的组件化能够（实际上，相当的简单）对您的应用程序进行单元测试。因此，您可以方便地对实体 bean、会话 bean 以及 JSP 独立编写测试用例，而不必考虑其他的代码。现在有许多用于 J2EE 测试的框架和工具，这些框架及工具使得这一过程更加简单。例如，JUnit（是一种由 junit.org 开发的开放源代码工具）和 Cactus（由 Apache 开发的开放源代码工具）对于测试 J2EE 组件都非常有用。[Hightower] 详细探讨了如何在 J2EE 中使用这些工具。 <br /><br />尽管所有这些详述了怎样彻底地测试您的应用程序，但是我们仍然看到一些人认为只要他们测试了 GUI（可能是基于 Web 的 GUI，或者是独立的 Java 应用程序），则他们就全面地测试了整个应用程序。GUI 测试很难达到全面的测试，有以下几种原因。首先，使用 GUI 测试很难彻底地测试到系统的每一条路径，GUI 仅仅是影响系统的一种方式，可能存在后台运算、脚本和各种各样的其他访问点，这也需要进行测试。然而，它们通常并不具有 GUI。第二，GUI 级的测试是一种非常粗粒度的测试。这种测试只是在宏观水平上测试系统的行为。这意味着一旦发现存在问题，则与此问题相关的整个子系统都要进行检查，这使得找出 bug（缺陷）将是非常困难的事情。第三，GUI 测试通常只有在整个开发周期的后期才能很好地得到测试，这是因为只有这那个时候 GUI 才得到完整的定义。这意味着只有在后期才可能发现潜在的 bug。第四，一般的开发人员可能没有自动的 GUI 测试工具。因此，当一个开发人员对代码进行更改时，没有一种简单的方法来重新测试受到影响的子系统。这实际上不利于进行良好的测试。如果开发人员具有自动的代码级单元测试工具，开发人员就能够很容易地运行这些工具以确保所做的更改不会破坏已经存在的功能。最后，如果添加了自动构建功能，则在自动构建过程中添加一个自动的单元测试工具是非常容易的事情。当完成这些设置以后，整个系统就可以有规律地进行重建，并且回归测试几乎不需要人的参与。 
<p></p><p>另外，我们必须强调，使用 EJB 和 Web 服务进行分布式的、基于组件的开发使得测试单个的组件变得非常必要。如果没有"GUI"需要测试，您就必须进行低级（lower-level）测试。最好以这种方式开始测试，省得当您将分布式的组件或 Web 服务作为您的应用程序的一部分时，您不得不花费心思重新进行测试。 <br /><br />总之，通过使用自动的单元测试，能够很快地发现系统的缺陷，并且也易于发现这些缺陷，使得测试工作变得更加系统化，因此整体的质量也得以提高。 <br /><br /><strong>3. 按照规范来进行开发，而不是按照应用服务器来进行开发。</strong><br /><br />要将规范熟记于心，如果要背离规范，要经过慎密的考虑后才可以这样做。这是因为当您背离规则的时候，您所做的事情往往并不是您应该做的事情。 <br /><br />当您要背离 J2EE 可以允许您做的事情的时候，这很容易让使您遭受不幸。我们发现有一些开发人员钻研一些 J2EE 允许之外的东西，他们认为这样做可以"稍微"改善J2EE的性能，而他们最终只会发现这样做会引起严重的性能问题，或者在以后的移植（从一个厂商到另一个厂商，或者是更常见的从一个版本到另一个版本）中会出现问题。实际上，这种移植问题是如此严重，以致 [Beaton] 将此原则称为移植工作的基本最佳实践。 <br /><br />现在有好几个地方如果不直接使用 J2EE 提供的方法肯定会产生问题。一个常见的例子就是开发人员通过使用 JAAS 模块来替代 J2EE 安全性，而不是使用内置的遵循规范的应用程序服务器机制来进行验证和授权。要注意不要脱离 J2EE 规范提供的验证机制，如果脱离了此规范，这将是系统存在安全漏洞以及厂商兼容性问题的主要原因。类似地，要使用 servlet 和 EJB 规范提供的授权机制，并且如果您要偏离这些规范的话，要确保使用规范定义的 API（例如 getCallerPrincipal()）作为实现的基础。通过这种方式，您将能够利用厂商提供的强安全性基础设施，其中，业务要求需要支持复杂的授权规则。 <br /><br />其他常见的问题包括使用不遵循 J2EE 规范的持久性机制（这使得事务管理变得困难）、在J2EE程序中使用不适当的J2SE 方法（例如线程或 singleton），以及使用您自己的方法解决程序到程序（program-to-program）的通信，而不是使用 J2EE 内在支持的机制（例如 JCA、JMS 或 Web 服务）。当您将一个遵循 J2EE 的服务器移植到其他的服务器上，或者移植到相同服务器的新版本上，上述的设计选择将会造成无数的问题。唯一要背离规范的情况是，当一个问题在规范的范围内无法解决的时候。例如，安排执行定时的业务逻辑在 EJB2.1 出现之前是一个问题，在类似这样的情况下，我们建议当有厂商提供的解决方案时就使用厂商提供的解决方案（例如 WebSphere Application Server Enterprise 中的 Scheduler 工具），而在没有厂商提供的解决方案时就使用第三方提供的工具。如果使用厂商提供的解决方案，应用程序的维护以及将其移植到新的规范版本将是厂商的问题，而不是您的问题。 <br /><br />最后，要注意不要太早地采用新技术。太过于热衷采用还没有集成到 J2EE 规范的其他部分或者还没有集成到厂商的产品中的技术常会带来灾难性的后果。支持是关键的??如果您的厂商不直接支持一种特定的在 JSR 中提出的技术，但此技术还没有被 J2EE 所接受，那么您就不应该采用此技术。毕竟，我们中的大多数人从事解决业务问题，而不是推进技术的发展。 <br /><br /><strong>4. 从一开始就计划使用 J2EE 安全性。</strong><br /><br />启用 WebSphere 安全性。这使您的 EJB 和 URL 至少可以让所有授权用户访问。不要问为什么??照着做就是了。 <br /><br />在与我们合作的客户中，一开始就打算启用 WebSphere J2EE 安全性的顾客是非常少的，这一点一直让我们感到吃惊。据我们估计大约只有 50% 的顾客一开始就打算使用此特性。例如，我们曾与一些大型的金融机构（银行、代理等等）合作过，他们也没有打算启用安全性。幸运的是，这种问题在部署之前的检查时就得以解决. <br /><br />不使用 J2EE 安全性是危险的事情。假设您的应用程序需要安全性（几乎所有的应用程序都需要），您敢打赌您的开发人员能够构建出自己的安全性系统，而这个系统比您从 J2EE 厂商那里买来的更好。这可不是个好的赌注，为分布式的应用程序提供安全性是异常困难的。例如，您需要使用网络安全加密令牌控制对 EJB 的访问。以我们的经验看来，大多数自己构建的安全性系统是不安全的，并且有重大的缺陷，这使产品系统极其脆弱。 <br /><br />一些不使用 J2EE 安全性的理由包括：担心性能的下降，相信其他的安全性（例如 Netegrity SiteMinder）可以取代 J2EE 安全性，或者是不知道 WebSphere Application Server 安全特性及功能。不要陷入这些陷阱之中，尤其是，尽管像 Netegrity SiteMinder 这样的产品能够提供优秀的安全特性，但是仅仅其自身不可能保护整个 J2EE 应用程序。这些产品必须与 J2EE 应用程序服务器联合起来才可能全面地保护您的系统。 <br /><br />其他的一种常见的不使用 J2EE 安全性的原因是：基于角色的模型没有提供足够的粒度访问控制以满足复杂的业务规则。尽管事实是这样的，但这也不应该成为不使用 J2EE 安全性的理由。相反地，应该将 J2EE 验证及 J2EE 角色与特定的扩展规则结合起来。如果复杂的业务规则需要做出安全性决策，那就编写相应的代码，其安全性决策要基于可以直接使用的以及可靠的 J2EE 验证信息（用户 ID 和角色）。<br />5、创建你所知道的<br /></p><p>反复的开发工作将使您能够逐渐地掌握所有的 J2EE 模块。要从创建小而简单的模块开始而不是从一开始就马上涉及到所有的模块。 <br /><br />我们必须承认 J2EE 是庞大的体系。如果一个开发小组只是开始使用 J2EE，这将很难一下子就能掌握它。在 J2EE 中有太多的概念和 API 需要掌握。在这种情况下，成功掌握 J2EE 的关键是从简单的步骤开始做起。 <br /><br />这种方法可以通过在您的应用程序中创建小而简单的模块来得到最好的实现。如果一个开发小组通过创建一个简单的域模型以及后端的持久性机制（也许使用的是 JDBC）,并且对其进行了完整的测试，这会增强他们的自信心，于是他们会使用该域模型去掌握使用 servlet 和 JSP 的前端开发。如果一个开发组发现有必要使用 EJB，他们也会类似地开始在容器管理的持久性 EJB 组件之上使用简单的会话 Facades，或者使用基于 JDBC 的数据访问对象（JDBC-based Data Access Objects，DAO），而不是跳过这些去使用更加复杂的构造（例如消息驱动bean和JMS）。 <br /><br />这种方法并不是什么新方法，但是很少有开发组以这种方式来培养他们的技能。相反地，多数开发组由于尝试马上就构建所有的模块，同时涉及 MVC 中的视图层、模型层和控制器层，这样做的结果是他们往往会陷入进度的压力之中。他们应该考虑一些敏捷（Agile）开发方法，例如极限编程（XP），这种开发方法采用一种增量学习及开发方法。在 XP 中有一种称为 ModelFirst 的过程，这个过程涉及到首先构建域模型作为一种机制来组织和实现用户场景。基本说来，您要构建域模型作为您要实现的用户场景的首要部分，然后在域模型之上构建一个用户界面（UI）作为用户场景实现的结果。这种方法非常适合让一个开发组一次只学到一种技术，而不是让他们同时面对很多种情况（或者让他们读很多书），这会令他们崩溃的。 <br /><br />还有，对每个应用程序层重复的开发可能会包含一些适当的模式及最佳实践。如果您从应用程序的底层开始应用一些模式如数据访问对象和会话 Facades，您就不应该在您的JSP和其他视图对象中使用域逻辑。 <br /><br />最后，当您开发一些简单的模块时，在开始的初期就可以对您的应用程序进行性能测试。如果直到应用程序开发的后期才进行性能测试的话，这往往会出现灾难性的后果。 </p><p><strong>6. 当使用 EJB 组件时，始终使用会话 Facades。 <br /><br /></strong><br /><br />决不要将实体 bean 直接暴露给任何用户类型。对实体 bean 只可以使用本地 EJB 接口（Local EJB interfaces）。 <br /><br />当使用 EJB 组件时，使用一个会话 Facades 是一个确认无疑的最佳实践。实际上，这个通用的实践被广泛地应用到任何分布式的技术中，包括 CORBA、EJB 和 DCOM。从根本上讲，您的应用程序的分布"交叉区域"越是底层化，对小块的数据由于多次重复的网络中继造成的时间消耗就越少。要达到这个目的的方法就是：创建大粒度的 Facades 对象，这个对象包含逻辑子系统，因而可以通过一个方法调用就可以完成一些有用的业务功能。这种方法不但能够降低网络开销，而且在 EJB 内部通过为整个业务功能创建一个事务环境也可以大大地减少对数据库的访问次数。 <br /><br />EJB 本地接口（从 EJB 2.0 规范开始使用）为共存的 EJB 提供了性能优化方法。本地接口必须被您的应用程序显式地进行访问，这需要代码的改变和防止以后配置 EJB 时需要应用程序的改变。由于会话 Facades 和它包含的整个 EJB 对于彼此来说都应该是本地的，我们建议对会话 Facades 后面的实体 bean 使用本地接口。然而，会话 Facades 本身的实现（典型例子如无状态会话 bean）应该设计为远程接口。 <br /><br />为了性能的优化，可以将一个本地接口添加到会话 Facades。这样做利用了这样一个事实：在大多数情况下（至少在 Web 应用程序中），您的 EJB 客户端和 EJB 会共同存在于同一个 Java 虚拟机（JVM）中。另外一种情况，如果会话 Facades 在本地被调用，可以使用 J2EE 应用服务器配置优化（configuration optimizations），例如 WebSphere 中的"No Local Copies"。然而，您必须注意到这些可供选择的方案会将交互方法从按值传递（pass-by-value）改变为按引用传递（pass-by-reference）。这可能会在您的代码中产生很微妙的错误。当您要利用这些方案时，您应该在一开始就考虑其可行性。 <br /><br />如果在您的会话 Facades 中使用远程接口（而不是本地接口），您也可以将同样的会话 Facades 在 J2EE 1.4 中以兼容的方式作为 Web 服务来配置。这是因为 JSR 109（J2EE 1.4 中的 Web 服务部署部分）要求使用无状态会话 bean 的远程接口作为 EJB Web 服务和 EJB 实现的接口。这样做是值得的，因为这样做可以为您的业务逻辑增加客户端类型的数量。 <br /><br /><strong>7. 使用无状态会话 bean，而不是有状态会话 bean</strong><br /><br />这样做可以使您的系统经得起错误的终止。使用 HttpSession 存储和用户相关的状态。 <br /><br />以我们的观点看来，有状态会话 bean 的概念已经过时了。如果您仔细对其考虑一下，一个有状态会话 bean 实际上与一个 CORBA 对象在体系结构上是完全相同的，无非就是一个对象实例，绑定到一个服务器，并且依赖于服务器来管理其生命周期。如果服务器关闭了，这种对象也就不存在，那么这个 bean 的客户端的信息也就不存在。 <br /><br />J2EE 应用服务器为有状态会话 bean 提供的故障转移（failover）能够解决一些问题，但是有状态的解决方案没有无状态的解决方案易于扩展。例如，在 WebSphere Application Server 中，对无状态会话 bean 的请求，是通过对部署无状态会话的成员集群进行平衡加载来实现。相反地，J2EE 应用服务器不能对有状态 bean 的请求进行平衡加载。这意味着您的集群中的服务器的加载过程会是不均衡的。此外，使用有状态会话 bean 将会再添加一些状态到您的应用服务器上，这也是不好的做法。这样就增加了系统的复杂性，并且在出现故障的情况下使问题变得复杂化。创建健壮的分布式系统的一个关键原则是尽量使用无状态行为。 <br /><br />因此，我们建议对大多数应用程序使用无状态会话 bean 方法。任何在处理时需要使用的与用户相关的状态应该以参数的形式传送到 EJB 的方法中（并且通过使用一种机制如 HttpSession 来存储它）或者从持久性的后端存储（例如通过使用实体 bean)作为 EJB 事务的一部分来进行检索。在合适的情况下，这个信息可以缓存到内存中，但是要注意在分布式的环境中保存这种缓存所潜在的挑战性。缓存非常适合于只读数据。 <br /><br />总之，您要确保从一开始就要考虑到可伸展性。检查设计中的所有设想，并且考虑到当您的应用程序要在多个服务器上运行时，是否也可以正常运行。这个规则不但适合上述情况的应用程序代码，也适用于如 MBean 和其他管理界面的情况下。 <br /><br />避免使用有状态性不只是对 IBM/WebSphere 的建议，这是一个基本的 J2EE 设计原则。 <br /><br /><strong>8. 使用容器管理的事务</strong><br /><br />学习一下 J2EE 中的两阶段提交事务，并且使用这种方式，而不是开放您自己的事务管理。容器在事务优化方面几乎总是比较好的。 <br /><br />使用容器管理的事务（CMT）提供了两个关键的优势（如果没有容器支持这几乎是不可能的）：可组合的工作单元和健壮的事务行为。 <br /><br />如果您的应用程序代码显式地使用了开始和结束事务（也许使用 javax.jts.UserTransaction 或者甚至是本地资源事务），而将来的要求需要组合模块（也许会是代码重构的一部分），这种情况下往往需要改变事务代码。例如，如果模块 A 开始了一个数据库事务，更新数据库，随后提交事务，并且有模块 B 做出同样的处理，请考虑一下当您在模块 C 中尝试使用上述两个模块，会出现什么情况呢？现在，模块 C 正在执行一个逻辑动作，而这个动作实际上将调用两个独立的事务。如果模块 B 在执行中失败了，而模块 A 的事务仍然能被提交。这是我们所不希望出现的行为。如果，相反地，模块 A 和模块 B 都使用 CMT 的话，模块 C 也可以开始一个 CMT（通常通过配置描述符），并且在模块 A 和模块 B 中的事务将是同一个事务的隐含部分，这样就不再需要复杂的重写代码的工作了。 <br /><br />如果您的应用程序在同一个操作中需要访问多种资源，您就要使用两阶段提交事务。例如，如果从 JMS 队列中删除一个消息，并且随后更新基于这条消息的纪录，这时，要保证这两个操作都会执行或都不会执行就变得尤为重要。如果一条消息已经从队列中被删除，而系统没有更新与此消息相关的数据库中的纪录，那么这种系统是不稳定的。一些严重的客户及商业纠纷源自不一致的状态。 <br /><br />我们时常看到一些客户应用程序试图实现他们自己的解决方案。也许会通过应用程序的代码在数据库更新失败的时候 "撤销"对队列的操作。我们不提倡这样做。这种实现要比您最初的想象要复杂得多，并且还有许多其他的情况（想象一下如果应用程序在执行此操作的过程中突然崩溃的情况）。作为替代的方式，应该使用两阶段提交事务。如果您使用 CMT，并且在一个单一的 CMT 中访问两阶段提交的资源（例如 JMS 和大多数数据库），WebSphere 将会处理所有的复杂工作。它将确保整个事务被执行或者都不被执行，包括系统崩溃、数据库崩溃或其他的情况。其实现在事务日志中保存着事务状态。当应用程序访问多种资源的时候，我们怎么强调使用 CMT 事务的必要性都不为过。 <br />9、将jsp作为表示层的首选<br />只有在需要多种表示输出类型，并且输出类型被一个单一的控制器及后端支持时才使用 XML/XSLT。 <br /><br />我们常听到一些争论说，为什么您选择 XML/XSLT 而不是 JSP 作为表示层技术。选择 XML/XSLT 的人的观点是，JSP" 允许您将模型和视图混合在一起"，而 XML/XSLT 不会有这种问题。遗憾的是，这种观点并不完全正确，或者至少不像白与黑那样分的清楚。实际上，XSL 和 XPath 是编程语言。XSL 是图灵完成的（Turing-complete），尽管它不符合大多数人定义的编程语言，因为它是基于规则的，并且不具备程序员习惯的控制工具。 <br /><br />现在的问题是既然给予了这种灵活性，开发人员就会利用这种灵活性。尽管每个人都认同 JSP 使开发人员容易在视图中加入"类似模型"的行为，而实际上，在 XSL 中也有可能做出一些同样的事情。尽管从 XSL 中进行访问数据库这样的事情会非常困难，但是我们曾经见到过一些异常复杂的 XSLT 样式表执行复杂的转换，这实际上是模型代码。 <br /><br />然而，应该选择 JSP 作为首选的表示技术的最基本的原因是，JSP 是现在支持最广泛的、也是最被广泛理解的 J2EE 视图技术。而随着自定义标记库、JSTL 和 JSP2.0 的新特性的引入，创建 JSP 变得更加容易，并且不需要任何 Java 代码，以及可以将模型和视图清晰的分离开。在一些开发环境中（如 WebSphere Studio）加入了对 JSP（包括对调试的支持）的强大支持，并且许多开发人员发现使用 JSP 进行开发要比使用 XLS 简单，一些支持 JSP 的图形设计工具及其他特征（尤其在 JSF 这样的框架下）使得开发人员可以以所见即所得的方式进行 JSP 的开发，而对于 XSL 有时不容易做到。 <br /><br />最后一个要谨慎考虑使用 JSP 的原因是速度问题。在 IBM 所作的对比 XSL 和 JSP 相对速度的性能测试显示：在大多数情况下，JSP 在生成同样的 HTML 的时候，要比 XSL 快好几倍，甚至使用编译过的 XSL 也是如此。尽管多数情况下这不是问题，但在性能要求很高的情况下，这就会成为问题。 <br /><br />然而，这也不能说，您永远也不要使用 XSL。在一些情况下，XSL 能够表示一组固定的数据，并且可以基于不同的样式表来以不同的方式显示这些数据的能力是显示视图的最佳解决方案。然而，这只是一种例外的情况，而不是通用的规则。如果您只是生成 HTML 来表达每一个页面，那么在大多数情况下，XSL 是一种不必要的技术，并且，它给您的开发人员所带来的问题远比它所能解决的问题多。 <br /><br />10. <strong>当使用 HttpSession 时，尽量只将当前事务所需要的状态保存其中，其他内容不要保存在 HttpSession 中。 <br /><br /></strong><br /><br />启用会话持久性。 <br /><br />HttpSessions 对于存储应用程序状态信息是非常有用的。其 API 易于使用和理解。遗憾的是，开发人员常常遗忘了 HttpSession 的目的----用来保持暂时的用户状态。它不是任意的数据缓存。我们已经见到过太多的系统为每个用户的会话放入了大量的数据（达到兆字节）。那好了，如果同时有 1000 个登录系统的用户，每个用户拥有 1MB 的会话数据，那么就需要 1G 或者更多的内存用于这些会话。要使这些 HTTP 会话数据较小一些，不然的话，您的应用程序的性能将会下降。一个大约比较合适的数据量应该是每个用户的会话数据在 2K-4K 之间，这不是一个硬性的规则，8K 仍然没有问题，但是显然会比 2K 时的速度要慢。一定要注意，不要使 HttpSession 变成数据堆积的场所。 <br /><br />一个常见的问题是使用 HttpSession 缓存一些很容易再创建的信息，如果有必要的话。由于会话是持久性的，进行不必要的序列化以及写入数据是一种很奢侈的决定。相反地，应该使用内存中的哈希表来缓存数据，并且在会话中保存一个对此数据进行引用的关键字。这样，如果不能成功登录到另外的应用服务器的话，就可以重新创建数据。 <br /><br />当谈及会话持久性时，不要忘记要启用这项功能。如果您没有启用会话持久性，或者服务器因为某种原因停止了（服务器故障或正常的维护），则所有此应用服务的当前用户的会话将会丢失。这是件令人非常不高兴的事情。用户不得不重新登录，并且重新做一些他们曾经已经做过的事情。相反地，如果启用了会话持久性，WebSphere 会自动将用户（以及他们的会话）移到另外一个应用服务器上去。用户甚至不知道会有这种事情的发生。我们曾经见到过一些产品系统因为存在于本地代码中令人难以忍受的 bug（不是 IBM 的代码！）而突然崩溃的情况，这这种情况下，上述功能仍然可以运行良好。 <br /><br /><strong>11. 在 WebSphere 中，使用动态缓存，并使用 WebSphere servlet 缓存机制。</strong> <br /><br />通过使用这些功能，系统性能可以得到很大的提高，而开销是很小的。并且不影响编程模型。 <br /><br />通过缓存来提高性能的好处是众所周知的事情。遗憾的是，当前的 J2EE 规范没有包括一种用于 servlet/JSP 缓存的机制。然而，WebSphere 提供了对页面以及片断缓存的支持，这种支持是通过其动态缓存功能来实现的，并且不需要对应用程序作出任何改变。其缓存的策略是声明性的，而且其配置是通过 XML 配置描述符来实现的。因此，您的应用程序不会受到影响，并保持与 J2EE 规范的兼容性和移植性，同时还从 WebSphere 的 servlet 及 JSP 的缓存机制中得到性能的优化。 <br /><br />从 servet 及 JSP 的动态缓存机制得到的性能的提高是显而易见的，这取决于应用程序的特性。Cox 和 Martin [Cox] 指出对一个现有的 RDF（资源描述格式）站点摘要 (RSS)servlet，当使用动态缓存时，其性能可以提高 10%。请注意这个实验只涉及到一个简单的 servlet，这个性能的增长量可能并不能反映一个复杂的应用程序。 <br /><br />为了更多地提高性能，将 WebSphere servlet/JSP 结果缓存与 WebSphere 插件 ESI Fragment 处理器、IBM HTTP Server Fast Response Cache Accelerator (FRCA) 和 Edge Server 缓存功能集成在一起。对于繁重的基于读取的工作负荷，通过使用这些功能可以得到许多额外的好处。 <br /><br /><strong>12. 为了提高程序员的工作效率，将 CMP 实体 bean 作为 O/R 映射的首选解决方案.</strong><br /><br />通过 WebSphere 框架（readahead、缓存、隔离级别等）优化性能。如果可能，有选择的应用一些模式来达到提高性能的目的，例如 Fast-Lane 阅读器 [Marinescu]。 <br /><br />对象/关系（O/R）映射是使用 Java 创建企业级的应用程序的基础。几乎每个 J2EE 应用程序都需要一些类型的 O/R 映射。J2EE 厂商提供一种 O/R 映射机制，这种机制在不同的厂商间是可移植的，高效的，并且能够被一些标准及工具很好地支持。这就是 EJB 规范中的 CMP（容器管理的持久性）部分。 <br /><br />早期的 CMP 实现以表现不佳及不支持许多 SQL 结构而著称。然而，随着 EJB 2.0 及 2.1 规范的出现，以及被一些厂商所采纳，并且随着像 IBM WebSphere Studio Application Developer 的出现，这些问题已经不再是问题了。 <br /><br />CMP EJB 组件现在已经被广泛地应用于许多高性能的应用程序中。WebSphere 包括一些优化功能以提高 EJB 组件的性能，优化功能包括：对生命周期的缓存和 read-ahead 能力。这两者优化功能都是配置时的选项，并且不需要对应用程序进行修改或者影响可移植性。 <br /><br />处于缓存状态的生命周期缓存 CMP 状态数据并提供基于时间的无效性。从处于缓存状态的生命周期得到的性能提高可以达到选项 A 的缓存性能，并且仍然可以为您的应用程序提供可伸展性。Read-ahead 能力和容器管理的关系结合使用。这个特性通过在相同的查询中随意地检索相关的数据作为父数据而减少与数据库的交互。如果相关的数据要通过使用并发的查询来访问的话，这种方法可以得到性能的改进。[Gunther]提供了详细的描述以及通过这些特性得到的性能提高的细节。 <br /><br />此外，为了完全优化您的 EJB 组件，当指定隔离级别时要特别注意。尽可能使用最低的隔离级别，并且仍然保持您的数据的完整性。较低的隔离级别可以提供最佳的性能，并且可以降低出现数据库死锁的危险。 <br /><br />这是目前最有争议的最佳实践。已经有大量的文章赞扬 CMP EJB，同样的贬斥声也不绝于耳。然而，这里最基本的问题是数据库开发是困难的。当您开始使用任何持久性解决方案之前，您需要掌握查询以及数据库锁定如何工作这些基础知识。如果您选择使用 CMP EJB，您要确保您已经通过一些书籍（例如 [Brown] 和 [Barcia]）知道如何使用它们。在锁定及争用方面有一些微妙的交互难以理解，但是，在您耗费一定的时间及努力后会将其掌握的。</p><img src ="http://www.blogjava.net/Kaixinhutu/aggbug/42074.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Kaixinhutu/" target="_blank">糊涂</a> 2006-04-20 09:08 <a href="http://www.blogjava.net/Kaixinhutu/archive/2006/04/20/42074.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>需要翻的书</title><link>http://www.blogjava.net/Kaixinhutu/archive/2006/04/10/40251.html</link><dc:creator>糊涂</dc:creator><author>糊涂</author><pubDate>Mon, 10 Apr 2006 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/Kaixinhutu/archive/2006/04/10/40251.html</guid><wfw:comment>http://www.blogjava.net/Kaixinhutu/comments/40251.html</wfw:comment><comments>http://www.blogjava.net/Kaixinhutu/archive/2006/04/10/40251.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Kaixinhutu/comments/commentRss/40251.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Kaixinhutu/services/trackbacks/40251.html</trackback:ping><description><![CDATA[
		<table id="table1" border="1" cellpading="0" border-color="blue">
				<tbody>
						<tr>
								<td>序号</td>
								<td>书名</td>
								<td>备注</td>
						</tr>
						<tr>
								<td>1</td>
								<td>JAVA数据结构</td>
								<td>清华大学出版社</td>
						</tr>
						<tr>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/Kaixinhutu/aggbug/40251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Kaixinhutu/" target="_blank">糊涂</a> 2006-04-10 16:11 <a href="http://www.blogjava.net/Kaixinhutu/archive/2006/04/10/40251.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Socket网络编程初级入门 </title><link>http://www.blogjava.net/Kaixinhutu/archive/2006/04/04/39155.html</link><dc:creator>糊涂</dc:creator><author>糊涂</author><pubDate>Tue, 04 Apr 2006 06:04:00 GMT</pubDate><guid>http://www.blogjava.net/Kaixinhutu/archive/2006/04/04/39155.html</guid><wfw:comment>http://www.blogjava.net/Kaixinhutu/comments/39155.html</wfw:comment><comments>http://www.blogjava.net/Kaixinhutu/archive/2006/04/04/39155.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Kaixinhutu/comments/commentRss/39155.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Kaixinhutu/services/trackbacks/39155.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 事实上网络编程简单的理解就是两台计算机相互通讯数据而已，对于程序员而言，去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了，Java SDK提供一些相对简单的Api来完成这些工作。Socket就是其中之一，对于Java而言，这些Api存在与java.net 这个包里面，因此只要导入这个包就可以准备网络编程了。　    网络编程的基本模型就是客户机到服务器模型，简单的说就是两个进程之间相互通...&nbsp;&nbsp;<a href='http://www.blogjava.net/Kaixinhutu/archive/2006/04/04/39155.html'>阅读全文</a><img src ="http://www.blogjava.net/Kaixinhutu/aggbug/39155.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Kaixinhutu/" target="_blank">糊涂</a> 2006-04-04 14:04 <a href="http://www.blogjava.net/Kaixinhutu/archive/2006/04/04/39155.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>