<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>looxiaohu</title>
    <description></description>
    <link>http://looxiaohu.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>selectmethod=cursor的含义及其使用 </title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/235840" style="color:red;">http://looxiaohu.javaeye.com/blog/235840</a>&nbsp;
          发表时间: 2008年09月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          连接字符串中碰到的SelectMethod=cursor<br />关键字: selectmethod=cursor的含义及其使用 <br />今天在数据库连接字符串中看到了selectMethod=cursor<br />知道了这个用法如下:<br />作用:以利用服务器端的游标加快速度<br />使用情况:<br />  1.执行多个Statements的操作的时候用<br />  2.需要手动使用事务的时候使用<br /><br /> <br /><br />以上是在使用sqlserver数据库的连接字符串的时候使用过。<br /><br />例如:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=071008_03;SelectMethod=cursor<br /><br /> <br /><br />但是今天我将其用在oracle数据库的时候，却报出了一下的错误信息: <br /><br />Io 异常: Connection refused(DESCRIPTION=(TMP=)(VSNNUM=169869824)(ERR=12505)(ERROR_STACK=(ERROR=(CODE=12505)(EMFI=4))))<br /><br /> <br /><br />这是个老话题,2002年在使用ejb的bmp就遇到了这个问题<br />连接数据库成功之后，想在一个事务中初始化多个预处理句柄时报错<br />dbConn.setAutoCommit(false)<br />for (int i = 0; i &lt; 5; i++) {<br />pstmt[i] = dbConn.prepareStatement(strPreSQL[i]);<br />错误提示：<br />java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Can't start manual transaction mode because there are cloned connections<br /><br />怀疑MS SQL不能在一个事务中建多个预处理句柄<br />Resolution: <br />You have to add a property to the pool definition, something to do with selectMode=cursor or selectMethod=cursor. Check the driver documentation. Otherwise the driver will not allow more than one statement per connection at any given time<br />微软的专家告诉的<br />This error occurs when you try to execute multiple statements against a SQL Server database with the JDBC driver while in manual transaction mode (AutoCommit=false) and while using the direct (SelectMethod=direct) mode. Direct mode is the default mode for the driver."<br /><br />import java.sql.*;<br />import java.io.*;<br /><br />public class Repro{<br /><br />public static void main(String args[])<br />{<br />try {<br />Connection con;<br />Statement s1 = null;<br />ResultSet r1 = null;<br />Statement s2 = null;<br />ResultSet r2 = null;<br />Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver"); <br />con = DriverManager.getConnection(<br />"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs;SelectMethod=Direct;User=User;Password=Password");<br />//fix 1<br />//"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs;SelectMethod=Cursor;User=User;Password=Password");<br />con.setAutoCommit(false);<br /><br />try {<br />s1 = con.createStatement();<br />r1 = s1.executeQuery("SELECT * FROM authors");<br /><br />//fix 2<br />//r1.close();<br />//s1.close();<br /><br />s2 = con.createStatement();<br />r2 = s2.executeQuery("SELECT * FROM publishers");<br />}<br />catch (SQLException ex)<br />{<br />System.out.println(ex); <br />}<br /><br />}<br />catch (Exception e)<br />{<br />e.printStackTrace();<br />}<br />}<br />}<br />用SQL Server驱动一次select很多数据最好在connection string中加上SelectMethod=Cursor,以利用服务器端游标加快速度,其实不只sqlserver,oracle的jdbc,只要使用PreparedStatement,驱动默认就使用游标,sqlserver则不然，必须使用SelectMethod=Cursor才打开游标。<br />这点在使用jotm时,并且使用Xapool时,必须修改DataSourceFactory，把PreparedStatementPool禁掉,否则记录插的太快了,很可能是游标没来得及关闭<br />即使不使用jotm,大量向oracle插入数据,例如每毫秒1条,也会引发游标用完,所以大量插入数据时,应该使用oracle的批处理batchupdate.<br />可惜的是,微软的sqlserver的jdbc驱动不支持这个属性
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/235840#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 02 Sep 2008 17:27:08 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/235840</link>
        <guid>http://looxiaohu.javaeye.com/blog/235840</guid>
      </item>
      <item>
        <title>【经典】JSP内置对象</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/230726" style="color:red;">http://looxiaohu.javaeye.com/blog/230726</a>&nbsp;
          发表时间: 2008年08月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1.request对象<br /><br />     客户端的请求信息被封装在request对象中，通过它才能了解到客户的需求，然后做出响应。它是HttpServletRequest类的实例。<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   object getAttribute(String name) 返回指定属性的属性值 
2   Enumeration getAttributeNames() 返回所有可用属性名的枚举 
3   String getCharacterEncoding() 返回字符编码方式 
4   int getContentLength() 返回请求体的长度（以字节数） 
5   String getContentType() 得到请求体的MIME类型 
6   ServletInputStream getInputStream() 得到请求体中一行的二进制流 
7   String getParameter(String name) 返回name指定参数的参数值 
8   Enumeration getParameterNames() 返回可用参数名的枚举 
9   String[] getParameterValues(String name) 返回包含参数name的所有值的数组 
10   String getProtocol() 返回请求用的协议类型及版本号 
11   String getScheme() 返回请求用的计划名,如:http.https及ftp等 
12   String getServerName() 返回接受请求的服务器主机名 
13   int getServerPort() 返回服务器接受此请求所用的端口号 
14   BufferedReader getReader() 返回解码过了的请求体 
15   String getRemoteAddr() 返回发送此请求的客户端IP地址 
16   String getRemoteHost() 返回发送此请求的客户端主机名 
17   void setAttribute(String key,Object obj) 设置属性的属性值 
18   String getRealPath(String path) 返回一虚拟路径的真实路径 
 </pre>    <br />      <br /><br /><pre name="code" class="java">&lt;%@ page contentType="text/html;charset=gb2312"%>
&lt;%request.setCharacterEncoding("gb2312");%>
&lt;html>
&lt;head>
&lt;title>request对象_例1&lt;/title>
&lt;/head>
&lt;body bgcolor="#FFFFF0">
&lt;form action="" method="post">
   &lt;input type="text" name="qwe">
   &lt;input type="submit" value="提交">
&lt;/form>
请求方式：&lt;%=request.getMethod()%>&lt;br>
请求的资源：&lt;%=request.getRequestURI()%>&lt;br>
请求用的协议：&lt;%=request.getProtocol()%>&lt;br>
请求的文件名：&lt;%=request.getServletPath()%>&lt;br>
请求的服务器的IP：&lt;%=request.getServerName()%>&lt;br>
请求服务器的端口：&lt;%=request.getServerPort()%>&lt;br>
客户端IP地址：&lt;%=request.getRemoteAddr()%>&lt;br>
客户端主机名：&lt;%=request.getRemoteHost()%>&lt;br>
表单提交来的值：&lt;%=request.getParameter("qwe")%>&lt;br>
&lt;/body>
&lt;/html> 
&lt;%@ page contentType="text/html;charset=gb2312"%>
&lt;%request.setCharacterEncoding("gb2312");%>
&lt;%@ page import="java.util.Enumeration"%>
&lt;html>
&lt;head>
   &lt;title>request对象_例2&lt;/title>
&lt;/head>
&lt;body bgcolor="#FFFFF0">
&lt;form action="" method="post">
    用户名：&lt;input type="text" name="username">&nbsp;&nbsp;
    密 码：&lt;input type="text" name="userpass">&nbsp;&nbsp;
    &lt;input type="submit" value="进入" >
&lt;/form>
&lt;%
String str="";
if(request.getParameter("username")!=null && request.getParameter("userpass")!=null){
    Enumeration enumt = request.getParameterNames();
    while(enumt.hasMoreElements()){
       str=enumt.nextElement().toString();
       out.println(str+":"+request.getParameter(str)+"&lt;br>");
    }
}
%>
&lt;/body>
&lt;/html> 
&lt;%@ page contentType="text/html;charset=gb2312"%>
&lt;%request.setCharacterEncoding("gb2312");%>
&lt;html>
&lt;head>
    &lt;title>request对象_例3&lt;/title>
&lt;/head>
&lt;body bgcolor="#FFFFF0">
&lt;form action="" method="post">
   擅长：&lt;input type="checkbox" name="cb" value="ON1">VC++&nbsp;
        &lt;input type="checkbox" name="cb" value="ON2">JAVA&nbsp;
        &lt;input type="checkbox" name="cb" value="ON3">DELPHI&nbsp;
        &lt;input type="checkbox" name="cb" value="ON4">VB&nbsp;
        &lt;br>
        &lt;input type="submit" value="进入" name="qwe">
&lt;/form>
&lt;%
if(request.getParameter("qwe")!=null ){
    for(int i=0;i&lt;request.getParameterValues("cb").length;i++){
       out.println("cb"+i+":"+request.getParameterValues("cb")[i]+"&lt;br>");
    }
    out.println(request.getParameter("qwe"));
}
%>
&lt;/body>
&lt;/html></pre> <br />　 <br />　 <br /><br />2.response对象<br /><br />     response对象包含了响应客户请求的有关信息，但在JSP中很少直接用到它。它是HttpServletResponse类的实例。<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   String getCharacterEncoding() 返回响应用的是何种字符编码 
2   ServletOutputStream getOutputStream() 返回响应的一个二进制输出流 
3   PrintWriter getWriter() 返回可以向客户端输出字符的一个对象 
4   void setContentLength(int len) 设置响应头长度 
5   void setContentType(String type) 设置响应的MIME类型 
6   sendRedirect(java.lang.String location) 重新定向客户端的请求 </pre> 　 <br />     　 <br /><br />3.session对象<br /><br />     session对象指的是客户端与服务器的一次会话，从客户连到服务器的一个WebApplication开始，直到客户端与服务器断开连接为止。它是HttpSession类的实例.<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   long getCreationTime() 返回SESSION创建时间 
2   public String getId() 返回SESSION创建时JSP引擎为它设的惟一ID号 
3   long getLastAccessedTime() 返回此SESSION里客户端最近一次请求时间 
4   int getMaxInactiveInterval() 返回两次请求间隔多长时间此SESSION被取消(ms) 
5   String[] getValueNames() 返回一个包含此SESSION中所有可用属性的数组 
6   void invalidate() 取消SESSION，使SESSION不可用 
7   boolean isNew() 返回服务器创建的一个SESSION,客户端是否已经加入 
8   void removeValue(String name) 删除SESSION中指定的属性 
9   void setMaxInactiveInterval() 设置两次请求间隔多长时间此SESSION被取消(ms)</pre> <br /> 　 　 <br />     　 <br /><br /><pre name="code" class="java">&lt;%@ page contentType="text/html;charset=gb2312"%>
&lt;%@ page import="java.util.*" %>
&lt;html>
&lt;head>&lt;title>session对象_例1&lt;/title>&lt;head>
&lt;body>&lt;br>
    session的创建时间:&lt;%=session.getCreationTime()%>&nbsp;&nbsp;&lt;%=new Date(session.getCreationTime())%>&lt;br>&lt;br>
    session的Id号:&lt;%=session.getId()%>&lt;br>&lt;br>
    客户端最近一次请求时间:&lt;%=session.getLastAccessedTime()%>&nbsp;&nbsp;&lt;%=new java.sql. Time(session.getLastAccessedTime())%>&lt;br>&lt;br>
    两次请求间隔多长时间此SESSION被取消(ms):&lt;%=session.getMaxInactiveInterval()%>&lt;br>&lt;br>
    是否是新创建的一个SESSION:&lt;%=session.isNew()?"是":"否"%>&lt;br>&lt;br>
&lt;%
   session.putValue("name","霖苑编程");
   session.putValue("nmber","147369");
%>
&lt;%
   for(int i=0;i&lt;session.getValueNames().length;i++)
   out.println(session.getValueNames()[i]+"="+session.getValue(session.getValueNames()[i]));
%>
&lt;!--返回的是从格林威治时间(GMT)1970年01月01日0：00：00起到计算当时的毫秒数-->
&lt;/body>
&lt;/html> </pre><br />　 <br />　 <br />　 <br /><br />4.out对象<br /><br />     out对象是JspWriter类的实例,是向客户端输出内容常用的对象<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   void clear() 清除缓冲区的内容 
2   void clearBuffer() 清除缓冲区的当前内容 
3   void flush() 清空流 
4   int getBufferSize() 返回缓冲区以字节数的大小，如不设缓冲区则为0 
5   int getRemaining() 返回缓冲区还剩余多少可用 
6   boolean isAutoFlush() 返回缓冲区满时，是自动清空还是抛出异常 
7   void close() 关闭输出流</pre> <br /> 　 <br />     　 <br /><br /><pre name="code" class="java">&lt;%@page contentType="text/html;charset=gb2312"%>
&lt;html>&lt;head>&lt;title>out对象_例1:缓存测试&lt;/title>&lt;/head>
&lt;%@page buffer="1kb"%>
&lt;body>
&lt;%
   for(int i=0;i&lt;2000;i++)
   out.println(i+"{"+out.getRemaining()+"}");
%>&lt;br>
缓存大小：&lt;%=out.getBufferSize()%>&lt;br>
剩余缓存大小：&lt;%=out.getRemaining()%>&lt;br>
自动刷新：&lt;%=out.isAutoFlush()%>&lt;br>
&lt;%--out.clearBuffer();--%>
&lt;%--out.clear();--%>
&lt;!--缺省情况下:服务端要输出到客户端的内容,不直接写到客户端,而是先写到一个输出缓冲区中.只有在下面三中情况下，才会把该缓冲区的内容输出到客户端上： 
1.该JSP网页已完成信息的输出 
2.输出缓冲区已满 
3.JSP中调用了out.flush()或response.flushbuffer() 
-->
&lt;/body>
&lt;/html> </pre><br />　 <br />　 <br />　 <br /><br />5.page对象<br /><br />     page对象就是指向当前JSP页面本身，有点象类中的this指针，它是java.lang.Object类的实例<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   class getClass 返回此Object的类 
2   int hashCode() 返回此Object的hash码 
3   boolean equals(Object obj) 判断此Object是否与指定的Object对象相等 
4   void copy(Object obj) 把此Object拷贝到指定的Object对象中 
5   Object clone() 克隆此Object对象 
6   String toString() 把此Object对象转换成String类的对象 
7   void notify() 唤醒一个等待的线程 
8   void notifyAll() 唤醒所有等待的线程 
9   void wait(int timeout) 使一个线程处于等待直到timeout结束或被唤醒 
10   void wait() 使一个线程处于等待直到被唤醒 
11   void enterMonitor() 对Object加锁 
12   void exitMonitor() 对Object开锁 </pre><br /><br />     　 <br /><br />6.application对象<br /><br />     application对象实现了用户间数据的共享，可存放全局变量。它开始于服务器的启动，直到服务器的关闭，在此期间，此对象将一直存在；这样在用户的前后连接或不同用户之间的连接中，可以对此对象的同一属性进行操作；在任何地方对此对象属性的操作，都将影响到其他用户对此的访问。服务器的启动和关闭决定了application对象的生命。它是ServletContext类的实例。<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   Object getAttribute(String name) 返回给定名的属性值 
2   Enumeration getAttributeNames() 返回所有可用属性名的枚举 
3   void setAttribute(String name,Object obj) 设定属性的属性值 
4   void removeAttribute(String name) 删除一属性及其属性值 
5   String getServerInfo() 返回JSP(SERVLET)引擎名及版本号 
6   String getRealPath(String path) 返回一虚拟路径的真实路径 
7   ServletContext getContext(String uripath) 返回指定WebApplication的application对象 
8   int getMajorVersion() 返回服务器支持的Servlet API的最大版本号 
9   int getMinorVersion() 返回服务器支持的Servlet API的最大版本号 
10   String getMimeType(String file) 返回指定文件的MIME类型 
11   URL getResource(String path) 返回指定资源(文件及目录)的URL路径 
12   InputStream getResourceAsStream(String path) 返回指定资源的输入流 
13   RequestDispatcher getRequestDispatcher(String uripath) 返回指定资源的RequestDispatcher对象 
14   Servlet getServlet(String name) 返回指定名的Servlet 
15   Enumeration getServlets() 返回所有Servlet的枚举 
16   Enumeration getServletNames() 返回所有Servlet名的枚举 
17   void log(String msg) 把指定消息写入Servlet的日志文件 
18   void log(Exception exception,String msg) 把指定异常的栈轨迹及错误消息写入Servlet的日志文件 
19   void log(String msg,Throwable throwable) 把栈轨迹及给出的Throwable异常的说明信息 写入Servlet的日志文件 </pre>   <br />     　  <br /><br /><pre name="code" class="java">&lt;%@ page contentType="text/html;charset=gb2312"%>
&lt;html>
&lt;head>&lt;title>APPLICATION对象_例1&lt;/title>&lt;head>
&lt;body>&lt;br>
JSP(SERVLET)引擎名及版本号:&lt;%=application.getServerInfo()%>&lt;br>&lt;br>
返回/application1.jsp虚拟路径的真实路径:&lt;%=application.getRealPath("/application1.jsp")%>&lt;br>&lt;br>
服务器支持的Servlet API的大版本号:&lt;%=application.getMajorVersion()%>&lt;br>&lt;br>
服务器支持的Servlet API的小版本号:&lt;%=application.getMinorVersion()%>&lt;br>&lt;br>
指定资源(文件及目录)的URL路径:&lt;%=application.getResource("/application1.jsp")%>&lt;br>&lt;br>&lt;!--可以将application1.jsp换成一个目录-->
&lt;br>&lt;br>
&lt;%
   application.setAttribute("name","霖苑计算机编程技术培训学校");
   out.println(application.getAttribute("name"));
   application.removeAttribute("name");
   out.println(application.getAttribute("name"));
%>
&lt;/body>
&lt;/html> 
&lt;%@ page contentType="text/html;charset=gb2312"%>
&lt;html>
&lt;head>&lt;title>APPLICATION对象_例2&lt;/title>&lt;head>
&lt;body>&lt;br>
&lt;!--由于application一直存在于服务器端，可以利用此特性对网页记数-->
&lt;%
if(application.getAttribute("count")==null)
application.setAttribute("count","1");
else
application.setAttribute("count",Integer.toString(Integer.valueOf(application.getAttribute("count").toString()).intValue()+1));
%>
你是第&lt;%=application.getAttribute("count")%>位访问者
&lt;/body>
&lt;!--由于getAttribute()方法得到的是一个Object类型对象,用getString()方法转化为String类型-->
&lt;!--用Integer类的valueOf()方法把得到的String转化成Integer的对象,在用intValue()方法得到int型,再加1,最后把计算的结果用Integer.toString()方法转化成setAttribute()方法所要求的String类型-->
&lt;/html> 
&lt;%@ page contentType="text/html;charset=gb2312"%>
&lt;html>
&lt;head>&lt;title>APPLICATION对象_例3&lt;/title>&lt;head>
&lt;body>&lt;br>
&lt;!--由于application一直存在于服务器端，可以利用此特性对网页记数-->
&lt;%
String str=application.getAttribute("count").toString();//getAttribute("count")返回的是Object类型
int i=0;
if(str==null)
application.setAttribute("count","1");
else
i=Integer.parseInt(str); //out.println(i);
application.setAttribute("count",++i+"");
%>
你是第&lt;%=application.getAttribute("count")%>位访问者
&lt;/body>
&lt;/html></pre> <br />　 <br /><br />7.exception对象<br /><br />   exception对象是一个例外对象，当一个页面在运行过程中发生了例外，就产生这个对象。如果一个JSP页面要应用此对象，就必须把isErrorPage设为true，否则无法编译。他实际上是java.lang.Throwable的对象<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   String getMessage() 返回描述异常的消息 
2   String toString() 返回关于异常的简短描述消息 
3   void printStackTrace() 显示异常及其栈轨迹 
4   Throwable FillInStackTrace() 重写异常的执行栈轨迹 </pre>   <br />     　 <br /><br />8.pageContext对象<br /><br />    pageContext对象提供了对JSP页面内所有的对象及名字空间的访问，也就是说他可以访问到本页所在的SESSION，也可以取本页面所在的application的某一属性值，他相当于页面中所有功能的集大成者，它的本 类名也叫pageContext。<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   JspWriter getOut() 返回当前客户端响应被使用的JspWriter流(out) 
2   HttpSession getSession() 返回当前页中的HttpSession对象(session) 
3   Object getPage() 返回当前页的Object对象(page) 
4   ServletRequest getRequest() 返回当前页的ServletRequest对象(request) 
5   ServletResponse getResponse() 返回当前页的ServletResponse对象(response) 
6   Exception getException() 返回当前页的Exception对象(exception) 
7   ServletConfig getServletConfig() 返回当前页的ServletConfig对象(config) 
8   ServletContext getServletContext() 返回当前页的ServletContext对象(application) 
9   void setAttribute(String name,Object attribute) 设置属性及属性值 
10   void setAttribute(String name,Object obj,int scope) 在指定范围内设置属性及属性值 
11   public Object getAttribute(String name) 取属性的值 
12   Object getAttribute(String name,int scope) 在指定范围内取属性的值 
13   public Object findAttribute(String name) 寻找一属性,返回起属性值或NULL 
14   void removeAttribute(String name) 删除某属性 
15   void removeAttribute(String name,int scope) 在指定范围删除某属性 
16   int getAttributeScope(String name) 返回某属性的作用范围 
17   Enumeration getAttributeNamesInScope(int scope) 返回指定范围内可用的属性名枚举 
18   void release() 释放pageContext所占用的资源 
19   void forward(String relativeUrlPath) 使当前页面重导到另一页面 
20   void include(String relativeUrlPath) 在当前位置包含另一文件 
    </pre><br />      <br />      　  <br /><br /><pre name="code" class="java">&lt;%@page contentType="text/html;charset=gb2312"%>
&lt;html>&lt;head>&lt;title>pageContext对象_例1&lt;/title>&lt;/head>
&lt;body>&lt;br>
&lt;%
request.setAttribute("name","霖苑编程");
session.setAttribute("name","霖苑计算机编程技术培训");
//session.putValue("name","计算机编程");
application.setAttribute("name","培训");
%>
request设定的值：&lt;%=pageContext.getRequest().getAttribute("name")%>&lt;br>
session设定的值：&lt;%=pageContext.getSession().getAttribute("name")%>&lt;br>
application设定的值：&lt;%=pageContext.getServletContext().getAttribute("name")%>&lt;br>
范围1内的值：&lt;%=pageContext.getAttribute("name",1)%>&lt;br>
范围2内的值：&lt;%=pageContext.getAttribute("name",2)%>&lt;br>
范围3内的值：&lt;%=pageContext.getAttribute("name",3)%>&lt;br>
范围4内的值：&lt;%=pageContext.getAttribute("name",4)%>&lt;br>
&lt;!--从最小的范围page开始，然后是reques、session以及application-->
&lt;%pageContext.removeAttribute("name",3);%>
pageContext修改后的session设定的值：&lt;%=session.getValue("name")%>&lt;br>
&lt;%pageContext.setAttribute("name","应用技术培训",4);%>
pageContext修改后的application设定的值：&lt;%=pageContext.getServletContext().getAttribute("name")%>&lt;br>
值的查找：&lt;%=pageContext.findAttribute("name")%>&lt;br>
属性name的范围：&lt;%=pageContext.getAttributesScope("name")%>&lt;br>
&lt;/body>&lt;/html> </pre>　 <br />　 <br /><br />9.config对象<br /><br />    config对象是在一个Servlet初始化时，JSP引擎向它传递信息用的，此信息包括Servlet初始化时所要用到的参数（通过属性名和属性值构成）以及服务器的有关信息（通过传递一个ServletContext对象）<br /><br />序号 方 法 说 明 <br /><pre name="code" class="java">1   ServletContext getServletContext() 返回含有服务器相关信息的ServletContext对象 
2   String getInitParameter(String name) 返回初始化参数的值 
3   Enumeration getInitParameterNames() 返回Servlet初始化所需所有参数的枚举 </pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/230726#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 20 Aug 2008 15:38:01 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/230726</link>
        <guid>http://looxiaohu.javaeye.com/blog/230726</guid>
      </item>
      <item>
        <title>Servlet 重导定向问题</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/230722" style="color:red;">http://looxiaohu.javaeye.com/blog/230722</a>&nbsp;
          发表时间: 2008年08月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          response.sendRedirect 与 request.getRequestDispatcher(url).forward(request,response)区别 <br /><br />  服务器端进行转向的4种方法：   <br /><pre name="code" class="java">  1.   ServletContext的getRequestDispatcher()   
  2.   ServletContext的getNamedDispatcher()   
  3.   ServletRequest的getRequestDispatcher()   
  4.   ServletResponse的sendRedirect()进行转向。 </pre>  <br />  1.2.3   功能大于等于   forward() 重导功能<br /> 4.   sendRedirect()           <br />  使用forward方法，因为这些这样比较高效。只有在forward方法不能使用时（比如要转向到一个非本web应用），再使用ServletResponse的sendRedirect()方法。   <br />    <br />  &lt;jsp:fordward>与   sendRedirect   方法的比较   <br />  虽然   &lt;jsp:fordward>与   sendRedirect   方法，都可以将浏览器浏览的网页，重导至另一个网页，但是两者在原理上是不太相同。   <br />  a. &lt;jsp:fordward>   :   动作是利用伺服端，将资料输出至缓冲区的机制，在前一个网页尚未输出到客户端前，取消资料的输出，然后输出另一个网页的资料，达到重导浏览器的效果。   <br />  优点:   两网页间可以分享   request   对象内的变量。   <br />  b. sendRedirect   :   动作是透过   HTTP   协议的   Header   ，   对浏览器下达重导指令，因此，不牵涉到服务器端缓冲区的问题。   <br />  不过由于   sendRedirect   方法作用于客户端，所以重导前后网页无法分享存在于   request   对象内的变量。   <br />  Solution:   response.sendRedirect(“test.jsp?key=view”)   <br />  今天才搞清楚这个原理，ServletResponse就是在客户端响应返回数据，在这里ServletResponse不保留，request.setAttribute()的属性，如果用response.sendRedirect重导话，一些数据最好绑定到session里，数据一多，服务器吃不消，建议用ServletRequest来重导。
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/230722#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 20 Aug 2008 15:32:17 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/230722</link>
        <guid>http://looxiaohu.javaeye.com/blog/230722</guid>
      </item>
      <item>
        <title>Java Date 锦囊</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/228520" style="color:red;">http://looxiaohu.javaeye.com/blog/228520</a>&nbsp;
          发表时间: 2008年08月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          相关文章:   <br />java中关于时间日期操作的常用函数 <br />如何确定一个月的某一周是从几月几号到几号 <br /><br />更多相关推荐 1.计算某一月份的最大天数 <br /><br />Calendar time=Calendar.getInstance(); <br />time.clear(); <br />time.set(Calendar.YEAR,year); //year 为 int <br />time.set(Calendar.MONTH,i-1);//注意,Calendar对象默认一月为0 <br />int day=time.getActualMaximum(Calendar.DAY_OF_MONTH);//本月份的天数 <br />注：在使用set方法之前，必须先clear一下，否则很多信息会继承自系统当前时间 <br /><br />2.Calendar和Date的转化 <br /><br />(1) Calendar转化为Date <br />Calendar cal=Calendar.getInstance(); <br />Date date=cal.getTime(); <br /><br />(2) Date转化为Calendar <br />Date date=new Date(); <br />Calendar cal=Calendar.getInstance(); <br />cal.setTime(date); <br /><br />3.格式化输出日期时间 （这个用的比较多） <br /><br />Date date=new Date(); <br />SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); <br />String time=df.format(date); <br />System.out.println(time); <br /><br />4.计算一年中的第几星期 <br /><br />(1)计算某一天是一年中的第几星期 <br />Calendar cal=Calendar.getInstance(); <br />cal.set(Calendar.YEAR, 2006); <br />cal.set(Calendar.MONTH, 8); <br />cal.set(Calendar.DAY_OF_MONTH, 3); <br />int weekno=cal.get(Calendar.WEEK_OF_YEAR); <br /><br />(2)计算一年中的第几星期是几号 <br />SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd"); <br />Calendar cal=Calendar.getInstance(); <br />cal.set(Calendar.YEAR, 2006); <br />cal.set(Calendar.WEEK_OF_YEAR, 1); <br />cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); <br />System.out.println(df.format(cal.getTime())); <br />输出: <br />2006-01-02 <br /><br />5.add()和roll()的用法(不太常用) <br /><br />(1)add()方法 <br />SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd"); <br />Calendar cal=Calendar.getInstance(); <br />cal.set(Calendar.YEAR, 2006); <br />cal.set(Calendar.MONTH, 8); <br />cal.set(Calendar.DAY_OF_MONTH, 3); <br />cal.add(Calendar.DATE, -4); <br />Date date=cal.getTime(); <br />System.out.println(df.format(date)); <br />cal.add(Calendar.DATE, 4); <br />date=cal.getTime(); <br />System.out.println(df.format(date)); <br />输出： <br />2006-08-30 <br />2006-09-03 <br />(2)roll方法 <br />cal.set(Calendar.YEAR, 2006); <br />cal.set(Calendar.MONTH, 8); <br />cal.set(Calendar.DAY_OF_MONTH, 3); <br />cal.roll(Calendar.DATE, -4); <br />date=cal.getTime(); <br />System.out.println(df.format(date)); <br />cal.roll(Calendar.DATE, 4); <br />date=cal.getTime(); <br />System.out.println(df.format(date)); <br />输出： <br />2006-09-29 <br />2006-09-03 <br />可见，roll()方法在本月内循环，一般使用add()方法； <br /><br />6.计算两个任意时间中间的间隔天数（这个比较常用） <br />(1)传进Calendar对象 <br />public int getIntervalDays(Calendar startday,Calendar endday)...{ <br />if(startday.after(endday))...{ <br />Calendar cal=startday; <br />startday=endday; <br />endday=cal; <br />} <br />long sl=startday.getTimeInMillis(); <br />long el=endday.getTimeInMillis(); <br /><br />long ei=el-sl; <br />return (int)(ei/(1000*60*60*24)); <br />} <br />(2)传进Date对象 <br /><br />public int getIntervalDays(Date startday,Date endday)...{ <br />if(startday.after(endday))...{ <br />Date cal=startday; <br />startday=endday; <br />endday=cal; <br />} <br />long sl=startday.getTime(); <br />long el=endday.getTime(); <br />long ei=el-sl; <br />return (int)(ei/(1000*60*60*24)); <br />} <br />(3)改进精确计算相隔天数的方法 <br />public int getDaysBetween (Calendar d1, Calendar d2) ...{ <br />if (d1.after(d2)) ...{ <br />java.util.Calendar swap = d1; <br />d1 = d2; <br />d2 = swap; <br />} <br />int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR); <br />int y2 = d2.get(Calendar.YEAR); <br />if (d1.get(Calendar.YEAR) != y2) ...{ <br />d1 = (Calendar) d1.clone(); <br />do ...{ <br />days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);//得到当年的实际天数 <br />d1.add(Calendar.YEAR, 1); <br />} while (d1.get(Calendar.YEAR) != y2); <br />} <br />return days; <br />} <br />注意：通过上面的方法可以衍生出求任何时间，如要查出邮箱三周之内收到的邮件（得到当前系统时间－再得到三周前时间）用收件的时间去匹配 最好装化成 long去比较 <br />如：1年前日期（注意毫秒的转换） <br />java.util.Date myDate=new java.util.Date(); <br />long myTime=(myDate.getTime()/1000)-60*60*24*365; <br />myDate.setTime(myTime*1000); <br />String mDate=formatter.format(myDate); <br /><br />7. String 和 Date ，Long 之间相互转换 （最常用） <br /><br />字符串转化成时间类型（字符串可以是任意类型，只要和SimpleDateFormat中的格式一致即可） <br />通常我们取时间跨度的时候，会substring出具体时间－－long－比较 <br /><br />java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("M/dd/yyyy hh:mm:ss a",java.util.Locale.US); <br />java.util.Date d = sdf.parse("5/13/2003 10:31:37 AM"); <br />long dvalue=d.getTime(); <br />SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); <br />String mDateTime1=formatter.format(d); <br /><br />8. 通过时间求时间 <br /><br />年月周求日期 <br />SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E"); <br />java.util.Date date2= formatter2.parse("2003-05 5 星期五"); <br />SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd"); <br />String mydate2=formatter3.format(date2); <br /><br />求是星期几 <br />mydate= myFormatter.parse("2001-1-1"); <br />SimpleDateFormat formatter4 = new SimpleDateFormat("E"); <br />String mydate3=formatter4.format(mydate); <br /><br />9. java 和 具体的数据库结合 <br /><br />在开发web应用中，针对不同的数据库日期类型，我们需要在我们的程序中对日期类型做各种不同的转换。若对应数据库数据是oracle的Date类型，即只需要年月日的，可以选择使用java.sql.Date类型，若对应的是MSsqlserver 数据库的DateTime类型，即需要年月日时分秒的，选择java.sql.Timestamp类型 <br />你可以使用dateFormat定义时间日期的格式，转一个字符串即可 <br /><br />class Datetest{ <br />*method 将字符串类型的日期转换为一个timestamp（时间戳记java.sql.Timestamp） <br />*@param dateString 需要转换为timestamp的字符串 <br />*@return dataTime timestamp <br /><br />public final static java.sql.Timestamp string2Time(String dateString) <br />throws java.text.ParseException { <br />DateFormat dateFormat; <br />dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);//设定格式 <br />//dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.ENGLISH); <br />dateFormat.setLenient(false); <br />java.util.Date timeDate = dateFormat.parse(dateString);//util类型 <br />java.sql.Timestamp dateTime = new java.sql.Timestamp(timeDate.getTime());//Timestamp类型,timeDate.getTime()返回一个long型 <br />return dateTime; <br />} <br /><br />*method 将字符串类型的日期转换为一个Date（java.sql.Date） <br />*@param dateString 需要转换为Date的字符串 <br />*@return dataTime Date <br /><br />public final static java.sql.Date string2Date(String dateString) <br />throws java.lang.Exception { <br />DateFormat dateFormat; <br />dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH); <br />dateFormat.setLenient(false); <br />java.util.Date timeDate = dateFormat.parse(dateString);//util类型 <br />java.sql.Date dateTime = new java.sql.Date(timeDate.getTime());//sql类型 <br />return dateTime; <br />} <br /><br />public static void main(String[] args){ <br />Date da = new Date(); <br />注意：这个地方da.getTime()得到的是一个long型的值 <br />System.out.println(da.getTime()); <br /><br />由日期date转换为timestamp <br /><br />第一种方法：使用new Timestamp(long) <br />Timestamp t = new Timestamp(new Date().getTime()); <br />System.out.println(t); <br /><br />第二种方法：使用Timestamp(int year,int month,int date,int hour,int minute,int second,int nano) <br />Timestamp tt = new Timestamp(Calendar.getInstance().get( <br />Calendar.YEAR) - 1900, Calendar.getInstance().get( <br />Calendar.MONTH), Calendar.getInstance().get( <br />Calendar.DATE), Calendar.getInstance().get( <br />Calendar.HOUR), Calendar.getInstance().get( <br />Calendar.MINUTE), Calendar.getInstance().get( <br />Calendar.SECOND), 0); <br />System.out.println(tt); <br /><br />try { <br />String sToDate = "2005-8-18";//用于转换成java.sql.Date的字符串 <br />String sToTimestamp = "2005-8-18 14:21:12.123";//用于转换成java.sql.Timestamp的字符串 <br />Date date1 = string2Date(sToDate); <br />Timestamp date2 = string2Time(sToTimestamp); <br />System.out.println("Date:"+date1.toString());//结果显示 <br />System.out.println("Timestamp:"+date2.toString());//结果显示 <br />}catch(Exception e) { <br />e.printStackTrace(); <br />} <br />} <br />}
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/228520#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 15 Aug 2008 21:21:26 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/228520</link>
        <guid>http://looxiaohu.javaeye.com/blog/228520</guid>
      </item>
      <item>
        <title>神奇的重构技术</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/228273" style="color:red;">http://looxiaohu.javaeye.com/blog/228273</a>&nbsp;
          发表时间: 2008年08月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          代码中经常会出现枚举性的变量，比如血型、性别之类。<br />以血型为例:<br /><br />  <pre name="code" class="java">class Blood  {
public final static  int  o = 0 ;
public final static  int  A = 1 ;
public final static  int  B = 2 ;
public final static  int  AB = 3 ;

private Blood();
} 
 
 
 class person  {
private  int  _blood;
public  void  setBlood( int  b)  {
   _blood = b;
} </pre>如果要给一个person的实例设置血型，代码如此：person.setBlood(Blood.A);<br />这个写法的代码中,setBlood的参数为整型，如果如此调用person.setBlood(9);<br />编译器无法发现错误，只能靠人为控制，如果在方法setBlood中检测参数的有效性，又超越了该方法的职责。<br /><br />重构后的代码如下：<br /><br /> <pre name="code" class="java">final class Blood{
public final static Blood O=new Blood(0);
public final static Blood A=new Blood(1);
public final static Blood B=new Blood(2);
public final static Blood AB=new Blood(3);
private int _bloodCode;
private Blood(int b){
    _bloodCode=b;
  }
public int getCode(){
    return _bloodCode;
  }
}

class person{
private Blood _blood;
public setBlood(Blood b){
    _blood=b;
  }
}</pre>如此，（1）隐藏了血型的编码细节<br />            （2）方便编译期间发现错误<br />            （3）避免使用超越数据范围的参数
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/228273#comments" style="color:red;">已有 <strong>1</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 15 Aug 2008 11:24:56 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/228273</link>
        <guid>http://looxiaohu.javaeye.com/blog/228273</guid>
      </item>
      <item>
        <title>单例模式陷阱</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/228271" style="color:red;">http://looxiaohu.javaeye.com/blog/228271</a>&nbsp;
          发表时间: 2008年08月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          今天去jdon，看了它的设计研究栏目，bang有几篇评论单例模式的文章，声称“Singleton is evil”（见http://www.jdon.com/jive/article.jsp?forum=91&thread=17578），并且引用几篇外文页面佐证自己的观点，其中有一篇文章更是说，单例不仅不是一种模式，而是一种反模式。<br />        下面我谈谈我对单例模式的看法。逐一分析单例模式的陷阱，帮助大家正确使用单例模式。<br />（1） 陷阱一：调用函数的性能瓶颈<br />        在c++中，单例只有一种实现方式——LazySingleton, 实现如下(本文全部使用java代码)：<br /><pre name="code" class="java">
  public   class  LazySingleton {
     private   static  LazySingleton m_instance = null ;
     private LazySingleton(){};
     synchronized public static LazySingleton getInstance(){
        if(m_instance==null)
            m_instance=new LazySingleton();
        return m_instance;
    }
} </pre><br />LazySingleton将对象的初始化推迟到调用的时候。并且为了防止多线程环境下产生多个实例，使用synchronized关键字保证函数getInstance调用的线程安全。synchronized关键字的存在保证了只会产生一个对象，但也成了多线程环境下的性能瓶颈。一个多线程的程序，到了这里却要排队等候成了一个单线程式的执行流程，这在高并发环境下是不可容忍的。而c++中可以使用双重检查机制将这种性能问题仅仅限制在第一次构造对象的时候，而java中不可以使用双重检查机制。<br />        但是java可以实现EagerSingleton，实现如下：<br /><br /><pre name="code" class="java">  public   class  EagerSingleton {
     private   static  EagerSingleton m_instance = new  EagerSingleton();
     private EagerSingleton(){};
     public static agerSingleton getInstance(){
        return m_instance;
    }</pre><br />} 与LazySingleton相比，EagerSingleton将对象的初始化放到了类加载的时候。这样就避免了synchronized关键字的性能瓶颈。<br />（2）陷阱二：访问互斥共享资源<br />         EagerSingleton中访问互斥资源也要考虑线程安全问题。下面看一个例子：<br /><pre name="code" class="java">public class EagerSingleton{
    private static EagerSingleton m_instance=new EagerSingleton();
    private HashMap map=new HashMap();
    private EagerSingleton(){};
    public static agerSingleton getInstance(){
        return m_instance;
    }
        public void refreshMap(Object key){
        synchronized(map){
            if(!map.contains(key))
                map.put(key,value);//value为此时的实时数据
        } 
    }</pre><br />}因为该类是单例，可能多线程并发访问map，map非线程安全，需要加线程安全关键字，否则就掉入了访问互斥资源的陷阱。<br />（3）陷阱三：非法逻辑陷阱<br />        这种情况一般是滥用单例模式造成的，下面考虑一种滥用单例的情况。下面的代码的作用是getValueByName后,马上printValue即完成操作流程。<br /><pre name="code" class="java">public class EagerSingleton{
    private static EagerSingleton m_instance=new EagerSingleton();
    private String value=null;
    private EagerSingleton(){};
    public static agerSingleton getInstance(){
        return m_instance;
    }
    synchronized public void getValueByName(String name){
        value=getByNameFromDateBase(name);
        
    }
    public viod printValue(){
        System.out.println(this.vaue);
    }
}</pre>该类含有一私有属性value，在多线程环境下不能保证value值的合理逻辑，一线程getValueByName后,马上printValue，也有可能value的值已经被其他线程修改。这种情况就属于单例模式的滥用，该类根本不适合做成单例。<br />        消除非法逻辑的陷阱，可以通过将该类重构为纯粹的行为类完成。重构后的代码如下：<br /><br /><pre name="code" class="java">public class EagerSingleton{
    private static EagerSingleton m_instance=new EagerSingleton();
    private EagerSingleton(){};
    public static agerSingleton getInstance(){
        return m_instance;
    }
    private String getValueByName(String name){
        return getByNameFromDateBase(name);
        
    }
    public viod printName(String name){
        String value=getValueByName(String name);
        System.out.println(value);
    }
}</pre>通过调用printName(String name)直接完成操作流程，将其中的私有属性处理成过程式的参数传递，将该类修改成纯粹的行为类。<br /><br />        含有私有属性并且含有对它赋值操作的类并非都会调入该陷阱，构造函数里进行对私有属性赋值不会引起非法逻辑，如下代码<br /><br /><pre name="code" class="java">public class EagerSingleton{
    private static EagerSingleton m_instance=new EagerSingleton();
    private HashMap map==new HashMap();
    
    private EagerSingleton(){
        map.put(key,value);//value为此时的实时数据
    }
    public static agerSingleton getInstance(){
        return m_instance;
    }
}</pre>构造函数里不必要加线程安全关键字也可以保证线程安全，因为类加载器是线程安全的，EagerSingleton只会在类加载的时候实例化一次，这样不会出现单例模式的线程不安全，也不会造成非法逻辑。<br />（4）陷阱四：单例陷阱的传递<br />        当含有对象作为单例类的私有属性时，陷阱不仅会出现在该类本身，还会传递到私有对象所在的类中。看如下代码：<br /><br /><pre name="code" class="java">public class EagerSingleton{
    private static EagerSingleton m_instance=new EagerSingleton();
    private NewClass newClass=nll;
    private EagerSingleton(){
        newClass=new NewClass();
    };
    public static agerSingleton getInstance(){
        return m_instance;
    }
    public viod printName(String name){
        String value=newClass.operationByNameAndReturnValue(String name);
        System.out.println(value);
    }</pre><br />}乍一看，代码中除了构造函数对私有属性进行了初始化操作，其他地方没有对私有属性的赋值，不会引起非法逻辑陷阱。其实这个赋值操作可能隐含在newClass.operationByNameAndReturnValue(String name)操作，只有保证了NewClass的operationByNameAndReturnValue操作不会对它的私有属性赋值操作，才能保证真正的合理逻辑。同样，只有保证NewClass的operationByNameAndReturnValue操作没有掉入访问互斥资源陷阱，才能真正保证EagerSingleton没有掉入该陷阱。<br />        消除该陷阱的方法：（1）类方法的名称要合理，比如纯粹的行为方法名：interprete,excute,operation之类的方法中就不该含有对私有属性直接或者间接的赋值操作，每个方法的责任要明确。（2）单例类中尽量不要含有非单例类的实例作为私有属性（容器类除外），一定要有类的实例作为私有属性的时候，重新审视这个作为私有属性的类，是不是也应该设计成单例类；或者保证对它的初始化赋值限制在构造函数内。
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/228271#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 15 Aug 2008 11:22:15 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/228271</link>
        <guid>http://looxiaohu.javaeye.com/blog/228271</guid>
      </item>
      <item>
        <title>深入探究【JFreeChart】</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/228266" style="color:red;">http://looxiaohu.javaeye.com/blog/228266</a>&nbsp;
          发表时间: 2008年08月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1 简介 <br />JFreeChart 是 SourceForge.net 上的一个开源项目，它的源码和 API 都可以免费获得。 JFreeChart 的功能非常强大，可以实现饼图 ( 二维和三维 ) ,  柱状图  ( 水平 , 垂直 ), 线图 , 点图 , 时序图 , 甘特图 ,  股票行情图 , 混和图 ,  温度计图 ,  刻度图等常用商用图表，   图形可以导出成 PNG 和 JPEG 格式，同时还可以与 PDF 和 EXCEL 关联，支持对图形的放大、缩小，支持常见图形的 3D 显示。 <br /><br /><br />2 图形 对象的处理 <br />2 ．1 JFreeChart对象 <br />JFreeChart 可以生成很多图形对象，它的工厂类提供了 33 个工厂方法用于生成不同的图形对象（具体的工厂方法可以参见 JFreeChart 的 API 手册或者源码中的 ChartFactory 类 ）。              JFreechart 对图形对象的抽象具体化。图形对象（ JFreeChart ），由 Title( 主标题 ) ， SubTitle （子标题 ) ， Plot （图形的绘制结构）等几个主要对象组成。各个组成部分如下图所示：<br /><img src="http://www.blogjava.net/images/blogjava_net/javaexplore/chart.JPG" /><br /><br /><br />这是一个 JFreeChart 对象，上面的“ chart 标题”是 Title 对象，中间区域是 Plot 对象（包括绘图区域和坐标轴区域），下面的区域是 LegendTitle 对象，是一种 SubTitle 对象。 <br /><br />每个 JFreeChart 对象只能有 1 个 Title 对象， 1 个 Plot 对象，可以有多个 SubTitle 对象。 JFreeChart 对象可以进行的操作有：背景的设置（背景颜色、背景图片、透明度等）、边框的设置（是否可见、笔画、 Paint 等）、渲染方式的设置、标题对象的设置、子标题对象的增删查操作。（本文中的所有操作都不提供代码级的介绍，可参见 API 手册或者源码） <br /><br />2 ．2 主标题对象 <br />主标题对象是 TextTitle 类型，可以进行的操作有：背景设置、字体设置（字体类型、颜色、内容、对齐方式等操作）、 tooltip 设置、 URL 设置。 <br /><br />2 ．3 Plot 对象 <br />Plot 对象是图形的绘制结构对象。 JFreeChart 中含有很多不同的 Plot 对象，每一种图形对象中的 Plot 对象都在实例化的时候创建。所有的 Plot 共有的操作有：背景设置（背景颜色、背景图片、透明度等）、前景透明度设置、无数据存在情况的设置（显示的字符内容、显示的字体、显示的 Paint ）、放大缩小比例的设置，大部分 Plot 对象还有设置 Datset 、设置 Renderer 对象操作。 <br /><br />JFreeChart 中有 18 种 Plot 抽象类的具体实现类。 Plot 的具体实现类主要由以下重要对象组成： Renderer 对象（图形的绘制单元——绘图域） Datset （图形的数据源）， DomainAxis （区域轴，相当于 x 轴）， RangeAxis （范围轴，相当于 y 轴）。不同的 Plot 对象组成方式不尽相同，有的不含有 Renderer 对象，比如 CompassPlot 、 ContourPlot 、 MultiplePiePlot 、 PiePlot 等，有的不含有 DomainAxis 、 RangeAxis 对象，另外除了 FastScatterPlot 类都含有 Datset 对象， FastScatterPlot 使用 float 的二维数组充当数据源。尤其说明一点，饼状图相关的 Plot 对象（ MultiplePiePlot 、 PiePlot 、 PiePlot3D 、 RingPlot ）中都不含有 Renderer 对象、 DomainAxis 对象、 RangeAxis 对象。 <br /><br />一般来说， Datset 对象存储数据模型， Renderer 对象存储显示模型， Plot 对象根据 Datset 对象、 Renderer 对象完成画图操作。 <br /><br />仍以上面的图形讲解 Plot 对象的组成。 <br /><br /><img src="http://www.blogjava.net/images/blogjava_net/javaexplore/chart.JPG" /><br /><br />   上图的中间区域是是一个 XYPlot 对象。其中的折线部分即是图形的绘制单元 Renderer 对象。 X 轴是 DomainAxis ， y 轴是 RangeAxis ，其中 Datset 对象属于数据模型范畴，是 UI 不可见对象。该图中的 plot 背景色、网格线的各种设置可以通过 XYPlot 对象本身完成。 <br /><br />       下面讲解 Renderer 对象、 Axis 对象（ X 轴、 y 轴都属于 Axis 对象）， Datset 对象在后续章节中专门讲解。 <br /><br />2 ．3．1 Renderer对象 <br />Renderer 对象是图形的绘制单元。 JFreeChart 提供了两个接口 CategoryItemRenderer 和 XYItemRenderer 、 1 个抽象类 AbstractRenderer 供具体的 Renderer 类实现，给出了将近 50 种具体实现类。 <br /><br />一般来说 Renderer 对象可进行的操作有：对 item label （下图中的柱状图上的红色数字即为 item label 的示例）的默认设置（ item label 的产生方式、是否可见、字体、 Paint 、正反向 item label 的位置设置等）、绘制图形的边框默认设置（ Paint 、笔画、是否可见等）、绘制图形的默认设置（形状、笔画、是否可见、对应的图例中是否可见等，折线图还有线条是否可见、折点图形是否可见、折点图形是否填充、折点图形的形状、对应的图例中线条是否可见、图形是否可见、整体是否可见等）、以及对指定 item label 的设置、指定绘制图形的设置。可以说和具体绘制的图形相关的属性都可以通过 Renderer 对象设置。<br /><br /><img src="http://www.blogjava.net/images/blogjava_net/javaexplore/chart3.JPG" /><br /><br />不同的 Renderer 的实现类实现了不同的显示方式，在含有 Renderer 对象的 JFreeChart 对象中， R enderer 对象决定了JFreeChart对象的显示方式。例如：柱状图的Plot对象中默认的Renderer对象是 CategoryItemRenderer 对象，通过设置 Plot 对象的Renderer对象 为 LineAndShapeRenderer ，则柱状图变为线图。使用中一般不需要显式的实例化一个 R enderer 对象，一般通过 JFreeChart 对象的 Plot 对象调用现有的 R enderer 对象进行重新设置等操作。 <br /><br />2 ．3．2 Axis对象 <br />JFreeChart 提供了两种类型的坐标轴： CategoryAxis （等级轴）和 ValueAxis （值轴）， ValueAxis 又有 3 个子类： DateAxis （时间轴）、 NumberAxis （数字轴）、 PeriodAxis （时期轴）。这些坐标轴还有更详细的子类，不再一一列举 <br /><br />Axis 对象可进行的操作有：标题的设置（内容、字体、Paint、显示角度等）、坐标线的设置（笔画、Paint、是否可见等）、刻度线的设置（是否可见、笔画、Paint、位于绘图区域的长度、位于绘图区域外的长度等）、刻度标示的设置（笔画、Paint、字体、与轴的距离等）、坐标轴范围设置等。 <br /><br />CategoryAxis 对象还可以进行的操作有： 刻度标示间距 设置（ 最小间距、最大间距、指定间距）等。 <br /><br />ValueAxis 对象可进行的操作有：轴端设置（显示的图形形状）、范围设置（是否自动产生范围、自动产生的最小范围、最大范围、指定确定范围、指定范围大小等）、间隔设置（是否自动产生间隔、指定间隔）等。 <br /><br />DateAxis 对象还有对时间刻度显示格式的设置操作。 <br /><br />2 ． 4 子标题对象 <br />    子标题对象是 Title 类型的对象，一个JFreeChart可以有多个子标题对象。JFreeChart提供了5种Title的实现，可以是图片、文本、图例等的形式。 <br /><br />（数据源以及常用图形的处理以及进一步的讨论在后续文章中介绍）
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/228266#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 15 Aug 2008 11:13:27 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/228266</link>
        <guid>http://looxiaohu.javaeye.com/blog/228266</guid>
      </item>
      <item>
        <title>深入探究【JFreeChart】数据源处理 </title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/228263" style="color:red;">http://looxiaohu.javaeye.com/blog/228263</a>&nbsp;
          发表时间: 2008年08月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          3 数据源处理 <br />JFreeChart 中的数据源是DataSet接口类型。该接口有三个主要的子类接口：CategoryDataset、PieDataset、SeriesDataset <br /><br />CategoryDataset 接口的实现类基本上都维护了一个三元组&lt;value,row,col>的列表结构。不同的实现类中value 的类型不相同。&lt;row,col>唯一确定一个三元组。CategoryDataset的实现类提供对这个三元组的增删改查操作。 <br /><br />PieDataset 接口有两个主要的实现类：CategoryToPieDataset 、DefaultPieDataset。PieDataset接口的实现类基本上都维护了一个二元组&lt;key,value>的列表结构。Key唯一确定一个二元组。CategoryDataset的实现类提供对这个二元组的增删改查操作。CategoryToPieDataset中的二元结构列表通过对CategoryDataset类型的对象指定行或者列转化过来。DefaultPieDataset直接维护一个二元结构列表。 <br /><br />SeriesDataset 接口的实现类基本上都维护了一种特定数据结构的列表。以TimeSeriesCollection为例。它维护一个TimeSeries对象列表，提供对该列表的增删查操作。每个TimeSeries对象维护一个&lt;time,value>列表，提供对该列表的增删改查操作。<br /><br /><br />三 JFreeChart 中对常见图形的处理 <br />       JFreeChart 并不存在多个不同的类来生成不同的图形。所有的图形都是具体类 JFreeChart 的实例化对象，初始化 JFreeChart 对象的时候通过指定不同的 Plot 实现类就可以显示出不同的图形。不同的 Plot 实现类具有不同的 Renderer 对象、 Axis 对象、 Dataset 对象。 <br /><br />       JFreeChart 提供工厂类 ChartFactory 方便使用者生成各种不同的图形。 ChartFactory 类的各个工厂方法中实现对具体 Plot 的指定以及对类 JFreeChart 构造函数的调用。 <br /><br />       下面以常用图形说一下常用的使用流程（大部分的操作讲的并不全面，比如 JFreeChart 可能提供了很多增加、修改数据的方式，下文中可能只列举一种）。 <br /><br />1 柱状图 <br />（ 1 ）平面柱状图 <br /><br />       生成柱状图操作： <br /><br />    <pre name="code" class="java">   JFreeChart chart = ChartFactory.createBarChart( 

                      String title,                 // 图标题 

                String categoryAxisLabel,     //x 轴标题 

                String valueAxisLabel,       //y 轴标题 

                CategoryDataset dataset,      // 数据源 

                PlotOrientation orientation,    // 显示方向 

                 boolean legend,             // 是否显示图例 

                 boolean tooltips,            // 是否显示 tooltip 

                 boolean urls) ；              // 是否指定 url </pre>平面柱状图的 Plot 对象是 CategoryPlot 类型。 CategoryPlot 对象的 x 轴是 CategoryAxis 对象， y 轴是 NumberAxis 对象，绘制单元是 BarRenderer 对象，数据源是 CategoryDataset 对象。 <br /><br />  <br /><br />获取 CategoryPlot 对象操作为： <br /><br /><pre name="code" class="java">CategoryPlot plot = ( CategoryPlot ) chart.getPlot(); 或者 

CategoryPlot plot = chart.getCategoryPlot(); </pre><br />获取绘制单元操作： <br /><br />       BarRenderer renderer = (BarRenderer) plot.getRenderer(); <br /><br />获取 x 轴的操作： <br /><br />CategoryAxis xAxis = ( CategoryAxis ) plot.getDomainAxis(); <br /><br />获取 y 轴操作： <br /><br />NumberAxis yAxis = (NumberAxis) plot.getRangeAxis(); <br /><br />获取数据源： <br /><br />CategoryDataset dataset=plot.getDataset(); <br /><br />  <br /><br />       柱状图可以接受一切 CategoryDataset 类型的数据源，下面讲解一下常用的 CategoryDataset 类型 DefaultCategoryDataset 的使用方式 <br /><br />实例化： <br /><br />DefaultCategoryDataset dataset = new DefaultCategoryDataset(); <br /><br />增加数据 <br /><br />dataset .addValue(double value, Comparable rowKey, Comparable columnKey) ; <br /><br />删除数据： <br /><br />       dataset .removeValue(Comparable rowKey, Comparable columnKey); <br /><br />       或者 <br /><br />       dataset. removeColumn(int columnIndex); <br /><br />       或者 <br /><br />       dataset. removeColumn(Comparable columnKey); <br /><br />       对行同样有上述两种删除方式，不在列举。 <br /><br />修改数据： <br /><br />       dataset. setValue(double value, Comparable rowKey, Comparable columnKey); <br /><br />查询数据 : <br /><br />对 plot 对象、绘制单元、 x 轴、 y 轴的显示特性修改不再一一介绍。 <br /><br />（ 2 ） 3D 柱状图 <br /><br />       对应的工厂方法为 createBarChart3D ，该方法的参数与平面柱状图相同。 3D 柱状图的 Plot 对象是 CategoryPlot 类型。 CategoryPlot 对象的 x 轴是 CategoryAxis3D 对象， y 轴是 NumberAxis3D 对象，绘制单元是 BarRenderer3D 对象，数据源是 CategoryDataset 对象。 <br /><br />       具体使用以及操作与平面柱状图雷同，不在详述。 <br /><br />2 饼状图 <br />(1) 平面饼状图 <br /><br />生成平面饼状图： <br /><br /><pre name="code" class="java">JFreeChart chart = ChartFactory. createPieChart(String title, // 图标题 

                          PieDataset dataset,       // 数据源 

                          boolean legend,         // 是否显示图例 

                          boolean tooltips,         // 是否显示tooltip 

                          boolean urls) ；          // 是否指定url </pre><br />平面饼状图的Plot对象是PiePlot类型。PiePlot对象没有x轴对象、y轴对象、绘制单元对象，数据源是PieDataset对象。 <br /><br />  <br /><br />获取PiePlot对象操作为： <br /><br />PiePlot plot = (PiePlot) chart.getPlot(); <br /><br />获取数据源： <br /><br />PieDataset dataset= plot .getDataset(); <br /><br />  <br /><br />饼状图可以接受一切 PieDataset 类型的数据源，下面讲解一下常用的 PieDataset 类型 DefaultPieDataset 的使用方式 <br /><br />实例化： <br /><br />    DefaultPieDataset dataset = new DefaultPieDataset(); <br /><br />增加修改操作： <br /><br />    dataset. setValue(Comparable key, double value); <br /><br />删除操作： <br /><br />    dataset. remove(Comparable key); <br /><br />查询操作： <br /><br />    dataset. getKey(int item); <br /><br />或者 <br /><br />dataset. getValue(int item); <br /><br />  <br /><br />(1)3D 饼状图 <br /><br />       对应的工厂方法为 createPieChart3D ，参数与平面饼状图相同。与平面饼状图的差别在于 Plot 对象是PiePlot3D类型 ，不再详述。 <br /><br />3 多重饼状图 <br />（ 1 ）多重平面饼状图 <br /><br />生成多重平面饼状图： <br /><br />    <pre name="code" class="java">   JFreeChart chart = ChartFactory. createMultiplePieChart 

(String title,               // 图标题 

                        CategoryDataset dataset,     // 数据源 

                        TableOrder order,       // 指定提取数据的方式（按行或者按列） 

                        boolean legend,            // 是否显示图例 

                        boolean tooltips,            // 是否显示 tooltip 

                        boolean urls)   ；            // 是否指定 url </pre><br /><br />多重平面饼状图的 Plot 对象是 MultiplePiePlot 类型。 MultiplePiePlot 对象没有 x 轴对象、 y 轴对象、绘制单元对象，数据源是 CategoryDataset 对象。 MultiplePiePlot 对象中可以含有多个子 JFreeChart 对象，子 JFreeChart 对象是上面讲过的饼状图对象。 <br /><br />  <br /><br />获取 MultiplePiePlot 对象操作为： <br /><br />MultiplePiePlot plotMain = (MultiplePiePlot) chart.getPlot(); <br /><br />获取子 JFreeChart 的操作为： <br /><br />       JFreeChart childChart=plotMain.getPieChart(); <br /><br />获取数据源： <br /><br />CategoryDataset dataset= plotMain .getDataset(); <br /><br />（ 2 ）多重 3D 饼状图 <br /><br />       对应的工厂方法为 createMultiplePieChart3D ，该方法的参数与 多重平面饼状图 相同。 多重 3D 饼状图的 Plot 对象是 MultiplePiePlot 类型。 MultiplePiePlot 对象中可以含有多个子 JFreeChart 对象，子 JFreeChart 对象是上面讲过的 3D 饼状图对象。 <br /><br />4 线图 <br />（ 1 ）平面线图 <br /><br />       生成平面线图： <br /><br />    <pre name="code" class="java">   JFreeChart chart = ChartFactory. createLineChart(String title,  // 图标题 

                         String categoryAxisLabel,         //x 轴标题 

                         String valueAxisLabel,            //y 轴标题 

                         CategoryDataset dataset,           // 数据源 

                         PlotOrientation orientation,         // 显示方向 

                         boolean legend,                 // 是否显示图例 

                         boolean tooltips,                 // 是否显示 tooltip 

                         boolean urls);                  // 是否指定 url </pre><br />平面线图除了的 Plot 对象中绘制单元对象是 LineAndShapeRenderer 对象，其他一切组成对象与平面柱状图相同。 <br /><br />获取 Renderer 操作： <br /><br />LineAndShapeRenderer renderer=(LineAndShapeRenderer) plot.getRenderer(); <br /><br />其他参考平面柱状图。 <br /><br />（ 2 ） 3D 线图 <br /><br />对应工厂方法为 createLineChart3D ，参数与 createLineChart 相同。 3D 线图的组成对象除了绘制单元对象是 LineAndShapeRenderer3D 对象，其他一切组成对象与 3D 柱状图相同。 <br /><br />5 时序图 <br />生成时序图： <br /><br />     <pre name="code" class="java">  JFreeChart chart = ChartFactory.createTimeSeriesChart( 

              String title,    // 图标题 

                 String timeAxisLabel,   //x 轴标题 

                 String valueAxisLabel,  //y 轴标题 

                 XYDataset dataset,       // 数据源 

                 boolean legend,          // 是否显示图例 

                 boolean tooltips,        // 是否显示 tooltip 

                 boolean urls);           // 是否指定 url </pre>时序图的 Plot 对象是 XYPlot 类型。 XYPlot 对象的 x 轴是 DateAxis 对象， y 轴是 NumberAxis 对象，绘制单元是 XYLineAndShapeRenderer 对象，数据源是 XYDataset 对象。 <br /><br />Plot 对象的获取操作： <br /><br />       XYPlot plot = (XYPlot) chart.getPlot(); <br /><br />X 轴对象的获取操作： <br /><br />       DateAxis xAxis = (DateAxis) plot.getDomainAxis(); <br /><br />Y 轴对象的获取操作： <br /><br />       NumberAxis yAxis =(NumberAxis) plot.getRangeAxis(); <br /><br />Renderer 对象的获取操作： <br /><br />       XYItemRenderer renderer= plot.getRenderer(); <br /><br />  <br /><br />时序图可以接受一切 XYDataset 类型的数据源，下面讲解一下常用的 XYDataset 类型 TimeSeriesCollection 的使用方式。 <br /><br />实例化： <br /><br />       TimeSeriesCollection dataset=new TimeSeriesCollection(); <br /><br />添加数据操作： <br /><br />       dataset. addSeries(TimeSeries); // 后面讲解 TimeSeries 对象 <br /><br />删除数据操作： <br /><br />       dataset. removeSeries(int index); <br /><br />查询数据操作 : <br /><br />       dataset. getSeries(int series); <br /><br />  <br /><br />TimeSeries 对象操作 <br /><br />实例化： <br /><br />       TimeSeries ts=TimeSeries(String name, Class timePeriodClass); <br /><br />增加数据操作： <br /><br />       ts. add(RegularTimePeriod period, double value);  <br /><br />删除数据操作： <br /><br />       ts. delete(RegularTimePeriod period);    <br /><br />修改数据操作： <br /><br />       ts. update(RegularTimePeriod period, Number value); <br /><br />查询数据操作： <br /><br />       ts. getValue(RegularTimePeriod period); <br /><br />类 RegularTimePeriod 是 JFreeChart 提供的时间模板类，它有很多具体的时间类，比如： Minute 、 Second 、 Hour 、 Day…… 等，不再详述。
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/228263#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 15 Aug 2008 11:09:34 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/228263</link>
        <guid>http://looxiaohu.javaeye.com/blog/228263</guid>
      </item>
      <item>
        <title>[转]MySQL中如何为连接添加索引</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/228179" style="color:red;">http://looxiaohu.javaeye.com/blog/228179</a>&nbsp;
          发表时间: 2008年08月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在MySQL中如何为连接添加索引，然后再看一个有挑战性的例子。 <br /><br /><br />简单的3个表的连接 <br /><br /><br />表结构很简单，3个表tblA, tblB, tblC，每个表有3个字段：col1, col2, col3。 <br />在没有索引的情况下连接3个表 <br /><br /><br /><pre name="code" class="java">SELECT 
