??xml version="1.0" encoding="utf-8" standalone="yes"?>一区国严二区亚洲三区,亚洲日韩精品无码专区,亚洲黄色在线观看视频http://www.tkk7.com/Kaixinhutu/p涂zh-cnMon, 12 May 2025 19:57:30 GMTMon, 12 May 2025 19:57:30 GMT60AJAX+J2EE开发组l机构管理系l(摘自天极|)http://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42079.htmlp涂p涂Thu, 20 Apr 2006 01:21:00 GMThttp://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42079.htmlhttp://www.tkk7.com/Kaixinhutu/comments/42079.htmlhttp://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42079.html#Feedback0http://www.tkk7.com/Kaixinhutu/comments/commentRss/42079.htmlhttp://www.tkk7.com/Kaixinhutu/services/trackbacks/42079.html 一?概述

AJAX是今q初才问世的新技术,是Asynchronous JavaScript and XML的羃写。它是一l开发Web应用E序的技术,它ɋ览器可以ؓ用户提供更ؓ自然的浏览体验。每当需要更新时Q客LWeb面的修Ҏ(gu)异步的和逐步增加的。这PAJAX在提交Web面内容时大大提高了用户界面的速度。在ZAJAX的应用程序中没有必要长时间等待整个页面的h。页面中需要更新的那部分才q行更改Q如果可能的话,更新是在本地完成的,q且是异步的?br />
J2ee是一U用来开发分布式pȝ的体pȝ构。它主要是用Javacd发业务实体。通过JSP来连接应用服务器?br />
本文开发一个组l机构管理小pȝQ通过q个实例来介l如何用Ajax开发WEB应用E序。本pȝh增加、修攏V删除组l机构的功能。同时给机构分配人员Q能增加、修攏V删除h员?br />
二?界面设计

树结构是大多软gpȝ中常采用的结构Ş式。由于树型结构层ơ分明、上下关系清楚、且展开收羃表达信息方便、界面也较美观,所以是大家热衷于用此结构。组l机构管理是一般Y件基本具有的。组l机构是指公司的l织l构。集团公司可包括分公子公司,公司下面又有U室。员工归属于所在的公司。系l运行后的界面如下:

orgManager.htm是组l机构管理的主页面。WEB应用E序界面设计是非帔R要的。如何布局、么Ll可直接体现一个h的设计水q?br />
l织机构主要包括树结构、组l机构编辑、h员编辑等三大块,如何分成三块呢,然而一般树型结构的H体常先二块Q树型结构独占一块,另一块又分成上下二部分,上面是机构编码,下面是h员编码。固可以把页面划分成如下囑Ş式:

树结构区1
l织~码?
人员理?


昄我们是通过表来实现。这是一个二行二列的表,且第一、二行的左边列合q单元格。代码如下:

Q?TABLE border="1" width="100%" height="100%"Q?br />
QTRQ?br />
QTD rowspan="2"Q<FONT face="宋体"Q</FONTQ</TDQ?br />
QTDQ</TDQ?br />
Q?TRQ?br />
QTRQ?br />
QTDQ</TDQ?br />
Q?TRQ?br />
Q?TABLEQ?/td>


我们?区(单元|上加上一个DIVQ因为DIV可以动态地滚动Qƈ且可以插入其它控件。DIV的id?divTree"Q且风格讄为溢出时自动滚动Q宽与高都ؓ100%Q及满区域。代码如下:

Qdiv id="divTree" style="width:100%; height:100%;background-color:#f5f5f5;border :1px solid Silver;overflow:auto;"Q?br />
Q?divQ?/td>


我们?区(单元|上也加上一个DIVQ在DIV里再插入一个表根{表g放下控gQ这很简单,׃详细说了?br />
我们?区(单元|上加上一个DIV。此DIV的id? divContent "Q且风格讄为竖直溢出时自动滚动Q宽与高都ؓ100%Q及满区域,此DIV用来装蝲人员信息;在DIV里再插入一个表? 此table的id? tbList "Q是用来输入、显CZh员作息,同时在此表中插入一些如checkbox 、text、select{控件。说明,表的W二列是用来放h员唯一~号的,不显C。代码如下:

Qdiv id="divContent" style="height:100%; overflow-y:auto;" width="100%"Q?br />
Qtable id="tbList" border="1" width="100%"Q?br />
Qtr seqNo="1"Q<tdQ?br />
Qtable border="1" width="100%"Q?br />
QtrQ?br />
Qtd width="5%"Q<input type="checkbox" value="on"Q</inputQ?Q?tdQ?br />
Qtd width="0%" style="display:none"Q?Qinput type="text" size="20"Q</inputQ</tdQ?br />
Qtd width="40%"Q<input type="text" size="20"Q</inputQ</tdQ?br />
Qtd width="25%"Q?br />
Qselect size="1" name="D1"Q?br />
Qoption value="0"Q男Q?optionQ?br />
Qoption selected="true" value="1"Q女Q?optionQ?br />
Q?selectQ?br />
Q?tdQ?br />
Q?trQ?br />
Q?tableQ?

Q?tdQ</trQ?br />
Q?tableQ?br />
Q?divQ?

三?前端面的主要编?br />
1. 树的实现

在WEB上实现树l构Q同h们是通过Ajax来实现的。树上可以显C定义的图标,可以插入、删除、结炏Vƈ且结点可LUd。这里我们不重点讲树的实现技术,我们已经装好了Q你只要按要求去改动是了?

1) 键接树型文g

在<headQ与Q?headQ之间键接我们的与树有关的文? 代码如下Q?br />

Qlink rel="STYLESHEET" type="text/css" href="css/dhtmlXTree.css"Q?br />
Qscript src="js/dhtmlXCommon.js"Q</scriptQ?br />
Qscript src="js/dhtmlXTree.js"Q</scriptQ?


2) 装蝲Ҏ(gu)

在页面的文档打开时装载自定义Ҏ(gu), preLoadImagesҎ(gu)实现树控件的图标定义QdoOnLoad实现树控件的图标定义代码如下Q?br />
Qbody onload="preLoadImages();doOnLoad();"Q?/td>


3) ~写Ҏ(gu)

//doOnLoad实现装蝲q显C树。设|树属性等?br />
function doOnLoad(){

 OrgTree=new dhtmlXTreeObject(document.getElementById('divTree'),"100%","100%",0);

 //dhtmlXTreeObject是树对象Q通过新徏对象Q指定树昄的DIV可定义树?br />
 OrgTree.setImagePath("imgs/");//讄树的囄所在位|?br />
 OrgTree.setDragHandler();//讄树结Ҏ(gu)?br />
 OrgTree.enableDragAndDrop(true) //讄树结Ҏ(gu)否可拖动

 OrgTree.setDragHandler(myDragHandler); //讄树结Ҏ(gu)动时所执行的方?br />
 OrgTree.setOnClickHandler(mySelectHandler); //讄树单L所执行的方?br />
 //OrgTree.setXMLAutoLoading("Org.jsp");//装蝲树结Ҏ(gu)据。数据来源如Org.jsp所q回的XML格式的字W串Q数据是动态装载,且当展开时才装蝲?br />
 OrgTree.loadXML("root.xml?0");//装蝲树结Ҏ(gu)据。数据来源root.xml文gQƈ且从xml文g的ID号ؓ0处读取数据?br />
 //OrgTree.loadXML("Org.jsp");//装蝲树结Ҏ(gu)据。数据来源如Org.jsp所q回的XML格式的字W串,q且是一ơ性全部装载数据?

}

//preLoadImagesҎ(gu)实现树控件的图标定义

function preLoadImages(){

 var imSrcAr = new Array("line1.gif","line2.gif","line3.gif","line4.gif","minus2.gif","minus3.gif",

"minus4.gif","plus2.gif","plus3.gif","plus4.gif","book.gif","books_open.gif","books_close.gif",

"magazine_open.gif","magazine_close.gif","tombs.gif","tombs_mag.gif","book_titel.gif")

 var imAr = new Array(0);

 for(var i=0;iQimSrcAr.length;i++){

imAr[imAr.length] = new Image();

imAr[imAr.length-1].src = "imgs/"+imSrcAr[i]

 }

}


 l织理的实?br />
l织可以增加、删除、编辑。同时当选择树结Ҏ(gu)应该把组l显C出来供~辑Q查看。ؓ了实现这些功能,你只要按要求L动就是了?br />
1) 全局变量的定?br />
许多地方我们要用C些公共变量,我们在<scriptQ与Q?scriptQ之间定义全局变量, 代码如下Q?br />

var OrgTree = null; //l织树Dom

var nextSeq = 0;//人员理的顺序号Q流水号Q?br />
var personDom;//人员Dom

var CurrNodeId;//当前l点Id



2) 初始?br />
当页面打开时我们要控g好那部分该显C,那部分要隐藏。且对全局变量的赋值等,l织cd装蝲。在面的文档打开时装载自定义Ҏ(gu)initQ), initҎ(gu)实现初始化?br />

Qbody onload="init();"Q?/td>



initҎ(gu)实现如下Q?br />

function init(){

 //定义personDomZ个XMLDOM'对象

 personDom= new ActiveXObject('Microsoft.XMLDOM');

 personDom.async = false;

 //定义stylesheetZ个XMLDOM'对象Q且stylesheet为personDom定昄风格

 stylesheet = new ActiveXObject('Microsoft.XMLDOM');

 stylesheet.async = false;

 stylesheet.load("addOrgPerson.xsl"); //装蝲stylesheet的风格定义文?br />
 //装蝲l织cd数据

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=GetOrgType", false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send();

 retXml=xmlhttp.responseText;

 // alert(retXml);

 //把组l类型插入下拉列表控件中

 var OrgDoc = new ActiveXObject('Microsoft.XMLDOM');

 OrgDoc.async = false;

 OrgDoc.loadXML(retXml);

 var root = OrgDoc.documentElement;

 oNodeList = root.childNodes;

 txtType.options.length =oNodeList.length;

 for (var i=0; iQoNodeList.length; i++)

 {

Item = oNodeList.item(i);

var OrgTypeId=Item.childNodes(0).text;

var OrgTypeName=Item.childNodes(1).text;

txtType.options[i].value=OrgTypeId;

txtType.options[i].text=OrgTypeName;

// txtType.options[0].

 }

}



