<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>老丛的博客</title>
    <description></description>
    <link>http://congpeixue.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>Click framework 的 Page类</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/230275" style="color:red;">http://congpeixue.javaeye.com/blog/230275</a>&nbsp;
          发表时间: 2008年08月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          pages（页面）是web程序的核心。 在click中，页面将html请求的处理<br />和html呈现整合在了一起。<br />本节讨论的click页面涵盖以下主题：<br />Classes - 页面对应的java类<br />Execution - 页面执行序列<br />Request Param Auto Binding - 请求参数自动绑定到page字段<br />Security - 页面安全模型<br />Navigation - 页面之间的跳转<br />Page Templating - 页面模板<br />Direct Rendering -页面 直接呈现<br />Stateful - 状态页 <br />Error Handling - 页面错误处理<br />Page Not Found - 对不能找到页面的处理<br />Message Properties - 页面消息属性<br /><br />在click中，一个逻辑页面由java类和Velocity 模板组成， 它们被定义在<br />click.xml的page元素里。<br />&lt;page path="search.htm" classname="com.mycorp.page.Search"/> <br /><br />path属性指定了Velocity 模板的位置， classname 属性指定了<br />java类的名字。<br /><br />如果你使用其他的模板引擎，使用步骤如上。<br />你也可以配置Click 使用jsp来呈现页面<br />&lt;page path="search.jsp" classname="com.mycorp.page.Search"/> <br /><br /><br /><br /><strong>Classes</strong><br /><br />所有的用户自定义page类都必须是Page的子类。如下的图标1描述了<br />Page类和它的关联类 （Context类及Control类）的关系。<br /><img src="http://www.javaeye.com/upload/attachment/35437/37d1d9c0-95bb-359d-8504-5d808ab92489.png" /><br /><br />page提供了model属性，model属性中保存着用于在Velocity 模板中显示的对象。<br />model属性也可以包含Control对象。<br /><br />Page拥有一个 Context对像， 用于访问所有的servlet对象。 当你使用Click进行<br />编程时， 你可以使用该对象来访问HttpServletRequest  parameters  HttpSession <br /><br /><br />Page类提供了一些空的处理方法， 用户可以覆盖这些方法。<br />onSecurityCheck() <br />onInit() <br />onGet() <br />onPost() <br />onRender() <br />onDestroy() <br /><br />ClickServlet 依赖一个public类型的无参的构造方法来初始化一个Page类， 所以当你<br />新建一个Page类的子类时， 你必须确保你没有添加一个不兼容的构造方法。<br /><br /><br />Execution<br />关于Page的GET请求的执行序列， 被概括如下：<br /><br /><img src="http://www.javaeye.com/upload/attachment/35435/3b839d71-a7a8-34da-b924-61052a461dee.png" />
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/230275#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Tue, 19 Aug 2008 23:25:36 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/230275</link>
        <guid>http://congpeixue.javaeye.com/blog/230275</guid>
      </item>
      <item>
        <title>选择click的理由</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/223670" style="color:red;">http://congpeixue.javaeye.com/blog/223670</a>&nbsp;
          发表时间: 2008年08月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          本话题讨论Click的设计原理和Click背后的原理，并希望阐明为什么<br />部分人选择了Click作为他们的web开发框架。<br /><br />Click是一款时兴的JEEweb应用框架， 提供了一种简单的富客户端程序设计<br />风格。 click包含的主要特征如下：<br /><br /><strong>简单易学</strong><br />click被设计的很简单以便于学习， 新开发者在一天内就可上手并运行<br />出来。 这对技术层次跨度很大的开发团队是非常关键的。<br /><br /> 向开发团队介绍Tapestry (2.3)时，我的经历是， Tapestry (2.3)非常复杂，<br />一般的程序员不容易学习。我曾经介绍使用Tapestry 的两个团队最终都放弃<br />了使用Tapestry ，返回继续使用Struts。<br /><br />Click比struts容易学习很多。Struts框架， 本质上使用了简化的命令<br />模式设计思想，包含很多费解并容易使人糊涂的设计。<br />为了便于学习， click作为开源的框架有着丰富的文档，并包含了很多<br />可以运行的例子。<br /><br /><br /><br /><strong>面向控件和页面设计</strong><br />如果你曾经使用Swing, VB 或 Delphi 做过经典的GUI编程， 你会发现<br />JEE web设计中存在一些非常严重的错误。JEE web设计运行非常缓慢，复杂，<br />并有很多错误。<br /><br />作为最早的JEE web设计框架之一的Struts提供了一种基于命令的设计<br />模式和一组jsp标签。不幸的是， 使用Struts你需将URLs映射到Actions，<br />还需使用ActionForms，这些特点本质上并没有为你的程序开发起到明显的<br />杠杆作用。<br /><br />Tapestry 也是一款JEE web 框架， 它较早的引用了组件， 页面和基于编程<br />模型的事件等概念。 它较大的提高了生产率， 这也是当我们遇到开发桌面<br />应用需求常用的替代方案。<br /><br />click的设计思路就是借鉴这种基于页面和组件的设计方法， 并使它变的更<br />更容易使用。<br /><br />click提供了一种面向页面的设计，控件元件特征和基于编程的事件模型。<br />click包含40种左右的控件， 这些控件对应了大部分主要的HMTL元素。 <br /><br />click表单和控件提供了自动验证和页面呈现，使程序开发变得更加快速和<br />健壮。<br /><br /><br /><strong>Velocity</strong><br />Click 使用Velocity引擎来呈现HTML。 Velocity有一组非常容易学习和使用的<br />简单指令集。 例如下面的指令集。<br /><pre name="code" class="java">#if (!$session.order.lineItems.empty)
&lt;table>
  &lt;tr>
    &lt;th>Name&lt;/th> &lt;th>Quantity&lt;/th> &lt;th>Total Price&lt;/th>
  &lt;/tr>
  #foreach ($lineItem in $session.order.lineItems)
  &lt;tr>
    &lt;td>$lineItem.name&lt;/td> 
    &lt;td>$lineItem.quantity&lt;/td>   
    &lt;td>$lineItem.totalPrice&lt;/td>   
  &lt;/tr>
  #end
&lt;/table>
#else
  No items have been ordered.
#end 
</pre><br /><br /><br />你或许会对这些没有使用任何标签的代码所做的事情感兴趣。 Velocity的使用简单使它<br />成了click的首选。<br /><br />请注意click的模板服务是可插入式， 你同样可以使用Freemarker或jsp在click中<br />呈现你个页面。<br />值得一提的是， 近年来jsp2.0及jsp El表达式也大大提高了jsp的可用性。
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/223670#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 03 Aug 2008 21:24:29 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/223670</link>
        <guid>http://congpeixue.javaeye.com/blog/223670</guid>
      </item>
      <item>
        <title>Java中堆和栈的区别 </title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/223258" style="color:red;">http://congpeixue.javaeye.com/blog/223258</a>&nbsp;
          发表时间: 2008年08月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          栈与堆都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。 <br /><br />     Java的堆是一个运行时数据区,类的对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立，它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的，堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，因为它是在运行时动态分配内存的，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要在运行时动态分配内存，存取速度较慢。 <br /><br />     栈的优势是，存取速度比堆要快，仅次于寄存器，栈数据可以共享。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。栈中主要存放一些基本类型的变量（,int, short, long, byte, float, double, boolean, char）和对象句柄。 <br /><br />栈有一个很重要的特殊性，就是存在栈中的数据可以共享。假设我们同时定义： <br />int a = 3; <br />int b = 3； <br /><br />      编译器先处理int a = 3；首先它会在栈中创建一个变量为a的引用，然后查找栈中是否有3这个值，如果没找到，就将3存放进来，然后将a指向3。接着处理int b = 3；在创建完b的引用变量后，因为在栈中已经有3这个值，便将b直接指向3。这样，就出现了a与b同时均指向3的情况。 <br /><br />      这时，如果再令a=4；那么编译器会重新搜索栈中是否有4值，如果没有，则将4存放进来，并令a指向4；如果已经有了，则直接将a指向这个地址。因此a值的改变不会影响到b的值。 <br /><br />      要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的，因为这种情况a的修改并不会影响到b, 它是由编译器完成的，它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态，会影响到另一个对象引用变量。 <br /><br />String是一个特殊的包装类数据。可以用： <br />String str = new String("abc"); <br />String str = "abc"; <br /><br />      两种的形式来创建，第一种是用new()来新建对象的，它会在存放于堆中。每调用一次就会创建一个新的对象。 而第二种是先在栈中创建一个对String类的对象引用变量str，然后查找栈中有没有存放"abc"，如果没有，则将"abc"存放进栈，并令str指向”abc”，如果已经有”abc” 则直接令str指向“abc”。 <br /><br />比较类里面的数值是否相等时，用equals()方法；当测试两个包装类的引用是否指向同一个对象时，用==，下面用例子说明上面的理论。 <br />String str1 = "abc"; <br />String str2 = "abc"; <br />System.out.println(str1==str2); //true <br />可以看出str1和str2是指向同一个对象的。 <br /><br />String str1 =new String ("abc"); <br />String str2 =new String ("abc"); <br />System.out.println(str1==str2); // false <br />用new的方式是生成不同的对象。每一次生成一个。 <br /><br /><br />     因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度，因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc")；的代码，则一概在堆中创建新对象，而不管其字符串值是否相等，是否有必要创建新对象，从而加重了程序的负担。 <br /><br />      另一方面, 要注意: 我们在使用诸如String str = "abc"；的格式定义类时，总是想当然地认为，创建了String类的对象str。担心陷阱！对象可能并没有被创建！而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。 <br />由于String类的immutable性质，当String变量需要经常变换其值时，应该考虑使用StringBuffer类，以提高程序效率。 <br /><br /><br />转载地址： http://q.yesky.com/group/dsc/view.do?rvId=9259291
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/223258#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Sat, 02 Aug 2008 00:47:55 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/223258</link>
        <guid>http://congpeixue.javaeye.com/blog/223258</guid>
      </item>
      <item>
        <title>Click framework 导言(二)</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/221321" style="color:red;">http://congpeixue.javaeye.com/blog/221321</a>&nbsp;
          发表时间: 2008年07月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong>Simple Form </strong><br /><br />表单和字段同样是Click框架中经常使用的控件。<br />下面的SimpleForm 提供了这些控件的一个简单应用。<br />在下面的例子代码中， 我们在表单中添加一个textfield字段和一个submit按钮， 同时<br />设置一个方法作为表单的控件监听器。<br />注意： 在本例中page的public类型的form字段被自动的添加到控件列表中。<br /><br /><pre name="code" class="java">public class SimpleForm extends Page {

    public Form form = new Form();
    public String msg;

    // ------------------------------------------------------------ Constructor

    public SimpleForm() {
        form.add(new TextField("name", true));
        form.add(new Submit("OK"));

        form.setListener(this, "onSubmit");
    }

    // --------------------------------------------------------- Event Handlers

    /**
     * 处理表单的提交事件
     */
    public boolean onSubmit() {
        if (form.isValid()) {
            msg = "Your name is " + form.getFieldValue("name");
        }
        return true;
    }
}</pre><br /><br />然后我们新建SimpleForm 的模板 simple-form.htm。 Click会自动地把simple-form.htm <br />模板和SimpleForm 类关联起来。<br /><br /><pre name="code" class="java">&lt;html>
&lt;head>
$cssImports
&lt;/head>
&lt;body>
  
$form
  
#if ($msg)
  &lt;div id="msgDiv"> $msg &lt;/div>
#end
    
