??xml version="1.0" encoding="utf-8" standalone="yes"?>国产亚洲福利在线视频,亚洲熟妇AV乱码在线观看,久久久久久亚洲精品中文字幕http://www.tkk7.com/RR00/category/2502.html不要埋头苦干Q要学习(fn)Q学?fn),再学习(fn)。。。。? <br> powered by <font color='orange'>R.Zeus</font>zh-cnTue, 27 Feb 2007 22:36:37 GMTTue, 27 Feb 2007 22:36:37 GMT60tileshttp://www.tkk7.com/RR00/articles/62793.htmlR.ZeusR.ZeusThu, 10 Aug 2006 06:51:00 GMThttp://www.tkk7.com/RR00/articles/62793.htmlhttp://www.tkk7.com/RR00/comments/62793.htmlhttp://www.tkk7.com/RR00/articles/62793.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/62793.htmlhttp://www.tkk7.com/RR00/services/trackbacks/62793.html虽然定义的body里有了tagQ但是各自的面q要加,因ؓ(f)q是动态编译以后加?所以每个页面都应该有!

R.Zeus 2006-08-10 14:51 发表评论
]]>
ActionMessageshttp://www.tkk7.com/RR00/articles/62543.htmlR.ZeusR.ZeusWed, 09 Aug 2006 04:36:00 GMThttp://www.tkk7.com/RR00/articles/62543.htmlhttp://www.tkk7.com/RR00/comments/62543.htmlhttp://www.tkk7.com/RR00/articles/62543.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/62543.htmlhttp://www.tkk7.com/RR00/services/trackbacks/62543.html        msgs.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(strMsg, args));
                                                                                                 //关于argsQ如果ApplicationMessages.properties                                                                                               中有Q就取对应的|如果没有Q就用这个args?br />

R.Zeus 2006-08-09 12:36 发表评论
]]>
struts 2个配|文?/title><link>http://www.tkk7.com/RR00/articles/62414.html</link><dc:creator>R.Zeus</dc:creator><author>R.Zeus</author><pubDate>Tue, 08 Aug 2006 11:35:00 GMT</pubDate><guid>http://www.tkk7.com/RR00/articles/62414.html</guid><wfw:comment>http://www.tkk7.com/RR00/comments/62414.html</wfw:comment><comments>http://www.tkk7.com/RR00/articles/62414.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/RR00/comments/commentRss/62414.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/RR00/services/trackbacks/62414.html</trackback:ping><description><![CDATA[ <p><init-param><br />            <param-name>config</param-name><br />            <param-value>/WEB-INF/config/struts/struts-config.xml</param-value><br />        </init-param></p> <p>        <init-param><br />                                  //q里表示所有以account开头的*.do都用下面的配置文gQ而在配置文g?br />                                       Actionmapping不用加上account?br />                                    <br />            <param-name><font style="BACKGROUND-COLOR: #ffffff" color="#ff1493">config/account</font></param-name><br />            <param-value>/WEB-INF/config/struts/struts-config-account.xml</param-value><br />        </init-param><br /><br /><font style="BACKGROUND-COLOR: #ffc0cb"><action-mappings><br />        <action path="/searchAccount" type="com.suzsoft.demo.account.web.AccountAction"<br />                name="AccountForm" scope="request"><br />            <forward name="success" path="/../WEB-INF/jsp/account/searchList.jsp"/><br />            <forward name="failure" path="/../WEB-INF/jsp/loginSuccess.jsp"/><br />        </action> </font><font style="BACKGROUND-COLOR: #ffffff">                                  //注意..,表示上一层目录,因ؓ(f)已经在account下,所以要回去<br />                                                              用tiles׃需要了Q?/font></p> <p> <br /> <font style="BACKGROUND-COLOR: #ffc0cb">    </action-mappings></font> </p> <img src ="http://www.tkk7.com/RR00/aggbug/62414.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/RR00/" target="_blank">R.Zeus</a> 2006-08-08 19:35 <a href="http://www.tkk7.com/RR00/articles/62414.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>三U联下拉菜单实现http://www.tkk7.com/RR00/articles/14936.htmlR.ZeusR.ZeusFri, 07 Oct 2005 08:35:00 GMThttp://www.tkk7.com/RR00/articles/14936.htmlhttp://www.tkk7.com/RR00/comments/14936.htmlhttp://www.tkk7.com/RR00/articles/14936.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/14936.htmlhttp://www.tkk7.com/RR00/services/trackbacks/14936.html
三U联下拉菜单实现
zhangv 原创  (参与分:(x)15623Q专家分Q?020)   发表Q?005-05-28 13:31   版本Q?.0   阅读Q?B>1490?

三U联下拉菜单实现(xml+js+struts)
derekzhangv.at.hotmail.com

好不Ҏ(gu)实现的一个三U联菜?喜欢把复杂的问题单化,所以从|上的一些方法中提取ZU相Ҏ(gu)爽的Ҏ(gu) - 

jsp面里只多了2行代?(不过多了两个文g)

目是用struts,所以jspZ(其实q个实现应该在Q何情况下都是可以用的,无论asp,php...)生成:"1个form里含2l?U

联菜? 
从某省某市某?BR>到某省某市某?BR>
步骤:
1.xml数据?也就是保存省市地名层ơ信?
如果没有q个文g可能需要自己做一?从数据库或者文本里提取一个xml文g出来应该不算难事?
再说q样的文件保存在xml文g里迟早会(x)有用处的.
本例?
(city.xml)
==========================
<?xml version="1.0" encoding="gb2312"?>
<provinces>
  <province name="吉林" shortname="?>
    <city name="长春">
      <county name="" />
      <county name="双阳" />
      <county name="农安" />
    </city>
  </province>
  <province name="北京" shortname="?>
    <city name="">
      <county name="" />
      <county name="北京" />
      <county name="东城" />
      <county name="西城" />
   </city>
  </province>
  <province name="p" shortname="?>
    <city name="太原">
      <county name="" />
      <county name="古交" />
      <county name="x" />
      <county name="清徐" />
      <county name="娄烦" />
    </city>
    <city name="大同">
      <county name="" />
      <county name="天镇" />
      <county name="灵丘" />
    </city>
  </province>
</provinces>
==========================

2.javascript(弟的js学的不好,q请各位写个更好更简z的Ҏ(gu))
(selectCity.js)
==========================
var from=["province","city","county"];
var to=["toprovince","tocity","tocounty"];
function selectFrom(num){
if(num==3) return;
var i,j,arrTemp=[];
 for(i=0;i<num;i++)
      arrTemp[i]=document.all(from[i]).options[document.all(from[i]).selectedIndex].text
 with(document.all(from[num])){
  length=0
  var obj=document.all.xmlData.XMLDocument.childNodes[1];
  for(i=0;i<num;i++)
      obj=obj.selectSingleNode(from[i]+'[@name="'+arrTemp[i]+'"]');
  for(i=0;i<obj.childNodes.length;i++)
      options[length++].text=obj.childNodes[i].getAttribute("name");
  onchange=new Function("selectFrom("+(num+1)+")");
  onchange();
 }
}
function selectTo(num){
if(num==3) return;
var i,j,arrTemp=[];
 for(i=0;i<num;i++)
      arrTemp[i]=document.all(to[i]).options[document.all(to[i]).selectedIndex].text
 with(document.all(to[num])){
  length=0
  var obj=document.all.xmlData.XMLDocument.childNodes[1];
  for(i=0;i<num;i++)
      obj=obj.selectSingleNode(from[i]+'[@name="'+arrTemp[i]+'"]');
  for(i=0;i<obj.childNodes.length;i++)
      options[length++].text=obj.childNodes[i].getAttribute("name");
  onchange=new Function("selectTo("+(num+1)+")");
  onchange();
 }
}
==========================

3.面文g:(q里是struts,--q个应该没有关系)
(test.jsp)

==========================
  <script src="selectCity.js"></script>
  <xml id=xmlData src="city.xml" />
<body onload="selectFrom(0);selectTo(0);">
<html:form>
?lt;html:select property="province" ></html:select><html:errors property="province"/>
    <html:select property="city"></html:select><html:errors property="city"/>
    <html:select property="county"></html:select><html:errors property="county"/><br/>
?nbsp;<html:select property="toprovince" ></html:select><html:errors property="toprovince"/>
    <html:select property="tocity"></html:select><html:errors property="tocity"/>
    <html:select property="tocounty"></html:select><html:errors property="tocounty"/>
</html:form>
</body>
==========================

q样的三步就构造了一?1个form里含2l?U联菜?,其实q是满麻烦的.之前q见q一U是在js里徏一个三l数l?