3) ~写树拖动及选择l点的方?br />

// myDragHandler实现树结Ҏ(gu)动时重新指定父子关系?br />
function myDragHandler(idFrom,idTo){

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=moveOrg&orgId=" + idFrom + "&newparentOrgId=" + idTo, false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send();

 retXml=xmlhttp.OrgponseText;

 return true;

}

// mySelectHandler实现选择树结点对pȝ的控Ӟ同时昄l织信息及该l织下的人员?br />
function mySelectHandler(id){

 tbOrg.style.display="block";

 divOrgMemo.style.display="none";

 divOrgInfo.style.display="none";

 if(id==1)

 {

divOrgMemo.style.display="block";

div1.style.display="none";

div2.style.display="none";

div3.style.display="none";

divContent.style.display="none";

div5.style.display="none";

 }

 else

 {

divOrgInfo.style.display="block";

div1.style.display="block";

div2.style.display="block";

div3.style.display="block";

divContent.style.display="block";

div5.style.display="block";

 }

 CurrNodeId=id;

 //装蝲l织信息q显C在~码和名U的文本控g上?

 loadOrg(id);

 //装蝲某组l下人员信息

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=GetPerson&orgId=" + id, false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send();

 retXml=xmlhttp.responseText;

 personDom.loadXML (retXml);

 //lh员信息的每行加上序号

 for(var i=0; iQpersonDom.documentElement.childNodes.length; i++){

personDom.documentElement.childNodes[i].setAttribute("seqNo", nextSeq);

nextSeq++;

 }

 //人员信息昄在divContent上面

 divContent.innerHTML = personDom.transformNode(stylesheet);

};

//装蝲l织信息q显C在~码和名U的文本控g上?br />
function loadOrg(OrgId){

 if(OrgId == null){

OrgId = OrgTree.getSelectedItemId();

 }

 if(OrgId == ""){

tbOrg.style.display = "none";

return;

 }

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=loadOrg&OrgId=" + OrgId, false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send();

 retXml=xmlhttp.responseText;

 var OrgDoc = new ActiveXObject('Microsoft.XMLDOM');

 OrgDoc.async = false;

 OrgDoc.loadXML(retXml);

 if(OrgId != 1){

txtCode.value = OrgDoc.selectSingleNode("http://OrgCode").text;

txtName.value = OrgDoc.selectSingleNode("http://OrgName").text;

 }

 tbOrg.style.display = "block";

}



4) 建立l织

l织建立主要是通过调用XMLHTTP对象来实现。我们主要学会如何调用XMLHTTP。组l徏立应该在后台实现Q把l织信息插入数据库中。这里我们通过JSP来实现。我们的Org.jsp 文g中有个createOrgҎ(gu)Q该Ҏ(gu)传递一个父ID?br />

function createOrg(parentOrgId){

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=createOrg&parentOrgId=" + parentOrgId, false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send();

 retXml=xmlhttp.responseText;

 var orgId = (new Number(retXml)).toString();

 return orgId;

}


5) 删除l织

l织删除同样是调用Org.jsp 文g中的deleteOrgҎ(gu)来实玎ͼ该方法传递所删除的结点ID?br />
function deleteOrg(){

 var OrgId = OrgTree.getSelectedItemId();

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=deleteOrg&OrgId=" + OrgId, false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send();

}


6) ~辑l织

l织修改是调用Org.jsp 文g中的modifyOrgҎ(gu)来实玎ͼ该方法传递所修改的结点ID。同时修改的数据通过自定义的XML格式的字W串传?q时通过send字符串来实现。修改前数据一律要验证其合法性,q提C错误信息?br />
function modifyOrg(){

 if(OrgTree.getSelectedItemId() == ""){

return "N";

 }

 if(txtCode.value == ""){

alert("误入编码!");

return "N";

 }

 if(txtName.value == ""){

alert("误入名Uͼ");

return"N";

 }

 var OrgId = OrgTree.getSelectedItemId();

 var OrgKind;

 //alert(txtType.options[txtType.selectedIndex].value)

 var strModify = "Q?xml version='1.0' encoding='gb2312'?Q? +

 "QdataQ? +

 "QOrgCodeQ<![CDATA[" + txtCode.value + "]]Q</OrgCodeQ? +

 "QOrgNameQ<![CDATA[" + txtName.value + "]]Q</OrgNameQ? +

 "QOrgKindQ<![CDATA[" + txtType.options[txtType.selectedIndex].value+ "]]Q</OrgKindQ? +

 "Q?dataQ?;

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=modifyOrg&OrgId=" + OrgId, false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send(strModify);

 OrgTree.setItemText(OrgTree.getSelectedItemId(),txtName.value);

}
3. 人员理的实?br />
人员可以增加、删除、编辑。同时当选择树结Ҏ(gu)应该把h员显C出来供~辑、查?.....

1) 增加人员

人员增加实现的原理是在personDom中加入结点peorsoneQ该l点相当于表的一行,讄属性。同时在peorsone中不l地加入其它l点Q代表数据库的字D,且必MXLT文g的标号同名。这些结点相当该行的列。最后在表中插入一行,行上插入一列,q显CZ?br />
function addPerson(){

 var seqNo = nextSeq;

 nextSeq++;

 var peorsonNode = personDom.createNode("1", "peorsone","");

 peorsonNode.setAttribute("isNew", "Y");

 peorsonNode.setAttribute("isDelete", "N");

 peorsonNode.setAttribute("seqNo", seqNo);

 personDom.documentElement.appendChild(peorsonNode);

 var PersonId= personDom.createNode("1", "personId", "");

 peorsonNode.appendChild(PersonId);

 var personCode= personDom.createNode("1", "personCode", "");

 peorsonNode.appendChild(personCode);

 var PersonName= personDom.createNode("1", "personName", "");

 peorsonNode.appendChild(PersonName);

 var Sex= personDom.createNode("1", "sex", "");

 peorsonNode.appendChild(Sex);

 var tr = tbList.insertRow(tbList.rows.length);

 tr.setAttribute("seqNo", seqNo);

 var td = tr.insertCell(0);

 td.innerHTML = peorsonNode.transformNode(stylesheet);

}


2) 删除人员

人员删除同样是调用Org.jsp 文g中的deletePersonҎ(gu)来实玎ͼ该方法传递所删除的h员I(y)D。如何确定h员I(y)D是通过d隐藏的IDQƈ扫描整个表,看那些被选中。这里我们要注意是提供多w择的?br />
function deletePerson(){

 for(var i=0; iQtbList.rows.length; i++){

var row=tbList.rows[i].cells[0].children[0].rows[0];

if(row.cells[0].children[0].checked)

{

 var personId=row.cells[1].children[0].value;

 if(personIdQ?)

 {

var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

xmlhttp.open("POST","Org.jsp?mode=deletePerson&personId=" + personId, false);

xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xmlhttp.send();

 }

 tbList.deleteRow(i);

 i--;

}

 }

}


3) ~辑人员

人员修改我们要判定哪些行被修改了。刚增加但没保存的行应该是新增而不是修改的?br />
function save(){

 if( modifyOrg()=="N")

 {

return;

 }

 for(var i=0; iQtbList.rows.length; i++)

 {

var row=tbList.rows[i].cells[0].children[0].rows[0];

var personId=row.cells[1].children[0].value;

var seqNo = tbList.rows[i].getAttribute("seqNo");

var staffNode = personDom.selectSingleNode("http://peorsone[@seqNo='" + seqNo + "']");

var personCode=row.cells[2].children[0].value;

var personName=row.cells[3].children[0].value;

var sex=row.cells[4].children[0].value; //alert(staffN;ode );

if(staffNode.getAttribute("isNew") == "Y")

{

 createPerson(CurrNodeId,personCode,personName,sex);

}

else

{

 var strXML = "Q?xml version='1.0' encoding='gb2312'?Q? +

"QdataQ? +

"QpersonCodeQ<![CDATA[" + personCode+ "]]Q</personCodeQ? +

"QpersonNameQ<![CDATA[" + personName + "]]Q</personNameQ? +

"QsexQ<![CDATA[" + sex+ "]]Q</sexQ? +

"QpersonIdQ<![CDATA[" + personId+ "]]Q</personIdQ? +

"Q?dataQ?;

 //alert(strXML );

 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

 xmlhttp.open("POST","Org.jsp?mode=modifyPerson", false);

 xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

 xmlhttp.send(strXML );

}

 }

}


四?XML与XSL文g设计