* 
FROM 
tblA, 
tblB, 
tblC 
WHERE 
tblA.col1 = tblB.col1 
AND tblA.col2 = tblC.col1; </pre><br /><br /><br />explain的结果如下： <br /><br /><pre name="code" class="java">Java代码 
+-------+------+---------------+------+---------+------+------+-------------+   
| table | type | possible_keys | key  | key_len | ref  | rows | Extra       |   
+-------+------+---------------+------+---------+------+------+-------------+   
| tblA  | ALL  | NULL          | NULL |    NULL | NULL | 1000 |             |   
| tblB  | ALL  | NULL          | NULL |    NULL | NULL | 1000 | Using where |   
| tblC  | ALL  | NULL          | NULL |    NULL | NULL | 1000 | Using where |   
+-------+------+---------------+------+---------+------+------+-------------+  

   +-------+------+---------------+------+---------+------+------+-------------+
   | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
   +-------+------+---------------+------+---------+------+------+-------------+
   | tblA  | ALL  | NULL          | NULL |    NULL | NULL | 1000 |             |
   | tblB  | ALL  | NULL          | NULL |    NULL | NULL | 1000 | Using where |
   | tblC  | ALL  | NULL          | NULL |    NULL | NULL | 1000 | Using where |
   +-------+------+---------------+------+---------+------+------+-------------+</pre><br />最后，在MySQL的手册中(7.2.1)： <br />表以它们在处理查询过程中将被MySQL读入的顺序被列出。MySQL用一遍扫描多次联接（single-sweep multi-join）的方式解决所有联接。这意味着MySQL从第一个表中读一行，然后找到在第二个表中的一个匹配行，然后在第3个表中等等。当所有的表处理完后，它输出选中的列并且返回表清单直到找到一个有更多的匹配行的表。从该表读入下一行并继续处理下一个表。 <br />如手册所说的，MySQL读第一个表(tnlA)，然后第二个(tblB)，然后第三个(tblC)，像explain中输出的一样。先前的表中的值用来查找当前表中的行。在我们的例子中，tblA中的值用来找tblB中的匹配行，然后tblB的值来找tblC的行。当一个完整的扫描结束(在表tblA,tblB,tblC中找到了结果)，MySQL不会返回tblA,它到tblB中查看是否有更多的行匹配当前tblA的值。如果有，它拿出这一行，然后再在tblC中找匹配的。记住 MySQL连接的基本原则是很重要的：先前的表中的值用来查找当前表中的行。 <br /><br /><br />按原理建索引 <br /><br />知道了MySQL使用从tblA中得到的值查找tblB中的行，我们需要怎么建索引来帮助MySQL？为此我们要知道它需要什么。考虑连接tblA和 tblB：它们通过“tblA.col1 = tblB.col1”来连接。我们已经有了tblA.col1的值，所以MySQL需要一个tblB.col1的值来完成等值操作。因此如果MySQL需要tblB.col1，我们就在tblB.col1上加索引。加了之后，这是新的explain结果： <br /><br /><br /><pre name="code" class="java">Java代码 