R.Zeus 2005-10-07 16:35 发表评论
]]>
使用struts,ibaits和JSTL开发简侉K用的文件上传系l?/title><link>http://www.tkk7.com/RR00/articles/13963.html</link><dc:creator>R.Zeus</dc:creator><author>R.Zeus</author><pubDate>Sat, 24 Sep 2005 16:20:00 GMT</pubDate><guid>http://www.tkk7.com/RR00/articles/13963.html</guid><wfw:comment>http://www.tkk7.com/RR00/comments/13963.html</wfw:comment><comments>http://www.tkk7.com/RR00/articles/13963.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/RR00/comments/commentRss/13963.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/RR00/services/trackbacks/13963.html</trackback:ping><description><![CDATA[<P><BR>文g上传也是一个老生常谈的问题了。struts提供了很方便的文件上传组Ӟ利用strutsQ很Ҏ(gu)开发文件上传的pȝ。本文结合ibatis和JSTL开发一个简便而通用的文件上传系l。通过本文Q你可以学到如何在struts里配|文件上传功能、struts1.1的动态form配置和用、如果简单的使用ibatisQ如果简单用的JSTL?BR><BR>首先我们要在struts-config里加上一句,来指定(f)时目录以?qing)限制大?BR><BR><controller maxFileSize="2M" tempDir="d:/temp"/> <BR><BR>然后只要在form中加上enctype="multipart/form-data" 可以实现struts的上传了Q十分简单吧Q?BR><BR>下面我们在数据库中徏立一张表?BR><BR>create sequence Attachment_seq;<BR>DROP TABLE ATTACHMENT;<BR>create table Attachment<BR>(<BR>AttachID INT not null, --自动增长?nbsp;AttachFilename VARCHAR2(250) null, --文g?nbsp;AttachFileSize INT not null, --文g大小 AttachMimeType VARCHAR2(70) null, --文gcd AttachDesc VARCHAR2(250) null, --说明 AttachCreationIP VARCHAR2(20) not null, --上传的IP AttachCreationDate TIMESTAMP not null, --创徏旉 AttachModifiedDate TIMESTAMP not null, --文g保存路径 ATTACHFILEPATH VARCHAR2 (250) NOT NULL,<BR>primary key (AttachID)<BR>);<BR>create or replace trigger Attach_trig_autoinc<BR>before insert on Attachment<BR>for each row<BR>begin<BR>if (:new.AttachID is null) then <BR>select Attachment_seq.nextval into :new.AttachID from dual;<BR>end if;<BR>end;<BR><BR><BR>字段的内定w很简单?BR><BR>下面建立ibatis的SQL map文g。徏立标准的insert、update、delete和find的SQL。相信看q前面系列文章的朋友Ҏ(gu)已经很熟(zhn)了?BR><BR><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE sql-mapPUBLIC "-//iBATIS.com//DTD SQL Map 1.0//EN""http://www.ibatis.com/dtd/sql-map.dtd";><sql-map name="attachment"><!-- ============================================= mapped-statement insert ============================================= --><dynamic-mapped-statement name="insertattachmentDao" > insert into ATTACHMENT ( <dynamic prepend=""> <isPropertyAvailable prepend="," property="ATTACHID" > <isNotNull prepend="" property="ATTACHID" > ATTACHID </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHFILENAME" > <isNotNull prepend="" property="ATTACHFILENAME" > ATTACHFILENAME </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHFILEPATH" > <isNotNull prepend="" property="ATTACHFILEPATH" > ATTACHFILEPATH </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHFILESIZE" > <isNotNull prepend="" property="ATTACHFILESIZE" > ATTACHFILESIZE </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHMIMETYPE" > <isNotNull prepend="" property="ATTACHMIMETYPE" > ATTACHMIMETYPE </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHDESC" > <isNotNull prepend="" property="ATTACHDESC" > ATTACHDESC </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHCREATIONIP" > <isNotNull prepend="" property="ATTACHCREATIONIP" > ATTACHCREATIONIP </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHCREATIONDATE" > <isNotNull prepend="" property="ATTACHCREATIONDATE" > ATTACHCREATIONDATE </isNotNull> </isPropertyAvailable> <isPropertyAvailable prepend="," property="ATTACHMODIFIEDDATE" > <isNotNull prepend="" property="ATTACHMODIFIEDDATE" > ATTACHMODIFIEDDATE </isNotNull> </isPropertyAvailable> </dynamic> ) valueS (<BR><dynamic prepend=""><BR><isPropertyAvailable prepend="," property="ATTACHID" ><BR><isNotNull prepend="" property="ATTACHID" ><BR>#ATTACHID#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILENAME" ><BR><isNotNull prepend="" property="ATTACHFILENAME" ><BR>#ATTACHFILENAME#<BR></isNotNull> <BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILEPATH" ><BR><isNotNull prepend="" property="ATTACHFILEPATH" ><BR>#ATTACHFILEPATH#<BR></isNotNull> <BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILESIZE" ><BR><isNotNull prepend="" property="ATTACHFILESIZE" ><BR>#ATTACHFILESIZE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHMIMETYPE" ><BR><isNotNull prepend="" property="ATTACHMIMETYPE" ><BR>#ATTACHMIMETYPE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHDESC" ><BR><isNotNull prepend="" property="ATTACHDESC" ><BR>#ATTACHDESC#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHCREATIONIP" ><BR><isNotNull prepend="" property="ATTACHCREATIONIP" ><BR>#ATTACHCREATIONIP#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHCREATIONDATE" ><BR><isNotNull prepend="" property="ATTACHCREATIONDATE" ><BR>#ATTACHCREATIONDATE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHMODIFIEDDATE" ><BR><isNotNull prepend="" property="ATTACHMODIFIEDDATE" ><BR>#ATTACHMODIFIEDDATE#<BR></isNotNull><BR></isPropertyAvailable><BR></dynamic>)<BR></dynamic-mapped-statement><BR><BR><!-- =============================================<BR>mapped-statement update <BR>============================================= --><BR><dynamic-mapped-statement name="updateattachmentDao" ><BR>update ATTACHMENT<BR><dynamic prepend="set"><BR><isPropertyAvailable prepend="," property="ATTACHID" ><BR>ATTACHID=#ATTACHID#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILENAME" ><BR>ATTACHFILENAME=#ATTACHFILENAME:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILEPATH" ><BR>ATTACHFILEPATH=#ATTACHFILEPATH:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILESIZE" ><BR>ATTACHFILESIZE=#ATTACHFILESIZE#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHMIMETYPE" ><BR>ATTACHMIMETYPE=#ATTACHMIMETYPE:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHDESC" ><BR>ATTACHDESC=#ATTACHDESC:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHCREATIONIP" ><BR>ATTACHCREATIONIP=#ATTACHCREATIONIP:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHCREATIONDATE" ><BR>ATTACHCREATIONDATE=#ATTACHCREATIONDATE#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHMODIFIEDDATE" ><BR>ATTACHMODIFIEDDATE=#ATTACHMODIFIEDDATE#<BR></isPropertyAvailable><BR></dynamic><BR><dynamic prepend="where"> <BR><isPropertyAvailable prepend="and" property="ATTACHID" ><BR>ATTACHID=#ATTACHID#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHFILENAME" ><BR>ATTACHFILENAME=#ATTACHFILENAME:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHFILEPATH" ><BR>ATTACHFILEPATH=#ATTACHFILEPATH:VARCHAR#<BR></isPropertyAvailable> <BR><isPropertyAvailable prepend="and" property="ATTACHFILESIZE" ><BR>ATTACHFILESIZE=#ATTACHFILESIZE#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMIMETYPE" ><BR>ATTACHMIMETYPE=#ATTACHMIMETYPE:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHDESC" ><BR>ATTACHDESC=#ATTACHDESC:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONIP" ><BR>ATTACHCREATIONIP=#ATTACHCREATIONIP:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONDATE" ><BR>ATTACHCREATIONDATE=#ATTACHCREATIONDATE#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMODIFIEDDATE" ><BR>ATTACHMODIFIEDDATE=#ATTACHMODIFIEDDATE#<BR></isPropertyAvailable><BR></dynamic><BR></dynamic-mapped-statement><BR><BR><!-- =============================================<BR>mapped-statement updateByPrimaryKey <BR>============================================= --><BR><dynamic-mapped-statement name="updateByPrimaryKeyattachmentDao" ><BR>update ATTACHMENT<BR><dynamic prepend="set"><BR><isPropertyAvailable prepend="," property="ATTACHID" ><BR>ATTACHID=#ATTACHID#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILENAME" ><BR>ATTACHFILENAME=#ATTACHFILENAME:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHFILEPATH" ><BR>ATTACHFILEPATH=#ATTACHFILEPATH:VARCHAR#<BR></isPropertyAvailable> <BR><isPropertyAvailable prepend="," property="ATTACHFILESIZE" ><BR>ATTACHFILESIZE=#ATTACHFILESIZE#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHMIMETYPE" ><BR>ATTACHMIMETYPE=#ATTACHMIMETYPE:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHDESC" ><BR>ATTACHDESC=#ATTACHDESC:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHCREATIONIP" ><BR>ATTACHCREATIONIP=#ATTACHCREATIONIP:VARCHAR#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHCREATIONDATE" ><BR>ATTACHCREATIONDATE=#ATTACHCREATIONDATE#<BR></isPropertyAvailable><BR><isPropertyAvailable prepend="," property="ATTACHMODIFIEDDATE" ><BR>ATTACHMODIFIEDDATE=#ATTACHMODIFIEDDATE#<BR></isPropertyAvailable><BR></dynamic><BR><BR><dynamic prepend="where"><BR><isPropertyAvailable prepend="and" property="ATTACHID" ><BR>ATTACHID=#ATTACHID#<BR></isPropertyAvailable><BR></dynamic><BR></dynamic-mapped-statement><BR><BR><!-- =============================================<BR>mapped-statement delete <BR>============================================= --><BR><dynamic-mapped-statement name="deleteattachmentDao" result-class="java.util.HashMap"><BR>delete from ATTACHMENT<BR><dynamic prepend="where"><BR><isPropertyAvailable prepend="and" property="ATTACHID" ><BR><isNotNull prepend="" property="ATTACHID" ><BR>ATTACHID=#ATTACHID#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHFILENAME" ><BR><isNotNull prepend="" property="ATTACHFILENAME" ><BR>ATTACHFILENAME=#ATTACHFILENAME#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property=" ATTACHFILEPATH" ><BR><isNotNull prepend="" property=" ATTACHFILEPATH" ><BR>ATTACHFILEPATH=# ATTACHFILEPATH#<BR></isNotNull><BR></isPropertyAvailable> <BR><isPropertyAvailable prepend="and" property="ATTACHFILESIZE" ><BR><isNotNull prepend="" property="ATTACHFILESIZE" ><BR>ATTACHFILESIZE=#ATTACHFILESIZE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMIMETYPE" ><BR><isNotNull prepend="" property="ATTACHMIMETYPE" ><BR>ATTACHMIMETYPE=#ATTACHMIMETYPE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHDESC" ><BR><isNotNull prepend="" property="ATTACHDESC" ><BR>ATTACHDESC=#ATTACHDESC#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONIP" ><BR><isNotNull prepend="" property="ATTACHCREATIONIP" ><BR>ATTACHCREATIONIP=#ATTACHCREATIONIP#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONDATE" ><BR><isNotNull prepend="" property="ATTACHCREATIONDATE" ><BR>ATTACHCREATIONDATE=#ATTACHCREATIONDATE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMODIFIEDDATE" ><BR><isNotNull prepend="" property="ATTACHMODIFIEDDATE" ><BR>ATTACHMODIFIEDDATE=#ATTACHMODIFIEDDATE#<BR></isNotNull><BR></isPropertyAvailable><BR></dynamic><BR></dynamic-mapped-statement><BR><BR><!-- =============================================<BR>mapped-statement deleteByPrimaryKey <BR>============================================= --><BR><mapped-statement name="deleteByPrimaryKeyattachmentDao" ><BR>delete from ATTACHMENT<BR>where<BR>ATTACHID=#ATTACHID#<BR><BR></mapped-statement><BR><BR><!-- =============================================<BR>mapped-statement find <BR>============================================= --><BR><dynamic-mapped-statement name="findattachmentDao" result-class="java.util.HashMap"><BR>select * from ATTACHMENT<BR><dynamic prepend="where"><BR><isPropertyAvailable prepend="and" property="ATTACHID" ><BR><isNotNull prepend="" property="ATTACHID" ><BR>ATTACHID=#ATTACHID#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHFILENAME" ><BR><isNotNull prepend="" property="ATTACHFILENAME" ><BR>ATTACHFILENAME=#ATTACHFILENAME#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHFILEPATH" ><BR><isNotNull prepend="" property="ATTACHFILEPATH" ><BR>ATTACHFILEPATH=#ATTACHFILEPATH#<BR></isNotNull><BR></isPropertyAvailable> <BR><isPropertyAvailable prepend="and" property="ATTACHFILESIZE" ><BR><isNotNull prepend="" property="ATTACHFILESIZE" ><BR>ATTACHFILESIZE=#ATTACHFILESIZE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMIMETYPE" ><BR><isNotNull prepend="" property="ATTACHMIMETYPE" ><BR>ATTACHMIMETYPE=#ATTACHMIMETYPE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHDESC" ><BR><isNotNull prepend="" property="ATTACHDESC" ><BR>ATTACHDESC=#ATTACHDESC#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONIP" ><BR><isNotNull prepend="" property="ATTACHCREATIONIP" ><BR>ATTACHCREATIONIP=#ATTACHCREATIONIP#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONDATE" ><BR><isNotNull prepend="" property="ATTACHCREATIONDATE" ><BR>ATTACHCREATIONDATE=#ATTACHCREATIONDATE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMODIFIEDDATE" ><BR><isNotNull prepend="" property="ATTACHMODIFIEDDATE" ><BR>ATTACHMODIFIEDDATE=#ATTACHMODIFIEDDATE#<BR></isNotNull><BR></isPropertyAvailable><BR></dynamic><BR><dynamic prepend="order by "><BR><isNotNull prepend="" property="sortOrder" ><BR>$sortOrder$<BR></isNotNull><BR><isNull prepend="" property="sortOrder" ><BR></isNull><BR></dynamic><BR></dynamic-mapped-statement><BR><BR><!-- =============================================<BR>mapped-statement findByPrimaryKey <BR>============================================= --><BR><mapped-statement name="findByPrimaryKeyattachmentDao" result-class="java.util.HashMap"><BR>select * from ATTACHMENT<BR>where<BR>ATTACHID=#ATTACHID#<BR></mapped-statement><BR><BR><!-- =============================================<BR>mapped-statement findcount <BR>============================================= --><BR><dynamic-mapped-statement name="findattachmentDaoCount" result-class="java.lang.Integer"><BR>select count(1) from ATTACHMENT<BR><dynamic prepend="where"><BR><isPropertyAvailable prepend="and" property="ATTACHID" ><BR><isNotNull prepend="" property="ATTACHID" ><BR>ATTACHID=#ATTACHID#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHFILENAME" ><BR><isNotNull prepend="" property="ATTACHFILENAME" ><BR>ATTACHFILENAME=#ATTACHFILENAME#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHFILEPATH" ><BR><isNotNull prepend="" property="ATTACHFILEPATH" ><BR>ATTACHFILEPATH=#ATTACHFILENAME#<BR></isNotNull><BR></isPropertyAvailable> <BR><isPropertyAvailable prepend="and" property="ATTACHFILESIZE" ><BR><isNotNull prepend="" property="ATTACHFILESIZE" ><BR>ATTACHFILESIZE=#ATTACHFILESIZE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMIMETYPE" ><BR><isNotNull prepend="" property="ATTACHMIMETYPE" ><BR>ATTACHMIMETYPE=#ATTACHMIMETYPE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHDESC" ><BR><isNotNull prepend="" property="ATTACHDESC" ><BR>ATTACHDESC=#ATTACHDESC#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONIP" ><BR><isNotNull prepend="" property="ATTACHCREATIONIP" ><BR>ATTACHCREATIONIP=#ATTACHCREATIONIP#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHCREATIONDATE" ><BR><isNotNull prepend="" property="ATTACHCREATIONDATE" ><BR>ATTACHCREATIONDATE=#ATTACHCREATIONDATE#<BR></isNotNull><BR></isPropertyAvailable><BR><isPropertyAvailable prepend="and" property="ATTACHMODIFIEDDATE" ><BR><isNotNull prepend="" property="ATTACHMODIFIEDDATE" ><BR>ATTACHMODIFIEDDATE=#ATTACHMODIFIEDDATE#<BR></isNotNull><BR></isPropertyAvailable><BR></dynamic><BR></dynamic-mapped-statement><BR><BR></sql-map><BR><BR><BR>下一就是徏立数据操作层的类代码<BR><BR>/* * Created on 2003-10-11 * * To change the template for this generated file go to * Window - Preferences - Java - Code Generation - Code and Comments */package com.ewuxi.champion.persistence.dao;<BR>import java.util.HashMap;<BR>import java.util.List;<BR>import com.ewuxi.champion.exception.DaoException;<BR>import com.ibatis.db.sqlmap.SqlMap;<BR>/**<BR>* @author champion<BR>*<BR>*attachment数据库操作对?BR>*/<BR>public class AttachDb {<BR>/**<BR>* @param vo<BR>* @throws DaoException<BR>* 插入一条记?BR>*/<BR>public void insert(HashMap vo) throws DaoException {<BR>try {<BR>SqlMap sqlMap = DaoCommon.getSqlMap(DaoCommon.getDefautDao());<BR>sqlMap.executeUpdate("insertattachmentDao", vo);<BR>} catch (Exception e) {<BR>throw new DaoException(e);<BR>}<BR>}<BR>/**<BR>* @param vo<BR>* @throws DaoException<BR>* 删除一条记?BR>*/<BR>public void delete(HashMap vo) throws DaoException {<BR>try {<BR>SqlMap sqlMap = DaoCommon.getSqlMap(DaoCommon.getDefautDao());<BR>sqlMap.executeUpdate("deleteByPrimaryKeyattachmentDao", vo);<BR>} catch (Exception e) {<BR>throw new DaoException(e);<BR>}<BR>}<BR>/**<BR>* @param vo<BR>* @throws DaoException<BR>* 修改一条记?BR>*/<BR>public void update(HashMap vo) throws DaoException {<BR>try {<BR>SqlMap sqlMap = DaoCommon.getSqlMap(DaoCommon.getDefautDao());<BR>sqlMap.executeUpdate("updateByPrimaryKeyattachmentDao", vo);<BR>} catch (Exception e) {<BR>throw new DaoException(e);<BR>}<BR>}<BR>/**<BR>* @param vo<BR>* @return<BR>* @throws DaoException<BR>* 查找一条记?BR>*/<BR>public HashMap findByPk(HashMap vo) throws DaoException {<BR>try {<BR>SqlMap sqlMap = DaoCommon.getSqlMap(DaoCommon.getDefautDao());<BR>return (HashMap) sqlMap.executeQueryForObject(<BR>"findByPrimaryKeyattachmentDao",<BR>vo);<BR>} catch (Exception e) {<BR>throw new DaoException(e);<BR>}<BR>}<BR>public List find(Object vo) throws DaoException {<BR>try {<BR>SqlMap sqlMap = DaoCommon.getSqlMap(DaoCommon.getDefautDao());<BR>return (List) sqlMap.executeQueryForList("findattachmentDao", vo);<BR>} catch (Exception e) {<BR>throw new DaoException(e);<BR>}<BR>}<BR>}<BR><BR><BR><BR>q一层的代码也是多次见到的老朋友了。事实上对于大多数数据库操作Q我们都只需要上面这么一点代码。然后我们徏立add的actionҎ(gu)<BR><BR>public ActionForward add(<BR>ActionMapping mapping,<BR>ActionForm form,<BR>HttpServletRequest request,<BR>HttpServletResponse response)<BR>throws Exception {<BR>try {<BR><BR>Service.initSet();<BR>if (form instanceof DynaActionForm) {<BR><BR>DynaActionForm fm = (DynaActionForm) form;<BR>FormFile ff = (FormFile) fm.get("upload");<BR>if (ff != null && ff.getFileSize()>0) {<BR>String fileName =<BR>Service.getPath().substring(<BR>0,<BR>Service.getPath().length()<BR>- "/WEB-INF/classes".length())<BR>+ "file/"<BR>+ ff.getFileName();<BR>HashMap map = new HashMap();<BR>map.put(Constattachment.ATTACHDESC, fm.get("desc"));<BR>map.put(Constattachment.ATTACHFILENAME, ff.getFileName());<BR>map.put(<BR>Constattachment.ATTACHMIMETYPE,<BR>ff.getContentType());<BR>map.put(Constattachment.ATTACHCREATIONDATE, new Date());<BR>map.put(Constattachment.ATTACHMODIFIEDDATE, new Date());<BR>map.put(<BR>Constattachment.ATTACHFILESIZE,<BR>String.valueOf(ff.getFileSize()));<BR>map.put(<BR>Constattachment.ATTACHFILEPATH,<BR>"/file/" + ff.getFileName());<BR>map.put(<BR>Constattachment.ATTACHCREATIONIP,<BR>request.getRemoteAddr());<BR>FileManager.saveFile(fileName, ff);<BR>AttachDb attachDb = new AttachDb();<BR><BR>DaoCommon.startTransaction();<BR>attachDb.insert(map);<BR>DaoCommon.commit();<BR>request.setAttribute("url", fm.get("url"));<BR>request.setAttribute(<BR>"fileName",<BR>"/file/" + ff.getFileName());<BR>log.info(ff.getFileName());<BR>return mapping.findForward("success");<BR>}<BR>}<BR>ActionErrors errors = new ActionErrors();<BR>errors.add(<BR>ActionErrors.GLOBAL_ERROR,<BR>new ActionError("errors.general", "请选择一个文?"));<BR>saveErrors(request, errors);<BR>return mapping.findForward("false");<BR>} catch (DaoException e) {<BR>log.error(e, e);<BR>DaoCommon.rollBack();<BR>ActionErrors errors = new ActionErrors();<BR>errors.add(<BR>ActionErrors.GLOBAL_ERROR,<BR>new ActionError("errors.general", "数据库操作错?"));<BR>saveErrors(request, errors);<BR>return mapping.findForward("false");<BR>} catch (FileNotFoundException e) {<BR>log.error(e, e);<BR>ActionErrors errors = new ActionErrors();<BR>errors.add(<BR>ActionErrors.GLOBAL_ERROR,<BR>new ActionError("errors.general", "文g保存错误!"));<BR>saveErrors(request, errors);<BR>return mapping.findForward("false");<BR>} catch (IOException e) {<BR>log.error(e, e);<BR>ActionErrors errors = new ActionErrors();<BR>errors.add(<BR>ActionErrors.GLOBAL_ERROR,<BR>new ActionError("errors.general", "文g操作错误!"));<BR>saveErrors(request, errors);<BR>return mapping.findForward("false");<BR>} catch (Exception e) {<BR>log.error(e, e);<BR>ActionErrors errors = new ActionErrors();<BR>errors.add(<BR>ActionErrors.GLOBAL_ERROR,<BR>new ActionError("errors.general", "意外错误!"));<BR>saveErrors(request, errors);<BR>return mapping.findForward("false");<BR>}<BR><BR>}<BR><BR><BR><BR>从上面可以看出,文g的保存工作很单,只有三句<BR><BR>DynaActionForm fm = (DynaActionForm) form; <BR>FormFile ff = (FormFile) fm.get("upload");<BR>FileManager.saveFile(fileName, ff); <BR><BR>此处有一个DynaActionFormQ通过DynaActionForm我们可以节省一个ActionForm的工作了。当Ӟq也多了一个配|工作。在struts-conifg.xml里加一?BR><BR><BR><!-- upload form bean --><BR><form-bean name="uploadForm"<BR>type="org.apache.struts.action.DynaActionForm"> <BR><form-property name="upload" type="org.apache.struts.upload.FormFile"/> <BR><form-property name="url" type="java.lang.String"/><BR><form-property name="desc" type="java.lang.String"/><BR></form-bean> <BR><BR>q样Qstruts在页面提交以后会(x)自动Lupload、rul?nbsp;descq三个输?nbsp;Qƈ它转成相应的数据类型?BR>所以我们很Ҏ(gu)得到一个FormFile对象Q而这个对象就包含了上传文件的所有信息。因此,我们的数据表相应的信息也有了<BR><BR>map.put(Constattachment.ATTACHFILENAME, ff.getFileName()); <BR>map.put( Constattachment.ATTACHMIMETYPE, ff.getContentType());<BR>map.put( Constattachment.ATTACHFILESIZE, String.valueOf(ff.getFileSize())); <BR>map.put( Constattachment.ATTACHFILEPATH, "/file/" + ff.getFileName()); <BR><BR>最后我们只要简单的调用函数插入数据?BR><BR>DaoCommon.startTransaction();<BR>attachDb.insert(map); <BR>DaoCommon.commit(); <BR><BR>核心技术基本讲解完毕。下面讲一下实现的程。大家可以先看一下demo。首先是一个index面Q可以选择一个上传一个图片文件直接显C出来。也可以把内Ҏ(gu)C在input框中?BR><BR><BR><form name="form1"><img name="image1" src=""><BR><input type="text" name="txt"><BR></form><BR><input type="button" value="? onclick="alert(image1.src)"><BR><input type="button" value="上传文g" onclick="popUpWindow(´<c:url value="/upload.do?m=list&url=documentQimage1.src"/>´)"><BR><input type="button" value="上传文g(文g名到输入?" onclick="popUpWindow(´<c:url value="/upload.do?m=list&url=documentQform1.txt.value"/>´)"><BR><BR><BR><BR>index.jsp的主要内容如上:(x)主要特别的一点的地方是<c:url>Q是JSTL的url的tag,通过它可以得到相对\径的URL。两个按钮的弹出框都是upload.doQ方法是list.list的方法很?BR><BR>AttachDb attachDb = new AttachDb(); <BR>DaoCommon.startTransaction();<BR><BR>request.setAttribute("fileslist", attachDb.find(new HashMap()));<BR><BR>DaoCommon.rollBack();<BR><BR><BR><BR>主要是列出表中所有文件。放到fileslistq个对象中去。然后指到attachlist.jspq个jsp文g厅R作为view层,attachlist很简单的?BR><BR><a href="attach.jsp?url=<c:out value="${param[´url´]}"/>">d文g</a><BR><table width="100%" border="1"><BR><tr><BR><td>名称</td><BR><td>格式</td><BR><td>文g</td><BR><td>选择</td><BR></tr><BR><c:forEach var="i" items="${fileslist}"><BR><tr><BR><td><c:out value="${i[´ATTACHDESC´]}"/></td><BR><td><c:out value="${i[´ATTACHMIMETYPE´]}"/></td><BR><td><c:out value="${i[´ATTACHFILEPATH´]}"/></td><BR><td><a href="#" onclick="selectone(´<c:url value="/${i[´ATTACHFILEPATH´]}"/>´);">选择</a> <a href="<c:url value="upload.do?m=del"><c:param name="url" value="${param[´url´]}"/><c:param name="ATTACHID" value="${i[´ATTACHID´]}"/></c:url>">删除</a></td><BR><BR></tr><BR></c:forEach><BR></table><BR></body><BR></html><BR><script> <BR>function selectone(value){ <BR>opener.<c:out value="${param[´url´]}"/>=value <BR>window.close();<BR>}<BR></script> <BR><BR><BR>首先我们可以看看怎么昄表格 <c:forEach var="i" items="${fileslist}">通过forEachq个tag.得到fieslist里的对象?nbsp;<c:out value="${i[´ATTACHDESC´]}"/>Q通过q一句也可以看到jstl昄HashMap的数据是多么Ҏ(gu)?nbsp;下面是参数化的URL,看下面的URL?BR><BR><a href="<c:url value="upload.do?m=del"><c:param name="url" value="${param[´url´]}"/><c:param name="ATTACHID" value="${i[´ATTACHID´]}"/></c:url>">q里有两个参敎ͼ一个是urlQ是从前面的paramQ也是前一늚参数取来的。另一个参数是从javaBean对象中取得。ATTACHID是唯一键,删除的时候就只要q一个参数就可以了?BR><BR>删除的代码也单,把ATTACHID攑օhashMap,然后执行删除(注,文g没有实际删除Q不q要实现文g删除的代码也很简单?。最后也是读取所有的文gQ再q回到本?BR><BR><BR>AttachDb attachDb = new AttachDb(); <BR>DaoCommon.startTransaction();<BR>HashMap delMap = new HashMap();<BR>delMap.put(<BR>Constattachment.ATTACHID,<BR>request.getParameter("ATTACHID"));<BR>attachDb.delete(delMap);<BR><BR>request.setAttribute("fileslist", attachDb.find(new HashMap()));<BR><BR>DaoCommon.commit();<BR><BR><BR>d文g指向attach.jsp。这个文件是上传的主要文Ӟ实现一个实际的上传界面?BR><BR><a href="<c:url value="/upload.do?m=list"><c:param name="url" value="${param[´url´]}"/></c:url>">文g理?lt;/a><BR><p><BR><html:form action="/upload" enctype="multipart/form-data" onsubmit="return validate(this);"><BR>说明Q?nbsp;<input name="desc" type="input" size="30"> <br><BR>文gQ?lt;input name="upload" type="file" id="upload" size="50"><br><BR><input name="url" type="hidden" value="<c:out value="${param[´url´]}"/>"><BR><input name="m" type="hidden" value="add"><BR><input type="submit" name="Submit" value="上传"> <BR><BR></html:form ><BR></p><BR></body> <BR><BR>提交以后执行前面所说的add斚w。然后{到success.jsp。其内容是把前面的fileName转到index面Q同时关闭自己?BR><BR><script> <BR>opener.<c:out value="${url}"/>="<c:url value="/${fileName}"/>"; <BR><BR>window.close();<BR><BR></script> <BR></P><img src ="http://www.tkk7.com/RR00/aggbug/13963.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/RR00/" target="_blank">R.Zeus</a> 2005-09-25 00:20 <a href="http://www.tkk7.com/RR00/articles/13963.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts Recipes: Hibernate and Strutshttp://www.tkk7.com/RR00/articles/13308.htmlR.ZeusR.ZeusSun, 18 Sep 2005 06:11:00 GMThttp://www.tkk7.com/RR00/articles/13308.htmlhttp://www.tkk7.com/RR00/comments/13308.htmlhttp://www.tkk7.com/RR00/articles/13308.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/13308.htmlhttp://www.tkk7.com/RR00/services/trackbacks/13308.html