XML是种可扩展的标记语言Q它h开攄、可扩展的、可自描q的语言l构Q它已经成ؓ|上数据和文档传输的标准。XSLT的目的是信息内容与 Web 昄分离QHTML 通过按抽象概念(如段落、重点和~号列表Q定义显C来实现讑֤独立性。XSLT用来具体昄控gQ设|控仉根{?br />
Ajax主要使用XML和XSLTq行数据交换与处理?br />
1. 树信息的XML文g(见root.xml文g)

XML是标记语aQ元素必L对出现。树l构中以tree为根l点Q以item为结点体Q属性text指出l点所昄的文本,id指出唯一的所标识受?br />

Q?xml version='1.0' encoding='gb2312'?Q?br />
Qtree id="0"Q?br />
Qitem child="1" text="l织" id="1" Q?br />
Q?itemQ?

Q?treeQ?/td>


q文件ƈ不是必要的,只是Zpȝ能独立运行才加的。事实如果连接了后台数据是不需要的。只要吧OrgTree.loadXML("root.xml?0")改ؓOrgTree.loadXML("Org.jsp")可以了?br />
2. 人员信息XML文g(见peorson.xml文g)

说明![CDATA[]]可在M昄M格式的文本,文本中可插入其它M字符。这文g也不是必要的?br />
3. 人员信息展现的xsl文gQ见addOrgPerson.xsl文gQ?br />
xsl文g同样是XML格式文g。所以一律遵守XML标准。下面对主要的行讲解Q?br />
Q?xml version="1.0" encoding="gb2312"?Q?br />
//q是定义xml文g的首行。用来指明版本及字符?br />
Qxsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl" language="JavaScript"Q?br />
//q里定义了stylesheet 元素。ƈ指出其国际命名的l织及语a?

Qxsl:template match="/"Q?br />
Qxsl:apply-templates select="peorsones"/Q?br />
Q?xsl:templateQ?br />
//上面是匹配的规则?/"表示从根l开始去匚w。匹配到下面的peorsones标记。这是正则表辑ּ有关的学问。我们只要理解就可以?br />
Qxsl:template match="peorsones"Q?br />
//当匹配上peorsones时所要做的事情?br />
Qtable id="tbList" border="1" width="100%"Q?br />
//定义一个id?tbList的表根{此表格是显C在WEB上的

Qxsl:for-each select="peorsone"Q?br />
//循环匚wpeorsone

QtrQ?br />
//定义tbList表格的一行,q在行上增加一个叫seqNo的属性名Qgؓ匚w到的seqNoQ序P

Qxsl:attribute name="seqNo"Q<xsl:value-of select="@seqNo"/Q</xsl:attributeQ?br />
QtdQ?br />
//定义行上的一列,列又d?br />
Qxsl:apply-templates select="."/Q?br />
Q?tdQ?br />
Q?trQ?br />
Q?xsl:for-eachQ?

Q?tableQ?br />
Q?xsl:templateQ?br />
Qxsl:template match="peorsone"Q?br />
Qtable border="1" width="100%"Q?br />
QtrQ?br />
//定义宽ؓ5%的一列,在该列上插入一个checkbox控g

Qtd width="5%"Q?br />
Qinput type="checkbox" value="on" size="10"Q</inputQ?br />
Q?tdQ?br />
//定义一个不昄的列Q在该列上插入一个text控gQtext的gؓ匚w到的personIdQh员I(y)dQ?br />
Qtd style="display:none"Q?br />
Qinput type="text" size="25"Q?br />
Qxsl:attribute name="value"Q<xsl:value-of select="personId"/Q</xsl:attributeQ?br />
Q?inputQ?

Q?tdQ?br />
Qtd width="30%"Q?

Qinput type="text" size="20"Q?

Qxsl:attribute name="value"Q<xsl:value-of select="personCode"/Q</xsl:attributeQ?

Q?inputQ?

Q?tdQ?

Qtd width="40%"Q?

Qinput type="text" size="40"Q?br />
Qxsl:attributename="value"Q<xsl:value-of select="personName"/Q</xsl:attributeQ?

Q?inputQ?br />
Q?tdQ?br />
//定义一个width?8%的列Q在该列上插入一个下拉列表select 控gQselect的值如果匹配到?时则??Q?时则??

Qtd width="28%"Q?br />
Qselect size="1"Q?br />
Qoption value="0"Q?br />
Qxsl:if test=".[sex=0]"Q?br />
Qxsl:attribute name="selected"QtrueQ?xsl:attributeQ?br />
Q?xsl:ifQ?br />
?br />
Q?optionQ?br />
Qoption value="1"Q?br />
Qxsl:if test=".[sex=1]"Q?br />
Qxsl:attribute name="selected"QtrueQ?xsl:attributeQ?br />
Q?xsl:ifQ?

奻I/optionQ?br />
Q?selectQ?br />
Q?tdQ?br />
//定义一列,在该列上插入一个button控gQonclick 事g定义的方法,该方法传递当前单ȝ按纽

Qtd width="*"Q?

Qbutton onclick="openPersonRolePage(this)" style="width: 36; height: 21"Q角Ԍ/buttonQ?br />
Q?tdQ?br />
Q?trQ?br />
Q?tableQ?br />
Q?xsl:templateQ?br />
Q?xsl:stylesheetQ?/td>


五?数据接口的实?/strong>Q见Org.jpg文gQ?br />
Org.JSP文g用来在服务器上运行Java的类与前台web之间架起一座桥。取C间g的接口作用?br />
q里分析部分代码Q?br />

Q?@ page contentType="text/html; charset=GBK" %Q?br />
Q?@ page import="java.sql.*" %Q?br />
Q?@ page import="javax.naming.*" %Q?br />
Q?@ page import="javax.sql.*" %Q?br />
Q?@ page import="tool.*" %Q?br />
Q?@ page import="orgNew.*" %Q?br />
Q?@ page import="org.w3c.dom.*" %Q?br />
//上面主要是引用一些javac?br />
Q?

try{

 //request.setCharacterEncoding("GBK");

 Document doc = XmlTool.createDocumentFromRequest(request);

 //建立web面文档请求的文档对象

 Connection conn = ConnTool.getConnectionFromPool();

 //获取h的方法名

 String mode=request.getParameter("mode");

 //out.println("ccc");

 //如果Ҏ(gu)中没有其它参数则dl织树数?br />
 if(mode == null){

/* int OrgId = Integer.parseInt(request.getParameter("id"));

String str = orgManager.getChildOrg(OrgId, conn);

out.println(str);

*/

 String str = orgManager.getTree(conn);

 //out.println(str);

 out.println(str);

}else if(mode.equals("createOrg")){

 //如果是createOrgҎ(gu)则徏立一个组l?br />
 int parentOrgId = Integer.parseInt(request.getParameter("parentOrgId"));

 //取出传递来的第一个参数parentOrgId

 int OrgId = orgManager.createOrg(parentOrgId, conn);

 //调用orgManager cȝcreateOrgҎ(gu)来徏立一个组l?br />
 out.println(OrgId);

 //q回l果

}

conn.close();

}

catch(Exception e){

 e.printStackTrace();

}

%Q?/td>



六?后台数据的实?/b>

1. 数据l构的定?br />
q里Q我们主要有三个表。一个是l织l构表,一个是人员表personQ一个组lh员关联表orgPerson。组l结构表有OrgCodeQ组l代码)、OrgNameQ组l名Uͼ、orgIdQ组lIdQ? parentOrgIdQ父IdQ。h员表有personCodeQh员代码)、personNameQh员名Uͼ, sexQ性别Q、personIdQh员I(y)dQ。orgPerson表有orgId, personId?br />
2. 数据库的q接

WEB应用E序常用MySQL作后台数据库Q这是因为MySQL单、高效。这里我们也用MySQL作ؓ数据库。Java中用jdbcq接数据库。下面是q接数据库的CODEQ?br />

public static Connection getConnectionFromPool() throws Exception {

 Context ctx = new InitialContext();

 DataSource ds = (DataSource) ctx.lookup("java:/erpds");

 return ds.getConnection();

}

/**

* 取数据库链接对象

* @return Connection 数据库链接对?br />
* @throws Exception

*/

/*

public static Connection getDirectConnection() throws Exception {

 Class.forName("com.sybase.jdbc2.jdbc.SybDriver");

 String url = "jdbc:sybase:Tds:19.64.13.16:4100/wydb?charset=iso_1";

 String user = "sa";

 String password = "2860008";

 Connection conn = DriverManager.getConnection(url, user, password);

 return conn;

}

*/


. 业务逻辑层的实现

后台开发我们用JavacL实现。这里我们开发了一个orgNew包,cd为orgManager。此cd装了与数据库操作有关的方法。通过main可调试程序的正确性?br />
q里l出了新增加一个组l的全部代码和通过XML取得树结构信息的代码Q树l构通过递归实现?br />

package orgNew;// JavacL打的?br />
import tool.*;

import java.sql.*;

import java.util.*; // 引用Javacȝ

public class orgManager {

 public orgManager() { }

 public static void main(String[] args) throws Exception {

Connection conn = tool.ConnTool.getDirectConnection();// 引用数据讉Kc?br />
conn.setAutoCommit(false);

orgManager orgManager1 = new orgManager();

orgManager1.createOrg(0, conn); //试建立l织是否正确

 }

 //建立一个组l?br />
 public static int createOrg(int parentOrgId, Connection conn) throws

 Exception {

String sql = "insert into Org (OrgName, parentOrgId) values('新组l?, ?)";

PreparedStatement pstat = conn.prepareStatement(sql);

pstat.setInt(1, parentOrgId);

pstat.executeUpdate();

pstat.close();

Statement stat = conn.createStatement();

String sql2 = "select max(OrgId) from Org";

ResultSet rs = stat.executeQuery(sql2);

rs.next();

int OrgId = rs.getInt(1);

rs.close();

stat.close();

System.out.println(OrgId);

return OrgId;

 }

}

//通过递归得到l织信息的XML格式的数?br />
public static String getTree(Connection conn) throws