+-------+------+---------------+----------+---------+-----------+------+-------------+   
| table | type | possible_keys | key      | key_len | ref       | rows | Extra       |   
+-------+------+---------------+----------+---------+-----------+------+-------------+   
| tblA  | ALL  | NULL          | NULL     |    NULL | NULL      | 1000 |             |   
| tblB  | ref  | ndx_col1      | ndx_col1 |       5 | tblA.col1 |    1 | Using where |   
| tblC  | ALL  | NULL          | NULL     |    NULL | NULL      | 1000 | Using where |   
+-------+------+---------------+----------+---------+-----------+------+-------------+  

+-------+------+---------------+----------+---------+-----------+------+-------------+
| table | type | possible_keys | key      | key_len | ref       | rows | Extra       |
+-------+------+---------------+----------+---------+-----------+------+-------------+
| tblA  | ALL  | NULL          | NULL     |    NULL | NULL      | 1000 |             |
| tblB  | ref  | ndx_col1      | ndx_col1 |       5 | tblA.col1 |    1 | Using where |
| tblC  | ALL  | NULL          | NULL     |    NULL | NULL      | 1000 | Using where |
+-------+------+---------------+----------+---------+-----------+------+-------------+</pre><br /><br />如上，MySQL现在使用ndx_col1索引来连接tblB到tblA。就是说，当MySQL要找tblB中的行时，使用了ndx_col1索引通过 tblA.col1的值直接得到匹配的行，而不是像以前需要做表扫描。这就是为什么tblB的ref列说“tablA.col1”。tblC现在还是用表扫描，这可以通过同样的方法解决。查看MySQL的需求：从sql中连接两表的语句“tblA.col2 = tblC.col1”可以看出它需要tblC.col1因为我们已经有了tblA.col2。给这一列加上索引之后explain： <br /><br /><br /><pre name="code" class="java">Java代码 
+-------+------+---------------+----------+---------+-----------+------+-------------+   
| table | type | possible_keys | key      | key_len | ref       | rows | Extra       |   
+-------+------+---------------+----------+---------+-----------+------+-------------+   
| tblA  | ALL  | NULL          | NULL     |    NULL | NULL      | 1000 |             |   
| tblB  | ref  | ndx_col1      | ndx_col1 |       5 | tblA.col1 |    1 | Using where |   
| tblC  | ref  | ndx_col1      | ndx_col1 |       5 | tblA.col2 |    1 | Using where |   
+-------+------+---------------+----------+---------+-----------+------+-------------+  

