星期三, 十月 24, 2007

用java操纵文件后缀名

 import java.io.File;

 /*
  * Created on 2006-9-19
  *
  * TODO To change the template for this generated file go to
  * Window - Preferences - Java - Code Style - Code Templates
  */

 /**
  * @author public2298
  *
  * TODO To change the template for this generated type comment go to
  * Window - Preferences - Java - Code Style - Code Templates
  */
 public abstract class BaseFolder {
  private String folderPath = null;
  protected String suffix = null;
  
  public void visit(File file)
  {
   if(file.isDirectory())
   {
       if(getCondition(file))
           folderOper(file);
       else
       {
     File[] fileArray = file.listFiles();
     for(int i=0;i<fileArray.length;i++)
     {
      visit(fileArray[i]);
     }
       }
   }
   else
   {
    fileOper(file);
   }
  }
  protected void folderOper(File file){}
  
  protected void fileOper(File file){}
  protected boolean getCondition(File file){return false;}
  protected void deleteFolder(File file)
  {
   if(file.isDirectory())
   {
    File[] fileArray = file.listFiles();
    for(int i=0;i<fileArray.length;i++)
    {
     deleteFolder(fileArray[i]);
    }
    file.delete();
   }
   else
    file.delete();
  }
  //添加后缀名
  protected void addSuffix(File file)
  {
      formatSuffix();
      file.renameTo(new File(file.getAbsolutePath()+suffix));
  }
  //去掉后缀名
  protected void deleteSuffix(File file)
  {
      formatSuffix();
      String path = file.getAbsolutePath();
      if(path.endsWith(suffix))
      {
          path = path.substring(0,path.length()-suffix.length());
          file.renameTo (new File(path));
      }
  }
  //如果后缀名不含有点,就加上点.
  private void formatSuffix()
  {
      if((suffix!=null)&&(!suffix.startsWith(".")))
          suffix = "."+suffix;
  }
  protected void clean()
  {
   
  }
  
  protected void setSuffix(String suffix) {
         this.suffix = suffix;
     }
 }

 
 //工具类

 import java.io.File;

 /*
  * Created on 2006-9-27

  * Window - Preferences - Java - Code Style - Code Templates
  */

 public class FolderUtils {
     private File file;
     private BaseFolder folder;
     public FolderUtils(File file)
     {
         this.file = file;
     }
     
     public void addSuffix(String suffix)
     {
         folder = new AddFileSuffix();
         folder.setSuffix(suffix);
         folder.visit(file);     
     }
     public void deleteSuffix(String suffix)
     {
         folder = new DeleteFileSuffix();
         folder.setSuffix(suffix);
         folder.visit(file);     
     }
     public void deleteFileByPattern(String pattern)
     {
         folder = new DeleteFileByPattern(pattern);
         folder.visit (file);
     }
     public void deleteFileBySuffix(String suffix)
     {
         folder = new DeleteFileBySuffix(suffix);
         folder.visit(file);
     }
     public void deleteFodler(String pattern)
     {
         folder = new DeleteFolderByName(pattern);
         folder.visit(file);
     }
     public void renameFile(long startNumber)
     {
         folder = new RenameFileLikeNumber(startNumber);
         folder.visit(file);
     }
     public static void main(String[] args) {
         FolderUtils util = new FolderUtils(new File("d:/src/yy"));
         //util.addSuffix(".yx");
         //util.deleteSuffix(".yx");
         //util.deleteFileByPattern("yinxing.txt");
         //util.deleteFileBySuffix(".yx");
         //util.deleteFodler("yyy");
         util.renameFile(999);
     }
     

     public void setFile(File file) {
         this.file = file;
     }
 }

 //如果文件是以指定名字为后缀,就删除文件的后缀
 class DeleteFileSuffix extends BaseFolder {
     public void fileOper(File file) {
         this.deleteSuffix(file);
     }
 }
 //如果文件增加后缀
 class AddFileSuffix extends BaseFolder {
     public void fileOper(File file) {
         this.addSuffix(file);
     }
 }

 //删除文件夹名和指定名字一样的文件夹,不考虑大小写.
 class DeleteFolderByName extends BaseFolder {
     private String pattern = null;
     public DeleteFolderByName(String pattern)
     {
         this.pattern = pattern;
     }
     public void folderOper(File file)
     {
         deleteFolder(file);
     }
     public boolean getCondition(File file)
     {
         return file.getName().equalsIgnoreCase(pattern);
     }
 }
 //如果文件名包含指定pattern,就将文件删除
 class DeleteFileByPattern extends BaseFolder {
     private String pattern = null;
     public DeleteFileByPattern(String pattern)
     {
         this.pattern = pattern;
     }   
     public void fileOper(File file) {
         if(pattern==null)
             return;
         String fileName = file.getName();
         if(fileName.contains(pattern))
             file.delete ();
     }
 }
 //删除具有指定后缀名的文件
 class DeleteFileBySuffix extends BaseFolder {
     private String suffix;
     public DeleteFileBySuffix(String suffix)
     {
         this.suffix = suffix;
     }
     public void fileOper(File file) {
         String path = file.getAbsolutePath();
         if(path.endsWith(suffix))
             file.delete();
     }
 }
 //以依次增加的数字编号重命名文件
 class RenameFileLikeNumber extends BaseFolder
 {
     private final String WILDCARD = "#";  //通配符
     private String pattern = null;
     private long startNumber = 0;
     private long count = 0;
     
     public RenameFileLikeNumber(){}
     public RenameFileLikeNumber(long startNumber)
     {
         this.startNumber = startNumber;
         count = startNumber;
     }
     public RenameFileLikeNumber(long startNumber,String pattern)
     {
         this.startNumber = startNumber;
         this.pattern = pattern;
         count = startNumber;
     }
     public void fileOper(File file) {
         this.rename(file,getNameForFile());
         count++;
     }
     private String getNameForFile()
     {
         String fileName = "";
         if(pattern!=null)
         {
          int i = pattern.length();
          int j =  Long.toString(count).length();
          for(int k=j;k<i;k++)
              fileName += "0";
          fileName += count+"";
          return fileName;
         }
         else
             return count+"";
     }
 }

星期日, 十月 14, 2007

关闭开机Ctrl + Alt + Del组合键

Start→Administrative Tools→Local security policy→Local Policies→Security Options→Interactive Logon:Do not require CTRL+ALT+DEL

关闭win2003事件跟踪程序

Run --->gpedit.msc--->Administrative Templates--->System--->Display Shutdown Event tracker

星期三, 十月 10, 2007

CSV文件格式

CSV即Comma Separate Values,这种文件格式经常用来作为不同程序之间的数据交互的格式。