Struts Recipes: Hibernate and Struts

Add the power of Hibernate to your Struts application

Summary
In this excerpt from Struts Recipes, (Manning Publications, December 2004) authors George Franciscus and Danilo Gurovich illustrate how to use Hibernate in a Struts application. They also show how to create a Struts plug-in to improve performance. (2,200 words; January 24, 2005)
By George Franciscus and Danilo Gurovich

Persistence is a fundamental piece of an application. Obviously, without persistence all work would be lost. However, persistence means different things to different people. The length of time something must be persisted is a fundamental qualifier in choosing a persistence storage medium. For example, the HTTP session may be suitable when the life of a piece of data is limited to the user's session. In contrast, persistence over several sessions, or several users, requires a database. The volume of data is another important qualifier. For example, best practices suggest large amounts of data should not be stored in an HTTP session. In those circumstances, you need to consider a database. In this recipe we target persistence in a database.

The type of database you choose has an important influence on your architecture and design. As object-oriented developers, we tend to represent data as an interconnected web of objects as a means to describe the business problem at hand—this is often called a domain model. However, the most common storage medium is based on a relational paradigm. Unless our object model mirrors a relational structure, the in-memory representation of our data is at odds with the means to persist it. This problem is called the mismatch paradigm. One of the most popular tools to address the mismatch problem is a category of tools called object-relational mappers. An object-relational mapper is software used to transform an object view of the data into a relational one, and provide persistence services, such as create, read, update, and delete (CRUD). Many good papers have been written on object-relational mappers, but in essence, they all speak to the Data Mapper pattern. One of the most popular object-relational mappers is the open source Hibernate project.

In this recipe, we show you how to employ Hibernate in a Struts application. In addition, we will show you how to create a Struts plug-in to give your Hibernate-powered Struts applications a performance boost.

Recipe
In this recipe, we use an example to illustrate everything you need to do to use Hibernate in a Struts application. We create an application to retrieve and display elements from the chemical periodic table. The application offers the user a search page to look for an element by element symbol. The application responds by searching the database for an element matching the symbol name and returns information about the element.

We'll start by showing you how to get the Hypersonic database server up and running. With the database server started, we create the table and data required to exercise the application. Once the database is ready to go, we'll create all the Hibernate artifacts required to execute this application by using the Hypersonic database server. The next step is to respond to search requests by calling upon Hibernate to handle database access from inside our Action. Because creating Hibernate factory objects is expensive, we'll create a Struts plug-in to create the factory and store it in context.

Let's start by bringing up the Hypersonic database server. You need to download Hypersonic from http://hsqldb.sourceforge.net/. Place hsqldb.jar in your classpath and launch Hypersonic by entering the following command in your DOS prompt:

java org.hsqldb.Server

Although the server's response varies from one version of Hypersonic to another, the following response is a typical indication that Hypersonic is ready to serve database requests.

Server 1.6 is running
Press [Ctrl]+{c} to abort

With the database server up and running, we are ready to create the elements table and populate it with data, as shown in Listing 1.

Listing 1. Create and populate elements tables

create table elements (id integer(3) IDENTITY,
                 name char(30),
                 number char(30),
                 mass char(30),
                 symbol char(2));

CREATE UNIQUE INDEX ui_elements_pk ON elements (symbol)

insert into elements ( name, number, mass, symbol) values ('Manganese','25','55','Mn');
insert into elements ( name, number, mass, symbol) values ('Zinc','30','65','Zn');
insert into elements ( name, number, mass, symbol) values ('Thulium','69','169','Tm');
insert into elements ( name, number, mass, symbol) values ('Californium','98','251','Cf');
insert into elements ( name, number, mass, symbol) values ('Gold','79','197','Au');
insert into elements ( name, number, mass, symbol) values ('Ytterbium','70','173','Yb');
insert into elements ( name, number, mass, symbol) values ('Molybdenum','42','96','Mo');
insert into elements ( name, number, mass, symbol) values ('Palladium','46','106','Pd');

Listing 1 presents the SQL commands necessary to create the elements table, create a unique index on symbol, and insert data We have only presented a few of the periodic elements. We'll leave it to you to dust off your high school chemistry textbook to create data for the remaining elements.

Listing 2 presents the Element JavaBean used to store data retrieved from the database.

Listing 2. Element JavaBean

package com.strutsrecipes.hibernate.beans;

public class Element {
   private String name;
   private String symbol;
   private String number;
   private String mass;
   private int id;

   public Element() {
      super();
   }

   public Element(String name, String symbol, String number, String mass) {
      this.name = name;
      this.symbol = symbol;
      this.number = number;
      this.mass = mass;

   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getMass() {
      return mass;
   }

   public String getName() {
      return name;
   }

   public String getNumber() {
      return number;
   }

   public String getSymbol() {
      return symbol;
   }

   public void setMass(String mass) {
      this.mass = mass;

   }

   public void setName(String name) {
      this.name = name;
   }

   public void setNumber(String number) {
      this.number = number;
   }

   public void setSymbol(String symbol) {
      this.symbol = symbol;
   }
}

Hibernate is an object-relational mapping tool. Its job is to map objects to relational tables and vice versa. Therefore, we must tell Hibernate how to map the columns in the "elements" table to the properties of the Elements JavaBean. This is done using the Element.hbm.xml file. The information embodied in this file is required to empower Hibernate to copy data from the table to the Elements JavaBean. If we were using Hibernate to update data, the information in the Element.hbm.xml file would be used to extract data from the Elements JavaBean to generate SQL update statements. Listing 3 presents Element.hbm.xml.

Listing 3. Element.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sf.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
   <class name="com.strutsrecipes.hibernate.beans.Element" table="elements">

      <id name="id" column="id">
         <generator class="native"/>
      </id>

      <property name="name" column="name"/>
      <property name="number" column="number"/>
      <property name="mass" column="mass"/>
      <property name="symbol" column="symbol"/>
   </class>
</hibernate-mapping>

Let's step through Listing 3

We declare the full package name of the class to be associated with the "elements" table. We then declare the name of the table associated with that class. Next, we declare the mapping from the id JavaBean property to the id column. Because the property and column names have the same value, we could have omitted the column attribute, but we have explicitly declared the column for clarity purposes. The <id> tag is a special tag. It is used to declare the primary key for the table. The enclosing <generator> tag instructs Hibernate to generate the key in whichever way is most appropriate for the database implementation. You should consult Hibernate documentation for more information on the <id> tag. Finally, we declare mapping for the remaining JavaBean properties. Once again the column attribute is declared for clarification purposes.

Once the mapping file has been broken down in detail, it's all rather straightforward. It simply describes which table maps to which class and which JavaBean properties map to which column names. Later on we will tell you where to place this file.

Next, we configure Hibernate by declaring environmental information. In Listing 4, we present the hibernate.cfg.xml file.

Listing 4. hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>
   <session-factory>
   <property name="dialect">net.sf.hibernate.dialect.HSQLDialect</property>
   <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
   <property name="connection.username">sa</property>
   <property name="connection.password"></property>
   <property name="connection.url">jdbc:hsqldb:hsql://127.0.0.1</property>
   <property name="show_sql"> </property>
   <property name="">true</property>

   <mapping resource="/com/strutscookbook/hibernate/beans/Element.hbm.xml"/>
</session-factory>
</hibernate-configuration>

Let's step through Listing 4.

We start by specifying the database implementation dialect that allows Hibernate to take advantage of implementation-specific features. We declare the Hypersonic dialect. You should consult the Hibernate documentation to choose the appropriate dialect for your database. We then declare the database driver. You must ensure this driver is in your application's classpath. We then declare the database username, the database password, and the database connection URL. Next, we instruct Hibernate to display the SQL generated at runtime in the log.

The hibernate.cfg.xml file must be placed in your classpath.

The procedure to use Hibernate within your application requires the following steps:

  1. Create a Hibernate configuration object

  2. Use the Hibernate configuration object to create a Hibernate factory object

  3. Use the Hibernate factory object to create a Hibernate session object

  4. Use the Hibernate session object to start a transaction (optional)

  5. Employ the Hibernate session object to create, read, update, and delete data on the database

  6. Commit the transaction (optional)

  7. Close the session

A Hibernate best practice is to create and cache the Hibernate factory to enhance performance. Therefore, we will create a Struts plug-in to perform Steps 1 and 2 and cache the Hibernate factory in the servlet context, as shown in Listing 5.

Listing 5. HibernatePlugin.java

package com.strutsrecipes.hibernate.plugin;

import java.net.URL;
import javax.servlet.ServletException;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;

public class HibernatePlugin implements PlugIn {
   private Configuration config;
   private SessionFactory factory;
   private String path = "/hibernate.cfg.xml";
   private static Class clazz = HibernatePlugin.class;

      public static final String KEY_NAME = clazz.getName();

      private static Log log = LogFactory.getLog(clazz);

   public void setPath(String path) {
      this.path = path;
   }

   public void init(ActionServlet servlet, ModuleConfig modConfig)
      throws ServletException {

      try {
         URL url = HibernatePlugin.class.getResource(path);
         config = new Configuration().configure(url);
         factory = config.buildSessionFactory();
         servlet.getServletContext().setAttribute(KEY_NAME, factory);

      } catch (MappingException e) {
         log.error("mapping error", e);
         throw new ServletException();

      } catch (HibernateException e) {
         log.error("hibernate error", e);
         throw new ServletException();
      }

   }

   public void destroy() {
      try {
         factory.close();
      } catch (HibernateException e) {
         log.error("unable to close factory", e);
      }
   }
}

Creating a Struts plug-in requires only two steps. First, create a class implementing org.apache.struts.action.PlugIn (Listing 5). Second, define a <plug-in> tag in the struts-config.xml file (Listing 6).

Let's step through Listing 5.

We create a constant to hold the name of the servlet context attribute key. We have chosen to use the HibernatePlugin class name. Notice the constant is static public final. We use the HibernatePlugin class to access the key name in the Action (Listing 7). We define the path property. By default, the Hibernate-Plugin looks for the Hibernate configuration file at /hibernate.cfg.xml. You can use this property to load the Hibernate configuration file from another filename and directory anywhere on the classpath. Next, we use the classloader to find the Hibernate configuration file and then we create the Hibernate configuration object. We use the Hibernate configuration object to create a Hibernate factory object and then we store the Hibernate factory object in the servlet context. The factory is now available to any code with a reference to the servlet.

As a good practice, we close the factory in the destroy method.

Listing 6 presents the application struts-config. The only thing out of the ordinary here is the <plug-in> tag. This is where we declare the Hibernate plug-in, which creates and caches the Hibernate factory object.

Listing 6. struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
   "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
   <form-beans>
      <form-bean name="searchForm"type="com.strutsrecipes.hibernate.forms.SearchForm"/>
   </form-beans>

   <global-forwards>
      <forward name="search" path="/search.jsp"/>
      <forward name="searchsubmit" path="/searchsubmit.do"/>
   </global-forwards>