+-------+------+---------------+----------+---------+-----------+------+-------------+
| table | type | possible_keys | key      | key_len | ref       | rows | Extra       |
+-------+------+---------------+----------+---------+-----------+------+-------------+
| tblA  | ALL  | NULL          | NULL     |    NULL | NULL      | 1000 |             |
| tblB  | ref  | ndx_col1      | ndx_col1 |       5 | tblA.col1 |    1 | Using where |
| tblC  | ref  | ndx_col1      | ndx_col1 |       5 | tblA.col2 |    1 | Using where |
+-------+------+---------------+----------+---------+-----------+------+-------------+</pre><br /><br /><br />更复杂的查询 <br /><br /><br />在实际中不会遇到刚才那种sql。所以你可能更想看看这样的： <br /><br /><br /><pre name="code" class="java">SELECT 
COUNT(tblB.a_id) as correct, 
tblA.type, 
tblA.se_type 
FROM 
tblA, 
tblB, 
tblC, 
tblD 
WHERE 
tblA.ex_id = tblC.ex_id 
AND tblC.st_ex_id = tblB.st_ex_id 
AND tblB.q_num = tblA.q_num 
AND tblB.se_num = tblA.se_num 
AND tblD.ex_id = tblA.ex_id 
AND tblD.exp &lt;> tblB.se_num 
AND tblB.ans = tblA.ans 
AND tblA.ex_id = 1001 
AND tblC.r_id = 542 
GROUP BY 
tblA.type, 
tblA.se_type; </pre><br /><br />乍一看是很复杂的：有4个表，有聚合函数，有9个where条件，还有一个group by。explain的伟大之处在于我们现在可以忽略这些，每次只看两个表，判断每一步MySQL需要什么。这是一个实际的查询，只是字段名有一些改动。explain的结果： <br /><br /><br /><pre name="code" class="java">Java代码 
+-------+--------+---------------+---------+---------+---------------+-------+----------------------------------------------+   
| table | type   | possible_keys | key     | key_len | ref           | rows  | Extra                                        |   
+-------+--------+---------------+---------+---------+---------------+-------+----------------------------------------------+   
| tblA  | ALL    | NULL          | NULL    |    NULL | NULL          |  1080 | Using where; Using temporary; Using filesort |   
| tblB  | ALL    | NULL          | NULL    |    NULL | NULL          | 87189 | Using where                                  |   
| tblC  | eq_ref | PRIMARY       | PRIMARY |       4 | tblB.st_ex_id |     1 | Using where                                  |   
| tblD  | eq_ref | PRIMARY       | PRIMARY |       4 | tblA.ex_id    |     1 | Using where                                  |   
+-------+--------+---------------+---------+---------+---------------+-------+----------------------------------------------+  