&lt;/body>
&lt;/html> 
$jsImports</pre><br /><br />当SimpleForm page被第一次请求的时候， $form 对象将自动地在页面上显示出来。<br /><br />这里要说明的是，如果用户没有输入用户名就点击了Ok按钮来提交表单。 ClickServlet <br />将生成一个新的SimpleForm实例并处理表单控件，表单控件处理时发现该字段不合法，<br />所以onsubmit()方法简单的返回一个true。 之后， 表单将显示验证错误信息。<br /><br /><img src="http://www.javaeye.com/upload/attachment/32804/bcb7526a-1d22-3525-ac1a-3bdfc58964df.jpg" /><br /><br />在提交和验证的时候表单将自动的维护输入的数据的状态。<br /><br />现在如果用户输入了名字并点击了OK按钮， 表单将被验证通过并通过onSubmit()将msg信息<br />添加到Pages模型中。页面将显示如下:<br />Your name is John Masters <br /><br /><br /><strong>Advanced Form Example</strong><br /><br />AdvancedForm  Page将提供一个使用表单的高级的例子，使用form、 field和fieldSet。<br />首先我们让AdvancedForm 在他的构造方法中生成一个Form。Form的Select列表<br />在页面的onInit()方法中被组装。此时， 要求page依赖的所有资源应该是有效的。<br /><br />在本例中， page的public类型的form字段被自动地添加到控件列表中。<br /><br /><pre name="code" class="java">public class AdvancedForm extends Page {

    public Form form = new Form();
    public String msg;

    private Select investmentSelect = new Select("investment");

    // ------------------------------------------------------------ Constructor

    public AdvancedForm() {
        FieldSet fieldSet = new FieldSet("Customer");
        form.add(fieldSet);

        TextField nameField = new TextField("name", true);
        nameField.setMinLength(5);
        nameField.setFocus(true);
        fieldSet.add(nameField);

        fieldSet.add(new EmailField("email", true));

        fieldSet.add(investmentSelect);

        fieldSet.add(new DateField("dateJoined", true));
        fieldSet.add(new Checkbox("active"));

        form.add(new Submit("ok", " OK ", this, "onOkClicked"));
        form.add(new Submit("cancel", this, "onCancelClicked"));
    }

    // --------------------------------------------------------- Event Handlers

    /**
     * @see Page#onInit()
     */
    public void onInit() {
        CustomerService customerService = getCustomerService();
        investmentSelect.add(Option.EMPTY_OPTION);
        investmentSelect.addAll(customerService.getInvestmentCatetories());
    }

    /**
     * 处理Ok 按钮的Click事件
     *
     * @return true
     */
    public boolean onOkClicked() {
        if (form.isValid()) {
            Customer customer = new Customer();
            form.copyTo(customer);

            getCustomerService().saveCustomer(customer);

            form.clearValues();

            msg = "A new customer record has been created.";
        }
        return true;
    }

    /**
     * Handle the Cancel button click event.
     *
     * @return false
     */
    public boolean onCancelClicked() {
        setRedirect(HomePage.class);
        return false;
    }
}</pre><br /><br />新建AdvancedForm 的对应的模板advanced-form.htm， Click 会自动地将advanced-form.htm 模板与AdvancedForm 类关联起来。<br /><br /><pre name="code" class="java">&lt;html>
&lt;head>
$cssImports
&lt;/head>
&lt;body>

#if ($msg)
  &lt;div id="msgDiv"> $msg &lt;/div>
#end
  
$form
    
&lt;/body>
&lt;/html> 
$jsImports</pre><br /><br />当AdvancedForm 第一次请求页面的时候， $form 对象对显示出来。<br /><img src="http://www.javaeye.com/upload/attachment/32802/ecb7cc75-993b-3bc8-9e8e-715368638c5d.jpg" /><br /><br />在本例中，当Ok按钮被点击的时候onOkClicked()被调用。 如果表单是有效的，一个新的<br />customer 对象被创建并使用form的copyto()方法将表单字段的值拷贝到customer对象中去。之后， customer 对象被保存，表单字段值被清空， info信息被显示给用户。<br /><br /><br /><strong>Form Layout</strong><br /><br />上面我们使用了表单控件来生成html表单和字段。 对快速构建页面这是一个很<br />好的特点 。表单控件也提供了一些布局属性。参见后面的章节。
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/221321#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Tue, 29 Jul 2008 22:54:17 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/221321</link>
        <guid>http://congpeixue.javaeye.com/blog/221321</guid>
      </item>
      <item>
        <title>Click framework 导言(一)</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/220823" style="color:red;">http://congpeixue.javaeye.com/blog/220823</a>&nbsp;
          发表时间: 2008年07月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Click 是一个简单的商用JEE web程序框架，项目在遵从Apache license. 的<br />前提下开源。 <br />Click 使用一个基于programming model 的事件来处理servlet请求。<br />使用Velocity来呈现页面。(其他的模板引擎如jsp和Freemarker也被支持)<br /><br />此框架使用了一个单独的名为ClickServlet的servlet,来作为请求分发器。<br />当一个请求到来的时候，ClickServlet生成一个Page对象来处理请求并<br />使用Velocity模板来呈现结果 。<br />Pages 为每个servlet请求生成一个新的page实例，以此来<br />提供了一个简单的线程安全的设计环境，<br /><br />可能的最好的学习Click如何工作的方式是练习一些例子。<br /><br /><em>Hello World - 经典的Hello World例子<br />Control Listener - 一个ActionLink控件监听器例子<br />Simple Table - 一个简单的Table控件例子<br />Advanced Table - 一个高级的Table控件例子<br />Simple Form - 一个简单的表单例子<br />Advanced Form - 一个复杂的表单例子</em><br /><strong><br />Hello World</strong><br /><br />一个使用Click的Hello World 例子如下所示<br />首先我们新建一个HelloWorld类<br /><pre name="code" class="java">package examples.page;

import java.util.Date;
import net.sf.click.Page;

public HelloWorld extends Page {

    public Date time = new Date();

} </pre><br /><br />建立一个page模板 hello-world.htm<br /><pre name="code" class="java">&lt;html>
  &lt;body>
  
    &lt;h2>Hello World&lt;/h2>
    
    Hello world from Click at $time
    
  &lt;/body>
&lt;/html> </pre><br /><br />最后建立一个click.xml配置文件，使用它来告诉Click将对<br />hello-world.htm 的请求映射到我们的HelloWorld类。<br /><br /><pre name="code" class="java">&lt;click-app>  
  &lt;pages package="examples.page"/> 
&lt;/click-app> </pre><br /><br />在运行期间，ClickSerlvet 映射一个Get请求hello-world.htm 到<br />我们的page类example.page.HelloWorld ， 并生成一个新的实例。<br />HelloWorld 生成一个新的public类型的Date对象， 并使用字段time<br />自动地将该对象添加到页面模型中。<br />页面模型使用Date对象替换掉模板中的$time ， Velocity呈现模板页面<br />如下：<br /><div class="quote_title">引用</div><div class="quote_div">Hello World<br />Hello world from Click at Tue May 08 19:37:05 EST 2007 </div><br /><strong><br />Control Listener</strong><br /><br />Click包含一系列提供用户接口功能的控件。<br /> ActionLink就是被广泛使用的其中之一， 你可以使用它在<br />一个Page对象中使一个链接调用一个方法。例如：<br /><pre name="code" class="java">public class ControlListenerPage extends Page {

    public ActionLink myLink = new ActionLink();

    public String msg;
    
    // ----------------------------------------------------------- Constructors

    /**
     * 生成一个新的Page实例
     */
    public ControlListenerPage() {
        myLink.setListener(this, "onMyLinkClick");
    }
    
    // --------------------------------------------------------- Event Handlers

    /**
     * 处理 the myLink 控件点击事件
     */
    public boolean onMyLinkClick() {
        msg = "ControlListenerPage#" + hashCode()
            + " object method &lt;tt>onMyLinkClick()&lt;/tt> invoked.";

        return true;
    }
}</pre><br /><br />在这个Page类里我们生成了一个名为myLink 的ActionLink并定义<br />对应本页面的控件的监听器方法onMyLinkClick()，<br />当用户点击了MyLink控件，它将执行监听器方法onMyLinkClick()。<br /><br />在Click中， 一个监听器方法可以起任何名字但必须返回一个布尔值。<br />该布尔值指定了下面的处理是否还要继续。<br /><br />回到我们的例子中，在page模板中， 我们定义了一个HTML链接，<br /><br /><pre name="code" class="java">&lt;html>
  &lt;head>
    &lt;link type="text/css" rel="stylesheet" href="style.css">&lt;/link>
  &lt;/head>
  &lt;body>
  
  Click myLink control &lt;a href="$myLink.href">here&lt;/a>.

  #if ($msg)
    &lt;div id="msgDiv"> $msg &lt;/div>
  #end

  &lt;/body>
&lt;/html></pre><br /><br />在运行期间此页面将被呈现如下：<br /><div class="quote_title">引用</div><div class="quote_div">Click myLink control <span style="color: red">here</span>.</div><br /><br /><br />当用户点击了link， onMyLinkClick()将被调用。 此方法生成了一个<br />msg模型值， 呈现如下：<br /><div class="quote_title">引用</div><div class="quote_div">Click myLink control here. <br />ControlListenerPage#12767107 object method onMyLinkClick() invoked. </div><br /><br /><strong>Simple Table Example</strong><br /><br />Table控件是最常使用的控件之一。<br />在客户端页面中使用Table控件的一个例子如下：<br /><pre name="code" class="java">public class SimpleTablePage extends Page {

    public Table table = new Table();

    // ------------------------------------------------------------ Constructor
     
    public SimpleTablePage() {
        table.setClass(Table.CLASS_ITS);
        
        table.addColumn(new Column("id"));
        table.addColumn(new Column("name"));
        table.addColumn(new Column("email"));
        table.addColumn(new Column("investments"));
    }
    
    // --------------------------------------------------------- Event Handlers
     
    /**
     * @see Page#onRender()
     */
    public void onRender() {
    	List list = getCustomerService().getCustomersSortedByName(10);
    	table.setRowList(list);
    }
}</pre><br /><br />在此例子中， 一个Table控件被生成，我们设置了表格的html类，并<br />定义了一些列对象。在这些列定义中，我们在其构造方法中指定了<br />列的名字。<br />最后做的事情是使用数据来组装表格。 我们只需覆写Page的onRender()<br />方法并在表格显示前设置表格的列表。<br /><br />在我们的页面模板中， 我们简单的引用了$table对象，当其toString()方法<br />被调用的时候，$table被呈现在页面上。<br /><pre name="code" class="java">&lt;html>
&lt;head>
$cssImports
&lt;/head>
&lt;body>
  
$table
    
&lt;/body>
&lt;/html> 
$jsImports</pre><br /><br />在上面我们指定了$cssImports 引用， 以便表格在头部可以包含<br />css样式。同时我们在底部也定义了$jsImports来引用scripts 。<br /><br />在运行期间， 表格将被呈现如下：<br /><br /><img src="http://www.javaeye.com/upload/attachment/32708/4611e523-995f-35d8-bce1-884b67482d8e.png" /><br /><strong>Advanced Table Example</strong><br />Table控件还提供如下支持：<br /><em>自动呈现<br />列格式化<br />自动分页<br />链接支持</em><br />一个更高级的Table例子如下：<br /><pre name="code" class="java">public class CustomerPage extends Page {

    public Table table = new Table();
    public PageLink editLink = new PageLink("Edit", EditCustomer.class);
    public ActionLink deleteLink = new ActionLink("Delete", this, "onDeleteClick");

    // ------------------------------------- Constructor
     
    public CustomersPage() {
        table.setClass(Table.CLASS_ITS);
        table.setPageSize(10);
        table.setShowBanner(true);
        table.setSortable(true);
    	
        table.addColumn(new Column("id"));

        table.addColumn(new Column("name"));
        
        Column column = new Column("email");
        column.setAutolink(true);
        column.setTitleProperty("name");
        table.addColumn(column);
        
        table.addColumn(new Column("investments"));
        
        editLink.setImageSrc("/images/window-edit.png");
        editLink.setTitle("Edit customer details");
        editLink.setParameter("referrer", "/introduction/advanced-table.htm");
        
        deleteLink.setImageSrc("/images/window-delete.png");
        deleteLink.setTitle("Delete customer record");
        deleteLink.setAttribute("onclick", "return window.confirm('Are you sure you want to delete this record?');");
    	
        column = new Column("Action");
        column.setTextAlign("center");
        AbstractLink[] links = new AbstractLink[] { editLink, deleteLink };
        column.setDecorator(new LinkDecorator(table, links, "id"));
        column.setSortable(false);
        table.addColumn(column);
    }
    
    // ---------------------------------- Event Handlers
         
    /**
     * Handle the delete row click event.
     */    
    public boolean onDeleteClick() {
        Integer id = deleteLink.getValueInteger();
        getCustomerService().deleteCustomer(id);
        return true;
    }
    
    /**
     * @see Page#onRender()
     */
    public void onRender() {
    	List list = getCustomerService().getCustomersByName();
    	table.setRowList(list);
    }
} </pre><br /><br />在这个Page代码中，一个Table控件被声明并添加了一些Columns对象。一个<br />名为 deleteLink的 ActionLink被用做“Action”列的装饰器。当此控件被点击的时候<br />将执行onDeleteClick()方法。最后，当页面被显示的时候，调用onRender()方法<br />来使Table控件和列完成组装。<br />在我们的页面模板中我们简单引用 $table对象 ， 当它的toString()方法被调用时， <br />$table对象被呈现出来。<br /><br /><pre name="code" class="java">&lt;html>
&lt;head>
$cssImports
&lt;/head>
&lt;body>
  
$table
    