   <action-mappings>
      <action path="/searchsubmit"
            type="com.strutsrecipes.hibernate.actions.SearchAction"
            name="searchForm"
            scope="request"
            input="/search.jsp">
            <forward name="success" path="/element.jsp"/>
      </action>
   </action-mappings>

   <plug-in className="com.strutsrecipes.hibernate.plugin.HibernatePlugin">
      <set-property property="path" value="/hibernate.cfg.xml"/>
   </plug-in>
</struts-config>

Listing 7 presents the SearchForm used to search for an element. It's very simple because the user can only search by element symbol.

Listing 7. SearchForm.java

package com.strutsrecipes.hibernate.forms;

import org.apache.struts.action.ActionForm;
public class SearchForm extends ActionForm {
   String symbol;

   public String getSymbol() {
      return symbol;
   }

   public void setSymbol(String symbol) {
      this.symbol = symbol;
   }
}

Let's have a look at the SearchAction in Listing 8. Although you may decide to employ Hibernate in other areas of your application architecture, we have chosen to use it in the Action. We'll defer the discussion of the other alternatives to the discussion section.

Listing 8. SearchAction.java

package com.strutsrecipes.hibernate.actions;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.strutsrecipes.hibernate.beans.Element;
import com.strutsrecipes.hibernate.forms.SearchForm;
import com.strutsrecipes.hibernate.plugin.HibernatePlugin;

public class SearchAction extends Action {
   private static Log log = LogFactory.getLog(SearchAction.class);

   final public static String HQL_FIND_ELEMENT =
      "from com.strutsrecipes.hibernate.beans.Element as e where e.symbol = ?";

   public ActionForward execute(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {

      SearchForm searchForm = (SearchForm) form;
      Element element = null;
      List elements = null;
      SessionFactory factory = null;
      Session session = null;

      try {

         factory =
                (SessionFactory) servlet.getServletContext()
               .getAttribute(HibernatePlugin.KEY_NAME);

         session = factory.openSession();

         elements =
            session.find(
            HQL_FIND_ELEMENT,
            searchForm.getSymbol(),
            Hibernate.STRING);

         if (!elements.isEmpty()) {
            element = (Element) elements.get(0);
         }

      } catch (HibernateException e) {
         log.error("Hibernate error", e);
         } finally {
            log.error("Hibernate exception encountered");
         session.close();
      }

      if (element != null) {
            request.setAttribute("element", element);
            return mapping.findForward("success");
      }

      ActionErrors errors = new ActionErrors();

      errors.add(ActionErrors.GLOBAL_ERROR,
         new ActionError("error.notfound"));
      saveErrors(request, errors);
      return mapping.getInputForward();
   }
}

Let's take a quick overview of what happens in the SearchAction. The SearchAction uses the SearchForm.getSymbol() method to obtain the element symbol entered by the user on the search page. Hibernate is used to search the database and convert the data stored in the database to an Element object. The Element object is placed in request context for the JavaServer Pages (JSP) page. Let's step through Listing 8 line by line to see how it's done in detail.

First, we declare a constant to search the database. We next cast the form to SearchForm and then we obtain the Hibernate factory. Recall the Hibernate plug-in has already created the factory and cached it in the servlet context. Next, we obtain a session. The session obtains a connection to the database. Hibernate uses the configuration information we created in Listing 4 to connect to the database. We then search the database.

There are other ways to employ Hibernate to search the database, but the find method is appropriate whenever a search doesn't use the primary key. Notice, we have the HQL_FIND_ELEMENT constant declared. The SQL defined in HQL_FIND_ELEMENT looks somewhat like standard SQL, but not quite. The SQL used by Hibernate is proprietary to Hibernate and reflects an object-oriented version of SQL, rather than the relational SQL to which you are accustomed.

Let's delve into the Hibernate SQL (HQL) code snippet.

from com.strutsrecipes.hibernate.beans.Element as e where e.symbol = ?

This statement tells Hibernate to select all Element objects residing in the com.strutsrecipes.hibernate.beans package. The where clause filters the list to only those elements whose symbols match a runtime parameter. The as e indicates that e may be used as an alias elsewhere in the HQL, as we have done in the where clause. You can see that we are selecting objects, not rows, in the database. Hibernate uses the information in Listing 4 to map the class we are interested in to its associated table. In this example, the relationship between the table and the object are very close, but that does not necessarily need to be the case.

The second and third arguments to the find method are the value and data type of the HQL replacement parameter. The Hibernate reference material describes other ways to replace runtime parameters.

The find method always returns a List. In this case, we obtain a list of Element objects. We are confident that a maximum of one instance is returned because the "elements" table has a unique key constraint on the symbol column (see Listing 1).

Returning to Listing 8, we copy the element reference in the first position in the list to the element variable. To deal with any Hibernate exceptions, we have chosen to log the exception and present the user a "not found" message, but you may decide to present a different message or use declarative exception handling. Next, we close the session. Closing the session in the finally clause guarantees it is attempted even when exceptions are thrown. We store the Element object in the request context and finally we build the ActionError when the symbol can't be found. For the sake of completeness, we have presented the search.jsp (Listing 9) and the element.jsp (Listing 10).

Listing 9. Search.jsp

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html:html>
<body>
   <h1>Search for an Element</h1>

   <html:form action="/searchsubmit.do">
      symbol <form:text property="symbol"/>
   <html:submit value="Search"/>
   </html:form>

   <html:errors/>

</body>
</html:html>

Listing 10. Element.jsp

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html:html>
   <h1>Periodic Element</h1>
   Name: <bean:write name="element" property="name"/><br>
   Symbol: <bean:write name="element" property="symbol"/><br>
   Number: <bean:write name="element" property="number"/><br>
   Mass: <bean:write name="element" property="mass"/><br>

   <html:link forward="search">Search</html:link><p>
</html:html>

Before putting Hibernate to work, consult the Hibernate documentation to ensure you have all the required Hibernate jar files in your classpath.

Discussion
Persistence of data is a tedious and laborious job. To make matters worse, a considerable effort must be spent transforming an object-oriented representation of the data to a relational one, and vice versa. Fortunately, several good object-relational mappers exist to ease this burden. In this recipe, we explored Hibernate—one of the most popular open source object-relational mappers available to Java programmers.

Hibernate is a very rich product with many unexplored features left for you to discover. Our simple example is limited to read behavior, but the rest of the CRUD family is just as easy. Update functionality is as simple as accessing the desired element, calling the desired JavaBean setter, and calling the session commit method. Hibernate takes care of generating the SQL and updating the table. A delete is also rather simple?CODE>session.delete(element) is all it takes! Finally, create only requires instantiating the object, calling the setters, and calling session.save(element).

Hibernate best practices recommend caching the Hibernate factory object. We chose to create and cache the factory using a Struts plug-in. Alternatively, you could have chosen to cache using any other means in your arsenal.

Although this recipe can serve you well, there are some drawbacks. First, we have exposed Hibernate to the Struts Action. Migrating to another persistence layer framework requires us to change every Action employing Hibernate. Second, our persistence is tightly coupled to the presentation layer. This coupling denies us the opportunity to reuse the persistence logic in some other presentation mechanism, such as a batch program.

Although there is room for improvement, this recipe is suitable when you do not expect to reuse your persistence logic. You may find yourself in this situation developing prototypes or small throwaway applications.

About the author
George Franciscus is a J2EE consultant and Struts authority. He is a coauthor of Manning's Struts in Action.

Danilo Gurovich is a manager of Web engineering at an e-commerce company. He has designed e-commerce and ERP/EAI Struts applications, and has led teams who have built them.



R.Zeus 2005-09-18 14:11 发表评论
]]>
Struts Resourceshttp://www.tkk7.com/RR00/articles/10014.htmlR.ZeusR.ZeusFri, 12 Aug 2005 19:57:00 GMThttp://www.tkk7.com/RR00/articles/10014.htmlhttp://www.tkk7.com/RR00/comments/10014.htmlhttp://www.tkk7.com/RR00/articles/10014.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/10014.htmlhttp://www.tkk7.com/RR00/services/trackbacks/10014.html Contributor Taglibs

MonkeyStruts by Arron Bates. An approach to nesting beans.

REGEXP.VALIDATOR.STRUTS by Emmanuel Boudrant - A validation component that works with Struts 1.0, to manage form validation on server-side and client-side.