+-------+--------+---------------+---------+---------+---------------+-------+----------------------------------------------+
| table | type   | possible_keys | key     | key_len | ref           | rows  | Extra                                        |
+-------+--------+---------------+---------+---------+---------------+-------+----------------------------------------------+
| tblA  | ALL    | NULL          | NULL    |    NULL | NULL          |  1080 | Using where; Using temporary; Using filesort |
| tblB  | ALL    | NULL          | NULL    |    NULL | NULL          | 87189 | Using where                                  |
| tblC  | eq_ref | PRIMARY       | PRIMARY |       4 | tblB.st_ex_id |     1 | Using where                                  |
| tblD  | eq_ref | PRIMARY       | PRIMARY |       4 | tblA.ex_id    |     1 | Using where                                  |
+-------+--------+---------------+---------+---------+---------------+-------+----------------------------------------------+</pre><br /><br />判断连接影响的主要看结果集。结果集就是查询的结果。对于连接，一个估计结果集大小的方法是把MySQL预测的读取每个表的行数相乘。作为估计，这样做比较偏向于坏的情况，因为where条件通常会减少很多的行数。但这个查询的结果集有9400万行。这就是没有索引连接很危险的原因；几千行乘几千行你就会有一个上百万的结果集了。 <br />那么现在这个查询需要什么？从tblA和tblB开始。在sql中： <br /><br /><br /><pre name="code" class="java">AND tblB.q_num = tblA.q_num 
AND tblB.se_num = tblA.se_num 
AND tblB.ans = tblA.ans </pre><br /><br />MySQL 至少需要q_num, se_num, ans中的一个。我选择在se_num和q_num上加索引因为在几乎所有其他的查询中我都会需要它们。折中是优化的一部分，多数人没有时间去为每一个查询找最优的索引方案，只能是找到一个对于大多数情况而言最优的方案。在tblB上加索引(se_num, q_num)，explain的结果： <br /><br /><br /><pre name="code" class="java">Java代码 
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+   
| table | type   | possible_keys | key         | key_len | ref                    | rows | Extra                                        |   
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+   
| tblA  | ALL    | NULL          | NULL        |    NULL | NULL                   | 1080 | Using where; Using temporary; Using filesort |   
| tblB  | ref    | ndx_secn_qn   | ndx_secn_qn |       2 | tblA.se_num,tblA.q_num |  641 | Using where                                  |   
| tblC  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblB.st_ex_id          |    1 | Using where                                  |   
| tblD  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblA.ex_id             |    1 | Using where                                  |   
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+  