具体文件格式

  • 每条记录占一行
  • 以逗号为分隔符
  • 逗号前后的空格会被忽略
  • 字段中包含有逗号,该字段必须用双引号括起来
  • 字段中包含有换行符,该字段必须用双引号括起来
  • 字段前后包含有空格,该字段必须用双引号括起来
  • 字段中的双引号用两个双引号表示
  • 字段中如果有双引号,该字段必须用双引号括起来
  • 第一条记录,可以是字段名
  • The CSV File Format


     

    • Each record is one line   ...but
      A record separator may consist of a line feed (ASCII/LF=0x0A), or a carriage return and line feed pair (ASCII/CRLF=0x0D 0x0A).
      ...but: fields may contain embedded line-breaks ( see below) so a record may span more than one line.

    • Fields are separated with commas.
      Example John,Doe,120 any st.,"Anytown, WW",08123

    • Leading and trailing space-characters adjacent to comma field separators are ignored.
      So   John  ,   Doe  ,... resolves to "John" and "Doe", etc. Space characters can be spaces, or tabs.

    • Fields with embedded commas must be delimited with double-quote characters.
      In the above example. "Anytown, WW" had to be delimited in double quotes because it had an embedded comma.

    • Fields that contain double quote characters must be surounded by double-quotes, and the embedded double-quotes must each be represented by a pair of consecutive double quotes.
      So, John "Da Man" Doe would convert to "John ""Da Man""",Doe, 120 any st.,...

    • A field that contains embedded line-breaks must be surounded by double-quotes
      So:
        Field 1: Conference room 1  
        Field 2:
          John,
          Please bring the M. Mathers file for review  
          -J.L.
        Field 3: 10/18/2002
        ...

      would convert to:

        Conference room 1, "John,  
        Please bring the M. Mathers file for review  
        -J.L.
        ",10/18/2002,...

      Note that this is a single CSV record, even though it takes up more than one line in the CSV file. This works because the line breaks are embedded inside the double quotes of the field.

      Implementation note: In Excel, leading spaces between the comma used for a field sepparator and the double quote will sometimes cause fields to be read in as unquoted fields, even though the first non-space character is a double quote. To avoid this quirk, simply remove all leading spaces after the field-sepparator comma and before the double quote character in your CSV export files.

    • Fields with leading or trailing spaces must be delimited with double-quote characters.
      So to preserve the leading and trailing spaces around the last name above: John ,"   Doe   ",...

      Usage note: Some applications will insist on helping you by removing leading and trailing spaces from all fields regardless of whether the CSV used quotes to preserve them. They may also insist on removing leading zeros from all fields regardless of whether you need them. One such application is Excel. :-( For some help with this quirk, see the section below entitled Excel vs. Leading Zero & Space .

    • Fields may always be delimited with double quotes.
      The delimiters will always be discarded.

      Implementation note: When importing CSV, do not reach down a layer and try to use the quotes to impart type information to fields. Also, when exporting CSV, you may want to be defensive of apps that improperly try to do this. Though, to be honest, I have not found any examples of applications that try to do this. If you have encountered any apps that attempt to use the quotes to glean type information from CSV files (like assuming quoted fields are strings even if they are numeric), please let me know about it.

    • The first record in a CSV file may be a header record containing column (field) names
      There is no mechanism for automatically discerning if the first record is a header row, so in the general case, this will have to be provided by an outside process (such as prompting the user). The header row is encoded just like any other CSV record in accordance with the rules above. A header row for the multi-line example above, might be:
        Location, Notes, "Start Date", ...

     

    星期一, 十月 01, 2007

    安装NOTES db的ODBC驱动,errorcode 126问题

    安装NotesSQL3.02j(文件名一般为C959CEN.exe);
    运行NotesSQL Authentication List Manager,设置notes.ini跟ID文件
    进入控制面板,管理工具,ODBC DataSource Administrator。新建DSN,这时候会有125错误,大体意思指*.nsf无法读取。
    不知道中文下提示信息具体是什么。
     
    解决方法:将notes.ini所在目录(通常为:C:\Program Files\Lotus\Notes)跟dll文件所在目录(通常为:C:\NotesSQL)加到环境变量Path中。
    问题解决。

    星期一, 九月 03, 2007

    伪静态

    apahce配置 URL重写(伪静态)

    把如下内容保存为 .htaccess添加到网站的目录下:

    # RewriteEngine 模式打开

    RewriteEngine On

     

    # 修改以下语句中的 / 为你的网站目录地址,如果程序放在二级目录中,如/phpcms 请将 / 修改为 /phpcms

    RewriteBase /

     

    # Rewrite 系统规则,添加或者修改请根据其规则

    RewriteRule ^(.*)show-([0-9]+)-([0-9]+)\.html$ $1/show.jsp?itemid=$2&page=$3  

    RewriteRule ^(.*)list-([0-9]+)-([0-9]+)\.html$ $1/list.jsp?catid=$2&page=$3  

    RewriteRule ^(.*)show-([0-9]+)\.html$ $1/show.jsp?specialid=$2


    星期四, 八月 16, 2007

    js:修改对象onclick属性

     aTag[0].onclick = function(){showHide(id)};//both of Mozilla and IE
     aTag[0].setAttribute("onclick", "showHide('"+id+"')");//Mozilla
     aTag[0].setAttribute("onclick", function(){showHide(id)});//IE

    星期五, 八月 10, 2007

    iptables

    /etc/sysconfig/iptables

    快速清空表

    ALTER TABLE  tablename ACTIVATE NOT LOGGED INITIALLY WITH EMPTY TABLE;

    星期四, 八月 09, 2007

    生成文件树

    3.在命令提示符窗口中输入以下命令,如图2所示。

      dir d:\ >c:\filelist.txt

    小技巧:用DOS命令生成光盘文件列表

    图2 用此命令生成列表文件

      这样就在C:盘根目录下生成了一个名为"filelist.txt"的文本文件,该文件中即包含D:盘的文件夹列表。

      如果希望将D:盘中子目录中的文件和文件夹列表也全部列出来,可以在命令提示符窗口中输入以下命令。

      dir d:\ /s >c:\filelist.txt

      如果使用下面的命令,即加一个/b,则会生成一个简单的文件名列表,不包括其它信息,这种方法可能更加实用一些。

      dir d:\ /s /b >c:\filelist.txt

      生成文本文件后,就可以将该文件中的内容拷贝到Excel中以备日后查询,或者将该文件作为一个对象插入到Excel工作表中。这样以后就可以快速找到所需要的光盘了。

     

    1、命令 dir *.*/b/s > filelist.txt
    生成的文件格式:
    X:\XXX\A.XXX
    X:\XXX\B.XXX
    ...

    2、命令 dir *.*/b > filelist.txt
    生成的文件格式:
    A.XXX
    B.XXX
    ...

    3、命令 dir *.*/s > filelist.txt
    生成的文件格式:
    驱动器 X 中的卷是 ASOFT
    卷的序列号是 18A2-30C9

    X:\XXX 的目录

    2005-01-13 19:46 3,739,854 A.XXX
    2005-01-13 19:45 3,924,174 B.XXX
    ...
    170 个文件 704,193,612 字节
    0 个目录 2,889,695,232 可用字节

    4、命令 dir *.*/b > filelist.txt
    生成的文件格式:
    同3

    5、命令 tree/f > X:\tree.txt
    可以生成树形文件结构,适合做层次分明的文件结构清单,比如网站内容清单等

    星期三, 八月 08, 2007

    星期三, 八月 01, 2007

    StringUtil


    package sample;

    import java.util.StringTokenizer;
    /**

      * StringUtil
      */
    public class StringUtil {
             /**
              * 文字列の分割(区切り文字指定)
              * @param str 対象文字列
              * @param delim 区切り文字列
              * @return 分割後の文字列
              */
             public static String[] split(String str, String delim) {
                      StringTokenizer st = new StringTokenizer(str, delim);
                      int length = st.countTokens();
                      String[] result = new String[length];
                      for (int i = 0; i < length; i++) {
                          result[i] = st.nextToken();
                      }
                      return result;
             }

    }

    星期四, 七月 19, 2007

    PreparedStatement和Statement

    preparedstatement 优点
     
    1,安全
    2,对于重复数据,速度快
    3,对了重复数据,占用服务器的pool少
     
    Statement优点
     
    1,利于编程,拼sql简单
    2,对于一次性执行,比preparedstatement快

    星期二, 七月 03, 2007

    copy file

    package test;

    import java.io.File;
    import java.io.IOException;
    import java.util.Calendar;


    public class test {

     
     public static void main(String args[]) {
      String filename1 = "C:\\1";
      String filename2 = "C:\\2";
      test test1 = new test();
      try{
      test1.copyFileByPath(filename1, filename2);
      }catch (Exception e) {
       // TODO: handle exception
      }
     }
     
     public void copyFileByPath(String scrPathName,String targetPathName)
      throws NullPointerException,IOException, Exception {
      try{
       File scrPath = new File(scrPathName);
       File targetPath = new File(targetPathName);
       copyFileByPath(scrPath, targetPath);
      }catch (NullPointerException e) {
       //logger.error(dir.getName() + " folder is not exist", e);
       throw e;
      } catch (IOException e) {
       //logger.error(e.getMessage(),e);
       throw e;
      }catch (Exception e) {
       //logger.error(e.getMessage(), e);
       throw e;
      }
     }
     public void copyFileByPath(File scrPath,File targetPath)
      throws NullPointerException,IOException, Exception {
      try {
       String[] fs = scrPath.list();

       for (int i = 0; i < fs.length; i++) {
        File fis = new File(scrPath, fs[i]);
        long currentTime = Calendar.getInstance().getTimeInMillis();
        if (fis.isFile()&&fis.lastModified()<(currentTime-1000*60*1)) {
         copyFile(fis, targetPath);
        } else if (fis.isDirectory()) {
         copyFileByPath(fis, targetPath);
        }
       }
      } catch (NullPointerException e) {
       //logger.error(dir.getName() + " folder is not exist", e);
       throw e;
      } catch (IOException e) {
       //logger.error(e.getMessage(),e);
       throw e;
      }catch (Exception e) {
       //logger.error(e.getMessage(), e);
       throw e;
      }
     }
     
     public void copyFile(File scrFile,File targetPath){
      long lastModifiedTime = scrFile.lastModified();
      
      try{
      File targetFile = new File(targetPath,scrFile.getName());
      java.io.FileInputStream in =new java.io.FileInputStream(scrFile);
         java.io.FileOutputStream out =new java.io.FileOutputStream(targetFile);
         byte Buff[]=new byte[1024];
         int len;
         while((len=in.read(Buff))>-1){
           out.write(Buff,0,len);
         }
         in.close();
         out.close ();
         targetFile.setLastModified(lastModifiedTime);
      }catch (Exception e) {
       // TODO: handle exception
      }
     }
    }

    星期五, 六月 15, 2007

    分布项目团队相关

    分布项目团队相关:
    适用对象:
    1,开源
    2,离岸
    3,xp and scrum
    4,非本地协作
     
    可利用资源:
    1,Internet 协议 (VoIP) 软件、即时通讯软件、电子邮件客户端和 wiki
    2,Mingle和VersionOne ,VNC
    3,Virtual Whiteboards
     
    注意点:
    1,共同的编码标准;源代码控制服务器;一键建立和部署脚本;连续集成;单元测试;错误跟踪;设计模式;以及应用程序块。
    2,项目信息,背景信息(因为难所以更显重要一些)
     
    建议:
    1,kickoff at the start
    2,standup every morning
    3,matrix
    4,TODO list
     
    PS:真实期权是使人们能作出在当前环境下的最优决策的一种方法。本质上它只是对当我们面对如何作出决策时的一个不同视角。真实期权有两面,一面是数学的,一面是心理学的。真实期权的数学方面,根据金融期权理论,给我们提供了一个最优决策过程。关于不确定性和决策的心理学研究(根据神经语言程序学和认知行为理论)告诉我们为什么人们不遵循最优决策过程而结果作出不理性的决定。
     

    星期三, 六月 13, 2007

    70个流行的AJAX应用的演示和源码下载

    1. Ajallerix : AJAX, simple, fast Web image gallery demo ; at Novell
    2. AJAX - microlink pattern tutorial : A microlink is a link that opens up content below it.
    3. Ajax BBC News RSS Reader : demo by Nigel Crawley
    4. AJAX Chat in Python with Dojo : at AquaAjax
    5. Ajax Chess : multiplayer chess
    6. Ajax examples at BackBase : examples demonstrating several aspects of the Backbase technology.
    7. Ajax examples at Rico : Inner HTML, JavaScript updater etc.
    8. Ajax examples using ColdFusionMX, SQLServer, SOAP : Contact Manager, NOAA 7 Day Forecast code and demos.
    9. Ajax Feed TV : News feed
    10. Ajax inline dictionary : Highlight any text on this site then right click. A tooltip containing the definition of the selected word should show up.
    11. Ajaxload : Ajax loading gif generator.
    12. Ajax Login Demo : Creating a secure login system using XMLHttpRequest
    13. Ajax Newsletter Signup : A newsletter signup form that shows Thank You on the same page.
    14. ajaxProject : Project Management applicaiton with rich UI
    15. Ajax Rater : A star rating system that uses Ajax.
    16. AJAX-S : An Ajax-based slideshow system.
    17. AJAX Spell Checker : spell check text / form content.
    18. Ajax Toolbox : Tools for the Ajax Developer
    19. Amazon Catalog Tree : Amazon Catalog Tree
    20. Amazon Zuggest : Amazon product suggestion (like google suggest)
    21. Askeet by symfony : Digg-like AJAX interactions; open source
    22. Backbase - Ajax Demos : Ajax demos at BackBase
    23. Basic Ajax Examples : Ping, track changes, drop down, Google suggest hack etc at Clearnova
    24. Behaviour : Fading lists, Sortable lists, Dropout boxen, Shaky lists
    25. chat.app : ajax chat
    26. Chihuahua Word Puzzle : daily word puzzles
    27. Coloir : Ajax Slideshow
    28. DHTML arcade/action games : a collection that demonstrate the power of DHTML
    29. DomAPI : Windows Desktop, Outlook-like, RSS Reader
    30. Drag and Drop Shopping Cart Demo : at CyberDummy
    31. Easy AJAX inline text edit 2.0 : edit a piece of text inline
    32. FileChucker : File upload and progress bar at Encodable.com
    33. Gmail Style Check Username AJAX Demo : at CyberDummy
    34. Google Web Toolkit Example Projects : Hello World, Dynamic Table, Desktop App Clone etc
    35. GreyBox : Pop up window using idea of light box.
    36. FiftyFourEleven: Ajax Examples
    37. IntuiCat - ajax Catalogue : Ajax-based Catalogue Demo
    38. jsLINB programming demos : LINB(Lazy INternet and Browser)
    39. JSlog : Ajax logging tool.
    40. JS/UIX Unix Shell : JS/UIX is an UN*X-like OS for standard web-browsers, written entirely in JavaScript.
    41. Lace : free web chat application
    42. Lightbox : simple, unobtrusive script used to overlay images on the current page.
    43. Leightbox : Light Box with inline div's instead of AJAX calls.
    44. Live Quote Demo : Simple way of creating an updating stock quote table in ajax.
    45. Magnetic Poetry : drag and drop poetry
    46. Metatron Chat Engine : PHP/MySQL/JavaScript powered chat engine
    47. Monket Calendar : online calendar
    48. Multi List Drag Drop Demo : at CyberDummy
    49. NetDirector : open and extensible framework for managing configurations of common open source network services.
    50. nexImage : Image processing demo
    51. Opera Platform : Enabling AJAX applications on mobile phones
    52. Orbeon examples : various examples illustrating the capabilities of OPS, from the OPS Tutorial examples to XForms examples
    53. OVO Suite : Online Virtual Office : virtual office limited demo
    54. phpFreeChat : php Free Chat
    55. S5: A Simple Standards-Based Slide Show System : S5 is a slide show format based entirely on XHTML, CSS, and JavaScript.
    56. script.aculo.us Reflector : image reflector script that uses uses opacity-based fades
    57. Slider Bar Demo : at CyberDummy
    58. SmallestAjax : Smallest Ajax example in the world?
    59. Spell Check demo : by Primal Grasp
    60. Super Maryo World : Japanese game demo
    61. Tacos : Tacos provides a library of useful Tapestry components. This application provides some examples to get you started.
    62. theList : to-do list / bug-tracker
    63. ThickBox : ThickBox is a Lightbox than can show html pages as well as images.
    64. Tooltip.js : Tooltip.js is a simple class to make it possible to add tooltips to your page.
    65. Treehouse Chat : ajax chat
    66. Tudu Lists : open-source to-do lists
    67. WeBoggle : Ajax Boggle
    68. XHTML live Chat : ajax chat
    69. YahooSearchAsYouType : Yahoo search as you type
    70. ZK Demo : demo programs for various components

    星期四, 六月 07, 2007

    java实现FTP功能

    有一个开源项目:edtftpj

    下边是从CSDN转的:

    ---- 在JAVA的编程中,您也许会遇到FTP方面的编程,本文就来演示如何实现它。

    ---- 本程序是由JBUILDER2.0来开发的,为了节约篇幅我只列出主要的三个部份。FtpList 部分是用来显示FTP服务器上的文件(附图略)。GetButton部分为从FTP服务器下传一个文件。PutButton 部分为向FTP服务器上传一个文件。别忘了在程序中还要引入两个库文件(import sun.net.*,import sun.net.ftp.*)。以下是这三部分的JAVA源程序。
    ---- 1)显示FTP服务器上的文件
    void ftpList_actionPerformed(ActionEvent e) {
    String server=serverEdit.getText();
    //输入的FTP服务器的IP地址
    String user=userEdit.getText ();
    //登录FTP服务器的用户名
    String password=passwordEdit.getText();
    //登录FTP服务器的用户名的口令
    String path=pathEdit.getText();
    //FTP服务器上的路径
    try {
    FtpClient ftpClient=new FtpClient();
    //创建FtpClient对象
    ftpClient.openServer (server);
    //连接FTP服务器
    ftpClient.login(user, password);
    //登录FTP服务器
    if (path.length()!=0) ftpClient.cd(path);
    TelnetInputStream is=ftpClient.list();
    int c;
    while ((c=is.read())!=-1) {
    System.out.print ((char) c);}
    is.close();
    ftpClient.closeServer();//退出FTP服务器
    } catch (IOException ex) {;}
    }
    2)从FTP服务器上下传一个文件
    void getButton_actionPerformed(ActionEvent e) {
    String server=serverEdit.getText ();
    String user=userEdit.getText();
    String password=passwordEdit.getText();
    String path=pathEdit.getText();
    String filename=filenameEdit.getText();
    try {
    FtpClient ftpClient=new FtpClient();
    ftpClient.openServer (server);
    ftpClient.login(user, password);
    if (path.length()!=0) ftpClient.cd(path);
    ftpClient.binary();
    TelnetInputStream is=ftpClient.get(filename);
    File file_out=new File(filename);
    FileOutputStream os=new
    FileOutputStream(file_out);
    byte[] bytes=new byte[1024];
    int c;
    while ((c=is.read(bytes))!=-1) {
    os.write(bytes,0,c);
    }
    is.close();
    os.close();
    ftpClient.closeServer();
    } catch (IOException ex) {;}
    }
    3)向FTP服务器上上传一个文件
    void putButton_actionPerformed(ActionEvent e) {
    String server=serverEdit.getText();
    String user=userEdit.getText();
    String password=passwordEdit.getText();
    String path= pathEdit.getText();
    String filename=filenameEdit.getText();
    try {
    FtpClient ftpClient=new FtpClient();
    ftpClient.openServer(server);
    ftpClient.login(user, password);
    if (path.length()!=0) ftpClient.cd(path);
    ftpClient.binary();
    TelnetOutputStream os=ftpClient.put(filename);
    File file_in=new File(filename);
    FileInputStream is=new FileInputStream(file_in);
    byte[] bytes=new byte[1024];
    int c;
    while ((c=is.read (bytes))!=-1){
    os.write(bytes,0,c);}
    is.close();
    os.close();
    ftpClient.closeServer();
    } catch (IOException ex) {;}
    }
    }
    原文地址: http://dev.csdn.net/author/Jason009/a20da6acb30441f6886c03adbb5996c4.html

    星期三, 六月 06, 2007

    eclipse GUI 插件

    http://cloudgarden.com/jigloo/

    关于几种不同的IDENTITY(SQLSERVER)


    SCOPE_IDENTITY、IDENT_CURRENT   和   @@IDENTITY  
    三者在功能上相似,因为它们都返回插入到   IDENTITY   列中的值。    
       
      IDENT_CURRENT   不受作用域和会话的限制,而受限于指定的表。IDENT_CURRENT   返回为任何会话和作用域中的特定表所生成的值。有关更多信息,请参见   IDENT_CURRENT。  
       
      SCOPE_IDENTITY   和   @@IDENTITY   返回在当前会话中的任何表内所生成的最后一个标识值。但是,SCOPE_IDENTITY   只返回插入到当前作用域中的值;@@IDENTITY   不受限于特定的作用域。  
       
      例如,有两个表   T1   和   T2,在   T1   上定义了一个   INSERT   触发器。当将某行插入   T1   时,触发器被激发,并在   T2   中插入一行。此例说明了两个作用域:一个是在   T1   上的插入,另一个是作为触发器的结果在   T2   上的插入。  
    假设   T1   和   T2   都有   IDENTITY   列,@@IDENTITY   和   SCOPE_IDENTITY   将在   T1   上的   INSERT   语句的最后返回不同的值。  
       
      @@IDENTITY   返回插入到当前会话中任何作用域内的最后一个   IDENTITY   列值,该值是插入   T2   中的值。  
       
      SCOPE_IDENTITY()   返回插入   T1   中的   IDENTITY   值,该值是发生在相同作用域中的最后一个   INSERT。如果在作用域中发生插入语句到标识列之前唤醒调用   SCOPE_IDENTITY()   函数,则该函数将返回   NULL   值。  

    星期五, 六月 01, 2007

    db2 sample address

    参考地址:
     
     
     
     
     
    Java サンプル・プログラム
     
  • UNIX の場合:
    sqllib/samples/java
    すべてのサブディレクトリー内の Java サンプル・プログラムの README ファイルが入っています。
    sqllib/samples/java/jdbc
    JDBC サンプル・プログラム・ファイルが入っています。
    sqllib/samples/java/sqlj
    SQLJ サンプル・プログラムが入っています。
    sqllib/samples/xml/java
    JDBC および SQLJ XML サンプルのサブディレクトリーが入っています。
    sqllib/samples/xml/java/jdbc
    README ファイルと JDBC XML サンプル・プログラムが入っています。
    sqllib/samples/xml/java/sqlj
    README ファイルと SQLJ XML サンプル・プログラムが入っています。
    sqllib/samples/java/Websphere
    WebSphere サンプル・プログラムが入っています。
    sqllib/samples/java/plugin
    DB2 コントロール・センターのプラグイン例のファイルが入っています。
    sqllib/samples/java/plugin/doc
    プラグイン・インターフェース用の javadoc ファイルが入っています。
  • Windows の場合;
    sqllib¥samples¥java
    すべてのサブディレクトリー内の Java サンプル・プログラムの README ファイルが入っています。
    sqllib¥samples¥java¥jdbc
    JDBC サンプル・プログラムが入っています。
    sqllib¥samples¥java¥sqlj
    SQLJ サンプル・プログラムが入っています。
    sqllib¥samples¥xml¥java
    JDBC および SQLJ XML サンプルのサブディレクトリーが入っています。
    sqllib¥samples¥xml¥java¥jdbc
    README ファイルと JDBC XML サンプル・プログラムが入っています。
    sqllib¥samples¥xml¥java¥sqlj
    README ファイルと SQLJ XML サンプル・プログラムが入っています。
    sqllib¥samples¥java¥Websphere
    WebSphere サンプル・プログラムが入っています。
    sqllib¥samples¥java¥plugin
    DB2 コントロール・センターのプラグイン例のファイルが入っています。
    sqllib¥samples¥java¥plugin¥doc
    プラグイン・インターフェース用の javadoc ファイルが入っています。
  •  

    java调用db2管理API——export,Import

     
    import java.io.*;    
    import java.lang.*;
    import java.util.*;
    import java.sql.*;

    class AdmCmdExport
    {

      public static void main(String argv[])
      {
        Connection con = null;
       
        int rows_exported;
        String msg_retrieval = null;
        String msg_removal = null;
        String sqlcode = null;
        String msg = null;
       
        CallableStatement callStmt1 = null;
        ResultSet rs1 = null;
        PreparedStatement stmt1 = null;
        ResultSet rs2 = null;
        CallableStatement callStmt2 = null;

        if (argv.length < 1)
        {
          System.out.println("\n Usage : java AdmCmdExport <path for export>");
        }
        else
        {            
          try
          {
            // initialize DB2Driver and establish database connection.
            COM.ibm.db2.jdbc.app.DB2Driver db2Driver =
              (COM.ibm.db2.jdbc.app.DB2Driver )
                Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
            con = DriverManager.getConnection("jdbc:db2:SAMPLE");

            System.out.println("HOW TO PERFORM EXPORT USING ADMIN_CMD.\n");
            // prepare the CALL statement for OUT_LANGUAGE
            String sql = "CALL SYSPROC.ADMIN_CMD(?)";
            callStmt1 = con.prepareCall(sql);

            String param = "export to "+ argv[0] + "org_ex.ixf ";
            param = param + "of ixf messages on server select * from org" ;

            // set the imput parameter
            callStmt1.setString(1, param);
            System.out.println("CALL ADMIN_CMD('" + param + "')");
          
            // execute export by calling ADMIN_CMD
            callStmt1.execute();
            rs1 = callStmt1.getResultSet();
            // retrieve the resultset 
            if( rs1.next())
            {
              // the numbers of rows exported
              rows_exported = rs1.getInt(1);

              // retrieve the select stmt for message retrival
              // containing SYSPROC.ADMIN_GET_MSGS
              msg_retrieval = rs1.getString(2);
     
              // retrive the stmt for message cleanup
              // containing CALL of SYSPROC.ADMIN_REMOVE_MSGS
              msg_removal = rs1.getString(3);
         
              // display the output
              System.out.println("Total number of rows exported  : " + rows_exported);
              System.out.println("SQL for retrieving the messages: " + msg_retrieval);
              System.out.println("SQL for removing the messages  : " + msg_removal);
            }
         
            stmt1 = con.prepareStatement(msg_retrieval);
            System.out.println("\n" + "Executing " + msg_retrieval); 

            // message retrivel
            rs2 = stmt1.executeQuery();

            // retrieve the resultset
            while(rs2.next())
            {
              // retrieve the sqlcode
        sqlcode = rs2.getString(1);
         
              // retrieve the error message
              msg = rs2.getString(2);
              System.out.println ("Sqlcode : " +sqlcode);
              System.out.println("Msg     : " +msg);
            }

            System.out.println("\nExecuting " + msg_removal);
            callStmt2 = con.prepareCall (msg_removal);

            // executing the message retrivel
            callStmt2.execute();     
          }
          catch(Exception e)
          {
            JdbcException jdbcExc = new JdbcException(e);
            jdbcExc.handle ();
          }
          finally
          {
            try
            {
              // close the statements
              callStmt1.close();
              callStmt2.close();
              stmt1.close();

              // close the resultsets
              rs1.close();
              rs2.close();
        
              // roll back any changes to the database made by this sample
              con.rollback();

              // close the connection                                  
              con.close();
            }
            catch (Exception x)
            {
              System.out.print("\n Unable to Rollback/Disconnect ");
              System.out.println("from 'sample' database");
            }
          }
        }
      } // main
    } // AdmCmdExport
     
     
    import java.io.*;     //JDBC classes          
    import java.lang.*;
    import java.util.*;
    import java.sql.*;

    class AdmCmdImport
    {

      public static void main(String argv[])
      {
        Connection con = null;
        CallableStatement callStmt1 = null;
        CallableStatement callStmt2 = null;
        ResultSet rs1 = null;
        ResultSet rs2 = null;
        PreparedStatement stmt1 = null;
        Statement stmt2 = null;
     
        int rows_read;
        int rows_skipped;
        int rows_loaded;
        int rows_rejected;
        int rows_deleted;
        int rows_committed;

        String msg_retrieval = null;
        String msg_removal = null;
        String sqlcode = null;
        String msg = null;
     
        if (argv.length < 1)
        {
          System.out.println("\n Usage : java AdmCmdImport <path for import>");
        }
        else
        {            
          try
          {
            // Initialize DB2Driver and establish database connection.
            COM.ibm.db2.jdbc.app.DB2Driver db2Driver =
              (COM.ibm.db2.jdbc.app.DB2Driver)
                Class.forName ("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
            con = DriverManager.getConnection("jdbc:db2:SAMPLE");

            System.out.println("HOW TO DO IMPORT USING ADMIN_CMD.\n");
            // prepare the CALL statement for OUT_LANGUAGE
            String sql = "CALL SYSPROC.ADMIN_CMD(?)";
            callStmt1 = con.prepareCall(sql);

            // argv[0] is the path for the file to be imported
            String param = "IMPORT FROM " + argv[0] + "org_ex.ixf OF IXF MESSAGES ";
            param = param + "ON SERVER CREATE INTO ORG_IMPORT" ;

            // setting the imput parameter
            callStmt1.setString(1, param);
            System.out.println("CALL ADMIN_CMD('" + param + "')");
          
            // executing import by calling ADMIN_CMD
            callStmt1.execute ();
            rs1 = callStmt1.getResultSet();
         
            // retrieving the resultset 
            if( rs1.next())
            {
              // retrieve the no of rows read
              rows_read = rs1.getInt(1);
              // retrieve the no of rows skipped
              rows_skipped = rs1.getInt(2);
              // retrieve the no of rows loaded
              rows_loaded = rs1.getInt(3);
              // retrieve the no of rows rejected
              rows_rejected = rs1.getInt(4);
              // retrieve the no of rows deleted
              rows_deleted = rs1.getInt(5);
              // retrieve the no of rows committed
              rows_committed = rs1.getInt (6);

              // retrieve the select stmt for message retrival
              // containing SYSPROC.ADMIN_GET_MSGS
              msg_retrieval = rs1.getString(7);
     
              // retrive the stmt for message cleanup
              // containing CALL of SYSPROC.ADMIN_REMOVE_MSGS
              msg_removal = rs1.getString(8);
         
              // Displaying the resultset
              System.out.print("\nTotal number of rows read      : ");
              System.out.println(rows_read);
              System.out.print("Total number of rows skipped   : ");
              System.out.println( rows_skipped);
              System.out.print("Total number of rows loaded    : ");
              System.out.println(rows_loaded);
              System.out.print("Total number of rows rejected  : ");
              System.out.println(rows_rejected);
              System.out.print("Total number of rows deleted   : ");
              System.out.println(rows_deleted);
              System.out.print("Total number of rows committed : ");
              System.out.println(rows_read);
              System.out.print("SQL for retrieving the messages: ");
              System.out.println(msg_retrieval);
              System.out.print("SQL for removing the messages  : ");
              System.out.println(msg_removal);
            }
         
            stmt1 = con.prepareStatement (msg_retrieval);
            System.out.println("\n" + "Executing " + msg_retrieval); 

            // message retrivel
            rs2 = stmt1.executeQuery();

            // retrieving the resultset
            while(rs2.next())
            {
              // retrieving the sqlcode
        sqlcode = rs2.getString(1);
         
              //retrieving the error message
              msg = rs2.getString(2);

              System.out.println("Sqlcode : " +sqlcode);
              System.out.println("Msg     : " +msg);
            }

            System.out.println("\n Executing " + msg_removal);
            callStmt2 = con.prepareCall(msg_removal);

            // executing the message retrivel
            callStmt2.execute();     

            System.out.println("\n Executing DROP TABLE ORG_IMPORT");  
            stmt2 = con.createStatement();
            stmt2.executeUpdate("DROP TABLE ORG_IMPORT");
          }
          catch(Exception e)
          {
            JdbcException jdbcExc = new JdbcException(e);
            jdbcExc.handle ();
          }
          finally
          {
            try
            {
              //closing the statements and resultset   
              callStmt1.close();
              callStmt2.close();
              stmt1.close();
              stmt2.close();
              rs1.close();
              rs2.close();
        
              // roll back any changes to the database made by this sample
              con.rollback();

              // closing the connection                                  
              con.close();
            }
            catch (Exception x)
            {
              System.out.print(x);
              System.out.print("\n Unable to Rollback/Disconnect ");
              System.out.println ("from 'sample' database");
            }
          }
        }
      } // main
    } // AdmCmdImport

    星期五, 五月 25, 2007

    去除list中的重复元素

    用HashSet
     
    Iterator it =list.iterator();
    HashSet set = new HashSet();

    while(it.hasNext()){
    set.add(it.next());
    }
    it = set.iterator();
    list.clear();
    while(it.hasNext()){
    list.add(it.next());
    }

    或者是
     
    list = new ArrayList(new HashSet(oldList));
     

    星期四, 五月 24, 2007

    java 读 properties格式文件


    package hddqcs.datamining.venus.venusfile;

    import hddqcs.datamining.venus.common.DMLogger;

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;

    import org.apache.log4j.Logger;

    /**
     *
     * COPYRIGHT(C) Hitachi Global Storage Technologies, Inc.
     * All Rights Reserved.
     *
     * This Class is to reading the process config file
     *
     *  eg. etl_venusProcess.properties
     *
     * @author liuqact
     */
    public class ReadingProcessProsFile {
     Logger logger = Logger.getLogger(ReadingProcessProsFile.class.getName());
     public Properties getProperties(String dir,String fileName)throws FileNotFoundException,IOException,Exception {
      // TODO Auto-generated method stub
      try{
       Properties pros = new Properties();
       InputStream prosFile = new FileInputStream("Log4j.properties");
       pros.load(prosFile);
      return pros;
      }catch(FileNotFoundException e){
       logger.error("Properties file inputted is not exist");
       throw e;
      }catch(IOException e){
       logger.error("Reading Properties file inputted failed");
       throw e;
      }catch(Exception e){
       logger.error("get values from Properties file inputted failed");
       throw e;
      }
     }
    }

    关于serialVersionUID


    在定义一个实现接口java.io.Serializable 的类时
    如果用EC IDE 会有缺少 UID的警告
     
    加一个吧,可以减少程序运行时的资源消耗
     
    在EC中,假如类出现这样的警告,那么你可以把鼠标放到类名上,然后
    CTRL+1
    看看出现在什么
    中间有一个是生成serialVersionUID的
     

    星期三, 五月 23, 2007

    Java操作Excel的一些可以参考的资源

    http://sourceforge.net/projects/jexcelapi
    JExcelApi is a java library which provides the ability to read, write, and modify
    Microsoft Excel spreadsheets. This project mirrors the files on http://www.jexcelapi.org,
    which has been known to go down on occasion.

     http://sourceforge.net/projects/excelutils
    ExcelUtils, easy export report in excel by excelutils.It like velocity or freemarker, but
    it's script is written in excel to control excel format and data.

    http://sourceforge.net/projects/exceltemplate
    Templating system for Microsoft Excel files in Java.
     
    http://sourceforge.net/projects/jaoff
    JavaOffice is a pure Java library to read and write MS Word files in the new WordML (format) and
    MS Excel files in the new SpreadsheetML format. WordML and SpreadsheetML are xml formats for word
    and excel files supported from Office 2003 and above.
     
    Simple library written in Java to allow the creation of Excel files based on a Java Collection.
    Each element of the collection goes in a row and the columns are based on the properties you define
    through an XML config file.
     
    http://sourceforge.net/projects/caxton
    Caxton is a general purpose package written in Java that is used to render HTML, PDF (using FOP),
     RTF (using JFOR), and Excel (using POI) using stylesheets. There are some additional tools for
     providing easy access to XML, merging XSL stylesheets

    Eclipse插件-- Bytecode Outline,Implementors, FindBugs 等

    1. Eclipse插件之Bytecode Outline

    本文介绍如何利用Eclipse插件Bytecode Outline在Eclipse中的操作使用。

      Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

      Bytecode Outline 插件可以把当前的正在编辑Java的文件或者class文件直接显示出其相应的字节码出来,而且可以进行两个Java文件的字节码比较或者两个class文件的字节码比较或一个Java文件与一个class文件进行字节码的比较。
     

    原文出处: http://dev2dev.bea.com.cn/bbsdoc/20060123182.html

    2 Eclipse插件之Implementors

    本文介绍如何利用Eclipse插件Implementors在Eclipse中的使用。

      Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

    问题提出:
      如果你想看看某个类或者方法的实现,一般是Ctrl + 鼠标左键,单击即可以打开这个类或者方法的具体实现代码。但是如果碰到接口时,只是到达接口而已,不能到达具体的实现类里。

    解决方法:利用Eclipse的Implementors插件。
      当追踪方法代码时,Eclipse默认是转到方法的接口类,而接口中是只有方法名称没有具体的实现代码,此插件提供了追踪到具体实现类的实现代码的功能。

      另外还有Call Hierarchy插件: 显示一个方法的调用层次,可以从中看到它被哪些方法调用了,以及它调用了哪些方法,是代码追踪比较实用的工具。Eclipse 3.1中已经自带有这个功能了。这个插件就不用另加介绍了。

    详细信息参考: http://dev2dev.bea.com.cn/bbsdoc/20060124188.html 

    3 利用Eclipse开发Hibernate应用程序 --Hibernate Synchronizer插件

    介绍如何利用Hibernate Synchronizer插件在Eclipse 3.0.1中快速的开发Hibernate应用程序,提高我们的工作效率。
    本文介绍如何利用Eclipse插件EasyExplorer在Eclipse中的使用。

      Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境,Hibernate也是目前很流行的O/R Mapping框架,至少在EJB 3.0大行其道之前,它是我们在考虑O/R Mapping时非常好的选择。

      关于Hibernate框架的细节,请参考《Hibernate in Action》一书。

    详细内容点击这里: http://dev2dev.bea.com.cn/bbsdoc/20060124187.html

    4 Eclipse插件之EasyExplorer

      Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

    问题提出:
      如果你经常需要在Eclipse里打开相关资源文件所在的文件夹,比较麻烦,要右键,属性,在Location一栏中把所在的文件夹拷贝一下,然后再去资源管理器里输入这个路径,回车,打开它。

    解决方法:
      用EasyExplorer插件,有了这个插件就可以很方便地打开资源文件所在的文件夹了。
     

    详细内容点击这里 ; http://dev2dev.bea.com.cn/bbsdoc/20060124184.html 

    5 Eclipse插件之SQLExplorer

    本文介绍如何利用Eclipse插件SQLExplorer在Eclipse中连接各种数据库进行操作使用。

      Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。
     

    详细内容点击这里 http://dev2dev.bea.com.cn/bbsdoc/20060126189.html 

    6 Eclipse插件之FindBugs

    本文介绍如何利用Eclipse插件FindBugs在Eclipse中的使用。

      Eclipse是目前非常流行的开发平台,开放扩展的架构让很多程序员找到了自己个性化的工作环境。

    问题提出:
      当我们编写完代码,做完单元测试等各种测试后就提交正式运行,只能由运行的系统来检测我们代码是否有问题了,代码中隐藏的错误在系统运行的过程中被发现后,然后再来进行相应的修改,那么后期修改的代价就相当高了。

    解决方法:
      现在有很多Java代码分析工具,FindBugs中开源项目当中的一个,它可以帮你找到代码中隐藏的一些错误,提升你的代码能力与系统安全可靠性。
     
    FindBugs:0.9.4 从http://findbugs.sourceforge.net/
    官方的文档 http://findbugs.sourceforge.net/manual/
    Eclipse plugin for FindBugs version 0.0.17
    http://findbugs.sourceforge.net/downloads.html 下载

    详细内容点击这里: http://dev2dev.bea.com.cn/bbsdoc/20060124186.html

    星期二, 五月 22, 2007

    JDK1.5中的线程池使用简介(转)


    在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池。这里介绍的就是1.5种的线程池的简单使用方法。
    创建日期:2005-05-11
    最后修改日期:2007-03-06
    panhaidong@gmail.com

    一、简介
    线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:
    ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime, TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler)
    • corePoolSize
      线程池维护线程的最少数量
    • maximumPoolSiz
      线程池维护线程的最大数量
    • keepAliveTime
      线程池维护线程所允许的空闲时间
    • unit
      线程池维护线程所允许的空闲时间的单位
    • workQueue
      线程池所使用的缓冲队列
    • handler
      线程池对拒绝任务的处理策略

    一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。

    当一个任务通过execute(Runnable)方法欲添加到线程池时:

    • 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
    • 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
    • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
    • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
    也就是:处理任务的优先级为:
    核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

    当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

    unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:
    NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

    workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue

    handler有四个选择:
    • ThreadPoolExecutor.AbortPolicy()
      抛出java.util.concurrent.RejectedExecutionException异常
    • ThreadPoolExecutor.CallerRunsPolicy()
      重试添加当前的任务,他会自动重复调用execute()方法
    • ThreadPoolExecutor.DiscardOldestPolicy()
      抛弃旧的任务
    • ThreadPoolExecutor.DiscardPolicy()
      抛弃当前的任务

    二、一般用法举例 [下载源代码]

    package cn.simplelife.exercise;

    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;

    public class TestThreadPool {
    private static int produceTaskSleepTime = 2;
    public static void main(String[] args) {
    //构造一个线程池
    ThreadPoolExecutor producerPool = new ThreadPoolExecutor(2, 4, 0,
    TimeUnit.SECONDS , new ArrayBlockingQueue(3),
    new ThreadPoolExecutor.DiscardOldestPolicy());

    //每隔produceTaskSleepTime的时间向线程池派送一个任务。
    int i=1;
    while(true){
    try {
    Thread.sleep(produceTaskSleepTime);

    String task = "task@ " + i;
    System.out.println("put " + task);

    producerPool.execute(new ThreadPoolTask(task));

    i++;
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    }

    package cn.simplelife.exercise;

    import java.io.Serializable;

    /**
    * 线程池执行的任务
    * @author hdpan
    */
    public class ThreadPoolTask implements Runnable,Serializable{

    //JDK1.5中,每个实现Serializable接口的类都推荐声明这样的一个ID
    private static final long serialVersionUID = 0;

    private static int consumeTaskSleepTime = 2000;
    private Object threadPoolTaskData;

    ThreadPoolTask(Object tasks){
    this.threadPoolTaskData = tasks;
    }

    //每个任务的执行过程,现在是什么都没做,除了print和sleep,:)
    public void run(){
    System.out.println("start .."+threadPoolTaskData);
    try {
    //便于观察现象,等待一段时间
    Thread.sleep(consumeTaskSleepTime);
    } catch (Exception e) {
    e.printStackTrace();
    }
    threadPoolTaskData = null;
    }
    }


    对这两段程序的说明:

    1. 在这段程序中,一个任务就是一个Runnable类型的对象,也就是一个ThreadPoolTask类型的对象。
    2. 一般来说任务除了处理方式外,还需要处理的数据,处理的数据通过构造方法传给任务。
    3. 在这段程序中,main()方法相当于一个残忍的领导,他派发出许多任务,丢给一个叫 threadPool的任劳任怨的小组来做。
      • 这个小组里面队员至少有两个,如果他们两个忙不过来, 任务就被放到任务列表里面。
      • 如果积压的任务过多,多到任务列表都装不下(超过3个)的时候,就雇佣新的队员来帮忙。但是基于成本的考虑,不能雇佣太多的队员, 至多只能雇佣 4个。
      • 如果四个队员都在忙时,再有新的任务, 这个小组就处理不了了,任务就会被通过一种策略来处理,我们的处理方式是不停的派发, 直到接受这个任务为止(更残忍!呵呵)。
      • 因为队员工作是需要成本的,如果工作很闲,闲到 3SECONDS都没有新的任务了,那么有的队员就会被解雇了,但是,为了小组的正常运转,即使工作再闲,小组的队员也不能少于两个。
      • 通过调整 produceTaskSleepTime和 consumeTaskSleepTime的大小来实现对派发任务和处理任务的速度的控制, 改变这两个值就可以观察不同速率下程序的工作情况。
      • 通过调整4中所指的数据,再加上调整任务丢弃策略, 换上其他三种策略,就可以看出不同策略下的不同处理方式。
      • 对于其他的使用方法,参看jdk的帮助,很容易理解和使用。
      这是另外一个例子
      public class NamePrinter implements Runnable {
      private final String name;
      private final int delay;
      public NamePrinter(String name, int delay) {
      this.name = name;
      this.delay = delay;
      }
      public void run() {
      System.out.println("Starting: " + name);
      try {
      Thread.sleep(delay);
      } catch (InterruptedException ignored) { }
      System.out.println("Done with: " + name);
      }
      }
      import java.util.concurrent.*;
      import java.util.Random;
      public class UsePool {
      public static void main(String args[]) {
      Random random = new Random();
      ExecutorService executor =
      Executors.newFixedThreadPool(3); //设定线程池容量为3
      // Sum up wait times to know when to shutdown
      int waitTime = 500;
      for (int i=0; i<10;>
      String name = "NamePrinter " + i;
      int time = random.nextInt(1000);
      waitTime += time;
      Runnable runner = new NamePrinter(name, time);
      System.out.println("Adding: " + name + " / " + time);
      executor.execute(runner);
      }
      try {
      Thread.sleep(waitTime);
      executor.shutdown();
      executor.awaitTermination
      (waitTime, TimeUnit.MILLISECONDS);
      } catch (InterruptedException ignored) {
      }
      System.exit(0);
      }
      }

      附:jdk1.5中关于ThreadPoolExecutor的javadoc地址

      星期日, 五月 20, 2007

      星期五, 五月 18, 2007

      Java SE 6中JDBC 4.0的增强特性(转)

      摘要:

      Java SE 6包含了对Java数据库互连(JDBC)API的一些增强特性。这些增强特性的版本将定为JDBC version 4.0。JDBC新特性的目的是提供更简单的设计和更好的开发体验。本文将概述JDBC 4.0的增强特性和为企业级Java开发人员带来的好处。我们将通过一个用Apache Derby作为后台数据库的贷款处理应用范例来探究JDBC的新特性。

      Java SE 6包含了对Java数据库互连(JDBC)API的一些增强特性。这些增强特性的版本将定为JDBC version 4.0。JDBC新特性的目的是提供更简单的设计和更好的开发体验。本文将概述JDBC 4.0的增强特性和为企业级Java开发人员带来的好处。我们将通过一个用Apache Derby作为后台数据库的贷款处理应用范例来探究JDBC的新特性。

      Java SE 6.0
      Java SE 6.0版以兼容性、稳定性和品质作为设计目标。本版本中有不少值得关注的增强特性,特别是JMX、web services、脚本语言支持(采用Rhino脚本引擎JSR 223把JavaScript技术与Java源码进行集成)、数据库连接、支持annotations和安全部分。另外,在JDBC API中还有不少新的特性,包括RowId支持和新增的SQLException子类。

      JDBC 4.0的特性
      得益于Mustang中的Java SE 服务提供商机制,Java开发人员再也不必用类似Class.forName()的代码注册JDBC驱动来明确加载JDBC。当调用DriverManager.getConnection()方法时,DriverManager类将自动设置合适的驱动程序。该特性向后兼容,因此无需对现有的JDBC代码作任何改动。

      通过对Java应用程序访问数据库代码的简化,使得JDBC 4.0有更好的开发体验。JDBC 4.0同时也提供了工具类来改进数据源和连接对象的管理,也改进了JDBC驱动加载和卸载机制。

      有了JDBC 4.0传承自Java SE 5.0 (Tiger)版对元数据的支持功能,Java开发人员可用Annotations明确指明SQL查询。基于标注的SQL查询允许我们通过在Java代码中使用Annotation关键字正确指明SQL查询字符串。这样,我们不必查看JDBC代码和他所调用的数据库两份不同的文件。例如,用一个名为getActiveLoans()方法在贷款处理数据库中获取一个活跃贷款清单,你可以添加@Query(sql="SELECT * FROM LoanApplicationDetails WHERE LoanStatus = 'A'")标注来修饰该方法。

      并且,最终版的Java SE 6开发包(JDK 6)以及其相应的执行期环境(JRE 6)会捆绑一个基于Apache Derby的数据库。这使得Java开发人员无需下载、安装和配置一款单独的数据库产品就能探究JDBC的新特性。

      JDBC 4.0中增加的主要特性包括:
      1.        JDBC驱动类的自动加载
      2.        连接管理的增强
      3.        对RowId SQL类型的支持
      4.        SQL的DataSet实现使用了Annotations
      5.        SQL异常处理的增强
      6.        对SQL XML的支持

      另外,对BLOB/CLOB 的改进支持以及对国际字符集的支持也是JDBC 4.0的特性。这些特性将在随后章节中详细讨论。

      JDBC驱动自动加载
      在JDBC 4.0中,我们不必再使用Class.forName()方法明确加载JDBC驱动。当调用getConnection方法时,DriverManager会尝试从初始化时已经加载的JDBC驱动程序库中选择合适的驱动,以及他在当前应用的同一个类加载器中明确加载使用过的驱动。
      DriverManager中的getConnection和getDrivers方法已作了改进,以支持Java SE 服务提供商机制(SPM)。根据SPM,所谓服务就是一组广为人知的接口和抽象类的集合,而服务提供商就是对某一服务的特定实现。SPM还指明了服务提供商的配置文件存放于META-INF/services目录下。JDBC 4.0的驱动程序库必须包含META-INF/services/java.sql.Driver文件。该文件包含对java.sql.Driver 实现的JDBC驱动文件名。例如,通过JDBC驱动连接Apache Derby数据库,META-INF/services/java.sql.Driver将含有以下路径:
      org.apache.derby.jdbc.EmbeddedDriver

      我们再来快速地看一下如何使用这一新特性加载一个JDBC驱动管理。以下显示的是我们用以加载JDBC驱动的典型范例代码。这里我们假设连接的是Apache Derby数据库,因为该数据库将在本文随后的范例应用中用到:
          Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
          Connection conn =
              DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword);
      但在JDBC 4.0中,我们不必写Class.forName()这一行,我们只需要调用getConnection()方法取得数据库连接。
      请注意,仅在完全独立的模式下可使用该方法取得数据库的连接。如果你使用一些类似数据库连接池等技术管理连接,那么代码将有所不同。

      连接管理
      在JDBC 4.0之前,我们依靠JDBC URL来定义一个数据源连接。现在有了JDBC 4.0,我们只需为标准连接工厂机制提供一组参数,就能获取与任何数据源的连接。Connection和Statement接口增添的新方法为池环境中管理Statement对象提供了更好的连接状态跟踪机制和更大的灵活度。元数据工具(JSR-175)被用来管理活跃连接。我们还能获得元数据信息,如:活跃连接状态,并能指明XA事务的某一连接是标准式(Connection,在独立应用的情况下)、池式(PooledConnection)还是分布式(XAConnection)。该接口仅在诸如WebLogic、WebSphere和JBoss等Java EE应用服务器的事务管理中使用。

      RowId支持
      JDBC 4.0增加了RowID接口以支持ROWID数据类型,Oracle和DB2数据库支持该数据类型。在你需要把大量缺少唯一标识符字段的查询记录放入一个不允许重复对象的Collection容器(如Hashtable)的情况下,RowId很有用。我们可以用ResultSet的getRowId()方法获取RowId,用PreparedStatement的setRowId()方法在查询中使用RowId。

      关于RowId对象需要记住的一件重要事项是,RowId值在数据源之间不可移植。当在PreparedStatement和ResultSet中单独使用set或update方法时,需要想到指明数据源。因此,RowId对象不应被不同的Connection和ResultSet对象共享。

      DatabaseMetaData中的getRowIdLifetime()方法可被用来确定RowId对象的有效存活时间。该方法的可能返回值如表1所列:
      RowId值                                          描述
      ROWID_UNSUPPORTED        Doesn't support ROWID data type.
      ROWID_VALID_OTHER        Lifetime of the RowID is dependent on database vendor implementation.
      ROWID_VALID_TRANSACTION        Lifetime of the RowID is within the current transaction as long as the row in the database table is not deleted.
      ROWID_VALID_SESSION        Lifetime of the RowID is the duration of the current session as long as the row in the database table is not deleted.
      ROWID_VALID_FOREVER        Lifetime of the RowID is unlimited as long as the row in the database table is not deleted.

      基于标注的SQL查询
      JDBC 4.0对标注(Java SE 5新增)作了进一步规范和补充,他允许开发人员不必再写大量代码就能达到联系SQL查询和Java类的目的。并且,通过使用Generics(JSR 014)和元数据(JSR 175) API,我们只要指明查询的输入和输出参数就能将SQL查询与Java对象进行关联。我们还可以将查询结果捆绑在Java类上以加快查询输出的处理。将查询对象置于Java对象之中,我们可以不必像往常一样写所有代码。在Java代码中指明SQL查询,经常用到两种标注:

      Select标注
      Select标注用于在Java类中指明一个选择查询,使get方法能从数据库表中取回数据。表2显示的是Select标注的不同属性及其作用:
      变量                                           类型        描述
      sql                                                            String        SQL Select query string.
      value                                                            String        Same as sql attribute.
      tableName                                            String        Name of the database table against which the sql will be invoked.
      readOnly, connected, scrollable            Boolean        Flags used to indicate if the returned DataSet is read-only or updateable, is connected to the back-end database, and is scrollable when used in connected mode respectively.
      allColumnsMapped                                            Boolean        Flag to indicate if the column names in the sql annotation element are mapped 1-to-1 with the fields in the DataSet.

      这里有一个应用Select标注从贷款数据库中获取所有活跃贷款的例子:
      interface LoanAppDetailsQuery extends BaseQuery {
              @Select("SELECT * FROM LoanDetais where LoanStatus = 'A'")
              DataSet<LoanApplication> getAllActiveLoans();
      }

      Sql标注同样允许I/O参数(参数标记以一个问号后跟一个整型数据表示)。这里是一个参数化sql查询的例子:
      interface LoanAppDetailsQuery extends BaseQuery {
              @Select(sql="SELECT * from LoanDetails
                      where borrowerFirstName= ?1 and borrowerLastName= ?2")
              DataSet<LoanApplication> getLoanDetailsByBorrowerName(String borrFirstName,
                      String borrLastName);
      }

      Update标注
      Update标注用于修饰Query接口方法以更新数据库表中的一条或多条记录。Update标注必须包含一个sql标注类型元素。这里是一个Update标注的例子:
      interface LoanAppDetailsQuery extends BaseQuery {
              @Update(sql="update LoanDetails set LoanStatus = ?1
                      where loanId = ?2")
              boolean updateLoanStatus(String loanStatus, int loanId);
      }

      SQL异常处理的增强特性
      异常处理是Java编程的一个重要部分,特别是对后台关系数据库进行连接或查询时。SQLException是我们用以指出与数据库相关错误的类。JDBC 4.0在SQLException处理中有不少增强。为了在处理SQLException时获得更好的开发体验,JDBC 4.0版作了如下增强:
      1.        新的SQLException子类
      2.        对因果关系的支持
      3.        对改进的for-each循环的支持

      新的SQLException类
      SQLException的新子类提供了一种方法,使Java开发人员能写出更方便改动的错误处理代码。JDBC 4.0介绍了两个新的SQLException型别:
      •        SQL non-transient exception
      •        SQL transient exception

      Non-Transient Exception:除非修正引发SQLException异常的代码,否则该异常在再次尝试相同JDBC操作失败后被抛出。表3显示了JDBC 4.0新增的SQLNonTransientException异常子类(SQL 2003规范中定义了SQLState类的值):

      Exception class                                         SQLState value
      SQLFeatureNotSupportedException          0A
      SQLNonTransientConnectionException     08
      SQLDataException                                           22
      SQLIntegrityConstraintViolationException        23
      SQLInvalidAuthorizationException             28
      SQLSyntaxErrorException                            42

      Transient Exception:当先前执行失败的JDBC操作在没有任何应用级功能干涉的情况下可能成功执行时,该异常被抛出。继承自SQLTransientException的新异常如表4所列:

      Exception class                                SQLState value
      SQLTransientConnectionException        08
      SQLTransactionRollbackException        40
      SQLTimeoutException                      None

      因果关系
      SQLException类现在支持Java SE链式异常机制(又称因果工具),它使我们能在一个JDBC操作中处理多条SQLException异常(如果后台数据库支持多条异常特性)。这种情形发生在执行一条可能会抛出多条SQLException异常的语句时。

      我们可以调用SQLException中的getNextException()方法在异常链中进行迭代。这里是一些处理getNextException()因果关系的范例代码:
      catch(SQLException ex) {
           while(ex != null) {
              LOG.error("SQL State:" + ex.getSQLState());
              LOG.error("Error Code:" + ex.getErrorCode());
              LOG.error("Message:" + ex.getMessage());
              Throwable t = ex.getCause();
              while(t != null) {
                  LOG.error("Cause:" + t);
                  t = t.getCause();
              }
              ex = ex.getNextException();
          }
      }

      增强的For-Each环
      Java SE 5中,SQLException类通过实现Iterable接口,增加了for-each循环支持的特性。这个循环的轨迹将会包括SQLException和其异常成因。这里的代码片断展示了SQLException中增加的增强型for-each环特性。
      catch(SQLException ex) {
           for(Throwable e : ex ) {
              LOG.error("Error occurred: " + e);
           }
      }

      对国际字符集转换的支持
      以下是JDBC类处理国际字符集的新增特性:
      1.        JDBC数据类型:新增NCHAR、NVARCHAR、LONGNVARCHAR和NCLOB数据类型。
      2.        PreparedStatement:新增setNString、setNCharacterStream和setNClob方法。
      3.        CallableStatement:新增getNClob、getNString和getNCharacterStream方法。
      4.        ResultSet:ResultSet接口新增updateNClob、updateNString和updateNCharacterStream方法。

      对大对象(BLOBs and CLOBs)支持的改进
      以下是JDBC 4.0处理LOBs的新增特性:
      1.        Connection:新增方法(createBlob()、createClob()和createNClob())以创建BLOB、CLOB和NCLOB对象新实例。
      2.        PreparedStatement:新增方法setBlob()、setClob()和setNClob()以使用InputStream对象插入BLOB对象,使用Reader对象插入CLOB和NCLOB对象。
      3.        LOBs:在Blob、Clob和NClob接口中新增方法(free())以释放这些对象所持有的资源。
      现在,让我们来看一看java.sql和javax.jdbc包的新类,以及他们所提供的服务。

      JDBC 4.0 API:新类
      RowId (java.sql)
      正如先前所介绍的,该接口是对数据库中SQL ROWID值的展示。ROWID是一种SQL内建的数据类型,用来标识数据库中的一行特定数据。ROWID经常用于从表中返回查询结果,而这些结果行往往缺少唯一ID字段。

      getRowId和setRowId等CallableStatement、PreparedStatement和ResultSet接口的方法允许程序员访问SQL ROWID值。RowId接口还提供了一个方法(叫getBytes())把ROWID值作为一个byte型数组返回。DatabaseMetaData接口有一个名为getRowIdLifetime的新方法,用以确定某一RowId对象的存活时间。RowId的存活时间范围可以是如下三种类型:
      1.        创建RowId的数据库事务持续时间
      2.        创建RowId的会话持续时间
      3.        数据库对应的记录还未被删除的持续时间

      DataSet (java.sql)
      DataSet接口提供了对执行SQL Query后所返回数据类型的安全检查。DataSet还可以运行在连接或非连接模式。在连接模式下,DataSet类似于ResultSet的功能;而在非连接模式下,他类似于CachedRowSet的功能。由于DataSet继承自List接口,因此我们能对查询返回的记录行进行迭代。

      对已有的类,JDBC 4.0也新增了不少方法。比如,Connection新增了createSQLXML和createSQLXML方法,ResultSet新增了getRowId方法。

      范例应用
      本文所示的范例应用是一个贷款处理应用软件,他有一个贷款搜索页面,用户可以通过输入贷款ID提交查询表,以获取贷款详情。贷款搜索页面调用一个控制器对象,而该对象又调用一个DAO对象访问后台数据库,以取回贷款详情。这些详情包括贷款人、贷款数额、贷款截至日期等信息,并显示在贷款详情屏幕上。后台数据库中,我们有一个名为LoanApplicationDetails的表,来存储贷款软件的详情。

      该范例应用的用例是通过指定贷款ID来获取贷款详情。当贷款已经登记并将抵押物与利息挂钩后,贷款详情就可以被获取。表5显示了贷款处理应用软件项目的详情。
      Name                            Value
      Project Name        JdbcApp
      Project Directory        c:\dev\projects\JdbcApp
      DB Directory        c:\dev\dbservers\apache\derby
      JDK Directory        c:\dev\java\jdk_1.6.0
      IDE Directory        c:\dev\tools\eclipse
      Database        Apache Derby 10.1.2.1
      JDK                        6.0 (beta 2 release)
      IDE                        Eclipse 3.1
      Unit Testing        JUnit 4
      Build                        Ant 1.6.5

      下表所列的是我们连接贷款详情Apache Derby数据库所需的JDBC参数。这些参数存放于一个名为derby.properties的文本文件中,并置于项目的etc/jdbc目录下(见表6)。

      Name                           Value
      JDBC Driver File        LoanApp\META-INF\services\java.sql.driver
      Driver                       org.apache.derby.ClientDriver
      URL                       jdbc:derby:derbyDB
      User Id                       user1
      Password                       user1

      请注意:Apache Derby数据库提供了两种JDBC驱动:嵌入式驱动(org.apache.derby.jdbc.EmbeddedDriver)和客户端/服务器驱动(org.apache.derby.jdbc.ClientDriver)。我在范例应用中使用客户端/服务器版驱动。
      以下是使用ij工具来启动Derby数据库服务器并创建新数据库的命令。

      要启动Derby网络服务器,需开启一个命令行窗口,并运行如下命令(请根据你本机的环境改写DERBY_INSTALL和JAVA_HOME环境变量)。
      set DERBY_INSTALL=C:\dev\dbservers\db-derby-10.1.2.1-bin
      set JAVA_HOME=C:\dev\java\jdk1.6.0
      set DERBY_INSTALL=C:\dev\dbservers\db- derby-10.1.3.1-bin
      set CLASSPATH=%CLASSPATH%;%DERBY_INSTALL%\lib\derby.jar;
                      %DERBY_INSTALL%\lib\derbytools.jar;
                      %DERBY_INSTALL%\lib\derbynet.jar;

      cd %DERBY_INSTALL%\frameworks\NetworkServer\bin
      startNetworkServer.bat

      要连接数据库服务器并创建测试数据库,需开启另一个命令行窗口并运行以下命令。请确保DERBY_INSTALL和JAVA_HOME环境变量符合你本机的环境。
      set JAVA_HOME=C:\dev\java\jdk1.6.0
      set DERBY_INSTALL=C:\dev\dbservers\db-derby-10.1.3.1-bin
      set CLASSPATH=%DERBY_INSTALL%\lib\derbyclient.jar;
                      %DERBY_INSTALL%\lib\derbytools.jar;.

      %JAVA_HOME%\bin\java org.apache.derby.tools.ij
      connect 'jdbc:derby://localhost:1527/LoanDB;create=true';

      测试
      要编译Java源代码,classpath需包括derby.jar和junit4.jar文件,这两个文件在项目的lib目录下。Classpath还需包括etc、etc/jdbc和etc/log4j目录,这样应用程序才能访问JDBC属性文件和Log4J配置文件。我创建了一个Ant构建脚本(在JdbcApp/build目录下)来自动完成编译和打包Java源代码的工作。

      用于测试贷款详情数据库访问对象的测试类名为LoanAppDetailsDAOTest。我们传入贷款ID和贷款人参数就可以获取贷款详情。
      以下部分显示了JDBC 4.0中自动加载JDBC驱动和基于标注的SQL查询特性的代码范例。

      JDBC驱动的自动加载
      BaseDAO抽象类有一个名为getConnection的方法用以获得一个数据库连接。以下代码片断显示了该方法(注意,我们不必注册JDBC驱动)。只要java.sql.Driver文件中有合适的驱动程序类名(org.apache.derby.jdbc.ClientDriver ),JDBC驱动将被自动加载。
      protected Connection getConnection() throws DAOException {
              // Load JDBC properties first
              if (jdbcUrl == null || jdbcUser == null ||
                              jdbcPassword == null) {
                      loadJdbcProperties();
              }
              // Get Connection
              Connection conn = null;
              try {
                      conn = DriverManager.getConnection(jdbcUrl, jdbcUser,
                                      jdbcPassword);
              } catch (SQLException sqle) {
                      throw new DAOException("Error in getting a DB connection.",
                                      sqle);
              }
              return conn;
      }

      SQL标注
      LoanAppDetailsQuery接口有标注了的SQL查询,用以获取活跃贷款清单(criteria is loanstatus="A")和某贷款人的贷款详情(在一个贷款人有多笔贷款的情况下)。在上文中,我们已经了解过了这些SQL标注。这里的范例代码显示了我们如何使用标注来调用已定义的SQL查询。
      public DataSet<LoanAppDetails> getAllActiveLoans() throws Exception {
              // Get Connection
              Connection conn = getConnection();
              LoanAppDetailsQuery query = null;
              DataSet<LoanAppDetails> loanDetails = null;
              query = QueryObjectFactory.createQueryObject (
                              LoanAppDetailsQuery.class, conn);
              loanDetails = query.getAllActiveLoans();
              return loanDetails;
      }

      public DataSet<LoanAppDetails> getLoanDetailsByBorrowerName(
                      String borrFirstName, String borrLastName) throws Exception {
              // Get Connection
              Connection conn = getConnection();
              LoanAppDetailsQuery query = null;
              DataSet<LoanAppDetails> loanDetails = null;
              query = QueryObjectFactory.createQueryObject(
                              LoanAppDetailsQuery.class, conn);
              loanDetails = query.getLoanDetailsByBorrowerName(
                              borrFirstName,borrLastName);
              return loanDetails;
      }

      结论
      JDBC 4.0在SQL方面为开发者提供了更好的开发体验。JDBC 4.0的另一个目标是为API增加更丰富的工具以提供企业级JDBC特性管理JDBC资源。并且,JDBC 4.0 API还提供了JDBC驱动的移植方式,使其符合J2EE连接器架构(JCA)规范。这为JDBC厂商提供了向JDBC连接器迁移的能力。在面向企业服务的架构(SPA)中使用JDBC数据源,该移植方式很重要。在SOA中,JDBC数据源可被部署在另一个企业服务总线(ESB)架构内,而不需要为JDBC数据源另写一份ESB实现代码。

      本文中,我们了解了RowId支持,JDBC驱动加载和基于标注的SQL等JDBC 4.0的增强特性。未来,JDBC 4.0还将增加更多特性以支持SQL:2003。请参阅特性文档,以获取更多有关JDBC 4.0特性的信息。

      Resources
      Matrix-与Java共舞
      Sample Application Code

      Srini Penchikala是Flagstar Bank的一位信息系统问题专家。