Exception {

 StringBuffer ret = new StringBuffer();//定义可缓冲的字符?br />
 ret.append("Q?xml version='1.0' encoding='gb2312'?Q<tree id='0'Q?);//定义XML格式的头信息

 ret.append(" Qitem child='1' text='l织' id='1' Q?);//插入l点体。注树结点以item为标?

 ret.append(getChildTree(1, conn));

 ret.append("Q?itemQ?);//l点体结束标?br />
 ret.append("Q?treeQ?);//树结束标?br />
 return ret.toString();//q回字符?br />
}

public static String getChildTree(int OrgId, Connection conn) throws

Exception {

 StringBuffer ret = new StringBuffer();

 String sql = "select a.OrgId, a.OrgName, a.OrgCode,count(b.parentOrgId) from Org a " +

"left join Org b on a.OrgId = b.parentOrgId " +

"where a.parentOrgId = ? " +

"group by a.OrgId, a.OrgName";

 PreparedStatement pstat = conn.prepareStatement(sql);

 pstat.setInt(1, OrgId);

 ResultSet rs = pstat.executeQuery();

 while (rs.next()) {

int childOrgId = rs.getInt(1);

String childOrgName = rs.getString(2);

String childOrgCode = rs.getString(3);

if (childOrgCode == null) {

 childOrgCode = " ";

}

if (childOrgName == null) {

 childOrgName = "新组l?;

}

int childCount = rs.getInt(3);

if (childCount Q?0) {

 childCount = 1;

}

ret.append("Qitem child='" + childCount + "' text='" + childOrgName +

"' id='" +childOrgId + "' code='"+childOrgCode+"'Q?);

ret.append(getChildTree(childOrgId, conn));

ret.append("Q?itemQ?);

 }

 rs.close();

 pstat.close();

 return ret.toString();

}

其它代码见orgManager.java文g?br />
七?ȝ

本文仉过一个实例全面介l了Ajax开发的各个l节。通过与J2ee的结合来实现三层分布式开发的层次划分Q后C前端的调用。数据的d、访问及展现?

通过q个实例Q我们可见,Ajax使WEB中的界面与应用分R数据与呈现分离的分,有利于分工合作、减非技术h员对面的修攚w成的WEB应用E序错误、提高效率、也更加适用于现在的发布pȝ。也可以把以前的一些服务器负担的工作{嫁到客户端,利于客户端闲|的处理能力来处理?br />
Ajax是传lWEB应用E序的一个{变。以前是服务器每ơ生成HTML面q返回给客户端(览器)。Ajax理念的出玎ͼ揭开了无h更新面时代的序q,q有代替传统web开发中采用form(表单)递交方式更新web面的趋势,可以是一个里E碑?br />
MQAjax适用于交互较多,频繁L据,数据分类良好的WEB应用?/p>

p涂 2006-04-20 09:21 发表评论
]]>
详解XML与J2EE之间l合技术的_N --Q摘自赛q网http://www.ccidnet.com/Q?/title><link>http://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42077.html</link><dc:creator>p涂</dc:creator><author>p涂</author><pubDate>Thu, 20 Apr 2006 01:17:00 GMT</pubDate><guid>http://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42077.html</guid><wfw:comment>http://www.tkk7.com/Kaixinhutu/comments/42077.html</wfw:comment><comments>http://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42077.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/Kaixinhutu/comments/commentRss/42077.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/Kaixinhutu/services/trackbacks/42077.html</trackback:ping><description><![CDATA[ <span id="a24cu4w" class="top11">当前QJava 2q_企业版(J2EEQ架构在厂商市场和开发者社Z倍受推崇。作ZU工P可扩展标记语aQXMLQ简化了数据交换、进E间消息交换q一cȝ事情Q因而对开发者逐渐变得有吸引力Qƈ开始流行v来。自Ӟ在J2EE架构中访问或集成XML解决Ҏ(gu)的想法也很诱人。因是强大pȝ架构同高度灵zȝ数据理Ҏ(gu)的结合?br />XML的应用似乎是无穷无尽的,但它们大致上可以分ؓ三大c:<br />1、简单数据的表示和交换(针对XML的简单APIQSAXQ和文档对象模型QDOMQ语法解析,不同的文档类型定义(DTDsQ和概要QschemasQ)<br />2、面向消息的计算QXML-RPCQ远E过E调用)QSOAP协议Q电(sh)子化业务XMLQebXMLQ)<br />3、用L面相兟뀁表C相关的上下文(可扩展样式表语言QXSLQ,可扩展样式表语言转换QXSLTQ)<br />q几cd用在J2EE架构中恰好有天然的对应:数据表示和交换功能是EJBlg模型中持久化服务Qpersistence servicesQ的一部分Q基于消息的通讯由Java消息服务QJMSQAPI来处理,而界面表C正是Java服务器页面(JSPQ和Java Servlets的拿手好戏。在本文中,我们看到当今基于J2EE的应用里QXML是如何在上述几个斚wq行应用的,以及在相x准的未来版本中这些应用将会如何发展?br /><strong>基础Q数据的表示和交?/strong><br />修改甚至写入某个XML文档而经常被d到某个对象模型中。作Z子,假定我们正处理多U类型的媒体Q图品、视频、文本文档等{)Qƈ且用下面q个单的XML DTD来描q这些媒体的元数据:<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 />以下是一个基于上q媒体DTD的XML文档Q描qC与某个课E讲座相关的内容Q?<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 />W?4?/name><desc>与第14讲相关的所有内?/desc><!-- 内容对象"lecture 14"的一套子lg --><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或者企业应用的角度看Q能以这U方式访问数据真是一U福韻I因ؓ它体C高度的可Ud性,使我们与元数据的实际资源本n隔离。这些资源可能来自一个关pL据库pȝ、某U活动媒体服务器或者Web服务器上的一个静态XML文档Q等{?<br />如果xq些数据加蝲到Java应用中,我们可以从当前众多的Java语言XML解析器中选用一个,通过它将XML数据装入一个DOM文档Q最后遍历文档,所有这些数据{换到我们应用pȝ的对象模型中?<br /></p><p></p><p><span id="ua8memk" class="top11">下面是个单的ZDOM的解析程序,可对上述的媒体DTDq行解析。解析器用的是Apache XercesQ?<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文档解析E序Q用上q媒?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 />/** 解析指定的URLQ返回找到的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文档Q将内容转换?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 < assetNodes.getLength();<br /> i++){Node assetNode = assetNodes.item(i);<br />MediaAsset asset = new MediaAsset(assetNode);<br />assets.add(asset);<br />}return assets;<br />}<br />/*** 错误处理代码Qؓzv见省略了Q?/<br />}<br />MediaParsercȝ构造函数初始化了一个Xerces DOM解析器?br />parse()Ҏ(gu)告诉解析器到哪个URLLXML源,然后得到l果文档q返回?br />loadAssets()Ҏ(gu)调用parse()Ҏ(gu)从某个XML源加载文档,<br />然后为文档中扑ֈ的每个“media-asset”节点创Z个MediaAsset对象?br />以下是一个用MediaAssetcȝ例子Q?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 />{// 为简zv见省略后面代?..}}<br /></ccid_code></pre></td></tr></tbody></table><p><br />因ؓ幅的关pȝ略了MediaAssetcȝ详细代码Q但应用模式依然是清晰的。MediaAssetc遍历文档的节点Q?br />当它到不同的子节点Ӟ它用子节点的内容填充自己的成员数据?br />如果它发C一个嵌套的子资源节点,它只需要创Z个新的MediaAsset对象Q?br />然后子资源节点的数据填充到新对象的成员数据中?br />实现上述处理的方法数不胜数。我们还可以使用其他的解析器或解析器架构Q?br />如Java API for XML Parsing (JAXP)?br />除了使用DOM模型外,事g驱动的SAX模型也可用于解析XML?br />cM的程序也可用来生XML数据——前提是允许产生新的数据对象Q在本例中是MediaAssetQ,它可其相应的XML实体插入到DOM中,<br />然后DOM输出C个流中(诸如一个文Ӟ一个SocketQ或者一个HTTPq接...Q?br />q有其他更高层次的标准,可将XML映射到Java对象的过E进一步自动化Q或化)?br />例如Q用XML概要QSchemaQ和XMLl定处理引擎Q?zhn)可以半自动地满x个XML概要的XML数据转变成Java数据对象?br />代表性的引擎是CastorQ是由ExoLab组理的一个开放源代码目的物?br />上述使用Xerces DOM的简单例子仅仅是演示了这一处理q程的底层模型?br />上述CZ表明Q在Java环境中解析或产生XML是非常方便的Q这与J2EE没有必然兌?br />格式化ؓXML的数据可以从应用E序的Q何层ơ流入或输出Q这使得与外部系l的集成性无可限量?br />但我们能否以一U更为直接的方式XML数据源集成到J2EE架构中去呢?<br /></p><p><span id="geeys2y" class="top11"><strong>N消息</strong><br /><br />J2EE架构包含了对JMSQJava消息服务QAPI的访问,以实现面向消息的通信QJ2EE 1.2.1版只需JMS<br />API卛_Q在J2EE 1.3版中JMS基本定型Q此时必ȝ某个兼容J2EEq_的服务器提供一个JMS API ProviderQ?br />q一cȝ异步交互Q与之相对的是:本地或远E方法调用所代表的同步交互)被证明在某些应用环境中是非常有用的?br />某些时候,交互只需要通过间接的请求或回答来实玎ͼ卻I在某些情况下Q发出消息后不可能立x到答复,<br />但我们仍希望当消息发重新在U时Q确保他能收到答复信息?br />面向消息pȝ的实际应用之一是企业之间的松散集成。类gEDIQ电(sh)子文档交换)时代的文档交换,<br />两个企业׃业务的需要而交换消息,此时通常不能Z使用RPC或者RMI、CORBA、DCOM之类的远E方法交互而在两者之间进行紧密集成?br />象JMS APIq样的消息系l允许双方交换基于JMS API的消息蝲P<br />前提是双方在会话的时候均能提供兼容的JMS API服务?br />当前仍然存在的困难是Q双Ҏ(gu)否能从相同的格式或协议?br />q正是XML大显w手的时候。XML明确地被设计来解xcL据交换问?br />——灵丹妙药就是“面向消息的概要表”(Message-Oriented Communication SchemeQ,<br />实质是Z一个双方认同的DTD或schemaQ用XML格式来交换消息蝲荗?br />JMS API支持好几U消息,其中的TextMessage代表文本消息载荷?br />一个简单而有效的XML消息交换Ҏ(gu)是,在一端将我们的XML文档插入TextMessageQ然后在另一端用自制的XML解析E序Q如前面的MediaParserQ解开数据qӞ可选地Q将其{换成Java对象?br />q得我们既可以用JMS API支持的公开预订的消息模型,也可以用JMS API支持的点对点的消息模型来发送XML消息?br />上述Ҏ(gu)有一些局限,因ؓ对于JMSq行时处理而言QXML的内容基本上是不透明的?br />例如QJMS API允许使用Z特定消息头的路由。这很容易理解,其当我们希望XML消息Ҏ(gu)其内定w取不同走向时?br />例如在我们的MediaAsset例子中,我们希望公开讲内容Q但只想把特定的内容传送给那些预订了课E的人,或传送给那些表明可以接受某些媒体格式Q如视频)的h?br />Z发挥JMS API的h(hun)|以便实现上述Z内容的消息\由,我们有必要从XML数据中解析出关键信息Q?br />然后在构造标准JMS API消息头时插入q些信息。这是可行的Q但要实现XML信息我们得额外地写很多代码Q交换消息的双方均如此)?br />Z在XML和JMS API之间架v桥梁Q一些厂商提供了自定义的JMS扩展Q以便直接支持XML消息机制?br />例如QBEApȝ公司ZJ2EE的WebLogic应用服务器特别ؓTextMessage提供了XMLMessage子类Q允许用XPath表达式来qoXML消息?br />不过q是一U专有的扩展Q这要求交换消息的双方必都能处理这cL息?br />为此QSun公司目前正在开发用于XML消息的Java APIQJAXMQ。其目标是提供一个高U别的标准服务,以实现基于ebXML的消息的合成与传送?br />一个JAXM服务提供E序可以这cL息映到适当的物理消息系l(诸如JMS APIQ中厅R?br /><strong>让XML看得?/strong><br />XML同Webpȝ的用L面进行集成显然是一U有益的试。绝大多数的界面E序Q无论是Zq是不基于WebQ都是将数据q行转换Q然后用易读的格式展现给用户?br />用诸如XMLq种“易消化”的格式存放数据简化上q工作,同时它还大大提高了内容的可管理性,接下来我们就可看到这一炏V?br />不过首先要大书一W的是,XML在Web界面层的应用得益于JSP技术的发展?br />一直以来大安希望能清晰地区分Web应用E序的表C层与底层对象模型,JSP框架诞生于这些努力之中(包括早期JHTML试Q?br />JSP框架允许Java代码嵌入到HTML内容中,q样既可以实现动态内容,又不必经怿改Java Servlets的代码?br />在页面中包含Java技术的途径是通过JSP标记QJSP TagsQ,q些标记以XML风格出现。在JSP中,<br />JavaE序以代码片Dc服务器端JavaBeanslg、在服务器端触发特定操作的不透明标记Q标准的或自定义的){Ş式存在?br />当某个用户通过览器请求JSP面Ӟ一个Java应用服务器解析该JSP面Q将其编译成一个Java ServletQ然后执行该Servlet以生答复页面?br />一U直接将XML数据源集成到JSP的界面中ȝҎ(gu)是,XML加蝲到JavaBeanslg中(如同我们在MediaAsset例子中所做的Q,然后在JSP中直接引用这些JavaBeanslg?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.*" %>]]><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>%>]]><TABLE border=0><TBODY><TR><TH>Name</TH><TH>Type</TH><TH>URN</TH></TR><![CDATA[<%while (iter.hasNext()) {asset = (MediaAsset)iter.next();<br>%>]]><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[<%}%>]]></TBODY></TABLE></CCID_CODE></PRE></TD></TR></TBODY></TABLE><BR>上述E序q有一U更z的写法Q那是使用自定义JSP面标记。这h们就可以从JSP面中剔Z码段Q只使用JavaBeanslg和自定义的JSP标记卛_。比如说Qؓ了去掉创析器、加载资源数据到集合中的那段代码Q我们可创徏一个自q标记Q由它在q后完成q些工作?</SPAN></P></TABLE></SPAN></html>]]><meta http-equiv="Cache-Control" content="no-transform" /> <meta http-equiv="Cache-Control" content="no-siteapp" /> <script>var V_PATH="/";window.onerror=function(){ return true; };</script> </head></html></ccid_code></pre></td></tr></tbody></table></span></p></span> <img src ="http://www.tkk7.com/Kaixinhutu/aggbug/42077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/Kaixinhutu/" target="_blank">p涂</a> 2006-04-20 09:17 <a href="http://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE最?jng)_践[12个最重要的]--摘自赛_|?http://www.ccidnet.com/)http://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42074.htmlp涂p涂Thu, 20 Apr 2006 01:08:00 GMThttp://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42074.htmlhttp://www.tkk7.com/Kaixinhutu/comments/42074.htmlhttp://www.tkk7.com/Kaixinhutu/archive/2006/04/20/42074.html#Feedback0http://www.tkk7.com/Kaixinhutu/comments/commentRss/42074.htmlhttp://www.tkk7.com/Kaixinhutu/services/trackbacks/42074.html1. 始终使用 MVC 框架?/strong>
         MVC 框架可以业务逻辑QJava beans ?EJB lg)、控制器逻辑QServlets/Struts 动作Q、表C层QJSP、XML/XSLTQ清晰地分离开来。良好的分层可以带来许多好处。?br />
         MVC 框架对于成功使用 J2EE 是如此重要,以致没有其他最?jng)_践可以与其相提ƈ论。模?视图-控制器(MVCQ是设计 J2EE 应用E序的基。MVC ?zhn)的程序代码简单地划分下面几个部分Q?

负责业务逻辑的代码(x??通常使用 EJB 或者普通的 Java 对象来实玎ͼ?

负责用户界面昄的代码(卌??通常通过 JSP 及标记库来实玎ͼ有时也?XML ?XSLT 来实玎ͼ?

负责应用E序程的代码(x制器??通常使用 Java Servlet 或像 Struts 控制器这LcL实现Q?

如果(zhn)不遵@基本?MVC 框架Q在开发过E中׃出现许多的问题。最常见的问题就是在视图部分d了太多的成分Q例如,可能存在使用 JSP 标记来执行数据库讉KQ或者在 JSP 中进行应用程序的程控制Q这在小规模的应用程序中是比较常见的Q但是,随着后期的开发,q样做将会带来问题,因ؓ JSP 逐步变得来难以维护和调试?

cM圎ͼ我们也经常看到将视图层构建到业务逻辑的情c例如,一个常见的问题是在构徏视图时用的 XML 解析技术直接应用到业务层。业务层应该对业务对??而不是绑定到视图的特定数据表C行操作?

然而,只是h合适的lgq不一定意味着可以使?zhn)的应用程序得到合适的分层。我们常常见C些应用程序包?servlet、JSP ?EJB lg所有这三项Q然而,其主要的业务逻辑却是?servlet 层实现的Q或者应用程序导航是?JSP 中处理的。?zhn)必须q行严格的代码检查ƈ重构(zhn)的代码Q以保应用E序的业务逻辑只在模型层(Model layerQ进行处理,应用E序D只通过控制器层QController layerQ进行处理,而?zhn)的视图(ViewsQ只是将传递过来的模型对象?HTML ?JavaScript 的Ş式表C出来?

2. 在应用程序的每一层都使用自动单元试和测试管理?/strong>

不要只是试(zhn)的囑Ş用户界面QGUI)。分层的试使测试及l护工作变得极其单?

在过ȝ几年中,在方法学领域有了相当大的革新Q例如新出现的被UCؓ AgileQ例?SCRUM [Schwaber] 和极限编E?[Beck1]Q的轻量U方法现在已l得C很普遍的应用。几乎所有的q些Ҏ(gu)中的一个共同的特征是它们都提倡用自动的试工具Q这些工具可以帮助开发h员用更少的时间进行回归测?(regression testing)Qƈ可以帮助他们避免׃不充分的回归试造成的错误,因此可以用来提高E序员的工作效率。实际上Q还有一U被UCؓ Test-First Development [Beck2] 的方法,q种Ҏ(gu)甚至提倡在开发实际的代码之前先~写单元试。然而,在?zhn)试代码之前Q?zhn)需要将代码分割成一些可试的片断。一?大惔?是难以测试的Q因为它不是只实C个简单的易于识别的功能。如果?zhn)的每个代码片断实现多个方面的功能Q这L代码难以保证其完全的正性。?br />
MVC 框架Q以?J2EE 中的 MVC 实现Q的一个优点就是元素的lg化能够(实际上,相当的简单)Ҏ(gu)的应用程序进行单元测试。因此,(zhn)可以方便地对实?bean、会?bean 以及 JSP 独立~写试用例Q而不必考虑其他的代码。现在有许多用于 J2EE 试的框架和工具Q这些框架及工具使得q一q程更加单。例如,JUnitQ是一U由 junit.org 开发的开放源代码工具Q和 CactusQ由 Apache 开发的开放源代码工具Q对于测?J2EE lg都非常有用。[Hightower] 详细探讨了如何在 J2EE 中用这些工兗?

管所有这些详qC怎样d地测试?zhn)的应用程序,但是我们仍然看到一些h认ؓ只要他们试?GUIQ可能是Z Web ?GUIQ或者是独立?Java 应用E序Q,则他们就全面地测试了整个应用E序。GUI 试很难辑ֈ全面的测试,有以下几U原因。首先,使用 GUI 试很难d地测试到pȝ的每一条\径,GUI 仅仅是媄响系l的一U方式,可能存在后台q算、脚本和各种各样的其他访问点Q这也需要进行测试。然而,它们通常q不h GUI。第二,GUI U的试是一U非常粗_度的测试。这U测试只是在宏观水^上测试系l的行ؓ。这意味着一旦发现存在问题,则与此问题相关的整个子系l都要进行检查,q得找?bugQ缺P是非常困难的事情。第三,GUI 试通常只有在整个开发周期的后期才能很好地得到测试,q是因ؓ只有q那个时?GUI 才得到完整的定义。这意味着只有在后期才可能发现潜在?bug。第四,一般的开发h员可能没有自动的 GUI 试工具。因此,当一个开发h员对代码q行更改Ӟ没有一U简单的Ҏ(gu)来重新测试受到媄响的子系l。这实际上不利于q行良好的测试。如果开发h员具有自动的代码U单元测试工P开发h员就能够很容易地q行q些工具以确保所做的更改不会破坏已经存在的功能。最后,如果d了自动构建功能,则在自动构徏q程中添加一个自动的单元试工具是非常容易的事情。当完成q些讄以后Q整个系l就可以有规律地q行重徏Qƈ且回归测试几乎不需要h的参与。?

另外Q我们必d调,使用 EJB ?Web 服务q行分布式的、基于组件的开发得测试单个的lg变得非常必要。如果没?GUI"需要测试,(zhn)就必须q行低Qlower-levelQ测试。最好以q种方式开始测试,省得当?zhn)分布式的组件?Web 服务作ؓ(zhn)的应用E序的一部分Ӟ(zhn)不得不p心思重新进行测试?

MQ通过使用自动的单元测试,能够很快地发现系l的~陷Qƈ且也易于发现q些~陷Q得测试工作变得更加系l化Q因此整体的质量也得以提高?

3. 按照规范来进行开发,而不是按照应用服务器来进行开发?/strong>

要将规范熟记于心Q如果要背离规范Q要l过慎密的考虑后才可以q样做。这是因为当(zhn)背规则的时候,(zhn)所做的事情往往q不是?zhn)应该做的事情?

