<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>lingcm</title>
    <description></description>
    <link>http://lingcm.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>关于hibernate 直接调用flush 如何让 hibernate 自动check version number的问</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/59036" style="color:red;">http://lingcm.javaeye.com/blog/59036</a>&nbsp;
          发表时间: 2007年03月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <br />
在hbm.xml文件里面已经配置了 <br />
<br />
......<br />
<version name="versionNum" column="VERSION_NUM" type="integer" unsaved-value="null"> </version>
<div class="code_title">xml 片段<br />
</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span></span><span class="string">&lt;&quot;VERSION_NUM&quot;</span><span>&nbsp;name=</span><span class="string">&quot;versionNum&quot;</span><span>&nbsp;type=</span><span class="string">&quot;integer&quot;</span><span>&nbsp;unsaved-value=</span><span class="string">&quot;null&quot;</span><span>/&gt;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<br />
......<br />
<br />
问题是这样的,, 我要update一个表, 比如是 User表, 我第一步就先去出来记录user1, 然后将user1里面的对应的值set到页面的form中, 其中也包括user1当时取出来的version number.&nbsp; 比如说有两个人(张三, 李四)同时修改user1这条记录, 再假设user1这个记录开始的version number是4.<br />
<br />
张三 先取出来user1记录想要进行update操作, 这时候数据库中user1的version number是4, 并且user1取到页面form中的version number 值也是4.<br />
<br />
然后 李四也取出来了 user1记录, 同样 user1在数据库中的version number也是4, 取到页面表单中的version 值也是4. 不过李四先过张三提交了修改. 经过李四修改后, 数据库中的version number已经变成了5.<br />
<br />
如果现在张三提交修改,按照道理应该是不可以成功的..不过我代码如下面这样写却不行,, 我只能显式的调用 session.merge() 方法才行..<br />
<br />
我的code<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span>UserVO&nbsp;userPO&nbsp;=&nbsp;userDAO.getByPk(user.getId());&nbsp;&nbsp;</span></span></li>
    <li class=""><span>userPO.setUserName&nbsp;=&nbsp;user.getUserName();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>......&nbsp;&nbsp;</span></li>
    <li class=""><span>userPO.setVersionNum(user.getVersionNum());&nbsp;<span class="comment">//&nbsp;这里的user.getVersionNum()是保存在页面表单里面的值</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>roleDAO.flush();&nbsp;<span class="comment">//&nbsp;实际上就是调用&nbsp;session.flush();</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<br />