Struts-WAS.jar by Christopher Assenza - Modified Struts 1.0 JAR for Websphere 3.5 or 4. Zipped for download. (For additional tips regarding Websphere 3.5 see http://jakarta.apache.org/struts/installation-was352-x.html.)

Struts Layout by Improve - An extension library to improve interfaces creation with Struts.

Indexed Tags [Also available in the nightly build] by Dave Hays - Produce indexed names such as <input type="text" name="parameter[0].value" value="Mac">. Link, Submit, and Select tags are included too.

Struts IF/THEN/ELSE and SWITCH tags by Niall Pemberton.

TextArea Wrapping by Matthias Bauer. Patch to HTML:TextArea tag to provide wrapping of long lines.

RowTag (ZIP file for download) - Source for a Struts-compatible tag to generate alternating row colors in a table by Niall Pemberton. [NOTE: Requires a Struts build dated after 2001-04-28]

Contributor Extensions

Pow2ACL - Access Control List library. Track of application users roles and permissions. User can be authenticated: - directly using the package API; - using custom JSP tag libraries.

Struts .. in Rose by Emmanuel.Boudrant - Use Struts with the Rational Rose UML model.

Multi-Controller by Sukachevin, Stoehr - Use more than once ActionServlet in your Struts application

JavaScript with html:errors - new Struts validation by Adam Grohs.

Scioworks Camino by Scioworks Pte Ltd. A visual tool for Struts.

Struts Console by James Holmes. The Struts Console is a Java Swing application that provides an easy to use interface for editing Struts' "struts-config.xml" configuration file.

Expresso by JCorporate. An open source application development (AD) framework integrated with Struts.

Dynamic ActionForm Properties by Jan Sorensen.

Bean Utils with Indexed Strings by Gregor Rayman.

Role-Based Actions by Nic Hobs. Set a security role for an Action from with struts-config.

Struts CodeMaker by Ravindran Ramaiah - Generate Struts application by reading configuration file or JSP files. Updated 2001-08-21.

Struts Generator by David Winterfeldt - Based on the generator.xml and a table/query an xml file is generated. Based on the generated xml file a primary key class, data bean class, jdbc class, and an ActionForm (Struts) can be generated.

ValueIterator by Ted Husted - Simple wrapper around a RowSet for use with Struts iterator tag. Also includes generic toMap(), set(map) methods for flexible data transfer.

Struts Transformer by Ron Smith - Transformations are responsible for taking an object in one form and transforming it into another. A forward transformation takes an object from its primary form to a secondary form (e.g. Date object to String). A reverse transformation takes an object from a secondary form to its primary form (e.g. String to Date).

Struts Extender by Ron Smith - Add extensions to the struts framework via entries in the Struts configuration file.

Mapper Framework by Capco - The Mapper framework can be used for automating the process of validating/converting/transferring data fields. (See README to get started. Updated 18-JUL-2001.)

Bean factory by Oleg V Alexeev - Adds the ability to easily link data bean creation to any Struts Action. All information about databeans and actions mappings stored in the standard Struts configuraton file.

Workflow Extension by Matthias Bauer - An extension to the core Struts framework which provides control flow between actions.

Struts Menu by Scott Sayles (ZIP file for download) - A Struts-compatible web menuing component (early release - work in progress) - unzip to a "struts-menu" folder, and see the README.

Struts Validator [Also in the nightly build /contrib folder] by David Winterfeldt - Perform basic validations to check if a field is required, matches a regular expression, and some basic type checking. Different validation rules can be defined for different locales. The framework has basic support for user defined constants which can be used in some field attributes. The validation routines are modifiable in the validation.xml file so custom validation routines can be created and added to the framework.

TLD to VLM by Mario Busche - Simple Java program to convert standard TLD's to the VLM format used by Homesite, CF Studio, and JRun Studio.

UltraDev 4.0 Custom Tag Library Extension - Hosted by Jakarta Taglibs.

Tiles Library for building JSP views [Also in the nightly build /contrib folder] by Cedric Dumoulin - A component is a JSP page that can be inserted in another JSP page, like templates, but can take "parameters" (URLs or 'direct' string intemplates).

Projects and Examples

Artimus by Ted Husted - Simple news poster application. Demonstrates using helper beans and a JDBC database with Struts. WAR zipped for download. Uses Scaffold package. See WEB-INF/README.txt for setup.

Scaffold by Ted Husted - Utility package of classes that can be used with various Web applications.

Struts Polls by Ted Husted - Simple poll application. Demonstrates using a database with Struts.

Struts-example modified for iPlanet Application Server SP2 by Matt Raible.

The Struts Framework by Steve Wilkinson - Excerpt from latest Wrox Professional JSP book.

Struts-Simple by Ted Husted - (WAR file zipped for download) A simple skeleton application outlining the files needs to input and re-display data. Now also demonstrates using "nested" beans.

myCart - Example Shopping Cart application using Struts - joint project with several contributors.

Sample hdml/wireless based struts application by Richard Backhouse.

Struts Login (WAR file zipped for download) by Ted Husted - A minimalist Struts application demonstrating form validation and tracking users with a session attribute (WAR file).

Tutorials

How To: (Form-Based Authentication) use the form-error page to login by Matt Raible.

WebSphere 4 Application Development Handbook - IBM "Redbook" - See "Designing with Frameworks (Chapter 7).

Struts Catalog by Ted Husted - Overview of Struts Design Patterns and Strategies.

HOWTO Setup and Debug STRUTS Example in Forte by Michael Mok.

JBuilder 5, Struts 1.0 & WebLogic 6.0, a Tutorial by Markus Colombo.

Using JBuilder5 with Struts 1.0 Release by Anthony Martin.

3148 Configuring AppServer to Work with Struts by Ken Sipe (7/25/2001)

3004 Building Extensible Web Frameworks Using XML, XSL-T, and Java by Richard Vowles 7/21/2001

Strut by Strut by Ted Husted - Building a web application from the ground up (maintenance release 2001/Aug/19).

J2EE Tutorial - Early Release chapter featuring Struts 1.0 tags.

Welcome to the Struts Framework by Bluestone Software.

An Introduction to Struts by Casey Kochmer.

Struts UML Diagrams (PDF) by Jean-Pierre Schnyder.

Blueprinting a Struts Application by Ted Husted - Sample specification and API for the Struts Example application.

Seminars

Fast Track to MVC Frameworks - 2001-Dec-2.

BravePoint - Advanced JSP Architecture for J2EE - 2001-11-19, 2001-12-10.

AvantSoft Inc. - JSP, Servlets and Struts

Articles

The Struts Framework's Action Mappings Configuration File by Wellington L.S. da Silva

Web Development Products Spreadsheet by Dan Cancro.

Layering Applications by Scott Stanchfield.

MVC and Struts by Steven Sweeting, Clive Jones, and Aaron Rustad.

Introduction to Jakarta Struts Framework by Sue Spielman.

The Struts Framework's Action Mappings Configuration File by Wellington L.S. da Silva

Is Struts Performant? by Ted Husted -- An analysis of framework components, and how they contribute to overall efficiency.

Struts for Everyone by Jonathan Asbell -- Word document zipped for download. Early release: still in working draft form.

Approaches to User Authentication and Access Control in Web Applications by Craig McClanahan. Slides from the JavaOne BOF (June 2001 #1291). Star Office Format. Zipped for download.

Support your application development with Struts [404] by McClanahan, McCay, and Bergenholtz.

Introduction to MVC and the Jakarta Struts Framework by Craig Tataryn.

Kickstart - The obligatory Struts Q&A.

Struts, an open-source MVC implementation by Malcom Davis.

Strut Your Stuff With JSP Tags, by Thor Kristmundsson.

Using the Struts Framework to Develop a Message Board by Maneesh Sahu (article requires registration with informit.com).

JSP templates by David Geary.

Books
Selected APIs, RFCs, and JSRs
Other Resource Pages

JGuru FAQ

More About Struts by Husted dot Com.

German Translation of Users Guide by Hartmut Bernecker.

Javasoft Tutorials

Javasoft Mailing Lists

Mailing List Archives

mail-archive.com.

Struts FAQ with Mailing List Threads - Clippings from the User Lists

Powered by Struts
Java / Struts ISPs

Provided as a reference only. No endorsements given or implied. To be listed, post a documentation enhancement request in Bugzilla.

Consultants

Provided as a reference only. No endorsements given or implied. To be listed, post a documentation enhancement request in Bugzilla.



R.Zeus 2005-08-13 03:57 发表评论
]]>
1. ?/title><link>http://www.tkk7.com/RR00/articles/10013.html</link><dc:creator>R.Zeus</dc:creator><author>R.Zeus</author><pubDate>Fri, 12 Aug 2005 19:51:00 GMT</pubDate><guid>http://www.tkk7.com/RR00/articles/10013.html</guid><wfw:comment>http://www.tkk7.com/RR00/comments/10013.html</wfw:comment><comments>http://www.tkk7.com/RR00/articles/10013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/RR00/comments/commentRss/10013.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/RR00/services/trackbacks/10013.html</trackback:ping><description><![CDATA[<TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1. ?/STRONG></FONT></TD></TR></TBODY></TABLE><A name=prereqs></A> <TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1.0 先决条g</STRONG></FONT></TD></TR> <TR> <TD> <P>q䆾用户指南是ؓ(f)那些z跃的Web开发者编写的Q假设读者已l了解java Web application是如何工作的。在开始之前,(zhn)应该已l掌握下列基本核心技术?</P> <UL> <LI><B>HTTP Request/Response l构.</B><BR>正式的文档在q里<A >RFC 2616 - Hypertext Transfer Protocol (HTTP/1.1)</A>. <LI><B>Java Servlets</B>.<BR>开始学?fn)的一个好地方?<A >Sun Servlet product page</A> ?<A >Sun Java Tutorials</A>. <LI><B>JavaServer Pages (JSP)</B>.<BR>cM的,一个开始学?fn)的好地?gu) <A >Sun JSP product page</A> ?A >Sun Java Tutorials</A>. <LI><B>JavaBeans</B>.<BR>很多Struts的类被编写成为Javabeans.如果(zhn)没有接触过Javabeans,参阅 <A >Sun JavaBean product page</A> ?<A >Sun Java Tutorials</A> </LI></UL> <P>如果(zhn)在其他q_上开发过web applications,(zhn)也许可以l。在需要的时候参考以上的资料。他们几乎是所有Java web开发项目需要用到的核心技术?</P> <BLOCKQUOTE></BLOCKQUOTE></TD></TR></TBODY></TABLE><A name=preface></A> <TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1.1 前言 Q回C前!Q也是Struts的简Ԍ</STRONG></FONT></TD></TR> <TR> <TD> <P>当java servlets被发明出来的时候,很多E序员迅速意识到q是一个好东西。它比标准CGI快速强大,可以ULQƈ且几乎可以无限扩展?</P> <P>但是无穷无尽的编?println()语句来吧HTML送到览器是费旉q且Ҏ(gu)造成问题。答案就是JavaServer Pages,它把~写servlet的Q务倒了个个ѝ现在开发者可以很Ҏ(gu)的把HTML和Java代码混合hQƈ且仍然拥有servlet的所有好处。只有天I才?x)限Ӟ我们Q! </P> <P>Java webE序很快变成了以JSPZ心的。关?JSP)本nq不是一件坏事,但是它ƈ没有解决程控制和web application的其他一些问?</P> <P>昄Q我们需要另一个模?..</P> <P>很多聪明的程序员认识到JSP和servlets可以?B>一?/B>使用来构造webE序。Servlets可以用来辅助程控制QJSP主要x于实现那些凌qHTML.在这L(fng)q程中,一起用JSP和servlet开始被UCؓ(f)Model 2.(同时只用JSP被称为Model 1)?</P> <P>当然Q天底下没有C?..很快很多人指出JSP的Model 2 遵@SmallTalk的经典的Model-View-controller设计模式。现在术语Model 2和MVC可以互相替代?</P> <P>Struts工程?000q?月由Craig R. McClanahan开始动工,来ؓ(f)JavaC֌实现一个标准的MVC框架?001q?月,Struts 1.0发布了。从此,Model 2开发开始变得不同?</P> <BLOCKQUOTE></BLOCKQUOTE></TD></TR></TBODY></TABLE><A name=mvc></A> <TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1.2 Model-View-Controller ('MVC') 设计模式</STRONG></FONT></TD></TR> <TR> <TD> <P>在MVC设计模式中,E序程׃个的Controller(控制?居中斡旋。Controller委派h--在我们的情Ş?HTTPh--到合适的handleQ处理程序)厅RHandle和ModelQ模型)相联p,每一个handle的作用就是成为在h和Model之间的适配?adaptor有一个意思是甉|插头--译者注)。Model 代表或者封装了一个程序的商业逻辑或者状态。通常控制由Controller重新转移到对应的View厅R这个{Uȝ一pd的映决定,一般从数据库或者配|文件中取得。这样就为View和Model提供了一个松散的联系Q编写和l护E序变得显而易见的的容易?</P> <BLOCKQUOTE></BLOCKQUOTE></TD></TR></TBODY></TABLE><A name=overview></A> <TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1.3 Struts 框架U览</STRONG></FONT></TD></TR> <TR> <TD> <P>忠实的和Model-View-Controller设计模式对应QStrutsE序有三个主要的部gQ一个Servlet Controller,它由Struts本n提供,JSP 面("view"),q有E序的商业逻辑("model").我们来看看他们是怎么l合CL(fng)?</P> <P>Struts的Controller servlet把HTTP h打包q传送到框架中的其他对象Q包括JavaServer Pages和由Struts开发者编写的<CODE>org.apache.struts.action.Action</CODE>的子cR当(pȝ)初始化的时候,Controller 解释一个配|资源文件。这个文件定义了(和其他配|一?q个E序?CODE>org.apache.struts.action.ActionMapping</CODE>。Controller用这些映来把HTTP h转换为程序的actions(动作)?</P> <P>一个ActionMapping通常?x)指?</P> <UL> <LI><B>一个requesth的\?/B> (U?"URI"), <LI>用于处理h?B>object typeQ对象)</B> (Action 的子c?, <LI>和其他一些必要的属性?</LI></UL> <P>Action 对象可以处理hq响应客L(fng)(通常是一个web browser),或者指出流E应该被指向另一个地斏V例如,如果d成功Q一个login Action可能希望把流E{Ud主菜单?</P> <P>Action对象可以操作E序的Controller servlet,所以可以操作这个Controller的方法。当转发控制的时候,一个Action对象可以不直接的转发一个或多个׃n对象Q包括JavaBeans,q个q程是通过把它们放到Java servlet׃n的某一个标准collection对象里去?</P> <P>Action对象可以创徏一个购物RBeanQ在购物车里面加上一个条目,把这个bean攑ֈsession l构里去Q然后把控制转发到另一个映。那个映会(x)使用一个JavaServer Page来显C用L(fng)购物车里的内宏V因为每个用户都有他自己的session,他们也会(x)有自q购物车。在一个StrutsE序里,大部分商业逻辑都可以由JavaBeans表示。一个Action可以调用一个JavaBean的属性,不需要知道她实际上是如何工作的。这装?商业逻辑Q所以Action可以专注于错误处理和如何转发控制?</P> <P>JavaBeans也可以用来管理输入的Forms.设计一个webE序的主要问题是得到q检查用户在h中的输入。通过Struts,你可?定义你自qForm Bean c集合,他们都是<CODE>org.apache.struts.action.ActionForm</CODE>的子c,q很Ҏ(gu)的把用户formQ这里是指HTTP form--译者注Q输入的内容攑ֈq些Form bean里去。这个bean被存攑ֈ一个标准的׃n上下文集合里去,所以另一个对象可以用它Q特别是指一个Action对象?Q我的理解,使用ActionForm是因样可以标准化的检查Form里的|也可以标准化的调用Action--译者注。) </P> <P>Form bean可以被一个JSP使用来从用户攉数据...通过一个Action 对象来检查用戯入的数据...然后再通过JSP来重新显Cform的字Dc(din)如果检查错误,Struts׃个公用的机制来提交和昄错误信息?</P> <P>Struts 的Form bean在配|文件中声明Q在一个Java文g中被定义Qƈ且通过一个通用的属性名字来q接C个ActionMapping厅R当一个请?调用一个需要FormBean 的Action时候,Controller servlet要么从输入中获取form bean,要么自己构造一个form bean,把它传递到Action对象厅RAction 对象可以在显CZ前检查form bean的内容,也可以ؓ(f)要在form里显C的内容排队。准备好之后QAction对象q回控制权ƈ转移到它的输入叶面去。controller可以响应HTTPhQƈ重定向到JavaServer Page厅R?</P> <P>Struts 框架包括自定义的Tag来自动从一个formBean填充子段。JavaServer Page唯一需要知道的是确切的字段名和下一步提交formC处。一些部件例如被Action排队的消息可以在一个自定义tagp?出。也可以定制其他为程序定制的tag来从jsp中隐藏实现细节?</P> <P>在Struts框架中的自定义tag被设计ؓ(f)使用Javaq_内置的国际化Ҏ(gu)。所有的字段名和消息都可以从消息资源中获取,q且Java可以自动Z个客L(fng)的国家和语言提供惛_应的资源。ؓ(f)了提供另一U语a的支持,只需单的的增加另一个资源文件?</P> <P>除了国际化之外,q个q步的好处还在于在不同的form中保持一L(fng)标签名字Q也可以全局化的复查所有的标签和消息?</P> <P>对于最单的E序来说Q有时候一个Action对象可以处理一个请求对应的商业逻辑?B>但是Q在大多数情况下Q一个Action?象应该调用另一个对象,一般是一个JavaBean来处理实际的业务逻辑?/B>q让Action专注于错误处理和程控制Q而非商业?辑。ؓ(f)了在其他q_上重用,商业逻辑JavaBean不应该引用Q何webE序的对象。Action对象应该从HTTPh译必要的细节ƈ 象普通的java变量一样传递到商业逻辑对象厅R?</P> <P>举个例子Q在一个数据库E序中:(x) </P> <UL> <LI>一个商业逻辑bean?x)连接到数据库ƈq行查询, <LI>商业逻辑bean把结果传递到Action, <LI>Action把结果保存在一个form bean中,攄到request中去, <LI>JavaServer Page把结果显C到一个HTML Form中去?</LI></UL> <P>不管是Actionq是JSP都不需要知道结果是从哪儿来的。他们只需要知道如何打包和昄l果?</P> <P>用户指南的其它部分非常详l的解释了Struts的不同部件。Struts发布版本也包含了一些开发者手册包含几个不同的主题Q也包括例子E序Q标准的Javadoc API,当然q有全部的源代码Q?</P> <P>Struts 在Apache软g基金?x)协议下发布。代码拥有版权,但是可以在Q何程序中自由的用。参?A >ASF license</A> 得到详细信息. </P> <BLOCKQUOTE></BLOCKQUOTE></TD></TR></TBODY></TABLE><A name=modelConcepts></A> <TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1.4 ModelQ模型): pȝ状态和商业逻辑JavaBeans</STRONG></FONT></TD></TR> <TR> <TD> <P>ZMVC的系l中?I>Model(模型)</I>部分可以被分Z个概念,pȝ的内部状态和可以用来改变状态的动作。从语法上来?Q我们可以把状态信息看成是<I>名词</I>Q而动作是<I>动词</I>Q用来改变状态)?</P> <P>一般来_(d)c的E序需要用一套包含一个或多个JavaBeans来表辑ֆ部状态,(q些)JavaBean包含了这个状态的详细属性。根?你的E序的复杂程度,他们可能是自我包含的Q自q道怎么样保留持l化信息Q,或者仅是一个知道必要时如何从外部数据源Q如数据库)获取信息的对象。Entity Enterprise JavaBeans (Entity EJBs)一般也用于表示内部状态?</P> <P>大型E序l常使用一些bean的方法来表示一l可能的商业逻辑Q这些方法维护状态信息。例如,你可能有一个购物RBean,保存 在每个用L(fng)session中,包含用户当前军_购买的条目。这个bean可能有一?CODE>checkOut()</CODE>Ҏ(gu)来取得用户信用卡 的授权,发送订单到仓库L发送。另一些系l可能把可能的动作单独包装,可能是一个Session Enterprise JavaBeans(Session EJBs). </P> <P>在一些较?yu)的E序中,相反Q可能的动作?x)内|于<CODE>Action</CODE>cMQ是Controller角色的一部分。当逻辑非常单的 时候,或者当重用商业逻辑不是x点的时候这是合适的。Struts框架支持M一U模式,但是<B>强烈</B>把商业逻辑 Q如何做Q从<CODE>Action</CODE>cL演的角色Q做什么)中分开?</P> <BLOCKQUOTE></BLOCKQUOTE></TD></TR></TBODY></TABLE><A name=presentationConcepts></A> <TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1.5 ViewQ视图): JSP面和表C部?/STRONG></FONT></TD></TR> <TR> <TD> <P>ZStrutsE序?I>View</I>部分基本上是由JavaServer pages(JSP)技术构成的。JSP面可以包含静态的HTMLQ或者XMLQ文本,被称为“模版文本”,再加上在Ҏ(gu)的标{运行时Q当面被调用的时候)插入动态内容的能力。JSP环境包含一套标准的动作标签Q比?CODE><jsp:useBean></CODE>他们?用处?A >JavaServer Pages Specification</A>描述了。另外,q有一U标准的Ҏ(gu)来定义你自己的标{,他们被组l在“自定义标签库”里?</P> <P>Struts包含了一个内容广泛的自定义标{ֺQ用以帮助编写完全国际化的用L(fng)面。它也和处于<I>Model</I>部分?CODE>ActionForm</CODE>高度互动。关于用这些标{Ҏ(gu)在后面会(x)详细讨论?</P> <P>除了JSP 面和原有的以及(qing)自定义的标签之外Q有时候让商业逻辑对象拥有把他们自己根据当前的状态渲染成HTMLQ或者XMLQ的能力?是经帔R要的。这些被渲染出来的输出可以很Ҏ(gu)的在一个结果JSP文g里面?CODE><jsp:include></CODE>标准动作?{ּ用?</P> <BLOCKQUOTE></BLOCKQUOTE></TD></TR></TBODY></TABLE><A name=controllerConcepts></A> <TABLE cellSpacing=5 cellPadding=5 width="100%" border=0> <TBODY> <TR> <TD bgColor=#023264><FONT face=arial,helvetica,sanserif color=#ffffff size=+1><STRONG>1.6 ControllerQ控制器Q? ActionServlet ?ActionMapping</STRONG></FONT></TD></TR> <TR> <TD> <P>E序?I>ControllerQ控制器Q?/I>部分x于从客户端接收请求(通常是一个用浏览器的用PQ决定那个商业逻辑Ҏ(gu)应该被执行,然后分配dl到一个合适的viewlg来制造下一步的用户界面。在Struts里面QController的主要部分是一个servlet,它是<CODE>ActionServlet</CODE>.q个servlet用一l?CODE>ActionMappings</CODE>来配|,一个ActionMapping定义了一?CODE>pathQ\径)</CODE>Q它和用戯求的URI对应Q一般会(x)指定一个完整的Actioncȝcd。所有的Actionc都?CODE>org.apache.struts.action.Action</CODE>的子cRAction装了商业逻辑Q组装结果,q且最l分配控制权到合适的View部g来创建结果?</P> <P>Struts也支持在<CODE>ActionMapping</CODE>中用除了标准的框架所需之外附加的属性。这样允怽保存你的E序所特定的附加信息。除此之外,Strutsq允怽定义控制转移的逻辑“名字”,q样一个ActionҎ(gu)可以要求“主菜单”(举例Q而不需要知道对应的JSP面的实际名字。这个功能很大的帮助你把控制逻辑(做什么)和表C逻辑(如何昄)分开?</P> <BLOCKQUOTE></BLOCKQUOTE></TD></TR></TBODY></TABLE><img src ="http://www.tkk7.com/RR00/aggbug/10013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/RR00/" target="_blank">R.Zeus</a> 2005-08-13 03:51 <a href="http://www.tkk7.com/RR00/articles/10013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3. 构?View Q视图)部g http://www.tkk7.com/RR00/articles/10012.htmlR.ZeusR.ZeusFri, 12 Aug 2005 19:46:00 GMThttp://www.tkk7.com/RR00/articles/10012.htmlhttp://www.tkk7.com/RR00/comments/10012.htmlhttp://www.tkk7.com/RR00/articles/10012.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/10012.htmlhttp://www.tkk7.com/RR00/services/trackbacks/10012.html
3.1 U览

q一章关注构造程序的View(视图)部g的Q务,主要是由JavaServer Pages(JSP)技术完成的。特别的QStruts提供对编写国际化E序的支持,同时也支持和(用户)输入的Form交互。其他几个和View(视图)有关的主题也?x)被要的涉及(qing)?

3.2 Internationalized Messages