&lt;/body>
&lt;/html>
$jsImports </pre><br /><br />在运行期间，表格将被呈现的页面如下：<br /><img src="http://www.javaeye.com/upload/attachment/32706/8d4fdc2d-8576-326e-b8b9-6aedc6e074a6.png" /><br />在这个例子中，如果用户点击了Delete链接， onDeleteClick()方法将被调用来<br />删除用户列。<br /><br />(续)
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/220823#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 28 Jul 2008 23:01:56 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/220823</link>
        <guid>http://congpeixue.javaeye.com/blog/220823</guid>
      </item>
      <item>
        <title>Click framework 快速入门指南</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/220221" style="color:red;">http://congpeixue.javaeye.com/blog/220221</a>&nbsp;
          发表时间: 2008年07月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          本章讨论的是如何快速组建一个web应用程序。只涉及基本的使程序能运行成功的部分， 不涉及IDE的配置。<br />该快速入门程序包含在Examples文件夹下。<br /><br />接下去的主题将涵盖：<br /><br /><u>web应用结构<br />Jar文件<br />Welcome File <br />Home Page <br />框架模板<br />日志<br />入门工程快速生成</u><br /><br /><strong>web应用结构</strong><br /><br />首先在你的web程序WEB-INF 目录下添加click.xml 和web.xml 配置文件。<br />click.xml<br />你的click.xml应该包含：<br /><pre name="code" class="java">&lt;?xml version="1.0" encoding="UTF-8"?> 
&lt;click-app> 

  &lt;pages package="com.quickstart.page"/>

&lt;/click-app>  </pre><br /><br />web.xml<br />你的web.xml应该包含<br /><pre name="code" class="java">&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;web-app>

  &lt;servlet>
    &lt;servlet-name>ClickServlet&lt;/servlet-name>
    &lt;servlet-class>net.sf.click.ClickServlet&lt;/servlet-class>
    &lt;load-on-startup>0&lt;/load-on-startup>
  &lt;/servlet>
  
  &lt;servlet-mapping>
    &lt;servlet-name>ClickServlet&lt;/servlet-name>
    &lt;url-pattern>*.htm&lt;/url-pattern>
  &lt;/servlet-mapping>
  
  &lt;welcome-file-list>
    &lt;welcome-file>redirect.html&lt;/welcome-file>
  &lt;/welcome-file-list>
  
&lt;/web-app></pre><br /><br /><strong>Jar文件</strong><br /><br />把如下jar文件添加到你的程序的WEB-INF/lib目录下：<br />click-1.x.jar <br />click-extras-1.x.jar <br /><br />你可以在Click 的dist目录下获得这些文件。<br /><br /><strong>Welcome File</strong><br /><br />为确保默认的请求被转发到 home page， 我们将在web程序根目录下新建<br />redirect.html。 文件内容：<br /><pre name="code" class="java">&lt;html>
&lt;head>&lt;meta http-equiv="Refresh" content="0;URL=home.htm">&lt;/head>
&lt;/html>  </pre><br /><br />在web.xml中配置redirect.html， 使默认的请求都由该文件来提供服务。<br />当浏览器执行redirect.html 时， 它将被转发到home.html页面。<br /><br /><strong>Home Page</strong><br /><br />现在我们准备来添加我们的第一个Click页面来作为我们应用程序的主页。<br />首先我们定义一个class HomePage ， 确保该class文件部署到应用程序<br />的 WEB-INF/classes 目录 。<br /><pre name="code" class="java">package com.quickstart.page;

import net.sf.click.Page;

public class HomePage extends Page {

} </pre><br /><br />我们在web主目录下添加相应的主页home.htm 。<br /><pre name="code" class="java">&lt;html>
&lt;head>
  &lt;title>Home&lt;/title>
  &lt;link rel="stylesheet" type="text/css" href="style.css" title="Style"/>
&lt;/head>

&lt;body>
 
  &lt;div id="header">
    &lt;span id="title">Home&lt;/span>
  &lt;/div>

  &lt;div id="container">
    &lt;b>Welcome&lt;/b> to Home page your application starting point.
  &lt;/div>
 
&lt;/body>
&lt;/html> </pre><br /><br />在你的主目录下添加 style.css文件<br /><pre name="code" class="java">body {
	font-family: Arial;
}

#header {
	background-color: navy;
}

#title {
	color: white; 
	font-size: 18px;
	font-weight: bolder;
}

#container { 
	padding-top: 1em;
	padding-left: 1.5em;
	position: relative;
	z-index: 0;
}

h3.title {
	margin-top: 0em;
	margin-bottom: 1em;
}</pre><br /><br />现在如果你web应用被部署到quickstart， 你应该能够生成如下请求：<br />http://localhost:8080/quickstart/ <br />你的浏览器被定位到HomePage ， 你应该能看到如下页面：<br /><img src="http://www.javaeye.com/upload/attachment/32524/d0ae7b12-3bf0-3ad7-bc4d-9a6ea0032164.jpg" /><br /><br />在这个例子中，Click将对文件home.htm的请求自动映射到HomePage class，<br />并使用该class来处理请求。<br /><br /><strong>框架模板（Border Template）</strong><br /><br />现在我们打算建立一个页面框架模板，以便应用程序页面有一个统一的风格。<br />首先在web根目录下建立文件border-template.htm。 此文件包含如下内容。<br /><pre name="code" class="java">&lt;html>
&lt;head>
&lt;title>Click Quickstart - $title&lt;/title>
&lt;link rel="stylesheet" type="text/css" href="$context/assets/style.css" title="Style"/>
&lt;/head>

&lt;body>
 
  &lt;div id="header">
    &lt;span class="title">$title&lt;/span>
  &lt;/div>
  
  &lt;div id="container">
    #parse($path)
  &lt;/div>
 
&lt;/body>
&lt;/html> </pre><br />现在我们定义BorderPage 类， 并将border-template.htm 文件指定为他的<br />模板。<br /><br /><pre name="code" class="java">package com.quickstart.page;

import net.sf.click.Page;

public class BorderPage extends Page {

   public String getTemplate() {
      return "border-template.htm";
   }

}</pre><br /><br />我们命名模板文件为border-template.htm ， 以便它不会自动地被Click映射<br />我们的BorderPage 类。<br />现在我们修改HomePage 类， 使其继承自BorderPage ， 并定义一个title字段。<br /><br /><pre name="code" class="java">public class HomePage extends BorderPage {

    public String title = "Home";

} </pre><br /><br />修改home.htm， 将页面borber去掉。 home.html内容如下：<br /><pre name="code" class="java">&lt;b>Welcome&lt;/b> to Home page your application starting point. </pre><br />修改后的web应用程序文件如下：<br /><br /><img src="http://www.javaeye.com/upload/attachment/32526/b350e666-4a87-30c2-a8c9-6c0171d74826.jpg" /><br /><br />现在， 如果你将浏览器请求定位到更新后的页面，你应该能够看到和前面同样的页面。<br /><strong><br />日志</strong><br /><br />Click有一些自带的日志功能， 它们可以帮助你显示页面模板何时自动映射到<br />页面class。 可以在click.xml中添加debug模块来激活debug日志。<br /><br /><pre name="code" class="java">&lt;?xml version="1.0" encoding="UTF-8"?> 
&lt;click-app> 

  &lt;pages package="com.quickstart.page"/>

  &lt;mode value="debug"/>

&lt;/click-app>  </pre><br /><br />当click应用启动的时候，它将打印如下日志信息：<br /><pre name="code" class="java">[Click] [debug] automapped pages:
[Click] [debug] /border-template.htm -> CLASS NOT FOUND
[Click] [debug] /home.htm -> com.quickstart.page.HomePage
[Click] [info ] initialized in debug mode  </pre><br />click告诉我们 border-template.htm 模板没有映射到任何page类，但是<br />home.htm 模板被映射到HomePage 类，我们还可以得出click正运行在debug <br />模式下。<br /><br />当向我们的主页发送一个请求时， 我们可以得到如下输出：<br /><pre name="code" class="java">[Click] [debug] GET http://localhost:8080/quickstart/home.htm
[Click] [info ] renderTemplate: /home.htm,border-template.htm - 46 ms
[Click] [info ] handleRequest:  /home.htm - 62 ms  </pre><br /><br />它告诉我们ClickServlet收到的http请求。然后我们看到绘制页面home.htm <br />和模板border-template.htm 用掉了41毫秒。最后，我们可以看到处理请求<br />共用掉了62毫秒。<br />如果你想获得更多的debuging信息， 你可以将应用模式设置为trace。<br />现在， 我们向浏览器发送一个请求：<br />http://localhost:8080/quickstart/home.htm?user=malcolm&password=secret <br /><br />我们可以看到请求参数被记录下来，这对调试post方式提交的表单很有用处。<br /><pre name="code" class="java">[Click] [debug] GET http://localhost:8080/quickstart/home.htm
[Click] [trace]    request param: password=secret
[Click] [trace]    request param: user=malcolm
[Click] [trace]    invoked: HomePage.&lt;&lt;init>>
[Click] [trace]    invoked: HomePage.onSecurityCheck() : true
[Click] [trace]    invoked: HomePage.onInit()
[Click] [trace]    invoked: HomePage.onGet()
[Click] [trace]    invoked: HomePage.onRender()
[Click] [info ]    renderTemplate: /user/home.htm,border-template.htm - 6 ms
[Click] [trace]    invoked: HomePage.onDestroy()
[Click] [info ] handleRequest:  /home.htm - 24 ms  </pre><br /><br /><br />附： 文件下载
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/220221#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 27 Jul 2008 22:03:09 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/220221</link>
        <guid>http://congpeixue.javaeye.com/blog/220221</guid>
      </item>
      <item>
        <title>持久化类</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/219244" style="color:red;">http://congpeixue.javaeye.com/blog/219244</a>&nbsp;
          发表时间: 2008年07月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          持久化类就是系统中有关业务实体的类（例如；电子商务系统中的<br />顾客类和订单类）。 并不是所有的持久化类的实例都处于持久化状态，<br />—— 可能是临时态(transient)或游离态(detached)。<br /><br />    如果遵守一些简单的约定，hibernate会工作的更好。 然而，这些<br />约定都不是强制的。事实上，Hibernate3 采取了遵守更少约定的策略。<br />你可以使用其他方式来表达一个实体域： 例如, 使用map树。<br /><strong>4.1 一个简单的POJO例子</strong><br /><br />大部分的java应用都使用一个扁平的持久化类。<br /><pre name="code" class="java">package eg;
import java.util.Set;
import java.util.Date;

public class Cat {
    private Long id; // identifier

    private Date birthdate;
    private Color color;
    private char sex;
    private float weight;
    private int litterId;

    private Cat mother;
    private Set kittens = new HashSet();

    private void setId(Long id) {
        this.id=id;
    }
    public Long getId() {
        return id;
    }

    void setBirthdate(Date date) {
        birthdate = date;
    }
    public Date getBirthdate() {
        return birthdate;
    }

    void setWeight(float weight) {
        this.weight = weight;
    }
    public float getWeight() {
        return weight;
    }

    public Color getColor() {
        return color;
    }
    void setColor(Color color) {
        this.color = color;
    }

    void setSex(char sex) {
        this.sex=sex;
    }
    public char getSex() {
        return sex;
    }

    void setLitterId(int id) {
        this.litterId = id;
    }
    public int getLitterId() {
        return litterId;
    }

    void setMother(Cat mother) {
        this.mother = mother;
    }
    public Cat getMother() {
        return mother;
    }
    void setKittens(Set kittens) {
        this.kittens = kittens;
    }
    public Set getKittens() {
        return kittens;
    }
    
    // addKitten not needed by Hibernate
    public void addKitten(Cat kitten) {
    	kitten.setMother(this);
	kitten.setLitterId( kittens.size() ); 
        kittens.add(kitten);
    }
}</pre><br /><br />这里主要有4个规则去遵守。<br /><br />4.1.1 一个无参的构造方法<br />Cat 拥有一个无参的构造方法。 所有的持久化类都应该有一个默认的<br />无参的构造方法（可以不为public）以便hibernate调用Constructor.newInstance()<br />来对它进行实例化。我们强烈建议至少拥有一个包可见性的<br />默认构造方法。<br /><br />4.1.2 提够一个标识符属性（可选）<br />Cat用户一个名为id的标识符。此属性映射到数据库表的主键列。<br />可以使用任何的基本类型或基本类型的包装类或 java.lang.String 或 java.util.Date来作为标识符。<br />(如过你的遗留数据库采用组合键， 你可以自定义一个class， class<br />属性为组合键)<br /><br />标识符属性不是必须的，你可以不写（但不推荐）<br />我们建议你在持久化类中使用一致的标识符。我们更加建议<br />使用一个非null(不是基本类型)的类型。<br />4.1.3推荐使用非final的类(可选)<br />Hibernate的一个典型特征是代理，proxy依赖于非final 且 方法类型为<br />public的类。<br />你可以借助Hibernate持久化一个final类型的class， 但是， 此种情况你<br />便不能使用延迟加载，这也在一定程度上限制了你的程序。<br />你也应该避免使用final类型的方法。如果你使用了final类型的方法，<br />你必须设置lazy="false"。<br />4.1.4 声明持久化字段的set/get<br />Cat为所有的持久化字段声明了访问方法。<br /><br />属性无需声明为public类型，Hibernate可以持久化任何一个具有默认<br />访问类型 或private或protected类型的属性。<br /><br /><strong>4.2 实现继承</strong><br />一个子类必须遵守第一和第二条规定。他从父类中继承标识符。<br /><pre name="code" class="java">package eg;

