﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Terry的Blog-随笔分类-java语言</title><link>http://www.blogjava.net/terry-zj/category/4744.html</link><description>&lt;script src="http://www.google-analytics.com/urchin.js" type="text/javascript"&gt;
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
_uacct = "UA-285051-1";
urchinTracker();
&lt;/script&gt;
</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 01:07:38 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 01:07:38 GMT</pubDate><ttl>60</ttl><item><title>jsp页面上调用Batch</title><link>http://www.blogjava.net/terry-zj/archive/2006/10/10/74308.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 10 Oct 2006 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/10/10/74308.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/74308.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/10/10/74308.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/74308.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/74308.html</trackback:ping><description><![CDATA[
		<p>有这样一个需求，web服务器是sun Soaris5.8 原来有一个java写的Batch打包成jar文件由shell调用 现在要在页面上增加一个按钮调用这个shell。<br />代码如下：<br /> struts中的Action</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> ActionForward execute(<br />    ActionMapping mapping,<br />    ActionForm form,<br />    HttpServletRequest request,<br />    HttpServletResponse response)<br />    </span>
				<span style="COLOR: #0000ff">throws</span>
				<span style="COLOR: #000000"> Exception {<br /><br />    String command </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">csh /home/zwfe/shell/zwfecv101.csh</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">;<br />    Process child;<br />    </span>
				<span style="COLOR: #0000ff">try</span>
				<span style="COLOR: #000000"> {<br />        child </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> Runtime.getRuntime().exec(command);<br /><br />        BufferedReader in </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> BufferedReader(</span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> InputStreamReader(child.getInputStream()));<br />        String line </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">""</span>
				<span style="COLOR: #000000">;<br />        </span>
				<span style="COLOR: #0000ff">while</span>
				<span style="COLOR: #000000"> ((line </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> in.readLine()) </span>
				<span style="COLOR: #000000">!=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">null</span>
				<span style="COLOR: #000000">) {<br />            System.out.println(line);<br />        }<br />        in.close();<br /><br />    } </span>
				<span style="COLOR: #0000ff">catch</span>
				<span style="COLOR: #000000"> (IOException e) {<br />        System.out.println(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">e.getMessage() = </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">+</span>
				<span style="COLOR: #000000"> e.getMessage());<br />        e.printStackTrace();<br />    }<br /><br />    BatchDateDAO dao </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> BatchDateDAO();<br />    Zwfecw002Form zwfe002form </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> (Zwfecw002Form) form;<br />    zwfe002form.setBatchDate(dao.batchDate());<br /><br />    </span>
				<span style="COLOR: #0000ff">return</span>
				<span style="COLOR: #000000"> mapping.findForward(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">screen.zwfecw002</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">);<br />}</span>
		</div>
		<br />这里应该注意child <span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Runtime.getRuntime().exec(command);后需要检查这个Process 是否已经执行完毕，否则当Action执行完返回后Process 将会中断。<br /></span><br /><img src ="http://www.blogjava.net/terry-zj/aggbug/74308.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-10-10 15:53 <a href="http://www.blogjava.net/terry-zj/archive/2006/10/10/74308.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习spring的好站</title><link>http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 07 Jul 2006 15:48:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/57215.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/57215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/57215.html</trackback:ping><description><![CDATA[http://www.javaworld.com.tw/confluence/display/opensrc/Spring<img src ="http://www.blogjava.net/terry-zj/aggbug/57215.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-07-07 23:48 <a href="http://www.blogjava.net/terry-zj/archive/2006/07/07/57215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Introducing to Spring Framework（中文修订版） 转载</title><link>http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 21 Jun 2006 03:42:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/54163.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/54163.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/54163.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载地址： http://forum.javaeye.com/viewtopic.php?t=4919  中文http://www.theserverside.com/tt/articles/article.tss?l=SpringFramework 英文Introducing to Spring Framework						作者：Rod Johnson 译者：yanger，taow...&nbsp;&nbsp;<a href='http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html'>阅读全文</a><img src ="http://www.blogjava.net/terry-zj/aggbug/54163.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-06-21 11:42 <a href="http://www.blogjava.net/terry-zj/archive/2006/06/21/54163.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代理模式(Proxy pattern) 转载</title><link>http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 20 Jun 2006 03:46:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/53937.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/53937.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/53937.html</trackback:ping><description><![CDATA[
		<p>1. 代理模式 <br />代理模式的作用是：为其他对象提供一种代理以控制对这个对象的访问。在某些情况下，一个客户不想或者不能直接引用另一个对象，而代理对象可以在客户端和目标对象之间起到中介的作用。 <br />代理模式一般涉及到三个角色： <br />抽象角色：声明真实对象和代理对象的共同接口； <br />代理角色：代理对象角色内部含有对真实对象的引用，从而可以操作真实对象，同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时，代理对象可以在执行真实对象操作时，附加其他的操作，相当于对真实对象进行封装。 <br />真实角色：代理角色所代表的真实对象，是我们最终要引用的对象。</p>
		<p>以下以《Java与模式》中的示例为例： </p>
		<p>抽象角色： <br />abstract public class Subject {<br />   abstract public void request(); <br />}  </p>
		<p>真实角色：实现了Subject的request()方法。 <br />public class RealSubject extends Subject { <br />    public RealSubject() { } <br />    <br />    public void request() { <br />        System.out.println("From real subject."); <br />    } <br />} </p>
		<p>代理角色： <br />public class ProxySubject extends Subject { <br />    private RealSubject realSubject; //以真实角色作为代理角色的属性 </p>
		<p>    public ProxySubject() { } </p>
		<p>
				<br />    public void request() { //该方法封装了真实对象的request方法 <br />        preRequest(); </p>
		<p>        if( realSubject == null ) { </p>
		<p>            realSubject = new RealSubject(); <br />        } </p>
		<p>        realSubject.request(); //此处执行真实对象的request方法 </p>
		<p>        postRequest(); <br />    }</p>
		<p>
				<br />    private void preRequest() { <br />        //something you want to do before requesting <br />    }</p>
		<p>    private void postRequest() { <br />        //something you want to do after requesting <br />    } <br />} </p>
		<p>客户端调用： <br />Subject sub=new ProxySubject(); <br />Sub.request(); </p>
		<p>由以上代码可以看出，客户实际需要调用的是RealSubject类的request()方法，现在用ProxySubject来代理 RealSubject类，同样达到目的，同时还封装了其他方法(preRequest(),postRequest())，可以处理一些其他问题。 </p>
		<p>另外，如果要按照上述的方法使用代理模式，那么真实角色必须是事先已经存在的，并将其作为代理对象的内部属性。但是实际使用时，一个真实角色必须对应一个 代理角色，如果大量使用会导致类的急剧膨胀；此外，如果事先并不知道真实角色，该如何使用代理呢？这个问题可以通过Java的动态代理类来解决。<br /> <br />2.动态代理类 </p>
		<p>Java动态代理类位于Java.lang.reflect包下，一般主要涉及到以下两个类： </p>
		<p>(1). Interface InvocationHandler：该接口中仅定义了一个方法Object：invoke(Object obj,Method method, Object[] args)。在实际使用时，第一个参数obj一般是指代理类，method是被代理的方法，如上例中的request()，args为该方法的参数数组。 这个抽象方法在代理类中动态实现。 </p>
		<p>
				<br />(2).Proxy：该类即为动态代理类，作用类似于上例中的ProxySubject，其中主要包含以下内容： </p>
		<p>Protected Proxy(InvocationHandler h)：构造函数，估计用于给内部的h赋值。 </p>
		<p>Static Class getProxyClass (ClassLoader loader, Class[] interfaces)：获得一个代理类，其中loader是类装载器，interfaces是真实类所拥有的全部接口的数组。 </p>
		<p>Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)：返回代理类的一个实例，返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。 </p>
		<p> </p>
		<p>所谓Dynamic Proxy是这样一种class：它是在运行时生成的class，在生成它时你必须提供一组interface给它，然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦，这个Dynamic Proxy其实就是一个Proxy，它不会替你作实质性的工作，在生成它的实例时你必须提供一个handler，由它接管实际的工作。</p>
		<p>在使用动态代理类时，我们必须实现InvocationHandler接口，以第一节中的示例为例： </p>
		<p>抽象角色(之前是抽象类，此处应改为接口)： </p>
		<p>public interface Subject { <br />   abstract public void request(); <br />} </p>
		<p>具体角色RealSubject：<br />public class RealSubject implements Subject{</p>
		<p>  public RealSubject(){}</p>
		<p>  public void request(){<br />    System.out.println("From real subject.");<br />  }</p>
		<p>} </p>
		<p>
				<br />代理处理器： <br />import java.lang.reflect.Method;</p>
		<p>import java.lang.reflect.InvocationHandler;</p>
		<p>public class DynamicSubject implements InvocationHandler {<br />  private Object sub;<br />  public DynamicSubject() {}</p>
		<p>  public DynamicSubject(Object obj) {<br />    sub = obj;<br />  }</p>
		<p>public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {<br />   System.out.println("before calling " + method);<br />   method.invoke(sub,args);</p>
		<p>   System.out.println("after calling " + method);<br />   return null;<br /> }</p>
		<p>}</p>
		<p> </p>
		<p>该代理类的内部属性为Object类，实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值；此外，在该类还实现了invoke方法，该方法中的 </p>
		<p>method.invoke(sub,args); </p>
		<p>其实就是调用被代理对象的将要被执行的方法，方法参数sub是实际的被代理对象，args为执行被代理对象相应操作所需的参数。通过动态代理类，我们可以在调用之前或之后执行一些相关操作。 </p>
		<p>客户端： </p>
		<p>import java.lang.reflect.InvocationHandler; <br />import java.lang.reflect.Proxy; <br />import java.lang.reflect.Constructor; <br />import java.lang.reflect.Method; </p>
		<p>public class Client { </p>
		<p>static public void main(String[] args) throws Throwable { </p>
		<p>   RealSubject rs = new RealSubject(); //在这里指定被代理类 <br />   InvocationHandler ds = new DynamicSubject(rs); <br />   Class cls = rs.getClass(); </p>
		<p>   //以下是一次性生成代理<br />   Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds ); <br />   subject.request(); </p>
		<p>} </p>
		<p>程序运行结果：<br />before calling public abstract void Subject.request()<br />From real subject.<br />after calling public abstract void Subject.request()</p>
		<p>通过这种方式，被代理的对象(RealSubject)可以在运行时动态改变，需要控制的接口(Subject接口)可以在运行时改变，控制的方式(DynamicSubject类)也可以动态改变，从而实现了非常灵活的动态代理关系。<br /> <br /><br />转载地址：<br /><a href="http://www.java3z.com/cwbwebhome/article/article2/2300.jsp?id=846">http://www.java3z.com/cwbwebhome/article/article2/2300.jsp?id=846</a><br /><a href="http://www.csdn.net/develop/Article/26/26750.shtm">http://www.csdn.net/develop/Article/26/26750.shtm</a> </p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/53937.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-06-20 11:46 <a href="http://www.blogjava.net/terry-zj/archive/2006/06/20/53937.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何用Java得到Excel中Formula的值</title><link>http://www.blogjava.net/terry-zj/archive/2006/05/23/47643.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 23 May 2006 06:47:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/05/23/47643.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/47643.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/05/23/47643.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/47643.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/47643.html</trackback:ping><description><![CDATA[工具1：POI<br />POI是常用的读取Office文件的开源工具。但是在它正式发布的版本中没有提供得到Excel中Formula值的功能。<br />这个POI还在开发中的功能。相关信息 请看<a href="http://jakarta.apache.org/poi/hssf/eval.html">http://jakarta.apache.org/poi/hssf/eval.html</a><br /><br />工具2：JExcelAPI<br /><strong>Java Excel API</strong> - A Java API to read, write, and modify Excel spreadsheets<br /><a href="http://jexcelapi.sourceforge.net/">http://jexcelapi.sourceforge.net/</a><br />目前的最新版本是2.6 <br /><br /><strong>Some Features</strong><br />* Reads data from Excel 95, 97, 2000, XP, and 2003 workbooks<br />* Reads and writes formulas (Excel 97 and later only)<br />* Generates spreadsheets in Excel 2000 format<br />* Supports font, number and date formatting<br />* Supports shading, bordering, and coloring of cells<br />* Modifies existing worksheets<br />* Is internationalized, enabling processing in almost any locale, country, language, or character encoding (formulas are currently only supported in English, French, * * Spanish, and German, but more can be added if translated)<br />* Supports copying of charts<br />* Supports insertion and copying of images into spreadsheets<br />* Supports logging with Jakarta Commons Logging, log4j, JDK 1.4 Logger, etc<br />...and much more<br /><br />　<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">  1</span> <span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.BufferedWriter;<br /></span><span style="COLOR: #008080">  2</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.File;<br /></span><span style="COLOR: #008080">  3</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.IOException;<br /></span><span style="COLOR: #008080">  4</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.OutputStream;<br /></span><span style="COLOR: #008080">  5</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.OutputStreamWriter;<br /></span><span style="COLOR: #008080">  6</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.UnsupportedEncodingException;<br /></span><span style="COLOR: #008080">  7</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">  8</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.util.ArrayList;<br /></span><span style="COLOR: #008080">  9</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.util.Iterator;<br /></span><span style="COLOR: #008080"> 10</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 11</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> jxl.Cell;<br /></span><span style="COLOR: #008080"> 12</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> jxl.CellType;<br /></span><span style="COLOR: #008080"> 13</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> jxl.FormulaCell;<br /></span><span style="COLOR: #008080"> 14</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> jxl.Sheet;<br /></span><span style="COLOR: #008080"> 15</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> jxl.Workbook;<br /></span><span style="COLOR: #008080"> 16</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> jxl.biff.CellReferenceHelper;<br /></span><span style="COLOR: #008080"> 17</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> jxl.biff.formula.FormulaException;<br /></span><span style="COLOR: #008080"> 18</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 19</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #008080"> 20</span> <span style="COLOR: #008000"> * Goes through each cell in the workbook, and if the contents of that cell is a<br /></span><span style="COLOR: #008080"> 21</span> <span style="COLOR: #008000"> * formula, it prints out the last calculated value and the formula string<br /></span><span style="COLOR: #008080"> 22</span> <span style="COLOR: #008000"> </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 23</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> Formulas {<br /></span><span style="COLOR: #008080"> 24</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 25</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> main(String[] args) {<br /></span><span style="COLOR: #008080"> 26</span> <span style="COLOR: #000000">        String file </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">jxlrwtest.xls</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 27</span> <span style="COLOR: #000000">        String encoding </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">UTF8</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 28</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> {<br /></span><span style="COLOR: #008080"> 29</span> <span style="COLOR: #000000">            Workbook w </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Workbook.getWorkbook(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> File(file));<br /></span><span style="COLOR: #008080"> 30</span> <span style="COLOR: #000000">            Formulas f </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Formulas(w, System.out, encoding);<br /></span><span style="COLOR: #008080"> 31</span> <span style="COLOR: #000000">            w.close();<br /></span><span style="COLOR: #008080"> 32</span> <span style="COLOR: #000000">        } </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (Exception e) {<br /></span><span style="COLOR: #008080"> 33</span> <span style="COLOR: #000000">            e.printStackTrace();<br /></span><span style="COLOR: #008080"> 34</span> <span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080"> 35</span> <span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080"> 36</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 37</span> <span style="COLOR: #000000">    </span><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #008080"> 38</span> <span style="COLOR: #008000">     * Constructor<br /></span><span style="COLOR: #008080"> 39</span> <span style="COLOR: #008000">     * <br /></span><span style="COLOR: #008080"> 40</span> <span style="COLOR: #008000">     * </span><span style="COLOR: #808080">@param</span><span style="COLOR: #008000"> w<br /></span><span style="COLOR: #008080"> 41</span> <span style="COLOR: #008000">     *            The workbook to interrogate<br /></span><span style="COLOR: #008080"> 42</span> <span style="COLOR: #008000">     * </span><span style="COLOR: #808080">@param</span><span style="COLOR: #008000"> out<br /></span><span style="COLOR: #008080"> 43</span> <span style="COLOR: #008000">     *            The output stream to which the CSV values are written<br /></span><span style="COLOR: #008080"> 44</span> <span style="COLOR: #008000">     * </span><span style="COLOR: #808080">@param</span><span style="COLOR: #008000"> encoding<br /></span><span style="COLOR: #008080"> 45</span> <span style="COLOR: #008000">     *            The encoding used by the output stream. Null or unrecognized<br /></span><span style="COLOR: #008080"> 46</span> <span style="COLOR: #008000">     *            values cause the encoding to default to UTF8<br /></span><span style="COLOR: #008080"> 47</span> <span style="COLOR: #008000">     * </span><span style="COLOR: #808080">@exception</span><span style="COLOR: #008000"> java.io.IOException<br /></span><span style="COLOR: #008080"> 48</span> <span style="COLOR: #008000">     </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 49</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Formulas(Workbook w, OutputStream out, String encoding)<br /></span><span style="COLOR: #008080"> 50</span> <span style="COLOR: #000000">            </span><span style="COLOR: #0000ff">throws</span><span style="COLOR: #000000"> IOException {<br /></span><span style="COLOR: #008080"> 51</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (encoding </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">encoding.equals(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">UnicodeBig</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)) {<br /></span><span style="COLOR: #008080"> 52</span> <span style="COLOR: #000000">            encoding </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">UTF8</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 53</span> <span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080"> 54</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 55</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> {<br /></span><span style="COLOR: #008080"> 56</span> <span style="COLOR: #000000">            OutputStreamWriter osw </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> OutputStreamWriter(out, encoding);<br /></span><span style="COLOR: #008080"> 57</span> <span style="COLOR: #000000">            BufferedWriter bw </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> BufferedWriter(osw);<br /></span><span style="COLOR: #008080"> 58</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 59</span> <span style="COLOR: #000000">            ArrayList parseErrors </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> ArrayList();<br /></span><span style="COLOR: #008080"> 60</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 61</span> <span style="COLOR: #000000">            </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sheet </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; sheet </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> w.getNumberOfSheets(); sheet</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br /></span><span style="COLOR: #008080"> 62</span> <span style="COLOR: #000000">                Sheet s </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> w.getSheet(sheet);<br /></span><span style="COLOR: #008080"> 63</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 64</span> <span style="COLOR: #000000">                bw.write(s.getName());<br /></span><span style="COLOR: #008080"> 65</span> <span style="COLOR: #000000">                bw.newLine();<br /></span><span style="COLOR: #008080"> 66</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 67</span> <span style="COLOR: #000000">                Cell[] row </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 68</span> <span style="COLOR: #000000">                Cell c </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 69</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 70</span> <span style="COLOR: #000000">                </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> s.getRows(); i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br /></span><span style="COLOR: #008080"> 71</span> <span style="COLOR: #000000">                    row </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> s.getRow(i);<br /></span><span style="COLOR: #008080"> 72</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 73</span> <span style="COLOR: #000000">                    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> j </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; j </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> row.length; j</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br /></span><span style="COLOR: #008080"> 74</span> <span style="COLOR: #000000">                        c </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> row[j];<br /></span><span style="COLOR: #008080"> 75</span> <span style="COLOR: #000000">                        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (c.getType() </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> CellType.NUMBER_FORMULA<br /></span><span style="COLOR: #008080"> 76</span> <span style="COLOR: #000000">                                </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> c.getType() </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> CellType.STRING_FORMULA<br /></span><span style="COLOR: #008080"> 77</span> <span style="COLOR: #000000">                                </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> c.getType() </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> CellType.BOOLEAN_FORMULA<br /></span><span style="COLOR: #008080"> 78</span> <span style="COLOR: #000000">                                </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> c.getType() </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> CellType.DATE_FORMULA<br /></span><span style="COLOR: #008080"> 79</span> <span style="COLOR: #000000">                                </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> c.getType() </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> CellType.FORMULA_ERROR) {<br /></span><span style="COLOR: #008080"> 80</span> <span style="COLOR: #000000">                            FormulaCell nfc </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (FormulaCell) c;<br /></span><span style="COLOR: #008080"> 81</span> <span style="COLOR: #000000">                            StringBuffer sb </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> StringBuffer();<br /></span><span style="COLOR: #008080"> 82</span> <span style="COLOR: #000000">                            CellReferenceHelper.getCellReference(c.getColumn(),<br /></span><span style="COLOR: #008080"> 83</span> <span style="COLOR: #000000">                                    c.getRow(), sb);<br /></span><span style="COLOR: #008080"> 84</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 85</span> <span style="COLOR: #000000">                            </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> {<br /></span><span style="COLOR: #008080"> 86</span> <span style="COLOR: #000000">                                bw.write(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Formula in </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> sb.toString()<br /></span><span style="COLOR: #008080"> 87</span> <span style="COLOR: #000000">                                        </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> value:  </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> c.getContents());<br /></span><span style="COLOR: #008080"> 88</span> <span style="COLOR: #000000">                                bw.flush();<br /></span><span style="COLOR: #008080"> 89</span> <span style="COLOR: #000000">                                bw.write(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> formula: </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> nfc.getFormula());<br /></span><span style="COLOR: #008080"> 90</span> <span style="COLOR: #000000">                                bw.flush();<br /></span><span style="COLOR: #008080"> 91</span> <span style="COLOR: #000000">                                bw.newLine();<br /></span><span style="COLOR: #008080"> 92</span> <span style="COLOR: #000000">                            } </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (FormulaException e) {<br /></span><span style="COLOR: #008080"> 93</span> <span style="COLOR: #000000">                                bw.newLine();<br /></span><span style="COLOR: #008080"> 94</span> <span style="COLOR: #000000">                                parseErrors<br /></span><span style="COLOR: #008080"> 95</span> <span style="COLOR: #000000">                                        .add(s.getName() </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> sb.toString()<br /></span><span style="COLOR: #008080"> 96</span> <span style="COLOR: #000000">                                                </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">: </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> e.getMessage());<br /></span><span style="COLOR: #008080"> 97</span> <span style="COLOR: #000000">                            }<br /></span><span style="COLOR: #008080"> 98</span> <span style="COLOR: #000000">                        }<br /></span><span style="COLOR: #008080"> 99</span> <span style="COLOR: #000000">                    }<br /></span><span style="COLOR: #008080">100</span> <span style="COLOR: #000000">                }<br /></span><span style="COLOR: #008080">101</span> <span style="COLOR: #000000">            }<br /></span><span style="COLOR: #008080">102</span> <span style="COLOR: #000000">            bw.flush();<br /></span><span style="COLOR: #008080">103</span> <span style="COLOR: #000000">            bw.close();<br /></span><span style="COLOR: #008080">104</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">105</span> <span style="COLOR: #000000">            </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (parseErrors.size() </span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) {<br /></span><span style="COLOR: #008080">106</span> <span style="COLOR: #000000">                System.err.println();<br /></span><span style="COLOR: #008080">107</span> <span style="COLOR: #000000">                System.err.println(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">There were </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> parseErrors.size()<br /></span><span style="COLOR: #008080">108</span> <span style="COLOR: #000000">                        </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> errors</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">109</span> <span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">110</span> <span style="COLOR: #000000">                Iterator i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> parseErrors.iterator();<br /></span><span style="COLOR: #008080">111</span> <span style="COLOR: #000000">                </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> (i.hasNext()) {<br /></span><span style="COLOR: #008080">112</span> <span style="COLOR: #000000">                    System.err.println(i.next());<br /></span><span style="COLOR: #008080">113</span> <span style="COLOR: #000000">                }<br /></span><span style="COLOR: #008080">114</span> <span style="COLOR: #000000">            }<br /></span><span style="COLOR: #008080">115</span> <span style="COLOR: #000000">        } </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (UnsupportedEncodingException e) {<br /></span><span style="COLOR: #008080">116</span> <span style="COLOR: #000000">            System.err.println(e.toString());<br /></span><span style="COLOR: #008080">117</span> <span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080">118</span> <span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">119</span> <span style="COLOR: #000000">}</span></div><br /><br /><br />两篇中文的介绍：<br /><a href="http://www.chinaitpower.com/A/2005-03-03/109739.html">http://www.chinaitpower.com/A/2005-03-03/109739.html</a><br /><a href="http://www.myfaq.com.cn/A200507/2005-07-24/166992.html">http://www.myfaq.com.cn/A200507/2005-07-24/166992.html</a><a href="http://www.gamvan.com/developer/java/2005/9/614.html"></a><img src ="http://www.blogjava.net/terry-zj/aggbug/47643.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-05-23 14:47 <a href="http://www.blogjava.net/terry-zj/archive/2006/05/23/47643.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>日文编码与Unicode编码转换（未完）</title><link>http://www.blogjava.net/terry-zj/archive/2006/04/20/42201.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 20 Apr 2006 09:45:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/04/20/42201.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/42201.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/04/20/42201.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/42201.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/42201.html</trackback:ping><description><![CDATA[
		<p>参考网址：<br />日本語のUnicodeベンダ依存文字表 <a href="http://www.ingrid.org/java/i18n/unicode.html">http://www.ingrid.org/java/i18n/unicode.html</a><br /></p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/42201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-04-20 17:45 <a href="http://www.blogjava.net/terry-zj/archive/2006/04/20/42201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>反射机制---Java的动态特性之一</title><link>http://www.blogjava.net/terry-zj/archive/2006/04/14/41128.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 14 Apr 2006 09:02:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/04/14/41128.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/41128.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/04/14/41128.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/41128.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/41128.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Reflection是Java的一个重要特性。这种机制可以让我们通过类名，方法名，数据成员名来得到相关的元素。关键类java.lang.Class：这个也是Object的子类 是利用反射机制的起点。1：产生Class object使用getClass()String str = "abc";Class c1 = str.getClass();使用Class.getSuperclass();Butt...&nbsp;&nbsp;<a href='http://www.blogjava.net/terry-zj/archive/2006/04/14/41128.html'>阅读全文</a><img src ="http://www.blogjava.net/terry-zj/aggbug/41128.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-04-14 17:02 <a href="http://www.blogjava.net/terry-zj/archive/2006/04/14/41128.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>What's Your Purpose？</title><link>http://www.blogjava.net/terry-zj/archive/2006/03/31/38430.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 31 Mar 2006 03:51:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/03/31/38430.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/38430.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/03/31/38430.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/38430.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/38430.html</trackback:ping><description><![CDATA[
		<p>      今天在javaeye上看到BirdGu的一席话，深有同感。<br />      他说：“<strong>重构的目的是什么？是为了满足程序员对完美程序的不懈追求吗？不是。重构的目的是改善程序的结构，使程序有更好的可扩展性和灵活性，使得更容易扩充新功能的需要和应对需求变更；同时使程序有更好的可读性，方便其它程序员的阅读和维护。</strong>这些当然对用户是有价值的，用户为这些工作买单也是理所当然的。 <br />      有味道的代码是从哪里来的呢？ <br />人是不完美的，自然也不可能一开始就写出完美的代码。 <br />另一方面，代码的好坏有时并无法作出绝对的判断。设计的过程是一个权衡的过程。某种条件组合下是好的，合理的权衡，另一种条件组合下会变成不好的，不合理的权衡。因此某些条件下是好的代码，条件变化了，可能会变成不好的代码，会需要重构了。 <br />先以最简单的方式实现功能，然后再进行重构。实质就是先提供用户最需要的东西：实现功能。再提供额外的价值，就是可扩展性，灵活性和可维护性。这也是从用户需要出发的。 <br />      那么在最开始写程序，甚至开始开发以前，我们能不能，需不需要做些工作以减少以后的重构呢？关于这个问题请看今年Jolt大奖的获奖作品：Prefactoring。“<br /><br />      不管做什么事情都要经常提醒自己最终的目的是什么。重构的目的不是满足代码洁癖，设计framework的目的不是练习各种Design pattern,下载电子书的目的不是收藏......</p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/38430.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-03-31 11:51 <a href="http://www.blogjava.net/terry-zj/archive/2006/03/31/38430.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts1.1中的Lazy ActionForm</title><link>http://www.blogjava.net/terry-zj/archive/2006/03/01/33037.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 01 Mar 2006 09:27:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/03/01/33037.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/33037.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/03/01/33037.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/33037.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/33037.html</trackback:ping><description><![CDATA[
		<p>以前我转载过一篇“介绍struts的新特性:Lazy ActionForm“<br /><a href="/terry-zj/archive/2005/12/09/23090.html">http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html</a><br />这篇文章里面介绍的方法大大较少了ActionForm中的编码工作，但是这个Lazy ActionForm在struts1.1的时候还没有。如果既要使用struts1.1又想Lazy一下那？（实际上struts1.1还是目前使用比较多的版本）<br />其实少量的代码就可以让普通的Form接近Lazy ActionForm的效果。<br /> jsp中写：<br />        &lt;table align="center" border="0" width="300"&gt;<br />                &lt;tr&gt;<br />                    &lt;td align="right" width="35%"&gt;<br />                        用户ID:<br />                    &lt;/td&gt;<br />                    &lt;td width="65%"&gt;<br />                        &lt;html:text property="<font color="#0000ff">data(username)</font>" size="20" maxlength="20" /&gt;<br />                    &lt;/td&gt;<br />                &lt;/tr&gt;<br />                &lt;tr&gt;<br />                    &lt;td align="right"&gt;<br />                        密码:<br />                    &lt;/td&gt;<br />                    &lt;td&gt;<br />                        &lt;html:text property="<font color="#0000ff">data(password)</font>" size="20" maxlength="10" /&gt;<br />                    &lt;/td&gt;<br />                &lt;/tr&gt;<br />                &lt;tr&gt;<br />                    &lt;td&gt;<br />                        &amp;nbsp;&amp;nbsp;&amp;nbsp;<br />                    &lt;/td&gt;<br />                    &lt;td&gt;<br />                        &lt;html:button property="login" value="确认" onclick="submitForm();" /&gt;<br />                        &amp;nbsp;&amp;nbsp;&amp;nbsp;<br />                        &lt;html:reset value="清空" /&gt;<br />                    &lt;/td&gt;<br />                &lt;/tr&gt;<br />            &lt;/table&gt;<br /><br />LoginAction中写：<br />public ActionForward doAction(ActionMapping mapping, <br />                                  RequestContext req) {<br />        String forward = "menu";<br />        BaseForm frm = (BaseForm)req.getForm();<br />        System.out.println(<font color="#0000ff">frm.get("username")</font>);<br />        System.out.println(<font color="#0000ff">frm.get("password")</font>);<br />        // ......        <br />        return mapping.findForward(forward);<br />}<br /><br />BaseForm中写：<br />public class BaseForm extends ActionForm {<br />    private HashMap data = new HashMap();</p>
		<p>    public HashMap getData() {<br />         return data;<br />    }</p>
		<p>    public void setData(HashMap data) {<br />        this.data = data;<br />    }</p>
		<p>    public String get(String key) {<br />        return (String) data.get(key);<br />    }</p>
		<p>    public void set(String key, Object value) {<br />        data.put(key, value);<br />    }<br />}</p>
		<p>struts-config.xml中写：<br /> &lt;form-beans&gt;<br />    &lt;form-bean       name="baseform"     type="com.web.system.base.BaseForm"/&gt;<br />  &lt;/form-beans&gt;<br /><br /></p>
<img src ="http://www.blogjava.net/terry-zj/aggbug/33037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-03-01 17:27 <a href="http://www.blogjava.net/terry-zj/archive/2006/03/01/33037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JTA知识(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2006/02/08/29931.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 08 Feb 2006 07:12:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/02/08/29931.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/29931.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/02/08/29931.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/29931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/29931.html</trackback:ping><description><![CDATA[<P>最近项目中遇到了JTA的内容，在网上搜索了一番了解了一下基本概念。<BR><BR>JTA知识 <A href="http://letgo.bokee.com/351051.html">http://letgo.bokee.com/351051.html</A><BR><BR>JTA主要用于分布式的多个数据源的两阶段提交的事务,而JDBC的Connection提供的单个数据源的事务; 后者因为只涉及到一个数据源,所以其事务可以由数据库自己单独实现, 而JTA事务因为其分布式和多数据源的特性, 不可能由任何"一个"数据源实现事务, 因此JTA中的事务是由"事务管理器"实现的,它会在多个数据源之间统筹事务,具体使用的技术就是所谓的"两阶段提交", 一般JTA事务都是用于EJB中(因为EJB本身也是分布式的), 所以一般的应用服务器都有自己的事务管理器用来管理JTA事务,注意这并不表示EJB容器有管理事务的功能; 事实上也有单独的事务管理器比如开源的Tyrex. 如果只用Tomcat做应用服务器的话是不能使用JTA事务的;</P>
<P>JTA主要用于分布式的多个数据源的两阶段提交的事务,而JDBC的Connection提供的单个数据源的事务; 后者因为只涉及到一个数据源,所以其事务可以由数据库自己单独实现, 而JTA事务因为其分布式和多数据源的特性, 不可能由任何"一个"数据源实现事务, 因此JTA中的事务是由"事务管理器"实现的,它会在多个数据源之间统筹事务,具体使用的技术就是所谓的"两阶段提交", 一般JTA事务都是用于EJB中(因为EJB本身也是分布式的), 所以一般的应用服务器都有自己的事务管理器用来管理JTA事务,注意这并不表示EJB容器有管理事务的功能; 事实上也有单独的事务管理器比如开源的Tyrex. 如果只用Tomcat做应用服务器的话是不能使用JTA事务的;<BR>使用 JDBC 事务界定时，您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。在下面，我们将看一下如何用 JTA 进行事务界定。因为 JTA 不像 JDBC 那样有名，所以我们首先做一个简介。<BR>JTA 简介<BR>Java 事务 API(JTA) 及其同门兄弟 Java 事务服务(Java Transaction Service JTS)为 J2EE 平台提供了分布式事务服务。一个分布式的事务涉及一个事务管理器和一个或者多个资源管理器。一个资源管理器是任何类型的持久性的数据存储。事务管理器负责协调所有事务参与者之间的通信。<BR>JTA 事务比 JDBC 事务功能更强。JDBC 事务局限为一个数据库连接，而 JTA 事务可以有多个参与者。所有下列 Java 平台组件都可以参与 JTA 事务：<BR>JDBC 连接 <BR>JDO PersistenceManager 对象 <BR>JMS 队列 <BR>JMS 主题 <BR>企业 JavaBeans <BR>符合 J2EE 连接体系结构(J2EE Connector Architecture)规范的资源适配器。<BR></P><img src ="http://www.blogjava.net/terry-zj/aggbug/29931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-02-08 15:12 <a href="http://www.blogjava.net/terry-zj/archive/2006/02/08/29931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一篇关于session的好文（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 05 Jan 2006 09:21:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/26749.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/26749.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/26749.html</trackback:ping><description><![CDATA[<P>作者：郎云鹏（dev2dev ID: hippiewolf）</P>
<P>摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。</P>
<P>目录：<BR>一、术语session<BR>二、HTTP协议与状态保持<BR>三、理解cookie机制<BR>四、理解session机制<BR>五、理解javax.servlet.http.HttpSession<BR>六、HttpSession常见问题<BR>七、跨应用程序的session共享<BR>八、总结<BR>参考文档</P>
<P>一、术语session<BR>在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。</P>
<P>session，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。有时候我们可以看到这样的话“在一个浏览器会话期间，...”，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关闭这个期间①。最混乱的是“用户（客户端）在一次会话期间”这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从登录到选购商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义①，其中的差别只能靠上下文来推断②。</P>
<P>然而当session一词与网络协议相关联时，它又往往隐含了“面向连接”和/或“保持状态”这样两个含义，“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你并不能确认对方的地址是否正确，通信渠道不一定能建立，但对发信人来说，通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来，使得消息之间可以互相依赖，比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session”③。</P>
<P>而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构，如“把xxx保存在session里”⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决方案，比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。</P>
<P>鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。<BR>在本文中，使用中文“浏览器会话期间”来表达含义①，使用“session机制”来表达含义④，使用“session”表达含义⑤，使用具体的“HttpSession”来表达含义⑥</P>
<P>二、HTTP协议与状态保持<BR>HTTP协议本身是无状态的，这与HTTP协议本来的目的是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去的行为，每一次请求之间都是独立的，好比一个顾客和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。</P>
<P>然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。</P>
<P>让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：<BR>1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。<BR>2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。<BR>3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。</P>
<P>由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个标识，所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。</P>
<P>三、理解cookie机制 <BR>cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：“会员卡”如何分发；“会员卡”的内容；以及客户如何使用“会员卡”。</P>
<P>正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如Javascript或者VBscript也可以生成cookie。</P>
<P>而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如果某家分店还发行了自己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。</P>
<P>cookie的内容主要包括：名字，值，过期时间，路径和域。<BR>其中域可以指定某一个域比如.google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如<A href="http://www.google.com">www.google.com</A>或者froogle.google.com，可以用飘柔来做比。<BR>路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。<BR>路径与域合在一起就构成了cookie的作用范围。<BR>如果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。</P>
<P>存储在硬盘上的cookie可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。对于IE，在一个打开的窗口上按Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie；对于Mozilla Firefox0.8，所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。</P>
<P>下面就是一个goolge设置cookie的响应头的例子<BR>HTTP/1.1 302 Found<BR>Location: <A href="http://www.google.com/intl/zh-CN/">http://www.google.com/intl/zh-CN/</A><BR>Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com<BR>Content-Type: text/html</P>
<P><IMG alt="" hspace=0 src="D:\home\200562922161847.jpg" align=baseline border=0></P>
<P><BR>这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分</P>
<P><IMG alt="" hspace=0 src="D:\home\200562922167755.jpg" align=baseline border=0></P>
<P><BR>浏览器在再次访问goolge的资源时自动向外发送cookie</P>
<P>&nbsp;<IMG alt="" hspace=0 src="D:\home\2005629221613750.jpg" align=baseline border=0></P>
<P><BR>使用Firefox可以很容易的观察现有的cookie的值<BR>使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221620917.jpg" align=baseline border=0></P>
<P><BR>IE也可以设置在接受cookie前询问</P>
<P>&nbsp;<IMG alt="" hspace=0 src="D:\home\2005629221623485.jpg" align=baseline border=0></P>
<P><BR>这是一个询问接受cookie的对话框。</P>
<P>四、理解session机制<BR>session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。</P>
<P>当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个session id将被在本次响应中返回给客户端保存。</P>
<P>保存这个session id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764，它的名字就是JSESSIONID。</P>
<P>由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为<A href="http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764</A><BR>另一种是作为查询字符串附加在URL后面，表现形式为<A href="http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764</A><BR>这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。<BR>为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id。</P>
<P>另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单<BR>&lt;form name="testform" action="/xxx"&gt;<BR>&lt;input type="text"&gt;<BR>&lt;/form&gt;<BR>在被传递给客户端之前将被改写成<BR>&lt;form name="testform" action="/xxx"&gt;<BR>&lt;input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"&gt;<BR>&lt;input type="text"&gt;<BR>&lt;/form&gt;<BR>这种技术现在已较少应用，笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。<BR>实际上这种技术可以简单的用对action应用URL重写来代替。</P>
<P>在谈论session机制的时候，常常听到这样一种误解“只要关闭浏览器，session就消失了”。其实可以想象一下会员卡的例子，除非顾客主动对店家提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保留，程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个session id就消失了，再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session。</P>
<P>恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。</P>
<P>五、理解javax.servlet.http.HttpSession<BR>HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。</P>
<P>首先，Weblogic Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域，cookie的生存时间等。</P>
<P>一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的持久化特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用，Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。</P>
<P>复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。</P>
<P>cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。</P>
<P>cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。</P>
<P>关于session的设置参考[5] <A href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869">http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</A></P>
<P>六、HttpSession常见问题<BR>（在本小节中session的含义为⑤和⑥的混合）</P>
<P><BR>1、session在何时被创建<BR>一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建，注意如果JSP没有显示的使用 &lt;<A href="mailto:%@page">%@page</A> session="false"%&gt; 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。</P>
<P>由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。</P>
<P>2、session何时被删除<BR>综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止（非持久session）</P>
<P>3、如何做到在浏览器关闭时删除session<BR>严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。</P>
<P>4、有个HttpSessionListener是怎么回事<BR>你可以创建这样的listener去监控session的创建和销毁事件，使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener，而不是相反。类似的与HttpSession有关的listener还有HttpSessionBindingListener，HttpSessionActivationListener和HttpSessionAttributeListener。</P>
<P>5、存放在session中的对象必须是可序列化的吗<BR>不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象，在session销毁时会有一个Exception，很奇怪。</P>
<P>6、如何才能正确的应付客户端禁止cookie的可能性<BR>对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6]<BR><A href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770">http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</A></P>
<P>7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session<BR>参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。</P>
<P>8、如何防止用户打开两个浏览器窗口操作导致的session混乱<BR>这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改操作，这样就可以不用设置。</P>
<P>9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue<BR>做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变，需要向其他服务器进程复制新的session值。</P>
<P>10、为什么session不见了<BR>排除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在iPlanet6SP1加若干补丁的Solaris版本上倒也遇到过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。<BR>出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。</P>
<P>七、跨应用程序的session共享</P>
<P>常常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个小项目之间需要共享一些信息，或者想使用session来实现SSO(single sign on)，在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session。</P>
<P>然而按照Servlet规范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。</P>
<P>首先来看一下Tomcat是如何实现web应用程序之间session的隔离的，从Tomcat设置的cookie路径来看，它对不同的应用程序设置的cookie路径是不同的，这样不同的应用程序所用的session id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221626822.jpg" align=baseline border=0><BR>&nbsp; </P>
<P>根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221626479.jpg" align=baseline border=0><BR>&nbsp;</P>
<P>笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很简单，实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id。</P>
<P>iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。<BR>&lt;session-info&gt;<BR>&lt;path&gt;/NASApp&lt;/path&gt;<BR>&lt;/session-info&gt;</P>
<P>需要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得setAttribute("name", "neo")变成setAttribute("app1.name", "neo")，以防止命名空间冲突，导致互相覆盖。</P>
<P><BR>在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session。对于版本4以上的Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段。</P>
<P>我们再看一下Weblogic Server是如何处理session的。</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221630550.jpg" align=baseline border=0><BR>&nbsp; </P>
<P>从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下</P>
<P><IMG alt="" hspace=0 src="D:\home\2005629221630874.jpg" align=baseline border=0><BR>&nbsp;</P>
<P>对于这样一种结构，在session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到ServletContext中，这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，</P>
<P>应用程序A<BR>context.setAttribute("appA", session); </P>
<P>应用程序B<BR>contextA = context.getContext("/appA");<BR>HttpSession sessionA = (HttpSession)contextA.getAttribute("appA"); </P>
<P>值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值，以上做法在Weblogic Server 8.1中通过。</P>
<P>那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA访问另外一个应用程序会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户信息也会丢失。注意做这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过session来实现的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。</P>
<P>八、总结<BR>session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。</P>
<P>关于作者：<BR>郎云鹏（dev2dev ID: hippiewolf），软件工程师，从事J2EE开发<BR>电子邮件：<A href="mailto:langyunpeng@yahoo.com.cn">langyunpeng@yahoo.com.cn</A><BR>地址：大连软件园路31号科技大厦A座大连博涵咨询服务有限公司</P>
<P>参考文档：<BR>[1] Preliminary Specification <A href="http://wp.netscape.com/newsref/std/cookie_spec.html">http://wp.netscape.com/newsref/std/cookie_spec.html</A><BR>[2] RFC2109 <A href="http://www.rfc-editor.org/rfc/rfc2109.txt">http://www.rfc-editor.org/rfc/rfc2109.txt</A><BR>[3] RFC2965 <A href="http://www.rfc-editor.org/rfc/rfc2965.txt">http://www.rfc-editor.org/rfc/rfc2965.txt</A><BR>[4] The Unofficial Cookie FAQ <A href="http://www.cookiecentral.com/faq/">http://www.cookiecentral.com/faq/</A><BR>[5] <A href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869">http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</A><BR>[6] <A href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770">http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</A><BR>[7] RFC2616 <A href="http://www.rfc-editor.org/rfc/rfc2616.txt">http://www.rfc-editor.org/rfc/rfc2616.txt</A></P>
<P><BR>代码下载：<A href="http://dev2dev.bea.com.cn/images/paihang_article/041020/sampleApp.zip">http://dev2dev.bea.com.cn/images/paihang_article/041020/sampleApp.zip</A><BR><BR>转载地址：<A href="http://www.supcode.com/Article/html/4/43/2005/06/29/216335472190.shtml">http://www.supcode.com/Article/html/4/43/2005/06/29/216335472190.shtml</A></P><img src ="http://www.blogjava.net/terry-zj/aggbug/26749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2006-01-05 17:21 <a href="http://www.blogjava.net/terry-zj/archive/2006/01/05/26749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>不设置JAVA_HOME环境变量 启动Tomcat</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/30/26026.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 30 Dec 2005 03:32:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/30/26026.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/26026.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/30/26026.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/26026.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/26026.html</trackback:ping><description><![CDATA[不设置JAVA_HOME环境变量 启动Tomcat<BR><BR>例如:Tomcat安装在D:\jakarta-tomcat-5.5.9<BR>步骤1：把JDK&nbsp; j2sdk1.4.2_08 copy 到Tomcat的安装目录下&nbsp;<BR>&nbsp; D:\jakarta-tomcat-5.5.9\j2sdk1.4.2_08<BR>步骤2：在D:\jakarta-tomcat-5.5.9\bin目录下设置statup.bat和shutdown.bat <BR>set JAVA_HOME=%CATALINA_HOME%\j2sdk1.4.2_08&nbsp; <BR>注意位置 必须在CATALINA_HOME赋值后<img src ="http://www.blogjava.net/terry-zj/aggbug/26026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-30 11:32 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/30/26026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让Java程序自带JRE（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 30 Dec 2005 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/26023.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/26023.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/26023.html</trackback:ping><description><![CDATA[<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用Java开发程序，发布时总要考虑的问题就是怎么在使用者的机器上装好JRE。要考虑的问题很多：使用者有没有能力独自安装JRE，<BR>使用者已有的JRE和我们需要的版本是不是一致，会不会出现版本问题，等等。使用.NET要考虑的问题就少些。现在.NET CLR似乎已经很普及<BR>了，看好多D版的Win XP都会自己安装最新的.NET CLR，而且似乎它的安装界面也比JRE友好些。彻底解决安装JRE的问题的方案，就是让我<BR>们的应用程序自己背着JRE！这样，我们的程序就像传统的Win32应用程序一样，双击就可以执行，不用管所在的机器上是否有JRE，是什么版<BR>本的JRE，无论怎样，我有我自己的！要做到这一点，其实非常容易。</FONT></P>
<P><BR><FONT size=2>王森在他的《Java深度历险》（强力推荐这本书，内容少而精）的第一章就解释了JDK，JRE，JVM之间的关系。解释了我们执行java.exe时<BR>发生的事情。其中提到，java.exe依照一套逻辑来寻找可以用的JRE，首先查找自己�诘哪柯枷掠忻挥蠮RE（据王森讲这样说不确切，我没有<BR>JDK全部的源代码，在此无从考证）；其次查找自己的父目录下有没有JRE；最后才是查询Windows的注册表。</FONT></P>
<P><BR><FONT size=2>通常我们在安装好了JRE的机器上的任何一个目录下都可以执行java.exe。因为它在安装时被复制到了windows的system32目录下，而后者<BR>无论如何都会在path环境变量中。这个java.exe最终必然会访问注册表来确定真正的JRE的所在地。若我们要求每一个应用程序都自带JRE，<BR>必然不能走这条路。但，逻辑的第二条讲，java.exe会在它的父目录下查找JRE，解决方案就在这一条中。</FONT></P>
<P><BR><FONT size=2>假设我们的应用程序打好了包，叫做MyApp.jar，放在MyApp的目录下。我们在MyApp目录下，可以执行java –jar MyApp.jar来运行我们<BR>的程序。我们安装的是JRE 1.5，在C:\Program Files\Java\jre1.5.0下。现在，我们只需要简单的将jre1.5.0目录搬到MyApp目录下，顺<BR>便改个容易写的名字比如叫jre。现在，我们的应用程序就象这样：</FONT></P>
<P><FONT size=2>MyApp</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyApp.jar</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jre</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jre1.5.0目录下的全部内容</FONT></P>
<P><FONT size=2>Java.exe就在jre目录下的bin目录中。根据第二条逻辑，java.exe会在它的父目录中查找jre，实验证实，它会查找lib目录，而lib就在jre目<BR>录下。因此，这样java.exe就会确定jre的所在然后正常执行java程序，不会去管我们是否安装了JRE，注册表中是否有注册项这些杂事了。</FONT></P>
<P><FONT size=2>试一下，在命令行下进入MyApp的目录下，假设它在C盘，将path指向MyApp下的JRE：</FONT></P>
<P><FONT size=2>set path=c:\MyApp\jre\bin</FONT></P>
<P><FONT size=2>然后运行：</FONT></P>
<P><FONT size=2>java –verbose –jar MyApp.jar</FONT></P>
<P><FONT size=2>加上verbose参数以确定我们确实用了这一套被搬出了家的JRE。</FONT></P>
<P><FONT size=2>程序可以运行，并且在命令行输出的前几行，可以看到：</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\rt.jar]</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\jsse.jar]</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\jce.jar]</FONT></P>
<P><FONT size=2>[Opened C:\MyApp\jre\lib\charsets.jar]</FONT></P>
<P><FONT size=2>因此程序读取的确实是它的私有的JRE。</FONT></P>
<P><FONT size=2>至此，我们似乎完成了任务。但是现在我们的私有JRE仍不完美，缺点是太大。JRE 1.5有接近70MB，作为我们的私有的JRE，好多内容都是<BR>可以抛弃的。Jre目录下的license都可以不要，bin下的执行文件只需要保留java.exe或者javaw.exe，lib下只要保留<BR>rt，jsse，jce，charsets几个库就可以了。除了i386和zi两个子目录外，其余的子目录都可以不要。Zi下只需要保留自己地区的子目录和其下<BR>的一些文件就可以。Lib下除了库之外的属性文件等等都要保留。这样清理一番，JRE仍然有接近50MB。还可以继续清理几个库文件里面不需<BR>要的内容，这需要仔细的整理，会很费功夫。最好能写出一个自动工具帮助我们整理它们。从Sun公司上下到的JMF里面附带的用Java写的媒<BR>体播放器就自带了JRE，只有几个MB。</FONT></P>
<P><BR><FONT size=2>清理过后需要运行几遍我们的应用程序，以确保我们的JRE不缺少东西。</FONT></P>
<P><FONT size=2>如果我们希望能有一个程序直接启动我们的应用程序，那就还要费些功夫。最简单的方法是弄出一个快捷方式来，但是快捷方式的路径不能是相<BR>对的，不方便我们安装。我想到的方案就是用Win32程序包装一下。在VS.NET下写一个Win32小程序：</FONT></P>
<P><FONT size=2>int PASCAL WinMain( HINSTANCE hInstance,</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; HINSTANCE hPrevInstance,</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; LPSTR lpszCmdLine,</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; int nCmdShow )</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; STARTUPINFO si;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; PROCESS_INFORMATION pi;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; ZeroMemory( &amp;si, sizeof(si) );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; si.cb = sizeof(si);</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; ZeroMemory( &amp;pi, sizeof(pi) );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; // Start the child process. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; if( !CreateProcess( "jre\\bin\\javaw.exe",//执行的程序名</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "jre\\bin\\javaw.exe -jar MyApp.jar", // 带参数的执行程序</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Process handle not inheritable. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Thread handle not inheritable. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FALSE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Set handle inheritance to FALSE. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // No creation flags. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use parent’s environment block. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use parent’s starting directory. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;si,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Pointer to STARTUPINFO structure.</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;pi )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Pointer to PROCESS_INFORMATION structure.</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; ) </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ErrorExit( "CreateProcess failed." );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; // Wait until child process exits.</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; WaitForSingleObject( pi.hProcess, INFINITE );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; // Close process and thread handles. </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; CloseHandle( pi.hProcess );</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; CloseHandle( pi.hThread );</FONT></P>
<P><FONT size=2>}</FONT></P>
<P><FONT size=2>基本上是按照MSDN文档中的例子照搬的。将它编译成一个EXE文件，我们的任务才全部完成。双击这个EXE文件，我们的程序启动了，看起来<BR>和传统的Win32程序没有两样，JRE完全被隐藏在底层。<BR><BR>转载地址&nbsp;</FONT><A href="http://www.matrix.org.cn/resource/article/44/44085_java.html"><FONT size=2>http://www.matrix.org.cn/resource/article/44/44085_java.html</FONT></A><BR></P><img src ="http://www.blogjava.net/terry-zj/aggbug/26023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-30 11:23 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/30/26023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>介绍struts的新特性:Lazy ActionForm（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 09 Dec 2005 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/23090.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/23090.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/23090.html</trackback:ping><description><![CDATA[
		<span class="postbody">
				<font size="2">
						<span style="FONT-WEIGHT: bold">STRUTS的 ActionForm到现在为止,出现了最少三种方式</span>: 普通的,动态的和懒的. <br /><br />所以你在你自已的开发中,可以有很多选择,如果你安全第一,可以用普通的.如果你更喜欢XML,则用动态的. <br /><br />如果你很懒,那就用Lazy ActionForm.  available in Version 1.2.6 onwards<br /><br />STRUTS提供的这三种ActionForm方式,要实际应用中你只要选择一种就可以了. <br /><br /><span style="FONT-WEIGHT: bold">下面说说Lazy ActionForm: </span><br /><br />如果你喜欢STRUTS的强大的功能的特性(就比如这个ActionForm有多种选择),又喜欢快捷, Lazy ActionForm对你来说是一个好消息. 这个有点类似于WW2中值得称道的一个特性,可以减少编写ActionForm的麻烦.(STRUTS正在把WW2中好的东西都吸收进来了,难怪这两个东西以后会合并为STRUTS IT). <br /><br />示例代码如下: <br /><br />struts-config.xml配置</font>
		</span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>
												</b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New',Courier,monospace">
												<font size="2">&lt;struts-config&gt; <br /><br />  &lt;form-beans&gt; <br />     &lt;form-bean name="lazyForm" type="org.<span style="COLOR: rgb(0,0,0)">apache</span>.<span style="COLOR: rgb(0,0,0)">struts</span>.<span style="COLOR: rgb(0,0,0)">validator</span>.<span style="COLOR: rgb(0,0,0)">LazyValidatorForm</span>"/&gt; <br />  &lt;/form-beans&gt; <br /><br />  &lt;action-mappings&gt; <br />    &lt;action path="/myActionPath" type="myPackage.<span style="COLOR: rgb(0,0,0)">MyAction</span>" name="lazyForm" validate="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />  &lt;/action-mappings&gt; <br /><br />&lt;/struts-config&gt; <br /></font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<font size="2">JSP网页 <br /></font>
		</span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>
														<font size="2">
														</font>
												</b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New',Courier,monospace">
												<font size="2">&lt;html:form action="/myActionPath"&gt; <br /><br />  &lt;h2&gt;Simple Property Example&lt;/h2&gt; <br />          <br />          Customer <span style="COLOR: rgb(170,170,221)">Number</span>: &lt;html:text property="custNo"/&gt; <br />          Customer <span style="COLOR: rgb(170,170,221)">Name</span>:   &lt;html:text property="custName"/&gt; <br /><br />  &lt;h2&gt;Mapped Property Example&lt;/h2&gt; <br />          <br />          Street:  &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>street<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br />          Town:    &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>town<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br />          State:   &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>state<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br />          Country: &lt;html:text property="address<span style="COLOR: rgb(0,0,0)">(</span>country<span style="COLOR: rgb(0,0,0)">)</span>"/&gt; <br /><br />  &lt;h2&gt;Indexed Property Example&lt;/h2&gt; <br />          <br />  &lt;logic:iterate id="products" property="products"&gt; <br />    Product Code:&lt;html:text name="products" property="code" indexed="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />    Product Description:&lt;html:text name="products" property="description" indexed="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />    Product Price:&lt;html:text name="products" property="price" indexed="<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">true</span>"/&gt; <br />  &lt;/logic:iterate&gt; <br /><br />&lt;/html:form&gt; <br /></font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<font size="2">action调用 <br /></font>
		</span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>
														<font size="2">java代码: </font>
												</b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New',Courier,monospace">
												<font size="2">
														<span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">public</span> ActionForward execute<span style="COLOR: rgb(0,0,0)">(</span>ActionMapping mapping, <br />                                 ActionForm form, <br />                                 HttpServeletRequest request, <br />                                 HttpServletResponse response<span style="COLOR: rgb(0,0,0)">)</span><span style="FONT-WEIGHT: bold; COLOR: rgb(153,0,102)">throws</span><span style="COLOR: rgb(170,170,221)">Exception</span><span style="COLOR: rgb(0,0,0)">{</span> <br />    <span style="COLOR: rgb(102,102,255)">// Cast form to DynaBean</span> <br />    DynaBean dynaForm = <span style="COLOR: rgb(0,0,0)">(</span>DynaBean<span style="COLOR: rgb(0,0,0)">)</span>form; <br /><br />    <span style="COLOR: rgb(102,102,255)">// Use the DynaBean</span> <br />    <span style="COLOR: rgb(170,170,221)">String</span> custNo = <span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(170,170,221)">String</span><span style="COLOR: rgb(0,0,0)">)</span>dynaForm.<span style="COLOR: rgb(0,0,0)">get</span><span style="COLOR: rgb(0,0,0)">(</span>"custNo"<span style="COLOR: rgb(0,0,0)">)</span>;   <span style="COLOR: rgb(102,102,255)">// simple</span> <br />    <span style="COLOR: rgb(170,170,221)">Map</span> address   = <span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(170,170,221)">Map</span><span style="COLOR: rgb(0,0,0)">)</span>dynaForm.<span style="COLOR: rgb(0,0,0)">get</span><span style="COLOR: rgb(0,0,0)">(</span>"address"<span style="COLOR: rgb(0,0,0)">)</span>;     <span style="COLOR: rgb(102,102,255)">// mapped</span> <br />    <span style="COLOR: rgb(170,170,221)">List</span> products = <span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(170,170,221)">List</span><span style="COLOR: rgb(0,0,0)">)</span>dynaForm.<span style="COLOR: rgb(0,0,0)">get</span><span style="COLOR: rgb(0,0,0)">(</span>"products"<span style="COLOR: rgb(0,0,0)">)</span>;   <span style="COLOR: rgb(102,102,255)">// indexed  </span><br />    //... <span style="COLOR: rgb(0,0,0)">etc</span><br /><span style="COLOR: rgb(0,0,0)">}</span><br /></font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<font size="2">在ACTION中,你可以使用 BeanUtils 1.7.0的特性,把dynaForm一次性拷贝到HIBERNATE的POJO中去!<br /><br />转载地址：http://forum.javaeye.com/viewtopic.php?t=17441<br /></font>
		</span>
<img src ="http://www.blogjava.net/terry-zj/aggbug/23090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-09 10:43 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/09/23090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java抽取word,pdf的四种武器(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Wed, 07 Dec 2005 06:40:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22856.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22856.html</trackback:ping><description><![CDATA[<DIV id=articleview_summary>摘要：<BR><BR>转载：转载请保留本信息，本文来自<A href="http://www.matrix.org.cn/resource/article/0/120.html">http://www.matrix.org.cn/resource/article/0/120.html</A> </DIV>
<DIV id=divarticlecontent>很多人问到如何抽取word，excel，pdf阿。这里我总结一下抽取word,pdf的<BR>几种方法。<BR><SPAN style="COLOR: red">1。用jacob.</SPAN><BR>其实jacob是一个bridage，连接java和com或者win32函数的一个中间件，jacob并不能直接抽取word,excel等文件，需要自己写dll哦，不过已经有为你写好的了，就是jacob的作者一并提供了。<BR>jacob下载：http://www.matrix.org.cn/down_view.asp?id=13<BR>下载了jacob并放到指定的路径之后(dll放到path,jar文件放到classpath)，就可以写你自己的抽取程序了，下面是一个例子：<BR>import java.io.File;<BR>import com.jacob.com.*;<BR>import com.jacob.activeX.*;<BR><BR>public class FileExtracter{<BR><BR>public static void main(String[] args) {<BR><BR>ActiveXComponent app = new ActiveXComponent("Word.Application");<BR>String inFile = "c:\\test.doc";<BR>String tpFile = "c:\\temp.htm";<BR>String otFile = "c:\\temp.xml";<BR>boolean flag = false;<BR>try {<BR>app.setProperty("Visible", new Variant(false));<BR>Object docs = app.getProperty("Documents").toDispatch();<BR>Object doc = Dispatch.invoke(docs,"Open", Dispatch.Method, new Object[]{inFile,new Variant(false), new Variant(true)}, new int[1]).toDispatch();<BR>Dispatch.invoke(doc,"SaveAs", Dispatch.Method, new Object[]{tpFile,new Variant(8)}, new int[1]);<BR>Variant f = new Variant(false);<BR>Dispatch.call(doc, "Close", f);<BR>flag = true;<BR>} catch (Exception e) {<BR>e.printStackTrace();<BR>} finally {<BR>app.invoke("Quit", new Variant[] {});<BR>}<BR><BR>}<BR>}<BR><SPAN style="COLOR: red">2。用apache的poi来抽取word，excel。</SPAN><BR>poi是apache的一个项目，不过就算用poi你可能都觉得很烦，不过不要紧，这里提供了更加简单的一个接口给你：<BR>下载经过封装后的poi包：http://www.matrix.org.cn/down_view.asp?id=14<BR>下载之后，放到你的classpath就可以了，下面是如何使用它的一个例子：<BR>import java.io.*;<BR>import org.textmining.text.extraction.WordExtractor;<BR>/**<BR>* &lt;p&gt;Title: pdf extraction&lt;/p&gt;<BR>* &lt;p&gt;Description: email:chris@matrix.org.cn&lt;/p&gt;<BR>* &lt;p&gt;Copyright: Matrix Copyright (c) 2003&lt;/p&gt;<BR>* &lt;p&gt;Company: Matrix.org.cn&lt;/p&gt;<BR>* @author chris<BR>* @version 1.0,who use this example pls remain the declare<BR>*/<BR><BR>public class PdfExtractor {<BR>public PdfExtractor() {<BR>}<BR>public static void main(String args[]) throws Exception<BR>{<BR>FileInputStream in = new FileInputStream ("c:\\a.doc");<BR>WordExtractor extractor = new WordExtractor();<BR>String str = extractor.extractText(in);<BR>System.out.println("the result length is"+str.length());<BR>System.out.println("the result is"+str);<BR>}<BR>}<BR><BR><SPAN style="COLOR: red">3。pdfbox-用来抽取pdf文件</SPAN><BR>但是pdfbox对中文支持还不好，先下载pdfbox：http://www.matrix.org.cn/down_view.asp?id=12<BR>下面是一个如何使用pdfbox抽取pdf文件的例子：<BR>import org.pdfbox.pdmodel.PDDocument;<BR>import org.pdfbox.pdfparser.PDFParser;<BR>import java.io.*;<BR>import org.pdfbox.util.PDFTextStripper;<BR>import java.util.Date;<BR>/**<BR>* &lt;p&gt;Title: pdf extraction&lt;/p&gt;<BR>* &lt;p&gt;Description: email:chris@matrix.org.cn&lt;/p&gt;<BR>* &lt;p&gt;Copyright: Matrix Copyright (c) 2003&lt;/p&gt;<BR>* &lt;p&gt;Company: Matrix.org.cn&lt;/p&gt;<BR>* @author chris<BR>* @version 1.0,who use this example pls remain the declare<BR>*/<BR><BR>public class PdfExtracter{<BR><BR>public PdfExtracter(){<BR>}<BR>public String GetTextFromPdf(String filename) throws Exception<BR>{<BR>String temp=null;<BR>PDDocument pdfdocument=null;<BR>FileInputStream is=new FileInputStream(filename);<BR>PDFParser parser = new PDFParser( is );<BR>parser.parse();<BR>pdfdocument = parser.getPDDocument();<BR>ByteArrayOutputStream out = new ByteArrayOutputStream();<BR>OutputStreamWriter writer = new OutputStreamWriter( out );<BR>PDFTextStripper stripper = new PDFTextStripper();<BR>stripper.writeText(pdfdocument.getDocument(), writer );<BR>writer.close();<BR>byte[] contents = out.toByteArray();<BR><BR>String ts=new String(contents);<BR>System.out.println("the string length is"+contents.length+"\n");<BR>return ts;<BR>}<BR>public static void main(String args[])<BR>{<BR>PdfExtracter pf=new PdfExtracter();<BR>PDDocument pdfDocument = null;<BR><BR>try{<BR>String ts=pf.GetTextFromPdf("c:\\a.pdf");<BR>System.out.println(ts);<BR>}<BR>catch(Exception e)<BR>{<BR>e.printStackTrace();<BR>}<BR>}<BR><BR>}<BR><BR><SPAN style="COLOR: red">4.抽取支持中文的pdf文件－xpdf</SPAN><BR>xpdf是一个开源项目，我们可以调用他的本地方法来实现抽取中文pdf文件。<BR>下载xpdf函数包：http://www.matrix.org.cn/down_view.asp?id=15<BR>同时需要下载支持中文的补丁包：http://www.matrix.org.cn/down_view.asp?id=16<BR>按照readme放好中文的patch，就可以开始写调用本地方法的java程序了<BR>下面是一个如何调用的例子：<BR>import java.io.*;<BR>/**<BR>* &lt;p&gt;Title: pdf extraction&lt;/p&gt;<BR>* &lt;p&gt;Description: email:chris@matrix.org.cn&lt;/p&gt;<BR>* &lt;p&gt;Copyright: Matrix Copyright (c) 2003&lt;/p&gt;<BR>* &lt;p&gt;Company: Matrix.org.cn&lt;/p&gt;<BR>* @author chris<BR>* @version 1.0,who use this example pls remain the declare<BR>*/<BR><BR><BR>public class PdfWin {<BR>public PdfWin() {<BR>}<BR>public static void main(String args[]) throws Exception<BR>{<BR>String PATH_TO_XPDF="C:\\Program Files\\xpdf\\pdftotext.exe";<BR>String filename="c:\\a.pdf";<BR>String[] cmd = new String[] { PATH_TO_XPDF, "-enc", "UTF-8", "-q", filename, "-"};<BR>Process p = Runtime.getRuntime().exec(cmd);<BR>BufferedInputStream bis = new BufferedInputStream(p.getInputStream());<BR>InputStreamReader reader = new InputStreamReader(bis, "UTF-8");<BR>StringWriter out = new StringWriter();<BR>char [] buf = new char[10000];<BR>int len;<BR>while((len = reader.read(buf))&gt;= 0) {<BR>//out.write(buf, 0, len);<BR>System.out.println("the length is"+len);<BR>}<BR>reader.close();<BR>String ts=new String(buf);<BR>System.out.println("the str is"+ts);<BR>}<BR>}<BR></DIV><img src ="http://www.blogjava.net/terry-zj/aggbug/22856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-07 14:40 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/07/22856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts1.0.2中上传文件功能的Bug</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/05/22514.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Dec 2005 02:47:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/05/22514.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22514.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/05/22514.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22514.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22514.html</trackback:ping><description><![CDATA[<P>Struts1.0.2中上传文件功能的Bug(日文文件名有时不能完整表示) <BR>&nbsp;<BR>struts1.0.2中解析"multipart/form-data"型的request时没有根据request.getCharacterEncoding()的结果来解码.<BR>当截取filename时就可能丢失一些字符.比如文件名为"ソウス.xls" </P>
<P>RequestUtil.java&nbsp; <BR>&nbsp;&nbsp;&nbsp; public static void populate(Object bean, String prefix, String suffix,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletRequest request)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws ServletException {<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //initialize a MultipartRequestHandler<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MultipartRequestHandler multipart = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String multipartClass = (String)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.getAttribute(Action.MULTIPART_KEY);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.removeAttribute(Action.MULTIPART_KEY);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//在这里取处理MultipartRequest的类<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; multipart = (MultipartRequestHandler) Class.forName(multipartClass).newInstance();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp; // 自定义一个DiskMultipartRequestHandlerX<BR><BR>&nbsp;&nbsp;&nbsp; ActionServlet.java<BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * The MultipartRequestHandler class name used for handling<BR>&nbsp;&nbsp;&nbsp;&nbsp; * multipart form requests.&nbsp; This is the global default value,<BR>&nbsp;&nbsp;&nbsp;&nbsp; * the handler can also be set in individual mapping entries<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; protected String multipartClass = "org.apache.struts.upload.DiskMultipartRequestHandler";<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; public class DefaultActionServlet extends ActionServlet {<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void process(HttpServletRequest request,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletResponse response) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String contentType = request.getContentType();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String method = request.getMethod();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //if this is a multipart request, wrap the HttpServletRequest object<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //with a MultipartRequestWrapper to keep the process sub-methods<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //from failing when checking for certain request parameters<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //for command tokens and cancel button detection<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((contentType != null) &amp;&amp; (contentType.startsWith("multipart/form-data"))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; (method.equals("POST"))) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //request.getAttribute(Action.MULTIPART_KEY);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 设置处理MultipartRequest的类，也可以在struts-config.xml中设置。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.setAttribute(Action.MULTIPART_KEY, "com.struts.upload.DiskMultipartRequestHandlerX");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.setCharacterEncoding("Shift_JIS");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.process(request, response);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch(Exception e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log.error("encode error: ", e);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR></P>
<P>这个问题在struts1.1中得到了解决.</P><img src ="http://www.blogjava.net/terry-zj/aggbug/22514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-05 10:47 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/05/22514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串中的正则表达式特殊符号(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Dec 2005 02:31:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22509.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22509.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22509.html</trackback:ping><description><![CDATA[<font size="2">字符串中的正则表达式特殊符号 <br><br>问题：<br>String s1="111+222+333";<br>System.out.println(s1.split("+").length);<br>//输出时提示错误：<br>java.util.regex.PatternSyntaxException: Dangling meta character '+' near index<br>问题出现在加号附近，查询相关的资料显示，+、*、|、\等符号在正则表达示中有相应的不同意义。<br><br>正则表达式的基本用法 zt &nbsp;&nbsp; &nbsp;<br>1、“.”为通配符，表示任何一个字符，例如：“a.c”可以匹配“anc”、“abc”、“acc”；<br>2、“[]”，在[]内可以指定要求匹配的字符，例如：“a[nbc]c”可以匹配“anc”、“abc”、“acc；<br>但不可以匹配“ancc”,a到z可以写成[a-z],0到9可以写成[0-9];<br><br>3、数量限定符号，表示匹配次数（或者叫做长度）的符号：<br><br>包括：“*”——0次或者多次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “+”——1次或者多次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “?”——0次或者1次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{n}”——匹配n次，n为整数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{n,m}”——匹配从n到m之间的某个数的次数；n和m都是整数；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{n,}”——匹配n到无穷次之间任意次数；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “{,m}”——匹配0到m之间任意次数；<br>他们放到匹配格式的后面：<br>例如：<br>电话号码：024－84820482，02484820482(假设前面3或者4位，后面7或者8位，并且中间的减号可有可无)<br><br>都是符合规定的，那么可以用如下格式来匹配：[0-9]{3,4} \-? [0-9]{7,8}；<br>注意：“\”为转义字符，因为“-”在正则表达式用有代表一个范围的意义，例如：前面所说的[0-9]，<br>所以它需要转义字符“\”进行转义才可使用；<br><br>4、“^”为否符号，表示不想匹配的符号，例如：[^z][a-z]+可以匹配所有除“z”开头的以外的所有字<br><br>符串（长度大于2，因为“+”表示大于等于1的次数，从第二位开始都是小写英文字符）；<br>如果^放到[]的外边则表示以[]开头的字符串；^[az][a-z]+表示a或者z开头的长度大于等于2的英文字符串；<br><br>5、“|”或运算符，例如：a[n|bc|cb]c可以匹配“abcc”,“anc”,“acbc”；<br>6、“$”以它前面的字符结尾的；例如：ab+$就可以被“abb”，“ab”匹配；<br><br>7、一些简单表示方法：<br>\d表示[0-9];\D表示[^0-9];\w表示[A-Z0-9];\W表示[^A-Z0-9];\s表示[\t\n\r\f],就是空格字符包括tab，空格等等;\S表示[^\t\n\r\f]，就是非空格字符;<br><br><br>明白了这些以后，我们再返回头看看它们如何被运用呢？一般来讲只需要加[]、或是\\即可。<br><br>举例来讲：<br>String s1="111+222+333";<br>System.out.println(s1.split("[+]").length);<br>或是<br>String s1="111+222+333";<br>System.out.println(s1.split("\\+").length);<br><br>其他用法类同。</font><img src ="http://www.blogjava.net/terry-zj/aggbug/22509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-05 10:31 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/05/22509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HttpSessionListener的用法</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/05/22508.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Dec 2005 02:28:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/05/22508.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22508.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/05/22508.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22508.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22508.html</trackback:ping><description><![CDATA[<font size="2">HttpSessionListener的用法 <br>&nbsp;<br>参考 http://www.javaroad.jp/servletjsp/sj_servlet9.htm<br><br>继承HttpSessionListener接口的类，来监听Session创建和销毁的事件<br>package jp.co.sysmex.sps.util;<br><br>import javax.servlet.*;<br>import javax.servlet.http.*;<br>import jp.co.sysmex.sps.app.web.WebAccountBean;<br><br>//①HttpSessionListener 接口的实现。<br>public class CheckSessionServlet implements HttpSessionListener {<br>&nbsp;&nbsp;&nbsp; private static int sesCount = 0;<br><br>&nbsp;&nbsp;&nbsp; //②session生成时触发sessionCreated方法<br>&nbsp;&nbsp;&nbsp; public void sessionCreated(HttpSessionEvent hse) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sesCount++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //ServletContext sc = hse.getSession().getServletContext();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sessid = hse.getSession().getId();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" session Created " + sesCount);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" session ++ " + sessid);<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; //③session无效时触发sessionDestroyed方法<br>&nbsp;&nbsp;&nbsp; //此时session中的内容还可以正常取道<br>&nbsp;&nbsp;&nbsp; public void sessionDestroyed(HttpSessionEvent hse) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sessid = hse.getSession().getId();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" session Destroyed " + sesCount);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" session -- " + sessid);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebAccountBean account =&nbsp; (WebAccountBean)(hse.getSession().getAttribute("ACCOUNT_KEY"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(account.getEnterpriseCode());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(account.getEnterpriseFullKanjiName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sesCount--;<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>web.xml文件中增加配置信息.<br>　&lt;listener&gt; <br>　　 &lt;listener-class&gt;jp.co.sysmex.sps.util.CheckSessionServlet&lt;/listener-class&gt;<br>　&lt;/listener&gt; <br><br>&nbsp;<br>&nbsp;<br><br></font><img src ="http://www.blogjava.net/terry-zj/aggbug/22508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-05 10:28 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/05/22508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Calendar使用方法（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 05 Dec 2005 02:15:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22506.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22506.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22506.html</trackback:ping><description><![CDATA[<font size="2">明海棠文集之日期时间1.0<br><br>--------它不是原创，是一种思念<br><br>Java 语言的Calendar，GregorianCalendar (日历),Date(日期), 和DateFormat(日期格式)组成了Java标准的一个基本但是非常重要的部分. 日期是商业逻辑计算一个关键的部分. 所有的开发者都应该能够计算未来的日期, 定制日期的显示格式, 并将文本数据解析成日期对象。学习日期, 日期格式, 日期的解析和日期的计算。 <br><br>我们将讨论下面的类: <br><br>1、&nbsp; 具体类(和抽象类相对)java.util.Date <br><br>2、&nbsp; 抽象类java.text.DateFormat 和它的一个具体子类,java.text.SimpleDateFormat <br><br>3、&nbsp; 抽象类java.util.Calendar 和它的一个具体子类,java.util.GregorianCalendar <br><br>具体类可以被实例化, 但是抽象类却不能. 你首先必须实现抽象类的一个具体子类.<br><br>1.&nbsp;&nbsp; java.util.Date及其格式化<br>Date 类从Java 开发包(JDK) 1.0 就开始进化, 当时它只包含了几个取得或者设置一个日期数据的各个部分的方法, 比如说月, 日, 和年. 这些方法现在遭到了批评并且已经被转移到了Calendar类里去了, 我们将在本文中进一步讨论它. 这种改进旨在更好的处理日期数据的国际化格式. 就象在JDK 1.1中一样, Date 类实际上只是一个包裹类, 它包含的是一个长整型数据, 表示的是从GMT(格林尼治标准时间)1970年, 1 月 1日00:00:00这一刻之前或者是之后经历的毫秒数. <br><br>1.1. 创建java.util.Date<br>Java统计从1970年1月1日起的毫秒的数量表示日期。也就是说，例如，1970年1月2日，是在1月1日后的86，400，000毫秒。同样的，1969年12月31日是在1970年1月1日前86，400，000毫秒。Java的Date类使用long类型纪录这些毫秒值.因为long是有符号整数，所以日期可以在1970年1月1日之前，也可以在这之后。Long类型表示的最大正值和最大负值可以轻松的表示290，000，000年的时间，这适合大多数人的时间要求。<br><br>让我们看一个使用系统的当前日期和时间创建一个日期对象并返回一个长整数的简单例子. 这个时间通常被称为Java 虚拟机(JVM)主机环境的系统时间. <br>import java.util.Date; <br><br>public class DateExample1 { <br><br>public static void main(String[] args) { <br><br>// Get the system date/time <br><br>Date date = new Date(); <br><br>// 打印出具体的年，月，日，小时，分钟，秒钟以及时区<br><br>System.out.println(date.getTime()); <br><br>}&nbsp;&nbsp; <br><br>} <br><br>在星期六, 2001年9月29日, 下午大约是6:50的样子, 上面的例子在系统输出设备上显示的结果是 1001803809710. 在这个例子中,值得注意的是我们使用了Date 构造函数创建一个日期对象, 这个构造函数没有接受任何参数. 而这个构造函数在内部使用了System.currentTimeMillis() 方法来从系统获取日期. <br><br>//1年前日期<br><br>&nbsp;&nbsp; java.util.Date myDate=new java.util.Date();&nbsp; <br><br>&nbsp;&nbsp; long myTime=(myDate.getTime()/1000)-60*60*24*365;<br><br>&nbsp;&nbsp; myDate.setTime(myTime*1000);<br><br>&nbsp;&nbsp; String mDate=formatter.format(myDate);<br><br>//明天日期<br><br>&nbsp;&nbsp; myDate=new java.util.Date(); <br><br>&nbsp;&nbsp; myTime=(myDate.getTime()/1000)+60*60*24;<br><br>&nbsp;&nbsp; myDate.setTime(myTime*1000);<br><br>&nbsp;&nbsp; mDate=formatter.format(myDate);<br><br>//两个时间之间的天数<br><br>&nbsp;&nbsp; SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");<br><br>&nbsp;&nbsp; java.util.Date date= myFormatter.parse("2003-05-1"); <br><br>&nbsp;&nbsp; java.util.Date mydate= myFormatter.parse("1899-12-30");<br><br>&nbsp;&nbsp; long&nbsp; day=(date.getTime()-mydate.getTime())/(24*60*60*1000);<br><br>//加半小时<br><br>SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");<br><br>java.util.Date date1 = format.parse("2002-02-28 23:16:00");<br><br>long Time=(date1.getTime()/1000)+60*30;<br><br>date1.setTime(Time*1000);<br><br>String mydate1=formatter.format(date1);<br><br>//年月周求日期<br><br>SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E");<br><br>java.util.Date date2= formatter2.parse("2003-05 5 星期五"); <br><br>SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd");<br><br>String mydate2=formatter3.format(date2);<br><br>//求是星期几<br><br>mydate= myFormatter.parse("2001-1-1");<br><br>SimpleDateFormat formatter4 = new SimpleDateFormat("E");<br><br>String mydate3=formatter4.format(mydate);<br><br>&nbsp;<br>&nbsp;<br><br>&nbsp;<br><br>1.2. Date格式化<br>能以一种用户明白的格式来显示这个日期呢? 在这里类java.text.SimpleDateFormat 和它的抽象基类 java.text.DateFormat。那么, 现在我们已经知道了如何获取从1970年1月1日开始经历的毫秒数了. 我们如何才format 就派得上用场了. <br><br>// 我们能不能用下面的代码构件出 2001/8/8 8:8<br>&nbsp;&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsDate<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Date date = new Date(2001, 8, 8, 8, 8, 8);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(date);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>Java 的编译器竟然报如下信息 (Sun JDK1.3, Windows 2000 中文下)<br><br>注意：<br>WhatIsDate.java 使用或覆盖一个不鼓励使用的API。<br>注意：<br>使用-deprecation重新编译，以得到详细信息。！<br>&nbsp;<br><br>那么 Date 对象究竟是为了满足哪个需求呢？看来它不是用来实现基于年/月/日小时:分钟 的时间表述。我们查看 Java 的文档，我们看到有 getTime() 方法，它返回的竟然是一个 long 值。<br><br>文档进一步又告诉我们这个值代表了当前系统的时间离1970/1/1 0:0 的毫秒差，而且是在 GMT 时区下(也被称为 EPOC)。如果我们指定的时间是在此之前的，那它将返回一个负数值。<br><br>这个发现让我们对 Date 对象有了一个全新的认识-Date 存放的是与 EPOC 的偏差值。换而言之我们也可通过 long 类型来表示时间？对了，这个猜想是得到了 Java 的支持：<br><br>&nbsp;&nbsp; // 第二种获得当前时间的方法<br>&nbsp;&nbsp;&nbsp; long dateInMilliSeconds = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; // 这时候打印出的只是一串数字而已<br>&nbsp;&nbsp;&nbsp; System.out.println(dateInMilliSeconds);<br>&nbsp;<br><br>对程序执行效率敏感的程序员可以发现这个方法只是生成一个 Java 的原始类型 (primitive type) long, 不需要实例化一个对象。因此如果我们对时间的处理只是在内部进行时，可以用 long 来代替 Date 对象。<br><br>最典型的应用就是在一段代码开始和结束时,分别获得系统当前的时间,然后计算出代码执行所需的时间(微秒级)。<br><br>&nbsp;&nbsp; long start = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; // 代码段<br>&nbsp;&nbsp;&nbsp; System.out.println("需要 "+(System.currentTimeMillis()-start)+" 微秒");<br>&nbsp;<br><br>那么当我们要把这个 long 值已更为友好的表现形式显示处理的时候，我们可以用它来构造 Date 对象：<br><br>Date date = new Date(dateInMilliSeconds);<br><br>System.out.println(date);<br>&nbsp;<br><br>我们看到了在 Java 中对时间最为基本的表示，有通过对EPOC 的偏差值进行处理。Date 对象是对它的一个对象的封装。我们同时也看到了，在现时世界中我们对时间的描述通常是通过"某年某月某日某时某分"来定义的。Date 的显示(实际上是 toString() 方法)描述了这些信息，但 Java 并不建议我们用这种方式直接来构件 Date 对象。因此我们需要找出哪个对象可以实现这个需求。这就是我们下面就要讲述的 Calendar 对象的功能。<br><br>在我们进一步研究 Calendar 之前，请记住 Date 只是一个对 long 值(基于 GMT 时区)的对象封装。它所表现出来的年/月/日小时:分钟时区的时间表述，只是它的 toString() 方法所提供的。千万不要为这个假象所迷惑。<br><br>假如我们希望定制日期数据的格式, 比方星期六-9月-29日-2001年. 下面的例子展示了如何完成这个工作: <br><br>import java.text.SimpleDateFormat; <br><br>import java.util.Date; <br><br>public class DateExample2 { <br><br>public static void main(String[] args) { <br><br>SimpleDateFormat bartDateFormat = new SimpleDateFormat("EEEE-MMMM-dd-yyyy"); Date date = new Date(); <br><br>System.out.println(bartDateFormat.format(date)); <br><br>}<br><br>}<br>&nbsp;<br><br>只要通过向SimpleDateFormat 的构造函数传递格式字符串"EEE-MMMM-dd-yyyy", 我们就能够指明自己想要的格式. 你应该可以看见, 格式字符串中的ASCII 字符告诉格式化函数下面显示日期数据的哪一个部分. EEEE是星期, MMMM是月, dd是日, yyyy是年. 字符的个数决定了日期是如何格式化的.传递"EE-MM-dd-yy"会显示 Sat-09-29-01. 请察看Sun 公司的Web 站点获取日期格式化选项的完整的指示. <br><br>1.3. 文本数据解析成日期对象 <br>假设我们有一个文本字符串包含了一个格式化了的日期对象, 而我们希望解析这个字符串并从文本日期数据创建一个日期对象. 我们将再次以格式化字符串"MM-dd-yyyy" 调用SimpleDateFormat类, 但是这一次, 我们使用格式化解析而不是生成一个文本日期数据. 我们的例子, 显示在下面, 将解析文本字符串"9-29-2001"并创建一个值为001736000000 的日期对象. <br><br>通过parse()方法，DateFormat能够以一个字符串创立一个Date对象。这个方法能抛出ParseException异常，所以你必须使用适当的异常处理技术。<br><br>例子程序: <br><br>import java.text.SimpleDateFormat; <br><br>import java.util.Date; <br><br>public class DateExample3 { <br><br>public static void main(String[] args) { <br><br>// Create a date formatter that can parse dates of <br><br>// the form MM-dd-yyyy. <br><br>SimpleDateFormat bartDateFormat = new SimpleDateFormat("MM-dd-yyyy"); <br><br>// Create a string containing a text date to be parsed. <br><br>String dateStringToParse = "9-29-2001"; <br><br>try { <br><br>// Parse the text version of the date. <br><br>// We have to perform the parse method in a <br><br>// try-catch construct in case dateStringToParse <br><br>// does not contain a date in the format we are expecting. <br><br>Date date = bartDateFormat.parse(dateStringToParse); <br><br>// Now send the parsed date as a long value <br><br>// to the system output. <br><br>System.out.println(date.getTime()); <br><br>}catch (Exception ex) { <br><br>System.out.println(ex.getMessage()); <br><br>}<br><br>} <br><br>} <br>&nbsp;<br><br>1.4. 使用标准的日期格式化过程 <br>既然我们已经可以生成和解析定制的日期格式了, 让我们来看一看如何使用内建的格式化过程. 方法 DateFormat.getDateTimeInstance() 让我们得以用几种不同的方法获得标准的日期格式化过程. 在下面的例子中, 我们获取了四个内建的日期格式化过程. 它们包括一个短的, 中等的, 长的, 和完整的日期格式. <br><br>import java.text.DateFormat; <br><br>import java.util.Date; <br><br>public class DateExample4 { <br><br>public static void main(String[] args) { <br><br>Date date = new Date(); <br><br>DateFormat shortDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.SHORT, DateFormat.SHORT); <br><br>DateFormat mediumDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.MEDIUM, DateFormat.MEDIUM); <br><br>DateFormat longDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.LONG, DateFormat.LONG); <br><br>DateFormat fullDateFormat = DateFormat.getDateTimeInstance( <br><br>DateFormat.FULL, DateFormat.FULL); <br><br>System.out.println(shortDateFormat.format(date)); System.out.println(mediumDateFormat.format(date)); System.out.println(longDateFormat.format(date)); System.out.println(fullDateFormat.format(date)); <br><br>} <br><br>} <br><br>注意我们在对 getDateTimeInstance的每次调用中都传递了两个值. 第一个参数是日期风格, 而第二个参数是时间风格. 它们都是基本数据类型int(整型). 考虑到可读性, 我们使用了DateFormat 类提供的常量: SHORT, MEDIUM, LONG, 和 FULL. 要知道获取时间和日期格式化过程的更多的方法和选项, 请看Sun 公司Web 站点上的解释. <br><br>运行我们的例子程序的时候, 它将向标准输出设备输出下面的内容: <br>9/29/01 8:44 PM <br>Sep 29, 2001 8:44:45 PM <br>September 29, 2001 8:44:45 PM EDT <br>Saturday, September 29, 2001 8:44:45 PM EDT <br><br>2.&nbsp;&nbsp; Calendar 日历类 <br>首先请记住 Calendar 只是一个抽象类, 也就是说你无法直接获得它的一个实例，换而言之你可以提供一个自己开发的 Calendar 对象。<br><br>那究竟什么是一个 Calendar 呢？中文的翻译就是日历，那我们立刻可以想到我们生活中有阳(公)历、阴(农)历之分。它们的区别在哪呢？<br><br>比如有：<br><br>月份的定义 - 阳`(公)历 一年12 个月，每个月的天数各不同；阴(农)历，每个月固定28天,每周的第一天 - 阳(公)历星期日是第一天；阴(农)历，星期一是第一天<br><br>实际上，在历史上有着许多种纪元的方法。它们的差异实在太大了，比如说一个人的生日是"八月八日" 那么一种可能是阳(公)历的八月八日，但也可以是阴(农)历的日期。所以为了计时的统一，必需指定一个日历的选择。那现在最为普及和通用的日历就是 "Gregorian Calendar"。也就是我们在讲述年份时常用 "公元几几年"。Calendar 抽象类定义了足够的方法，让我们能够表述日历的规则。Java 本身提供了对 "Gregorian Calendar" 规则的实现。我们从 Calendar.getInstance() 中所获得的实例就是一个 "GreogrianCalendar" 对象(与您通过 new GregorianCalendar() 获得的结果一致)。<br><br>下面的代码可以证明这一点：<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendar<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar calendar = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (calendar instanceof GregorianCalendar)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("It is an instance of GregorianCalendar");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>&nbsp;<br><br>Calendar 在 Java 中是一个抽象类(Abstract Class)，GregorianCalendar 是它的一个具体实现。<br><br>Calendar 与 Date 的转换非常简单：<br><br>&nbsp;&nbsp; Calendar calendar = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp; // 从一个 Calendar 对象中获取 Date 对象<br>&nbsp;&nbsp;&nbsp; Date date = calendar.getTime();<br>&nbsp;&nbsp;&nbsp; // 将 Date 对象反应到一个 Calendar 对象中，<br>&nbsp;&nbsp;&nbsp; // Calendar/GregorianCalendar 没有构造函数可以接受 Date 对象<br>&nbsp;&nbsp;&nbsp; // 所以我们必需先获得一个实例，然后设置 Date 对象<br>&nbsp;&nbsp;&nbsp; calendar.setTime(date);<br>&nbsp;<br>&nbsp;<br><br>&nbsp;<br><br>Calendar 对象在使用时，有一些值得注意的事项：<br><br>1. Calendar 的 set() 方法<br><br>set(int field, int value) - 是用来设置"年/月/日/小时/分钟/秒/微秒"等值<br><br>field 的定义在 Calendar 中<br><br>set(int year, int month, int day, int hour, int minute, int second) 但没有set(int year, int month, int day, int hour, int minute, int second, int millisecond) 前面 set(int,int,int,int,int,int) 方法不会自动将 MilliSecond 清为 0。<br><br>另外，月份的起始值为０而不是１，所以要设置八月时，我们用７而不是8。<br><br>calendar.set(Calendar.MONTH, 7);<br><br>我们通常需要在程序逻辑中将它清为 0，否则可能会出现下面的情况：<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendarWrite<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectOutputStream out =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectOutputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileOutputStream("calendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(2000, 7, 1, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>我们将 Calendar 保存到文件中<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendarRead<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream in =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectInputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileInputStream("calendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cal1.equals(cal2))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Equals");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("NotEqual");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Old calendar "+cal2.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("New calendar "+cal1.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cal1.equals(cal2))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Equals");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("NotEqual");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Processed Old calendar "+cal2.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Processed New calendar "+cal1.getTime().getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>然后再另外一个程序中取回来（模拟对数据库的存储），但是执行的结果是：<br><br>NotEqual<br>Old calendar 965113200422 &lt;------------ 最后三位的MilliSecond与当前时间有关<br>New calendar 965113200059 &lt;-----------/<br>Equals<br>Processed Old calendar 965113200000<br>Processed New calendar 965113200000<br>&nbsp;<br>&nbsp;<br><br>另外我们要注意的一点是，Calendar 为了性能原因对 set() 方法采取延缓计算的方法。在 JavaDoc 中有下面的例子来说明这个问题：<br><br>Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31<br>&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MONTH, Calendar.SEPTEMBER); //应该是 2000-9-31，也就是 2000-10-1<br>&nbsp;&nbsp;&nbsp; cal1.set(Calendar.DAY_OF_MONTH, 30); //如果 Calendar 转化到 2000-10-1，那么现在的结果就该是 2000-10-30<br>&nbsp;&nbsp;&nbsp; System.out.println(cal1.getTime()); //输出的是2000-9-30，说明 Calendar 不是马上就刷新其内部的记录<br>&nbsp;<br><br>在 Calendar 的方法中，get() 和 add() 会让 Calendar 立刻刷新。Set() 的这个特性会给我们的开发带来一些意想不到的结果。我们后面会看到这个问题。<br><br>2. Calendar 对象的容错性，Lenient 设置<br><br>我们知道特定的月份有不同的日期，当一个用户给出错误的日期时，Calendar 如何处理的呢？<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class WhatIsCalendar<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 1, 32, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal1.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.setLenient(false);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 1, 32, 0, 0, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal1.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>它的执行结果是：<br><br>&nbsp;&nbsp; Tue Feb 01 00:00:00 PST 2000<br>&nbsp;&nbsp;&nbsp; Exception in thread "main" java.lang.IllegalArgumentException<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:1368)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.Calendar.updateTime(Calendar.java:1508)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.Calendar.getTimeInMillis(Calendar.java:890)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.util.Calendar.getTime(Calendar.java:871)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at WhatIsCalendar.main(WhatIsCalendar.java:12)<br>&nbsp;<br><br>当我们设置该 Calendar 为 Lenient false 时，它会依据特定的月份检查出错误的赋值。<br><br>3. 不稳定的 Calendar<br><br>我们知道 Calendar 是可以被 serialize 的，但是我们要注意下面的问题<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class UnstableCalendar implements Serializable<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0 , 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectOutputStream out =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectOutputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileOutputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream in =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectInputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileInputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal2.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>&nbsp;<br><br>运行的结果竟然是: Thu Jan 01 00:00:00 PST 1970<br><br>它被复原到 EPOC 的起始点，我们称该 Calendar 是处于不稳定状态。这个问题的根本原因是 Java 在 serialize GregorianCalendar 时没有保存所有的信息，所以当它被恢复到内存中，又缺少足够的信息时，Calendar 会被恢复到 EPOCH 的起始值。Calendar 对象由两部分构成：字段和相对于 EPOC 的微秒时间差。字段信息是由微秒时间差计算出的，而 set() 方法不会强制 Calendar 重新计算字段。这样字段值就不对了。<br><br>下面的代码可以解决这个问题：<br><br>&nbsp;&nbsp; import java.io.*;<br>&nbsp;&nbsp;&nbsp; import java.util.*;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; public class StableCalendar implements Serializable<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal1 = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(2000, 7, 1, 0, 0 , 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal1.set(Calendar.MILLISECOND, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectOutputStream out =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectOutputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileOutputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.writeObject(cal1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream in =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ObjectInputStream(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileInputStream("newCalendar.out"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar cal2 = (Calendar)in.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.get(Calendar.MILLISECOND); //先调用 get()，强制 Calendar 刷新<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal2.set(Calendar.MILLISECOND, 0);&nbsp; //再设值<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal2.getTime());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br><br>运行的结果是: Tue Aug 01 00:00:00 PDT 2000,这个问题主要会影响到在 EJB 编程中，参数对象中包含 Calendar 时。经过 Serialize/Deserialize 后，直接操作 Calendar 会产生不稳定的情况。<br><br>4. add() 与 roll() 的区别<br><br>add() 的功能非常强大，add 可以对 Calendar 的字段进行计算。如果需要减去值，那么使用负数值就可以了，如 add(field, -value)。<br><br>add() 有两条规则：<br><br>当被修改的字段超出它可以的范围时，那么比它大的字段会自动修正。如：<br><br>Calendar cal1 = Calendar.getInstance();<br><br>cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31<br><br>cal1.add(Calendar.MONTH, 1); //2000-9-31 =&gt; 2000-10-1，对吗？System.out.println(cal1.getTime()); //结果是 2000-9-30<br>&nbsp;<br><br>另一个规则是，如果比它小的字段是不可变的（由 Calendar 的实现类决定），那么该小字段会修正到变化最小的值。<br><br>以上面的例子，9-31 就会变成 9-30，因为变化最小。<br><br>Roll() 的规则只有一条：当被修改的字段超出它可以的范围时，那么比它大的字段不会被修正。如：<br><br>Calendar cal1 = Calendar.getInstance();<br>cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日<br>cal1.roll(Calendar.WEEK_OF_MONTH, -1); //1999-6-1, 周二<br>cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日<br>cal1.add(Calendar.WEEK_OF_MONTH, -1); //1999-5-30, 周日<br>WEEK_OF_MONTH 比 MONTH 字段小，所以 roll 不能修正 MONTH 字段。<br>&nbsp;<br><br>我们现在已经能够格式化并创建一个日期对象了, 但是我们如何才能设置和获取日期数据的特定部分呢, 比如说小时, 日, 或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类. 就如我们前面提到的那样, Calendar 类中的方法替代了Date 类中被人唾骂的方法. <br><br>假设你想要设置, 获取, 和操纵一个日期对象的各个部分, 比方一个月的一天或者是一个星期的一天. 为了演示这个过程, 我们将使用具体的子类 java.util.GregorianCalendar. 考虑下面的例子, 它计算得到下面的第十个星期五是13号. <br><br>import java.util.GregorianCalendar; <br><br>import java.util.Date; <br><br>import java.text.DateFormat; <br><br>public class DateExample5 { <br><br>public static void main(String[] args) { <br><br>DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL); <br><br>// Create our Gregorian Calendar. <br><br>GregorianCalendar cal = new GregorianCalendar(); <br><br>// Set the date and time of our calendar <br><br>// to the system&amp;s date and time <br><br>cal.setTime(new Date()); <br><br>System.out.println("System Date: " + dateFormat.format(cal.getTime())); // Set the day of week to FRIDAY <br><br>cal.set(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.FRIDAY); System.out.println("After Setting Day of Week to Friday: " + dateFormat.format(cal.getTime())); <br><br>int friday13Counter = 0; <br><br>while (friday13Counter &lt;= 10) { <br><br>// Go to the next Friday by adding 7 days. cal.add(GregorianCalendar.DAY_OF_MONTH, 7); <br><br>// If the day of month is 13 we have <br><br>// another Friday the 13th. <br><br>if (cal.get(GregorianCalendar.DAY_OF_MONTH) == 13) { <br><br>friday13Counter++; System.out.println(dateFormat.format(cal.getTime())); <br><br>} <br><br>} <br><br>} <br><br>} <br><br>在这个例子中我们作了有趣的函数调用: <br><br>cal.set(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.FRIDAY); <br><br>和:cal.add(GregorianCalendar.DAY_OF_MONTH, 7); <br><br>set 方法能够让我们通过简单的设置星期中的哪一天这个域来将我们的时间调整为星期五. 注意到这里我们使用了常量 DAY_OF_WEEK 和 FRIDAY来增强代码的可读性. add 方法让我们能够在日期上加上数值. 润年的所有复杂的计算都由这个方法自动处理. <br><br>我们这个例子的输出结果是: <br><br>System Date: Saturday, September 29, 2001 <br><br>当我们将它设置成星期五以后就成了: Friday, September 28, 2001 <br><br>Friday, September 13, 2002 <br><br>Friday, December 13, 2002 <br><br>Friday, June 13, 2003 <br><br>Friday, February 13, 2004 <br><br>Friday, August 13, 2004 <br><br>Friday, May 13, 2005 <br><br>Friday, January 13, 2006 <br><br>Friday, October 13, 2006 <br><br>Friday, April 13, 2007 <br><br>Friday, July 13, 2007 <br><br>Friday, June 13, 2008 <br><br>Calendar类的基础即有变量域的观念。每个类元素都是域，并且这些域在Calendar类中表现为静态变量。这些变量域，可以通过get/set类方法来获得或者设置域值。<br><br>// 获得默认的Calendar实例，给它设置时间<br>Calendarcal = Calendar.getInstance();<br>intyear = cal.get(Calendar.YEAR);<br>cal.set(Calendar.MONTH,Calendar.NOVEMBER); <br>Calendar类的add和roll方法提供在日期之间转换的能力。每个方法都由一个参数变量和一个参数值来修改，通过这个可为正数或负数的参数值来修改它。仅仅不同的是，add方法可以向高阶的变量域溢出。例如，如果从九月三号向后倒退三天，将得到：<br><br>Calendar cal = Calendar.getInstance();<br><br>cal.add(Calendar.DATE,-3);<br><br>// 值为: 星期六八月 31 23:43:19 EDT 2002 <br><br>然而使用roll方法向后回滚三天得出：<br><br>Calendar cal = Calendar.getInstance();<br><br>cal.roll(Calendar.DATE,-3);<br><br>// 值为: 星期一九月 30 23:43:47 EDT 2002 <br>这就是为什么通常主要使用add方法的原因。<br><br>还有一个隐藏在最通用的Calendar的子类中的功能性方法--isLeapYear（判断是否为闰年）方法。<br><br>Calendar cal = Calendar.getInstance();<br><br>booleanleapYear = ( (GregorianCalendar)cal ).isLeapYear(2002);<br><br>// 这个值是false <br><br>尽管它是一个实例方法，isLeapYear方法的行为表现像静态方法，需要提供年份的参数传值给日历。<br><br>其实求几天几月几年前/后的方法，应该用Calendar类比较好的（比Date）。<br><br>Calendar cal = Calendar.getInstance();<br><br>cal.setTime(date);<br><br>cal.add(Calendar.MONTH,1);<br><br>cal.add(Calendar.YEAR,2000);<br><br>date = cal.getTime();<br><br>通过接管日期修改的功能，java.util.Calendar类看上去更像是Data类的复杂版本。但是它还提供额外的功能，更不用说它的国际化支持，使得它值得拥有学习的难度曲线。<br><br>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用GregorianCalendar类<br>创建一个代表任意日期的一个途径使用GregorianCalendar类的构造函数，它包含在java.util包中：<br><br>GregorianCalendar(int year, int month, int date) <br>注意月份的表示，一月是0，二月是1，以此类推，是12月是11。因为大多数人习惯于使用单词而不是使用数字来表示月份，这样程序也许更易读，父类Calendar使用常量来表示月份：JANUARY, FEBRUARY,等等。所以，创建Wilbur 和 Orville制造第一架动力飞机的日期（December 17, 1903），你可以使用：<br><br>GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17); <br><br>出于清楚的考虑，你应该使用前面的形式。但是，你也应该学习怎样阅读下面的短格式。下面的例子同样表示December 17,1903（记住，在短格式中，11表示December）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GregorianCalendar firstFlight = new GregorianCalendar(1903, 11, 17);&nbsp;&nbsp; 在上一节中，你学习了转换Date对象到字符串。这里，你可以做同样的事情；但是首先，你需要将GregorianCalendar对象转换到Date。要做到这一点，你可以使用getTime()方法，从它得父类Calendar继承而来。GetTime()方法返回GregorianCalendar相应的Date对象。你能够创建GregorianCalendar对象，转换到Date对象，得到和输出相应的字符串这样一个过程。下面是例子： <br><br>import java.util.*;<br><br>import java.text.*;<br><br>public class Flight {<br><br>&nbsp;&nbsp; public static void main(String[] args) {<br><br>GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);&nbsp;&nbsp;&nbsp; <br><br>Date d = firstFlight.getTime();<br><br>DateFormat df = DateFormat.getDateInstance();<br><br>String s = df.format(d);<br><br>System.out.println("First flight was " + s);<br><br>}<br><br>有时候创建一个代表当前时刻的GregorianCalendar类的实例是很有用的。你可以简单的使用没有参数的GregorianCalendar构造函数，象这样：<br><br>GregorianCalendar thisday = new GregorianCalendar();<br>一个输出今天日期的例子程序，使用GregorianCalendar对象：<br><br>import java.util.*;<br>import java.text.*;<br>class Today {<br>&nbsp;&nbsp; public static void main(String[] args) {<br>GregorianCalendar thisday = new GregorianCalendar(); <br>Date d = thisday.getTime();<br>DateFormat df = DateFormat.getDateInstance();<br>String s = df.format(d);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Today is " + s);<br>&nbsp;&nbsp; }<br>}<br>注意到，Date()构造函数和GregorianCalendar()构造函数很类似：都创建一个对象，条件简单，代表今天。<br>GregorianCalendar类提供处理日期的方法。一个有用的方法是add().使用add()方法，你能够增加象年，月数，天数到日期对象中。要使用add()方法，你必须提供要增加的字段，要增加的数量。一些有用的字段是DATE, MONTH, YEAR, 和 WEEK_OF_YEAR。下面的程序使用add()方法计算未来80天的一个日期。在Jules的&lt;环球80天&gt;是一个重要的数字，使用这个程序可以计算Phileas Fogg从出发的那一天1872年10月2日后80天的日期：<br><br>import java.util.*;<br>import java.text.*;<br>public class World {<br>&nbsp;&nbsp; public static void main(String[] args) {<br>GregorianCalendar worldTour = new GregorianCalendar(1872, Calendar.OCTOBER, 2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; worldTour.add(GregorianCalendar.DATE, 80);<br>Date d = worldTour.getTime();<br>DateFormat df = DateFormat.getDateInstance();<br>String s = df.format(d);<br>System.out.println("80 day trip will end " + s);<br>&nbsp;&nbsp; }<br>}<br>add()一个重要的副作用是它改变了原来的日期。有时候，拥有原始日期和修改后的日期很重要。不幸的是，你不能简单的创建一个GregorianCalendar对象，设置它和原来的相等（equal）。原因是两个变量指向同一个Date()对象地址。如果Date对象改变，两个变量就指向改变后的日期对象。代替这种做法，应该创建一个新对象。下面的程序示范了这种做法：import java.util.*;<br><br>import java.text.*;<br><br>public class ThreeDates {<br><br>&nbsp;&nbsp; public static void main(String[] args) {<br><br>GregorianCalendar gc1 = new GregorianCalendar(2000, Calendar.JANUARY, 1);<br><br>GregorianCalendar gc2 = gc1;<br><br>GregorianCalendar gc3 = new GregorianCalendar(2000, Calendar.JANUARY, 1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Three dates all equal to January 1, 2000<br><br>gc1.add(Calendar.YEAR, 1);<br><br>//gc1 and gc2 are changed&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><br>DateFormat df = DateFormat.getDateInstance();<br><br>Date d1 = gc1.getTime();<br><br>Date d2 = gc2.getTime();<br><br>Date d3 = gc3.getTime();<br><br>String s1 = df.format(d1);<br><br>String s2 = df.format(d2);<br><br>String s3 = df.format(d3);<br><br>System.out.println("gc1 is " + s1);<br><br>System.out.println("gc2 is " + s2);<br><br>System.out.println("gc3 is " + s3);<br><br>&nbsp;&nbsp; }<br><br>}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 程序运行后，gc1和gc2被变成2001年（因为两个对象指向同一个Date，而Date已经被改变了）。对象gc3指向一个单独的Date，它没有被改变。<br>&nbsp;package com.minght.sys.util;<br><br>/**<br>&nbsp;* &lt;p&gt;Title: 开源,开放&lt;/p&gt;<br>&nbsp;* &lt;p&gt;Description: opeansource&lt;/p&gt;<br>&nbsp;* &lt;p&gt;Copyright: Copyright (c) 2004&lt;/p&gt;<br>&nbsp;* &lt;p&gt;Company: ?海棠&lt;/p&gt;<br>&nbsp;* @author HaiTang Ming<br>&nbsp;* @version 1.0<br>&nbsp;*/<br><br>import java.util.*;<br>import java.math.BigDecimal;<br>import java.math.BigInteger;<br>import java.sql.Timestamp;<br>import java.text.*;<br><br><br>public class timeUtil {<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将Date类型日期转化成String类型"任意"格式<br>&nbsp;&nbsp; * java.sql.Date,java.sql.Timestamp类型是java.util.Date类型的子类<br>&nbsp;&nbsp; * @param date Date<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "2003-01-01"格式<br>&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "yyyy年M月d日"<br>&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "yyyy-MM-dd HH:mm:ss"格式<br>&nbsp;&nbsp; * @return String<br>&nbsp;&nbsp; */<br>&nbsp; public static String dateToString(java.util.Date date,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (date==null || format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String str = sdf.format(date);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return str;<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将String类型日期转化成java.utl.Date类型"2003-01-01"格式<br>&nbsp;&nbsp; * @param str String&nbsp; 要格式化的字符串<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Date stringToUtilDate(String str,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (str==null||format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.util.Date date = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date = sdf.parse(str);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return date;<br>&nbsp; }<br><br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将String类型日期转化成java.sql.Date类型"2003-01-01"格式<br>&nbsp;&nbsp; * @param str String<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.sql.Date stringToSqlDate(String str,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (str==null||format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.util.Date date = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date = sdf.parse(str);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new java.sql.Date(date.getTime());<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将String类型日期转化成java.sql.Date类型"2003-01-01"格式<br>&nbsp;&nbsp; * @param str String<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return Timestamp<br>&nbsp;&nbsp; */<br>&nbsp; public static java.sql.Timestamp stringToTimestamp(String str,String format) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (str==null||format==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new&nbsp; SimpleDateFormat(format);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.util.Date date = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date = sdf.parse(str);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new java.sql.Timestamp(date.getTime());<br>&nbsp; }<br><br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将java.util.Date日期转化成java.sql.Date类型<br>&nbsp;&nbsp; * @param Date<br>&nbsp;&nbsp; * @return 格式化后的java.sql.Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.sql.Date toSqlDate(Date date) {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (date==null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; return new java.sql.Date(date.getTime());<br>&nbsp; }<br>&nbsp; /**<br>&nbsp;&nbsp; * 将字符串转化为时间格式 string to string<br>&nbsp;&nbsp; * @param str String<br>&nbsp;&nbsp; * @param format String<br>&nbsp;&nbsp; * @return String<br>&nbsp;&nbsp; */<br>&nbsp; public static String toDateString(String str,String oldformat,String newformat){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return dateToString(stringToUtilDate(str,oldformat),newformat);<br><br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将日历转化为日期<br>&nbsp;&nbsp; * @param calendar Calendar<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Date converToDate(java.util.Calendar calendar){<br>&nbsp;&nbsp;&nbsp; return Calendar.getInstance().getTime();<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 将日期转化为日历<br>&nbsp;&nbsp; * @param date Date<br>&nbsp;&nbsp; * @return Calendar<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Calendar converToCalendar(java.util.Date date){<br>&nbsp;&nbsp;&nbsp;&nbsp; Calendar calendar = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp; calendar.setTime(date);<br>&nbsp;&nbsp;&nbsp;&nbsp; return calendar;<br>&nbsp; }<br><br>&nbsp; /**<br>&nbsp;&nbsp; * 求得从某天开始，过了几年几月几日几时几分几秒后，日期是多少<br>&nbsp;&nbsp; * 几年几月几日几时几分几秒可以为负数<br>&nbsp;&nbsp; * @param date Date<br>&nbsp;&nbsp; * @param year int<br>&nbsp;&nbsp; * @param month int<br>&nbsp;&nbsp; * @param day int<br>&nbsp;&nbsp; * @param hour int<br>&nbsp;&nbsp; * @param min int<br>&nbsp;&nbsp; * @param sec int<br>&nbsp;&nbsp; * @return Date<br>&nbsp;&nbsp; */<br>&nbsp; public static java.util.Date modifyDate(java.util.Date date,int year ,int month,int day,int hour,int min,int sec){<br>&nbsp;&nbsp;&nbsp; Calendar cal = Calendar.getInstance();<br>&nbsp;&nbsp;&nbsp; cal.setTime(date);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.YEAR,year);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.MONTH,month);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.DATE,day);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.HOUR,hour);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.MINUTE,min);<br>&nbsp;&nbsp;&nbsp; cal.add(Calendar.SECOND,sec);<br><br>&nbsp;&nbsp;&nbsp; return cal.getTime();<br><br>&nbsp; }<br><br><br>&nbsp; /**<br>&nbsp;&nbsp; * 取得当前日期时间<br>&nbsp;&nbsp; * 1:year<br>&nbsp;&nbsp; * 2:month<br>&nbsp;&nbsp; * 3:day<br>&nbsp;&nbsp; */<br>&nbsp; public static int getCurTime(int i) {<br>&nbsp;&nbsp;&nbsp; if (i == 1) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return java.util.Calendar.getInstance().get(Calendar.YEAR);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else if (i == 2) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return java.util.Calendar.getInstance().get(Calendar.MONTH) + 1;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else if (i == 3) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return java.util.Calendar.getInstance().get(Calendar.DATE);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; return 0;<br><br>&nbsp; }<br><br>&nbsp; public static void main(String[] args){<br>&nbsp;&nbsp;&nbsp; System.out.println(dateToString(modifyDate(Calendar.getInstance().getTime(),-1,-1,-1,-1,-1,-1),"yyyy-MM-dd HH:mm:ss"));<br>&nbsp; }<br><br>}<br></font><img src ="http://www.blogjava.net/terry-zj/aggbug/22506.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-05 10:15 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/05/22506.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的Encode的问题</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/02/22193.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 02 Dec 2005 02:14:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/02/22193.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22193.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/02/22193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22193.html</trackback:ping><description><![CDATA[<font size="2"><span class="postbody">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 众所周知，<span style="color: blue;">com.mysql.jdbc.Connection</span>的构造函数<span style="color: blue;">public java.sql.Connection connect(String url, Properties info)</span>会在构造的时候接受一个Properties型的参数，其中的“useUnicode”和“characterEncoding”决定了它是否在客户端和服务器端传输过程中进行Encode，以及如何进行Encode。详细可参见private void <span style="color: blue;">checkServerEncoding()</span>方法。
<br>

Hibernate使用<span style="color: blue;">net.sf.hibernate.cfg.Environment</span>来存储系统级的所有属性，而用<span style="color: blue;">net.sf.hibernate.cfg.Settings</span>来存储Hibernate的设定。
<br>

但是<span style="color: blue;">net.sf.hibernate.cfg.Environment</span>里保存的Properties不是直接提供给<span style="color: blue;">com.mysql.jdbc.Connection</span>使用的。
<br>

<span style="color: blue;">net.sf.hibernate.connection.ConnectionProviderFactory</span>会在public void configure(Properties props)中使用用<span style="color: blue;">public static Properties getConnectionProperties(Properties properties)</span>方法进行筛选。
<br>
带有特定前缀<span style="color: blue;">public static final String CONNECTION_PREFIX = "hibernate.connection"</span>并且没有被放到<span style="color: blue;">private static final Set SPECIAL_PROPERTIES</span>里的属性才会被留下来。
<br>
然后，它在<span style="color: blue;">public Connection getConnection()</span>中建立连接的时候使用的是它自己筛选完之后的<span style="color: blue;">private Properties connectionProps</span>属性。
<br>

所以答案就很明显了。
<br>
使用hibernate.cfg.xml的话，在&lt;session-factory&gt;和&lt;/session-factory&gt;之间加入这么一段：
<br>
</span></font>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 
	  <td><font size="2"><span class="genmed"><b>java代码:&nbsp;</b></span></font></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<font size="2"><br>
&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="connection.<span style="color: rgb(0, 0, 0);">useUnicode</span>"&gt;<span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>&lt;/property&gt;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="connection.<span style="color: rgb(0, 0, 0);">characterEncoding</span>"&gt;UTF-<span style="color: rgb(0, 0, 0);">8</span>&lt;/property&gt;</font></div>
<font size="2"><br></font>
</td>
	</tr>
</tbody></table>
<font size="2"><span class="postbody">
<br>
如果是些程序的话，在创建完net.sf.hibernate.cfg.Configuration、并使用configure()读取完配置文件之后，buildSessionFactory()之前，执行如下代码：
<br>
</span></font>
<table style="width: 893px; height: 147px;" align="center" border="0" cellpadding="3" cellspacing="1">
<tbody><tr> 
	  <td><font size="2"><span class="genmed"><b>java代码:&nbsp;</b></span></font></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<font size="2"><br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(170, 170, 221);">Properties</span> extraProperties = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Properties</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; extraProperties.<span style="color: rgb(0, 0, 0);">put</span><span style="color: rgb(0, 0, 0);">(</span>"hibernate.<span style="color: rgb(0, 0, 0);">connection</span>.<span style="color: rgb(0, 0, 0);">useUnicode</span>", "<span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; extraProperties.<span style="color: rgb(0, 0, 0);">put</span><span style="color: rgb(0, 0, 0);">(</span>"hibernate.<span style="color: rgb(0, 0, 0);">connection</span>.<span style="color: rgb(0, 0, 0);">characterEncoding</span>", "UTF-<span style="color: rgb(0, 0, 0);">8</span>"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; myConfiguration.<span style="color: rgb(0, 0, 0);">addProperties</span><span style="color: rgb(0, 0, 0);">(</span>extraProperties<span style="color: rgb(0, 0, 0);">)</span>;</font></div>
<font size="2"><br></font>
</td>
	</tr>
</tbody></table>
<font size="2"><span class="postbody">OK！万事大吉了！<br><br>*</span><span class="postbody">直接写在connection url后面也可以<br></span><span class="postbody">Hibernate配置文件使用xml格式吗？试试看把connection url后面的 &amp; 符号用xml转义符替代试试看，或者用&lt;![CDATA[]]&gt;也行。</span><br></font><img src ="http://www.blogjava.net/terry-zj/aggbug/22193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-02 10:14 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/02/22193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HQL的返回值该怎么取得</title><link>http://www.blogjava.net/terry-zj/archive/2005/12/02/22190.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 02 Dec 2005 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/12/02/22190.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/22190.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/12/02/22190.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/22190.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/22190.html</trackback:ping><description><![CDATA[<font size="2"><span class="postbody">
取单个字段，会返回字段List：
<br>

<br>
</span></font>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 
	  <td><font size="2"><span class="genmed"><b>java代码:&nbsp;</b></span></font></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<font size="2">Query q = s.<span style="color: rgb(0, 0, 0);">createQuery</span><span style="color: rgb(0, 0, 0);">(</span>"select c.<span style="color: rgb(0, 0, 0);">id</span> from Cat as c"<span style="color: rgb(0, 0, 0);">)</span>;
<br><span style="color: rgb(170, 170, 221);">List</span> l = q.<span style="color: rgb(0, 0, 0);">list</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br><span style="color: rgb(153, 0, 102); font-weight: bold;">for</span> <span style="color: rgb(0, 0, 0);">(</span>i=<span style="color: rgb(0, 0, 0);">0</span>; i&lt; l.<span style="color: rgb(0, 0, 0);">size</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>; i++<span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(0, 0, 0);">{</span>&nbsp;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Long</span> id = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Long</span><span style="color: rgb(0, 0, 0);">)</span> l.<span style="color: rgb(0, 0, 0);">get</span><span style="color: rgb(0, 0, 0);">(</span>i<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">System</span>.<span style="color: rgb(0, 0, 0);">out</span>.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>id.<span style="color: rgb(0, 0, 0);">longValue</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br><span style="color: rgb(0, 0, 0);">}</span></font>


</div>

</td>
	</tr>
</tbody></table>
<font size="2"><span class="postbody">
<br>
取多个字段，Hibernate把每个id和name做成一个2个元素的单维数组，List实际上是一个单维数组的集合。
<br>

<br>
</span></font>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 
	  <td><font size="2"><span class="genmed"><b>java代码:&nbsp;</b></span></font></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<font size="2">Query q = s.<span style="color: rgb(0, 0, 0);">createQuery</span><span style="color: rgb(0, 0, 0);">(</span>"select Cat.<span style="color: rgb(0, 0, 0);">id</span>, Cat.<span style="color: rgb(0, 0, 0);">name</span>, from Cat "<span style="color: rgb(0, 0, 0);">)</span>;
<br><span style="color: rgb(170, 170, 221);">List</span> l = q.<span style="color: rgb(0, 0, 0);">list</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br><span style="color: rgb(153, 0, 102); font-weight: bold;">for</span> <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i=<span style="color: rgb(0, 0, 0);">0</span>;&nbsp; i&lt; l.<span style="color: rgb(0, 0, 0);">size</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>; i++<span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> row = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span><span style="color: rgb(0, 0, 0);">)</span> l.<span style="color: rgb(0, 0, 0);">get</span><span style="color: rgb(0, 0, 0);">(</span>i<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Long</span> id = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Long</span><span style="color: rgb(0, 0, 0);">)</span> row<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">String</span> name = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">String</span><span style="color: rgb(0, 0, 0);">)</span> row<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">]</span>;&nbsp;
<br><span style="color: rgb(0, 0, 0);">}</span></font>