当?zhn)要背?J2EE 可以允许(zhn)做的事情的时候,q很Ҏ(gu)让(zhn)遭受不q。我们发现有一些开发h员钻研一?J2EE 允许之外的东西,他们认ؓq样做可?E微"改善J2EE的性能Q而他们最l只会发现这样做会引起严重的性能问题Q或者在以后的移植(从一个厂商到另一个厂商,或者是更常见的从一个版本到另一个版本)中会出现问题。实际上Q这U移植问题是如此严重Q以?[Beaton] 此原则UCؓUL工作的基本最?jng)_c?br />
现在有好几个地方如果不直接?J2EE 提供的方法肯定会产生问题。一个常见的例子是开发h员通过使用 JAAS 模块来替?J2EE 安全性,而不是用内|的遵@规范的应用程序服务器机制来进行验证和授权。要注意不要q J2EE 规范提供的验证机Ӟ如果q了此规范Q这是pȝ存在安全漏洞以及厂商兼容性问题的主要原因。类似地Q要使用 servlet ?EJB 规范提供的授权机Ӟq且如果(zhn)要偏离q些规范的话Q要保使用规范定义?APIQ例?getCallerPrincipal()Q作为实现的基础。通过q种方式Q?zhn)能够利用厂商提供的强安全性基设施Q其中,业务要求需要支持复杂的授权规则?