几年前,E序开发者们只期望支持他们自己国家的国民Q只使用一U(有时候是两种Q语aQ也只有一U表达日期,数字Q钱币的格式。然而,ZWeb技术的,在internet和其他一些可以被q泛讉K的网l上的程序开发有了爆炸性的增长Q让国界问题?gu)现在我们的g。这个问题被理解为对于支?I>国际?/I>(l常被称为i18n,因ؓ(f)?国际?一词internationalization中i和n之间?8个字??I>本地?/I>E序的需要?

Struts 在Javaq_上编写,可以辅助支持~写国际化和本地化的E序。需要熟(zhn)的概念有:(x)

  • Locale (国籍,地区) - 支持国际化的最基本的JavacLjava.util.Locale。每一?CODE>Locale表示一个特定的国家和语a(包括一U可选的不同语言),和一套对于数字,日期之类的字W串的格式化Ҏ(gu)?
  • ResourceBundle (资源? - java.util.ResourceBundlecL供了支持不同语言的信息的基本支持。参?CODE>ResourceBundle的Javadoc和在你的JDK版本中的国际化支持的信息来得到进一步的帮助?
  • PropertyResourceBundle (属性资源包) - 一?CODE>ResourceBundle的标准实玎ͼ它允怽用和properties文g一L(fng)"name=value"的格式来定义资源。这对于在webE序中准备信息资源宝矛_方便的,因ؓ(f)大部分的信息都是文本?
  • MessageFormat (信息格式) - java.text.MessageFormat cd怽在运行时用参数的方式替代一个信息字W串Q在q种情况下,是从reousece bundle中取出的Q。有时候你要编写一个句子,但是在不同的语言中词语出现的序不一Pq就很有用了。字W串中的占位W?CODE>{0}?x)被W一个运行时参数取代Q?CODE>{1}?x)被W二个取代,其它的也是这栗?
  • MessageResources (信息资源Q?/B> - Strutsc?CODE>org.apache.struts.util.MessageResources让你把一套resource bundle当成数据库,允许你得到某U特定的LocaleQ一般是当前用户的LocaleQ中的特定信息字W串Q而非服务器自己正在用的Locale?

h意在一个Struts之类的框架中i18n的支持只限于国际化的字符串和囑փl用戗支持地区相关的输入?/B>(在日语,中文Q或者韩文之cȝ语言中?被留l客L(fng)讑֤Q一般是一个web览器?

对于一个国际化E序来说Q请遵@JDK中附带的国际化文档中描述的步骤来Z的^台创建每一U语a的properties文g。下面的例子更深入的说明q一点:(x)

假设你的源代码位?CODE>com.mycompany.mypackage?所以它保存?CODE>com/mycompany/mypackage目录中(相对于你的源代码目录Q。要创徏一个名?CODE>com.mycompany.mypackage.MyResources的资源包Q你应该?CODE>com/mycompany/mypackage下创Z列文?

  • MyResources.properties - 包含了用你的服务器所在的语言的文本。如果你的默认语a是英语,你可能会(x)有如下的条目Q?prompt.hello=Hello
  • MyResources_xx.properties - 包含了ISO代码?xx"的语a的文本(参阅ResourceBundle的Javadoc得到最新的代码列表Q。对于一个上面所C文本的法语版本Q你可能?x)有如下的条目?x) prompt.hello=Bonjour 你可以编写所以你愿意支持的语a的资源包?

当你配置你webE序中controller servlet的发布描q时Q你需要定义的一个国际化参数是程序的基本资源包的名字。在我们上面丄例子中,它就?CODE>com.mycompany.mypackage.MyResources?

<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  <init-param>
    <param-name>application</param-name>
    <param-value>com.mycompany.mypackage.MyResources</param-value>
  </init-param>
  <.../>
</servlet>

一仉要的事情是要让你的资源包在你E序可以讉K的class path中。另一个方法是?CODE>MyResources.properties攑֜你的E序?CODE>classes目录下,你就可以单的用“myResource”作为程序的倹{但是要注意如果你的~译脚本Z保证一个“干净”的~译目标Q会(x)删除整个classes目录Q这时要保证q个资源文g不被删除?

如果是这U情形,q儿有一DA(ch)ntd可以包含在你的编译脚本中Q它?CODE>src/conf目录中的内容拯?CODE>classes目录厅R?

        <!-- Copy any configuration files -->
        <copy todir="classes">
            <fileset dir="src/conf"/>
        </copy>
       
3.3 Forms ?FormBean 的交?/STRONG>

以前Q大多数web开发者用标准的HTML能力来编写Forms,比如使用<input>标签。用户希望和E序互动Q生某U特定的行ؓ(f)Q其中之一和错误处理有关——如果用L(fng)了个错误Q程序应该允总们改正需要改正的地方——而非重新填写面上所有的字段?

使用标准的HTML和JSP面来满U需求是非常J琐和粗W的QD个例子,一?CODE>username字段的输入框可能是这L(fng)(在JSP?Q?

<input type="text" name="username"
      value="<%= loginBean.getUsername() %>"/>

如果HTMLE序员ƈ没有~程基础知识的话Q这很难输入正确Q而且也会(x)寚w面编辑者带来麻烦。基于JSP1.1中的自定义标{ֺQStruts为编写form提供了很大的方便Q可以取代原始的Ҏ(gu)。上面的例子用Struts来编写的话会(x)是这?

<html:text property="username"/>

q不需要显式的引用一个JavaBean以取得初始倹{框架自动完成这些事情?

HTML form有时候被用来上传一些文件。大部分览器通过<input type="file"> 元素来支持这一点,它会(x)昄一个浏览文件的按钮Q但是(在Server?-译者注Q下面就轮到开发者来处理q些(上传)来的文g了。Struts可以用和普通的form一致的方式来处理这?multipart" form.在下一节里Q我们会(x)谈到用Struts来创Z个简单的login面Q还包括一个简单的multipart form?

3.3.1 在Struts里编写Form

一个完整的login面有助于展CStruts如何用比直接的HTML和标准JSP方式更轻杄方式来处理form。考虑如下的页面(ZStruts附带的示例程序)Q名字是logon.jsp:


<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld"
        prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld"
        prefix="bean" %>
<html:html>
<head>
<title>
  <bean:message key="logon.title"/>
</title>
<body bgcolor="white">
<html:errors/>
<html:form action="/logon" focus="username">
<table border="0" width="100%">
  <tr>
    <th align="right">
      <html:message key="prompt.username"/>
    </th>
    <td align="left">
      <html:text property="username"
                     size="16"/>
    </td>
  </tr>
  <tr>
    <th align="right">
      <html:message key="prompt.password"/>
    </th>
    <td align="left">
      <html:password property="password"
                         size="16"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <html:submit>
        <bean:message key="button.submit"/>
      </html:submit>
    </td>
    <td align="right">
      <html:reset>
        <bean:message key="button.reset"/>
      </html:reset>
    </td>
  </tr>
</table>
</html:form>
</body>
</html:html>

Ҏ(gu)上面的例子,下面描述了Struts里form处理的关键特?

  • taglib指o(h)告诉JSP面~译器如何去L关于Struts标签库的标签库描q?/I>。在q里Q我们用bean作ؓ(f)表示struts-bean标签库的前缀代号Q?html"是struts-html的前~代号。你可以用Q何你希望使用的前~?
  • q个面使用了几个message 来从包含q个E序所有可用资源的MessageResources对象中查扑֛际化信息丌Ӏ下列文本关键字必须在资源文件中定义Q这个页面才能正常工?
    • logon.title - logon 面的标?
    • prompt.username - "Username:" 询问用户名的标签
    • prompt.password - "Password:" 询问密码的标{?
    • button.submit - "Submit" "提交表单"的按钮的标签
    • button.reset - "Reset" "重置"按钮的标{?
    当用L(fng)录的时候,E序?x)在用户的session中保存一?CODE>Locale对象。这?CODE>Locale对象?x)被用来选择合适的语言信息。这栯用户自己选择语言?x)变得很?gu)——简单的改变q个保存?CODE>Locale对象Q所有的文本都会(x)自动切换?
  • 错误标签昄M保存在商业逻辑部g中的可能的错误信息,如果没有错误Q那么就不显C。关于这个标{,下面?x)详l讨论?
  • Ҏ(gu)指定的属性,form标签展开Z个HTML <form>元素。它也让所有在q个form内部的字DD存放C个session范围的FormBean中去Q它在session中的关键字是logonForm。Struts开发者会(x)l出关于q个form bean的Java实现Q它是一个Strutsc?CODE>ActionForm的字cR这个bean用来l出所有的输入字段的初始|只要字段名和bean的属性名一致。如果合适的bean没有扑ֈQ会(x)自动用指定的Javacd字来创徏一个新的?
  • q个formbean也需要在Struts配置文g中指明。这里名字和cd可以被省略。参?Action Mappings Q动作映)配置文g"得到详细信息?
  • Text标签展开成ؓ(f)HTML里的<input>元素Q它的类型是"text"。在q里Q在览器中昄时占据多个字符I间也被指明了。当q个面被执行的时候,对应的bean?CODE>username属性的g(x)被作为初始|是getUsername()的返回|?
  • password 标签用v来很单。不同之处是当用戯入自q密码时浏览器?x)显C星可非用户输入倹{?
  • submit和reset标签生成form中对应的按钮。其上的标签文字是用message 标签生成的,所以它们显C的是国际化的字W串?

处理multipart form也是很简单的。显而易见,当你~写一个multipart form的时候你创徏的form中具有至一?file"cd的input输入框。编写一个multipart的form的第一步是使用struts-html标签库来创徏昄面Q?


<%@page language="java">
<%@taglib uri="/WEB-INF/struts-html.tld"
       prefix="html">
<html:form action="uploadAction.do">
  Please Input Text:
  <html:text property="myText"><br/>
  Please Input The File You Wish to Upload:<br/>
  <html:file property="myFile"><br />
  <html:submit />
</html:form>

下一步是创徏你的ActionForm beanQ?


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
public class UploadForm extends ActionForm {
  protected String myText;
  protected FormFile myFile;
  public void setMyText(String text) {
    myText = text;
  }
  public String getMyText() {
    return myText;
  }
  public void setMyFile(FormFile file) {
    myFile = file;
  }
  public FormFile getMyFile() {
    return myFile;
  }
}

?A href="file:///D:/DOWNLOAD/2004822203916/api/index.html">Javadocs里查阅FormFile可以看到在文件上传时它提供的处理文g的方法。也要看Javadoc里面的ActionServlet 和ActionMapping的不同的参数Q你可以指定它们来指明文件如何上传。基本上你在你的Actioncȝperform()Ҏ(gu)中需要调?CODE>((UploadForm) form).getMyFile()得到你的文gq且做出你的处理?

3.3.2 支持的Input 字段的类?/STRONG>

下面列出了Struts定义的所有的input字段的类型,带有指向手册的连接?

在Q何情况下Q字D|{N必须内置?CODE>form标签中,q样q些字段才知道用哪个bean来得到初始倹{?

3.3.3 其它有用的表C层标签

有好几个有用的tag用来创徏表示层,h阅它们的标签库的文档和Tag Develipers Guide得到更多的信息:(x)

  • [逻辑] iterate 枚D Z个列表中的所有元素重复输出标{。(q个列表可能?Enumeration,Hashtable, Vector, 或者对象数l)?
  • [逻辑] present 存在 Ҏ(gu)一个指定的属性,q个tag在当前的request中检查,如果q个属性存在的话就昄它所包含的页面内宏V每ơ用这个标{时候只能指定一个属性,名字是必需的。属性可以包括cookie, header,name,parameter,property,role,scoprq有user?
  • [逻辑] notPresent 不存?/A> 和present作用相反的标{,当指定的属性不存在的时候显C?
  • [html] link q接 创徏一?<a> HTML元素Q作Z个锚Ҏ(gu)者指向指定URL的超链接Q它?x)自动进行URL~码Q以在不支持cookie的时候维护session状态?
  • [html] img 囑փ 创徏一?<img> HTML元素Q它可以动态改?src"?lowurl"中指定的URLQ和<html:link>的方式相同?
  • [bean] parameter 参数 获取特定的request 参数的|把结果作Z个page范围的属性,cd是字W串或者字W串数组?
3.3.4 自动form?/STRONG>

除了上文提到的form和bean之间的交互之外,Strutsq提供了附加的机制来查它接收到的输入字段。要使用q个Ҏ(gu),在你的ActionForm中重载下面的q个c?

public ActionErrors
  validate(ActionMapping mapping,
    HttpServletRequest request);

validate() Ҏ(gu)在bean的属性被自动填充之后Q在对应的Actioncȝporform()Ҏ(gu)调用之前由controller servlet自动调用?CODE>validate()Ҏ(gu)有下面几个选择Q?

  • q行了恰当的查,没有发现M问题——返?CODE>null或者长度ؓ(f)零的ActionError实例QController servlet?x)l调用对应的Action的perform()Ҏ(gu)?
  • q行了恰当的查,发现了问题。——返回一个包?CODE>ActionError的ActionErrors实例Q它包含了应该显C错误信息的关键字(位于E序?CODE>MessageResources 信息资源库中的关键字Q。controller servlet?x)把q个数组保存为request的属性,以便<html:errors>标签使用Qƈ且流E会(x)重新转回到输入form(通过ActionMapping?CODE>input属性得刎ͼ?

前面曄提到q,q个Ҏ(gu)完全是可选的。默认的validate()Ҏ(gu)q回null,controller servelt?x)认为对应的ActioncM(x)做必要的查?

另一个常用的方式是在ActionForm的validate()Ҏ(gu)中进行简单的主要的检查,在Action里面做“商业逻辑”检查?

在夜间编译包和下列地址q有一个可选的ActionForm查的包可以用:(x)David Winterfeldt的网?/A>?

3.4 其他表示层技?/STRONG>

虽然你的E序的观感可以完全用标准的JSP和Struts的自定义标签库创建,你也怼(x)考虑动用其他技术来增加部g重用Q减维护工作,q且/或者减错误。下面几节讨Z几种可选项?

3.4.1 针对E序的自定义标签

除了Struts定义的自定义标签Q你针对你正在编写的E序创徏标签也很Ҏ(gu)Q这?x)帮助你~写用户界面。通过针对下面的程序编写tag,Struts附带的示例程序描l了基本原理Q?

  • checkLogon - 察是否存在一个特定的session对象Qƈ且如果没有的话就转向到登录页面。这可以防止用户在用你的程序到一半的时候,把页面用书签记录下来Q试图以后蟩q登录这一步。或者防止session失效?
  • linkSubscription - 生成一个指向明l页面的连接,它传递需要的主键的g为request属性。这在列出用h有的订阅U录时有用,它提供了~辑或者删除订阅信息的链接?
  • linkUser - 生成一个指向用戯l信息页面的链接,把需要的主键信息作ؓ(f)request属性传递?

q些tag的源代码都在src/example目录下,位于org.apache.struts.example包中Q和其它在程序中需要的javacd一赗?

3.4.2 用Include(引用)来组合页?/STRONG>

用一个JSP面Q包括子定义标签和Bean来取得必要的动态数据)在生成整个表现是一个很普通的方式Q在Struts的示例程序中也出现过。然而,很多E序需要在同一个页面中昄多个不同的单一逻辑部分的组合?

举例Q一个门L(fng)点可能在门户的主上有以下几个功能部分:(x)

  • 昄门户的搜索引?
  • 一个或多个"新闻"昄部分Q根据用L(fng)记的个性文件中的兴组合?
  • 昄关于q个门户的讨Z?
  • 一个“有邮g在等待”提C,如果你的门户提供免费邮g账户?

如果你能把工作分成不同的部分Qؓ(f)每个部分分配不同的开发者,开发工作会(x)Ҏ(gu)些。那么你需要用JavaServer Pages技术中?I>include(包含)能力Q或者Struts提供的include 标签来把不同的页面结果组合到一起去。取决于你需要在什么时候组合你的输出,有三U不同的include可供选择:

  • 一?<%@ include file="xxxxx" %>指o(h)可以包含一个包括Java代码或者JSP标记的页面。其中的代码甚至可以讉K爉面之前定义的变量。在JavaServer Page~译之前Q这D代码已l被包含了,所以它可以包含的不只是HTML代码?
  • include action(动作,q里指JSP中的标准指o(h))(<jsp:include page="xxxxx" flush="true" />)在请求时被处理,服务器会(x)透明的处理它。除此以外,q意味着你通过在一个类?A href="file:///D:/DOWNLOAD/2004822203916/struts-logic.html#equals">equalsq样使用参数的标{中~写q条hQ可以有条g的进行包含?
  • bean:included一?forward"参数通过一个逻辑名字映射C个被包含的jsp面Q或者读?id"参数Q打C个页面上下文的字W串变量到jsp面上?

另一个方法是使用Struts Template Tag library(模版标签库)。察看Developer's Guide得到详细信息?

Tiles是一个原来的Template Tag library的替代品Q提供几处增强和新功能。Tiles位于夜间~译包,或者在Cedric Dumoulin的网?/A>?

3.4.3 囑փ生成部g

有一些程序需要动态生成图像,比如h图或者股报告等{。一般有两种不同的方法满个需求:(x)

  • 昄一个指向servleth的超链接。这个servlet?x)用一个图像库来渲染出囑փQ把输出改ؓ(f)合适的内容cd(比如image/gif),q出囑փ的字节流到浏览器。浏览器?x)像一个静态图像一hC它?
  • 生成必要的HTML代码来下载一个Java applet来创建需要的囑փ。通过在生成的代码中传送初始化参数Q你可以军_囑փ。或者applet也可以自行和serverq结以取得这些参数?
3.4.4 生成文字

有些E序需要动态生成文本或者打包的文本Q例如XML.如果整个面都是被生成的Q可以用PrintWriter输出Q从Action里可以很Ҏ(gu)的办?

           response.setContentType("text/plain"); // or text/xml
           PrintWriter writer = response.getWriter();
           // use writer to render text
           return(null);


R.Zeus 2005-08-13 03:46 发表评论
]]>
4. 构?Controller Q控制器Q部?http://www.tkk7.com/RR00/articles/10011.htmlR.ZeusR.ZeusFri, 12 Aug 2005 19:17:00 GMThttp://www.tkk7.com/RR00/articles/10011.htmlhttp://www.tkk7.com/RR00/comments/10011.htmlhttp://www.tkk7.com/RR00/articles/10011.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/10011.htmlhttp://www.tkk7.com/RR00/services/trackbacks/10011.html 4. 构?Controller Q控制器Q部?/STRONG>
4.1 U览

现在我们已经理解如何构造你的程序的Model(模型)和View(视图)部gQ现在是时候来xControllder部g了。Struts包含一个主要功能是映射一个请求URIC?CODE>Actioncȝservlet。因此,对于Controller你的主要责Q是关?

  • 为每一个可能接收的逻辑h~写一?CODE>Actionc(扩展?CODE>org.apache.action.ActionQ?
  • 为每一个可能提交的逻辑h在XML中配|一个ActionMapping。这个XML配置文g通常命名?CODE>struts-config.xml?
  • 更新你的webE序的部|描q文Ӟ在XML里)来包含需要的Struts部g?
  • 在你的程序里增加恰当的Struts部g?
4.2 Action c?/STRONG>

ActioncL供了两个可以被承的Ҏ(gu)Q适应你的servlet环境:

public ActionForward perform(ActionMapping mapping,
                             ActionForm form,
                             ServletRequest request,
                             ServletResponse response)
  throws IOException, ServletException;

public ActionForward perform(ActionMapping mapping,
                             ActionForm form,
                             HttpServletRequest request,
                             HttpServletResponse response)
  throws IOException, ServletException;

大部分工E可能只需要用?HttpServletRequest"版本?

Actioncȝ目标是通过它的perform()Ҏ(gu)处理一个请求,q回一?CODE>ActinForward对象表明控制权应该被转移到哪里(例如一个JSPQ作为合适的相应。在MVC/Model 2设计模式中,一个典型的ActioncM(x)?CODE>perform()中执行如下逻辑Q?

  • 查当前用户session的状态(比如Q检查用h否已l成功登录)。如?CODE>Actioncd现尚未登录,h可以被{Ud一个JSP面提示让用戯入用户名和密码。当用户试图讉K一个程序的“中间部分”(可能是从一个书{)的时候,或者是session已经时Qservlet容器创徏了一个新的session的时候者都可能发生?
  • 如果查还未完成的话,l箋查form bean的属性。如果发C问题Q把相应的错误的信息关键字放在request的属性里Q然后把控制权重新{到输入页面来让用h正?
  • q行h需要的操作(比如在数据库中保存一行数据)。这可能?CODE>Action内部的逻辑代码自己来完成,但是一般应该调用一个商业逻辑bean的合适的Ҏ(gu)?
  • 更新服务器端的对象,来创Z一步用户面对的界面Q典型的是request范围或者session范围的bean,取决于你需要这些条目保存多长时_(d)?
  • q回一个合适的ActionForward对象来挑选JSP面Ҏ(gu)刚刚更新的bean来生成回应。典型的Q你需要通过你接收到?CODE>ActionMapping?CODE>findForward()Ҏ(gu)或者从controller servlet自nQ如果你使用一个全局的逻辑名字Q来得到q样的一个引用?

在编?CODE>ActioncM码时误住以下几个设计要点:(x)

  • Controller servlet只创Z?CODE>Actioncȝ一个实例,用来对对付所有的h。所以,你需要处理好你的代码Q在一个多U程环境下你?CODE>Action应该q作良好Q就象你~写一个servlet?CODE>service()Ҏ(gu)一栗?
  • 最有助于编写线E安全的E序的原则是在你?CODE>ActioncM只用本地变?local variable)Q而非实例变量(instance variable)。本地变量在堆栈中创建ƈ依附于每一个独立的hU程Q由你的JVM处理Q,所以你不用担心׃n它们?
  • 你系l中表示Model(模型)的bean由可能因问数据库或者其他资源而抛出异常。你应该在你?CODE>perform()逻辑中捕h有的异常Q把它们记录到程序的log文g中去Q同时给出对应的stack trace)。可以这样做Q?BR>servlet.log("Error message text", exception);
  • 作ؓ(f)一基本的规则Q分配稀的资源q且为每一个用户在它们的session里分配一个会(x)D规模问题。你应该在把你的控制转移到ViewQ视图)部g之前释攑֮们(比如数据库连接)——就你调用的bean的方法抛Z异常也要q样?

除此之外Q你q需要警惕你?CODE>ActioncM变得太大。出现这U情冉|Ҏ(gu)的可能就是把功能逻辑攑֜Action本nQ而不是在独立的商业逻辑bean。除了让Actioncd得难以阅dl护Q这U方法还?x)让重用商业逻辑变得困难Q因为它们被嵌入在部件内部(那个Actionc)Q从而被限制在一个webE序环境中运行?

只要需要的所有属性都是在Ҏ(gu){֐中传递的Q指的是通过函数调用传递?——译者注Q,一?CODE>Action可以被分散在几个本地Ҏ(gu)中。JVM把这些属性在堆栈中处理,所以它们就是是U程安全的?

Struts附带的例子程序只是设计用于展C某些原理,因ؓ(f)它自q商业逻辑是被嵌入?CODE>ActioncM的。这应该被理解ؓ(f)设计中的某种bugQ而非Struts体系本n的特性,或者应该被模仿的方法?

4.3 ActionMapping 的实?/STRONG>

Z能成功的操作Q关于如何把每一个请求URI映射到恰当的Actionc,Struts controller servlet需要知道几件事情。这些需要的知识被封装在一个叫?CODE>ActionMapping的Java接口中,下列是最重要的几个属?

  • type - 在这个映中Action实现的完整javacd?
  • name - q个action?x)用到的form bean在配|文件中使用的名?
  • path - h的URL用以选择Q触发)q个映射。下面会(x)有关于匹配如何工作的例子?
  • unknown - 当无法找到合适的其他action来处理请求时Q某个action可以被配|ؓ(f)默认处理q个hQ这时候把q一置?CODE>true。一个程序中只能有一个action作ؓ(f)默认处理action?
  • validate - 如果q个映射中涉?qing)的action需要在调用前先调用validate()Ҏ(gu)Q把q一置?CODE>true?
  • forward - 当这个映被调用的时候,转向一个请求URI。这?B>type属性的一个替代品?
4.4 Action Mappings 配置文g

controller servlet是如何知道你希望的映的Q写一个小javacL创徏新的ActionMapping的实例,q且调用每一个setterҎ(gu)来赋值是可行的,但是非常J琐。ؓ(f)了简化这个步骤,Struts包含一个Digester模块Q它能够d一D基于XML的关于需要的映射的描qͼq创建合适的对象。参?A href="file:///D:/DOWNLOAD/2004822203916/api/index.html">API 文档得到关于Digester的更多信息?

开发者的责Q是编写一个命名ؓ(f)struts-config.xml的XML文gQƈ把它攑֜你的E序的WEB-INF目录下。文档的格式?struts-config_1_0.dtd"中的描述指定。最外层的XML元素必须?CODE><struts-config>?

?lt;struts-config>元素之内Q有两个重要的元素被用于描述你的action: <form-beans>
q一D包含你的form bean的定义。你为每一个form bean使用一?lt;form-bean> 元素Q包含下列属性:(x)

  • name: q个bean的一个唯一的标识名Q它?yu)?x)被用来在action映射中引用来指定q个bean.通常Q这也是把这个对象存攑֜request或者session中的属性的关键字?
  • type: 你的form bean的完整的Javacd?