+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+
| table | type   | possible_keys | key         | key_len | ref                    | rows | Extra                                        |
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+
| tblA  | ALL    | NULL          | NULL        |    NULL | NULL                   | 1080 | Using where; Using temporary; Using filesort |
| tblB  | ref    | ndx_secn_qn   | ndx_secn_qn |       2 | tblA.se_num,tblA.q_num |  641 | Using where                                  |
| tblC  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblB.st_ex_id          |    1 | Using where                                  |
| tblD  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblA.ex_id             |    1 | Using where                                  |
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+</pre><br />现在结果集下降了99.3%变为692280行。但为什么要停在这里？我们可以很容易的解决tblA的表扫描。因为它是第一个表，我们并不需要为连接加索引，这在tblB上已经做过了。一般来说，给第一个表加索引可以把它当成只在这一个表上查询的情况。在这个例子中很幸运，tblA是："AND tblA.ex_id = 1001"。我们只需要加ex_id索引： <br /><br /><br /><pre name="code" class="java">Java代码 
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+   
| table | type   | possible_keys | key         | key_len | ref                    | rows | Extra                                        |   
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+   
| tblA  | ref    | ndx_ex_id     | ndx_ex_id   |       4 | const                  |    1 | Using where; Using temporary; Using filesort |   
| tblB  | ref    | ndx_secn_qn   | ndx_secn_qn |       2 | tblA.se_num,tblA.q_num |  641 | Using where                                  |   
| tblC  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblB.st_ex_id          |    1 | Using where                                  |   
| tblD  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblA.ex_id             |    1 | Using where                                  |   
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+  

+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+
| table | type   | possible_keys | key         | key_len | ref                    | rows | Extra                                        |
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+
| tblA  | ref    | ndx_ex_id     | ndx_ex_id   |       4 | const                  |    1 | Using where; Using temporary; Using filesort |
| tblB  | ref    | ndx_secn_qn   | ndx_secn_qn |       2 | tblA.se_num,tblA.q_num |  641 | Using where                                  |
| tblC  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblB.st_ex_id          |    1 | Using where                                  |
| tblD  | eq_ref | PRIMARY       | PRIMARY     |       4 | tblA.ex_id             |    1 | Using where                                  |
+-------+--------+---------------+-------------+---------+------------------------+------+----------------------------------------------+</pre><br /><br />现在结果集是641行。相比开始的9400万，可以说了下降了100%。如果继续研究这个查询我们还可以去掉temp table和filesort，但现在查询已经很快了，也已经说明了如何为连接加索引。尽管最初看这个查询很麻烦，但可以看到只要每次独立的看两张表，为 MySQL的需求加索引，整个过程并不困难。 <br /><br /><br />结论 <br /><br />为复杂的连接加索引要认识到两件事： <br /><br />1. 不管sql多复杂，每次只看explain中的两个表 <br /><br />2. 先前表中的值已经有了，我们的工作就是通过索引帮助MySQL在当前表中使用这些值来找到匹配行
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/228179#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 14 Aug 2008 23:25:14 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/228179</link>
        <guid>http://looxiaohu.javaeye.com/blog/228179</guid>
      </item>
      <item>
        <title>sqlserver2000里，nvarchar、varchar有何区别；text、ntext有何区别</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/224734" style="color:red;">http://looxiaohu.javaeye.com/blog/224734</a>&nbsp;
          发表时间: 2008年08月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1.sqlserver2000里，nvarchar、varchar有何区别；text、ntext有何区别；以及  nvarchar、varchar和text、ntext之间有何区别；分别在何种情况下用?<br /><pre name="code" class="java">
带N的类型是Unicode   数据，使用   Unicode   数据类型，列可存储由   Unicode   标准定义的任何字符，包含由不同字符集定义的所有字符。Unicode   数据类型需要相当于非   Unicode   数据类型两倍的存储空间，之所以varchar的最大长度是8000，而NVarchar的最大长度只有4000。
Top