其他常见的问题包括用不遵@ J2EE 规范的持久性机Ӟq得事务管理变得困难)、在J2EEE序中用不适当的J2SE Ҏ(gu)Q例如线E或 singletonQ,以及使用(zhn)自qҎ(gu)解决E序到程序(program-to-programQ的通信Q而不是?J2EE 内在支持的机Ӟ例如 JCA、JMS ?Web 服务Q。当(zhn)将一个遵?J2EE 的服务器UL到其他的服务器上Q或者移植到相同服务器的新版本上Q上q的设计选择会造成无数的问题。唯一要背规范的情况是,当一个问题在规范的范围内无法解决的时候。例如,安排执行定时的业务逻辑?EJB2.1 出现之前是一个问题,在类DL情况下,我们当有厂商提供的解x案时׃用厂商提供的解决Ҏ(gu)Q例?WebSphere Application Server Enterprise 中的 Scheduler 工具Q,而在没有厂商提供的解x案时׃用第三方提供的工兗如果用厂商提供的解决Ҏ(gu)Q应用程序的l护以及其UL到新的规范版本将是厂商的问题Q而不是?zhn)的问题。?br />
最后,要注意不要太早地采用新技术。太q于热衷采用q没有集成到 J2EE 规范的其他部分或者还没有集成到厂商的产品中的技术常会带来灾难性的后果。支持是关键??如果(zhn)的厂商不直接支持一U特定的?JSR 中提出的技术,但此技术还没有?J2EE 所接受Q那么?zhn)׃应该采用此技术。毕竟,我们中的大多Ch从事解决业务问题Q而不是推q技术的发展?

4. 从一开始就计划使用 J2EE 安全性?/strong>

启用 WebSphere 安全性。这使?zhn)?EJB ?URL 臛_可以让所有授权用戯问。不要问Z??照着做就是了。?br />
在与我们合作的客户中Q一开始就打算启用 WebSphere J2EE 安全性的֮是非常少的,q一点一直让我们感到吃惊。据我们估计大约只有 50% 的顾客一开始就打算使用此特性。例如,我们曾与一些大型的金融机构Q银行、代理等{)合作q,他们也没有打启用安全性。幸q的是,q种问题在部|之前的查时得以解?

不?J2EE 安全性是危险的事情。假设?zhn)的应用程序需要安全性(几乎所有的应用E序都需要)Q?zhn)敢打赌(zhn)的开发h员能够构建出自己的安全性系l,而这个系l比(zhn)从 J2EE 厂商那里买来的更好。这可不是个好的赌注Qؓ分布式的应用E序提供安全性是异常困难的。例如,(zhn)需要用网l安全加密o牌控制对 EJB 的访问。以我们的经验看来,大多数自己构建的安全性系l是不安全的Qƈ且有重大的缺Pq产品pȝ极其脆弱?

一些不使用 J2EE 安全性的理由包括Q担心性能的下降,怿其他的安全性(例如 Netegrity SiteMinderQ可以取?J2EE 安全性,或者是不知?WebSphere Application Server 安全Ҏ(gu)及功能。不要陷入这些陷׃中,其是,管?Netegrity SiteMinder q样的品能够提供优U的安全特性,但是仅仅其自w不可能保护整个 J2EE 应用E序。这些品必M J2EE 应用E序服务器联合v来才可能全面C护?zhn)的系l?

其他的一U常见的不?J2EE 安全性的原因是:Z角色的模型没有提供够的_度讉K控制以满_杂的业务规则。尽事实是q样的,但这也不应该成ؓ不?J2EE 安全性的理由。相反地Q应该将 J2EE 验证?J2EE 角色与特定的扩展规则l合h。如果复杂的业务规则需要做出安全性决{,那就~写相应的代码,其安全性决{要Z可以直接使用的以及可靠的 J2EE 验证信息Q用?ID 和角Ԍ?br />5、创Z所知道?br />

反复的开发工作将使?zhn)能够逐渐地掌握所有的 J2EE 模块。要从创建小而简单的模块开始而不是从一开始就马上涉及到所有的模块?

我们必须承认 J2EE 是庞大的体系。如果一个开发小l只是开始?J2EEQ这很难一下子p掌握它。在 J2EE 中有太多的概念和 API 需要掌握。在q种情况下,成功掌握 J2EE 的关键是从简单的步骤开始做赗?br />
q种Ҏ(gu)可以通过在?zhn)的应用程序中创徏而简单的模块来得到最好的实现。如果一个开发小l通过创徏一个简单的域模型以及后端的持久性机Ӟ也许使用的是 JDBCQ?q且对其q行了完整的试Q这会增Z们的自信心,于是他们会用该域模型去掌握使用 servlet ?JSP 的前端开发。如果一个开发组发现有必要?EJBQ他们也会类似地开始在容器理的持久?EJB lg之上使用单的会话 FacadesQ或者用基?JDBC 的数据访问对象(JDBC-based Data Access ObjectsQDAOQ,而不是蟩q这些去使用更加复杂的构造(例如消息驱动bean和JMSQ?

q种Ҏ(gu)q不是什么新Ҏ(gu)Q但是很有开发组以这U方式来培养他们的技能。相反地Q多数开发组׃试马上构建所有的模块Q同时涉?MVC 中的视图层、模型层和控制器层,q样做的l果是他们往往会陷入进度的压力之中。他们应该考虑一些敏PAgileQ开发方法,例如极限~程QXPQ,q种开发方法采用一U增量学习及开发方法。在 XP 中有一U称?ModelFirst 的过E,q个q程涉及到首先构建域模型作ؓ一U机制来l织和实现用户场景。基本说来,(zhn)要构徏域模型作为?zhn)要实现的用户场景的首要部分,然后在域模型之上构徏一个用L面(UIQ作为用户场景实现的l果。这U方法非帔R合让一个开发组一ơ只学到一U技术,而不是让他们同时面对很多U情况(或者让他们d多书Q,q会令他们崩溃的?

q有Q对每个应用E序层重复的开发可能会包含一些适当的模式及最?jng)_c如果?zhn)从应用程序的底层开始应用一些模式如数据讉K对象和会?FacadesQ?zhn)׃应该在(zhn)的JSP和其他视囑֯象中使用域逻辑?

最后,当?zhn)开发一些简单的模块Ӟ在开始的初期可以对(zhn)的应用E序q行性能试。如果直到应用程序开发的后期才进行性能试的话Q这往往会出现灾难性的后果?

6. 当?EJB lgӞ始终使用会话 Facades?



决不要将实体 bean 直接暴露lQ何用L型。对实体 bean 只可以用本?EJB 接口QLocal EJB interfacesQ?

当?EJB lgӞ使用一个会?Facades 是一个确认无疑的最?jng)_c实际上Q这个通用的实践被q泛地应用到M分布式的技术中Q包?CORBA、EJB ?DCOM。从Ҏ(gu)上讲Q?zhn)的应用程序的分?交叉区域"是底层化,对小块的数据׃多次重复的网l中l造成的时间消耗就少。要辑ֈq个目的的方法就是:创徏大粒度的 Facades 对象Q这个对象包含逻辑子系l,因而可以通过一个方法调用就可以完成一些有用的业务功能。这U方法不但能够降低网l开销Q而且?EJB 内部通过为整个业务功能创Z个事务环境也可以大大地减对数据库的讉Kơ数?

EJB 本地接口Q从 EJB 2.0 规范开始用)为共存的 EJB 提供了性能优化Ҏ(gu)。本地接口必被(zhn)的应用E序昑ּ地进行访问,q需要代码的改变和防止以后配|?EJB 旉要应用程序的改变。由于会?Facades 和它包含的整?EJB 对于彼此来说都应该是本地的,我们对会?Facades 后面的实?bean 使用本地接口。然而,会话 Facades 本n的实玎ͼ典型例子如无状态会?beanQ应该设计ؓq程接口?

Z性能的优化,可以一个本地接口添加到会话 Facades。这样做利用了这样一个事实:在大多数情况下(臛_?Web 应用E序中)Q?zhn)?EJB 客户端和 EJB 会共同存在于同一?Java 虚拟机(JVMQ中。另外一U情况,如果会话 Facades 在本地被调用Q可以?J2EE 应用服务器配|优化(configuration optimizationsQ,例如 WebSphere 中的"No Local Copies"。然而,(zhn)必L意到q些可供选择的方案会交互方法从按g递(pass-by-valueQ改变ؓ按引用传递(pass-by-referenceQ。这可能会在(zhn)的代码中生很微妙的错误。当(zhn)要利用q些Ҏ(gu)Ӟ(zhn)应该在一开始就考虑其可行性。?br />
如果在?zhn)的会?Facades 中用远E接口(而不是本地接口)Q?zhn)也可以将同样的会?Facades ?J2EE 1.4 中以兼容的方式作?Web 服务来配|。这是因?JSR 109QJ2EE 1.4 中的 Web 服务部v部分Q要求用无状态会?bean 的远E接口作?EJB Web 服务?EJB 实现的接口。这样做是值得的,因ؓq样做可以ؓ(zhn)的业务逻辑增加客户端类型的数量?

7. 使用无状态会?beanQ而不是有状态会?bean

q样做可以(zhn)的pȝl得起错误的l止。?HttpSession 存储和用L关的状态?

以我们的观点看来Q有状态会?bean 的概念已l过时了。如果?zhn)仔细对其考虑一下,一个有状态会?bean 实际上与一?CORBA 对象在体pȝ构上是完全相同的Q无非就是一个对象实例,l定C个服务器Qƈ且依赖于服务器来理其生命周期。如果服务器关闭了,q种对象也就不存在,那么q个 bean 的客L的信息也׃存在?

J2EE 应用服务器ؓ有状态会?bean 提供的故障{U(failoverQ能够解决一些问题,但是有状态的解决Ҏ(gu)没有无状态的解决Ҏ(gu)易于扩展。例如,?WebSphere Application Server 中,Ҏ(gu)状态会?bean 的请求,是通过寚w|无状态会话的成员集群q行q加蝲来实现。相反地QJ2EE 应用服务器不能对有状?bean 的请求进行^衡加载。这意味着(zhn)的集群中的服务器的加蝲q程会是不均衡的。此外,使用有状态会?bean 会再添加一些状态到(zhn)的应用服务器上Q这也是不好的做法。这样就增加了系l的复杂性,q且在出现故障的情况下问题变得复杂化。创建健壮的分布式系l的一个关键原则是量使用无状态行为?

因此Q我们徏议对大多数应用程序用无状态会?bean Ҏ(gu)。Q何在处理旉要用的与用L关的状态应该以参数的Ş式传送到 EJB 的方法中Qƈ且通过使用一U机制如 HttpSession 来存储它Q或者从持久性的后端存储Q例如通过使用实体 bean)作ؓ EJB 事务的一部分来进行检索。在合适的情况下,q个信息可以~存到内存中Q但是要注意在分布式的环境中保存q种~存所潜在的挑战性。缓存非帔R合于只L据?

MQ?zhn)要确保从一开始就要考虑到可伸展性。检查设计中的所有设惻Iq且考虑到当(zhn)的应用E序要在多个服务器上q行Ӟ是否也可以正常运行。这个规则不但适合上述情况的应用程序代码,也适用于如 MBean 和其他管理界面的情况下?

避免使用有状态性不只是?IBM/WebSphere 的徏议,q是一个基本的 J2EE 设计原则?

8. 使用容器理的事?/strong>

学习一?J2EE 中的两阶D|交事务,q且使用q种方式Q而不是开放?zhn)自己的事务管理。容器在事务优化斚w几乎L比较好的?

使用容器理的事务(CMTQ提供了两个关键的优势(如果没有容器支持q几乎是不可能的Q:可组合的工作单元和健壮的事务行ؓ?

如果(zhn)的应用E序代码昑ּC用了开始和l束事务Q也怋?javax.jts.UserTransaction 或者甚x本地资源事务Q,而将来的要求需要组合模块(也许会是代码重构的一部分Q,q种情况下往往需要改变事务代码。例如,如果模块 A 开始了一个数据库事务Q更新数据库Q随后提交事务,q且有模?B 做出同样的处理,误虑一下当(zhn)在模块 C 中尝试用上qC个模块,会出C么情况呢Q现在,模块 C 正在执行一个逻辑动作Q而这个动作实际上调用两个独立的事务。如果模?B 在执行中p|了,而模?A 的事务仍然能被提交。这是我们所不希望出现的行ؓ。如果,相反圎ͼ模块 A 和模?B 都?CMT 的话Q模?C 也可以开始一?CMTQ通常通过配置描述W)Qƈ且在模块 A 和模?B 中的事务是同一个事务的隐含部分Q这样就不再需要复杂的重写代码的工作了?

如果(zhn)的应用E序在同一个操作中需要访问多U资源,(zhn)就要用两阶段提交事务。例如,如果?JMS 队列中删除一个消息,q且随后更新Zq条消息的纪录,q时Q要保证q两个操作都会执行或都不会执行就变得ؓ重要。如果一条消息已l从队列中被删除Q而系l没有更C此消息相关的数据库中的纪录,那么q种pȝ是不E_的。一些严重的客户及商业纠Uh自不一致的状态?

我们时常看到一些客户应用程序试囑֮C们自q解决Ҏ(gu)。也怼通过应用E序的代码在数据库更新失败的时?"撤销"寚w列的操作。我们不提倡这样做。这U实现要比?zhn)最初的惌要复杂得多,q且q有许多其他的情况(惌一下如果应用程序在执行此操作的q程中突然崩溃的情况Q。作为替代的方式Q应该用两阶段提交事务。如果?zhn)使?CMTQƈ且在一个单一?CMT 中访问两阶段提交的资源(例如 JMS 和大多数数据库)QWebSphere 会处理所有的复杂工作。它?yu)确保整个事务被执行或者都不被执行Q包括系l崩溃、数据库崩溃或其他的情况。其实现在事务日志中保存着事务状态。当应用E序讉K多种资源的时候,我们怎么使用 CMT 事务的必要性都不ؓq?
9、将jsp作ؓ表示层的首?br />只有在需要多U表C出类型,q且输出cd被一个单一的控制器及后端支持时才?XML/XSLT?

我们常听C些争Qؓ什么?zhn)选择 XML/XSLT 而不?JSP 作ؓ表示层技术。选择 XML/XSLT 的h的观Ҏ(gu)QJSP" 允许(zhn)将模型和视图؜合在一?Q?XML/XSLT 不会有这U问题。遗憄是,q种观点q不完全正确Q或者至不像白与黑那样分的清楚。实际上QXSL ?XPath 是编E语a。XSL 是图灵完成的QTuring-completeQ,管它不W合大多Ch定义的编E语aQ因为它是基于规则的Qƈ且不具备E序员习惯的控制工具?

现在的问题是既然l予了这U灵zL,开发h员就会利用这U灵zL。尽每个h都认?JSP 使开发h员容易在视图中加?cM模型"的行为,而实际上Q在 XSL 中也有可能做Z些同L事情。尽从 XSL 中进行访问数据库q样的事情会非常困难Q但是我们曾l见到过一些异常复杂的 XSLT 样式表执行复杂的转换Q这实际上是模型代码?

然而,应该选择 JSP 作ؓ首选的表示技术的最基本的原因是QJSP 是现在支持最q泛的、也是最被广泛理解的 J2EE 视图技术。而随着自定义标记库、JSTL ?JSP2.0 的新Ҏ(gu)的引入Q创?JSP 变得更加Ҏ(gu)Qƈ且不需要Q?Java 代码Q以及可以将模型和视图清晰的分离开。在一些开发环境中Q如 WebSphere StudioQ加入了?JSPQ包括对调试的支持)的强大支持,q且许多开发h员发C?JSP q行开发要比?XLS 单,一些支?JSP 的图形设计工具及其他特征Q尤其在 JSF q样的框架下Q得开发h员可以以所见即所得的方式q行 JSP 的开发,而对?XSL 有时不容易做到?

最后一个要谨慎考虑使用 JSP 的原因是速度问题。在 IBM 所作的Ҏ(gu) XSL ?JSP 相对速度的性能试昄Q在大多数情况下QJSP 在生成同L HTML 的时候,要比 XSL 快好几倍,甚至使用~译q的 XSL 也是如此。尽多数情况下q不是问题,但在性能要求很高的情况下Q这׃成ؓ问题?