public class DomesticCat extends Cat {
        private String name;

        public String getName() {
                return name;
        }
        protected void setName(String name) {
                this.name=name;
        }
}</pre><br /><br /><br /><strong>4.3 实现equals() 和hashCode()</strong><br />如果你打算将持久化类的游离态的实例放到一个set中去时你必须复写equals()和<br />hashCode()方法。因为Hibernate只能在一个session内部保证java标识符和<br />数据库主键列相等。 <br />推荐使用业务字段来实现equals()和hashCode()， 而不是主键。<br /><br /><pre name="code" class="java">public class Cat {

    ...
    public boolean equals(Object other) {
        if (this == other) return true;
        if ( !(other instanceof Cat) ) return false;

        final Cat cat = (Cat) other;

        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
        if ( !cat.getMother().equals( getMother() ) ) return false;

        return true;
    }

    public int hashCode() {
        int result;
        result = getMother().hashCode();
        result = 29 * result + getLitterId();
        return result;
    }

}</pre><br /><br /><strong>4.4 动态模型</strong><br />注意： 动态模型短时间内仍处于试验状态， 有可能会进行修改。<br />持久化的实体无需在运行期间被声明为POJO类型或一个javabean。Hibernate<br />支持动态模型和以DOM4j树的形式来展现实体。通过这种方法，你可以仅仅使用<br />映射文件来描述一个持久化类。<br />默认情况下，Hibernate工作在POJO模式下，你可以使用default_entity_mode <br />来设定一个默认模式。
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/219244#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Thu, 24 Jul 2008 22:30:17 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/219244</link>
        <guid>http://congpeixue.javaeye.com/blog/219244</guid>
      </item>
      <item>
        <title>H2 + hibernate</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/218782" style="color:red;">http://congpeixue.javaeye.com/blog/218782</a>&nbsp;
          发表时间: 2008年07月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          也不啰嗦了，文件不大 ， 有兴趣的可以下载看下 （如题）。 <br /><br /><br /><br />jar 文件如下 （可在hibernate 官方文档的 lib 文件下找到 ）：<br /> <br /><br /><img src="http://www.javaeye.com/upload/attachment/32118/6cc9cc3b-2464-3f37-9c08-3852c743ae67.jpg" /><br /><br /><br /><br />末了顺带挂上转换成hsqldb时 的hibernate.cfg.xml  <br /><br /><pre name="code" class="java">&lt;?xml version='1.0' encoding='utf-8'?>
&lt;!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

&lt;hibernate-configuration>

    &lt;session-factory>

        &lt;!-- Database connection settings -->
        &lt;property name="connection.driver_class">org.hsqldb.jdbcDriver&lt;/property>
        &lt;property name="connection.url">jdbc:hsqldb:mem:baseball&lt;/property>
        &lt;property name="connection.username">sa&lt;/property>
        &lt;property name="connection.password">&lt;/property>

        &lt;!-- JDBC connection pool (use the built-in) -->
        &lt;property name="connection.pool_size">1&lt;/property>

        &lt;!-- SQL dialect -->
        &lt;property name="dialect">org.hibernate.dialect.HSQLDialect&lt;/property>

        &lt;!-- Enable Hibernate's automatic session context management -->
        &lt;property name="current_session_context_class">thread&lt;/property>

        &lt;!-- Disable the second-level cache  -->
        &lt;property name="cache.provider_class">org.hibernate.cache.NoCacheProvider&lt;/property>

        &lt;!-- Echo all executed SQL to stdout -->
        &lt;property name="show_sql">true&lt;/property>

        &lt;!-- Drop and re-create the database schema on startup -->
        &lt;property name="hbm2ddl.auto">create&lt;/property>

        &lt;mapping resource="events/Event.hbm.xml"/>

    &lt;/session-factory>

&lt;/hibernate-configuration></pre>
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/218782#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 23 Jul 2008 23:37:10 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/218782</link>
        <guid>http://congpeixue.javaeye.com/blog/218782</guid>
      </item>
      <item>
        <title>Velocity</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/218391" style="color:red;">http://congpeixue.javaeye.com/blog/218391</a>&nbsp;
          发表时间: 2008年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Velocity， 简单来说是一种模板语言， 支持变量的替换， 支持简单的控制语句，譬如循环和if/else等……； 另外， 它是一种运行期语言，其上下文可以在运行期被任何程序修改。（这也是webwork集成了Velocity语言并提供了对值栈访问的方式。）<br /><br /><strong>首先回顾一下velocity的基本语法和操作</strong><br /><br />  属性访问  ：  <br />         $object <br />     对于某个特定的页面，Velocity要访问的所有可用对象都包含于VelocityContext中。  <br />如果$object表达式返回null， 那么Velocity将直接把表达式打印出来。 为了防止将表达式打印出来， 可以使用 $!object。<br /><br />  方法调用 ： <br />     Velocity支持方法调用。 如$xxx.length()。 实际使用时应避免使用方法调用， 相比起来，属性访问方式更简单易懂。<br /><br /><br />指令符 ： <br />在Velocity中， 指令符通过#标识。<br />例 ： <br />使用foreach对产品集合进行遍历 <br /><pre name="code" class="java">#foreach ($product in $products) 
		&lt;tr>
			&lt;td>
				$product.name
			&lt;/td>
			&lt;td>
				$product.price
			&lt;/td>
		&lt;/tr>
	#end</pre><br /><br />使用set进行变量赋值<br /><pre name="code" class="java">#set($seller = $item.seller)</pre><br /><br /><br /><strong>在webwork UI 标签中的使用</strong><br /><br />早期版本的webwork使用velocity作为其标签的标准模板语言。<br />模板的查找：<br /><pre name="code" class="java">resource.loader = wwfile, wwclass </pre><br /><br /><br />webwork提供了两个默认的资源装载器：wwfile和wwclass.wwfile比wwclass具有更<br />高的优先级。 因此， 你就可以在jar文件或WEB-INF/classes中提供默认的模板（对应wwclass）， 然后在Web应用程序/war这样的上下文基点（对于你个wwfile）处放置某一部分模板文件， 从而覆写对应的默认模板。<br /><br /><br /><strong><br />webwork UI 的高级应用</strong><br /><br />覆盖已有模板： <br />通过在web应用中创建一个路径和文件名都相同的文件覆盖原有文件。<br /><br /><br />编写自定义模板 ： <br /><pre name="code" class="java">&lt;ww:component template="calendar"
		label="Birther"
		name = "birthdate"/></pre><br />然后在theme中新建calendar.vm<br /><br /><br /><br />编写默认主题 ： <br />  在类路径下新建/template/xxx目录，xxx是你准备使用的主题的名字。<br /><br /><br />webwork UI 按照以下顺序检查主题<br /><ul><li>使用标签中特别指明的主题</li><li>在page request session 和application范围内查找以theme为关键字的主题</li><li>查找在webwork.properties中指定的默认主题</li></ul>
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/218391#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Tue, 22 Jul 2008 22:03:56 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/218391</link>
        <guid>http://congpeixue.javaeye.com/blog/218391</guid>
      </item>
      <item>
        <title>struts2 拦截器 </title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/217311" style="color:red;">http://congpeixue.javaeye.com/blog/217311</a>&nbsp;
          发表时间: 2008年07月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="quote_title">引用</div><div class="quote_div">默认的的拦截器栈被设计成能满足大部分应用的需要，所以不再需要添加新的拦截器或更改拦截器栈。</div><br /><br />不同的action可能有不同的关注点， 一些action需要表单验证，一些action需要文件上传功能，一些action需要防止双重提交……struts框架使用“Interceptor”策略使得解决这些关注点变得容易。<br /><br /><strong>理解拦截器</strong><br /><br />在action执行前后interceptor都要被执行。框架的大部分核心功能（包括类型转化，防止双重提交等……）都是借助拦截器来实现的。 所有的拦截器都是插件式的，你可以为你的action精确的设置需要的拦截器。<br /><br /><em>action生命周期</em><br /><br /><strong>配置拦截器</strong><br /><pre name="code" class="java">&lt;package name="default" extends="struts-default">
   &lt;interceptors>
       &lt;interceptor name="timer" class=".."/>
       &lt;interceptor name="logger" class=".."/>
   &lt;/interceptors>

   &lt;action name="login"
      class="tutorial.Login">
        &lt;interceptor-ref name="timer"/>
        &lt;interceptor-ref name="logger"/>
         &lt;result name="input">login.jsp&lt;/result>
         &lt;result name="success"
            type="redirect-action">/secure/home&lt;/result>
   &lt;/action>
&lt;/package></pre><br /><br /><br /><strong>拦截器栈</strong><br /><br />在大部分web程序中，我们发现需要屡次使用相同的拦截器序列。 此时， 我们可以把这些拦截器序列绑定为一个拦截器栈，而无需重申这些拦截器列表。<br /><pre name="code" class="java">&lt;package name="default" extends="struts-default">
   &lt;interceptors>
        &lt;interceptor name="timer" class=".."/>
        &lt;interceptor name="logger" class=".."/>
        &lt;interceptor-stack name="myStack">
           &lt;interceptor-ref name="timer"/>
           &lt;interceptor-ref name="logger"/>
        &lt;/interceptor-stack>
    &lt;/interceptors>

&lt;action name="login"
     class="tutuorial.Login">
         &lt;interceptor-ref name="myStack"/>
         &lt;result name="input">login.jsp&lt;/result>
         &lt;result name="success"
             type="redirect-action">/secure/home&lt;/result>
&lt;/action>
&lt;/package></pre><br /><br /><br /><strong>几个重要的拦截器</strong><br />在struts配置文件中，拦截器类被定义为键值对的形式。<br />拦截器的名字在 struts-default.xml中都进行了定义，如果你继承了 struts-default.xml包，后面的操作你可以通过引用来使用拦截器；如果没有继承struts-default.xml，你需要在&lt;interceptors>中指定名字和名字对应的拦截器类来引用拦截器。<br /><br /><br /><ul><li>chain  ： 使上一个action的属性能在当前的action中有效</li><li>execAndWait 　： 生成一个新的线程以执行action， 然后返回wait作为result code。而wait这个code可以映射至一张包含刷新指示的页面，告知浏览器每隔数秒自动刷新。当新线程执行action完毕之后，下一个来自浏览器到请求将返回原始action调用所生成的result。</li><li>exception  ：　映射一个异常页面。　一般情况下，应该为最后一个拦截器。</li><li>fileUpload : 处理文件上传。</li><li>logger ： 记录用于追踪的信息（可位于拦截器序列的不同位置）。</li><li>params:使用request参数设置action的属性。request参数会被映射到action中与之同名的属性。</li><li>static-params ：将配置文件中参数设置到action实例中。</li><li>prepare ： 此拦截器将调用实现了Preparable的action中的prepare方法。</li><li>token ：　检查表单中的合法令牌，当表单被多次提交时，跳转到一个错误页面。</li><li>tokenSession ：类似于token， 只是不跳转到错误页面，再次生成与第一次相同的页面。</li><li>validation  ： 调用校验框架读取*-validation.xml文件并且应用在这些文件中声明的校验。 </li><li>workflow  ：为action定义默认的工作流， 一般跟在validation等其它拦截器后。</li><li>timer ： 计算ActionInvocation余下部分执行的时间并记录下来。</li></ul><br /><br /><span style="color: red">从2.0.7版本后拦截器和Result中含有的连字符号都被转化为来骆驼格式。<br /> 如：（model-driven 被转化为modelDriven）。<br /> 直到Struts 2.1.0， 原有的连字符号格式以别名的形式仍被使用。</span><br /><br /><strong>方法过滤 覆写拦截器参数</strong><br />一个抽象的过滤器被用于过滤方法的名字。<br />excludeMethods ： 不被包含的方法的名字。<br />includeMethods ： 包含的方法的名字。<br />如果方法的名字在excludeMethods和includeMethods都适合， 那么将包含方法的名字， includeMethods比excludeMethods的<br />优先级高。<br /><br />方法1<br /><pre name="code" class="java">&lt;action name="myAction" class="myActionClass">
  &lt;interceptor-ref name="exception"/>
    &lt;interceptor-ref name="alias"/>
    &lt;interceptor-ref name="params"/>
    &lt;interceptor-ref name="servlet-config"/>
    &lt;interceptor-ref name="prepare"/>
    &lt;interceptor-ref name="i18n"/>
    &lt;interceptor-ref name="chain"/>
    &lt;interceptor-ref name="model-driven"/>
    &lt;interceptor-ref name="fileUpload"/>
    &lt;interceptor-ref name="static-params"/>
    &lt;interceptor-ref name="params"/>
    &lt;interceptor-ref name="conversionError"/>
    &lt;interceptor-ref name="validation">
      &lt;param name="excludeMethods">myValidationExcudeMethod&lt;/param>
    &lt;/interceptor-ref>
    &lt;interceptor-ref name="workflow">
      &lt;param name="excludeMethods">myWorkflowExcludeMethod&lt;/param>
    &lt;/interceptor-ref>