nvarchar(n)   包含n个字符可变长度Unicode字符数据。n   的值必须介于1与4,000   之间。字节的存储大小是所输入字符个数的两倍。   
    
  varchar[(n)]   长度为n个字节的可变长度且非Unicode的字符数据。n必须是一个介于1和8,000之间的数值。存储大小为输入数据的字节的实际长度。   
    
  ntext   可变长度Unicode数据，最大长度为(1,073,741,823)个字符，存储大小是所输入字符个数的两倍（以字节为单位）。   </pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/224734#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 05 Aug 2008 20:36:50 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/224734</link>
        <guid>http://looxiaohu.javaeye.com/blog/224734</guid>
      </item>
      <item>
        <title>【学习娱乐】推荐一款B/S网络游戏</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/223618" style="color:red;">http://looxiaohu.javaeye.com/blog/223618</a>&nbsp;
          发表时间: 2008年08月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          武林三国<br /><a href="http://u.9way.cn/uport/u56984_8" target="_blank">http://u.9way.cn/uport/u56984_8</a><br />有点遗憾，这个B/S游戏是php做的，咋jsp就没有做过了，<img src="/images/smiles/icon_cry.gif"/>。
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/223618#comments" style="color:red;">已有 <strong>13</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 03 Aug 2008 13:41:46 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/223618</link>
        <guid>http://looxiaohu.javaeye.com/blog/223618</guid>
      </item>
      <item>
        <title>【开发工具选集】遇到以下文件，用什么工具打开</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/223505" style="color:red;">http://looxiaohu.javaeye.com/blog/223505</a>&nbsp;
          发表时间: 2008年08月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          *形式* *典型出处和路径* *文件释义及典型用法* <br />****** **************** ******************** <br />——A类—— <br />*.arc 压缩文件,pkarc的压缩文件. <br />*.arj 压缩文件,由arj解压 <br />*.asc 任何地方 无格式的文本文件,只含有文本. <br />*.asm masm,tasm 汇编语言程序, <br />*.asx mp3 列表文件,mp3 playlist(mp3播放文件列表文件) <br />*.avi 多媒体(游戏)中 动画文件,(Audio Video Interface)微软标准动画文件, <br />——B类—— <br />*.bak 任何地方 备份文件, <br />*.bas basica,qbasic basic语言程序, <br />*.bat 任何地方 批处理文件, <br />*.bgi Borland公司的图形界面文件, <br />*.bin (Binary)dos的二进制文件, <br />*.bmp 任何地方 图形文件,位图文件,分灰度,256色,和真彩 <br />——C类—— <br />*.c tubro c c语言程序, <br />*.cab 微软软件 压缩软件, <br />*.cda cd碟 cd文件, <br />*.cfg 任何地方 配置文件, <br />*.chk 由chkdsk.exe产生的文件, <br />*.cmf 音乐文件,(Creative Music File)Creative公司的音乐文件, <br />*.com 任何地方 可执行文件, <br />*.cpl windows 控制面板文件, <br />*.cpp c++ c++语言程序, <br />——D类—— <br />*.dat 任何地方 二进制数据文件, <br />*.dat vcd光盘 vcd文件, <br />*.dat 游戏中 存档文件,如果游戏存盘退出后用dir/os显示的最后一文件是 <br />*.dat,那么它就有可能是存盘文件。 <br />*.dbf Foxbase dBase,Foxbase等的标准数据库文件, <br />*.ddi 压缩文件,diskdupe的压缩文件,可由hd-copy还原 <br />*.dll windows\system (Dynamic Linked Libraty)Windows动态链接库 <br />*.doc word 文本文件,(Document)Windows Word 文档 <br />*.drv (Drive)驱动程序 <br />*.dsm mod 文件 <br />——E类—— <br />*.eps PostScript所用的格式 <br />*.exe 任何地方 可执行文件, <br /><br /><br /><br />——F类—— <br />*.fli 动画文件,Auto Desk公司的动画文件, <br />*.fmt foxbase 格式文件,Foxbase中系统给用户提供的编写各种不同格式的文件, <br />*.fnt windows 字体文件,(Font)Windows的字体文件, <br />*.fox foxbase 程序文件,foxbase编译过的*.prg程序文件 <br />*.frm Visual Basic VB系列的Form窗体文件, <br />*.frm Foxbase 报表格式文件,Foxbase中的报表格式文件 <br />*.frm 注册文件, <br />*.fxp Foxpro 程序文件,Foxpro编译过的*.prg程序文件 <br />——G类—— <br />*.gb 网上常见 文本文件,gb格式的文本 <br />*.gif 网上常见 图形文件,有256色,真彩,gif89等, <br />——H类—— <br />*.h tubro c c语言所需要的include的头文件, <br />*.hlp 任何地方 帮助文件, <br />*.hpp c++ c++的头文件 <br />*.htm internet 超文本文件, <br />*.html internet 超文本文件, <br />——I类—— <br />*.ice 压缩文件,由lha解压 <br />*.icn windows 图标文件,windows的图标文件(Icon) <br />*.ico windows 图标文件,windows的图标文件(Icon) <br />*.idx Foxbase 索引文件, <br />*.idxe Foxbase 索引文件, <br />*.iff 图形文件,AMIGAIFF格式文件 <br />*.img 磁盘镜像文件,由hd-copy还原 <br />*.ini 任何地方 (Initial)初始化文件, <br />*.ins 音色文件,Creative公司的音色文件, <br />*.it Impulse Tracker modules(应该是一种声音文件) <br />*.izh 压缩文件,由lha解压 <br />——J类—— <br />*.jpg 任何地方 图形文件,依照jpeg压缩规格的图形文件, <br />——K类—— <br />——L类—— <br />*.lbl Foxbase 标签文件, <br />*.lbm 图形文件, <br />*.lib 编程语言中 库文件(library) <br />——M类—— <br />*.m3u mp3 列表文件,mp3 playlist(mp3播放文件列表文件) <br />*.mbd Office 表格文件,Access的表格文件, <br />*.mem Foxbase 内存变量文件,用来存放内存变量的文件 <br />*.mid 任何地方 midi文件, <br />*.midi 任何地方 midi文件, <br />*.mlv vcd mpeg文件, <br />*.mod mod文件,protracker modules <br />*.mov 多媒体中 动画文件,压缩率极大的格式 <br />*.mp2 声音文件,压缩率极大的格式 <br />*.mp3 mp3 声音文件,压缩率极大的格式 <br />*.mpe vcd mpeg文件, <br />*.mpeg vcd mpeg文件, <br />*.mpg vcd mpeg文件, <br />*.mpv vcd mpeg文件, <br />*.mtm mod 文件, <br />——N类—— <br />*.ndx Foxbase 索引文件, <br />——O类—— <br />*.obj 编程语言中 目标文件(Object) <br />——P类—— <br />*.pas pascal pascal语言程序, <br />*.pbc 分布式程序库, <br />*.pbd 动态运行程序, <br />*.pbm 图形文件, <br />*.pbr 资源文件, <br />*.pcx 任何地方 图形文件, <br />*.pgm 图形文件, <br />*.pif windows (Program Information File)Windows执行dos程序的资讯文件, <br />*.pls mp3 列表文件,mp3 playlist(mp3播放文件列表文件) <br />*.png 图形文件, <br />*.prg Foxbase 程序文件,Foxbase的程序文件 <br />*.pwl win95,windows＼*.pwl 口令文件,删除后可取消windows开机用户口令 <br />——Q类—— <br />*.qid 线导文件, <br />——R类—— <br />*.reg 注册表的备份文件, <br />*.rle 图形文件, <br />——S类—— <br />*.s3m Screamtracker Modules(应该也是一种声音文件) <br />*.scr windows 屏幕保护程序, <br />*.stm Screamtracker Modules(应该也是一种声音文件) <br />*.sys 任何地方 设备驱动程序(系统文件) 这类文件含有关于硬件的说明. <br />——T类—— <br />*.tga 图形文件, <br />*.tif 图形文件, <br />*.tmp 几乎任何地方,temp＼*.tmp 临时文件,非正常退出时产生的临时文件,可删除 <br />*.txt 任何地方 文本文件,记录文本 <br />——U类—— <br />——V类—— <br />*.vol 任何地方 声音文件, <br />——W类—— <br />*.wav 任何地方, 声音文件, <br />*.wmf 图形文件, <br />*.wps wps中,ucdos＼*.wps wps 文件,记录文本,表格 <br />*.wri 文本文件,Windows书写器文件 <br />——X类—— <br />*.xls Office 表格文件,Excel的表格文件, <br />*.xm extended modules(应该也是一种声音文件) <br />——Y类—— <br />——Z类—— <br />*.zip 任何地方 压缩文件, <br />——其他—— <br />*.%a% dos版wps中,wps＼*.%a% 临时文件,由于wps非正常退出产生的文件, <br />*.%b% dos版wps中,wps＼*.%a% 临时文件,由于wps非正常退出产生的文件, <br />~*.* 临进文件,以 ~ 开头的文件为临时文件,可删除 <br /><br /><br /><br />补充:文件类型 扩展名及打开方式 <br />文档文件 txt（所有文字处理软件或编辑器都可打开）、doc（word及wps等软件可打开）、hlp（adobe acrobat reader可打开）、wps（wps软件可打开）、rtf（word及wps等软件可打开）、htm（各种浏览器可打开、用写字板打开可查看其源代码）、pdf（adobe acrobat reader 和各种电子阅读软件可打开） <br />压缩文件 rar（winrar可打开）、zip（winzip可打开）、arj（用arj解压缩后可打开）、gz（unix系统的压缩文件，用winzip可打开）、z（unix系统的压缩文件，用winzip可打开） <br />图形文件 bmp、gif、jpg、pic、png、tif（这些文件类型用常用图像处理软件可打开） <br />声音文件 wav（媒本播放器可打开）、aif（常用声音处理软件可打开）、au（常用声音处理软件可打开）、mp3（由winamp播放）、ram（由realplayer播放） <br />动画文件 avi（常用动画处理软件可播放）、mpg（由vmpeg播放）、mov（由activemovie播放）、swf（用flash自带的players程序可播放） <br />系统文件 int、sys、dll、adt <br />可执行文件 exe、com <br />语言文件 c、asm、for、lib、lst、msg、obj、pas、wki、bas <br />映像文件 map （其每一行都定义了一个图像区域以及当该区域被触发后应返回的url信息） <br />备份文件 bak（被自动或是通过命令创建的辅助文件，它包含某个文件的最近一个版本） <br />临时文件 $ $ $（word、excel等软件在操作时会产生此类文件） <br />模板文件 dot（通过word模板可以简化一些常用格式文档的创建工作） <br />批处理文件 bat（在ms-dos中，bat文件是可执行文件，由一系列命令构成，其中可以包含对其他程序的调用）
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/223505#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 03 Aug 2008 01:35:42 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/223505</link>
        <guid>http://looxiaohu.javaeye.com/blog/223505</guid>
      </item>
      <item>
        <title>URL编码方法比较 Encode,Javascript,escape,encodeURI,encod</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/220334" style="color:red;">http://looxiaohu.javaeye.com/blog/220334</a>&nbsp;
          发表时间: 2008年07月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          javascript中存在几种对URL字符串进行编码的方法：escape()，encodeURI()，以及encodeURIComponent()。这几种编码所起的作用各不相同。 <br />escape() 方法： <br /><br />采用ISO Latin字符集对指定的字符串进行编码。所有的空格符、标点符号、特殊字符以及其他非ASCII字符都将被转化成%xx格式的字符编码（xx等于该字符在字符集表里面的编码的16进制数字）。比如，空格符对应的编码是%20。 <br /><br />不会被此方法编码的字符： @ * / + <br /><br />encodeURI() 方法： <br /><br />把URI字符串采用UTF-8编码格式转化成escape格式的字符串。 <br /><br />不会被此方法编码的字符：! @ # $& * ( ) = : / ; ? + ' <br /><br />encodeURIComponent() 方法： <br /><br />把URI字符串采用UTF-8编码格式转化成escape格式的字符串。与encodeURI()相比，这个方法将对更多的字符进行编码，比如 / 等字符。所以如果字符串里面包含了URI的几个部分的话，不能用这个方法来进行编码，否则 / 字符被编码之后URL将显示错误。 <br /><br />不会被此方法编码的字符：! * ( ) ' <br /><br />因此，对于中文字符串来说，如果不希望把字符串编码格式转化成UTF-8格式的（比如原页面和目标页面的charset是一致的时候），只需要使用escape。如果你的页面是GB2312或者其他的编码，而接受参数的页面是UTF-8编码的，就要采用encodeURI或者encodeURIComponent。 <br /><br />另外，encodeURI/encodeURIComponent是在javascript1.5之后引进的，escape则在javascript1.0版本就有。
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/220334#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 28 Jul 2008 10:07:16 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/220334</link>
        <guid>http://looxiaohu.javaeye.com/blog/220334</guid>
      </item>
      <item>
        <title>系统管理软件中帐号和账号哪个正确？谁来帮帮我</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/218634" style="color:red;">http://looxiaohu.javaeye.com/blog/218634</a>&nbsp;
          发表时间: 2008年07月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">古汉语词典上说: 
帐:1.帐幕 2.帐薄,户籍薄 
账:单指薄籍,薄册 

现在汉语词典上说: 
当指和钱财相关的记载时,"帐"和"账"是通用的. 

所以,“账户”和“帐户”没有区别. 

有人说以前的一次汉语语法修订中将“帐户”这个用法给取消了。事实也是如此，在Word中输入的“帐户”会被Word的语法检查看作是错别字，而Word也认为“账户”是正确的。可是Windows中用的全部是“帐户”。 

《后汉书》：“帐者，犹中国之户数也。”（意思是：游牧民族所说的“帐”相当于中原的“户”） 

《辞源》：“账”，古作“帐”，后为避免与“帷帐”混淆，另造“账”字，用于money。 
（《说文解字》时尚无“账”） 

所以这是文字自然流变造成的，历史够悠久了，不是今人之错。 

这样的现象还很多，积习难改。 

所以，最新版的《现代汉语词典》（它反映国家的语言文字政策）是这样处理的： 
在“帐”的释义里注明：②同“账”。 
但不在“帐”下收列与“账”有关的词。 
就是说，你还可以用“帐户”etc，但推荐使用“账户”etc。 