然而,q也不能_(zhn)永q也不要使用 XSL。在一些情况下QXSL 能够表示一l固定的数据Qƈ且可以基于不同的样式表来以不同的方式昄q些数据的能力是昄视图的最佌x案。然而,q只是一U例外的情况Q而不是通用的规则。如果?zhn)只是生?HTML 来表达每一个页面,那么在大多数情况下,XSL 是一U不必要的技术,q且Q它l?zhn)的开发h员所带来的问题远比它所能解决的问题多?

10. 当?HttpSession Ӟ量只将当前事务所需要的状态保存其中,其他内容不要保存?HttpSession 中。?br />


启用会话持久性?

HttpSessions 对于存储应用E序状态信息是非常有用的。其 API 易于使用和理解。遗憄是,开发h员常帔R忘了 HttpSession 的目?---用来保持暂时的用L态。它不是L的数据缓存。我们已l见到过太多的系lؓ每个用户的会话放入了大量的数据(辑ֈ兆字节)。那好了Q如果同时有 1000 个登录系l的用户Q每个用h?1MB 的会话数据,那么需?1G 或者更多的内存用于q些会话。要使这?HTTP 会话数据较小一些,不然的话Q?zhn)的应用程序的性能会下降。一个大U比较合适的数据量应该是每个用户的会话数据在 2K-4K 之间Q这不是一个硬性的规则Q?K 仍然没有问题Q但是显然会?2K 时的速度要慢。一定要注意Q不要 HttpSession 变成数据堆积的场所。?br />
一个常见的问题是?HttpSession ~存一些很Ҏ(gu)再创建的信息Q如果有必要的话。由于会话是持久性的Q进行不必要的序列化以及写入数据是一U很奢侈的决定。相反地Q应该用内存中的哈希表来缓存数据,q且在会话中保存一个对此数据进行引用的关键字。这P如果不能成功d到另外的应用服务器的话,可以重新创建数据?

当谈及会话持久性时Q不要忘记要启用q项功能。如果?zhn)没有启用会话持久性,或者服务器因ؓ某种原因停止了(服务器故障或正常的维护)Q则所有此应用服务的当前用L会话会丢失。这是g令h非常不高兴的事情。用户不得不重新dQƈ且重新做一些他们曾l已l做q的事情。相反地Q如果启用了会话持久性,WebSphere 会自动将用户Q以及他们的会话Q移到另外一个应用服务器上去。用L至不知道会有q种事情的发生。我们曾l见到过一些品系l因为存在于本地代码中o人难以忍受的 bugQ不?IBM 的代码!Q而突然崩溃的情况Q这q种情况下,上述功能仍然可以q行良好。?br />
11. ?WebSphere 中,使用动态缓存,q?WebSphere servlet ~存机制?/strong> 

通过使用q些功能Q系l性能可以得到很大的提高,而开销是很的。ƈ且不影响~程模型?

通过~存来提高性能的好处是众所周知的事情。遗憄是,当前?J2EE 规范没有包括一U用?servlet/JSP ~存的机制。然而,WebSphere 提供了对面以及片断~存的支持,q种支持是通过其动态缓存功能来实现的,q且不需要对应用E序作出M改变。其~存的策略是声明性的Q而且光|是通过 XML 配置描述W来实现的。因此,(zhn)的应用E序不会受到影响Qƈ保持?J2EE 规范的兼Ҏ(gu)和UL性,同时q从 WebSphere ?servlet ?JSP 的缓存机制中得到性能的优化?

?servet ?JSP 的动态缓存机制得到的性能的提高是显而易见的Q这取决于应用程序的Ҏ(gu)。Cox ?Martin [Cox] 指出对一个现有的 RDFQ资源描q格式)站点摘要 (RSS)servletQ当使用动态缓存时Q其性能可以提高 10%。请注意q个实验只涉及到一个简单的 servletQ这个性能的增镉K可能q不能反映一个复杂的应用E序?

Z更多地提高性能Q将 WebSphere servlet/JSP l果~存?WebSphere 插g ESI Fragment 处理器、IBM HTTP Server Fast Response Cache Accelerator (FRCA) ?Edge Server ~存功能集成在一赗对于繁重的Zd的工作负P通过使用q些功能可以得到许多额外的好处?

12. Z提高E序员的工作效率Q将 CMP 实体 bean 作ؓ O/R 映射的首选解x?

通过 WebSphere 框架Qreadahead、缓存、隔ȝ别等Q优化性能。如果可能,有选择的应用一些模式来辑ֈ提高性能的目的,例如 Fast-Lane 阅读?[Marinescu]?

对象/关系QO/RQ映是使用 Java 创徏企业U的应用E序的基。几乎每?J2EE 应用E序都需要一些类型的 O/R 映射。J2EE 厂商提供一U?O/R 映射机制Q这U机制在不同的厂商间是可UL的,高效的,q且能够被一些标准及工具很好地支持。这是 EJB 规范中的 CMPQ容器管理的持久性)部分?

早期?CMP 实现以表C?jng)_不支持许?SQL l构而著U。然而,随着 EJB 2.0 ?2.1 规范的出玎ͼ以及被一些厂商所采纳Qƈ且随着?IBM WebSphere Studio Application Developer 的出玎ͼq些问题已经不再是问题了?

CMP EJB lg现在已经被广泛地应用于许多高性能的应用程序中。WebSphere 包括一些优化功能以提高 EJB lg的性能Q优化功能包括:对生命周期的~存?read-ahead 能力。这两者优化功能都是配|时的选项Qƈ且不需要对应用E序q行修改或者媄响可UL性?

处于~存状态的生命周期~存 CMP 状态数据ƈ提供Z旉的无效性。从处于~存状态的生命周期得到的性能提高可以辑ֈ选项 A 的缓存性能Qƈ且仍然可以ؓ(zhn)的应用E序提供可展性。Read-ahead 能力和容器管理的关系l合使用。这个特性通过在相同的查询中随意地索相关的数据作ؓ父数据而减与数据库的交互。如果相关的数据要通过使用q发的查询来讉K的话Q这U方法可以得到性能的改q。[Gunther]提供了详l的描述以及通过q些Ҏ(gu)得到的性能提高的细节?

此外Qؓ了完全优化?zhn)?EJB lgQ当指定隔离U别时要特别注意。尽可能使用最低的隔离U别Qƈ且仍然保持?zhn)的数据的完整性。较低的隔离U别可以提供最佳的性能Qƈ且可以降低出现数据库死锁的危险?

q是目前最有争议的最?jng)_c已l有大量的文章赞?CMP EJBQ同L贬斥C不绝于耟뀂然而,q里最基本的问题是数据库开发是困难的。当(zhn)开始用Q何持久性解x案之前,(zhn)需要掌握查询以及数据库锁定如何工作q些基础知识。如果?zhn)选择使用 CMP EJBQ?zhn)要确保(zhn)已经通过一些书c(例如 [Brown] ?[Barcia]Q知道如何用它们。在锁定及争用方面有一些微妙的交互难以理解Q但是,在?zhn)耗费一定的旉及努力后会将其掌握的?/p>

p涂 2006-04-20 09:08 发表评论
]]>
需要翻的书http://www.tkk7.com/Kaixinhutu/archive/2006/04/10/40251.htmlp涂p涂Mon, 10 Apr 2006 08:11:00 GMThttp://www.tkk7.com/Kaixinhutu/archive/2006/04/10/40251.htmlhttp://www.tkk7.com/Kaixinhutu/comments/40251.htmlhttp://www.tkk7.com/Kaixinhutu/archive/2006/04/10/40251.html#Feedback0http://www.tkk7.com/Kaixinhutu/comments/commentRss/40251.htmlhttp://www.tkk7.com/Kaixinhutu/services/trackbacks/40251.html 序号 书名 备注 1 JAVA数据l构 清华大学出版C?/td>

p涂 2006-04-10 16:11 发表评论
]]>
Java Socket|络~程初入门 http://www.tkk7.com/Kaixinhutu/archive/2006/04/04/39155.htmlp涂p涂Tue, 04 Apr 2006 06:04:00 GMThttp://www.tkk7.com/Kaixinhutu/archive/2006/04/04/39155.htmlhttp://www.tkk7.com/Kaixinhutu/comments/39155.htmlhttp://www.tkk7.com/Kaixinhutu/archive/2006/04/04/39155.html#Feedback0http://www.tkk7.com/Kaixinhutu/comments/commentRss/39155.htmlhttp://www.tkk7.com/Kaixinhutu/services/trackbacks/39155.html阅读全文

p涂 2006-04-04 14:04 发表评论
]]>
վ֩ģ壺 ҹҹ۲ӰԺ| ɫѿ| ۺɫ¶| 97ɫ׳Ƶ| ȫƴȫɫȫѴƬ| ѿŮҹƬ| ۺŷۺվ | ޻ɫѵӰ| þþþAVվ | þþƷ鶹| Ļ߾ƷƵѹۿ| ëƬӰƬ| պAVר| þһѲ| ԻƵ߿Ƭ| ޾ƷŮþ7777777| ޹Ʒ˾þþ| ޹Ʒ߹ۿ | wwwһwww| ƷƵ| ޹avŪŵ˸| ޹Ƶþ| һ| ޹Ʒۺϸר| ŮƵ| ˳վӰȷ沥| Ʒþþ| A޾VƷ| ˳߲վ| ɫóվ߹ۿ| ˳77777ɫ߲| AVվ߹ۿ| ޳߲va| Ĺ˾Ʒþ޾ƷA뾫Ʒ | ѾþþƷþþ| ĻѲ| ڵƵ| һƵ| һӰԺ| ƷѾƷ| þþþav|