如果向上面这样的代码,, 张三还是可以update成功,, 比较想不通, 难道hibernate不知道用我给的version number先去 check一下??<br />
<br />
不过我如果把上面的roleDAO.flush();改成 roleDAO.merge(userPO); 就可以用我给的version先check了.. 真是搞不通了... 不知道各位在用hibernate的时候这种情况是怎么处理的.. 给我一点建议吧.. 谢谢
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/59036#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 11 Mar 2007 02:42:24 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/59036</link>
        <guid>http://lingcm.javaeye.com/blog/59036</guid>
      </item>
      <item>
        <title>关于struts中validate的几种情况</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/23292" style="color:red;">http://lingcm.javaeye.com/blog/23292</a>&nbsp;
          发表时间: 2005年08月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          说明）这里采用了最新版本struts-1.2.7，是在struts-blank的基础上演示的，为了以后的学习和参考用。<br /><br /> <br /><br />一、在对应的Form Baens中重载validate方法<br /><br />在struts-config.xml文件中，action节点下有“validate”这样一个属性。在struts框架中，默认属性是validate=”true”。所以如果想通过Form Baens的重载validate方法来验证数据的话，可以不用理会这一点。题外话：如果你在struts-config.xml文件中，设置validate="false"的话，validate方法将不起作用。这一点同样对Validate框架来验证数据起作用。<br /><br /> <br /><br />二、通过Validate框架来验证数据<br /><br />1、首先在struts-config.xml文件中，追加如下代码：<br /><br />&lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;<br /><br />  &lt;set-property property="pathnames"<br /><br />          value="/WEB-INF/validator-rules.xml,/WEB-INF/validations.xml"/&gt;<br /><br />  &lt;set-property property="stopOnFirstError" value="false"/&gt;<br /><br />&lt;/plug-in&gt;<br /><br /> <br /><br />2、然后编写自己的Form Baens，有两种方式可供选择：<br /><br />① 写的formBaen需要继承ValidatorForm，而不是第一种方法中的ActionForm<br /><br />public class UserForm extends ValidatorForm {<br /><br />                     private String userId = "";<br /><br />                     private String password = "";<br /><br />                     public void setUserId(String userId) {<br /><br />                                   this.userId = userId;<br /><br />                     }<br /><br />                     public String getUserId() {<br /><br />                                   return userId;<br /><br />                     }<br /><br />                     。。。。。。<br /><br />          然后配置struts-config文件<br /><br />        &lt;form-bean  name="userForm"<br /><br />            type="com.wxhx.presentation.UserForm"/&gt;<br /><br />② 配置struts-config文件<br /><br />&lt;form-beans&gt;<br /><br />        &lt;form-bean name=" userForm"<br /><br />            type="org.apache.struts.validator.DynaValidatorForm"&gt;<br /><br />                &lt;form-property name=" userId" type="java.lang.String"/&gt;<br /><br />                &lt;form-property name="password" type="java.lang.String"/&gt;<br /><br />             &lt;/form-bean&gt;<br /><br />&lt;/form-beans&gt;<br /><br />3、配置validation.xml文件<br /><br />       &lt;formset&gt;<br /><br />           &lt;form name="userForm"&gt;  ----这里的userForm是Form Beans的名字<br /><br />            &lt;field<br /><br />                property="userId"<br /><br />                depends="required"&gt;<br /><br />                    &lt;arg key="userForm.userId"/&gt;<br /><br />            &lt;/field&gt;<br /><br />            &lt;field<br /><br />                property="password"<br /><br />                depends="required,mask"&gt;<br /><br />                    &lt;arg key="userForm.password"/&gt;<br /><br />                    &lt;var&gt;<br /><br />                        &lt;var-name&gt;mask&lt;/var-name&gt;<br /><br />                        &lt;var-value&gt;^[0-9a-zA-Z]*$&lt;/var-value&gt;<br /><br />                    &lt;/var&gt;<br /><br />            &lt;/field&gt;<br /><br />        &lt;/form&gt;<br /><br />       &lt;/formset&gt;<br /><br />       其中key="userForm.userId"和key="userForm.password"需要在资源文件中配置<br /><br />       这里需要说明一点，例如：&lt;arg key="userForm.password" resource="false"/&gt;<br /><br />如果多了resource="false"这句话，那么它不会再从资源文件中去取，而是直接用key值来表示。<br /><br /> <br /><br />以上是通过validatorForm- or DynaValidatorForm来实现Validate验证的<br /><br /> <br /><br />（附）<br /><br />现在有这样一个问题，Form Beans可以被多个Action应用，而每个Action可能需要的验证字段都不一样。而在validation.xml中配置的验证方式（如&lt;form name="userForm"&gt;）是对这个Form Beans进行的。这样的话，如何来验证呢？<br /><br />你的Form Beans可以继承ValidatorActionForm（当然可以直接配置DynaValidatorActionForm）。如下所示：<br /><br />public class UserForm extends ValidatorActionForm {<br /><br />  ...<br /><br />}<br /><br />或是<br /><br />&lt;form-bean name=" userForm "<br /><br />          type="org.apache.struts.validator.DynaValidatorActionForm"&gt;<br /><br />  ...<br /><br />&lt;/form-bean&gt;<br /><br /> <br /><br />struts-config文件配置如下：<br /><br />&lt;action-mappings&gt;<br /><br />  &lt;action path="/technology/createUser"<br /><br />         type="com.wxhx.minihr.CreateUserAction"<br /><br />         name="userForm"/&gt;<br /><br /> <br /><br />  &lt;action path="/technology/editUser"<br /><br />         type="com.wxhx.minihr.EditUserAction"<br /><br />         name="userForm"/&gt;<br /><br />&lt;/action-mappings&gt;<br /><br /> <br /><br />validation.xml文件配置如下：<br /><br />&lt;formset&gt;<br /><br />  &lt;form name="/technology/ createUser "&gt;----这里的采用的是action的path路径<br /><br />    &lt;field property="city"<br /><br />          depends="required"&gt;<br /><br />      &lt;arg0 key="prompt.city"/&gt;<br /><br />    &lt;/field&gt;<br /><br />  &lt;/form&gt;<br /><br />  &lt;form name="/technology/editUser "&gt;<br /><br />    &lt;field property="state"<br /><br />          depends="required"&gt;<br /><br />      &lt;arg0 key="prompt.state"/&gt;<br /><br />    &lt;/field&gt;<br /><br />  &lt;/form&gt;<br /><br />&lt;/formset&gt;<br /><br /> <br /><br />关于validator-rules.xml，定义了常用的一些规则，当然也可以自己追加新的规则。<br /><br />这里经常会看到msg="errors.required"字样，也是通过资源文件中配置的，默认的资源如下：<br /><br /># -- validator --<br /><br />errors.invalid={0} is invalid.<br /><br />errors.maxlength={0} can not be greater than {1} characters.<br /><br />errors.minlength={0} can not be less than {1} characters.<br /><br />errors.range={0} is not in the range {1} through {2}.<br /><br />errors.required={0} is required.<br /><br />errors.byte={0} must be an byte.<br /><br />errors.date={0} is not a date.<br /><br />errors.double={0} must be an double.<br /><br />errors.float={0} must be an float.<br /><br />errors.integer={0} must be an integer.<br /><br />errors.long={0} must be an long.<br /><br />errors.short={0} must be an short.<br /><br />errors.creditcard={0} is not a valid credit card number.<br /><br />errors.email={0} is an invalid e-mail address.<br /><br />这在struts-blank的例子中会有，在开发项目的时候，注意这些默认资源<br /><br />关于自己定义规则，以后再作研究<br /><br /> <br /><br />三、结合上面的两种验证<br /><br />如果即在Form Beans中重载了validate方法，又启用了Validate框架，那会是什么效果呢？<br /><br />由于要启用Validate框架，Form Beans需要继承ValidatorForm，查看ValidatorForm的源代码，发现validate方法已经作了处理（真是为Validate框架所服务的）。<br /><br />那么在Form Beans中重载了validate方法的话，就会覆盖原有ValidatorForm中对应的功能，所以如果想一起用的话，需要在Form Beans的validate方法中调用errors = super.validate(mapping, request);这句代码是启用Validate框架所要做的工作，然后可以判断errors再作下一步的处理。<br /><br />当然也可以先做Form Beans中的validate方法，然后启用Validate框架，要看具体情况而定。<br /><br /> <br /><br />四、启用客户端验证<br /><br />也是结合validation.xml来验证的，我把validation.xml相关的内容在复制下来，便于看清楚：<br /><br />       &lt;formset&gt;<br /><br />           &lt;form name="userForm"&gt;  ----这里的userForm是Form Beans的名字<br /><br />            &lt;field<br /><br />                property="userId"<br /><br />                depends="required"&gt;<br /><br />                    &lt;arg key="userForm.userId"/&gt;<br /><br />            &lt;/field&gt;<br /><br />            &lt;field<br /><br />                property="password"<br /><br />                depends="required,mask"&gt;<br /><br />                    &lt;arg key="userForm.password"/&gt;<br /><br />                    &lt;var&gt;<br /><br />                        &lt;var-name&gt;mask&lt;/var-name&gt;<br /><br />                        &lt;var-value&gt;^[0-9a-zA-Z]*$&lt;/var-value&gt;<br /><br />                    &lt;/var&gt;<br /><br />            &lt;/field&gt;<br /><br />        &lt;/form&gt;<br /><br />&lt;/formset&gt;<br /><br /> <br /><br />①在需要客户端验证的jsp中加上这么一句&lt;html:javascript formName=" userForm "/&gt;<br />其中formName就是validation.xml中&lt;form name="userForm"&gt;所对应的内容<br /><br />②在&lt;html:form中追加一个属性onsubmit="return validateUserForm(this);"<br /><br />它的语法为：return validate + struts-config.xml中定义的form-bean名称 + (this);<br /><br />③追加&lt;scriptlanguage="Javascript1.1"  src="staticJavascript.jsp"&gt;&lt;/script&gt;<br /><br />staticJavascript.jsp的内容为：<br /><br />&lt;%@ page language="java" %&gt;<br /><br />&lt;%-- set document type to Javascript(addresses a bug in Netscape according <br /><br />to a web resource --%&gt;<br /><br />&lt;%@ page contentType="application/x-javascript" %&gt;<br /><br />&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;<br /><br />&lt;html:javascript dynamicJavascript="false" staticJavascript="true"/&gt;<br /><br />这只是一种方式，还有其他简洁的（具体为啥这样，不是很明白，希望得到）<br /><br />比如：追加onsubmit="return validateUserForm(this);"<br /><br />&lt;html:javascript formName="userForm"  staticJavascript="true"/&gt;
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/23292#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 03 Aug 2005 14:56:42 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/23292</link>
        <guid>http://lingcm.javaeye.com/blog/23292</guid>
      </item>
      <item>
        <title>[Jakarta Commons笔记] 代码范例 - BeanUtils</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/23291" style="color:red;">http://lingcm.javaeye.com/blog/23291</a>&nbsp;
          发表时间: 2005年08月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          假定我们有如下两个标准的JavaBean：<br /><br /> <br /><br />/** Address.java */<br /><br /> <br /><br />package sean.study.commons.beanutils;<br /><br /> <br /><br />public class Address {<br /><br /> <br /><br />    private String zipCode;<br /><br />    private String addr;<br /><br />    private String city;<br /><br />    private String country;<br /><br /> <br /><br />    public Address() {<br /><br />    }<br /><br /> <br /><br />    public Address(String zipCode, String addr, String city, String country) {<br /><br />        this.zipCode = zipCode;<br /><br />        this.addr = addr;<br /><br />        this.city = city;<br /><br />        this.country = country;<br /><br />    }<br /><br /> <br /><br />    public String getAddr() {<br /><br />        return addr;<br /><br />    }<br /><br /> <br /><br />    public void setAddr(String addr) {<br /><br />        this.addr = addr;<br /><br />    }<br /><br /> <br /><br />    public String getCity() {<br /><br />        return city;<br /><br />    }<br /><br /> <br /><br />    public void setCity(String city) {<br /><br />        this.city = city;<br /><br />    }<br /><br /> <br /><br />    public String getCountry() {<br /><br />        return country;<br /><br />    }<br /><br /> <br /><br />    public void setCountry(String country) {<br /><br />        this.country = country;<br /><br />    }<br /><br /> <br /><br />    public String getZipCode() {<br /><br />        return zipCode;<br /><br />    }<br /><br /> <br /><br />    public void setZipCode(String zipCode) {<br /><br />        this.zipCode = zipCode;<br /><br />    }<br /><br /> <br /><br />}<br /><br /> <br /><br />/** Customer.java */<br /><br /> <br /><br />package sean.study.commons.beanutils;<br /><br /> <br /><br />public class Customer {<br /><br /> <br /><br />    private long id;<br /><br />    private String name;<br /><br />    private Address[] addresses;<br /><br /> <br /><br />    public Customer() {<br /><br />    }<br /><br /> <br /><br />    public Customer(long id, String name, Address[] addresses) {<br /><br />        this.id = id;<br /><br />        this.name = name;<br /><br />        this.addresses = addresses;<br /><br />    }<br /><br /> <br /><br />    public Address[] getAddresses() {<br /><br />        return addresses;<br /><br />    }<br /><br /> <br /><br />    public void setAddresses(Address[] addresses) {<br /><br />        this.addresses = addresses;<br /><br />    }<br /><br /> <br /><br />    public long getId() {<br /><br />        return id;<br /><br />    }<br /><br /> <br /><br />    public void setId(long id) {<br /><br />        this.id = id;<br /><br />    }<br /><br /> <br /><br />    public String getName() {<br /><br />        return name;<br /><br />    }<br /><br /> <br /><br />    public void setName(String name) {<br /><br />        this.name = name;<br /><br />    }<br /><br /> <br /><br />}<br /><br /> <br /><br /> <br /><br />我们来看看通常我们是怎样利用Commons BeanUtils来完成一些基本的JavaBean和DynaBean操作：<br /><br /> <br /><br />package sean.study.commons.beanutils;<br /><br /> <br /><br />import org.apache.commons.beanutils.BasicDynaBean;<br /><br />import org.apache.commons.beanutils.BasicDynaClass;<br /><br />import org.apache.commons.beanutils.DynaBean;<br /><br />import org.apache.commons.beanutils.DynaProperty;<br /><br />import org.apache.commons.beanutils.PropertyUtils;<br /><br />import org.apache.commons.lang.StringUtils;<br /><br /> <br /><br />public class BeanUtilsUsage {<br /><br /> <br /><br />    public static void main(String[] args) throws Exception {<br /><br />        demoNormalJavaBeans();<br /><br />        demoDynaBeans();<br /><br />    }<br /><br /> <br /><br />    public static void demoNormalJavaBeans() throws Exception {<br /><br /> <br /><br />        System.out.println(StringUtils.center(" demoNormalJavaBeans ", 40, "="));<br /><br />        <br /><br />        // data setup<br /><br />        Address addr1 = new Address("CA1234", "xxx", "Los Angeles", "USA");<br /><br />        Address addr2 = new Address("100000", "xxx", "Beijing", "China");<br /><br />        Address[] addrs = new Address[2];<br /><br />        addrs[0] = addr1;<br /><br />        addrs[1] = addr2;<br /><br />        Customer cust = new Customer(123, "John Smith", addrs);<br /><br />        <br /><br />        // accessing the city of first address<br /><br />        String cityPattern = "addresses[0].city";<br /><br />        String name = (String) PropertyUtils.getSimpleProperty(cust, "name");<br /><br />        String city = (String) PropertyUtils.getProperty(cust, cityPattern);<br /><br />        Object[] rawOutput1 = new Object[] { "The city of customer ", name,<br /><br />                "'s first address is ", city, "." };<br /><br />        System.out.println(StringUtils.join(rawOutput1));<br /><br />        <br /><br />        // setting the zipcode of customer's second address<br /><br />        String zipPattern = "addresses[1].zipCode";<br /><br />        if (PropertyUtils.isWriteable(cust, zipPattern)) {<br /><br />            System.out.println("Setting zipcode ...");<br /><br />            PropertyUtils.setProperty(cust, zipPattern, "200000");<br /><br />        }<br /><br />        String zip = (String) PropertyUtils.getProperty(cust, zipPattern);<br /><br />        Object[] rawOutput2 = new Object[] { "The zipcode of customer ", name,<br /><br />                "'s second address is now ", zip, "." };<br /><br />        System.out.println(StringUtils.join(rawOutput2));<br /><br />        <br /><br />        System.out.println();<br /><br />    }<br /><br /> <br /><br />    public static void demoDynaBeans() throws Exception {<br /><br /> <br /><br />        System.out.println(StringUtils.center(" demoDynaBeans ", 40, "="));<br /><br />        <br /><br />        // creating a DynaBean<br /><br />        DynaProperty[] dynaBeanProperties = new DynaProperty[] {<br /><br />                new DynaProperty("name", String.class), <br /><br />                new DynaProperty("inPrice", Double.class),  <br /><br />                new DynaProperty("outPrice", Double.class), <br /><br />        };<br /><br />        BasicDynaClass cargoClass = new BasicDynaClass("Cargo", BasicDynaBean.class, dynaBeanProperties);<br /><br />        DynaBean cargo = cargoClass.newInstance();<br /><br />        <br /><br />        // accessing a DynaBean<br /><br />        cargo.set("name", "Instant Noodles");<br /><br />        cargo.set("inPrice", new Double(21.3));<br /><br />        cargo.set("outPrice", new Double(23.8));<br /><br />        System.out.println("name: " + cargo.get("name"));<br /><br />        System.out.println("inPrice: " + cargo.get("inPrice"));<br /><br />        System.out.println("outPrice: " + cargo.get("outPrice"));<br /><br /> <br /><br />        System.out.println();<br /><br />    }<br /><br /> <br /><br />}<br /><br /> <br /><br />上述代码运行结果如下：<br /><br /> <br /><br />========= demoNormalJavaBeans ==========<br /><br />The city of customer John Smith's first address is Los Angeles.<br /><br />Setting zipcode ...<br /><br />The zipcode of customer John Smith's second address is now 200000.<br /><br /> <br /><br />============ demoDynaBeans =============<br /><br />name: Instant Noodles<br /><br />inPrice: 21.3<br /><br />outPrice: 23.8<br /><br /> <br /><br />以上代码简单说明了一下BeanUtils常见的基本用法，还有很多高阶或者更具体的应用及原理，这里无法一一讲到，而且有很多笔者也不熟悉、不了解，对BeanUtils的讲解就到此吧。如果你有兴趣，或者还不是很清楚为什么像这样动态的或者说松散的访问JavaBean是有必要的，可以把Struts的源码拿下来研究一下，看看FormBean以及DynaActionForm这些是如何被动态创建的，一定会有收获。
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/23291#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 03 Aug 2005 14:33:42 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/23291</link>
        <guid>http://lingcm.javaeye.com/blog/23291</guid>
      </item>
      <item>
        <title>具有臭味的代码</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/23023" style="color:red;">http://lingcm.javaeye.com/blog/23023</a>&nbsp;
          发表时间: 2005年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          下面介绍几种具有坏味道的代码结构，其中很多经验学习自Eclipse，与Martin Fowler不同的是，我找到的几种坏味道都存在于设计理念之中，而不是缺乏设计模式的抽象，也不是未重构的代码。先别急着反驳，也别急着嗤之以鼻，先想想这些设计理念的优点，看看是不是微不足道，再看看这些理念的缺点，是不是有可能铸成大错，作者还给出了去掉这些坏味道的某个思路，即作者自己的思路，仅供参考。最后，别忘了想想自己手中的软件的设计，看看会不会遇到其中的熟面孔啊。。。。。<br /><br />1。味道：控件耦合。<br />“如果第一个复选框被选中，那么下面的文本域全部失效。”通过这种方式表述的效果在软件开发中经常遇到，很多人称之为“界面逻辑”，想想看，界面逻辑真的可以直接变成代码吗？<br />典型重构思路：有限状态机。<br />状态与控件属性集一一对应，控件属性被改变时，状态机收到事件，检查状态是否发生了迁移，如果是则向控件属性集的控制器发出状态迁移事件，控制器批量改变控件状态。<br /><br />2。味道：控件/绘制器存在状态。<br />有人认为Motif和Windows已经差别很大了，有没有想过它们和IBM收银机上的字符界面差别有多大呢？既然差别这么大的绘制器仍然存在相同的复杂了（有时是很复杂的）状态，那我们为什么不把它们extract出来而要让它们冗余呢？<br />典型重构思路：视图的模型。<br />视图有视图的模型，并不是MVC中的模型，这种方式就是Swing的基础。<br /><br />3。味道：视图发出有意义的事件。<br />什么？你的意思是视图应该发出无意义的事件咯？不是这样吗？视图应该不了解任何业务逻辑，也不应该了解任何界面逻辑，如果界面逻辑真的存在的话。<br />典型重构思路：事件翻译器。<br />视图发出无意义的事件，比如鼠标事件，键盘事件，或某个控件的事件，事件翻译器把低级事件翻译为高级事件，再把高级事件包装成请求，请求被传递给一个根控制器。<br /><br />4。味道：动作/命令知道自己的形象。<br />很多时候，一个Action或者一个Command都知道自己叫什么名字，能不能被禁用，有没有被禁用，图标如何，甚至还知道及时帮助的字符串，执行需要什么条件，返回什么结果等等，如果这么做的话Action和Command就有了自己的视图状态，发出了第2种味道。<br />典型重构思路：动作代理。<br />重磅的工作交给代理完成，动作/命令只是一个视图的模型罢了。在UI系统装载之初，动作/命令被装载并绘制在界面上，直到用户点击或触发了这个动作/命令，它的代理才被调入并开始工作。<br /><br />5。味道：模型知道自己的每一个用处。<br />有n种视图对应同一个模型，比如对一个网页制作工具来说，一个html文件至少有三种视图：代码、设计、预览。如果模型同时能满足这三种视图的需求的话，这个模型就太重磅了，而且还不好添加一种新视图。比如Dreamwaver的代码/设计页面。<br />典型重构思路1：一个模型，多个维度。<br />如果一个模型拥有n个维度，则n个对象，就可以确定一个事实，n-1个对象就可以得到一个线性聚集，n-2个对象就可以得到一个二维表。每个维度就是一组Interface,而事实的类型，其实是不可见的，（内部的巨大类型），只能通过维度确定事实，再提取事实的属性。<br />典型重构思路2：适配器模式。<br />模型首先实现最必要的接口，然后当需要模型实现某个非必要接口时，模型会主动或被动的适配为一个满足需求接口的“意外”对象。<br /><br />6。味道：控制器变成顾问类。<br />有些人认为我们的社会需要复合型的人才，因为每个人都要具备管理的能力，控制器也要懂管理，它要负责视图和模型之间的交互。但是仔细想想，如果被模型以外的对象知道了业务逻辑的话，那模型还可以替换吗？<br />典型重构思路：控制器标准化。<br />控制器将请求包装为命令，并将命令交给命令堆栈执行。控制器并不了解模型，模型只能由模型自己了解，控制器也不知道领域逻辑，它只是做一些机械的翻译工作，并利用视图和模型提供的（互补相关）的素材，创建和模型相关的命令。<br /><br />7。味道：模型变成无所不知博士。<br />在没有发生上面六种情况的时候，千万不要大意啊，你很有可能发生了这一种情况，恰恰是因为控制器和视图都不知道业务逻辑，模型才有可能发展为Dr.Know。但是视图往往是树状结构的啊，它怎么和Dr.Know合作呢？通过代理？还是Facade？<br />典型重构思路：复杂模型结构（树状、图状、知识/操作分离）。<br />如果有可能，模型也是树状的，可以和视图一一对应；如果这一点做不到，不要紧，可以把大模型划分成轻量小板块，或者迭代子，再用关系对象解释它们之间的关系；如果还不行，那总得做到知识和操作分离吧。。。。。。。
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/23023#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 10 Apr 2005 21:31:13 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/23023</link>
        <guid>http://lingcm.javaeye.com/blog/23023</guid>
      </item>
      <item>
        <title>ActionForm 初始化</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/23001" style="color:red;">http://lingcm.javaeye.com/blog/23001</a>&nbsp;
          发表时间: 2005年04月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          如果一个action-mapping映射如下： <br />[code:1]<br />&lt;action path=&quot;/admin/prepareToMoveForum&quot; <br />type=&quot;com.jaqsoft.jaqforums.actions.admin.PrepareToMoveForumAction&quot;&gt; <br />&lt;/action&gt; <br />[/code:1]<br />那么当ActionServlet将请求发送传递给prepareToMoveForum的时候，是不构建ActionForm的， <br />也就是说，PrepareToMoveForumAction类中的: <br />[code:1]<br />public ActionForward execute&#40; <br />ActionMapping mapping, <br />ActionForm form, <br />HttpServletRequest request, <br />HttpServletResponse response&#41; <br />throws Exception &#123; <br />[/code:1]<br />form参数将是一个空的引用。 <br /><br />如果将映射文件改为： <br />[code:1]<br />&lt;action path=&quot;/admin/prepareToMoveForum&quot; <br />name=&quot;prepareToMoveForumForm&quot; <br />type=&quot;com.jaqsoft.jaqforums.actions.admin.PrepareToMoveForumAction&quot;&gt; <br />&lt;/action&gt; <br />[/code:1]<br />那么，当PrepareToMoveForumAction的时候是，会先从pageContext中查看有否prepareToMoveForumForm的对象， <br />如果没有，他将创建一个新的实例，然后调用此实例的validate方法，如果出现问题，那么，他调用ActionMapping.getInput()， <br />如果此时没有配置input选项，那么将抛出异常。因此，input选项存在的价值是：当validate没有通过的时候告诉ActionServlet <br />应该返回到哪个页面，这也就是为什么我必须为prepareToUpdateForumAction的prepareToUpdateForumForm配置input属性的原因， <br />因为，这个ActionForm中的属性的缺省值是不能通过validate的。 <br /><br />那么，现在要让，<br />[code:1] <br />public ActionForward execute&#40; <br />ActionMapping mapping, <br />ActionForm form, <br />HttpServletRequest request, <br />HttpServletResponse response&#41; <br />throws Exception &#123; <br />[/code:1]<br />不返回一个空的form，只要让ActionForm的validate方法通过即可。 <br />这样很容易办到，让validate方法为空，或者让有要求的属性赋初始值即可。 <br /><br />============================= <br />以上的方法会带来一个新的问题：完全可以构造一个不满足validate的 <br />一组数据，来填充这个formbean，一旦这个formbean被缓存之后，将随时 <br />有抛出No input attribute的异常。解决这个问题有个不合适的方法： <br />将验证写到action中，这样当然不太合理。但有更合适的方法吗？
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/23001#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 04 Apr 2005 21:52:31 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/23001</link>
        <guid>http://lingcm.javaeye.com/blog/23001</guid>
      </item>
      <item>
        <title>Struts+Spring+Hibernate快速入门</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/23000" style="color:red;">http://lingcm.javaeye.com/blog/23000</a>&nbsp;
          发表时间: 2005年04月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　本文是开发基于spring的web应用的入门文章，前端采用Struts MVC框架，中间层采用spring，后台采用Hibernate。 <br /><br />　　 本文包含以下内容：<br /><br />　　　 ·配置Hibernate和事务<br /><br />　　　 ·装载Spring的applicationContext.xml文件<br /><br />　　　 ·建立业务层和DAO之间的依赖关系<br /><br />　　　 ·将Spring应用到Struts中<br /><br />　　简介<br /><br />　　 这个例子是建立一个简单的web应用，叫MyUsers,完成用户管理操作，包含简单的数据库增，删，查，该即CRUD（新建，访问，更新，删除）操作。这是一个三层的web应用，通过Action（Struts）访问业务层，业务层访问DAO。图一简要说明了该应用的总体结构。图上的数字说明了流程顺序－从web（UserAction）到中间层（UserManager），再到数据访问层（UserDAO），然后将结果返回。<br /><br />　　 Spring层的真正强大在于它的声明型事务处理，帮定和对持久层支持（例如Hiberate和iBATIS）<br /><br />　　 以下下是完成这个例子的步骤：<br /><br />　　 1． 安装Eclipse插件<br /><br />　　 2． 数据库建表<br /><br />　　 3． 配置Hibernate和Spring<br /><br />　　 4． 建立Hibernate DAO接口的实现类<br /><br />　　 5． 运行测试类，测试DAO的CRUD操作<br /><br />　　 6． 创建一个处理类，声明事务<br /><br />　　 7． 创建web层的Action和model<br /><br />　　 8． 运行Action的测试类测试CRUD操作<br /><br />　　 9． 创建jsp文件通过浏览器进行CRUD操作<br /><br />　　 10． 通过浏览器校验jsp<br /><br />　　安装eclipse插件<br /><br />　　 1． Hibernate插件http://www.binamics.com/hibernatesync<br /><br />　　 2． Spring插件http://springframework.sourceforge.net/spring-ide/eclipse/updatesite/<br /><br />　　 3． MyEclipse插件(破解版)<br /><br />　　 4． Tomcat插件. tanghan<br /><br />　　 5． 其他插件包括xml，jsp，<br /><br />　　 数据库建表<br /><br />[code:1]
create table app_user&#40;id number not null primary,firstname vchar&#40;32&#41;,lastname vchar&#40;32&#41;&#41;;

[/code:1]
　　新建项目

　　 新建一个web project，新建后的目录结构同时包含了新建文件夹page用于放jsp文件，和源文件夹test用于放junit测试文件。同时将用到的包，包括struts，hibernate，spring都导入到lib目录下。

　　 创建持久层O/R mapping

　　 1． 在src/com.jandar.model下用hibernate插件从数据库导出app_user的.hbm.xml文件改名为User.hbm.xml

[code:1]
＜?xml version=&quot;1.0&quot;?＞
＜!DOCTYPE hibernate-mapping PUBLIC
　　 &quot;-//Hibernate/Hibernate Mapping DTD//EN&quot;
　　 &quot;http&#58;//hibernate.sourceforge.net/hibernate-mapping-2.0.dtd&quot; ＞
＜hibernate-mapping package=&quot;com.jandar.model&quot;＞
＜class name=&quot;User&quot; table=&quot;APP_USER&quot;＞
　 ＜id
　　 column=&quot;ID&quot;
　　 name=&quot;id&quot;
　　 type=&quot;integer&quot;
　 ＞

　　 ＜generator class=&quot;assigned&quot; /＞

　 ＜/id＞

　 ＜property
　　　 column=&quot;LASTNAME&quot;
　　　 length=&quot;10&quot;
　　　 name=&quot;lastname&quot;
　　　 not-null=&quot;false&quot;
　　　 type=&quot;string&quot;
　 /＞

　 ＜property
　　　 column=&quot;FIRSTNAME&quot;
　　　 length=&quot;10&quot;
　　　 name=&quot;firstname&quot;
　　　 not-null=&quot;true&quot;
　　　 type=&quot;string&quot;
　 /＞

＜/class＞
＜/hibernate-mapping＞ 
[/code:1]
　　 2． 通过hibernate synchronizer-＞synchronizer file生成User.java文件,User对象对应于数据库中的app_user表

　　 注：在eclipse下自动生成的对象文件不完全相同，相同的是每个对象文件必须实现Serializable接口，必需又toString和hashCode方法；

[code:1]
import java.io.Serializable;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class BaseObject implements Serializable &#123;
　 public String toString&#40;&#41; &#123;
　　 return ToStringBuilder.reflectionToString&#40;this,
　　 ToStringStyle.MULTI_LINE_STYLE&#41;;
　 &#125; 

　 public boolean equals&#40;Object o&#41; &#123;
　　 return EqualsBuilder.reflectionEquals&#40;this, o&#41;;
　 &#125; 

　 public int hashCode&#40;&#41; &#123;
　　 return HashCodeBuilder.reflectionHashCode&#40;this&#41;;
　 &#125;
&#125;
[/code:1]
[code:1]

public class User extends BaseObject &#123;
　 private Long id;
　 private String firstName;
　 private String lastName; 

　 /**
　 * @return Returns the id.
　 */

　 public Long getId&#40;&#41; &#123;
　　 return id;
　 &#125; 

　 /**
　　 * @param id The id to set.
　 */

　 public void setId&#40;Long id&#41; &#123;
　　 this.id = id;
　 &#125;

　 /**
　 * @return Returns the firstName.
　 */

　 public String getFirstName&#40;&#41; &#123;
　　 return firstName;
　 &#125; 

　 /**
　　 * @param firstName The firstName to set.
　 */

　 public void setFirstName&#40;String firstName&#41; &#123;
　　 this.firstName = firstName;
　 &#125; 

　 /**
　 * @return Returns the lastName.
　 */

　 public String getLastName&#40;&#41; &#123;
　　 return lastName;
　 &#125; 

　 /**
　 * @param lastName The lastName to set.
　 */

　 public void setLastName&#40;String lastName&#41; &#123;
　　 this.lastName = lastName;
　 &#125;
&#125;
[/code:1]

创建DAO访问对象

　　 1． 在src/com.jandar.service.dao新建IDAO.java接口，所有的DAO都继承该接口


[code:1]
package com.jandar.services.dao;

public interface IDAO &#123;

&#125;

[/code:1]
　　 2． 在src/com.jandar.service.dao下新建IUserDAO.java接口 

[code:1]
public interface IUserDAO extends DAO &#123; 
　 List getUsers&#40;&#41;;
　 User getUser&#40;Integer userid&#41;;
　 void saveUser&#40;User user&#41;;
　 void removeUser&#40;Integer id&#41;; 
&#125;

[/code:1]
　　 该接口提供了访问对象的方法，

　　 3． 在src/com.jandar.service.dao.hibernate下新建UserDAOHiberante.java
[code:1]
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.hibernate.support.HibernateDaoSupport; 
import com.jandar.model.User;
import com.jandar.service.dao.IUserDAO;

public class UserDaoHibernate extends HibernateDaoSupport implements IUserDAO &#123; 

　 private Log log=LogFactory.getLog&#40;UserDaoHibernate.class&#41;;
　 /* （非 Javadoc）
　 * @see com.jandar.dao.IUserDAO#getUsers&#40;&#41;
　 */

　 public List getUsers&#40;&#41; &#123;
　　 return getHibernateTemplate&#40;&#41;.find&#40;&quot;from User&quot;&#41;; 
　 &#125; 

　 /* （非 Javadoc）
　 * @see com.jandar.dao.IUserDAO#getUser&#40;java.lang.Long&#41;
　 */

　 public User getUser&#40;Integer id&#41; &#123;
　　 // TODO 自动生成方法存根
　　 return &#40;User&#41; getHibernateTemplate&#40;&#41;.get&#40;User.class,id&#41;;
　 &#125; 

　 /* （非 Javadoc）
　 * @see com.jandar.dao.IUserDAO#saveUser&#40;com.jandar.model.User&#41;
　 */

　 public void saveUser&#40;User user&#41; &#123;
　　 log.debug&#40;&quot;xxxxxxx&quot;&#41;;
　　 System.out.println&#40;&quot;yyyy&quot;&#41;;
　　 getHibernateTemplate&#40;&#41;.saveOrUpdate&#40;user&#41;;
　　 if&#40;log.isDebugEnabled&#40;&#41;&#41;
　　 &#123;
　　　 log.debug&#40;&quot;userId set to &quot;+user.getId&#40;&#41;&#41;;
　　 &#125; 
　 &#125; 

　 /* （非 Javadoc）
　 * @see com.jandar.dao.IUserDAO#removeUser&#40;java.lang.Long&#41;
　 */

　 public void removeUser&#40;Integer id&#41; &#123;
　　 Object user=getHibernateTemplate&#40;&#41;.load&#40;User.class,id&#41;;
　　 getHibernateTemplate&#40;&#41;.delete&#40;user&#41;;
　　 if&#40;log.isDebugEnabled&#40;&#41;&#41;&#123;
　　　 log.debug&#40;&quot;del user &quot;+id&#41;;
　　 &#125; 
　 &#125; 
&#125;
[/code:1][/code]
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/23000#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 04 Apr 2005 17:33:35 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/23000</link>
        <guid>http://lingcm.javaeye.com/blog/23000</guid>
      </item>
      <item>
        <title>Struts标记库</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/22995" style="color:red;">http://lingcm.javaeye.com/blog/22995</a>&nbsp;
          发表时间: 2005年03月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Struts标记库<br />JSP视窗组件所使用的struts标记库由四类标记组成：<br />2. Bean标记：用来在JSP页中管理bean<br />3. 逻辑标记：用来在JSP页中控制流程<br />4. HTML标记：用来生成HTML标记，在表单中显示数据，使用会话ID对URL进行编程<br />5. 模板标记：使用动态模板构造普通格式的页<br />2.1 Bean标记<br />这个标记库中包含用于定义新bean、访问bean及其属性的标记。Struts框架提供了多种自定义标记用来在JSP页中处理JavaBean。这些标记被封装在一个普通的标记库中，在文件struts-bean.tld中定义了它的标记库描述器。Bean标记库将标记定义在四个子类别中：<br />创建和复制bean的标记<br />脚本变量定义标记<br />bean翻译标记<br />消息国际化标记<br />2.1.1 Bean复制标记<br />可定义新bean，可复制现有bean，还可从现有bean复制属性。<br />&lt;bean:define&gt;标记用来：<br />定义新字符串常数<br />将现有的bean复制到新定义的bean对象<br />复制现有bean的属性来创建新的bean<br />&lt;bean:define&gt;标记属性：<br />属性描述Id 新定义的bean脚本变量名称，必须设置Type 定义引入脚本变量的类Value 为id属性定义的脚本变量分配一个新的对象Name 目标bean的名称。若value属性没有设置，这个属性就必须设置property Name属性定义的bean的属性名称，用来定义新的bean<br />13<br />Scope 源bean的作用域。若没有设置，搜索范围是从页作用域到应用程序作用域toScope 目标bean的作用域。若没有设置，默认值是页作用域<br />例如：定义一个bean:<br />&lt;bean:define id=”test” value=”this is a test”/&gt;<br />源bean在页作用域中被拷贝大哦请求作用域中的另一个bean:<br />&lt;bean:define id=”targetBean” name=”sourceBean”<br />scope=”page” toScope=”request”/&gt;<br />2.1.2 定义脚本变量的标记<br />从多种资源中定义和生成脚本变量，这些资源包括cookie,请求参数，HTTP标头等等。属性如下：<br />属性描述Id 脚本变量和要定义的页作用域属性的名称Name cookie/标头/参数的名称multiple 如果这个属性设置了任意一个数值，所有匹配的cookie都会被积累并存储到一个Cookie[](一个数组)类型的bean里。若无设置，指定cookie的第一个值将作为Cookie类型的值Value 如果没有匹配的cookie或数值，就返回这个属性指定的默认值<br />例如：<br />&lt;bean:cookie id=”myCookie” name=”userName”/&gt;<br />脚本变量名称是myCookie，用来创建这个属性的cookie的名称是userName。<br />&lt;bean:header id=”myHeader” name=”Accept-Language”/&gt;<br />脚本变量名称是myHeader,请求标头的名称是Accept-Language.<br />&lt;bean:parameter id=”myParameter” name=”myParameter”&gt;<br />脚本变量名称是myPatameter,它保存的请求参数的名称也是myParameter.<br />&lt;bean:include&gt;标记将对一个资源的响应进行检索，并引入一个脚本变量和字符串类型的页作用域属性。这个资源可以是一个页，一个ActionForward或一个外部URL。与&lt;jsp:include&gt;的不同是资源的响应被存储到一个页作用域的bean中，而不是写入到输出流。属性如下：<br />属性描述Id 脚本变量和要定义的页作用域属性的名称Page 一个内部资源forward 一个ActionForward Href 要包含的资源的完整URL<br />例如：<br />&lt;bean:include id=”myInclude” page=”MyJsp?x=1”/&gt;<br />脚本变量的名称是myInclude，要检索的响应来自资源MyJsp?x=1。<br />&lt;bean:resource&gt;标记将检索web应用中的资源，并引入一个脚本变量和InputStream或字符串类型的页作用域属性。如果在检索资源时发生问题，就会产生一个请求时间异常。属性如下：<br />属性描述<br />14<br />Id 脚本变量和要定义的页作用域属性的名称Name 资源的相对路径Input 如果这个属性不存在，资源的类型就是字符串<br />例如：<br />&lt;bean:resource id=”myResource” name=”/WEB-INF/images/myResource.xml”/&gt;<br />脚本变量的名称是myResource，要检索的资源的名称是myResource.xml。<br />2.1.3 显示Bean属性<br />标记库中定义了&lt;bean:write&gt;标记，用来将bean的属性输送到封装的JSP页写入器。这个标记与&lt;jsp:getProperty&gt;类似，属性如下：<br />属性描述Name 要进行属性显示的bean的名称property 要显示的属性的名称。如果这个属性类有java.beans.PropertyEditor,getAsText()或toString 方法会被调用Scope Bean的作用域，若没有设置，搜索范围是从页到应用程序作用域Filter 如果设置true,属性中的所有特殊HTML字符都将被转化为相应的实体引用Ignore 如果设置false，当发现属性时会产生一个请求时间异常，否则返回null<br />例如：<br />&lt;bean:write name=”myBean” property=”myProperty” scope=”request”<br />filter=”true”/&gt;<br />myBean的属性myProperty将会被显示，作用域为请求，如果发现任何HTML特殊字符都将被转化为相应的实体引用。<br />2.1.4 消息标记和国际化<br />strtus框架支持国际化和本地化。用户在他们的计算机中定义自己所在的区域，当web应用程序需要输出一条消息时，它将引用一个资源文件，在这个文件中所有的消息都使用了适当的语言。一个应用程序可能提供了很多资源文件，每个文件提供了用不同语言编写的消息。如果没有找到所选语言的资源文件，就将使用默认的资源文件。<br />struts框架对国际化的支持是使用&lt;bean:message&gt;标记，以及使用java.util数据包中定义的Locale和ResourceBundle类来实现Java2平台对这些任务的支持。Java.text.MessageFormat类定义的技术可以支持消息的格式。利用此功能，开发人员不需了解这些类的细节就可进行国际化和设置消息的格式。<br />用strtus实现国际化和本地化：<br />第一步要定义资源文件的名称，这个文件会包含用默认语言编写的在程序中会出现的所有消息。这些消息以“关键字-值”的形式存储，如下：<br />error.validation.location = The entered location is invalid<br />这个文件需要存储在类的路径下，而且它的路径要作为初始化参数传送给ActionServlet作为参数进行传递时，路径的格式要符合完整Java类的标准命名规范。比如，如果资源文件存储在WEB-INFclasses目录中，文件名是<br />15<br />ApplicationResources.properties，那么需要传递的参数值是ApplicationResources。如果文件在WEB-INFclassescom est中，那么参数值就应该是com.test. ApplicationResources.<br />为了实现国际化，所有的资源文件必须都存储在基本资源文件所在的目录中。基本资源文件包含的是用默认地区语言-本地语言编写的消息。如果基本资源文件的名称是ApplicationResources.properties，那么用其他特定语言编写的资源文件的名称就应该是ApplicationResources_xx.properties(xx为ISO编码，如英语是en)。因此这些文件应包含相同的关键字，但关键字的值是用特定语言编写的。<br />ActionServlet的区域初始化参数必须与一个true值一起传送，这样ActionServlet就会在用户会话中的Action.LOCALE_KEY关键字下存储一个特定用户计算机的区域对象。现在可以运行一个国际化的web站点，它可以根据用户计算机上的设置的区域自动以相应的语言显示。<br />我们还可以使用特定的字符串来替换部分消息，就象用java.text.MessageFormat的方法一样：<br />error.invalid.number = The number {0} is valid<br />我们可以把字符串{0}替换成任何我们需要的数字。&lt;bean:message&gt;标签属性如下：<br />属性描述Key 资源文件中定义消息关键字Locale 用户会话中存储的区域对象的属性名称。若没有设置，默认值是Action.LOCALE_KEY Bundle 在应用程序上下文中，存储资源对象的属性的名称。如果没有设置这个属性，默认值是Action.MESSAGE_KEY arg0 第一个替换参数值arg1 第二个替换参数值arg2 第三个替换参数值arg3 第四个替换参数值<br />例如：资源文件中定义了一个消息：<br />info.myKey = The numbers entered are {0},{1},{2},{3}<br />我们可使用下面的消息标记：<br />&lt;bean:message key=”info.myKey” arg0=”5” arg1=”6” arg2=”7” arg3=”8”/&gt;<br />这个信息标记输出到JSP页会显示为：The numbers entered are 5,6,7,8<br />2.2 逻辑标记<br />逻辑库的标记能够用来处理外观逻辑而不需要使用scriptlet。Struts逻辑标签库包含的标记能够有条件地产生输出文本，在对象集合中循环从而重复地产生输出文本，以及应用程序流程控制。它也提供了一组在JSP页中处理流程控制的标记。这些标记封装在文件名为struts-logic.tld的标记包中。逻辑标记库定义的标记能够执行下列三个功能：<br />条件逻辑<br />重复<br />转发/重定向响应<br />16<br />2.2.1 条件逻辑<br />struts有三类条件逻辑。第一类可以比较下列实体与一个常数的大小：<br />cookie<br />请求参数<br />bean或bean的参数<br />请求标头<br />以下列出了这一类标记：<br />标记功能&lt;equal&gt; 如果常数与被定义的实体相等，返回true &lt;notEqual&gt; 如果常数与被定义的实体不相等，返回true &lt;greaterEqual&gt; 如果常数大于等于被定义的实体，返回true &lt;lessEqual&gt; 如果常数小于等于被定义的实体，返回true &lt;lessThan&gt; 如果常数小于被定义的实体，返回true &lt;greaterThan&gt; 如果常数大于被定义的实体，返回true<br />这一类的所有标记有相同的属性<br />属性描述Value 要进行比较的常数值Cookie 要进行比较的HTTP cookie的名称Header 要进行比较的HTTP请求标头的名称parameter 要进行比较的HTTP请求参数的名称Name 如果要进行比较的是bean或bean的属性，则这个属性代表bean的名称property 要进行比较的bean属性的名称Scope Bean的作用域，如果没有指定作用域，则它的搜索范围是从页到应用程序<br />例如：<br />&lt;logic:equal parameter=”name” value=”SomeName”&gt;<br />The entered name is SomeName<br />&lt;/logic:equal&gt;<br />判断名为”name”的请求参数的值是否是”SomeName”。<br />&lt;logic:greaterThan name=”bean” property=”prop” scope=”page” value=”7”&gt;<br />The value of bean.Prop is greater than 7<br />&lt;/logic:greaterThan&gt;<br />判断在页的作用域中是否有一个名为”bean”的bean，它有一个prop属性，这个属性的值是否大于7。如果这个属性能够转化为数值，就进行数值比较，否则就进行字符串比较。<br />第二类条件标记定义了两个标记：<br />&lt;logic:present&gt;<br />&lt;logic:notPresent&gt;<br />它们的功能是在计算标记体之前判断特定的项目是否存在。标记的属性和属性值决定了要进行检查的项目。<br />属性描述<br />17<br />Cookie 由这个属性指定的cookie将被检查是否存在Header 由这个属性指定的请求标头将被检查是否存在parameter 由这个属性指定的请求参数将被检查是否存在Name 如果没有设置property属性，那么有这个属性指定的bean将被检查是否存在。如果设置了，那么bean和bean属性都将被检查是否存在。property 检查有name属性指定的bean中是否存在指定的属性Scope 如果指定了bean的名称，这就是bean的作用域。如果没有指定作用域，搜索的范围从页到应用程序作用域。Role 检查当前已经确认的用户是否属于特殊的角色User 检查当前已经确认的用户是否有特定的名称<br />例如：<br />&lt;logic:notPresent name=”bean” property=”prop” scope=”page”&gt;<br />The bean property bean.prop is present<br />&lt;/logic:notPresent&gt;<br />标记判断在页作用域中是否存在一个名为”bean”的bean，这个bean有一个prop属性。<br />第三类条件标记比较复杂，这些标记根据模板匹配的结果检查标记体的内容。换句话说，这些标记判断一个指定项目的值是否是一个特定常数的子字符串：<br />&lt;logic:match&gt;<br />&lt;logic:notMatch&gt;<br />这些标记允许JSP引擎在发现了匹配或是没有发现时计算标记主体。属性如下：<br />属性描述Cookie 要进行比较的HTTP cookie的名称Header 要进行比较的的HTTP标头的名称parameter 要进行比较的的HTTP请求参数的名称Name 若要对bean或bean的属性进行比较，这个属性是用户指定bean的名称location 如果设置了这个属性的值，将会在这个指定的位置(索引值)进行匹配scope 如果对bean进行比较，这个属性指定了bean的作用域。如果没有设置这个参数，搜索范围是从页到应用程序作用域property 要进行比较的bean的属性名称value 要进行比较的常数值<br />例如：<br />&lt;logic:match parameter=”name” value=”xyz” location=”1”&gt;<br />The parameter name is a sub-string of the string xyz from index 1<br />&lt;/logic:match&gt;<br />标记检查名为”name”的请求参数是否是”xyz”的子字符串，但是子字符串必须从”xyz”的索引位置1开始（也就是说子字符串必须是”y”或”yz”）。<br />2.2.2 重复标记<br />在逻辑标记库中定义了&lt;logic:iterate&gt;标记，它能够根据特定集合中元素的数目对标记体的内容进行重复的检查。集合的类型可以是java.util.Iterator,java.util.Collection<br />18<br />,java.util.Map或是一个数组。有三种方法可以定义这个集合：<br />使用运行时间表达式来返回一个属性集合的集合<br />将集合定义为bean，并且使用name属性指定存储属性的名称。<br />使用name属性定义一个bean，并且使用property属性定义一个返回集合的bean属性。<br />当前元素的集合会被定义为一个页作用域的bean。属性如下，所有这些属性都能使用运行时表达式。<br />属性描述collection 如果没有设置name属性，它就指定了要进行重复的集合Id 页作用域bean和脚本变量的名称，它保存着集合中当前元素的句柄indexed 页作用域JSP bean的名称，它包含着每次重复完成后集合的当前索引Length 重复的最大次数Name 作为集合的bean的名称，或是一个bean名称，它由property属性定义的属性，是个集合Offset 重复开始位置的索引property 作为集合的Bean属性的名称Scope 如果指定了bean名称，这个属性设置bean的作用域。若没有设置，搜索范围从页到应用程序作用域Type 为当前定义的页作用域bean的类型<br />例如：<br />&lt;logic:iterate id=”currentInt”<br />collection=”&lt;% =myList %&gt;”<br />type=”java.lang.Integer”<br />offset=”1”<br />length=”2”&gt;<br />&lt;% =currentint %&gt;<br />&lt;/logic:iterate&gt;<br />代码将从列表中的第一个元素开始重复两个元素并且能够让当前元素作为页作用域和java.lang.Integer类型的脚本变量来使用。也就是说，如果myList包含元素1，2，3，4等，代码将会打印1和2。<br />2.2.3 转发和重定向标记<br />转发标记<br />&lt;logic:forward&gt;标记能够将响应转发给重定向到特定的全局ActionForward上。ActionForward的类型决定了是使用PageContext转发响应，还是使用sendRedirect将响应进行重定向。此标记只有一个”name”属性，用来指定全局ActionForward的名称，例如：<br />&lt;logic:forward name=”myGlobalForward”/&gt;<br />重定向标记<br />&lt;logic:redirect&gt;标记是一个能够执行HTTP重定向的强大工具。根据指定的不同属性，它能够通过不同的方式实现重定向。它还允许开发人员指定重定向URL的查询参数。属性如下：<br />19<br />属性描述Forward 映射了资源相对路径的ActionForward Href 资源的完整URL Page 资源的相对路径Name Map类型的页名称，请求，会话或程序属性的名称，其中包含要附加大哦重定向URL（如果没有设置property属性）上的“名称-值”参数。或是具有Map类型属性的bean名称，其中包含相同的信息（没有设置property属性） Property Map类型的bean属性的名称。Bean的名称由name属性指定。Scope 如果指定了bean的名称，这个属性指定搜索bean的范围。如果没有设置，搜索范围从页到应用程序作用域ParamID 定义特定查询参数的名称ParamName 字符串类型的bean的名称，其中包含查询参数的值(如果没有设置paramProperty属性)；或是一个bean的名称，它的属性(在paramProperty属性中指定)包含了查询参数值paramProperty 字符串bean属性的名称，其中包含着查询参数的值ParamScope ParamName定义的bean的搜索范围<br />使用这个标记时至少要指定forward,href或page中的一个属性，以便标明将响应重定向到哪个资源。<br />2.3 HTML标记<br />Struts HTML标记可以大致地分为以下几个功能：<br />显示表单元素和输入控件<br />显示错误信息<br />显示其他HTML元素<br />2.3.1 显示表单元素和输入控件<br />struts将HTML表单与为表单操作而定义的ActionForm bean紧密联系在一起。表单输入字段的名称与ActionForm bean里定义的属性名称是对应的。当第一次显示表单时，表单的输入字段是从ActionForm bean中移植过来的，当表单被提交时，请求参数将移植到ActionForm bean实例。<br />所有可以在&lt;form&gt;标记中使用的用来显示HTML输入控件的内嵌标记都使用下列属性来定义JavaScript事件处理器。<br />属性描述Onblur 字段失去了焦点Onchange 字段失去了焦点并且数值被更改了Onclick 字段被鼠标点击Ondblclick 字段被鼠标双击Onfocus 字段接收到输入焦点Onkeydown 字段拥有焦点并且有键按下<br />20<br />onkeypress 字段拥有焦点并且有键按下并释放Onkeyup 字段拥有焦点并且有键被释放onmousedown 鼠标指针指向字段并且点击onmousemove 鼠标指针指向字段并且在字段内移动onmouseout 鼠标指针指向控件，但是指针在元素外围移动onmouseover 鼠标指针没有指向字段，但是指针在元素内部移动Onmouseup 鼠标指针指向字段，并且释放了鼠标按键<br />&lt;form&gt;元素中能够被定义的其他一般属性有：<br />属性描述Accesskey 定义访问输入字段的快捷键Style 定义输入字段的样式styleClass 定义输入字段的样式表类Tabindex 输入字段的tab顺序<br />a) 表单标记<br />&lt;html:form&gt;标记用来显示HTML标记，可以指定AcitonForm bean的名称和它的类名。如果没有设置这些属性，就需要有配置文件来指定ActionMapping以表明当前输入的是哪个JSP页，以及从映射中检索的bean名和类。如果在ActionMapping指定的作用域中没有找到指定的名称，就会创建并存储一个新的bean，否则将使用找到的bean。<br />&lt;form&gt;标记能够包含与各种HTML输入字段相对应的子标记。<br />&lt;html:form&gt;标记属性如下：<br />属性描述Action 与表单相关的操作。在配置中，这个操作也用来标识与表单相关的ActionForm bean Enctype 表单HTTP方法的编码类型Focus 表单中需要初始化焦点的字段Method 表单使用的HTTP方法Name 与表单相关的ActionForm bean的名称。如果没有设置这个属性，bean的名称将会从配置信息中获得Onreset 表单复位时的JavaScript事件句柄Onsubmit 表单提交时的JavaScript事件句柄Scope 搜索ActionForm bean的范围。如果没有设置，将从配置文件中获取Style 使用的格式styleClass 这个元素的格式表类Type ActionForm bean的完整名称。如果没有设置，将从配置文件获得<br />例如：<br />&lt;html:form action=”validateEmploee.do” method=”post”&gt;<br />&lt;/html:form&gt;<br />与表单相关的操作路径是validateEmployee,而表单数据是通过POST传递的。对于这个表单来说，ActionForm bean的其他信息，如bean名称类型，作用域，都是从表单指定操作的ActionMapping中检索得到的：<br />21<br />&lt;form-beans&gt;<br />&lt;form-bean name=”empForm” type=”com.example.EmployeeForm”/&gt;<br />&lt;/form-beans&gt;<br />&lt;action-mappings&gt;<br />&lt;action path=”/validateEmployee”<br />type=”com.example.ValidateExampleAction”<br />name=”empForm”<br />scope=”request”<br />input=”/employeeInput.jsp”&gt;<br />&lt;forward name=”success” path=”/employeeOutput.jsp”&gt;<br />&lt;/action&gt;<br />&lt;/action-mapping&gt;<br />如果配置文件中包含上述信息，并且请求URI的*.do被映射到ActionServlet，与表单相关的ActionForm bean的名称，类型和作用域分别是empForm,com.example.EmployeeForm和request.这些属性也可以使用&lt;html:form&gt;标记属性进行显示的定义。<br />以下标记必须嵌套在&lt;html:form&gt;标记里<br />b) 按钮和取消标记<br />&lt;html:button&gt;标记显示一个按钮控件；&lt;html:cancel&gt;标记显示一个取消按钮。属性如下：<br />属性描述Property 定义在表单被提交时返回到服务器的请求参数的名称Value 按钮上的标记<br />c) 复位和提交标记<br />&lt;html:reset&gt;和&lt;html:submit&gt;标记分别能够显示HTML复位按钮和提交按钮。<br />d) 文本和文本区标记<br />&lt;html:text&gt;和&lt;html:textarea&gt;标记分别HTML文本框和文本区，属性如下：<br />属性描述Property 定义当表单被提交时送回到服务器的请求参数的名称，或用来确定文本元素当前值的bean的属性名称Name 属性被查询的bean的名称，它决定了文本框和文本区的值。如果没有设置，将使用与这个内嵌表单相关的ActionForm的名称<br />&lt;html:text&gt;标记还有以下属性：<br />属性描述Maxlength 能够输入的最大字符数<br />22<br />Size 文本框的大小（字符数）<br />&lt;html:textarea&gt;标记特有的属性如下：<br />属性描述Rows 文本区的行数Cols 文本区的列数<br />e) 检查框和复选框标记<br />&lt;html:checkbox&gt;标记能够显示检查框控件。&lt;html:multibox&gt;标记能够显示HTML复选框控件，请求对象在传递检查框名称时使用的getParameterValues()调用将返回一个字符串数组。属性如下：<br />属性描述Name Bean的名称，其属性会被用来确定检查是否以选中的状态显示。如果没有设置，将使用与这个内嵌表单相关的ActionFrom bean的名称。Property 检查框的名称，也是决定检查框是否以选中的状态显示的bean属性名称。在复选框的情况下，这个属性必须是一个数组。Value 当检查框被选中时返回到服务器的请求参数的值<br />例如：<br />&lt;html:checkbox property=”married” value=”Y”/&gt;<br />一个名为married的检查框，在表单提交时会返回一个”Y”.<br />f) 文件标记<br />&lt;html:file&gt;标记可以显示HTML文件控件。属性如下：<br />属性描述Name Bean的名称，它的属性将确定文件控件中显示的内容。如果没设置，将使用与内嵌表单相关的ActionForm bean的名称property 这个属性定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定文件控件中显示内容的bean属性名称Accept 服务器能够处理的内容类型集。它也将对客户浏览器对话框中的可选文件类型进行过滤Value 按钮上的标记，这个按钮能够在本地文件系统中浏览文件<br />g) 单选钮标记<br />&lt;html:radio&gt;标记用来显示HTML单选钮控件，属性如下：<br />属性描述Name Bean的名称，其属性会被用来确定单选钮是否以选中的状态显示。如果没有设置，将使用与这个内嵌表单相关的ActionFrom bean的名称。property 当表单被提交时送回到服务器的请求参数的名称，以及用来确定单选钮是否以被选中状态进行显示的bean属性的名称<br />23<br />Value 当单选钮被选中时返回到服务器的值<br />h) 隐藏标记<br />&lt;html:hidden&gt;标记能够显示HTML隐藏输入元素，属性如下：<br />属性描述Name Bean的名称，其属性会被用来确定隐藏元素的当前值。如果没有设置，将使用与这个内嵌表单相关的ActionFrom bean的名称。property 定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定隐藏元素当前值的bean属性的名称Value 用来初始化隐藏输入元素的值<br />i) 密码标记<br />&lt;html:password&gt;标记能够显示HTML密码控件，属性如下：<br />属性描述maxlength 能够输入的最大字符数Name Bean的名称，它的属性将用来确定密码元素的当前值。如果没有设置，将使用与这个内嵌表单相关的ActionFrom bean的名称。property 定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定密码元素当前值的bean属性的名称redisplay 在显示这个字段时，如果相应的bean属性已经被设置了数据，这个属性决定了是否显示密码的内容Size 字段的大小<br />j) 选择标记<br />&lt;html:select&gt;标记能够显示HTML选择控件，属性如下：<br />属性描述multiple 表明这个选择控件是否允许进行多选Name Bean的名称，它的属性确定了哪个。如果没有设置，将使用与这个内嵌表单相关的ActionFrom bean的名称。property 定义了当表单被提交时送回到服务器的请求参数的名称，以及用来确定哪个选项需要被选中的bean属性的名称Size 能够同时显示的选项数目Value 用来表明需要被选中的选项<br />k) 选项标记(这个元素需要嵌套在&lt;html:select&gt;标记里)<br />&lt;html:option&gt;标记用来显示HTML选项元素集合，属性如下：<br />24<br />属性描述collection Bean集合的名称，这个集合存储在某个作用域的属性中。选项的数目与集合中元素的数目相同。Property属性能够定义选项值所使用的bean属性，而labelProperty属性定义选项标记所使用的bean的属性labelName 用来指定存储于某个作用域的bean，这个bean是一个字符串的集合，能够定义&lt;html:option&gt;元素的标记(如果标志与值不相同) labelProperty 与collection属性共同使用时，用来定义了存储于某个作用域的bean，这个bean将返回一个字符串集合，能够用来写入&lt;html:option&gt;元素的value属性Name 如果这是唯一被指定的属性，它就定义了存储于某个作用域的bean，这个bean将返回一个字符串集合，能够用来写入&lt;html:option&gt;元素的value属性property 这个属性在与collection属性共同使用时，定义了每个要显示选项值的独立bean的name属性。如果不是与collection属性共同使用，这个属性定义了由name属性指定的bean的属性名称(如果有name属性)，或是定义了一个ActionForm bean，这个bean将返回一个集合来写入选项的值<br />我们看一下这个标记的一些例子：<br />&lt;html:option collection=”optionCollection” property=”optionValue”<br />labelProperty=”optionLabel”/&gt;<br />标记假设在某个作用域中有一个名为optionCollection的集合，它包含了一些具有optionValue属性的独立的bean，每个属性将作为一个选项的值。每个选项的标志由bean的optionLabel属性属性进行定义。<br />&lt;html:option name=”optionValues” labelName=”optionLabels”/&gt;<br />标记中optionValues代表一个存储在某个作用域中的bean，它是一个字符串集合，能够用来写入选项的值，而optionLabels代表一个存储在某个作用域中的bean，它也是一个字符串集合，能够用来写入选项的标志。<br />2.3.2.显示错误信息的标记<br />&lt;html:errors&gt;标记能够与ActionErrors结合在一起来显示错误信息。这个标记首先要从当前区域的资源文件中读取消息关键字errors.header，然后显示消息的文本。接下去它会在ActionErrors对象(通常作为请求参数而存储在Action.ERROR_KEY关键字下)中循环，读取单个ActionError对象的消息关键字，从当前区域的资源文件中读取并格式化相应的消息，并且显示它们。然后它读取与errors.footer关键字相对应的消息并且显示出来。<br />通过定义property属性能够过滤要显示的消息，这个属性的值应该与ActionErrors对象中存储ActionError对象的关键字对应。属性如下：<br />属性描述Bundle 表示应用程序作用域属性的名称，它包含着消息资源，其默认值Acion.MESSAGE_KEY Locale 表示会话作用域属性的名称，它存储着用户当前登录的区域信息。其默认值是Action.ERROR_KEY<br />25<br />Name 表示请求属性的名称，它存储着ActionErrors对象。其默认值是Action.ERROR_KEY property 这个属性指定了ActionErrors对象中存储每个独立ActionError对象的关键字，它可以过滤消息<br />例子：<br />&lt;html:errors/&gt;<br />显示集合中所有的错误。<br />&lt;html:errors property=”missing.name”/&gt;<br />显示存储在missing.name关键字的错误。<br />2.3.3.其他HTML标记<br />struts HTML标记还定义了下列标记来显示其他HTML元素：<br />&lt;html:html&gt; : 显示HTML元素<br />&lt;html:img&gt; : 显示图象标记<br />&lt;html:link&gt; : 显示HTML链接或锚点<br />&lt;html:rewrite&gt; : 创建没有锚点标记的URI<br />这些标记的详细内容请参照struts文档。<br />2.4. 模板标记<br />动态模板是模块化WEB页布局设计的强大手段。Struts模板标记库定义了自定义标记来实现动态模板。<br />2.4.1.插入标记<br />&lt;template:insert&gt;标记能够在应用程序的JSP页中插入动态模板。这个标记只有一个template属性，用来定义模板JSP页。要插入到模板的页是有多个&lt;template:put&gt;标记来指定的，而这些标记被定义为&lt;template:insert&gt;标记的主体内容。<br />2.4.2.放置标记<br />&lt;template:put&gt;标记是&lt;template:insert&gt;标记内部使用的，用来指定插入到模板的资源。属性如下：<br />属性描述content 定义要插入的内容，比如一个JSP文件或一个HTML文件direct 如果这个设置为true，由content属性指定的内容将直接显示在JSP上而不是作为包含文件Name 要插入的内容的名称Role 如果设置了这个属性，只有在当前合法用户具有特定角色时才能进行内容的插入。<br />26<br />2.4.3.获得标记<br />在模板JSP页中使用&lt;template:get&gt;标记能够检索由&lt;template:put&gt;标记插入到JSP页的资源。属性如下：<br />属性描述Name 由&lt;template:put&gt;标记插入的内容的名称Role 如果设置了这个属性，只有在当前合法用户具有特定角色时才能进行内容的检索<br />2.4.4.使用模板标记<br />首先编写一个模板JSP页，它将被所有的web页使用：<br />&lt;html&gt;<br />&lt;%@ taglib uri=”/template” prefix=”template” %&gt;<br />&lt;head&gt;<br />&lt;title&gt;&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;table width=”100%” height=”100%” &gt;<br />&lt;tr height=”10%”&gt;<br />&lt;td&gt;<br />&lt;template:get name=”header”/&gt;<br />&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr height=”80%”&gt;<br />&lt;td&gt;<br />&lt;template:get name=”content”/&gt;<br />&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr height=”10%”&gt;<br />&lt;td&gt;<br />&lt;template:get name=”footer”/&gt;<br />&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;/table&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br />我们将这个文件命名为template.jsp。这个文件使用&lt;template:get&gt;标记来获得由JSP页使用&lt;template:put&gt;标记提供的内容，并且将内容在一个HTML表格中显示出来。这三个内容是标题，内容和页脚。典型的内容JSP会是这样：<br />&lt;%@ taglib uri=”/template” prefix=”/template” %&gt;<br />&lt;template:insert template=”template.jsp”&gt;<br />&lt;template:put name=”header” content=”header.html”/&gt;<br />27<br />&lt;template:put name=”content” content=”employeeList.jsp”/&gt;<br />&lt;template:put name=”footer” content=”footer.html”/&gt;<br />&lt;/template:insert&gt;<br />这个应用程序JSP页使用&lt;template:insert标记来定义模板，然后使用&lt;template:put&gt;标记将特定内容名称指定的资源放到模板JSP页中。如果我们有上百个布局相同的页，但突然想改变这个模板，我们只需要改变template.jsp文件。
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/22995#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 30 Mar 2005 18:12:47 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/22995</link>
        <guid>http://lingcm.javaeye.com/blog/22995</guid>
      </item>
      <item>
        <title>Eclipse3.0.1上安装tanghan插件。</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/22991" style="color:red;">http://lingcm.javaeye.com/blog/22991</a>&nbsp;
          发表时间: 2005年03月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Tanghan Plugin是jlinux开发的Eclipse上运行的Hibernate的插件工具，可以辅助生成hbm映射文件和POJO。具体情况请看以下网址：<br />http://www.hibernate.org.cn/download/jlinux/help/<br /><br />但是我们发现tanghan的制作者只发布了支持Eclipe2.1.*和Hibernatebanben2.0.3的版本以及支持Eclipe3.0M5和Hibernatebanben2.0.3的版本，具体请看这里：<br />http://www.hibernate.org.cn/download/jlinux/<br /><br />我在使用最新的Eclipe3.0.1版时发现，tanghan插件不支持。<br /><br />经过我的1个小时的研究，我让tanghan插件插入了Eclipe3.0.1。<br />其实很简单：<br />只要把Eclipe3.0M5中有的插件而Eclipe3.0.1没有的插件，拷贝到Eclipe3.0.1中就可以了。<br />也就是将Eclipe3.0M5中plugins目录下的以下这些插件拷贝到eclipse3.0.1中的plugins目录下，就搞定了：<br />org.apache.lucene_1.3.0.RC2<br />org.apache.xerces_4.0.13<br />org.eclipse.help.ui.win32_3.0.0<br />org.eclipse.platform.source.win32.win32.x86_3.0.0<br />org.eclipse.swt.win32_3.0.0<br />org.eclipse.ui.versioncheck_3.0.0<br />org.eclipse.ui.win32_3.0.0<br />org.eclipse.update.ui.forms_3.0.0<br /><br />这样不仅tanghan可以用了，连lomboz等其他插件也能用了。
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/22991#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 28 Mar 2005 13:17:41 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/22991</link>
        <guid>http://lingcm.javaeye.com/blog/22991</guid>
      </item>
      <item>
        <title>english study</title>
        <author>lingcm</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lingcm.javaeye.com">lingcm</a>&nbsp;
          链接：<a href="http://lingcm.javaeye.com/blog/22980" style="color:red;">http://lingcm.javaeye.com/blog/22980</a>&nbsp;
          发表时间: 2005年03月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          暂时还不能用英语写出自己的想法!没有办法,选择了计算机也就意味着自己也一起选择了english,记得有位兄弟说过,看不懂英语的计算机书就永远也站不到计算机的高段,默默的对自己说一定要努力,努力…… 相信一句不能成为英语的英语（我就成为英语成语了）“Good good study , day day up”努力吧自己！以后这些话一定要用e文写出来！
          <br/><br/>
          <span style="color:red;">
            <a href="http://lingcm.javaeye.com/blog/22980#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 24 Mar 2005 15:37:02 +0800</pubDate>
        <link>http://lingcm.javaeye.com/blog/22980</link>
        <guid>http://lingcm.javaeye.com/blog/22980</guid>
      </item>
  </channel>
</rss>