</div>

</td>
	</tr>
</tbody></table>
<font size="2"><span class="postbody">
<br>

在这种情况下，HQL是不会去构造PO的，这一点很容易验证。JCS是对象Cache，如果写了这样的HQL，JCS里面是空的，说明Hibernate没有构造PO，如果再加上一个对象c本身，JCS里面就有数据了，如下：
<br>

<br>
</span></font>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 
	  <td><font size="2"><span class="genmed"><b>java代码:&nbsp;</b></span></font></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<font size="2">Query q = s.<span style="color: rgb(0, 0, 0);">createQuery</span><span style="color: rgb(0, 0, 0);">(</span>"select c.<span style="color: rgb(0, 0, 0);">id</span>, c.<span style="color: rgb(0, 0, 0);">name</span>,c from Cat as c"<span style="color: rgb(0, 0, 0);">)</span>;
<br><span style="color: rgb(170, 170, 221);">List</span> l = q.<span style="color: rgb(0, 0, 0);">list</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br><span style="color: rgb(153, 0, 102); font-weight: bold;">for</span> <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i=<span style="color: rgb(0, 0, 0);">0</span>; i&lt; l.<span style="color: rgb(0, 0, 0);">size</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>; ; i++<span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> row = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span><span style="color: rgb(0, 0, 0);">)</span> l.<span style="color: rgb(0, 0, 0);">get</span><span style="color: rgb(0, 0, 0);">(</span>i<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Long</span> id = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Long</span><span style="color: rgb(0, 0, 0);">)</span> row<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">String</span> name = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">String</span><span style="color: rgb(0, 0, 0);">)</span> row<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">]</span>;
<br>
&nbsp; Cat c = <span style="color: rgb(0, 0, 0);">(</span>Cat<span style="color: rgb(0, 0, 0);">)</span> row<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">]</span>;&nbsp;
<br><span style="color: rgb(0, 0, 0);">}</span></font>


</div>
</td></tr></tbody></table><img src ="http://www.blogjava.net/terry-zj/aggbug/22190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-12-02 09:41 <a href="http://www.blogjava.net/terry-zj/archive/2005/12/02/22190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate学习资源介绍</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/29/21820.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Tue, 29 Nov 2005 05:30:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/29/21820.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21820.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/29/21820.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21820.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21820.html</trackback:ping><description><![CDATA[<P>IBM的developerWorks上的Hibernate文章(重点推荐 入门最佳教程)<BR><A href="http://www-900.ibm.com/developerWorks/cn/java/l-hibernate1/">http://www-900.ibm.com/developerWorks/cn/java/l-hibernate1/</A> <BR><A href="http://www-900.ibm.com/developerWorks/cn/java/l-hibernate2/">http://www-900.ibm.com/developerWorks/cn/java/l-hibernate2/</A> <BR><BR>&nbsp;Hibernate 3.1.2中文文档发布(重点推荐 中文官方文档)<BR><A href="http://www.redsaga.com/mambo/content/view/42/2/">http://www.redsaga.com/mambo/content/view/42/2/</A><BR><BR>Hibernate 入門記(日文网站)<BR><A href="http://www.wikiroom.com/koichik">http://www.wikiroom.com/koichik</A><BR><BR>huihoo网站的Hibernate入门文章 <BR><A href="http://www.huihoo.com/java/hibernate/">http://www.huihoo.com/java/hibernate/</A> <BR>cn-java上的Hibernate的Hello World文章 <BR><A href="http://www.cn-java.com/target/news.php?news_id=2738">http://www.cn-java.com/target/news.php?news_id=2738</A> <BR>Hibernate查询语言：HQL <BR><A href="http://www.cn-java.com/target/news.php?news_id=2673">http://www.cn-java.com/target/news.php?news_id=2673</A> <BR>Hibernate对象关系 <BR><A href="http://www.erproad.org/article/HibernateObjRela.htm">http://www.erproad.org/article/HibernateObjRela.htm</A> <BR>Hibernate Session和Transaction管理 <BR><A href="http://chinawebservices.net/dreamland/space/Hibernate+Session%E5%92%8CTransaction%E7%AE%A1%E7%90%86">http://chinawebservices.net/dreamland/space/Hibernate+Session%E5%92%8CTransaction%E7%AE%A1%E7%90%86</A><BR></P><img src ="http://www.blogjava.net/terry-zj/aggbug/21820.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-29 13:30 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/29/21820.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>始终会用上的Common BeanUtils （转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Fri, 25 Nov 2005 09:22:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21443.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21443.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21443.html</trackback:ping><description><![CDATA[<DIV class=postText>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Beanutils用了魔术般的反射技术，实现了很多夸张有用的功能，都是C/C++时代不敢想的。无论谁的项目，始终一天都会用得上它。我算是后知后觉了，第一回看到它的时候居然错过。<BR></FONT><FONT size=2><STRONG><BR>1.属性的动态getter、setter <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>在这框架满天飞的年代，不能事事都保证执行getter,setter函数了，有时候属性是要根据名字动态取得的，就像这样：　　<BR></FONT><FONT size=2>BeanUtils.getProperty(myBean,"code");<BR></FONT><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而Common BeanUtils的更强功能在于可以直接访问内嵌对象的属性，只要使用点号分隔。<BR></FONT><FONT size=2>BeanUtils.getProperty(orderBean, "address.city");<BR></FONT><FONT size=2>相比之下其他类库的BeanUtils通常都很简单，不能访问内嵌的对象，所以有时要用Commons BeanUtils来替换它们。<BR><BR>BeanUtils还支持List和Map类型的属性，如下面的语法即可取得Order的顾客列表中第一个顾客的名字<BR></FONT><FONT size=2>BeanUtils.getProperty(orderBean, "customers[1].name");<BR></FONT><FONT size=2>其中BeanUtils会使用ConvertUtils类把字符串转为Bean属性的真正类型，方便从HttpServletRequest等对象中提取bean，或者把bean输出到页面。<BR></FONT><FONT size=2>而PropertyUtils就会原色的保留Bean原来的类型。</FONT></P>
<P><FONT size=2><STRONG>2.BeanCompartor 动态排序 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>还是通过反射，动态设定Bean按照哪个属性来排序，而不再需要在实现bean的Compare接口进行复杂的条件判断。 <BR></FONT><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List peoples = ...; // Person对象的列表<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.sort(peoples, new BeanComparator("age"));<BR></FONT><FONT size=2>如果要支持多个属性的复合排序，如"Order By lastName,firstName" </FONT></P><PRE><FONT size=2>ArrayList sortFields = new ArrayList();<BR>sortFields.add(new BeanComparator("lastName"));<BR>sortFields.add(new BeanComparator("firstName"));<BR>ComparatorChain multiSort = new ComparatorChain(sortFields);<BR>Collections.sort(rows,multiSort);<BR></FONT></PRE>
<P><FONT size=2>其中ComparatorChain属于jakata commons-collections包。<BR>如果age属性不是普通类型，构造函数需要再传入一个comparator对象为age变量排序。<BR>另外, BeanCompartor本身的ComparebleComparator, 遇到属性为null就会抛出异常, 也不能设定升序还是降序。这个时候又要借助commons-collections包的ComparatorUtils.</FONT></P><PRE><FONT size=2>&nbsp;&nbsp; Comparator mycmp = ComparableComparator.getInstance();<BR>&nbsp;&nbsp;&nbsp;mycmp = ComparatorUtils.nullLowComparator(mycmp);&nbsp; //允许null<BR>&nbsp;&nbsp; mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序<BR>&nbsp;&nbsp; Comparator cmp = new BeanComparator(sortColumn, mycmp);</FONT></PRE><FONT size=2><STRONG>3.Converter 把Request或ResultSet中的字符串绑定到对象的属性 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>经常要从request,resultSet等对象取出值来赋入bean中，如果不用MVC框架的绑定功能的话，下面的代码谁都写腻了。<BR>&nbsp; <BR></FONT><FONT size=2>&nbsp;&nbsp; String a = request.getParameter("a");<BR>&nbsp;&nbsp; bean.setA(a);<BR>&nbsp;&nbsp; String b = ....<BR>&nbsp;&nbsp; bean.setB(b);<BR>&nbsp;&nbsp; ......<BR></FONT><FONT size=2>不妨写一个Binder自动绑定所有属性:</FONT><PRE><FONT size=2>    MyBean bean = ...;<BR>    HashMap map = new HashMap();<BR>    Enumeration names = request.getParameterNames();<BR>    while (names.hasMoreElements())<BR>    {<BR>      String name = (String) names.nextElement();<BR>      map.put(name, request.getParameterValues(name));<BR>    }<BR>    BeanUtils.populate(bean, map);</FONT></PRE>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; 其中BeanUtils的populate方法或者getProperty,setProperty方法其实都会调用convert进行转换。<BR>&nbsp;&nbsp;&nbsp;&nbsp;但Converter只支持一些基本的类型，甚至连java.util.Date类型也不支持。而且它比较笨的一个地方是当遇到不认识的类型时，居然会抛出异常来。&nbsp;对于Date类型，我参考它的sqldate类型实现了一个Converter，而且添加了一个设置日期格式的函数。<BR>要把这个Converter注册，需要如下语句：</FONT></P><PRE><FONT size=2>   ConvertUtilsBean convertUtils = new ConvertUtilsBean();<BR>&nbsp;&nbsp; DateConverter dateConverter = new DateConverter();<BR>&nbsp;&nbsp; convertUtils.register(dateConverter,Date.class);<BR> <BR><BR><BR>   //因为要注册converter,所以不能再使用BeanUtils的静态方法了，必须创建BeanUtilsBean实例<BR>   BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new PropertyUtilsBean());<BR>   beanUtils.setProperty(bean, name, value);</FONT></PRE><FONT size=2><STRONG>4 其他功能</STRONG></FONT> 
<DIV><FONT size=2><STRONG>4.1 ConstructorUtils，动态创建对象<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>public static Object invokeConstructor(Class klass, Object arg)<BR></FONT><FONT size=2><STRONG>4.2 MethodUtils，动态调用方法</STRONG></FONT>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT size=2>MethodUtils.invokeMethod(bean, methodName, parameter);</FONT></DIV><FONT size=2><STRONG>4.3 PropertyUtils，当属性为Collection,Map时的动态读取：<BR></STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collection: 提供index<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getIndexedProperty(orderBean,"items",1);</FONT> 
<DIV><FONT size=2>或者<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getIndexedProperty(orderBean,"items[1]");</FONT><FONT size=2>Map: 提供Key Value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getMappedProperty(orderBean, "items","111");//key-value goods_no=111 </FONT><FONT size=2>或者<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>BeanUtils.getMappedProperty(orderBean, "items(111)") </FONT></DIV>
<DIV><FONT size=2><STRONG>4.4 PropertyUtils，直接获取属性的Class类型<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </STRONG></FONT><FONT size=2>public static Class getPropertyType(Object bean, String name)</FONT></DIV>
<DIV><FONT size=2><STRONG>4.5 动态Bean </STRONG>见<A href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://blog.csdn.net/calvinxiu/archive/2005/02/02/277765.aspx" target=__blank><FONT color=#000080>用DynaBean减除不必要的VO和FormBean&nbsp;</FONT></A><BR></FONT></DIV><FONT size=2><BR></FONT>
<P id=TBPingURL><FONT size=2>Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=277748</FONT></P></DIV><img src ="http://www.blogjava.net/terry-zj/aggbug/21443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-25 17:22 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/25/21443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 2 升级为Hibernate 3 的注意事项(转载)</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 03:22:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21250.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21250.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21250.html</trackback:ping><description><![CDATA[<DIV class=postbody><FONT size=2>目的，主要是那当前的项目练手，熟悉一下hibernate2和hibernate3的差别，给当前项目一点扩展的空间。<BR><BR>1.首先将hibernate2.jar替换为hibernate3.jar(hibernate-3.0.5)<BR>&nbsp;&nbsp;hibernate-tools.jar也替换成新的(从hibernate-tools-3.0.0.alpha4a找出来的)<BR><BR>2.将所有程序中的net.sf.hibernate替换为org.hibernate.<BR>&nbsp;<BR>3.但是有例外<BR>&nbsp;&nbsp;net.sf.hibernate.expression.Expression换为org.hibernate.criterion.Expression<BR>&nbsp;&nbsp;如果用eclipse,用ctrl+shift+o快捷键可以加快速度<IMG onclick="window.open('http://Anonymouse.org/cgi-bin/anon-www.cgi/http://blog.donews.com/images/smile.gif','_blank');" alt="" hspace=2 src="http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.blogcn.com/images/smile.gif" onload="javascript:if(this.width>screen.width/2)this.width=screen.width/2" vspace=2 border=0><BR>&nbsp;<BR>4.在使用hql查询时将<BR>&nbsp;&nbsp;createSQLQuery(hql,"c",EZCampaignDTO.class);改为createSQLQuery(hql).addEntity("c",EZCampaignDTO.class);<BR>&nbsp;<BR>5.在批量插入时<BR>&nbsp;&nbsp;将原来的int&nbsp;size&nbsp;=&nbsp;((SessionFactoryImpl)(session.getSessionFactory())).getJdbcBatchSize()<BR>&nbsp;&nbsp;改为int&nbsp;size&nbsp;=&nbsp;((SessionFactoryImpl)(session.getSessionFactory())).getSettings().getJdbcBatchSize();<BR>&nbsp;<BR>6.在计算count时<BR>&nbsp;&nbsp;将原来的int&nbsp;size&nbsp;=&nbsp;((Integer)&nbsp;session.iterate(hql).next()).intValue();<BR>&nbsp;&nbsp;改为int&nbsp;size&nbsp;=&nbsp;((Integer)&nbsp;session.createQuery(hql).iterate().next()).intValue();<BR>其中hql="select&nbsp;count(*)&nbsp;from&nbsp;"&nbsp;+&nbsp;DAOVar.contactClass;<BR>&nbsp;<BR>7.还有就是把.hbm中的hibernate-mapping-2.0.dtd替换为hibernate-mapping-3.0.dtd<BR>&nbsp;&nbsp;Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;2.0替换为Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;3.0<BR>&nbsp;<BR>8.hibernate.cfg.xml中<BR>&nbsp;&nbsp;Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;2.0替换为Hibernate&nbsp;Mapping&nbsp;DTD&nbsp;3.0<BR>&nbsp;&nbsp;&lt;property&nbsp;name="hibernate.dialect"&gt;org.hibernate.dialect.SQLServerDialect&lt;/property&gt;<BR>&nbsp;<BR>9.hibernate.properties中类似<BR>&nbsp;<BR>10.cache-config.xml中<BR>&nbsp;&nbsp;&nbsp;&lt;provider&nbsp;className="net.sf.hibernate.cache.OSCacheProvider"/&gt;替换为<BR>&nbsp;&nbsp;&nbsp;&lt;provider&nbsp;className="org.hibernate.cache.OSCacheProvider"/&gt;<BR>&nbsp;<BR>11.classeshibernate.properties中<BR>&nbsp;&nbsp;&nbsp;hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider<BR>&nbsp;&nbsp;&nbsp;hibernate.dialect=org.hibernate.dialect.SQLServerDialect<BR>&nbsp;<BR>12.在自动外部模块部分有一个功能是根据模版自动生成.hbm文件在load,结果出来的.hbm中有问题:<BR>&nbsp;&nbsp;&nbsp;生成的&nbsp;&lt;composite-id&nbsp;unsaved-value="any"&nbsp;mapped="false"&gt;其中mapped="false"&nbsp;出错。找了半天才发现在网上的hibernate-mapping-3.0.dtd文件有支持mapped="false"这个属性。而本地的hebernate3.0.5中的hibernate-mapping-3.0.dtd文件没有这个属性。晕，hibernate也太不负责了吧。解决办法把hibernate-mapping-3.0.dtd&nbsp;copy到jboss\bin目录下然后，在template文件中&lt;!DOCTYPE&nbsp;hibernate-mapping&nbsp;PUBLIC&nbsp;"-//Hibernate/Hibernate&nbsp;Mapping&nbsp;DTD//EN"&nbsp;"hibernate-mapping-3.0.dtd"&gt;，然后他会在jboss\bin目录下读取该文件。<BR>&nbsp;<BR>13.重新测试,还是咣铛，发现子类读父类数据时抛出异常：<BR>&nbsp;&nbsp;&nbsp;"org.hibernate.LazyInitializationException:&nbsp;could&nbsp;not&nbsp;initialize&nbsp;proxy"<BR>&nbsp;&nbsp;&nbsp;延迟抓取出的错，hb3对many-to-one的默认处理是lazy&nbsp;=&nbsp;"proxy"，没有搞懂到底怎么回事，把所有many-to-one,one-to-one都加上lazy="false"，再测试终于大功告成。<BR><BR>文章原作者Blog：</FONT><A href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://blog.csdn.net/chinaewolf/" target=_blank><FONT size=2><IMG alt=::URL:: hspace=2 src="http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.blogcn.com/images/aurl.gif" align=absBottom border=0></FONT></A><A href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://blog.csdn.net/chinaewolf/" target=_blank><FONT color=#000080 size=2>http://blog.csdn.net/chinaewolf/</FONT></A></DIV><img src ="http://www.blogjava.net/terry-zj/aggbug/21250.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 11:22 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21250.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的未来发展之路（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 03:14:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21248.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21248.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21248.html</trackback:ping><description><![CDATA[<font size="2"><span class="postbody">Hibernate的未来发展之路 <br><br>最近半年多来，在Java世界，Hibernate是最引人关注的一个话题。从Gavin King加入EJB3.0 EG，负责制订EJB3.0的持久层规范；到Gavin King非正式退出JDO EG，并且充满个人情绪的攻击JDO2.0规范；到《Hibernate in Action》的发行；再到Hibernate3 Alpha的发布；最后再到最近JBoss 3.0 PR的发布(使用Hibernate3实现Entity Bean)。可以说这其中的每一步都引起业界的侧目。 <br><br>Hibernate在不到3年的时间里，从一个不起眼的开源软件发展到今天令业界瞩目的主流O/R Mapping框架，Gavin King从一个开源软件的作者成为业界举足轻重的人物，这多少有些传奇的色彩。毕竟，单纯从技术成就而言，Hibernate不算是最有成就的Java开源框架软件，到目前为止也不是一个完美无缺的软件；从个人技术水平而言，Gavin King也不算绝顶高手。 <br><br>在当前的Java持久层框架中，最流行的O/R Mapping产品分别是Hibernate，JDO和TopLink。 <br><br>自从去年Gavin King加入JBoss之后，Hibernate已经由一个民间的开源软件走上了兼容EJB EntityBean的道路。然而更加令人侧目的是，Gavin King在EJB3.0 EG中充当了一个非常重要的角色，只要对比一下EJB3.0的EntityBean和Hibernate3，真相就会大白，虽然API接口不同，但是EntityBean的设计理念完全来自于Hibernate。 <br><br>虽然EJB3.0的EntityBean在相当程度上来源于Hibernate，但是毕竟是不同的API接口，因此Hibernate和EJB3.0 EntityBean究竟是怎样的一种关系，是很多人心中的疑问。 <br><br>今年四月份JBoss的Ben Wang访华期间，我曾经向Ben请教Hibernate的未来发展，他回答说，Hibernate未来将仍旧以独立的软件产品存在和发展，既可以outside EJB container使用；同时Hibernate也将做为JBoss EntityBean Implementation，又可以inside EJB container使用。然而如何既inside，又outside，终究缺乏一个感性的认识。 <br><br>10月8日JBoss发布的EJB3.0 PR揭开了答案。从Sourceforge的CVS服务器上面checkout出来源代码看一下，我们可以发现，Gavin King对Hibernate3进行了简单的封装，将EJB 3.0 EntityBean API调用转换为内部Hibernate3自己的API，从而实现EJB3.0 EntityBean的兼容。 <br><br>EJB3.0不承诺脱离容器调用，如果你想享用EJB3.0，则必须运行在某个EJB Vendor提供的容器内，例如你使用JBoss提供的容器，那么你调用的是EntityBean API，这些调用请求会被转换为Hibernate API的调用请求。这意味着Hibernate实际上提供了两套API：一套是Hibernate原生API；另一套是兼容EJB3.0 EntityBean API。对于那些需要分布式调用支持，需要EJB容器的开发人员来说，他们选择后一套API；对于不需要EJB容器的开发人员来说，他们选择前一套API。这就是Hibernate既定的发展策略。 <br><br>今年夏天投票通过的JDO2.0标准从某种程度而言，并不逊色于Hibernate当前的版本，有些功能甚至比Hibernate还要好，例如JDO支持对类属性的lazy loading，而Hibernate要到3才支持，当前Hibernate仅仅支持类的lazy loading。实际上在去年，就已经有很多用户不断提出对类属性的lazy loading的需求，然而Gavin King当时一直不认为这个需求有添加的必要性。再例如被Gavin King形容为“可憎的”JDOQL，实际上是类SQL查询语言和对象条件查询的混合体。从功能上来说，不如HQL强大，但是远比Hibernate自己的条件查询强很多。 <br><br>不知道究竟出于什么原因，Gavin King对JDO似乎一直怀有由衷的厌恶，今年5月，他在Hibernate的blog上面对JDO进行了毫不留情的批判，列举了JDO的种种缺点来解释为什么EJB3持久层规范没有把JDO考虑进去。然而事实上他的批判充满了对JDO的误解和偏见，例如Gavin King憎恨JDOQL丝毫没有什么特别的理由，只因为JDOQL不是一个纯粹的查询语言，而是一个混合体，这多少让人对Gavin King的风度感到遗憾。在被SolarMetric的Abe White反驳之后，同样没有风度的说，“我可没有时间做这种无谓的争论，事实上每个人都认为他自己的技术是最好的……我是错了，JDO那伙人也错了，每个人都会犯错误……”。（所以说人无完人阿！） <br><br>JDO2规范的出台事实上构成了对Hibernate，乃至基于Hibernate理念的EJB3.0 EntityBean的严重威胁。JDO1.0规范在功能上的严重缺失导致了JDO无力面对Hibernate和TopLink的竞争，然而功能基本完备的JDO2挟众多JDO Vendor商业支持的合力，同时JDO规范可以避免产品锁定在某个Vendor的优势，已经将竞争的天平拉直。 <br><br>然而JDO2和EJB3两大商业主流标准的分裂，是大部分人，甚至包括厂商所不希望看到的。 于是最终EJB3的Lead Linda DeMichiel和JDO2的Lead Craig Russell联名发表公开信，宣布了一个合并EJB3和JDO2持久层规范的计划，新的持久层规范将以JSR-220(EJB3.0)的持久层规范为基础，融合JDO2的部分特性。新的持久层规范将进入J2EE1.5之中，独立于EJB存在，既可以inside J2EE容器来使用，也可以脱离J2EE容器，独立的运行。 <br><br>这个新的持久层框架可以说完全是一个政治的产物。EJB Vendors出于自身利益反对JDO，使得JDO没有办法成为J2EE的一部分，然而标准的分裂也是大部分人更加不希望看到的，于是最终JDO成了政治斗争的牺牲品。从表面上来看，JDO和EJB3.0 EntityBean都将被新的持久层框架取代，似乎JDO并没有吃亏，但实际上JDO2标准已经成熟，部分JDO领导厂商的产品已经蓄始待发，而EJB3.0 EntityBean还处于Early Draft，等待产品诞生至少也是一年之后的事情了；另外值得耐人寻味的是，新的持久层框架将基于当前EJB3.0 EntityBean，再结合JDO2的规范，并且将处于EJB3.0 EG的控制之下，再加入一些JDO2 EG的成员。因此可以看出来新的持久层框架无疑还是以EJB3.0 EG为主导进行制定的。 <br><br>从长远来看，EJB3和JDO2的政治斗争对双方都有好处，长期分裂带来的后果对双方的发展都不利，然而从短期来看，JDO2确实是在这场政治斗争中败下阵来。最直接的体现就是，已经有一些JDO的用户对JDO的前景产生了动摇和迷茫，不少的JDO爱好者更是直言JDO将死。 <br><br>不过对JDO来说，事情未必如此悲观。因为新的持久层框架的最终发布最快也要在2005年夏天，这还是乐观的估计，比较广泛的使用则是2006年的事情了。并且如果新的持久层框架还是像EJB3 EntityBean那样严重依赖J2SE5.0的annotation的话，无疑将无法在很多当前运行的系统和遗留系统上使用。这些都是JDO2的市场生存空间。有了这段时间的缓冲，JDO Vendor将可以平缓的转变为一个J2EE1.5持久层框架的供应商，面临更加广阔的企业客户群体。 <br><br>TopLink是一个老牌的O/R Mapping软件了，自从被Oracle收购之后，又增加了对Oracle数据库的良好支持，和对Oracle AS EntityBean的支持。Oracle提供了TopLink的图形设计环境，可以使得设计好的TopLink域模型既可以被单独用在TopLink中，也可以被用在EJB CMP中。因此看来TopLink也走了一条和Hibernate同样策略的路。 <br><br>TopLink的问题在于相比Hibernate的开源和免费的优势来说，TopLink既不开源，售价又不菲上。本来商业软件TopLink应该在技术支持和商业宣传策略上拥有足够的优势，然而Oracle公司毕竟是一个以数据库为核心产品的公司，其他的一切产品都是为了数据库销售业绩而服务的。在Oracle产品线中处于一个从属地位的TopLink，由于先天不足，只能眼睁睁看着Hibernate的日益壮大而无所作为，因此TopLink更多的被局限在购买了Oracle数据库，并且绑定Oracle数据库的用户群体中。 <br><br>J2EE1.5的新持久层规范将毫无悬念的成为未来持久层框架的主流API，无论是Hibernate，JDO，还是TopLink终将兼容这个主流商业API。在当前的这三种持久层API当中，Hibernate无疑是最有前途的。这是因为： <br><br>1、新的持久层规范将基于EJB3.0 EntityBean规范，这意味着仍将以Hibernate的设计理念为基础 <br>2、JBoss对EJB3.0规范跟随的步伐非常紧密，在规范制定过程中就不断的发布参考实现产品，因此可以对对EJB3.0规范产生比较大的影响力。 <br>3、根据内部泄漏出来的小道消息，BEA公司的WebLogic9产品线的项目经理已经在用Hibernate2来实现EJB3.0的持久层框架。WebLogic9 beta1预计年底发布，beta2预计明年3月发布，正式产品将紧随EJB3.0规范正式版发布之后的明年秋季发布。 <br><br>综上所述，我们有理由对Hibernate的前途抱有强烈的信心。 <br><br>最后的一个疑问是，既然J2EE1.5的新持久层框架可以脱离J2EE容器运行，那么大家不全部都去用Hibernate的后一套兼容API，而完全放弃Hibernate的原生API了吗？那么是否意味着Hibernate做为一个独立产品的使命彻底终结呢？ <br><br>对于这个问题我的看法是：J2EE1.5的持久层规范要综合各个EJB Vendor，JDO Vendor的意见，要平衡他们之间的利益得失，那么这样一个瞻前顾后的规范必然无法覆盖所有应用场合的全面需要，这不像Hibernate的原生API可以随时根据开发人员的要求增加功能那么灵活。因此我预计Hibernate的原生API以其更加强大的功能仍然会吸引一大批人直接使用原生API，而不是兼容J2EE规范的API。 <br><br>总而言之，对于我们当前的持久层开发来说，最好的办法莫过于坚定的使用DAO层来隔离持久层和业务层逻辑，那么不管未来持久层风云如何变换，但凡基于POJO的持久层框架都可以被我们拿来任意替换。</span><br><br>转载来源：<a href="http://www.hibernate.org.cn/viewtopic.php?t=8146&amp;postdays=0&amp;postorder=asc&amp;start=0"><br>http://www.hibernate.org.cn/viewtopic.php?t=8146&amp;postdays=0&amp;postorder=asc&amp;start=0</a></font><img src ="http://www.blogjava.net/terry-zj/aggbug/21248.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 11:14 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21248.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的三种查询方式（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 02:27:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21233.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21233.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21233.html</trackback:ping><description><![CDATA[<SPAN class=postdetails><FONT size=2><SPAN style="COLOR: red">（一）HQL</SPAN> <BR>HQL：Hibernate Qusery Language，如果你已经熟悉它，就会发现它跟SQL非常相像。不过 你不要被表面的假象迷惑，HQL是面向对象的（OO，用生命的眼光看待每一个对象，他们是如此 鲜活）。如果你对JAVA和SQL语句有一定了解的话，那么HQL对你简直易如反掌，你完全可以利用在公车上的时间掌握它。 <BR><BR>以下从几个方面进行慢慢深入： <BR><BR>1。大小些敏感 <BR>大家知道SQL-92 Query是对大小写不敏感的，但是在HQL（前面提到它是OO的）中对对象类的名称和属性确实大小写敏感的（符合java编程语法）。 <BR>HQL 子句本身大小写无关，但是其中出现的类名和属性名必须注意大小写区分 <BR>如：sElect cat.name from Cat as cat和select cat.name from Cat as cat是一样的 <BR>但是： <BR>sElect cat.name from CAT as cat和select cat.name from Cat as cat确实不一样的。 <BR><BR>2。from语句 <BR>最简单的： <BR>from eg.Cat <BR>它只是简单的返回所有eg.Cat的实例,通常我们此时会为eg.Cat其个别名，因为在query的其余部分可能会用到(参看上边关于大小写敏感时的例子情形)，如： <BR>from eg.Cat as cat 这里as可以省略。 <BR><BR>上边只是单表查询，多表的情况如下写法： <BR>from eg.Cat, eg.Dog <BR>from eg.Cat as cat, eg.Dog as dog <BR><BR>3。join相关 <BR>(inner) join <BR>left (outer) join <BR>right (outer) join <BR>full join <BR>HQL同样对SQL中的这些特性支持 <BR>下面插播一个小话题，关于上边的那些特性，我一直都没怎么用，今天既然说到这里，就想把上边的几个特性的用法说一下，也算对自己的一个补充： <BR><BR>假设有两个表：部门、员工，下面列举一些数据： <BR>员工(Employee)： <BR>ID Name DepNo <BR>001 Jplateau 01 <BR>002 Jony 01 <BR>003 Camel 02 <BR>部门(Department)： <BR>ID Name <BR>01 研发部 <BR>02 营销部 <BR><BR>在Hibernate中我们操纵的都是对象，所以我们操纵的是部门类和员工类 <BR><BR><BR><BR><BR><BR>1).(inner) join <BR>select employee.ID as id1,employee.Name as name1, <BR>department.ID as id2,department.Name as name2 from Employee as employee <BR>join Department as department on employee.DepNo=department.ID (注意到条件语句我用on 没有用where) <BR>那么执行结果是什么呢？ <BR>id1 name1 id2 name2 <BR>++++++++++++++++++++++++++++++++++++++ <BR>001 Jplateau 01 研发部 <BR>002 Jony 01 研发部 <BR><BR>2).left (outer) join <BR>select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name <BR>as name2 from Employee as employee left join Department as department on employee.DepNo= <BR>department.ID <BR>那么执行结果又该是什么呢？ <BR>id1 name1 id2 name2 <BR>++++++++++++++++++++++++++++++++++++++ <BR>001 Jplateau 01 研发部 <BR>002 Jony 01 研发部 <BR>003 Camel null null <BR>{就是说此时我要已第一个表的记录多少为准，第二个表中没有相应纪录的时候填充null} <BR>3). right (outer) join <BR>select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name <BR>as name2 from Employee as employee right join Department as department on employee.DepNo= <BR>department.ID <BR>那么执行结果又该是什么呢？ <BR>id1 name1 id2 name2 <BR>++++++++++++++++++++++++++++++++++++++ <BR>001 Jplateau 01 研发部 <BR>002 Jony 01 研发部 <BR>null null 02 营销部 <BR>{就是说此时我要已第二个表的记录多少为准，第一个表中没有相应纪录的时候填充null} <BR><BR>4。select语句 <BR>就是要确定你要从查询中返回哪些对象或者哪些对象的属性。写几个例子吧： <BR>select employee form Employee as employee <BR>select employee form Employee as employee where employee.Name like 'J%' <BR>select employee.Name form Employee as employee where employee.Name like 'J%' <BR>select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name <BR>as name2 from Employee as employee right join Department as department on employee.DepNo= <BR>department.ID <BR><BR>select elements(employee.Name) from Employee as employee <BR>（不明白elements到底是做什么用的？望给于说明） <BR>等等 <BR><BR>5。数学函数 <BR>JDO目前好像还不支持此类特性。 <BR>avg(...), sum(...), min(...), max(...) <BR><BR>count(*) <BR><BR>count(...), count(distinct ...), count(all...) <BR><BR>其用法和SQL基本相同 <BR><BR>select distinct employee.name from Employee as employee <BR>select count(distinct employee.name),count(employee) from Employee as employee <BR><BR>6。polymorphism (暂时不知道如何解释？) <BR>from com.test.Animal as animal <BR>不光得到所有Animal得实例，而且可以得到所有Animal的子类（如果我们定义了一个子类Cat） <BR>一个比较极端的例子 <BR>from java.lang.Object as o <BR>可以得到所有持久类的实例 <BR><BR>7。where语句 <BR>定义查询语句的条件，举几个例子吧： <BR>from Employee as employee where employee.Name='Jplateau' <BR>from Employee as employee where employee.Name like 'J%' <BR>from Employee as employee where employee.Name like '%u' <BR>在where语句中“=”不光可以比较对象的属性，也可以比较对象，如： <BR>select animal from com.test.Animal as animal where animal.name=dog <BR><BR>8。表达式 <BR><BR>在SQL语句中大部分的表达式在HQL中都可以使用： <BR>mathematical operators +, -, *, / <BR><BR>binary comparison operators =, &gt;=, &lt;=, &lt;&gt;, !=, like <BR><BR>logical operations and, or, not <BR><BR>string concatenation || <BR><BR>SQL scalar functions like upper() and lower() <BR><BR>Parentheses ( ) indicate grouping <BR><BR>in, between, is null <BR><BR>JDBC IN parameters ? <BR><BR>named parameters :name, :start_date, <IMG alt=Mad src="http://www.fankai.com/images/smiles/icon_mad.gif" border=0>1 （这种应该是另一种"?"的变通解决方法） <BR><BR>SQL literals 'foo', 69, '1970-01-01 10:00:01.0' <BR><BR>Java public static final constants eg.Color.TABBY <BR><BR>其他不必解释了，在这里我只想对查询中的参数问题说明一下： <BR>大家知道在SQL中进行传递参数进行查询的时候，我们通常用PreparedStatement，在语句中写一大堆的“？”， <BR>在hql中也可以用这种方法，如： <BR>List mates = sess.find( <BR>"select employee.name from Employee as employee " + <BR>"where employee.Name=? ", <BR>name, <BR>Hibernate.STRING <BR>); <BR>(说明：上面利用Session里的find方法，在hibernate的api Session中重载了很多find方法，它可以满足你多种形式的查询) <BR>上边是一个参数的情形，这种情况下紧接着引入参数和定义参数的类型，当为多个参数，调用另一个find方法，它的后两个 <BR>参数都是数组的形式。 <BR><BR>还有另外一种方法来解决上边的问题，JDO也有这样的方法，不过和hibernate的表现形式上有差别，但他们两个骨子里却是 <BR>一样的，如： <BR>Query q = sess.createQuery("select employee.name from Employee as employee where employee.Name=:name"); <BR>q.setString("name", "Jplateau"); <BR>//当有多个参数的时候在此逐一定义 <BR>Iterator employees = q.iterate(); <BR><BR>9。order 语句 <BR>和sql语句没什么差别，如： <BR>select employee.name from Employee as employee where employee.Name like 'J%' order by employee.ID desc (或者asc) <BR><BR>10。group by 语句 <BR>同样和sql语句没什么差别，如： <BR><BR>select employee.name,employee.DepNo from Employee as employee group by employee.DepNo <BR><BR>select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) from eg.Foo foo group by foo.id <BR>{Note: You may use the elements and indices constructs inside a select clause, even on databases with no subselects.} <BR>谁帮我解释一下上边两句，谢过！ <BR><BR>11。子查询 <BR>hibernate同样支持子查询，写几个例子： <BR><BR>from eg.Cat as fatcat where fatcat.weight &gt; ( select avg(cat.weight) from eg.DomesticCat cat ) <BR><BR><SPAN style="COLOR: red">（二）条件查询</SPAN> <BR>Session osession = ownerSession.getSession(); <BR>Criteria criteria = osession.createCriteria(Owner.class); <BR>criteria.add(Expression.eq("age", new Integer(100))); <BR>criteria.setFirstResult(2); //从返回结果的第二条记录开始的5条记录 <BR>criteria.setMaxResults(5); <BR>List lc=criteria.list(); <BR>System.out.println("条件查询"); <BR>System.out.println(lc.size()); <BR><BR><SPAN style="COLOR: red">（三）原生sql语句查询 </SPAN><BR>Query query=osession.createSQLQuery("select {owner.*} from Owner as owner", "owner", Owner.class); <BR>query.setMaxResults(4); <BR>List l=query.list(); <BR>System.out.println("原生sql语句查询"); <BR>System.out.println(l.get(0)); </FONT><BR></SPAN><img src ="http://www.blogjava.net/terry-zj/aggbug/21233.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 10:27 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21233.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate3主要的新特性（转载）</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 24 Nov 2005 02:26:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/21232.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/21232.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/21232.html</trackback:ping><description><![CDATA[Hibernate3主要的新特性包括：<BR><BR>1:实现了EJB3风格的持久化操作。在原有的saveOrUpdate()和saveOrUpdateCopy()两个方法之外，又提供了EJB3风格的create()和merge()两个操作。<BR><BR>2:提供更强的映射灵活性。允许将一个类映射到多张表，允许混合使用“每个继承体系一张表”和“每个子类一张表”的映射策略，等等。<BR><BR>3:支持存储过程和手写SQL，并且可以用手写SQL替代Hibernate自动生成的SQL语句。<BR><BR>4:基于AST（抽象语法树）的HQL解析。<BR><BR>5:字段级的懒式获取。每个属性都可以在映射描述符中声明“lazy=true”，这样声明的属性会到真正使用时才从数据库加载。不过，实现这项功能需要首先在编译期对字节码进行增强。<BR><BR>具体特性请访问<A href="http://www.hibernate.org/200.html">http://www.hibernate.org/200.html</A><img src ="http://www.blogjava.net/terry-zj/aggbug/21232.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-24 10:26 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/24/21232.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 学习准备</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/21/20804.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Mon, 21 Nov 2005 10:00:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/21/20804.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/20804.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/21/20804.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/20804.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/20804.html</trackback:ping><description><![CDATA[<P><STRONG><FONT size=4>Hibernate源代码包简要介绍 </FONT></STRONG></P>
<P><FONT size=2>net.sf.hibernate.* </FONT></P>
<P><FONT size=2>该包的类基本上都是接口类和异常类 </FONT></P>
<P><FONT size=2>net.sf.hibernate.cache.* </FONT></P>
<P><FONT size=2>JCS的实现类 </FONT></P>
<P><FONT size=2>net.sf.hibernate.cfg.* </FONT></P>
<P><FONT size=2>配置文件读取类 </FONT></P>
<P><FONT size=2>net.sf.hibernate.collection.* </FONT></P>
<P><FONT size=2>Hibernate集合接口实现类，例如List，Set，Bag等等，Hibernate之所以要自行编写集合接口实现类是为了支持lazy loading </FONT></P>
<P><FONT size=2>net.sf.hibernate.connection.* </FONT></P>
<P><FONT size=2>几个数据库连接池的Provider </FONT></P>
<P><FONT size=2>net.sf.hibernate.dialect.* </FONT></P>
<P><FONT size=2>支持多种数据库特性，每个Dialect实现类代表一种数据库，描述了该数据库支持的数据类型和其它特点，例如是否有AutoIncrement，是否有Sequence，是否有分页sql等等 </FONT></P>
<P><FONT size=2>net.sf.hibernate.eg.* </FONT></P>
<P><FONT size=2>Hibernate文档中用到的例子 </FONT></P>
<P><FONT size=2>net.sf.hibernate.engine.* </FONT></P>
<P><FONT size=2>这个包的类作用比较散 </FONT></P>
<P><FONT size=2>net.sf.hibernate.expression.* </FONT></P>
<P><FONT size=2>HQL支持的表达式 </FONT></P>
<P><FONT size=2>net.sf.hibernate.hq.* </FONT></P>
<P><FONT size=2>HQL实现 </FONT></P>
<P><FONT size=2>net.sf.hibernate.id.* </FONT></P>
<P><FONT size=2>ID生成器 </FONT></P>
<P><FONT size=2>net.sf.hibernate.impl.* </FONT></P>
<P><FONT size=2>最核心的包，一些重要接口的实现类，如果Session，SessionFactory，Query等 </FONT></P>
<P><FONT size=2>net.sf.hibernate.jca.* </FONT></P>
<P><FONT size=2>JCA支持，把Session包装为支持JCA的接口实现类 </FONT></P>
<P><FONT size=2>net.sf.hibernate.jmx.* </FONT></P>
<P><FONT size=2>我不懂JMX，只知道JMX是用来编写App Server的管理程序的，大概是JMX部分接口的实现，使得App Server可以通过JMX接口管理Hibernate </FONT></P>
<P><FONT size=2>net.sf.hibernate.loader.* </FONT></P>
<P><FONT size=2>也是很核心的包，主要是生成sql语句的 </FONT></P>
<P><FONT size=2>net.sf.hibernate.lob.* </FONT></P>
<P><FONT size=2>Blob和Clob支持 </FONT></P>
<P><FONT size=2>net.sf.hibernate.mapping.* </FONT></P>
<P><FONT size=2>hbm文件的属性实现 </FONT></P>
<P><FONT size=2>net.sf.hibernate.metadata.* </FONT></P>
<P><FONT size=2>PO的Meta实现 </FONT></P>
<P><FONT size=2>net.sf.hibernate.odmg.* </FONT></P>
<P><FONT size=2>ODMG是一个ORM标准，这个包是ODMG标准的实现类 </FONT></P>
<P><FONT size=2>net.sf.hibernate.persister.* </FONT></P>
<P><FONT size=2>核心包，实现持久对象和表之间的映射 </FONT></P>
<P><FONT size=2>net.sf.hibernate.proxy.* </FONT></P>
<P><FONT size=2>Proxy和Lazy Loading支持 </FONT></P>
<P><FONT size=2>net.sf.hibernate.ps.* </FONT></P>
<P><FONT size=2>该包是PreparedStatment Cache </FONT></P>
<P><FONT size=2>net.sf.hibernate.sql.* </FONT></P>
<P><FONT size=2>生成JDBC sql语句的包 </FONT></P>
<P><FONT size=2>net.sf.hibernate.test.* </FONT></P>
<P><FONT size=2>测试类，你可以用junit来测试Hibernate </FONT></P>
<P><FONT size=2>net.sf.hibernate.tool.hbm2ddl.* </FONT></P>
<P><FONT size=2>用hbm配置文件生成DDL </FONT></P>
<P><FONT size=2>net.sf.hibernate.transaction.* </FONT></P>
<P><FONT size=2>Hibernate Transaction实现类 </FONT></P>
<P><FONT size=2>net.sf.hibernate.type.* </FONT></P>
<P><FONT size=2>Hibernate中定义的持久对象的属性的数据类型 </FONT></P>
<P><FONT size=2>net.sf.hibernate.util.* </FONT></P>
<P><FONT size=2>一些工具类，作用比较散 </FONT></P>
<P><FONT size=2>net.sf.hibernate.xml.* </FONT></P>
<P><FONT size=2>XML数据绑定<BR><BR><STRONG><FONT size=4>Hibernate入门 - 基础配置</FONT></STRONG><BR></FONT></P><SPAN class=postbody>Hibernate配置文件可以有两种格式，一种是hibernate.properties，另一种是hibernate.cfg.xml。后者稍微方便一些，当增加hbm映射文件的时候，可以直接在hibernate.cfg.xml里面增加，不必像hibernate.properties必须在初始化代码中加入。但不管怎么说，两种的配置项都是一样的，下面详细介绍： <BR><BR>在Hibernate的src目录下有一个hibernate.properties模板，我们不必自己从头写，修改模板就可以了<IMG alt=Smile src="http://www.javaeye.com/images/smiles/icon_smile.gif" border=0> <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">query</SPAN>.<SPAN style="COLOR: #000000">substitutions</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>true</SPAN> <SPAN style="COLOR: #000000" ?>1</SPAN>, <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>false</SPAN> <SPAN style="COLOR: #000000" ?>0</SPAN>, yes <SPAN style="COLOR: #0000ff">'Y'</SPAN>, no <SPAN style="COLOR: #0000ff">'N'</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>这个配置意思是当你在Hibernate里面输入true的时候，Hibernate会转化为0插入数据库，当你在Hibernate里面输入false的时候，Hibernate会转化为1插入数据库，后面的Y，N同理。对于某些数据库，例如Oracle来说，没有boolean数据类型，就是采用1代表true，0代表false，因此使用这个配置在Hibernate里面直接用true/false会非常直观。 <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">dialect</SPAN> net.<SPAN style="COLOR: #000000">sf</SPAN>.<SPAN style="COLOR: #000000">hibernate</SPAN>.<SPAN style="COLOR: #000000">dialect</SPAN>.<SPAN style="COLOR: #000000">MySQLDialect</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">driver_class</SPAN> org.<SPAN style="COLOR: #000000">gjt</SPAN>.<SPAN style="COLOR: #000000">mm</SPAN>.<SPAN style="COLOR: #000000">mysql</SPAN>.<SPAN style="COLOR: #000000">Driver</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">driver_class</SPAN> com.<SPAN style="COLOR: #000000">mysql</SPAN>.<SPAN style="COLOR: #000000">jdbc</SPAN>.<SPAN style="COLOR: #000000">Driver</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">url</SPAN> jdbc:mysql:<SPAN style="COLOR: #6666ff">///test</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">username</SPAN> root <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">password</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>这是一个连接MySQL数据库的例子，很直观，不必解释，不同的数据库的连接参数模板中全部给出了。 <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">pool_size</SPAN> <SPAN style="COLOR: #000000" ?>1</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">statement_cache</SPAN>.<SPAN style="COLOR: #000000">size</SPAN> 25</DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>这是Hibernate自带的连接池的配置参数，在默认情况下将采用。意义很直观，不多解释。只是提醒一点，Hibernate这个连接池是非常原始非常简单的连接池，如果你在项目中用Hibernate的话，建议你首选App Server的连接池，次选Hibernate带的DBCP连接池。自带的连接池应该做为末选。 <BR><BR>如果你采用DBCP连接池，除了要配置DBCP连接池以外，还需要取消掉下行的注释： <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">provider_class</SPAN> net.<SPAN style="COLOR: #000000">sf</SPAN>.<SPAN style="COLOR: #000000">hibernate</SPAN>.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">DBCPConnectionProvider</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>其它的连接池同理。 <BR><BR>如果采用App Server的连接池，假设App Server连接池的DataSource的JNDI名称为"mypool"的话，配置应该如下： <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">dialect</SPAN> net.<SPAN style="COLOR: #000000">sf</SPAN>.<SPAN style="COLOR: #000000">hibernate</SPAN>.<SPAN style="COLOR: #000000">dialect</SPAN>.<SPAN style="COLOR: #000000">MySQLDialect</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">datasource</SPAN> mypool <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">provider_class</SPAN> net.<SPAN style="COLOR: #000000">sf</SPAN>.<SPAN style="COLOR: #000000">hibernate</SPAN>.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">DatasourceConnectionProvider</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>其它参数就不必写了，因为已经在App Server配置连接池的时候指定好了。 <BR><BR>如果你不是在App Server环境中使用Hibernate，例如远程客户端程序，但是你又想用App Server的数据库连接池，那么你还需要配置JNDI的参数，例如Hibernate连接远程Weblogic上的数据库连接池： <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">dialect</SPAN> net.<SPAN style="COLOR: #000000">sf</SPAN>.<SPAN style="COLOR: #000000">hibernate</SPAN>.<SPAN style="COLOR: #000000">dialect</SPAN>.<SPAN style="COLOR: #000000">MySQLDialect</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">datasource</SPAN> mypool <BR>hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">provider_class</SPAN> net.<SPAN style="COLOR: #000000">sf</SPAN>.<SPAN style="COLOR: #000000">hibernate</SPAN>.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">DatasourceConnectionProvider</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">jndi</SPAN>.<SPAN style="COLOR: #000000">class</SPAN> weblogic.<SPAN style="COLOR: #000000">jndi</SPAN>.<SPAN style="COLOR: #000000">WLInitialContextFactory</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">jndi</SPAN>.<SPAN style="COLOR: #000000">url</SPAN> t3:<SPAN style="COLOR: #6666ff">//servername:7001/</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>最后，如果你需要在EJB或者JTA中使用Hibernate，需要取消下行的注释： <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">transaction</SPAN>.<SPAN style="COLOR: #000000">factory_class</SPAN> net.<SPAN style="COLOR: #000000">sf</SPAN>.<SPAN style="COLOR: #000000">hibernate</SPAN>.<SPAN style="COLOR: #000000">transaction</SPAN>.<SPAN style="COLOR: #000000">JTATransactionFactory</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>杂项配置： <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">show_sql</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>false</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>是否将Hibernate发送给数据库的sql显示出来，这是一个非常非常有用处的功能。当你在调试Hibernate的时候，让Hibernate打印sql语句，可以帮助你迅速解决问题。 <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>#hibernate.<SPAN style="COLOR: #000000">connection</SPAN>.<SPAN style="COLOR: #000000">isolation</SPAN> 4</DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>指定数据库的隔离级别，往往不同的数据库有自己定义的隔离级别，未必是Hibernate的设置所能更改的，所以也不必去管它了。 <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>hibernate.<SPAN style="COLOR: #000000">jdbc</SPAN>.<SPAN style="COLOR: #000000">fetch_size</SPAN> <SPAN style="COLOR: #000000" ?>50</SPAN> <BR>hibernate.<SPAN style="COLOR: #000000">jdbc</SPAN>.<SPAN style="COLOR: #000000">batch_size</SPAN> 25</DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>这两个选项非常非常非常重要！！！将严重影响Hibernate的CRUD性能! <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>C = create, R = read, U = update, D = delete</DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。例如一次查询1万条记录，对于Oracle的JDBC驱动来说，是不会1次性把1万条取出来的，而只会取出Fetch Size条数，当纪录集遍历完了这些记录以后，再去数据库取Fetch Size条数据。因此大大节省了无谓的内存消耗。当然Fetch Size设的越大，读数据库的次数越少，速度越快；Fetch Size越小，读数据库的次数越多，速度越慢。这有点像平时我们写程序写硬盘文件一样，设立一个Buffer，每次写入Buffer，等Buffer满了以后，一次写入硬盘，道理相同。 <BR><BR>Oracle数据库的JDBC驱动默认的Fetch Size=10，是一个非常保守的设定，根据我的测试，当Fetch Size=50的时候，性能会提升1倍之多，当Fetch Size=100，性能还能继续提升20%，Fetch Size继续增大，性能提升的就不显著了。因此我建议使用Oracle的一定要将Fetch Size设到50。 <BR><BR>不过并不是所有的数据库都支持Fetch Size特性，例如MySQL就不支持。MySQL就像我上面说的那种最坏的情况，他总是一下就把1万条记录完全取出来，内存消耗会非常非常惊人！这个情况就没有什么好办法了 <IMG alt=Sad src="http://www.javaeye.com/images/smiles/icon_sad.gif" border=0> <BR><BR>Batch Size是设定对数据库进行批量删除，批量更新和批量插入的时候的批次大小，有点相当于设置Buffer缓冲区大小的意思。Batch Size越大，批量操作的向数据库发送sql的次数越少，速度就越快。我做的一个测试结果是当Batch Size=0的时候，使用Hibernate对Oracle数据库删除1万条记录需要25秒，Batch Size = 50的时候，删除仅仅需要5秒！！！ 可见有多么大的性能提升！很多人做Hibernate和JDBC的插入性能测试会奇怪的发现Hibernate速度至少是JDBC的两倍，就是因为Hibernate使用了Batch Insert，而他们写的JDBC没有使用Batch的缘故。以我的经验来看，Oracle数据库 Batch Size = 30 的时候比较合适，50也不错，性能会继续提升，50以上，性能提升的非常微弱，反而消耗内存更加多，就没有必要了。 <BR><BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>#hibernate.<SPAN style="COLOR: #000000">jdbc</SPAN>.<SPAN style="COLOR: #000000">use_scrollable_resultset</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>true</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>设定是否可以使用JDBC2.0规范的可滚动结果集，这对Hibernate的分页显示有一定的作用，默认就好了。 <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR>#hibernate.<SPAN style="COLOR: #000000">cglib</SPAN>.<SPAN style="COLOR: #000000">use_reflection_optimizer</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>false</SPAN></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody>
<P>默认打开，启用cglib反射优化。cglib是用来在Hibernate中动态生成PO字节码的，打开优化可以加快字节码构造的速度。 <BR><BR>不过，当你在调试程序过程中，特别是和proxy，lazy loading相关的应用中，代码出错，但是出错提示信息有语焉不详，那么你可以把cglib优化关掉，这样Hibernate会输出比较详细的调试信息，帮助你debug。<BR><BR><BR><STRONG>Hibernate的灵活性也是一把双刃剑</STRONG>，用好了就特别舒服，用不好，就特别头疼。把我原来在jdon一个帖子转过来，谈到了这个问题： </P>
<P>一、Hibernate是JDBC的轻量级的对象封装，它是一个独立的对象持久层框架，和App Server，和EJB没有什么必然的联系。Hibernate可以用在任何JDBC可以使用的场合，例如Java应用程序的数据库访问代码，DAO接口的实现类，甚至可以是BMP里面的访问数据库的代码。从这个意义上来说，Hibernate和EB不是一个范畴的东西，也不存在非此即彼的关系。 </P>
<P>二、Hibernate是一个和JDBC密切关联的框架，所以Hibernate的兼容性和JDBC驱动，和数据库都有一定的关系，但是和使用它的Java程序，和App Server没有任何关系，也不存在兼容性问题。 </P>
<P>三、Hibernate不能用来直接和Entity Bean做对比，只有放在整个J2EE项目的框架中才能比较。并且即使是放在软件整体框架中来看，Hibernate也是做为JDBC的替代者出现的，而不是Entity Bean的替代者出现的，让我再列一次我已经列n次的框架结构： </P>
<P>传统的架构： <BR>1) Session Bean &lt;-&gt; Entity Bean &lt;-&gt; DB <BR>为了解决性能障碍的替代架构： <BR>2) Session Bean &lt;-&gt; DAO &lt;-&gt; JDBC &lt;-&gt; DB <BR>使用Hibernate来提高上面架构的开发效率的架构： <BR>3) Session Bean &lt;-&gt; DAO &lt;-&gt; Hibernate &lt;-&gt; DB </P>
<P>就上面3个架构来分析： <BR>1、内存消耗：采用JDBC的架构2无疑是最省内存的，Hibernate的架构3次之，EB的架构1最差。 </P>
<P>2、运行效率：如果JDBC的代码写的非常优化，那么JDBC架构运行效率最高，但是实际项目中，这一点几乎做不到，这需要程序员非常精通JDBC，运用Batch语句，调整PreapredStatement的Batch Size和Fetch Size等参数，以及在必要的情况下采用结果集cache等等。而一般情况下程序员是做不到这一点的。因此Hibernate架构表现出最快的运行效率。EB的架构效率会差的很远。 </P>
<P>3、开发效率：在有JBuilder的支持下以及简单的项目，EB架构开发效率最高，JDBC次之，Hibernate最差。但是在大的项目，特别是持久层关系映射很复杂的情况下，Hibernate效率高的惊人，JDBC次之，而EB架构很可能会失败。 </P>
<P>4、分布式，安全检查，集群，负载均衡的支持 <BR>由于有SB做为Facade，3个架构没有区别。 </P>
<P>四、EB和Hibernate学习难度在哪里？ </P>
<P>EB的难度在哪里？不在复杂的XML配置文件上，而在于EB运用稍微不慎，就有严重的性能障碍。所以难在你需要学习很多EJB设计模式来避开性能问题，需要学习App Server和EB的配置来优化EB的运行效率。做EB的开发工作，程序员的大部分精力都被放到了EB的性能问题上了，反而没有更多的精力关注本身就主要投入精力去考虑的对象持久层的设计上来。 </P>
<P>Hibernate难在哪里？不在Hibernate本身的复杂，实际上Hibernate非常的简单，难在Hibernate太灵活了。 </P>
<P>当你用EB来实现持久层的时候，你会发现EB实在是太笨拙了，笨拙到你根本没有什么可以选择的余地，所以你根本就不用花费精力去设计方案，去平衡方案的好坏，去费脑筋考虑选择哪个方案，因为只有唯一的方案摆在你面前，你只能这么做，没得选择。 </P>
<P>Hibernate相反，它太灵活了，相同的问题，你至少可以设计出十几种方案来解决，所以特别的犯难，究竟用这个，还是用那个呢？这些方案之间到底有什么区别呢？他们的运行原理有什么不同？运行效率哪个比较好？光是主键生成，就有七八种方案供你选择，你为难不为难？集合属性可以用Set，可以用List，还可以用Bag，到底哪个效率高，你为难不为难？查询可以用iterator，可以用list，哪个好，有什么区别？你为难不为难？复合主键你可以直接在hbm里面配置，也可以自定义CustomerType，哪种比较好些？你为难不为难？对于一个表，你可以选择单一映射一个对象，也可以映射成父子对象，还可以映射成两个1:1的对象，在什么情况下用哪种方案比较好，你为难不为难？ </P>
<P>这个列表可以一直开列下去，直到你不想再看下去为止。当你面前摆着无数的眼花缭乱的方案的时候，你会觉得幸福呢？还是悲哀呢？如果你是一个负责的程序员，那么你一定会仔细研究每种方案的区别，每种方案的效率，每种方案的适用场合，你会觉得你已经陷入进去拔不出来了。如果是用EB，你第一秒种就已经做出了决定，根本没得选择，比如说集合属性，你只能用Collection，如果是Hibernate，你会在Bag，List和Set之间来回犹豫不决，甚至搞不清楚的话，程序都没有办法写。</SPAN></P><img src ="http://www.blogjava.net/terry-zj/aggbug/20804.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-21 18:00 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/21/20804.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个类在运行的时候可以知道自己所在的目录吗？</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/17/20286.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 17 Nov 2005 09:50:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/17/20286.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/20286.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/17/20286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/20286.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/20286.html</trackback:ping><description><![CDATA[<P>今天为一个Batch类配置Log4j的时候。遇到一个问题：log4j.properties放在Batch类的相同目录下。<BR>怎样在运行时动态的取得这个配置文件。<BR>后来解决的办法很简单：<BR>Properties prop = ResourceManager.getResourceAsProperties("jp.co.swics.edinaiji.batch.log4j");&nbsp;<BR> PropertyConfigurator.configure(prop);<BR>log.debug("[Standard Logger is ready.]");<BR><BR>不过由此想到了一个问题。一个类在运行的时候可以知道自己所在的目录吗？</P><img src ="http://www.blogjava.net/terry-zj/aggbug/20286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-17 17:50 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/17/20286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用java复制移动文件</title><link>http://www.blogjava.net/terry-zj/archive/2005/11/17/20258.html</link><dc:creator>Terry的Blog</dc:creator><author>Terry的Blog</author><pubDate>Thu, 17 Nov 2005 08:03:00 GMT</pubDate><guid>http://www.blogjava.net/terry-zj/archive/2005/11/17/20258.html</guid><wfw:comment>http://www.blogjava.net/terry-zj/comments/20258.html</wfw:comment><comments>http://www.blogjava.net/terry-zj/archive/2005/11/17/20258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/terry-zj/comments/commentRss/20258.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/terry-zj/services/trackbacks/20258.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Moving a File to Another Directory<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param srcFile&nbsp; eg: c:\windows\abc.txt<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param destPath eg: c:\temp<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @return success <BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public static boolean move(String srcFile, String destPath){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // File (or directory) to be moved<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File file = new File(srcFile);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Destination directory<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File dir = new File(destPath);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Move file to new directory<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean success = file.renameTo(new File(dir, file.getName()));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return success;<BR>&nbsp;&nbsp;&nbsp; }<img src ="http://www.blogjava.net/terry-zj/aggbug/20258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/terry-zj/" target="_blank">Terry的Blog</a> 2005-11-17 16:03 <a href="http://www.blogjava.net/terry-zj/archive/2005/11/17/20258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>