<action-mappings>
q一D包含你的action的定义。你Z的每一个需要定义的action使用一?lt;action> 元素。每一个action元素需要定义下列的属性:(x)
  • path: q个action的程序上下文相关的\?
  • type: q个Actioncȝ完整cd
  • name: Action中所用到?lt;form bean>元素的名?

CZE序中的struts-config.xml文g包含了下列的映射元素Q它们是用来实现“登录”功能的Q我们用它来说明需求。注意其它的Action的条目都被剔除了Q?

<struts-config>
  <form-beans>
    <form-bean
      name="logonForm"
      type="org.apache.struts.example.LogonForm" />
  </form-beans>      
  <global-forwards
      type="org.apache.struts.action.ActionForward" />
    <forward name="logon" path="/logon.jsp"
         redirect="false" /> 
  </global-forwards>      
  <action-mappings>     
    <action
        path="/logon" 
        type="org.apache.struts.example.LogonAction"
        name="logonForm"
       scope="request"
       input="/logon.jsp"
     unknown="false"
    validate="true" />          
  </action-mappings>
</struts-config>

首先定义的是form bean .一个基?org.apache.struts.example.LogonForm"c被映射为逻辑?logonForm"。这个名字也被用在session或者request作ؓ(f)q个form bean的属性名?

"global-forwards"部分用来创徏全局可用的逻辑名映。这儿的M一个{U都可以通过调用你的action mapping的实例实玎ͼ比如actionMappingInstace.findForward("logicalName")?

你可以看刎ͼq个映射匚w/logon路径Q实际上Q因为实例程序用了后~名映,你指定的URIh?x)是?CODE>/logon.dol尾的)。当收到一个匹配这个\径的hӞ?x)创Z?CODE>LogonAction的实例(仅当W一ơ)Qƈ且用它。controller serverl?x)寻找一个session范围的名?CODE>logonForm的bean,如果需要的话,创徏q保存这L(fng)一个bean?

局部的"forward" 元素是可选的但是非常实用。在实例E序中,很多action包含一个局部的"success"??failure"转移作ؓ(f)Action mapping的一部分?

<!-- Edit mail subscription -->
<action    path="/editSubscription"
  type="org.apache.struts.example.EditSubscriptionAction"
  name="subscriptionForm"
  scope="request"
  validate="false">
  <forward name="failure" path="/mainMenu.jsp"/>
  <forward name="success" path="/subscription.jsp"/>
  </action>

只用了两个额外的属性,CZE序中的Actioncd得几乎和面设计者用的实际JSP面的名字无关了。页面可以在重新设计的时候被改名QD个例子)Q只?x)?CODE>Actioncd来微不道的冲击。如果“下一个”JSP面的名字是被硬~码?CODE>Action里面的话Q所有的cd必须做出改动。当Ӟ你可以决定在你的E序中用怎样的局部{Ud性?

另一个很有用的部分是<data-sources>Q它定义了你的程序可以用的数据源。下面是你如何在你的E序的struts-config.xml中指定一个基本的数据源:(x)

<struts-config>
  <data-sources>
    <data-source
      autoCommit="false"
     description="Example Data Source Description"
     driverClass="org.postgresql.Driver"
        maxCount="4"
        minCount="2"
        password="mypassword"
             url="jdbc:postgresql://localhost/mydatabase"
            user="myusername"/>
  </data-sources>
</struts-config>

关于如何获取q个数据源,参阅讉K关系数据?/A>q一节?

4.5 Web E序发布描述

讄你的E序的最后一步是配置E序的发布描qͼ保存?CODE>WEB-INF/web.xml文g中)来包含所有需要的Struts部g。用CZE序中的发布描述作ؓ(f)一个指南,我们发现下列条目需要创建或者修攏V?

4.5.1 配置Action servlet实例

增加一个条目来定义action servlet自己Q包含合适的初始化参数。这L(fng)一个条目可能是q样的:(x)

<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class>
    org.apache.struts.action.ActionServlet
  </servlet-class>
  <init-param>
    <param-name>application</param-name>
    <param-value>
      org.apache.struts.example.ApplicationResources
    </param-value>
  </init-param>
  <init-param>
    <param-name>config</param-name>
    <param-value>
      /WEB-INF/struts-config.xml
    </param-value>
  </init-param>
  <init-param>
    <param-name>debug</param-name>
    <param-value>2</param-value>
  </init-param>
  <init-param>
    <param-name>mapping</param-name>
    <param-value>
      org.apache.struts.example.ApplicationMapping
    </param-value>
  </init-param>
  <load-on-startup>2</load-on-startup>
</servlet>

controller servlet支持的初始化参数如下所C。(你也可以?A href="file:///D:/DOWNLOAD/2004822203916/api/index.html">Javadocs中查找ActionServletcd到详l信息。)Ҏ(gu)可C如果你没有l出初始值时使用的默认倹{?

  • application - E序的资源包的基cȝJavacd?[NONE]
  • bufferSize - 处理文g上传的输入缓冲区大小。[4096]
  • config - 指向包含我们的配|信息的XML资源的相对于上下文的路径。[/WEB-INF/struts-config.xml]
  • content - 默认输出响应的的文档cL和字符集编码。它可以被一个{Ud的servlet或者JSP重蝲。[text/html]
  • debug - q个servlet的debug信息详细E度Q它控制多少信息应该被记录。[0]
  • detail - 我们?CODE>initMapping()中用的Digester的debug信息详细E度Q它输出到System.out而非servlet的log。[0]
  • factory - 用于创徏E序?CODE>MessageResources对象?CODE>MessageResourcesFactory的类名?[org.apache.struts.util.PropertyMessageResourcesFactory]
  • formBean - ActionFormBeanl承的根的Javacd。[org.apache.struts.action.ActionFormBean].
  • forward - ActionForwarderl承的根的Javacd?[org.apache.struts.action.ActionForward]. 两个你可能选择的类是:(x) Two convenient classes you may wish to use are:
    • org.apache.struts.action.ForwardingActionForward - org.apache.struts.action.ActionForward的子c,它的 redirect属性被默认|ؓ(f)false(和Actionforward 默认gP?
    • org.apache.struts.action.RedirectingActionForward - org.apache.struts.action.ActionForward的子c,它的redirect属性被默认|ؓ(f)true?
  • locale - 如果被置?true, q且有一个用户session,如果没有Locale对象的话Q放|一个合适的java.util.Locale object (?CODE>Action.LOCALE_KEY作ؓ(f)标识关键?到用户session中去。[true]
  • mapping - ActionMappingl承的根的Javacd。[org.apache.struts.action.ActionMapping]. 两个你可能选择的类是:(x)
    • org.apache.struts.action.RequestActionMapping - org.apache.struts.action.ActionMapping 的子c,scope属性默认是"request"?
    • org.apache.struts.action.SessionActionMapping - of org.apache.struts.action.ActionMapping 的子c,scope属性默认是"session"(和ActionMapping默认gP?
  • maxFileSize - 一ơ上传文件可能的最大大(单位是字节)。可以在数字后面加上"K","M',或?G", 代表千字节,兆字节和千兆字节。[250M]
  • multipartClass - 用于文g上传的MultipartRequestHandler 的实现的完整Javacd。[org.apache.struts.upload.DiskMultipartRequestHandler]
  • nocache - 如果讄?CODE>true, 在每一个响应中加上HTTP头信息来访置我们的Q何响应或者{U被览器缓存。[false]
  • null - 如果讄?CODE>true, 如果Q资源)信息的关键字无法扑ֈQ返回一?CODE>null。否则,q回一个带有此关键字的错误信息。[true]
  • tempDir - 文g上传时的临时目录?[q个webE序的servlet上下文属性指定的工作目录]
  • validate - 我们是否适用性的配置文g格式Q[true]
  • validating - 我们是否使用一个带有校验的XML 解释器来处理配置文gQ强烈徏议)Q?[true]
4.5.2 配置Action Servlet 映射

注意Q?/STRONG> q一D中的材料不是针对Struts的。配|servlet映射是在Java Servlet规格书中定义的。这一D|qC最普通的针对配置一个StrutsE序的方法?

又两U一般的Ҏ(gu)来配|一个URL成ؓ(f)被controller servlet处理的URL - 前缀匚w和后~匚w。每U方法相应的配置条目?x)在下面描述?

前缀匚w意味着你希望所有的以某一个特定值开头的URLQ在上下文\径部分之后)都被送往q个servlet。这L(fng)条目可能是这P(x)

  <servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>/execute/*</url-pattern>
   </servlet-mapping>

是说前面我们提到过的匹?CODE>/logon的URIh?x)被q样描述Q?

http://www.mycompany.com/myapplication/execute/logon

q里/myapplication是你的程序部|的上下文\径?

后缀匚w映射Q相反,在URL以某一个特定的字符串结时把URIh匚w到action servlet.举个例子QJSP处理servlet对应?CODE>*.jspQ这P每当一个jsp面被访问,它都?x)被调用q行处理。ؓ(f)了?CODE>*.do后缀名(意思是“做什么”)Q映条目可能是q样的:(x)

  <servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>*.do</url-pattern>
   </servlet-mapping>

前面我们提到q的匚w/logon的URIh?x)被q样描述Q?

http://www.mycompany.com/myapplication/logon.do
4.5.3 配置 Struts 标签?/STRONG>

下一步,你必d加一个条目来定义Struts标签库。当前Struts打包?个标{ֺ?

struts-bean 标签库包含访问bean和它们的属性的有用的标{,也包含利用这些访问定义新的bean以便在页面剩下的部分用脚本中的变量和面范围的属性来讉K。还有用request coolie,header和parameter的值来创徏bean的便利机制?

struts-html 标签库包含用户创建struts输入表单Q还有其他通常很在创徏ZHTML的用L(fng)面上很有用的标签?

struts-logic 标签库包括用于有条g的生成输Z码,循环整个对象容器来输出重复的文本Q还有程序流理?

struts-template 标签库包含定义了一个模版机制的标签?

下面是在你的E序中如何定义所有这些标{。在实际工作中你可以只指定你的程序要用到的?

<taglib>
  <taglib-uri>
    /WEB-INF/struts-bean.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-bean.tld
  </taglib-location>
</taglib>
<taglib>
  <taglib-uri>
    /WEB-INF/struts-html.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-html.tld
  </taglib-location>
</taglib>
<taglib>
  <taglib-uri>
    /WEB-INF/struts-logic.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-logic.tld
  </taglib-location>
</taglib>
<taglib>
  <taglib-uri>
    /WEB-INF/struts-template.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-template.tld
  </taglib-location>
</taglib>

q告诉JSPpȝ到哪里去L标签库的定义Q在你的E序的WEB-INF目录Q而不是Internet上的某处Q?

4.5.4 把Struts部g增加C的程序中

Z使用Struts,你必L贝你需要的.tld文gC?CODE>WEB-INF目录Qƈ且拷?CODE>struts.jarQ和其它所有的commons-*.jar文gQ到你的WEB-INF/lib目录?



R.Zeus 2005-08-13 03:17 发表评论
]]>
2. 构造ModelQ模型)部g http://www.tkk7.com/RR00/articles/10010.htmlR.ZeusR.ZeusFri, 12 Aug 2005 18:18:00 GMThttp://www.tkk7.com/RR00/articles/10010.htmlhttp://www.tkk7.com/RR00/comments/10010.htmlhttp://www.tkk7.com/RR00/articles/10010.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/10010.htmlhttp://www.tkk7.com/RR00/services/trackbacks/10010.html 2. 构造ModelQ模型)部g
2.1 U览

很多用于构造webE序的需求文档都是关注于View(视图)的。但是,你需要确认每一个确定的h需要的处理也是?I>Model(模型)层清楚的定义的。一般说来,Model(模型Q?/I>的开发者会(x)x如何建立满所有功能需求的JavaBeancR一个特定的E序所需要的明确定义的bean?x)有很大不同Q取决于他们的需求。然而他们大致上可以被归Z面会(x)讨论的几cR然而,先做一个关于“Scope范围”这个概늚要的回顾?x)是很有用的?

2.2 JavaBeans ?scope(范围)

在一个基于web的程序中QJavaBean可以被存攑֜Q也是获取于)几个不同的“属性”集合。每一个集合有不同的关于集合的生存期和储存在其中的bean的可视范围的规则。定义生存期和可视范围的规则共同被称些bean的“scope(范围)”。JavaServer pages(JSP)的规g定义了以下的术语(在servlet API中同L(fng)也有q些定义Q?

  • page - Bean在一个单一的JSP面中可见,生存期是q个h。(service()函数的本地变量)
  • request - Beans 在一个单一的JSP面中可见,包括被包含在q个面中或者被此页面{Ud的Q何页面或者servlet. (Request 属?
  • session - Beans 在一个特定的用户session中的所有JSP面和Servlet中可见,跨越一个或多个h?Session 属?
  • application - Beans 在web E序的所有的JSP面和servlet中可见?(Servlet context属?

C同一个webE序中的JSP面和servlet׃n同样的bean集合是很重要的。例如,如下的代码在一个servlet中把一个bean加入了request的属?

MyCart mycart = new MyCart(...);
request.setAttribute("cart", mycart);

马上在这个servlet转移到的JSP面中可?通过使用一个标准的动作tag,像q样Q?

<jsp:useBean id="cart" scope="request"
class="com.mycompany.MyApp.MyCart"/>

2.3 ActionForm Beans

注意:ActionForm Beans实际上更靠近View(视图)而非Model(模型)?

Struts框架一般会(x)假设你已lؓ(f)你程序中每一个需要输入的Form定义好了一?CODE>ActionFormBean(q是一个从ActionForml承的一个类).ActionForm beans有时候就叫做"form beans"。如果你已经在你?CODE>ActionMapping配置文g?参阅"构造ControllerQ控制器Q部?/A>")生命了这些bean, Struts Controller servlet在调用合适的ActionҎ(gu)之前?x)自动?f)你提供如下服?

  • 在用L(fng)session里面察看在恰当的键g是否有一个合适的cȝ实例?
  • 如果没有q样的session范围的bean存在Q会(x)自动创徏一个新的实例ƈ加入到user的session中?
  • Ҏ(gu)一个request 参数Q如果能对应?form) bean的一个同名属性,?x)调用相应的setterҎ(gu)。这个操作很象标准的JSP动作<jsp:setProperty>,当你?*'W号来选择所有的属性的时候?
  • 更新q的ActionFormbean ?x)被传递到Action cȝperform()Ҏ(gu)Q(当这个方法被调用Ӟq些值马上就可以使用了?

当你~写你的 ActionForm bean的时候,Cq些基本的原则:(x)

你可能注意到了一个在q里讨论?form"Qƈ非必L用户界面端一个单独的JSP面。在很多E序里都?x)出现跨多个页面?form"(从用者的角度来说Q。想一下,举例来说Q在安装新程序时l常?x)出现的向导风格的用L(fng)面。Struts鼓励你定义一个单独的ActionForm包含所有可能用到的属性,不管到底是在那个面昄的。同L(fng)Q同一个form的不同页面应该被提交到同L(fng)ActioncR如果你遵@q些Q页面设计者可以重新在面之间安排q些字段Q通常不需要修改处理逻辑?

2.4 pȝ状态Beans

pȝ的实际状态一般会(x)表现Z套包括一个或多个JavaBeanc,它们的属性定义了当前的状态。一个购物RQD例来_(d)?x)包括?f)每一个购物者维护一个bean,q且?x)(和其他属性一P包括一些购物者当前选择的物品条目。另外,pȝ也会(x)包括不同的bean来保存用L(fng)个h资料Q包括他们的信用卡号码和送货地址Q,q有按照他们的购物等U所能得到的可购买物品清单?

对于一个小型的pȝQ或者对不需要长期保存状态信息的pȝ来说Q一套系l状态bean可能已经保存了系l所需要的全部特定l节。否则,大多数情况下Q系l状态bean?x)把它持有的信息包村C个外部的数据库去Q比如一?CODE>CustomerBean对象对应于CUSTOMERS表中的一个特定的行)Qƈ可以在服务器的内存中按照需要创建或者删除。Entity Enterprise JavaBeans 在大规模pȝ也是Zq个目的使用的?

2.5 商业逻辑 Beans

你应该把你的E序的功能逻辑装在你为此设计的JavaBean的方法调用中。这些方法可能是同一个系l状态bean,或者他们分布在不同的类中,潜在的体C逻辑。在后一U状况中Q你往往需要把pȝ状态bean作ؓ(f)参数调用以便q些Ҏ(gu)处理?

Z最大化代码重用Q商业逻辑bean因ؓ(f)被设计和实现为假讑֮?B>?/B>知道?x)在web环境下被执行。如果你发现你在你的bean中importjavax.servlet.*Q你(q道你?在试图把q个商业逻辑bean攄在web环境中。请考虑重新~排Q让你的Actionc(属于controller角色的一部分Q下文将?x)谈刎ͼ从HTTPh译所有需要的信息Q通过调用你的商业逻辑bean的setterҎ(gu)预置Q然后调用一?CODE>execute()Ҏ(gu)来执行。这L(fng)商业逻辑cd以在不是最初的Web的环境下重用?

取决于你的程序的复杂E度和范?宽广E度)Q商业逻辑bean可能是普通的JavaBeans(它们和作为参C递的pȝ状态bean打交?,或者是通过JDBC调用存取数据库的一般的JavaBeans。对于大规模E序来说Q它们往往是被有状态的或者无状态的Enterprise JavaBeans(EJBs)所取代?

2.6 讉K关系数据?/STRONG>

Struts可以在它的标准配|文件中为程序定义datasource.也提供一?B>?/B>的JDBCq接池。参?A href="file:///D:/DOWNLOAD/2004822203916/struts/building_controller.html#config">Action Mappings 配置文g和Utilities Developer Guide(工具开发指?得到更详l的信息?

当datasource被定义号之后Q下面是一个在Action的performҎ(gu)中取得连接的例子?

public ActionForward
       perform(ActionMapping mapping,
               ActionForm form,
               HttpServletRequest request,
               HttpServletResponse response)
{
 try {
   javax.sql.DataSource dataSource =
     servlet.findDataSource(null);
   java.sql.Connection myConnection =
     dataSource.getConnection();

   //do what you wish with myConnection
 } catch (SQLException sqle) {
   getServlet().log("Connection.process", sqle);
 } finally {

   //enclose this in a finally block to make
   //sure the connection is closed
   try {
     myConnection.close();
   } catch (SQLException e) {
     getServlet().log("Connection.close", e);
   }
 }
}

注意Struts 普通连接池是一?B>可?/B>lg。很多StrutsE序使用其它q接池来获取更高的性能Q特别是大流量的生pȝ?



R.Zeus 2005-08-13 02:18 发表评论
]]>
struts study bloghttp://www.tkk7.com/RR00/articles/9158.htmlR.ZeusR.ZeusWed, 03 Aug 2005 20:07:00 GMThttp://www.tkk7.com/RR00/articles/9158.htmlhttp://www.tkk7.com/RR00/comments/9158.htmlhttp://www.tkk7.com/RR00/articles/9158.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/9158.htmlhttp://www.tkk7.com/RR00/services/trackbacks/9158.html1?ACTION path="/inputProduct"
   type="com.yourcompany.struts.DemoAction" name="DemoForm"
   scope="request" input="/index.jsp" />

一?FONT color=#ff0000>DemoForm(l承 ActionForm)对应一?FONT color=#ff0000>DemoActionQ?extends ActionQ必d?execute
  (ActionMapping mapping,ActionForm form,
  HttpServletRequest request,
  HttpServletResponse response)

里面的ActionForm form对应DemoFormQ?/FONT>

2。DemoForm里面的validate(ActionMapping mapping,HttpServletRequest request)验证Q?/FONT>

不通过转向 input="/index.jsp" /Q?/FONT>

否则?nbsp;type="com.yourcompany.struts.DemoAction" 验证Q?/FONT>

3??xml:namespace prefix = html />
    user:
   

   name="UserForm" scope="request" input="/failedIn.do" />

html:form对应action="/user.do">对应UserForm"

property对应UserForm"里的属性!

q可dreset(ActionMapping mapiping,HttpServletRequest request)

 

4


    logic:present:
   


   
   

判断userbean是否存在Q存在则昄后面的内容!

5 web.xml
tomcat 启动时加?servletc,cM对象保存在httpcontext中,即application范围内,所有组件可׃n?

1q句话不能缺!Q!Q!Q!Q!Q!

6.
"/>

前一句多了个I格Q导致严重错误!Q!Q!Q!Q!Q!

7.DynaActionForm f = (DynaActionForm) form;
  String[] s = (String[]) f.getMap().get("results");
注意getMap部分


R.Zeus 2005-08-04 04:07 发表评论
]]>
Eclipse3.0.1+Myeclipse3.8.2+tomcat5开发第一个struts应用Q配|篇)http://www.tkk7.com/RR00/articles/9157.htmlR.ZeusR.ZeusWed, 03 Aug 2005 20:06:00 GMThttp://www.tkk7.com/RR00/articles/9157.htmlhttp://www.tkk7.com/RR00/comments/9157.htmlhttp://www.tkk7.com/RR00/articles/9157.html#Feedback0http://www.tkk7.com/RR00/comments/commentRss/9157.htmlhttp://www.tkk7.com/RR00/services/trackbacks/9157.html最q刚刚进入STRUTS大门Q学?fn)了《STRUTS IN ACTION》,写了几个程序,感觉必须选一个IDE?BR>省点力气。去GOOGLE了一下,发现很多Z用Eclipse+Easystruts插g+Tomcat插g来开发,立刻?BR>下了所有的E序Q找了一些文章来指导配置Q但用尽力气Q用了所有可能的Ҏ(gu)都没有成功,可以
识别LOMBOZ和TOMCAT但无法识别Easystruts插gQ但是在Eclipse的HELP--About Eclipse Platform
--Plug-in Details里面却有Easystruts插gQ无奈!最后在|上l箋找了下,发现有些Eclipse3.0.1
支持LOMBOZ但不能支持EasystrutsQ不知道真实性怎么样~Q,q是了Q换个方法吧?BR>    于是我选择Eclipse3.0.1+Myeclipse3.8.2+tomcat5来开发strutsQ这个配|就单多了,哈哈?


一.下蝲
我的环境?BR>JDK1.4.2
TOMCAT5.0.28
Eclipse3.0.1
Myeclipse3.8.2


?安装
Eclipse3.0.1+Myeclipse3.8.2的安装就不多说了Q很单?BR>主要的Myeclipse3.8.2的破?BR>我在|上扑ֈ了Myeclipse3.8.2的破解程?BR>q是我的UhI间Q我已经把破解程序上传了Q方便大家?BR>地址是:(x)
下完后解压到
MyEclipse\eclipse\plugins\com.genuitec.eclipse.core_3.8.2
覆盖原来的文Ӟ
然后启动MyEclipse
填入MyEclipse3.6.4的注册信息(E序里面有,|上也很多!Q,可以了?/P>

?基础配置

破解文g覆盖后,启动MyEclipse
q入Window--->Perferences--->MyEclipse---->Subscription输入注册信息?BR>然后在Window--->Perferences--->Java--->Installed JREsd你的jdk路径
在你需要默认的jdk路径前打勾?BR>最后设|tomcat服务?BR>Window--->Perferences--->MyEclipse---->Application Servers--->tomcat5
使得tomcat server   Enable
然后选择tomcat HomeQ还要add JDKQ选你刚才在java里面讄的jdkQ然后要记得applyQ?/P>

q样你的环境?yu)配|好了!


L(fng)下篇实战,初学者愚见,请大侠们指点.写这些的目的是想和其他初学者一赯?/P>

R.Zeus 2005-08-04 04:06 发表评论
]]>
վ֩ģ壺 պƷ3| aëƬþ| ůůƵƵ| ߹ۿƵ| A߹ۿ| ѴƬavֻƬ| ѹۿҹ| vavavaþ| վ߹ۿ| AVƬ߲Ψ| ޾Ʒa| ɫһһһһƵѿ| Ļ벥| ޾Ʒ99þ| һëƬһֱӹۿ| ѿƬѲ| ˳ձ߹ۿ| þһҰ| gvվ| ŷۺһ| ɫһ| ɫþAVۺ| aƬ߲| һëƬֱ| պƷרձȡ | 91۲ѹ| ɫƷaһ| Ѽվһҳ| ëƬѹۿƵ| ͬgayվ߹ۿ| ҹžƵ߹ۿ| һֻ߹ۿ| freeƵ| ?VþþƷ| žžƷAVպ| Ʒѹۿþþ| պһĺ| Ʒһ| aƬ߹ۿ| ww߹Ƶѹۿ| ޾ƷƵ|