&lt;/action></pre><br /><br />方法2<br /><pre name="code" class="java">&lt;action name="myAction" class="myActionClass">
  &lt;interceptor-ref name="defaultStack">
    &lt;param name="validation.excludeMethods">myValidationExcludeMethod&lt;/param>
    &lt;param name="workflow.excludeMethods">myWorkflowExcludeMethod&lt;/param>
  &lt;/interceptor-ref>
&lt;/action></pre><br /><br /><br /><strong>拦截器的执行顺序</strong><br /><br />拦截器提供了一种对处理前后进行包装的思想， 这种观念大大减少了代码副本。（参考AOP）<br /><pre name="code" class="java">&lt;interceptor-stack name="xaStack">
  &lt;interceptor-ref name="thisWillRunFirstInterceptor"/>
  &lt;interceptor-ref name="thisWillRunNextInterceptor"/>
  &lt;interceptor-ref name="followedByThisInterceptor"/>
  &lt;interceptor-ref name="thisWillRunLastInterceptor"/>
&lt;/interceptor-stack></pre><br />一些拦截器有可能会打断执行流程，因此拦截器的顺序也是很重要的 。<br /><br />另， 实现了com.opensymphony.xwork2.interceptor.PreResultListener 的拦截器将在Action执行之后和Result返回之前调用。<br /><pre name="code" class="java">thisWillRunFirstInterceptor
  thisWillRunNextInterceptor
    followedByThisInterceptor
      thisWillRunLastInterceptor
        MyAction1
        MyAction2 (chain)
        MyPreResultListener
        MyResult (result)
      thisWillRunLastInterceptor
    followedByThisInterceptor
  thisWillRunNextInterceptor
thisWillRunFirstInterceptor</pre><br /><br /><strong>自定义拦截器</strong><br /><br />自定义拦截器必须实现 com.opensymphony.xwork2.interceptor.Interceptor <br /><pre name="code" class="java">public interface Interceptor extends Serializable {

    void destroy();

    void init();

    String intercept(ActionInvocation invocation) throws Exception;
}</pre><br /><br />在拦截器被实例化之后和 intercept方法被调用之前 执行init方法。 此方法用来初始化拦截器需要的资源。<br />拦截器的主体代码写在intercept中， 和action类似， intercept返回一个result， result被struts2用于将请求转发到另一个资源，调用ActionInvocation 中的invoke 方法以执行action （如果是最后一个拦截器）或调用另一个拦截器。<br />在result被调用之后方法才返回， 这种情况适合open-session-in-view模式。 如果你想在result被调用之前做一些事情，你必须实现PreResultListener。<br /><br /><span style="color: red">拦截器必须是线程安全的<br />对于struts2， 每个请求都会实例化一个action， 所以action不需要线程安全。 但是， 拦截器会在请求之间共享，所以，<br />拦截器必须线程安全。</span>
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/217311#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 21 Jul 2008 19:02:52 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/217311</link>
        <guid>http://congpeixue.javaeye.com/blog/217311</guid>
      </item>
      <item>
        <title>H2database指南</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/216423" style="color:red;">http://congpeixue.javaeye.com/blog/216423</a>&nbsp;
          发表时间: 2008年07月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          前言 ：H2database是一款用java语言编写的开源数据库。 H2服务器下载下载地址： <a href="http://www.h2database.com/" target="_blank">http://www.h2database.com/</a>。<br />原文地址<a href="http://www.h2database.com/html/tutorial.html" target="_blank">http://www.h2database.com/html/tutorial.html</a><br />下文前提是数据库已被解压安装完毕。 <br /> 本文地址<a href="http://congpeixue.javaeye.com/admin/blogs/216423" target="_blank">http://congpeixue.javaeye.com/admin/blogs/216423</a><br /><br /><br /><strong>开启和使用H2控制台</strong><br />H2Database支持通过浏览器可以访问一个SQL数据库，数据库种类包括H2和其他相应的支持JDBC的数据库类型。<br /><img src="http://www.javaeye.com/upload/attachment/31624/76dd8631-b91f-3969-a344-e8a64f55d4b0.png" /><br /><br />这是一个客户端/服务器端模式，所以运行它需要一个服务器端和一个客户端（浏览器）。根据你的平台和环境，你可以通过多种方式启动H2：<br />1、Windows      Click [Start], [All Programs], [H2], and [H2 Console (Command Line)]<br /> 	如果你使用的是SUN JKD1.4 或1.5，将会弹出一个标题为“H2 Console”的窗口； 如果你使用的是SUN JDK1.6，将会出现在成功启动的系统上显示图标<img src="http://www.javaeye.com/upload/attachment/31626/556b483c-73e6-3420-b732-e5ad794aa7fc.png" />。<br /> 	假如未弹出窗口也未出现图标，原因很可能是你的JAVA没有被正确的安装（在这种情况下，尝试通过其它方法启动服务，如：打开一个浏览器窗口，并使其指向http://localhost:8082）。<br />2、Windows       从文件夹中定位到h2/bin，双击h2.bat。<br />	将会出现一个控制台窗口。如果有问题的话，在控制台窗口中将会出现错误信息。 随后一个浏览器窗口将被打开并指向登录页面（URL: http://localhost:8082）。<br />3、Any 　      　启动一个控制台窗口，定位到目录'h2/bin' ， 输入：<br />	<pre name="code" class="java">java -cp h2.jar org.h2.tools.Server</pre><br /><br />	<br /><strong>防火墙</strong><br />当你启动服务时，防火墙可能会显示一个安全警告信息（如果你安装了防火墙）。如果你不打算让位于同一个网络中的其他计算机访问你本机的数据库服务， 你可以设置防火墙<br />阻止这些连接。此时来自本机的连接保持仍然可用。相反的，如果你打算允许其他机器访问本机的提供的数据库服务， 你可以设置防火墙允许这些连接。<br />此外H2本身自带了一个小的防火墙： 默认情况下，其他机器不能连接到本服务。 为了改变默认， 你可以进入'Preferences' ， 选择'Allow connections from other computers'<br />译者注（Preferences选项位置数据库启动页面顶部）<br /><br /><br /><br /><strong>本地版本</strong><br />本地版本不必需JAVA支持， 因为它可以使用GCJ来编译。但是，现在基于Window的GCJ下运行H2仍不稳定。<br /><br /><br /><strong>测试JAVA</strong><br />打开命令窗口并输入 测试你安装的java的版本<br />java -version<br />如果你得到的是错误信息， 此时你可能需要把java目录添加到环境变量中。<br /><br /><br /><strong>错误消息“端口被使用”</strong><br />同一端口你只能运行一个H2控制台实例，否则你将得到如下错误信息<br /><div class="quote_title">引用</div><div class="quote_div">Port is in use, maybe another ... server already running on.... <br /></div>在同一台电脑上可以开启多个控制台程序（使用不同的端口）， 如果控制台支持并发连接，则无需使用不同端口。<br /><br /><br /><strong>使用其他端口</strong><br />如果端口被其它程序使用，你可能会想在其它端口开启H2服务。此时可以通过改变.h2.server.properties中的端口设置来实现。<br />该文件被保存在用户目录下（对于Windows 通常是Documents and Settings/&lt;username>）。对应的管理配置项是webPort。<br /><br /><br /><strong>启动成功</strong><br />如果服务在控制台中启动成功，将会打开一个新的窗口并显示如下：<br />H2 Server running on port 9092<br />Webserver running on https://localhost:8082/<br />不要在此窗口内操作，否则你可能会停止掉H2服务（如果你开启了快速编辑模式）。<br /> <br /><br /><strong>借助浏览器连接服务器</strong><br />如果H2服务器成功启动的话 你能够使用一个web浏览器来连接H2。 浏览器必须支持javascript、frames和样式层叠表（css）。<br />如果你是在本地启动服务， 在浏览器中输入http://localhost:8082。 如果你是从另外一台计算机连接启动服务，你必须提供<br />H2服务器的ip地址，例如：http://192.168.0.2:8082. 如果你打算在服务器端启用ssl， 浏览器的URL地址必须以https开头。<br /><br /><br /><strong>多个并发的sessions</strong><br />h2Database支持多个并发的浏览器session。 因为数据库对象位于服务器， 所以连接的数目受服务器端内存大小的限制。<br /><br /><br /><strong>程序配置</strong><br />启动服务时将在本地目录下创建一个配置文件（.h2.server.properties）。 对于windows来说， 该文件位于<br />c：Document and Settings/[username]。 此文件中包含应用程序的配置信息。<br /><br /><br /><strong>登录</strong><br />在登录页面，你必须提供数据库的连接信息。包括设置你的数据库的JDBC驱动、 JDBC URL、 用户名和密码。 如果你做完上面步骤，点击[connect]<br />你可以保存并重新使用以前的连接信息， 这些信息被自动保存在应用程序的properties文件中。<br /><br /><strong><br />错误信息</strong><br />错误信息以红色字来显示。 点击该信息可以显示或隐藏相应的异常链。<br /><br /><br /><strong>添加数据库驱动</strong><br />通过将相应驱动的jar文件地址添加进环境变量H2DRIVERS 或CLASSPATH， 可以为H2数据库注册其它的驱动。 例如：（Window） 为了添加数据库驱动包C:\Programs\hsqldb\lib\hsqldb.jar，<br />你可以将环境变量的H2DRIVERS 设置成C:\Programs\hsqldb\lib\hsqldb.jar。<br />H2支持多种驱动，驱动之间使用“；”（windows）或“：”（其他操作系统）来分割。另外，描述驱动的路径中支持空格， 路径加引用。<br />	<br /><br /><strong>使用程序</strong><br />程序包含3个面板， 顶部的工具条、 左边的树和右边的查询/结果面板。 数据库实体（例如: tables）在左边的树结构中显示。在查询面板中输入SQL命令<br />并点击“Run”。命令的执行结果将紧跟在命令下面。<br /><br /><br /><strong>添加数据表名和列名</strong><br />通过单击左边的相应树状结构你可以将表名或列名字段插入到查询面板中。 在查询面板中查询语句为空时，如果你单击一个表，‘SELECT * FROM ...’将被添加进去。当在查询面板中输入一个查询语句后，<br />被使用的表将自动展开在左边的树中。例如： 如果你输入SELECT * FROM TEST T WHERE T， 表TEST将在左边的树中被自动展开。<br /><br /><br /><strong>断开连接和停止服务</strong><br />	在浏览器中， 点击工具面板上的'Disconnect'断开连接。  但是，此时H2服务器仍然在运行并且可以接受新的session。 <br />	为了停止服务， 你可以通过点击顶部工具面板中的【exit】图标。 如果该图标不存在，（因为你可能是通过其他方式启动的服务）， 你可以在启动该H2服务的控制台窗口中按Ctrl+C来停止H2服务， 或直接关闭该控制台窗口来停止H2服务。<br /><br /><br /><strong>使用JDBC连接到数据库</strong><br />	为了连接到数据库， 一个java程序首先需要加载数据库驱动，然后获得一个连接。完成上述操作的一个简单方法是使用如下的代码：<br />	<br /><pre name="code" class="java">	import java.sql.*;
	public class Test {
 		 public static void main(String[] a)
 		 throws Exception {
  	 	 Class.forName("org.h2.Driver");
  	 	 Connection conn = DriverManager.
     	 getConnection("jdbc:h2:~/test", "sa", "");
    	 // add application code here
 		 }
	}</pre><br />	该代码首先加载驱动（Class.forName()）然后打开一个连接（使用DriverManager.getConnection()）。在所有的场合下，驱动的名字都是'org.h2.Driver'。<br />为了能使被该数据库验证通过，数据库的URL通常以jdbc:h2:开头。getConnection()中的第二个参数是用户名（在本例中'sa'是数据库管理员）；第三个参数是密码。<br />注意： 在本数据库中用户名是不区分大小写的， 密码区分大小写。<br /><br /><br /><strong>新建数据库</strong><br />默认情况下，如果URL中指定的数据库不存在将自动创建。创建数据库的用户将成为该数据库的管理员。<br /><br /><br /><strong>使用服务器</strong><br />H2目前支持3种服务模式: web服务、TCP服务及ODBC服务模式。这些服务模式以不同的方式启动。<br /><br /><em>从命令行启动方式</em><br />命令行启动将加载默认配置， 运行<br />java org.h2.tools.Server<br />将加载默认配置。 为了得到配置选项列表和值， 可以运行<br />java org.h2.tools.Server -?<br />通过这些选项可以开启或停止H2服务器部分功能。 为了获得更详细的信息， 可以参考服务器的Api文档。<br /><br /><em>连接到TCP启动方式</em><br />为了借助TCP服务连接远程数据库，需使用如下驱动和数据库URL<br />JDBC driver class: org.h2.Driver <br />Database URL: jdbc:h2:tcp://localhost/~/test <br />关于数据库URL更详细描述，可以参考具体文档。<br /><br /><em>程序内部启动服务器方式</em><br />可以在应用程序内部启动或关闭服务。 例子代码：<br /><pre name="code" class="java">import org.h2.tools.Server;
...
// start the TCP Server
Server server = Server.createTcpServer(args).start();
...
// stop the TCP Server
server.stop();</pre><br /><br /><strong>从其他进程中关闭一个TCP服务</strong><br />TCP服务方式可以从其他进程中关闭， 从命令行中关闭服务器。 运行：<br />java org.h2.tools.Server -tcpShutdown tcp://localhost:9092<br />从应用程序中TCP服务，可以运行如下代码：<br />org.h2.tools.Server.shutdownTcpServer("tcp://localhost:9094");<br />这种方法将在服务器端调用System.exit。此方法调用的前提是所有的数据库连接已被关闭，以便数据库在下一次被打开时能正确运行。为了关闭远程服务器，应该确保服务器上的远程连接有效。<br /><br /><span style="color: red">（未完待续）</span>  翻译不好之处，还请见谅 ^_^
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/216423#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Sat, 19 Jul 2008 00:33:03 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/216423</link>
        <guid>http://congpeixue.javaeye.com/blog/216423</guid>
      </item>
      <item>
        <title>Log4J简介</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/215190" style="color:red;">http://congpeixue.javaeye.com/blog/215190</a>&nbsp;
          发表时间: 2008年07月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          第1章. Log4j 的优点 <br />Log4j是Apache的一个开放源代码项目，通过使用Log4j，我们可以控制日志信息输送的；我们也可以控制每一条日志的输出格式；通过定义每一条日志信息的级别，我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是，这些可以通过一个配置文件来灵活地进行配置，而不需要修改应用的代码。 <br />log4j的好处在于： <br />1) 通过修改配置文件，就可以决定log信息的目的地——控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等 <br />2) 通过修改配置文件，可以定义每一条日志信息的级别，从而控制是否输出。在系统开发阶段可以打印详细的log信息以跟踪系统运行情况,而在系统稳定后可以关闭log输出,从而在能跟踪系统运行情况的同时,又减少了垃圾代码（System.out.println(......)等)。 <br />3) 使用log4j，需要整个系统有一个统一的log机制，有利于系统的规划。 <br /><br />第2章. 配置文件 <br /><br />Log4j由三个重要的组件构成：日志信息的优先级，日志信息的输出目的地，日志信息的输出格式。日志信息的优先级从高到低有FATAL、ERROR、WARN、INFO、DEBUG，分别用来指定这条日志信息的重要程度；日志信息的输出目的地指定了日志将打印到控制台还是文件中；而输出格式则控制了日志信息的显示内容。 <br />2.1. 日志信息的优先级 <br /><br />分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。 <br />Log4j建议只使用四个级别，优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别，您可以控制到应用程序中相应级别的日志信息的开关。 <br />假如在一个级别为q的Logger中发生一个级别为p的日志请求，如果p>=q,那么请求将被启用。这是Log4j的核心原则。 <br />比如在这里定义了INFO级别，则应用程序中所有DEBUG级别的日志信息将不被打印出来； <br /><br />2.2. 输出源的使用 <br /><br />有选择的能用或者禁用日志请求仅仅是Log4j的一部分功能。Log4j允许日志请求被输出到多个输出源。用Log4j的话说，一个输出源被称做一个Appender。 <br />Appender包括console（控制台）, files（文件）, GUI components（图形的组件）, remote socket servers（socket 服务）, JMS（java信息服务）, NT Event Loggers（NT的事件日志）, and remote UNIX Syslog daemons（远程UNIX的后台日志服务）。它也可以做到异步记录。 <br />一个logger可以设置超过一个的appender。 <br />用addAppender 方法添加一个appender到一个给定的logger。对于一个给定的logger它每个生效的日志请求都被转发到该logger所有的appender上和该logger的父辈logger的appender上。 <br />2.2.1. ConsoleAppender <br /><br />如果使用ConsoleAppender，那么log信息将写到Console。效果等同于直接把信息打印到System.out上了。 <br />2.2.2. FileAppender <br /><br />使用FileAppender，那么log信息将写到指定的文件中。这应该是比较经常使用到的情况。 <br />相应地，在配置文件中应该指定log输出的文件名。如下配置指定了log文件名为dglog.txt <br />log4j.appender.A2.File=dglog.txt <br />注意将A2替换为具体配置中Appender的别名。 <br />2.2.3. DailyRollingAppender <br /><br />使用FileAppender可以将log信息输出到文件中，但是如果文件太大了读起来就不方便了。这时就可以使用DailyRollingAppender。DailyRollingAppender可以把Log信息输出到按照日期来区分的文件中。配置文件就会每天产生一个log文件，每个log文件只记录当天的log信息： <br />log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A2.file=dglog <br />log4j.appender.A2.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern= %5r %-5p %c{2} - %m%n <br />2.2.4. org.apache.log4j.RollingFileAppender <br /><br />文件大小到达指定尺寸的时候产生一个新的文件。 <br />log4j.appender.R=org.apache.log4j.RollingFileAppender <br />log4j.appender.R.File= ../logs/dglog.log <br /># Control the maximum log file size <br />log4j.appender.R.MaxFileSize=100KB <br /># Archive log files (one backup file here) <br />log4j.appender.R.MaxBackupIndex=1 <br />log4j.appender.R.layout=org.apache.log4j.PatternLayout <br />log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n <br />这个配置文件指定了输出源R，是一个轮转日志文件。最大的文件是100KB，当一个日志文件达到最大尺寸时，Log4J会自动把example.log重命名为dglog.log.1，然后重建一个新的dglog.log文件，依次轮转。 <br /><br />2.2.5. org.apache.log4j.WriterAppender <br /><br />将日志信息以流格式发送到任意指定的地方。 <br /><br />2.3. Layout的配置 <br /><br />Layout指定了log信息输出的样式。 <br />2.3.1. 布局样式 <br /><br />org.apache.log4j.HTMLLayout（以HTML表格形式布局）， <br />org.apache.log4j.PatternLayout（可以灵活地指定布局模式）， <br />org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串）， <br />org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息） <br />2.3.2. 格式 <br /><br />%m 输出代码中指定的消息 <br />%p 输出优先级，即DEBUG，INFO，WARN，ERROR，FATAL <br />%r 输出自应用启动到输出该log信息耗费的毫秒数 <br />%c 输出所属的类目，通常就是所在类的全名 <br />%t 输出产生该日志事件的线程名 <br />%n 输出一个回车换行符，Windows平台为"rn"，Unix平台为"n" <br />%d 输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyy MMM dd HH:mm:ss,SSS}，输出类似：2002年10月18日 22：10：28，921 <br />%l 输出日志事件的发生位置，包括类目名、发生的线程，以及在代码中的行数。举例：Testlog4.main(Test Log4.java:10) <br /><br />2.3.3. 例子 <br /><br />例子1：显示日期和log信息 <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %m%n <br />打印的信息是： <br />2002-11-12 11:49:42,866 SELECT * FROM Role WHERE 1=1 order by createDate desc <br /><br />例子2：显示日期，log发生地方和log信息 <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %l "#" %m%n <br />2002-11-12 11:51:46,313 cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) "#" <br />SELECT * FROM Role WHERE 1=1 order by createDate desc <br /><br />例子3：显示log级别,时间,调用方法,log信息 <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br />log信息: <br />[DEBUG] 2002-11-12 12:00:57,376 <br />method:cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) <br />SELECT * FROM Role WHERE 1=1 order by createDate desc <br /><br />2.4. 配置文件的例子: <br /><br />log4j.rootLogger=DEBUG <br />#将DAO层log记录到DAOLog,allLog中 <br />log4j.logger.DAO=DEBUG,A2,A4 <br />#将逻辑层log记录到BusinessLog,allLog中 <br />log4j.logger.Businesslog=DEBUG,A3,A4 <br /><br />#A1--打印到屏幕上 <br />log4j.appender.A1=org.apache.log4j.ConsoleAppender <br />log4j.appender.A1.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A1.layout.ConversionPattern=%-5p [%t] %37c %3x - %m%n <br /><br />#A2--打印到文件DAOLog中--专门为DAO层服务 <br />log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A2.file=DAOLog <br />log4j.appender.A2.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br /><br />#A3--打印到文件BusinessLog中--专门记录逻辑处理层服务log信息 <br />log4j.appender.A3=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A3.file=BusinessLog <br />log4j.appender.A3.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A3.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A3.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br /><br />#A4--打印到文件alllog中--记录所有log信息 <br />log4j.appender.A4=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A4.file=alllog <br />log4j.appender.A4.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A4.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A4.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br /><br /><br />第3章. API使用 <br /><br />log4j使用步骤有3个： <br />3.1. 初始化 <br />3.1.1. Tomcat下的初始化 <br /><br />默认的Log4j initialization典型的应用是在web-server 环境下。在tomcat3.x和tomcat4.x下，你应该将配置文件Log4j.properties放在你的web应用程序的WEB-INF/classes 目录下。 <br />Log4j将发现属性文件，并且以此初始化。这是使它工作的最容易的方法。 <br />你也可以选择在运行tomcat前设置系统属性Log4j.configuration 。对于tomcat 3.x，TOMCAT_OPTS 系统变量是用来设置命令行的选项。对于tomcat4.0，用系统环境变量CATALINA_OPTS 代替了TOMCAT_OPTS。 <br />UNIX 命令行 <br />export TOMCAT_OPTS="-DLog4j.configuration=foobar.txt" <br />告诉Log4j用文件foobar.txt作为默认的配置文件。这个文件应该放在WEB-INF/classes 目录下。这个文件将被PropertyConfigurator所读。每个web-application将用不同的默认配置文件，因为每个文件是和它的web-application 相关的。 <br />1. export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml" export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml" <br />告诉Log4j输出Log4j-internal的调试信息，并且用foobar.xml作为默认的配置文件。这个文件应该放在你的web-application的WEB-INF/classes 目录下。因为有.xml的扩展名，它将被DOMConfigurator所读。每个web-application将用不同的默认配置文件。因为每个文件都和它所在的web-application 相关的。 <br />2. set TOMCAT_OPTS=-DLog4j.configuration=foobar.lcf <br />-DLog4j.configuratorClass=com.foo.BarConfigurator <br />告诉Log4j用文件foobar.lcf作为默认的配置文件。这个文件应该放在你的web-application的WEB-INF/classes 目录下。因为定义了Log4j.configuratorClass 系统属性，文件将用自定义的com.foo.barconfigurator类来解析。每个web-application将用不同的默认配置文件。因为每个文件都和它所在的web-application 相关的。 <br />3. set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf <br />告诉Log4j用文件foobar.lcf作为默认的配置文件。这个配置文件用URL file:/c:/foobar.lcf定义了全路径名。这样同样的配置文件将被所有的web-application所用。 <br />不同的web-application将通过它们自己的类装载器来装载Log4j。这样，每个Log4j的环境将独立的运作，而没有任何的相互同步。例如：在多个web-application中定义了完全相同的输出源的FileAppenders将尝试写同样的文件。结果好象是缺乏安全性的。你必须确保每个不同的web-application的Log4j配置没有用到同样的系统资源。 <br />3.1.2. Servlet 的初始化 <br /><br />用一个特别的servlet来做Log4j的初始化也是可以的。如下是一个例子： <br />public class Log4jInit extends HttpServlet { <br />public void init() { <br />String prefix = getServletContext().getRealPath("/"); <br />String file = getInitParameter("Log4j-init-file"); <br />if(file != null) { <br />PropertyConfigurator.configure(prefix+file); <br />} <br />} <br />public void doGet(HttpServletRequest req, HttpServletResponse res) { <br />} <br />} <br /><br />在web.xml中定义随后的servlet为你的web-application。 <br />&lt;servlet> <br />&lt;servlet-name>Log4j-init&lt;/servlet-name> <br />&lt;servlet-class>xx.xx.Log4jInit&lt;/servlet-class> <br />&lt;init-param> <br />&lt;param-name>Log4j-init-file&lt;/param-name> <br />&lt;param-value>WEB-INF/classes/Log4j.properties&lt;/param-value> <br />&lt;/init-param> <br />&lt;load-on-startup>1&lt;/load-on-startup> <br />&lt;/servlet> <br />写一个初始化的servlet是最有弹性的初始化Log4j的方法。代码中没有任何限制，你可以在servlet的init方法中定义它。 <br />3.2. 根据配置文件初始化log4j <br /><br />log4j可以使用3中配置器来初始化：BasicConfigurator,DOMConfigurator,PropertyConfigurator <br />其语法为： <br />BasicConfigurator.configure ()： 自动快速地使用缺省Log4j环境。 <br />PropertyConfigurator.configure ( String configFilename) ：读取使用Java的特性文件编写的配置文件。 <br />DOMConfigurator.configure ( String filename ) ：读取XML形式的配置文件。 <br />这里用的是PropertyConfigurator。使用PropertyConfigurator适用于所有的系统。如下的语句： <br />PropertyConfigurator.configure("log4j.properties"); <br />就以log4j.properties为配置文件初始化好了log4j环境。 <br />注意一点：这个语句只需要在系统启动的时候执行一次。例如，在ActionServlet的init()方法中调用一次。 <br />public class ActionServlet extends HttpServlet{ <br />... <br />/** <br />* Initialize global variables <br />*/ <br />public void init() throws ServletException { <br />// 初始化Action资源 <br />try{ <br />initLog4j(); <br />... <br />}catch(IOException e){ <br />throw new ServletException("Load ActionRes is Error"); <br />} <br />} <br />... <br />protected void initLog4j(){ <br />PropertyConfigurator.configure("log4j.properties"); <br />} <br />... <br />}//end class ActionServlet <br /><br />3.3. 在需要使用log4j的地方获取Logger实例 <br /><br />使用Log4j，首先就是获取日志记录器，这个记录器将负责控制日志信息。其语法为： <br />public static Logger getLogger( String name)， <br />通过指定的名字获得记录器，如果必要的话，则为这个名字创建一个新的记录器。Name一般取本类的名字，比如： <br />static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ; <br />Log4j使得通过软件组件命名logger很容易。我们可以通过Logger的静态的初始化方法在每一个类里定义一个logger，令logger的名字等于类名的全局名，而实现logger的命名。这是一个实效的简单的定义一个logger的方法。因为日志输出带有产生日志的类的名字，这个命名策略使得我们更容易定位到一个日志信息的来源。虽然普通，但却是命名logger的常用策略之一。 <br />Log4j没有限制定义logger的可能。开发员可以自由的按照它们的意愿定义logger的名称。 <br />然而，以类的所在位置来命名Logger好象是目前已知的最好方法。 <br /><br />3.4. 使用Logger对象的debug,info,fatal...方法 <br /><br />log.debug("it is the debug info"); <br /><br />第4章. 优化 <br /><br />一个经常引用的依靠于logging的参数是可以计算的花费。这是一个合理的概念，一个适度的应用程序可能产生成千上万个日志请求。许多努力花在测量和调试logging的优化上。Log4j要求快速和弹性：速度最重要，弹性是其次。 <br />4.1. 日志为禁用时，日志的优化。 <br /><br />当日志被彻底的关闭，一个日志请求的花费等于一个方法的调用加上整数的比较时间。在233mhz的Pentium II 机器上这个花费通常在5-50纳秒之间。 <br />然而，方法调用包括参数构建的隐藏花费。 <br />例如，对于logger cat，logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); <br />引起了构建信息参数的花费，例如，转化整数i和entry[i]到一个string，并且连接中间字符串，不管信息是否被输出。这个参数的构建花费可能是很高，它主要决定于被调用的参数的大小。 <br />避免参数构建的花费应如下， <br /><br />if(logger.isDebugEnabled()) <br />{ <br />logger.debug("result is" + result ); <br />} <br /><br />如果logger的debug被关闭这将不会招致参数构建的花费。另一方面，如果logger是debug的话，它将产生两次判断 logger是否能用的花费。一次是在debugenabled，一次是debug。这是无关紧要的，因为判断日志的能用 只占日志实际花费时间的约1%。 <br />在Log4j里，日志请求在Logger 类的实例里。Logger 是一个类，而不是一个接口。这大量的减少了在方法调用上的弹性化的花费。 <br />当然用户采用预处理或编译时间技术去编译出所有的日志声明。这将导致完美的执行成效。然而因为二进制应用程序不包括任何的日志声明的结果，日志不可能对那个二进制程序开启。以我的观点，以这种较大的代价来换取较小的性能优化是不值得的。 <br /><br />4.2. 当日志状态为启用时，日志的优化。 <br /><br />这是本质上的优化logger的层次。当日志状态为开，Log4j依然需要比较请求的级别与logger的级别。然而， logger可能没有被安排一个级别；它们将从它们的father继承。这样，在继承之前，logger可能需要搜索它的ancestor。 <br />这里有一个认真的努力使层次的搜索尽可能的快。例如，子logger仅仅连接到它的存在的father logger。 <br />在先前展示的BasicConfigurator 例子中，名为com.foo.bar 的logger是连接到跟根logger，因此绕过 了不存在的logger com和com.foo。这将显著的改善执行的速度，特别是解析logger的层结构时。 <br />典型的层次结构的解析的花费是logger彻底关闭时的三倍。 <br /><br />4.3. 日志信息的输出时，日志的优化。 <br /><br />这是主要花费在日志输出的格式化和发送它到它的输出源上。这里我们再一次的付出努力以使格式化执行的尽可能快。同appender一样。实际上典型的花费大约是100-300毫秒。 <br />详情看org.apache.log4.performance.Logging。 <br />虽然Log4j有许多特点，但是它的第一个设计目标还是速度。一些Log4j的组件已经被重写过很多次以改善性能。不过，投稿者经常提出了新的优化。你应该满意的知道，以SimpleLayout的配置执行测试已经展示了Log4j的输出同System.out.println一样快。<br /><br /><br />转自： http://thblovezhj.javaeye.com/blog/172187
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/215190#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Tue, 15 Jul 2008 19:18:01 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/215190</link>
        <guid>http://congpeixue.javaeye.com/blog/215190</guid>
      </item>
      <item>
        <title>freemarker 内置的几个处理</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/214744" style="color:red;">http://congpeixue.javaeye.com/blog/214744</a>&nbsp;
          发表时间: 2008年07月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          freemarker 内置的几个处理（使用“?”）<br /><br />default ：&lt;#if parameters.vertical?default(false) >　默认为false<br /><br />html ： 对字符串进行HTML编码<br /><br />trim：去掉字符串前后的空白字符<br /><br />int：取得数字的整数部分<br /><br />exists ：用在逻辑判断<br /><br /><br /><br /><br /><br />不推荐你从头编写自己的模板.推荐你学习一点FreeMarker,并且扩展已有的模板<br /><br /><br /><br />传个freemarker IDE，
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/214744#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 14 Jul 2008 23:15:17 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/214744</link>
        <guid>http://congpeixue.javaeye.com/blog/214744</guid>
      </item>
      <item>
        <title>maven</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/214359" style="color:red;">http://congpeixue.javaeye.com/blog/214359</a>&nbsp;
          发表时间: 2008年07月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1、产生maven结构<br /><br /><img src="http://www.javaeye.com/upload/attachment/30910/b4227653-8760-319c-88c6-64c68f50ae41.jpg" /><br /><br />2、enable maven<br /><br /><br /><img src="http://www.javaeye.com/upload/attachment/30908/1031658a-9596-3541-a164-5a93847b3f93.jpg" /><br />3、设置生成的class文件的路径<br /><br /><br /><img src="http://www.javaeye.com/upload/attachment/30906/22c93abd-2c03-31a2-b0c2-59cf59151956.jpg" /><br />4、打开yourproject/.settings/org.eclipse.wst.common.component ，修改java-output-path 为 yourproject/target/classes
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/214359#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 13 Jul 2008 16:43:50 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/214359</link>
        <guid>http://congpeixue.javaeye.com/blog/214359</guid>
      </item>
      <item>
        <title>servlet（CRUD）以飨初学者</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/214134" style="color:red;">http://congpeixue.javaeye.com/blog/214134</a>&nbsp;
          发表时间: 2008年07月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          用业余时间写成的使用servlet的一个DEMO，(希望对初学者有所帮助，末了我会把完整的程序代码都贴出来)<br /><br /><br />先简要回顾一下servlet的使用（具体的请参考servlet的api<a href="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html" target="_blank">http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html</a>，或者百度一下<img src="/images/smiles/icon_biggrin.gif"/>）， 首先是类层次结构，我们自己的servlet一般都继承自httpservlet， httpservlet继承自genericservlet， genericservlet实现了servlet（声明了init 、service。。等方法）和servletconfig（声明了getServletName、 getservletContext。等方法）接口。<br /><img src="http://www.javaeye.com/upload/attachment/30839/82650e2b-69a6-3542-9896-82f35bdc5298.jpg" /><br /><br /><br /><br />getParameter ：以字符串的形式返回请求参数的值，如果请求参数不存在，返回null，请求参数作为额外的信息和请求一起被发送。对于httpservlet来说，请求参数被存放与查询字符串或post表单中。<br /><br /><br />setAttribute ：在本次请求中存放一个属性， 多个请求之间属性会被复位。<br /><br /><br />getRequestDispatcher ：返回一个用于包装路径的类。<br /><br />forward ：转发请求到另一个资源（servlet, JSP file, or HTML file）<br /><br />include ：包含一个资源的上下文。<br />。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。<br /><br />下面是有关jdbc操作的辅助类(代码不足之处，请多多指正。)<br />DButil<br /><pre name="code" class="java">
package tutorial;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;

/**
 * 数据库操作工具类
 * 
 * @author cong-px
 */
public class DButil {

	private static DButil instance;

	/*
	 * private 构造方法
	 */
	private DButil() {
	}

	/**
	 * 单例
	 * 
	 * @return
	 */
	public synchronized static DButil getInstance() {
		if (null == instance) {
			instance = new DButil();
		}
		return instance;
	}

	/**
	 * 打开连接
	 * 
	 * @return conn 连接
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public Connection getConnection() throws ClassNotFoundException,
			SQLException {
		// 加载类
 Class.forName("com.mysql.jdbc.Driver");
	
		// H2Database 连接数据库
//		Class.forName("org.h2.Driver");
		// 获得连接
		Connection conn = DriverManager
				.getConnection("jdbc:mysql://localhost:3306/servletapp?user=root&password=123456&&useUnicode=true&characterEncoding=utf-8");
//		Connection conn = DriverManager.getConnection("jdbc:h2:~/test", "sa", "");
		// 返回连接
		return conn;
	}

	/**
	 * 关闭连接
	 * 
	 * @throws SQLException
	 */
	public static void closeConnection(Connection conn) throws SQLException {
		if (null != conn) {
			conn.close();
		}
	}

	/**
	 * 获得PreparedStatement
	 * 
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	public PreparedStatement getPreparedStatement(Connection conn, String sql)
			throws SQLException {
		PreparedStatement preparedStatement = conn.prepareStatement(sql);
		return preparedStatement;
	}

	/**
	 * 关闭 PreparedStatement
	 * 
	 * @throws SQLException
	 */
	public static void closePreparedStatement(
			PreparedStatement preparedStatement) throws SQLException {
		if (null != preparedStatement) {
			preparedStatement.close();
		}
	}

	/**
	 * 关闭ResultSet
	 * 
	 * @throws SQLException
	 */
	public static void closeResultSet(ResultSet resultSet) throws SQLException {
		if (null != resultSet) {
			resultSet.close();
		}
	}

	/**
	 * 查询操作&lt;B>方法后不要忘记关闭连接&lt;/B>
	 * 
	 * @param sql
	 * @param params
	 * @param preparedStatement
	 * @return resultSet 结果集
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	public ResultSet ExecuteQuery(PreparedStatement preparedStatement,
			String sql, Object[] params) throws SQLException,
			ClassNotFoundException {
		ResultSet resultSet = null;
		try {
			this.fillStatement(preparedStatement, params);
			resultSet = preparedStatement.executeQuery();
		} catch (SQLException e) {
			this.rethrow(e, sql, params);
		}
		return resultSet;
	}

	/**
	 * 更新操作
	 * 
	 * @param sql
	 * @param params
	 * @return rows 更新条数
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	public int ExecuteUpdate(String sql, Object[] params) throws SQLException,
			ClassNotFoundException {
		// 影响的行数
		int rows = 0;
		PreparedStatement preparedStatement = null;
		Connection conn = null;
		try {
			conn = this.getConnection();
			preparedStatement = this.getPreparedStatement(conn, sql);
			this.fillStatement(preparedStatement, params);
			rows = preparedStatement.executeUpdate();
		} catch (SQLException e) {
			this.rethrow(e, sql, params);
		} finally {
			DButil.closePreparedStatement(preparedStatement);
			DButil.closeConnection(conn);
		}
		return rows;
	}

	/**
	 * 参数化preparedStatement
	 * 
	 * @param stmt
	 * @param params
	 * @throws SQLException
	 */
	protected void fillStatement(PreparedStatement stmt, Object[] params)
			throws SQLException {
		if (null == params) {
			return;
		}
		/*
		 * 参数化preparedStatement
		 */
		for (int i = 0; i &lt; params.length; i++) {
			if (null != params[i]) {
				stmt.setObject(i + 1, params[i]);
			} else {
				stmt.setNull(i + 1, Types.CHAR);
			}
		}
	}

	/**
	 * 重新抛出异常
	 * 
	 * @param cause
	 * @param sql
	 * @param params
	 * @throws SQLException
	 */
	protected void rethrow(SQLException cause, String sql, Object params[])
			throws SQLException {
		StringBuilder msg = new StringBuilder();
		msg.append(" Query :");
		msg.append(sql);
		if (null == params) {
			msg.append("[]");
		} else {
			msg.append(Arrays.asList(params));
		}
		SQLException exception = new SQLException(msg.toString(), cause
				.getSQLState(), cause.getErrorCode());

		// 
		exception.setNextException(cause);
		throw exception;
	}

	/**
	 * 不对异常进行处理
	 * 
	 * @param conn
	 */
	public static void closeQuietly(Connection conn) {
		try {
			DButil.closeConnection(conn);
		} catch (Exception e) {
			// quiet
		}
	}

	/**
	 * 不对异常进行处理
	 * 
	 * @param preparedStatement
	 */
	public static void closeQuietly(PreparedStatement preparedStatement) {
		try {
			DButil.closePreparedStatement(preparedStatement);
		} catch (Exception e) {
			// quiet
		}
	}

	/**
	 * 不对异常进行处理
	 * 
	 * @param resultSet
	 */
	public static void colseQuietly(ResultSet resultSet) {
		try {
			resultSet.close();
		} catch (Exception e) {
			// quiet
		}
	}

	/**
	 * 不对异常进行处理
	 * 
	 * @param conn
	 * @param preparedStatement
	 * @param resultSet
	 */
	public static void colseQuietly(Connection conn,
			PreparedStatement preparedStatement, ResultSet resultSet) {
		try {
			DButil.colseQuietly(resultSet);
		} finally {
			try {
				DButil.closeQuietly(preparedStatement);
			} finally {
				DButil.closeQuietly(conn);
			}
		}
	}
}

</pre>
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/214134#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Sat, 12 Jul 2008 12:05:41 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/214134</link>
        <guid>http://congpeixue.javaeye.com/blog/214134</guid>
      </item>
      <item>
        <title>关于Struts2 的CRUD（并涉及页面，数据库，服务器端的乱码解决）</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/213245" style="color:red;">http://congpeixue.javaeye.com/blog/213245</a>&nbsp;
          发表时间: 2008年07月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          数据库采用mysql， （Navicat MySQL作为mysql的UI<a href="http://www.w2blog.net/view/142.html" target="_blank">http://www.w2blog.net/view/142.html</a>）<br />服務器采用tomcat6.0， <br />IDE使用Europa ,<br /> 使用dbutil（<a href="http://commons.apache.org/dbutils/" target="_blank">http://commons.apache.org/dbutils/</a>）作为操作数据库辅助的jar。<br /><br />1. 国际化问题<br />   所有代码都使用utf-8（在europa中如下设置jsp、js 、 properties的编码格式）<img src="http://www.javaeye.com/upload/attachment/30529/5bf01a23-eada-3a65-818d-3b3716c3a248.jpg" /><br /><br /><br />  <strong> 所有jsp页面</strong><br />   &lt;%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>（JSP编译器在将JSP文件编译成Servlet时使用的编码）<br /><br />   &lt;META http-equiv="Content-Type" content="text/html; charset=UTF-8"><br />（重新认定编码方式）<br /><br />  <strong>tomcat的server.xml</strong><br /><pre name="code" class="java">
    &lt;Connector port="8080" 
	      URIEncoding="UTF-8" 
	       protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" 
			   />
</pre><br /><br /><br />(<span style="color: red">注意要重新建europa的javaee的tomcat server;否则europa会保留第一次设置的值</span>)<br /><br />     <strong>数据库编码</strong><br /><br />   确保mysql安装时选择的编码为utf8，可以通过如下方式确认。（<br />my.ini）<br /><br /><pre name="code" class="java">
[client]

port=3306

[mysql]

default-character-set=utf8
</pre><br /><br /><br />  连接代码  <br /><pre name="code" class="java">&useUnicode=true&characterEncoding=utf-8</pre><br /><br />2、struts2的配置文件<br /><br />package.properties<br /><pre name="code" class="java">
User.name = 用户名
User.pwd = 用户密码
User.description = 用户详细信息
##############################
User.submit = 登录
User.create = 注册
User.update = 提交
User.reset = 重置
User.edit = 修改注册信息
User.logout = 退出登录
User.delete = 删除用户
User.selectAll = 查询全部
</pre><br /><br />键值对就是为了实现国际化（package.properties可以有多种命名方法，看你的具体业务需要了，我只是写个例子）<br /><br />在jsp中调用：   &lt;s:properties value="%getText('User.name')"/><br />在java source中调用：  String name = getText("User.name")<br /><br />UserAction-user_create-validation.xml<br /><br /><br /><pre name="code" class="java">
&lt;!DOCTYPE validators PUBLIC
        "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
        "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

&lt;validators>
    &lt;field name="name">
        &lt;field-validator type="requiredstring">
            &lt;message>&lt;![CDATA[ 用户名不能为空 ]]&gt;&lt;/message>
        &lt;/field-validator>
    &lt;/field>
    &lt;field name="pwd">
        &lt;field-validator type="requiredstring">
            &lt;message key="requiredstring"/>
        &lt;/field-validator>
    &lt;/field>
&lt;/validators>

</pre><br /><br />文件名格式为 <span style="color: red">className-actionalias-validation.xml</span><br /><br /><br /><strong>关于标签</strong><br /><br />&lt;s:iterator value="userList"><br />........<br />&lt;/s:iterator><br /><br /><br /><br /><br /><br /><br /><br /><span style="color: red"><strong>关于action的别名</strong></span><br /><br />xml配置文件： <br /><br /><pre name="code" class="java">
		&lt;action name="user_*" method="{1}" class="example.UserAction">
			&lt;result name="input">
				/example/user_create.jsp
			&lt;/result>
			&lt;result name="create_success">
				/example/user_create_success.jsp
			&lt;/result>
			&lt;result name="editInit">
				/example/user_edit.jsp
			&lt;/result>
			&lt;result name="selectAll">
				/example/user_selectAll.jsp
			&lt;/result>
			&lt;result name="delete_success">
				/example/user_create_success.jsp
			&lt;/result>
			&lt;result name="create">
				/example/user_create.jsp
			&lt;/result>
		&lt;/action>
</pre><br /><br />java代码中：<pre name="code" class="java">

	public String select() throws Exception {

		// 查询SQL
		String USER_SELECT = "SELECT u.NAME, u.PWD, u.DESCRIPTION FROM USER u";
		ResultSetHandler rsh = new ResultSetHandler() {
			public Object handle(ResultSet rs) throws SQLException {
				List&lt;User> userListTemp = new ArrayList&lt;User>();
				/*
				 * select
				 */

。。。。。。。。。。。。。。。。。。。。

	public String createInit() throws Exception {
		return "create";
	}
</pre><br /><br />jsp代码中：<br /><pre name="code" class="java">

					&lt;td>
						&lt;s:url action="user_editInit" id="user_edit">
							&lt;s:param name="name" value="name">&lt;/s:param>
						&lt;/s:url>
						&lt;s:a href="%{user_edit}">&lt;s:text name="%{getText('User.edit')}"/>&lt;/s:a>
						&lt;s:url action="user_delete" id="user_delete">
							&lt;s:param name="name" value="name">&lt;/s:param>
						&lt;/s:url>
						&lt;s:a href="%{user_delete}">&lt;s:text name="%{getText('User.delete')}"/>&lt;/s:a>
						&lt;hr>
					&lt;/td>	
</pre><br /><br /><br />从action的命名及java source的方法名中， 相信大家已经看出规律来了。<br /><br />附：<br />sql<br /><div class="quote_title">引用</div><div class="quote_div"><br />/*<br />MySQL Data Transfer<br />Source Host: localhost<br />Source Database: webapp<br />Target Host: localhost<br />Target Database: webapp<br />Date: 2008-7-9 下午 11:31:33<br />*/<br /><br />SET FOREIGN_KEY_CHECKS=0;<br />-- ----------------------------<br />-- Table structure for user<br />-- ----------------------------<br />CREATE TABLE `user` (<br />  `id` int(8) NOT NULL auto_increment,<br />  `name` varchar(45) NOT NULL,<br />  `pwd` varchar(45) NOT NULL,<br />  `description` varchar(245) default NULL,<br />  PRIMARY KEY  (`id`)<br />) ENGINE=InnoDB DEFAULT CHARSET=utf8;<br /><br />-- ----------------------------<br />-- Records <br />-- ----------------------------<br />INSERT INTO `user` VALUES ('42', '1', '1', '1');<br />INSERT INTO `user` VALUES ('43', '11', '11', '11');<br /><br /></div><span style="color: blue"><br />其他地方感觉也没什么可说的啦， (其实上面每一点要深入下去， 都能写成一篇, 我只是草草说下，抛砖引玉了)我把源码贴上， 如果需要jar文件， 可以congpeixue@126.com</span> <br /><br />后面有时间我会对这个例子再完善一下。。。。
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/213245#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 09 Jul 2008 22:41:56 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/213245</link>
        <guid>http://congpeixue.javaeye.com/blog/213245</guid>
      </item>
      <item>
        <title>java类型的生命周期</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/212038" style="color:red;">http://congpeixue.javaeye.com/blog/212038</a>&nbsp;
          发表时间: 2008年07月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          java虚拟机通过装载、连接和初始化一个java类型，使该类型可以被一个正在运行的java程序所使用。<br />装载就是把二进制形式的java类型读入java虚拟机中；<br />连接就是把已经读入虚拟机的二进制形式的类型数据合并到虚拟机的运行时状态中去，连接阶段分为3个子步骤--验证、准备、解析。<br />之后就时初始化。<br /><br />java虚拟机实现必须在每个类或接口首次主动使用时初始化。<br /><br /><br />下面这六种情形符合主动使用的要求：<br />1 、当创建某个类的新实例时（或者通过在字节码中执行new指令；或者通过不明确的创建、反射、克隆或者反序列化）。<br />2、当调用某的类的静态方法时（即在字节码中执行invokestatic指令时）。<br />3、当使用某个类或接口的静态字段，或者对该字段赋值时（即在字节码中，执行getstatic或putstatic指令时），用final修饰的静态字段除外，它被初始化为一个编译时的常量表达式。<br />4、当调用api中的某些反射方法时，比如类class中的方法或者java.lang.reflect包中的类方法。<br />5、当初始化某个类的子类时，（某个类初始化时，要求它的超类已经被初始化了）<br />6、当虚拟机启动某个被表明为启动类的类（即含有main方法的那个类）<br /><br />注意：<br />使用一个非常量的静态字段只有当类或者接口的确声明了这个字段的时候才是主动调用； <br />类中声明的字段可能会被子类引用；接口中声明的字段可能会被子接口或者实现了这个接口的类引用。对于子类、子接口和实现了接口的类来说，就是被动调用--使用它们并不会触发它们的初始化。 <br /><br /><br /><br />如果程序不在引用某类型，那么这个类型就无法再对未来的计算过程产生影响。类型变成不可触及的，而且可以被垃圾收集。
          <br/>
          <span style="color:red;">
            <a href="http://congpeixue.javaeye.com/blog/212038#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 06 Jul 2008 14:49:02 +0800</pubDate>
        <link>http://congpeixue.javaeye.com/blog/212038</link>
        <guid>http://congpeixue.javaeye.com/blog/212038</guid>
      </item>
      <item>
        <title>单例模式</title>
        <author>congpeixue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://congpeixue.javaeye.com">congpeixue</a>&nbsp;
          链接：<a href="http://congpeixue.javaeye.com/blog/211967" style="color:red;">http://congpeixue.javaeye.com/blog/211967</a>&nbsp;
          发表时间: 2008年07月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">



package singleton;

/**
 * @author 丛培雪 E-mail:congpeixue@126.com
 * @version 创建时间：2008-7-6 上午02:21:41 类说明
 */
public class Singleton {
	static class SingletonHolder {
		static Singleton instance = new Singleton();
	}

	public static Singleton getInstance() {
		return SingletonHolder.instance;
	}
}


</pre><br /><br /><br /><br /><br /><pre name="code" class="java">
	package singleton;
	
	/**
	 * @author 丛培雪 E-mail:congpeixue@126.com
	 * @version 创建时间：2008-7-6 上午02:00:50 类说明
	 */
	public class Singleton1 {
		private Singleton1() {
		}
	
		private static Singleton1 instance = new Singleton1();
	
		public static Singleton1 getInstance() {
			return instance;
		}
	}


</pre><br /><br /><br /><pre name="code" class="java">

package singleton;

/**
 * @author 丛培雪 E-mail:congpeixue@126.com
 * @version 创建时间：2008-7-6 上午02:03:50 类说明
 */
public class Singleton2 {
	private static Singleton2 instance = null;