一些报纸上常把“账户”写成“帐户”，对不对呢？“审计”一番可知：前些年这样“作帐”还马马虎虎。后来有了新规范，这样“作帐”就不妥了。 
据国家语委有关资料，由于古人常把账目记于布帛上悬挂起来以利保存，故称日用的账目为“帐”；后来为了与帷帐分开，另造形声字“账”，表示与钱财有关。 
教育部、国家语委发布的《第一批异形词整理表》（2002年3月31日试行）的注释中说，“账”、“帐”二字分工如下：“账”用于货币和货物出入的记载、债务等，如“账本、报账、借账、还账”等；“帐”专表用布、纱、绸子等制成的遮蔽物，如“蚊帐、帐篷、青纱帐（比喻用法）”等。 
《现代汉语词典》（2002年增补本）只有“账户”词条，而无“帐户”词条，对“账户”的解释是：会计上指账簿中对各种资金运用、来源和周转过程等设置的分类。 
经国家语委等修改而成的《图书编校质量差错认定细则》中的第七条列举了“常见的较难界定的别字”，其中有“欠账（帐）、账（帐）簿”等，并特别说明“括号里的字是错的”。 </pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://looxiaohu.javaeye.com/blog/218634#comments" style="color:red;">已有 <strong>1</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 23 Jul 2008 16:45:59 +0800</pubDate>
        <link>http://looxiaohu.javaeye.com/blog/218634</link>
        <guid>http://looxiaohu.javaeye.com/blog/218634</guid>
      </item>
      <item>
        <title>XML 经典教程</title>
        <author>looxiaohu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://looxiaohu.javaeye.com">looxiaohu</a>&nbsp;
          链接：<a href="http://looxiaohu.javaeye.com/blog/216766" style="color:red;">http://looxiaohu.javaeye.com/blog/216766</a>&nbsp;
          发表时间: 2008年07月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          dom4j 是一种解析 XML 文档的开放源代码 XML 框架。本文介绍如何使用包含在 dom4j 中的解析器创建并修改 XML 文档。<br />dom4j API 包含一个解析 XML 文档的工具。本文中将使用这个解析器创建一个示例 XML 文档。清单 1 显示了这个示例 XML 文档，catalog.xml。<br /><br />清单 1. 示例 XML 文档（catalog.xml） <br /><pre name="code" class="java">&lt;?xml version="1.0" encoding="UTF-8"?> 
&lt;catalog> 
&lt;!--An XML Catalog--> 
&lt;?target instruction?>
  &lt;journal title="XML Zone" 
                  publisher="IBM developerWorks"> 
&lt;article level="Intermediate" date="December-2001">
 &lt;title>Java configuration with XML Schema&lt;/title> 
 &lt;author> 
     &lt;firstname>Marcello&lt;/firstname> 
     &lt;lastname>Vitaletti&lt;/lastname> 
 &lt;/author>
  &lt;/article>
  &lt;/journal> 
&lt;/catalog></pre><br /> <br /><br /><br />然后使用同一个解析器修改 catalog.xml，清单 2 是修改后的 XML 文档，catalog-modified.xml。<br /><br />清单 2. 修改后的 XML 文档（catalog-modified.xml） <br /><pre name="code" class="java">&lt;?xml version="1.0" encoding="UTF-8"?> 
&lt;catalog> 
&lt;!--An XML catalog--> 
&lt;?target instruction?>
  &lt;journal title="XML Zone"
                   publisher="IBM developerWorks"> 
&lt;article level="Introductory" date="October-2002">
 &lt;title>Create flexible and extensible XML schemas&lt;/title> 
 &lt;author> 
     &lt;firstname>Ayesha&lt;/firstname> 
     &lt;lastname>Malik&lt;/lastname> 
 &lt;/author> 
  &lt;/article>
  &lt;/journal> 
&lt;/catalog>
 </pre><br /><br /><br />与 W3C DOM API 相比，使用 dom4j 所包含的解析器的好处是 dom4j 拥有本地的 XPath 支持。DOM 解析器不支持使用 XPath 选择节点。<br /><br />本文包括以下几个部分：<br /><br />预先设置 <br />创建文档 <br />修改文档 <br />预先设置<br /><br />这个解析器可以从 http://dom4j.org 获取。通过设置使 dom4j-1.4/dom4j-full.jar 能够在 classpath 中访问，该文件中包括 dom4j 类、XPath 引擎以及 SAX 和 DOM 接口。如果已经使用了 JAXP 解析器中包含的 SAX 和 DOM 接口，向 classpath 中增加 dom4j-1.4/dom4j.jar 。 dom4j.jar 包括 dom4j 类和 XPath 引擎，但是不含 SAX 与 DOM 接口。 <br /><br /><br /><br />创建文档<br /><br />本节讨论使用 dom4j API 创建 XML 文档的过程，并创建示例 XML 文档 catalog.xml。<br /><br />使用 import 语句导入 dom4j API 类：<br /><br />import org.dom4j.Document;<br />import org.dom4j.DocumentHelper;<br />import org.dom4j.Element;<br /> <br /><br /><br />使用 DocumentHelper 类创建一个文档实例。 DocumentHelper 是生成 XML 文档节点的 dom4j API 工厂类。 <br /><br /><pre name="code" class="java"> Document document = DocumentHelper.createDocument(); </pre><br /><br /><br />使用 addElement() 方法创建根元素 catalog 。 addElement() 用于向 XML 文档中增加元素。 <br /><br /><pre name="code" class="java">Element catalogElement = document.addElement("catalog"); </pre><br /><br /><br />在 catalog 元素中使用 addComment() 方法添加注释“An XML catalog”。 <br /><br /> <pre name="code" class="java">catalogElement.addComment("An XML catalog"); </pre><br /><br /><br />在 catalog 元素中使用 addProcessingInstruction() 方法增加一个处理指令。 <br /><br /><pre name="code" class="java">catalogElement.addProcessingInstruction("target","text"); </pre><br /><br /><br />在 catalog 元素中使用 addElement() 方法增加 journal 元素。 <br /><br /><pre name="code" class="java">Element journalElement =  catalogElement.addElement("journal"); </pre><br /><br /><br />使用 addAttribute() 方法向 journal 元素添加 title 和 publisher 属性。 <br /><br /><pre name="code" class="java">journalElement.addAttribute("title", "XML Zone");
         journalElement.addAttribute("publisher", "IBM developerWorks"); </pre><br /><br />向 article 元素中添加 journal 元素。 <br /><br /><pre name="code" class="java">Element articleElement=journalElement.addElement("article"); </pre><br /><br /><br />为 article 元素增加 level 和 date 属性。 <br /><br /><pre name="code" class="java">articleElement.addAttribute("level", "Intermediate");
      articleElement.addAttribute("date", "December-2001"); </pre><br /><br /><br />向 article 元素中增加 title 元素。 <br /><br /><pre name="code" class="java">Element titleElement=articleElement.addElement("title"); </pre><br /><br /><br />使用 setText() 方法设置 article 元素的文本。 <br /><br /><pre name="code" class="java">titleElement.setText("Java configuration with XML Schema"); </pre><br /><br /><br />在 article 元素中增加 author 元素。 <br /><br /><pre name="code" class="java">Element authorElement=articleElement.addElement("author"); </pre><br /><br /><br />在 author 元素中增加 firstname 元素并设置该元素的文本。 <br /><br /><pre name="code" class="java">Element  firstNameElement=authorElement.addElement("firstname");
     firstNameElement.setText("Marcello");</pre> <br /><br /><br />在 author 元素中增加 lastname 元素并设置该元素的文本。 <br /><br /><pre name="code" class="java">Element lastNameElement=authorElement.addElement("lastname");
     lastNameElement.setText("Vitaletti"); </pre><br /><br /><br />可以使用 addDocType() 方法添加文档类型说明。 <br /><br /><pre name="code" class="java">document.addDocType("catalog", null,"file://c:/Dtds/catalog.dtd"); </pre>这样就向 XML 文档中增加文档类型说明：<br /><br />&lt;!DOCTYPE catalog SYSTEM "file://c:/Dtds/catalog.dtd"> <br /><br /><br />如果文档要使用文档类型定义（DTD）文档验证则必须有 Doctype。<br /><br />XML 声明 &lt;?xml version="1.0" encoding="UTF-8"?> 自动添加到 XML 文档中。 <br /><br />清单 3 所示的例子程序 XmlDom4J.java 用于创建 XML 文档 catalog.xml。<br /><br />清单 3. 生成 XML 文档 catalog.xml 的程序（XmlDom4J.java） <br /><pre name="code" class="java">import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import java.io.*;
public class XmlDom4J{
public void generateDocument(){
Document document = DocumentHelper.createDocument();
     Element catalogElement = document.addElement("catalog");
     catalogElement.addComment("An XML Catalog");
     catalogElement.addProcessingInstruction("target","text");
     Element journalElement =  catalogElement.addElement("journal");
     journalElement.addAttribute("title", "XML Zone");
     journalElement.addAttribute("publisher", "IBM developerWorks");
     Element articleElement=journalElement.addElement("article");
     articleElement.addAttribute("level", "Intermediate");
     articleElement.addAttribute("date", "December-2001");
     Element  titleElement=articleElement.addElement("title");
     titleElement.setText("Java configuration with XML Schema");
     Element authorElement=articleElement.addElement("author");
     Element  firstNameElement=authorElement.addElement("firstname");
     firstNameElement.setText("Marcello");
     Element lastNameElement=authorElement.addElement("lastname");
     lastNameElement.setText("Vitaletti");
     document.addDocType("catalog",
                           null,"file://c:/Dtds/catalog.dtd");
    try{
    XMLWriter output = new XMLWriter(
            new FileWriter( new File("c:/catalog/catalog.xml") ));
        output.write( document );
        output.close();
        }
     catch(IOException e){System.out.println(e.getMessage());}
}
public static void main(String[] argv){
XmlDom4J dom4j=new XmlDom4J();
dom4j.generateDocument();
}}
 </pre><br /><br />这一节讨论了创建 XML 文档的过程，下一节将介绍使用 dom4j API 修改这里创建的 XML 文档。 <br /><br /><br /><br />修改文档<br /><br />这一节说明如何使用 dom4j API 修改示例 XML 文档 catalog.xml。<br /><br />使用 SAXReader 解析 XML 文档 catalog.xml：<br /><pre name="code" class="java">
SAXReader saxReader = new SAXReader();
 Document document = saxReader.read(inputXml); </pre><br /><br /><br />SAXReader 包含在 org.dom4j.io 包中。 <br /><br />inputXml 是从 c:/catalog/catalog.xml 创建的 java.io.File。使用 XPath 表达式从 article 元素中获得 level 节点列表。如果 level 属性值是“Intermediate”则改为“Introductory”。 <br /><br /><pre name="code" class="java">List list = document.selectNodes("//article/@level" );
      Iterator iter=list.iterator();
        while(iter.hasNext()){
            Attribute attribute=(Attribute)iter.next();
               if(attribute.getValue().equals("Intermediate"))
               attribute.setValue("Introductory"); 
       } </pre>获取 article 元素列表，从 article 元素中的 title 元素得到一个迭代器，并修改 title 元素的文本。 <br /><br /><pre name="code" class="java">list = document.selectNodes("//article" );
     iter=list.iterator();
   while(iter.hasNext()){
       Element element=(Element)iter.next();
      Iterator iterator=element.elementIterator("title");
   while(iterator.hasNext()){
   Element titleElement=(Element)iterator.next();
   if(titleElement.getText().equals("Java configuration with XML Schema"))
     titleElement.setText("Create flexible and extensible XML schema");
    }} </pre><br />通过和 title 元素类似的过程修改 author 元素。 <br /><br />清单 4 所示的示例程序 Dom4JParser.java 用于把 catalog.xml 文档修改成 catalog-modified.xml 文档。<br /><br />清单 4. 用于修改 catalog.xml 的程序（Dom4Jparser.java） <br /><pre name="code" class="java">import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Attribute;
import java.util.List;
import java.util.Iterator;
import org.dom4j.io.XMLWriter;
import java.io.*;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader; 
public class Dom4JParser{
 public void modifyDocument(File inputXml){
  try{
   SAXReader saxReader = new SAXReader();
   Document document = saxReader.read(inputXml);
   List list = document.selectNodes("//article/@level" );
   Iterator iter=list.iterator();
   while(iter.hasNext()){
    Attribute attribute=(Attribute)iter.next();
    if(attribute.getValue().equals("Intermediate"))
      attribute.setValue("Introductory"); 
       }
   
   list = document.selectNodes("//article/@date" );
   iter=list.iterator();
   while(iter.hasNext()){
    Attribute attribute=(Attribute)iter.next();
    if(attribute.getValue().equals("December-2001"))
      attribute.setValue("October-2002");
       }
   list = document.selectNodes("//article" );
   iter=list.iterator();
   while(iter.hasNext()){
    Element element=(Element)iter.next();
    Iterator iterator=element.elementIterator("title");
      while(iterator.hasNext()){
        Element titleElement=(Element)iterator.next();
        if(titleElement.getText().equals("Java configuration with XML
      Schema"))
        titleElement.setText("Create flexible and extensible XML schema");
                                          }
                                }
    list = document.selectNodes("//article/author" );
    iter=list.iterator();
     while(iter.hasNext()){
     Element element=(Element)iter.next();
     Iterator iterator=element.elementIterator("firstname");
     while(iterator.hasNext()){
      Element firstNameElement=(Element)iterator.next();
      if(firstNameElement.getText().equals("Marcello"))
      firstNameElement.setText("Ayesha");
                                     }
                              }
    list = document.selectNodes("//article/author" );
    iter=list.iterator();
     while(iter.hasNext()){
      Element element=(Element)iter.next();
      Iterator iterator=element.elementIterator("lastname");
     while(iterator.hasNext()){
      Element lastNameElement=(Element)iterator.next();
      if(lastNameElement.getText().equals("Vitaletti"))
      lastNameElement.setText("Malik");
                                  }
                               }
     XMLWriter output = new XMLWriter(
      new FileWriter( new File("c:/catalog/catalog-modified.xml") ));
     output.write( document );
     output.close();
   }
 
  catch(DocumentException e)
                 {
                  System.out.println(e.getMessage());
                            }
  catch(IOException e){
                       System.out.println(e.getMessage());
                    }
 }
 public static void main(String[] argv){
  Dom4JParser dom4jParser=new Dom4JParser();
  dom4jParser.modifyDocument(new File("c:/catalog/catalog.xml"));
                                        }
   }
 </pre>
          <br/><br/>
          <span style="color: