拾贝壳

走过的路
随笔 - 39, 文章 - 1, 评论 - 14, 引用 - 0
数据加载中……

2006年5月26日

System.getProperty()参数大全

System.getProperty()参数大全  
  •   
  • java.version            Java Runtime Environment version  
  • java.vendor            Java Runtime Environment vendor  
  • java.vendor.url            Java vendor URL  
  • java.home            Java installation directory  
  • java.vm.specification.version                    Java Virtual Machine specification version  
  • java.vm.specification.vendor                    Java Virtual Machine specification vendor  
  • java.vm.specification.name                    Java Virtual Machine specification name  
  • java.vm.version            Java Virtual Machine implementation version  
  • java.vm.vendor            Java Virtual Machine implementation vendor  
  • java.vm.name            Java Virtual Machine implementation name  
  • java.specification.version                Java Runtime Environment specification version  
  • java.specification.vendor             Java Runtime Environment specification vendor  
  • java.specification.name        Java Runtime Environment specification name  
  • java.class.version                        Java class format version number  
  • java.class.path                  Java class path  
  • java.library.path                        List of paths to search when loading libraries  
  • java.io.tmpdir                Default temp file path  
  • java.compiler            Name of JIT compiler to use  
  • java.ext.dirs            Path of extension directory or directories  
  • os.name                Operating system name  
  • os.arch                Operating system architecture  
  • os.version            Operating system version  
  • file.separator            File separator ("/" on UNIX)  
  • path.separator            Path separator (":" on UNIX)  
  • line.separator            Line separator ("\n" on UNIX)  
  • user.name            User's account name  
  • user.home            User's home directory  
  • user.dir                User's current working directory 
  • posted @ 2008-02-18 17:43 binge 阅读(690) | 评论 (0)编辑 收藏

    axis userguide(3)

    服务类型

    在axis中有4中服务类型
    RPC服务采用soap rpc的标准,and also the SOAP "section 5" encoding.
    Document 服务没有采用任何编码(所以你在组装时不会看到复杂对象的序列化以及soap-style数组),但是仍然作了xml和java对象的互映射。
    Wrapped服务和Document服务类似
    Message 服务接受和返回soap Envelope中的任意的xml而不需要mapping/data得榜定。如果你想处理来自外部的原始的xml,可以采用Message 服务。

    RPC服务
       这个服务是axis默认的服务。我们在前面的例子中写的就是rpc服务。<service ... provider="java:RPC"> 。rpc服务遵从soap rpc规范和编码规则,意味着来自rpc服务的xml将类似上面例子中的“echoString”--每个rpc调用被模块化为一个外部元素,匹配操作名称,并包含了很多内部元素,每一个都是操作的一个参数。axis将把这些xml转化为java对象,配送给你得服务,并将序列化来自服务的java对象为xml.因为rpc服务默认采用soap section 5规则,对象将会通过"multi-ref" 序列化来编码。
    Document / Wrapped 服务
     这2个服务很类似,都不需要用soap编码来处理数据。他就是一个普通的xml格式。无论哪种情况,axis还是对他们做了xml到java得榜定,所以你最终处理的还是java对象,而不是xml结构的字符串。
     下面的例子来说明他们2个之间的区别。
     <soap:Envelope xmlns="http://xml.apache.org/axis/wsdd/"
        xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
      <soap:Body>
        <myNS:PurchaseOrder xmlns:myNS="http://commerce.com/PO">
          <item>SK001</item>
          <quantity>1</quantity>
          <description>Sushi Knife</description>
        </myNS:PurchaseOrder>
      </soap:Body>
    </soap:Envelope>

    相关的PurchaseOrder类型定义如下:

    <schema targetNamespace="http://commerce.com/PO">
      <complexType name="POType">
        <sequence>
          <element name="item" type="xsd:string"/>
          <element name="quantity" type="xsd:int"/>
          <element name="description" type="xsd:string"/>
        </sequence>
      </complexType>
      <element name="PurchaseOrder" type="POType"/>
    </schema>

    对于一个document服务来说,他将对应到这样的方法
    public void method(PurchaseOrder po)

    换句话说,整个PurchaseOrder元素将被处理为一个单一的对象,包含3个属性。
    而对于wrapped服务来说,他对应于下面的方法
    public void purchaseOrder(String item, int quantity, String description)
    注意到,在wrapped中,PurchaseOrder元素被映射为代表了一个方法。他的参数就是他的那些元素。
    他们在wsdd得使用如下
    <service ... style="document"> for document style
    <service ... style="wrapped"> for wrapped style
    Message 服务
      当你需要处理纯xml而不是java对象时,你将会用到这种服务。
      message服务的方法有4中签名
    public Element [] method(Element [] bodies);
    public SOAPBodyElement [] method (SOAPBodyElement [] bodies);
    public Document method(Document body);
    public void method(SOAPEnvelope req, SOAPEnvelope resp);

    posted @ 2008-02-17 20:31 binge 阅读(615) | 评论 (0)编辑 收藏

    axis userguide(2)

    发布service
    有2种发布方式,一种是实例发布,一种是描述符发布
    实例发布很简单
      把我们的java源文件拷贝到axis目录下,改扩展名为jws
      然后就可以直接访问了,例如:
    java samples.userguide.example2.CalcClient -p8080 add 2 5
     他将调用add方法,传递的2个变量分别为2和5。
    很显然,第一种方法有很多弊端,比如需要源文件,不能有包路径等等
    描述符发布
    一个最简单的例子如下:
    <deployment xmlns="http://xml.apache.org/axis/wsdd/"
        xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
      <service name="MyService" provider="java:RPC">
        <parameter name="className" value="samples.userguide.example3.MyService"/>
        <parameter name="allowedMethods" value="*"/>
      </service>
    </deployment>
    一个服务是一个targeted chain ,可能包含下面的一些或者全部:请求Handler,pivot Handler 支点Handler,响应Handler。支点hander在服务中叫做provider,在例子中我们的provider是java:RPC,他被axis内嵌,代表了Java RPC service,具体的类是org.apache.axis.providers.java.RPCProvider.
    我们告诉RPCProvider 我们要调用的服务MyService,并以参数的形式告诉他具体的目标以及可以被调用的方法。
    我们也可以给我们要调用的对象设置作用范围scope,和servlet的scope一样,有request,session,application.
    我们需要把这个描述符定义的内容告诉应用服务器才能真正提供我们需要的服务。
    如果已经部署axis到tomcat,我们可以这样发布
    org.apache.axis.client.AdminClient deploy.wsdd
    这样我们的服务就可以通过soap来访问了
    测试一下
    java samples.userguide.example3.Client
      -lhttp://localhost:8080/axis/services/MyService "test me!"
    可以通过下面来查看所有已经部署的服务
    java org.apache.axis.client.AdminClient list
    来看看更进一步的应用,使用一下request handler
    <deployment xmlns="http://xml.apache.org/axis/wsdd/"
        xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
      <!-- define the logging handler configuration -->
      <handler name="track" type="java:samples.userguide.example4.LogHandler">
        <parameter name="filename" value="MyService.log"/>
       </handler>

      <!-- define the service, using the log handler we just defined -->
      <service name="LogTestService" provider="java:RPC">
        <requestFlow>
          <handler type="track"/>
        </requestFlow>

        <parameter name="className" value="samples.userguide.example4.Service"/>
        <parameter name="allowedMethods" value="*"/>
      </service>
    </deployment>
    这个例子会在客户端掉用LogTestService的时候,先调用samples.userguide.example4.LogHandler作记录操作
    远程管理
    默认状态下,axis只允许在axis部署的机器上使用管理请求,如果希望在其他的机器上进行管理操作可以参照下面的例子

    <service name="AdminService" provider="java:MSG">
      <parameter name="className" value="org.apache.axis.util.Admin"/>
      <parameter name="allowedMethods" value="*"/>
      <parameter name="enableRemoteAdmin" value="true"/>
    </service>
    注意,这样配置需要作必要的安全配置

    posted @ 2008-02-17 12:17 binge 阅读(598) | 评论 (0)编辑 收藏

    osworkflow几个主要组件和概念

    原文见:

    http://blog.csdn.net/huabingl/archive/2008/02/12/2089145.aspx

    posted @ 2008-02-17 10:36 binge 阅读(771) | 评论 (0)编辑 收藏

    Javascript 的dtree

    说dtree是使用最广泛的目录树javascript应该也不为过.这得意于他简单的使用方式和良好的结构.

    可能这里是他最早的发源地之一http://www.destroydrop.com/javascripts/tree/

    上面有他的示例和api文档.

    dtree使用简单,使用起来就是引入一个dtree.js,dtree.css和一些小图片文件。.在需要显示树的地方,插入类似下面的代码

    可以参照这里做些配置,观看效果.可选的选项有folderLinks, useIcons, useLines, useSelection, useStatusText, closeSameLevel

    http://www.destroydrop.com/javascripts/tree/example/ 

    你可以放置radio或者checkbox在相应的节点上,或者在节点上加上链接.

    posted @ 2008-02-17 10:35 binge 阅读(1521) | 评论 (0)编辑 收藏

    用opencms java API获取资源信息

    原文见

    http://blog.csdn.net/huabingl/archive/2008/02/12/2088711.aspx

    posted @ 2008-02-17 10:34 binge 阅读(727) | 评论 (0)编辑 收藏

    opencms分页

    opencms列表显示
     先准备要显示的数据。比如在站点下建立一个sports目录,里面以news的格式放入一些xmlpage.
      注意给这些xmlpage准备好detail显示页面。
    <%@ taglib prefix="cms" uri="http://www.opencms.org/taglib/cms" %>
    <%@ page import="java.util.*"%>
    <%@ page import="org.opencms.jsp.*"%>

    <%
    String sPageIndex=request.getParameter("pageIndex");
    int iPageIndex=1;
    if(sPageIndex!=null){
    iPageIndex=Integer.parseInt(sPageIndex);
    }

     pageContext.setAttribute("pageIndex", iPageIndex+"");
    %>
    <cms:contentload collector="allInFolderDateReleasedDesc" param="/myfirstsite/sports/%(number)_news.html|news" pageIndex="%(pageContext.pageIndex)" pageSize="2">
    <cms:contentinfo var="contentInfo" scope="request" />
    <a href="<cms:link><cms:contentshow element="%(opencms.filename)"/></cms:link>" target=_blank><cms:contentshow element="Title"/> </a>
    <%out.println("---");%>
    </cms:contentload>
    <%
    CmsContentInfoBean info  = (CmsContentInfoBean)request.getAttribute("contentInfo");
    int totalNum=info.getResultSize();
    %>
    共<%=totalNum%>条数据,当前第<%=info.getPageIndex()%>/<%=info.getPageCount()%>
    <a href="list_taglib?pageIndex=<%=info.getPageNavStartIndex()%>">第一页</a>
    <a href="list_taglib?pageIndex=<%=(info.getPageNavStartIndex()-1)>0?(info.getPageNavStartIndex()-1):1%>">上一页</a>
    <a href="list_taglib?pageIndex=<%=(info.getPageNavStartIndex()+1)>info.getPageCount()?info.getPageCount():(info.getPageNavStartIndex()+1)%>">下一页</a>
    <a href="list_taglib?pageIndex=<%=info.getPageNavEndIndex()%>">最后页</a>
    上面的例子力求尽可能少的使用标签。主要使用了CmsContentInfoBean ,CmsJspXmlContentBean ,I_CmsXmlContentContainer(CmsJspTagContentLoad )等多个对象。分页的关键在CmsContentInfoBean 和 CmsJspTagContentLoad的关系上。 

    参考资料:

    http://www.javaedu.com/bbs/viewthread?thread=128

    http://wangyi878750.blog.sohu.com/41725191.html

    http://l--w.blog.sohu.com/47996664.html

    http://wangyi878750.blog.sohu.com/41378072.html

     

    posted @ 2008-02-17 10:31 binge 阅读(1629) | 评论 (0)编辑 收藏

    Ruby之Blocks&Iterator

    Ruby之Blocks,Iterator
    -------读《Programming Ruby 2nd》

    posted @ 2007-08-09 10:22 binge 阅读(354) | 评论 (0)编辑 收藏

    Ruby简介

    Ruby是”一种用于迅速和简便的面向对象编程的解释性脚本语言”;这意味着什么?
    解释性脚本语言:

    • 有直接呼叫系统调用的能力
    • 强大的字符串操作和正则表达式
    • 开发中快速回馈

    迅速和简便:

    • 无需变量声明
    • 变量无类型
    • 语法简单而坚实
    • 自动内存管理

    面向对象编程

    • 任何事物都是一个对象
    • 类,继承,方法,等等
    • 单态方法
    • 模块糅合
    • 迭代器和闭包(closures)

    以及:

    • 多精度整数
    • 异常处理模式
    • 动态装载
    • 线程

    如果你对上面的那些概念还不熟悉,继续读,别担心.Ruby的箴言是”迅速和简便”.

    posted @ 2007-08-02 10:16 binge 阅读(437) | 评论 (0)编辑 收藏

    ruby日记

    ruby初体验
    参考网址:
    http://sitekreator.com/satishtalim/ruby_tools.html
    http://blog.linuxmine.com/23633/viewspace-5329

      ror  制作简单网页
    helloworld达成
    (启动服务器的时候,错误的直接切到script目录去启动,耽误了不少时间)
    参考网址:
    http://www.javaeye.com/article/35929
    ror实现简单的mvc
    参考资料:
    http://www.onlamp.com/pub/a/onlamp/2007/01/05/revisiting-ruby-on-rails-revisited-2.html?page=1
    http://www.ibm.com/developerworks/cn/linux/l-rubyrails/   (最后的修改的 form标签应该写成<%= start_form_tag :action => 'update', :id => @contact.id %>)
    ror作复杂的mvc
    制作中。。。。
    需要解决的问题有:
    1,登陆以及session处理
    参考文档:
    http://wiki.rubyonrails.org/rails/pages/UnderstandingSessions
    2,多表关联以及复杂查询
    参考文档:
    http://tech.it168.com/j/d/2006-10-20/200610200913835_2.shtml
    3,分页实现
    参考文档:
    http://wiki.rubyonrails.com/rails/pages/HowtoPagination



     

    posted @ 2007-07-31 16:40 binge 阅读(581) | 评论 (0)编辑 收藏

    javascript操作word控件

    <script language="javascript">
    //定义全局变量,用于清理工作
    var word;
    var doc;
    function editFile(){
    //调用word控件
     word= new ActiveXObject("Word.Application");
    //屏蔽“另存为”按钮
     word.CommandBars("File").Controls(5).Enabled= false;
      word.CommandBars("File").Controls(5).visible= false;
    //屏蔽"另存为网页"按钮

     word.CommandBars("File").Controls(6).Enabled= false;
     word.CommandBars("File").Controls(6).visible= false;

     word.visible = true;
     // word.activate();
    try{
    //打开文件
      doc=word.Documents.Open("http://212312.doc");
      //痕迹保留
      word.ActiveDocument.TrackRevisions   =true; 
    //切换成web视图
      word.ActiveDocument.ActiveWindow.View.Type=3
     
          }catch(e){
           alert(e.message);
          };  
    }
    function myfinalize(){
    //文档保存
        doc.save();
    //文档关闭
       doc.close();
    //把屏蔽的功能打开
       word.CommandBars("File").Controls(5).Enabled= true;
      word.CommandBars("File").Controls(5).visible= true;
    //word退出
     word.quit();
     
    }
    //参考文档
       http://bbs.hidotnet.com/712/ShowPost.aspx

    posted @ 2007-07-25 10:54 binge 阅读(3155) | 评论 (0)编辑 收藏

    DB2

    原文:

    http://blog.csdn.net/huabingl/archive/2008/02/11/2088477.aspx

    posted @ 2007-07-09 16:20 binge 阅读(333) | 评论 (0)编辑 收藏

    AXIS User Guide(1)

         摘要: AXIS User Guide(1)  阅读全文

    posted @ 2007-01-03 20:54 binge 阅读(1165) | 评论 (0)编辑 收藏

    Sliding into WebDAV

         摘要: Sliding into WebDAV  阅读全文

    posted @ 2007-01-03 20:49 binge 阅读(2414) | 评论 (0)编辑 收藏

    HibernateTemplate方法

         摘要: HibernateTemplate方法索引  阅读全文

    posted @ 2006-12-26 15:47 binge 阅读(4389) | 评论 (0)编辑 收藏

    小心对js函数命名,避免和它的内置函数重名

    最近又遇到个对js取名不帅导致错误的问题,特开此贴,以示警戒:
    不要把自己的js函数取成close(),open(),start()之类的名字!!

    window得resizeto和resizeby方法对模式窗口无效。

    posted @ 2006-12-10 13:25 binge 阅读(708) | 评论 (0)编辑 收藏

    webdav使用指南

      最近研究了一下webdav,关于webdav的详细信息可以在 google上搜索或者参看官方网站http://www.webdav.org.
      "WebDAV stands for "Web-based Distributed Authoring and Versioning". It is a set of extensions to the HTTP protocol which allows users to collaboratively edit and manage files on remote web servers. "
     笔者简单的尝试了它下面的slide和mod_dav.
    slide是jakarta下面的子项目,分为服务端和客户端.个人认为服务端是专门为tomcat定做的一个webdav实现.关于slide,javaeye上有些讨论,可以参考http://www.javaeye.com/t/5267.html.本人涉入的不是很深,中文问题让我碰到了,slide提供2中存储方式,文件形式和数据库形式,限于时间,笔者没有对数据库形式进行测试.slide的工作目录默认在服务器bin目录下.
    用mod_dav来实现相比就简单多了,如果你熟悉apache httpserver,应该很容易搞定.http://www.webdav.org/mod_dav/ 上的有部分资料.可以根据http://www.webdav.org/mod_dav/install.html 的讲解来配置.apache server1.3以后(包括1.3)在发布的时候都自带了mod_dav包.需要做的就是加载和配置它.
    LoadModule dav_module libexec/libdav.so
    AddModule mod_dav.c
    笔者在配置的时候由于没有认真看文档,犯了个小小的错误.所以注意下面的文字:
    "In the following example, the DAV lock database will be stored in the /usr/local/apache/var directory (which must be writable by the server process). The file's name will be DAVLock when mod_dav needs to create it.
    (actually, mod_dav will create one or more files using this file name plus an extension)

    DAVLockDB /usr/local/apache/var/DAVLock"
    然后你需要配置一个webdav的工作目录,由于访问apache服务的用户会默认是nobody用户,所以你至少得让工作目录对nobody可读写.在目录的定义中加入DAV on这样的属性就 ok了
    eg:
    "Alias /pages /home/www/davhome
    <Location /pages>
        DAV On
    </Location>
    "
    测试webdav
    安装完webdav后,你可以做简单的测试:
       IE浏览器-〉文件-〉打开,然后输入配置的url,http://127.0.0.1/pages,选上"以Web文件夹方式打开".可以看到效果。
    客户端API.
    如果是 java可以 采用slide的客户端.(php用户咋办?).
    这个最新的客户端使用的是最新的jdom,注意哦..
    参考资料:
    http://www.uplinux.com/www/net/02/131.shtml

    posted @ 2006-12-10 12:40 binge 阅读(5995) | 评论 (0)编辑 收藏

    mvnforum权限系统分析

       mvnforum是一个开源的论坛软件.网址如下:
    http://sourceforge.net/projects/mvnforum/
       本文主要研究它的权限部分,以作为使用借鉴.
       这里有篇中文的文档,以作参考:
      http://www.cn-java.com/target/news.php?news_id=3298


    权限部分的UML图如下:
      

    数据流程:
    1,系统从OnlineUserManager这个入口进入.这个部件有个Map用来存储当前的非过期用户。OnlineUserManager会先根据当前时间和最后一个用户的请求时间做对比,检查是否有刷新过期用户的必要,如果超过所设置的时间,那么先更新Map。然后OnlineUserManager根据提供的用户的 sessionid和username在这个Map中查找。如果找到,则刷新该用户的最后一次访问时间;否则,OnlineUserManager调用OnlineUserFactory部件创建该OnlineUser,并把这个OnlineUser存入Map之中。
    判对用户是否过期的原理是:从OnlineUser的OnlineUserAction中取出最后一次的访问时间和当前时间做对比.
    2,OnlineUserFactory负责创建OnlineUser并为该OnlineUser提供完整的权限信息.OnlineUser包括3大部分信息,一部分是用户的基本信息,一部分是用户的权限信息,一部分是用户的在线信息.在线信息由OnlineUserManager负责管理,其他2部分信息由OnlineUserFactory从持久层获得.
    获得权限信息并把它设置到OnlineUser部件上,提供给OnlineUserManager管理.
    3.CNMPermissionFactory类似我们常说的service.主要负责和持久层通信,最终返回一个CNMPermission部件供OnlineUserFactory合成OnlineUser部件.在下面的章节里,笔者会对他细化讨论.
    权限结构:
    用来实现用户权限的主要的是CNMPermission接口和他是2个子类AbstractPermission和CNMPermissionImpl.CNMPermission接口负责定义权限有关的常量和对外API.AbstractPermission设置了保存权限信息的变量并实现了CNMPermission接口中定义的抽象方法,因此,笔者把这个抽象类叫做鉴权类.CNMPermissionImpl 则负责对AbstractPermission使用的变量进行设值,因此,笔者称之为赋权类.
    先看看AbstractPermission的结构。这里涉及到这么几个概念:全局权限,特定权限,单个权限,组合权限。
    全局权限用true/false来设置。
    特定权限是指某一个动作所作用的不同的对象。比如:某用户只能将写操作作用于1,2,4这3个论坛板块之上。表示为这个特定权限内部的ArrayList容器中只有1,2,4三个编号。
    单个权限是指单个动作。比如读操作。
    组合权限是为了方便设置提供的对单个权限的组合。比如对某用户一次设置某板块的“读”和“发布”2种权限。
    前2种权限是一个纬度的划分,后2个是另一个纬度的划分。
    如何鉴权?
    鉴权的接口都会在CNMPermission中定义。对全局权限,直接返回对应的标志位的值,对于特定权限,则先判断是否特定权限全开,否,则然后判断其ArrayList中是否包含对应的对象编号。
    如何赋权?
    这里要承接到上述数据流程的第三步。由CNMPermissionFactory根据一定先后循序(其实无关顺序,因为采用的为真覆盖原则,即持久层返回的权限都是真值,后面的真值对前面的真值可覆盖)从持久层获得所有的全局权限和特定权限。mvnforum只有用户和角色2种概念(当然也可以扩展),因此它的顺序是:用户全局全县-〉用户特定权限-〉角色全局全县-〉角色特定权限。当然无论哪一部都是对同一个CNMPermission进行操作。
    无论在设置全局权限还是特定权限的时候都可能会遇到所定义的组合权限。具体的组合权限拆分是由CNMPermissionImpl来做的.
    相关的表结构:
       member表,存贮用户基本信息。
       membergroup ,存储用户和组(角色)的对应关系。
       groups表,存储组/角色的基本信息
       grouppermission,存储组/角色的全局权限,字段为groupid permissionid
       groupforum,存储组/角色 的论坛权限, 字段为groupid ,forum,permissionid
       memberpermission 存贮用户的全局权限,字段为 memberid permissionid
       memberforum 存贮用户的论坛权限,字段为memberid ,forum,permissionid


      修改于2006/12/16  晚8时

    posted @ 2006-09-19 10:07 binge 阅读(1539) | 评论 (0)编辑 收藏

    Log4j/common log和各种服务器集成的问题

      目前的很多商业和非商业的服务器中间件都默认集成了common-log甚至是log4j.因此当我门把我们的应用发布在上面的时候,都会遇到关于log方面的问题.
      1.webshpere下面集成log4j.
      "WebSphere的类装入器方式有两种方式:PARENT_FIRST和PARENT_LAST。默认值是PARENT_FIRST,这种方式在载入当前classpath的类之前先载入其上一级classloader能够装入的类。这是标准的JVM classloader的默认策略。如果采用PARENT_LAST,则过程正好相反,即先载入当前classpath的类,再载入其上一级classloader能够装入的类,这样可以用当前classpath中更新的类覆盖其上一级classloader的相同类。受类装入器方式影响的classloader包括application classloader、WAR classloader以及共享类库的classloader。"
     因为websphere在共享类库的classloader中有一套common logging,但是确没有合适配置文件.如果我们把配置正确的log4j.properties文件放在共享类库下,我们会发现log4j可以运行.但还有另外一个很通用的方式--改变webshpere的类库加载顺序.我们让他先加载我们web应用所需的类库.即我们把web应用的加栽方式改为PARENT_LAST.
      哎,尽管我小心的提防,今天还是中招了,在我的配置里,log4j的配置文件只能读取一次,不能一个应用一个配置文件.为了让它加载自己的配置,可以自己写(或者用spring的)servlet/listener去手动加载这个配置文件.
     2.jboss下面的集成log4j
      大家可能都曾在为jboss下面配置log4j郁闷过.jboss比webshpere走的还远.无论你的项目是否使用了log4j,jboss在自己启动的时候就已经运行他了.也就是说在jboss加载自己共享类库的时候,已经读取了自己log4j.xml文件配置.这个文件在conf中可以找到.如果你需要为你的应用单独配置一个catagory,你需要直接在这里配置.
       在webloader装载应用的时候,如果应用中有log4j的包,似乎总出现appender已被占用的问题.笔者把log4j的包连带应用中的log4j配置文件一并移去,世界清净了.
    关于为了让应用自带的log4j配置文件生效,有人建议修改
     <attribute name="Java2ClassLoadingCompliance">false</attribute>

     <attribute name="UseJBossWebLoader">false</attribute>
    这两个属性.
     3.sunone下面集成log4j
        距离上次用SunOne服务器已经好长时间了,似乎sunOne的log有些类似jboss,也是一个服务器的log集中管理.由于使用的不是很多,暂且在这里站个位子.
    随手贴点关于log的信息:
    http://wiki.apache.org/jakarta-commons/Logging/FrequentlyAskedQuestions
    http://www-128.ibm.com/developerworks/cn/websphere/library/techarticles/0408_baigang/part3.html

     

    posted @ 2006-09-05 17:23 binge 阅读(1482) | 评论 (1)编辑 收藏

    OpenLDAP快速上手

    OpenLDAP 快速上手

       Ben 的项目里面要用到 OpenLDAP, 我的项目里面也要用到 LDAP, 所以这 2 天集中看了一下 LDAP 相关的内容。做了个笔记,也算是为人类知识的积累做点或有或无的贡献。

       OpenLDAP 的官方站点是 http://www.openldap.org

           上面有个 QuickStart, 我将大致按照这个来讲解。

    一、 安装
    在官方站点上发布的是 linux/unix 下的 OpenLDAP 源文件,当然也很容易找到 windows 系统下的版本。笔者学习安装的就是 windows 版本的。

    二、 配置

    OpenLDAP 2 个用户最关注的配置文件。

    一个是 slapd.conf 在他里面定义了最基本的 DN 以及管理员的账号和密码。

    另一个是 LDIF 的文件。在它里面可以配置所有的用户和组织。

    1、  我们先来了解 LDAP 的相关概念。
    我们知道 LDAP 的全称为( Lightweight Directory Access Protocol ),即轻量级目录访问协议。

    Ldap 是怎样的一个结构呢 ?用官方的话说:“ In LDAP, directory entries are arranged in a hierarchical tree-like structure. Traditionally, this structure reflected the geographic and/or organizational boundaries. Entries representing countries appear at the top of the tree. Below them are entries representing states and national organizations. Below them might be entries representing organizational units, people, printers, documents, or just about anything else you can think of.. ”他是一个树状的结构。每一个节点被称为一个 Entry 。这些 Entry 有着有趣的含义。

    下面是他的 2 个实例。一个反映了 geographic ,一个反映了 organizational

                                                               传统命名

                                                               网络命名

    我们来看看个个节点的定义方式。

    每个 Entry 都有一个自己得一个标示 ,我们把他叫 DN(Distinguished Name) ,这个 dn 包含了一个 RDN Relative Distinguished Name )。在上面的第二个图例 中,Barbara Jensen的RDN是 uid=babs,他的dn是 uid=babs,ou=People,dc=example, dc=com。

    每个节点都需要一个类别 这个类别信息用objectClass来表示。ObjectClass就是该节点的schema,他定义了该节点该有和不该有的属性。默认的objectClass都在schema/core.schema中有定义。如果在你的配置过程中出现了关于找不到objectClass的问题,您不妨参看一下这里面有没有你用到的objectClass . 在schema文件夹下还有其他一些schema文件,你也可以定义自己的schema.想要加载其他的schema,你可以在slapd.conf文件中用include加入.如:include  ./schema/core.schema. 为了方便识别,其实我们在DN里面用的都是objectClass的简写形式。如:ou代表organizationUnit,c代表country,st代表state,dc代表??等。

    2、  来看看 slapd.conf 这个文件
    这个文件的主要信息是如下几行:

    database bdb

    suffix "dc=<MY-DOMAIN>,dc=<COM>"

    rootdn "cn=Manager,dc=<MY-DOMAIN>,dc=<COM>"

    rootpw secret

    directory /usr/local/var/openldap-data

    定义了数据库,最基本的后缀,管理员的 dn 和密码,以及数据存放路径。

    编辑好这个文件,我们就可以启动了。

    如果你把 ldap 安装为 windows 服务,你可以像我一样启动:

    net start OpenLDAP-slapd

     

    3、  我们主要操作的就是这个 LDIF 文件
    我们需要在这个文件里面加入所需要的 dn.

    注意,因为我们在 slapd.conf 中定义了一个 base dn 和一个管理员 dn ,所以我们需要首先把这 2 dn 加进来。

    dn: dc=<MY-DOMAIN>,dc=<COM>

    objectclass: dcObject

    objectclass: organization

    o: <MY ORGANIZATION>

    dc: <MY-DOMAIN>

     

    dn: cn=Manager,dc=<MY-DOMAIN>,dc=<COM>

    objectclass: organizationalRole

    cn: Manager

    保存为 ldif 后缀的文件。然后我们用命令把这些信息加到 ldap 中去:

    ldapadd -x -D "cn=Manager,dc=<MY-DOMAIN>,dc=<COM>" -W -f example.ldif

    让我们来查看以下我们的设置是否出现问题:

    ldapsearch -x -b 'dc=example,dc=com' '(objectclass=*)'

    上面的是 linux/unix 下的命令, windows 下我们需要做点更改:

    ldapsearch -x -b dc=example,dc=com (objectclass=*)

    对,就是去掉引号。

    为了察看方便,笔者建议使用 GUI 工具来查看,比如笔者使用的 Softerra LDAP Browser 2.6

     

    三、 java 集成
    我们的 ldap Server 已经搭建起来了,我们需要在我们的 java 程序中访问这个服务。

    Openldap.org 上有没有讲?有讲?下面介绍的 JLDAP 就是干这个的。

    我们需要看一下“ Java LDAP Overview ”里面的内容。内容不是很多,但很实用。

    要在 java 中访问 ldap ,我们需要一套 api, 你可以在下面的网站上获得:

    http://developer.novell.com/wiki/index.php/LDAP_Classes_for_Java

    在下在的文件里面有许多的例子,在 novell 的网站上也有很多的例子。我就不讲了。 Try yourself

    posted @ 2006-08-26 08:37 binge 阅读(9149) | 评论 (7)编辑 收藏

    JUDE还是很好用的

       没有华丽的Rose,也没有Togather,用JUDE的感觉也不错.刚刚把PicoContainer反向了.可惜,好东西都陆续要收费了.只能用用Community /Free 版.
     
    JUDE的一个下载地址:
       http://jude.change-vision.com/jude-web/product/community.html

    posted @ 2006-07-23 15:27 binge 阅读(888) | 评论 (1)编辑 收藏

    PicoContainer源码导读

         摘要: 一、简介   感谢“简易java框架”分享的学习心得。循着他的足迹,我把picocontainer读了一遍。源代码的版本是1.2-RC-2。   pico的官方站点:http://www.picocontainer.org/   由于它是一个专门的ioc容器,所以使用起来没有spring那么麻烦。关于他的文档,在官方站点上有一篇《5分钟搞定pico》的文章。国人似乎也有很多的翻译版本。讲解得很详细...  阅读全文

    posted @ 2006-07-23 14:30 binge 阅读(3007) | 评论 (0)编辑 收藏

    一个简单的ThreadPool分析

    一个简单的ThreadPool
      原文来自http://www.informit.com/articles/printerfriendly.asp?p=30483&r1=1&rl=1
      项目是多线程的,所以引入了线程池这个东西。池子是个老美写的。在项目中表现的还不错。所以把它摘出来,介绍给以后或许需要用到它的同行们。
      关于为什么要采用ThreadPool,原文已经提到了:创建一个线程是需要开销的;如果线程数量过大的话,cpu就会浪费很大的精力做线程切换。
      ThreadPool的实现过程就是对WorkerThread的同步和通信的管理过程。
      我们来看代码。
      首先,在ThreadPool构造的时候,创建10个WorkerThread(size=10)并让他们运行。每个WorkerThread线程都有个ThreadPool的引用,用于查询ThreadPool的状态和获得同步锁.WorkerThread运行以后,循环调用ThreadPool的方法进行查询,如果没有发现任务,ThreadPool告诉正在查询的线程进入休眠状态,WorkerThread释放对查询方法的锁定.这样在还没有任务的时候,所有的10个WorkerThread都会进入休眠状态,进入等待ThreadPool对象的等待锁定池,只有ThreadPool对象发出notify方法(或notifyAll)后WorkerThread线程才进入对象锁定池准备获得对象锁进入运行状态。
    代码片断:
    while ( !assignments.iterator().hasNext() )
        wait();
    如果你有jprofile或者其他的观察线程的工具,你可以看到有10个线程都在休眠状态.
      接着,我们向ThreadPool中加入任务,这些任务都实现了Runnable的run方法.(至于为什么把任务都做成Runnable,译者至今也有些疑问?预定俗成?TimerTask也是实现自Runnable,弄得初学者经常把真正运行的线程搞混).ThreadPool每assign一个任务,就会发出一条消息,通知它的等待锁定池中的线程.各个线程以抢占的方式获得对象锁,然后很顺利的获得一条任务.并把此任务从ThreadPool里面删除.没有抢到的继续等待.
    Runnable r = (Runnable)assignments.iterator().next();
       assignments.remove(r);
    WorkerThread从ThreadPool那里获得了任务,继续向下执行。
    target = owner.getAssignment();
       if (target!=null) {
        target.run();     
        owner.done.workerEnd();
       }
    记住,这里调用的是target.run();而不是调用的线程的start()方法。也就是说在这里表现出的WorkerThread和task之间的关系仅仅是简单的方法调用的关系,并没有额外产生新线程。(这就是我上面纳闷为什么大家都实现Runnable来做task的原因)
     大家可能注意到,WorkerThread并没有对异常作处理。而我们知道发生在线程上的异常会导致线程死亡。解决的办法有2中,一种是通过threadpool的管理来重新激起一个线程,一种是把异常在线程之内消灭。在项目中,我采用的是第二中,因此这个片断改称这样:
    if (target!=null) {
      try{
        target.run();     
       }
      catch(Throwable t){
     .......
       }
        owner.done.workerEnd();
    }
    在WorkerThread完成一个task以后,继续循环作同样的流程.
    在这个ThreadPool的实现里面,Jeff Heaton用了一个Done类来观察WorkerThread的执行情况.和ThreadPoool的等待锁定池不同,Done的等待锁定池里面放的是初始化ThreadPool的线程(可能是你的主线程),我们叫他母线程.
      在给出的测试例子中.母线程在调用complete()方法后进入休眠(在监视中等待),一开始是waitBegin()让他休眠,在assign加入task以后,waitDone()方法让他休眠.在WorkerThread完成一个task以后,通知waitDone()起来重新检查activeThreads的数值.若不为0,继续睡觉.若为0,那么母线程走完,死亡(这个时候该做的task已经做完了).母线程走完,ThreadPool还存在吗?答案是存在,因为WorkerThread还没有消亡,他们在等待下一批任务,他们有ThreadPool的引用,保证ThreadPool依然存在.大家或许已经明白Done这个类的作用了.
      细心的读者或许会发现,发生在Done实例上的notify()并不是像ThreadPool上的notify()那样每次都能完成一项工作.比如除了第一个被assign的task,其他的task在assign进去的时候,发出的notify()对于waitDone()来说是句"狼来了".
     最后在ThreadPool需要被清理得时候,使每一个WorkerThread中断(这个时候或许所有的WorkerThread都在休眠)并销毁.记住这里也是一个异步的过程.等到每一个WorkerThread都已经销毁,finalize()的方法体走完.ThreadPool被销毁.
     for (int i=0;i<threads.length;i++) {
       threads[i].interrupt();
       done.workerBegin();
       threads[i].destroy();
      }
      done.waitDone();
    为什么有句done.workerBegin();?不明白.
    参考文章:
    http://www.zdnet.com.cn/developer/common/printfriend/printfriendly.htm?AT=39276905-3800066897t-20000560c

    posted @ 2006-07-16 20:07 binge 阅读(7181) | 评论 (1)编辑 收藏

    关于作者

        吕华兵,男,24岁。
        2000-2004年,在中国民航大学读书。学习期间,笔者以技术部长身份参与了校易航工作室暨易航网站的创建和发展工作,参与和独立完成了多个项目的设计和开发。
       2004年5月到2006年5月,在北京环亚时代(港新合资)天津软件中心从事Java的开发工作。参与了CMCC的OA的实施工作,主力开发了MOCHA AM的前端显示和MOCHA ITAM的报表系统。
      2006年5月至今,在美国易达软件有限公司工作。设计并开发了Information Publisher的多线程后端程序。
      
      笔者长期从事j2se,j2ee的开发工作,对各种设计模式亦有丰富的使用经验。
      笔者从来重视规范的软件流程,对RUP有很深的理解。
      对于javascript,dhtml,ajax,笔者有着丰富的经验。
      笔者也是“拿来主义”的拥趸,不遗余力的翻译、学习、使用和宣传各种开源项目。目前使用过的开源项目有:spring、picocontainer、hibernate、ibatis、struts、webwork等框架系列,DOM系列,commons系列,Quartz,log4j,ant,oscache,proxool以及各种报表工具等等。

     笔者从来重视知识的提取和积累,这也是笔者开此blog的主要原因,同时,也希望通过此blog结交更多的朋友。

    posted @ 2006-07-16 10:15 binge 阅读(410) | 评论 (0)编辑 收藏

    关于GWT的第一手经验

    译者安:你敢大胆采用最新的技术吗?你顾虑哪些方面?下面的采访将给我们提供一个参考。
     原文:
         在java中,对技术的采用是一件让人心烦的事情,因为我们获得通知的途径太多。不同的会议,不同的站点如slashdot和theserverside,而且还有数不清的个人博客如dhh和o'Reilly's Radar.
    一个让人感兴趣的技术总是让业界议论纷纷,正如人们所意识到的,这个产品并不是成熟期。
        为了让一个产品成为主流,早期的采用者必须足够喜欢这项产品来承担很多非常的任务以便
    让更为胆怯的开发者相信这项新技术值得采用。像Hibernate和Spring Framework这样的技术花了好几年
    才成为一个成熟产品。许多产品,比如maven,在版本确定之前经历了痛苦的时期因为他们早期缺乏
    足够的文档或者有不同的足够强大的挑战者比如ant.本人对这个过程中的盲点很感兴趣,从议论这个产品的介绍到大范围的采用往往要经历成月上年,而且很难指定时间表。hibernate并不是暴雨似的到来,而是通过大量用户自我采用.一个失败的项目比如ojb出来的时候也是引起轰动,但是它最终没有承诺的那么好.在这种情况下,早期的hibernate使用者其实信心不足.
      让我们来看Google Web Toolkit (GWT)…
    GWT在这个进程中处于什么位置?
    gwt看起来是在早期使用(early-adopter)的中期。一开始的议论声已经消去,现在陆续出现了许多关于gwt的文章和博客,表明了人们正在期待关于gwt的第一个helloworld的反馈报告。我的很多谨慎的同行都在回避他,事实上认为它是个不好的主意。风险阻碍了开发者对大多数新技术的评估直到他们在现实中看到了一个活生生的实例解决方案--就像maven被ibm使用一样。那些有能力来尝试风险的开发者正在对这个框架进行测试。他们中的某一个或许宣称gwt不适合它的组织。另外一个同行已经原则上接受了gwt的观点,但是没有时间来在他的应用中集成。所以,到底gwt处于什么时期?早期的使用人群有哪些经验呢?
       关于这个问题,我专门采访了Grassroots Technologies公司的Michael Podrazik。Grassroots Technologies是一个在纽约的咨询小组。通过在Grassroots的工作,michael已经正在把gwt应用在他们的一个新的正在开发的web应用当中。在下面的采访里面,我要求他来交流他的产品经验来帮助其他人去理解gwt.我特别要求他给一些gwt客观的意见,而且细致的描述他在用gwt开发过程中遇到的挑战。幸运的是,他的信息将会帮助你决定是否gwt是你项目的正确选择。
    采访内容:
    q:什么使你选择了gwt?
    a:我订阅了google的blog,所以我听说了gwt当他发布到javaone的时候。在阅读了他的文档之后我开始对这种方式很好奇,因此我把它down了下来而且开始使用它(play with it).我刚刚开始了一个项目,这个项目是把遗留的 Access/VBA的桌面应用升级为一个web应用。在UI方面有许多ajaxian特性所以我想我可以让gwt一展身手。我认为(figure)只要我保持我的架构足够抽象,我就有能力用更为传统的web应用框架来替换gwt层。gwt会很伤脑筋吗?至少目前为止我很开心。
    q:gwt出现了那些挑战?你围绕着gwt设计的web框架吗?gwt是否挑战了你关于web应用开发的观点?
    a:你确实不能简单的认为gwt是一个webapp的框架,他更是一个有着rpc和对象序列化的ui类库。因为你需要改变你项目组织的assumptions以及包的结构。在java服务端开发rich-client用户界面我们有大量的经验,比如flash/actionscript.gwt和他们十分类似,因此可以想象有这些元素的项目--分隔的服务端和客户端而不是同一的webapp--很爽。
      朝着这个方向,你需要明确区分服务端和客户端的功能。我相信一个好的哲学就是使你的客户端仅仅用于展示。
      你需要思考你服务接口的设计,比如每个操作的粒度
      你不能在客户端代码上用java5得语法
    Q:你的意思是不能再gwt的具体类或者普通的web应用里面用java5的语法?
    a:你不能在客户代码里面使用java5的语法。我们在服务端代码中使用了许多java5的特性,但是所有将要被转换成javascript的代码必须是1.4的规范。
    这个也包括许多事实上你用在服务端的类。因为rpc框架允许用户定义的数据类型的序列化,意思是你将在浏览器端得到一个已经被转化为javascript实例的类,这个类作为一个参数传递到服务端的实现中。在你的服务端代码中,你将操纵同一个class而且是编译过的字节码。
     这个时候就出现了一个选择,domain module和gwt的耦合度怎样才合适呢?
    What we decided was to keep value objects implementation-agnostic so as to avoid “infecting” the API and persistence layers with beans implementing GWT’s IsSerializable interface.
    举个例子,在服务端我们有个IUser接口的用户模块,这个借口继承自IPersistable.gwt的实现接受和返回实现IsSerializable接口的GwtUser的实例并把这些实例利用commons-beanutils发送到服务端。
     对于这一点可能有些争论,这样做并不非必要。但是我觉得这点额外的工作将带给你更为清晰的层次划分。我们可以嵌入gwt到任何一点,而且可以转换到springmvc或者struct或者其他的地方,而不需要担心代码上 的反应。
    q:你发现gwt产生的javascript不能垮浏览器的地方了吗?你发现gwt产生的javascript包含一些错误需要手动调试了吗?
    a:都没有,这正是令我们惊讶的地方。跨浏览器javascript的开发是PITA,而且GWT真正的把你从他那里隔离开来。
    我发现了大量的在FIREFOX和IE不同的地方,但是这些最后被确认都是CSS支持的问题而于GWT无关。
    我也遇到了一大队JAVASCRIPT错误,但是这些错误都是应为变量而不在初始化,这些问题很快就会找到并且不需要大量的调试。目前已经完成的大多数工作并不全是ui控件的问题,或许随着我们的深入,我们会遇到一些问题,但是目前为止,我们还没有多少麻烦。
    q:你的工作组的成员是更喜欢java还是javascript呢?
    显然是java,哈哈。但是我们有人对javascript和actionscript也很精通。就像译者本人。
    q:一句话,对正在考虑gwt的人,你有什么建议?你会推荐他吗?你对这项技术的客观观点是什么?thumbs up or thumbs down?
    a:目前是thumbs up.我们目前仍然在开发的早期,而且我还不想说在它是完美的或者在以后的进程中不会咬我们一口。意思是说,你的建构要搭好。 它真的像是在作swing或者其他UI的桌面应用。
     我们用基于Controller和IView实现的GWT生成了全部的ui.除了gwt模块引入以外,那里没有html。
      这是对几乎所有主流web应用范例的违背,但是如果你喜欢ui编程,他完美的抽象了ajax/dhtml的行为到一个十分友好和可扩展的api.
      我或许会说如果你的工作是php,asp或者其他语言,你或许需要花更多的功夫。如果你已经是一个有经验的java程序员,那么你可以很快投入其中。

    posted @ 2006-07-08 13:47 binge 阅读(1164) | 评论 (0)编辑 收藏

    java.util.Date和java.sql.Date

    java.sql.Date,java.sql.Time和java.sql.Timestamp三个都是java.util.Date的子类(包装类)。
    但是为什么java.sql.Date类型的值插入到数据库中Date字段中会发生数据截取呢?
    java.sql.Date是为了配合SQL DATE而设置的数据类型。“规范化”的java.sql.Date只包含年月日信息,时分秒毫秒都会清零。格式类似:YYYY-MM-DD
    当我们调用ResultSet的getDate()方法来获得返回值时,java程序会参照"规范"的java.sql.Date来格式化数据库中的数值。因此,如果
    数据库中存在的非规范化部分的信息将会被劫取。在sun提供的ResultSet.java中这样对getDate进行注释的:
    Retrieves the value of the designated column in the current row of this <code>ResultSet</code> object as a “java.sql.Date” object in the Java programming language.
    同理。如果我们把一个java.sql.Date值通过PrepareStatement的setDate方法存入数据库时,java程序会对传入的java.sql.Date规范化
    ,非规范化的部分将会被劫取。
     然而,我们java.sql.Date一般由java.util.Date转换过来,如:java.sql.Date sqlDate=new java.sql.Date(new java.util.Date().getTime()).
     显然,这样转换过来的java.sql.Date往往不是一个规范的java.sql.Date.
     在http://www.thunderguy.com/semicolon/2003/08/14/java-sql-date-is-not-a-real-date/ 文章中提到,要保存java.util.Date的精确值,
     我们需要利用java.sql.Timestamp.
     感谢这篇文章的铺垫:http://community.csdn.net/Expert/topic/4354/4354971.xml?temp=.5256616

    posted @ 2006-07-06 16:51 binge 阅读(4276) | 评论 (0)编辑 收藏

    log4j配置概要

    官方网址:
    http://logging.apache.org/log4j/docs/index.html

    一个中文翻译的文档:

    http://www.jaxwiki.org/zh/project/logging.apache.org/log4j/docs/manual.html


    我摘出黄色字体表明几条列在下面,也是笔者认为log4j最主要特点的浓缩:

    1.阶层式的命名:

          如果一个logger 的名字后面跟着一个点号(dot),它就是点号(dot)后面的那个logger的前辈( ancestor),是这个晚辈(descendant) 的前缀。如果在它自己和这个晚辈之间没有其它的前辈,它和这个晚辈之间就是关系。

    2.级别继承

       对于一个给定的logger C,它继承的级别等于logger阶层里,从C开始往root logger上去的第一个non-null级别。


    3.执行规则

       在一个级别为q(被指定的或继承的)的logger里,一个级别为p的日志请求,只有在p >= q 时才能够被执行。

    4.appender添加性的规则

    Logger C的log输出信息将被输出到C的所有appenders和它的前辈的 appenders。这就是"appender additivity"的意思。但是,如果logger C的前辈,比如说P,P的additivity flag被设置为 false,那么,C的输出信息将被输出到C的所有appenders中去,以及它的前辈的——截止在P那里,包括P在内的,appenders中去,但是不会输出到P的前辈的 appenders中去。 默认情况下,Loggers的additivity flag设置为true

    关于日志格式:暂贴几个样例:
    log4j.appender.A1.layout.ConversionPattern=%d %-5p [%t] %-c (%13F:%L) %3x - %m%n

    在配置文件中,log4j可以访问到系统环境变量。具体的变量参考相关资料。
    一篇我很早以前在csdn写的文章:
    http://blog.csdn.net/huabingl/archive/2005/02/19/293933.aspx

    posted @ 2006-07-04 10:07 binge 阅读(527) | 评论 (0)编辑 收藏

    Mysql数据库使用技巧

      我承认我用mysql有很长时间了,不过似乎我仍然很白。好吧,还是写写吧。
      1。1067错误,无法启动。7/3/2006
         解决步骤和方案:察看日至,mysql.user表莫名其妙的弄丢了。从其他地方扒下一个放在这里就可以了。
     2.非安装版mysql的安装和启动。
         一般情况下,本人习惯用非安装版的软件。为了安装方便,你可以把解压后的文件拷贝到c盘根目录下,并把总目录改为mysql.然后进入windows命令 控制台,在c:/mysql/bin下面运行mysqld-nt --install把它安装为一个服务,然后调用net start mysql启动它,停止的命令是net stop mysql  .想要移除这个服务,用命令mysqld-nt --remove
     3.访问mysql的命令:mysql -h host -u user -p 。不过有好多好用的客户端可以使用,比如5.0自带的工具和SQLyog Enterprise
     4。库表相关的命令:SHOW DATABASES;SHOW TABLES;DESCRIBE table1/desc table1;
     5.察看当前配置:show variables;
     6.关于中文乱码问题,到一定积累,笔者准备开专题。目前简要列下:
       在mysql的一次会话中,服务器收到客户端发来的指令后,大致要执行3个动作:
      1、服务器认为收到的指令是按当前character_set_client环境变量所指定的字符集编码的,
      2、然后再将其转换成character_set_connection所指定的字符集编码
      3、分析、执行该指令。
      4、 用character_set_results变量所指定的字符集返回服务器向客户端传输的数据
     解决这个问题的关键点在于设置 default-character-set 变量。
    7,在创建数据库的时候,我们有时会需要提供一些编码上的参数,如:
    #1. Create mvnforum database with the "Create database" syntax (for unicode and others):
    #   mysql> CREATE DATABASE mvnforum CHARACTER SET [charater_set] COLLATE [collation]
    #  mysql> CREATE DATABASE mvnforum CHARACTER SET utf8 collate
    #   Where charater_set and collation : @see http://dev.mysql.com/doc/refman/4.1/en/charset-mysql.html
    #
    #   a, practice to view all supported character set
    #      mysql> SHOW CHARACTER SET;
    #   b, practice to view all supported collation:
    #      mysql> SHOW COLLATION;
    #
    #   c, Example for Unicode:
    #      mysql> CREATE DATABASE mvnforum CHARACTER SET utf8 COLLATE utf8_general_ci
    #"
    "
       未完待续。
      欢迎回帖。

    posted @ 2006-07-03 23:16 binge 阅读(1436) | 评论 (2)编辑 收藏

    关于异常Exception

    1。什么是异常
       异常是一种状态,是程序出现了符合该异常条件的一种状态。因此,他也可以说成是一种条件。
    2。为什么要捕获异常
      捕获异常是为了对程序中出现的某种状况进行处理。如果有异常而没有捕获,异常将会向上一层传播,最终导致线程在此中止。
    3。什么是check异常和unchecked异常
      uncheck异常一般是RuntimeException.出现这类异常,编译器不会强制要用户去捕获(当然你可以捕获)。   编译器会强制要求用户对checked异常进行捕获并作出一定的处理。
    4。为什么不推荐捕获顶层异常(Exception)
      程序中会发生各种各样的异常。除非你的程序是个终端(一个业务的终点),否则不推荐捕获顶层异常。
     在程序的中间环节捕获所有异常毫无意义,并有可能导致流程上的隐患。比如,出现某种异常后,期望线程就此结束,不去做下面的工作,但是如果在中间环节对顶层异常进行了非法处理,程序有可能会运行下去,将导致不可控的错误。
    5。为什么要自定义异常
     自定义异常是为了设置异常链的起点。一般情况下,我们都是允许每个程序员看到所有的异常信息,这个时候大多数都是把下一层的异常直接重掷到上一层。然而在多层次的结构中,我们有时候需要隐藏底层异常(这种异常的信息很多,很枯燥),而给消费者提供一个更为直观的异常,这个时候我们需要自定义异常。有的异常类jdk已经给我们提供,比如常用的IllegalArgumentException。如果你想在此再作包装,你可以创建自己的异常类。如此,消费者将以此异常作为异常链的起点。
    6。为什么要重掷异常
     重掷异常是处理异常的一种方式。在捕获了某种异常后,用户可能不希望在这一层做出裁决,或者即使做出了一定的处理,但仍然需要向上一层报告,因此需要重掷异常。
    7。异常机制。
       一旦某个点发生异常,这个点下面和catch语句之间的代码将不会被执行。因此,异常是一种中止流程的很有效的机制。
       关于异常,在effective java中提到“异常转译”和“异常连接”的概念。本人倾向于用“异常转译”,前提是要配置log4j,并作详细的日志纪录。

    posted @ 2006-06-29 11:40 binge 阅读(1388) | 评论 (1)编辑 收藏

    XMLBeans

     XmlBeans由 BEA公司发明,后捐赠给Apache基金会的。
     在项目中遇到这样的需求,根据已有的schema对xml进行格式校验,并读取出xml得数据。
     在大搜一番后,我最终把目光停留在xmlbeans上面。被淘汰的是digester.
     下面是一篇dev2dev得文章:
      http://dev2dev.bea.com/pub/a/2006/05/xmlbeans-2.html?page=4
     我就不炒饭了。
     好心的人给简单翻译了一下:
    http://dev2dev.bea.com.cn/techdoc/200403127.html
     翻译得内容很少,有空本人补上。
    ibm dw上也有个豆腐块:
    http://www-128.ibm.com/developerworks/cn/xml/x-beans1/
    关于digester的内容,只选了一篇文章:来自devx得
    http://www.devx.com/Java/Article/21832/1763

    关于2中方法的对比,他们的文章已经说的很详细了。

    xmlbeans采用的是sax来读取数据。2004年,由bea公司发明的stax(stream API for XML)已经被jcp列为标准jsr-173,在jdk6.0中会出现。
     
    关于stax,sax和dom的对比超出本篇范围,在此略过。
    后记:
      在正在完成的项目中,我采用了xmlbeans,它的引入给我带来了很大的方便.

    posted @ 2006-06-21 13:50 binge 阅读(622) | 评论 (0)编辑 收藏

    Ten Reasons Why Blogging is Good For Your Career

    1. You have to get noticed to get promoted.

    2. You have to get noticed to get hired.

    3. It really impresses people when you say “Oh, I’ve written about that, just google for XXX and I’m on the top page” or “Oh, just google my name.”

    4. No matter how great you are, your career depends on communicating. The way to get better at anything, including communication, is by practicing. Blogging is good practice.

    5. Bloggers are better-informed than non-bloggers. Knowing more is a career advantage.

    6. Knowing more also means you’re more likely to hear about interesting jobs coming open.

    7. Networking is good for your career. Blogging is a good way to meet people.

    8. If you’re an engineer, blogging puts you in intimate contact with a worse-is-better 80/20 success story. Understanding this mode of technology adoption can only help you.

    9. If you’re in marketing, you’ll need to understand how its rules are changing as a result of the current whirlwind, which nobody does, but bloggers are at least somewhat less baffled.

    10. It’s a lot harder to fire someone who has a public voice, because it will be noticed.

      from http://www.tbray.org/ongoing/When/200x/2005/03/08/BloggingIsGood

    posted @ 2006-06-16 15:25 binge 阅读(308) | 评论 (0)编辑 收藏

    JAVA开发者应该去的20个英文网站

    http://www.javaalmanac.com

        Java开发者年鉴一书的在线版本. 要想快速查到某种Java技巧的用法及示例代码, 这是一个不错的去处.

    http://www.onjava.com

        O'Reilly的Java网站. 每周都有新文章

    http://java.sun.com

        官方的Java开发者网站 - 每周都有新文章发表

    http://www.developer.com/java

        由Gamelan.com 维护的Java技术文章网站

    http://www.java.net

        Sun公司维护的一个Java社区网站

    http://www.builder.com

        Cnet的Builder.com网站 - 所有的技术文章, 以Java为主.

    http://www.ibm.com/developerworks/java

        IBM的Developerworks技术网站; 这是其中的Java技术主页

    http://www.javaworld.com

        最早的一个Java站点. 每周更新Java技术文章

    http://www.devx.com/java

        DevX维护的一个Java技术文章网站

    http://www.fawcette.com/javapro

        JavaPro在线杂志网站.

    http://www.sys-con.com/java

        Java Developers Journal的在线杂志网站.

    http://www.javadesktop.org

        位于Java.net的一个Java桌面技术社区网站.

    http://www.theserverside.com

        这是一个讨论所有Java服务器端技术的网站.

    http://www.jars.com

        提供Java评论服务. 包括各种framework和应用程序

    http://www.jguru.com

        一个非常棒的采用Q&A形式的Java技术资源社区.

    http://www.javaranch.com

         一个论坛,得到Java问题答案的地方,初学者的好去处。

    http://www.ibiblio.org/javafaq/javafaq.html

        comp.lang.java的FAQ站点 - 收集了来自comp.lang.java新闻组的问题和答案的分类目录.

    http://java.sun.com/docs/books/tutorial/

        来自SUN公司的官方Java指南 - 对于了解几乎所有的java技术特性非常有帮助.

    http://www.javablogs.com

        互联网上最活跃的一个Java Blog网站.

    http://java.about.com/

    转自51cto

    posted @ 2006-06-16 14:11 binge 阅读(782) | 评论 (0)编辑 收藏

    JTA和JDBC事务

     一般情况下,J2EE应用服务器支持JDBC事务、JTA事务、容器管理事务。这里讨论JTA和JDBC事务的区别。这2个是常用的DAO模式事务界定方式。
    JDBC 事务
     JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。
    ★ 在jdbc中,事务操作缺省是自动提交。也就是说,一条对数据库的更新表达式代表一项事务操作,操作成功后,系统将自动调用commit()来提交,否则将调用rollback()来回滚。
    ★ 在jdbc中,可以通过调用setAutoCommit(false)来禁止自动提交。之后就可以把多个数据库操作的表达式作为一个事务,在操作完成后调用commit()来进行整体提交,倘若其中一个表达式操作失败,都不会执行到commit(),并且将产生响应的异常;此时就可以在异常捕获时调用rollback()进行回滚。这样做可以保持多次更新操作后,相关数据的一致性,示例如下:

        try {

    conn = 

    DriverManager.getConnection    

    (&quot;jdbc:oracle:thin:@host:1521:SID&quot;,&quot;username&quot;,&quot;userpwd&quot;;

           conn.setAutoCommit(false);//禁止自动提交,设置回滚点

           stmt = conn.createStatement();

    stmt.executeUpdate(“alter table …”); //数据库更新操作1

    stmt.executeUpdate(“insert into table …”); //数据库更新操作2

           conn.commit(); //事务提交

         }catch(Exception ex) {    

             ex.printStackTrace();

             try {

              conn.rollback(); //操作不成功则回滚

              }catch(Exception e) {

    e.printStackTrace();

               }

    }

     JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。
    JTA事务
     JTA(Java Transaction API) 为 J2EE 平台提供了分布式事务服务。
     要用 JTA 进行事务界定,应用程序要调用 javax.transaction.UserTransaction 接口中的方法。例如:
     utx.begin();
          // ...
          DataSource ds = obtainXADataSource();
          Connection conn = ds.getConnection();
          pstmt = conn.prepareStatement("UPDATE MOVIES ...");
          pstmt.setString(1, "Spinal Tap");
          pstmt.executeUpdate();
          // ...
          utx.commit();

     让我们来关注下面的话:
     “用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection s 是参与 JTA 事务的 JDBC 连接。”
     要使用JTA事务,必须使用XADataSource来产生数据库连接,产生的连接为一个XA连接。
     XA连接(javax.sql.XAConnection)和非XA(java.sql.Connection)连接的区别在于:XA可以参与JTA的事务,而且不支持自动提交。
         Note:
    Oracle, Sybase, DB2, SQL Server等大型数据库才支持XA, 支持分布事务。
    My SQL 连本地都支持不好,更别说分布事务了。
    JTA方式的实现过程
       用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理.对于调用者来说,根本看不到事务是如果管理的,你只要声明开始事务,告诉容器我下面的操作要求事务参与了,最后告诉事务说到这儿可以提交或回滚了,别的都是黑箱操作。
     在使用JTA之前,你必须首先实现一个Xid类用来标识事务(在普通情况下这将由事务管理程序来处理)。Xid包含三个元素:formatID、gtrid(全局事务标识符)和bqual(分支修饰词标识符)。
     下面的例子说明Xid的实现:

    import javax.transaction.xa.*;
    public class MyXid implements Xid
    {
     protected int formatId;
     protected byte gtrid[];
     protected byte bqual[];
     public MyXid()
     {
     }
     public MyXid(int formatId, byte gtrid[], byte bqual[])
     {
      this.formatId = formatId;
      this.gtrid = gtrid;
      this.bqual = bqual;
     }

     public int getFormatId()
     {
      return formatId;
     }

     public byte[] getBranchQualifier()
     {
      return bqual;
     }

     public byte[] getGlobalTransactionId()
     {
      return gtrid;
     }

    }
     其次,你需要创建一个你要使用的数据库的数据源:

    public DataSource getDataSource()
     throws SQLException
     {
      SQLServerDataSource xaDS = new
      com.merant.datadirect.jdbcx.sqlserver.SQLServerDataSource();
      xaDS.setDataSourceName("SQLServer");
      xaDS.setServerName("server");
      xaDS.setPortNumber(1433);
      xaDS.setSelectMethod("cursor");
      return xaDS;
    }

      例1?这个例子是用“两步提交协议”来提交一个事务分支:

    XADataSource xaDS;
    XAConnection xaCon;
    XAResource xaRes;
    Xid xid;
    Connection con;
    Statement stmt;
    int ret;
    xaDS = getDataSource();
    xaCon = xaDS.getXAConnection("jdbc_user", "jdbc_password");
    xaRes = xaCon.getXAResource();
    con = xaCon.getConnection();
    stmt = con.createStatement();
    xid = new MyXid(100, new byte[]{0x01}, new byte[]{0x02});
    try {
      xaRes.start(xid, XAResource.TMNOFLAGS);
      stmt.executeUpdate("insert into test_table values (100)");
      xaRes.end(xid, XAResource.TMSUCCESS);
      ret = xaRes.prepare(xid);
      if (ret == XAResource.XA_OK) {
        xaRes.commit(xid, false);
       }
    }
    catch (XAException e) {
     e.printStackTrace();
    }
    finally {
     stmt.close();
     con.close();
     xaCon.close();
    }
     当然,实际过程中,我们不需要写这些代码,这些代码是JTA最终的实现代码。
    关于“两步提交协议”,可以参看下面的文章:
    http://www.jspcn.net/htmlnews/11049371131251752.html

     http://www.vermicelli.pasta.cs.uit.no/ipv6/students/andrer/doc/html/node18.html


    选择最好的方式
    用 JDBC API 进事务界定来构建 DAO 类的。这些 DAO 类可以总结如下:

    事务界定代码嵌入在 DAO 类中。
    DAO 类使用 JDBC API 进行事务界定。
    调用者不能界定事务。
    事务范围局限于单个 JDBC 连接。
    JDBC 事务并不总是适合复杂的企业应用程序。如果您的事务要跨越多个 DAO 或者多个数据库,那么下列实现策略也许更合适:

    事务用 JTA 界定。
    事务界定代码从 DAO 中分离出来。
    调用者负责界定事务。
    DAO 加入一个全局事务。
    JDBC 方式由于其简单性而具有吸引力,JTA 方式提供了更大的灵活性。您所选择的实现将取决于应用程序的特定需求。
    XADataSource例子:
    <?xml version="1.0" encoding="UTF-8"?>

    <!-- ===================================================================== -->
    <!--    -->
    <!--  JBoss Server Configuration    -->
    <!-- Thanks to Horia Muntean <horia@bvb.ro>   -->
    <!-- ===================================================================== -->

    <!-- $Id: db2-xa-ds.xml,v 1.1.2.1 2003/05/30 18:25:57 d_jencks Exp $ -->


    <datasources>
       <!--
           XADatasource for DB2 V8.1 (app driver)
           copy $db2_install_dir/java/db2java.zip into $jboss_install_dir/server/default/lib
       -->

       <xa-datasource>
         <jndi-name>DB2XADS</jndi-name>
         <xa-datasource-class>COM.ibm.db2.jdbc.DB2XADataSource</xa-datasource-class>
         <xa-datasource-property name="DatabaseName">yout_database_name</xa-datasource-property>
         <xa-datasource-property name="User">your_user</xa-datasource-property>
         <xa-datasource-property name="Password">your_password</xa-datasource-property>
       </xa-datasource>
    </datasources>

    引用:
     http://www.jspcn.net/htmlnews/11049371131251752.html
    http://www-128.ibm.com/developerworks/cn/java/j-dao/
    http://www.vermicelli.pasta.cs.uit.no/ipv6/students/andrer/doc/html/node18.html

     

    posted @ 2006-06-15 15:53 binge 阅读(5196) | 评论 (1)编辑 收藏

    JMS初读

    33.2 基本的jms api概念
       33.2.1 jms api体系结构
         jms应用程序组成部分:
        a. jms提供者--------j2ee平台.
        b.jms客户端--------需要用户完成的应用程序.
        c.消息----在客户端之间传递信息的对象
       d.管理的对象----连接工厂和目的地
     33.2.2 消息域
       分为"点到点消息传递域"和"发表/订阅小心传递域"
     33.2.3 消费消息
       两种方式:同步和异步.同步直接用receive方法提取消息.异步需要可湖段为消费者注册一个见听器.通过调用见听器的onMessage方法来分发消息.
    33.3 jms api编程模型
      33.3.1 管理的对象
       a.连接工厂
        通常是执行jndi查找获得连接工厂.eg:
      Context ctx= new InitialContext();
      ConnectionFactory cf=(ConnectionFactory ) ctx.lookup("jms/QueueConnectionFactory");
    ConnectionFactory cf=(ConnectionFactory ) ctx.lookup("jms/TopicConnectionFactory");
     b.目的地
       在ptp中,目的地是"队列".在发表/订阅中,目的地是"主题".
      eg:
    Destination mydest=(Topic)ctx.lookup("jms/mytopic");
    33.3.2 连接
     连接由连接工厂来创建.eg:
    Connection conn=ConnectionFactory .createConnection();
    33.3.3 会话
    会话 由 Connection来创建
    Session session=Connection.createSession(false,Session.AUTO_ACKOWLEDGE);
    事务性的会话
    Session session=Connection.createSession(true,0);
    33.3.4 消息生产者
    由session 来创建,实现MessageProducer接口.
       MessageProducer mp=session.createProducer(myQueue);
    发送动作
    mp.send(message);
    33.3.5 消息消费者
     由session创建,实现MessageConsumer接口.
    eg:
    MessageConsumer mc=session.createConsumer(myQueue);
    bwt:
    利用session.createDurableSubscriber可以创建长期的订阅者.
      ========获得消息==
    同步方式.
    connection.start();
    Message m=consumer.receive();
    connection.start();
    Message m=consumer.receive(1000); //time out afer a second
    异步方式.
    构造一个消息舰艇器,用setMessageListener方法向具体的MessageConsumer中注册.eg:
      Listener myListener= new Listener ();
    consumer.setMessageListener (myListener );
    33.3.6 消息
    分为消息头,消息属性和消息体,只有消息头是必须的.
    消息头存放了可护短和提供者用来识别和路由消息的值.
    常见的消息体的格式(消息类型)有5种.
     
     

    posted @ 2006-05-31 22:25 binge 阅读(421) | 评论 (0)编辑 收藏

    [转]一篇不错的讲解Java异常的文章

    六种异常处理的陋习

      你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗?

      1 OutputStreamWriter out = ...

      2 java.sql.Connection conn = ...

      3 try { // ⑸

      4  Statement stat = conn.createStatement();

      5  ResultSet rs = stat.executeQuery(

      6   "select uid, name from user");

      7  while (rs.next())

      8  {

      9   out.println("ID:" + rs.getString("uid") // ⑹

      10    ",姓名:" + rs.getString("name"));

      11  }

      12  conn.close(); // ⑶

      13  out.close();

      14 }

      15 catch(Exception ex) // ⑵

      16 {

      17  ex.printStackTrace(); //⑴,⑷

      18 }

      作为一个Java程序员,你至少应该能够找出两个问题。但是,如果你不能找出全部六个问题,请继续阅读本文。

      本文讨论的不是Java异常处理的一般性原则,因为这些原则已经被大多数人熟知。我们要做的是分析各种可称为“反例”(anti-pattern)的违背优秀编码规范的常见坏习惯,帮助读者熟悉这些典型的反面例子,从而能够在实际工作中敏锐地察觉和避免这些问题。

      反例之一:丢弃异常

      代码:15行-18行。

      这段代码捕获了异常却不作任何处理,可以算得上Java编程中的杀手。从问题出现的频繁程度和祸害程度来看,它也许可以和C/C++程序的一个恶名远播的问题相提并论??不检查缓冲区是否已满。如果你看到了这种丢弃(而不是抛出)异常的情况,可以百分之九十九地肯定代码存在问题(在极少数情况下,这段代码有存在的理由,但最好加上完整的注释,以免引起别人误解)。

      这段代码的错误在于,异常(几乎)总是意味着某些事情不对劲了,或者说至少发生了某些不寻常的事情,我们不应该对程序发出的求救信号保持沉默和无动于衷。调用一下printStackTrace算不上“处理异常”。不错,调用printStackTrace对调试程序有帮助,但程序调试阶段结束之后,printStackTrace就不应再在异常处理模块中担负主要责任了。

      丢弃异常的情形非常普遍。打开JDK的ThreadDeath类的文档,可以看到下面这段说明:“特别地,虽然出现ThreadDeath是一种‘正常的情形’,但ThreadDeath类是Error而不是Exception的子类,因为许多应用会捕获所有的Exception然后丢弃它不再理睬。”这段话的意思是,虽然ThreadDeath代表的是一种普通的问题,但鉴于许多应用会试图捕获所有异常然后不予以适当的处理,所以JDK把ThreadDeath定义成了Error的子类,因为Error类代表的是一般的应用不应该去捕获的严重问题。可见,丢弃异常这一坏习惯是如此常见,它甚至已经影响到了Java本身的设计。

      那么,应该怎样改正呢?主要有四个选择:

      1、处理异常。针对该异常采取一些行动,例如修正问题、提醒某个人或进行其他一些处理,要根据具体的情形确定应该采取的动作。再次说明,调用printStackTrace算不上已经“处理好了异常”。

      2、重新抛出异常。处理异常的代码在分析异常之后,认为自己不能处理它,重新抛出异常也不失为一种选择。

      3、把该异常转换成另一种异常。大多数情况下,这是指把一个低级的异常转换成应用级的异常(其含义更容易被用户了解的异常)。

      4、不要捕获异常。

      结论一:既然捕获了异常,就要对它进行适当的处理。不要捕获异常之后又把它丢弃,不予理睬。

      反例之二:不指定具体的异常

      代码:15行。

      许多时候人们会被这样一种“美妙的”想法吸引:用一个catch语句捕获所有的异常。最常见的情形就是使用catch(Exception ex)语句。但实际上,在绝大多数情况下,这种做法不值得提倡。为什么呢?

      要理解其原因,我们必须回顾一下catch语句的用途。catch语句表示我们预期会出现某种异常,而且希望能够处理该异常。异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。由于绝大多数异常都直接或间接从java.lang.Exception派生,catch(Exception ex)就相当于说我们想要处理几乎所有的异常。

      再来看看前面的代码例子。我们真正想要捕获的异常是什么呢?最明显的一个是SQLException,这是JDBC操作中常见的异常。另一个可能的异常是IOException,因为它要操作OutputStreamWriter。显然,在同一个catch块中处理这两种截然不同的异常是不合适的。如果用两个catch块分别捕获SQLException和IOException就要好多了。这就是说,catch语句应当尽量指定具体的异常类型,而不应该指定涵盖范围太广的Exception类。

      另一方面,除了这两个特定的异常,还有其他许多异常也可能出现。例如,如果由于某种原因,executeQuery返回了null,该怎么办?答案是让它们继续抛出,即不必捕获也不必处理。实际上,我们不能也不应该去捕获可能出现的所有异常,程序的其他地方还有捕获异常的机会??直至最后由JVM处理。

      结论二:在catch语句中尽可能指定具体的异常类型,必要时使用多个catch。不要试图处理所有可能出现的异常。

      反例之三:占用资源不释放

      代码:3行-14行。

      异常改变了程序正常的执行流程。这个道理虽然简单,却常常被人们忽视。如果程序用到了文件、Socket、JDBC连接之类的资源,即使遇到了异常,也要正确释放占用的资源。为此,Java提供了一个简化这类操作的关键词finally。

      finally是样好东西:不管是否出现了异常,Finally保证在try/catch/finally块结束之前,执行清理任务的代码总是有机会执行。遗憾的是有些人却不习惯使用finally。

      当然,编写finally块应当多加小心,特别是要注意在finally块之内抛出的异常??这是执行清理任务的最后机会,尽量不要再有难以处理的错误。

      结论三:保证所有资源都被正确释放。充分运用finally关键词。

      反例之四:不说明异常的详细信息

      代码:3行-18行。

      仔细观察这段代码:如果循环内部出现了异常,会发生什么事情?我们可以得到足够的信息判断循环内部出错的原因吗?不能。我们只能知道当前正在处理的类发生了某种错误,但却不能获得任何信息判断导致当前错误的原因。

      printStackTrace的堆栈跟踪功能显示出程序运行到当前类的执行流程,但只提供了一些最基本的信息,未能说明实际导致错误的原因,同时也不易解读。

      因此,在出现异常时,最好能够提供一些文字信息,例如当前正在执行的类、方法和其他状态信息,包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。

      结论四:在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读。

      反例之五:过于庞大的try块

      代码:3行-14行。

      经常可以看到有人把大量的代码放入单个try块,实际上这不是好习惯。这种现象之所以常见,原因就在于有些人图省事,不愿花时间分析一大块代码中哪几行代码会抛出异常、异常的具体类型是什么。把大量的语句装入单个巨大的try块就象是出门旅游时把所有日常用品塞入一个大箱子,虽然东西是带上了,但要找出来可不容易。

      一些新手常常把大量的代码放入单个try块,然后再在catch语句中声明Exception,而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难,因为一大段代码中有太多的地方可能抛出Exception。
    结论五:尽量减小try块的体积。

      反例之六:输出数据不完整

      代码:7行-11行。

      不完整的数据是Java程序的隐形杀手。仔细观察这段代码,考虑一下如果循环的中间抛出了异常,会发生什么事情。循环的执行当然是要被打断的,其次,catch块会执行??就这些,再也没有其他动作了。已经输出的数据怎么办?使用这些数据的人或设备将收到一份不完整的(因而也是错误的)数据,却得不到任何有关这份数据是否完整的提示。对于有些系统来说,数据不完整可能比系统停止运行带来更大的损失。

      较为理想的处置办法是向输出设备写一些信息,声明数据的不完整性;另一种可能有效的办法是,先缓冲要输出的数据,准备好全部数据之后再一次性输出。

      结论六:全面考虑可能出现的异常以及这些异常对执行流程的影响。

      改写后的代码

      根据上面的讨论,下面给出改写后的代码。也许有人会说它稍微有点?嗦,但是它有了比较完备的异常处理机制。

      OutputStreamWriter out = ...

      java.sql.Connection conn = ...

      try {

      Statement stat = conn.createStatement();

      ResultSet rs = stat.executeQuery(

      "select uid, name from user");

      while (rs.next())

      {

      out.println("ID:" + rs.getString("uid") + ",姓名: " + rs.getString("name"));

      }

      }

      catch(SQLException sqlex)

      {

      out.println("警告:数据不完整");

      throw new ApplicationException("读取数据时出现SQL错误", sqlex);

      }

      catch(IOException ioex)

      {

      throw new ApplicationException("写入数据时出现IO错误", ioex);

      }

      finally

      {

      if (conn != null) {

      try {

       conn.close();

      }

      catch(SQLException sqlex2)

      {

       System.err(this.getClass().getName() + ".mymethod - 不能关闭数据库连接: " + sqlex2.toString());

      }

      }

      if (out != null) {

      try {

       out.close();

      }

      catch(IOException ioex2)

      {

      System.err(this.getClass().getName() + ".mymethod - 不能关闭输出文件" + ioex2.toString());

      }

      }

      }


      本文的结论不是放之四海皆准的教条,有时常识和经验才是最好的老师。如果你对自己的做法没有百分之百的信心,务必加上详细、全面的注释。

      另一方面,不要笑话这些错误,不妨问问你自己是否真地彻底摆脱了这些坏习惯。即使最有经验的程序员偶尔也会误入歧途,原因很简单,因为它们确确实实带来了“方便”。所有这些反例都可以看作Java编程世界的恶魔,它们美丽动人,无孔不入,时刻诱惑着你。也许有人会认为这些都属于鸡皮蒜毛的小事,不足挂齿,但请记住:勿以恶小而为之,勿以善小而不为。

    posted @ 2006-05-31 22:20 binge 阅读(305) | 评论 (0)编辑 收藏

    Commons Configuration

         摘要: Configuration 简介  Configuration 的参数可能来自下面的资源:     *  Properties files    * XML documents    * Property list files (.plist)    * JNDI    * JDBC Datasource    * System prope...  阅读全文

    posted @ 2006-05-31 10:30 binge 阅读(2955) | 评论 (0)编辑 收藏

    Commons Lang

    官方地址:http://jakarta.apache.org/commons/lang/

    概述:
       标准的java库并没有提供足够的处理他的核心类的方法,Lang组件提供了这些扩展的方法
       lang 组件为java.lang API提供了一套帮助类。特别是String处理方法,基本的数字处理方法,对象反射,创建和序列化和系统属性。另外他包含了一个可继承的
    enum类型,一个exception结构,对java.util.Date的基本加强以及一系列构建方法,比如hashCode,toString和equals
    可以点击下面的连接获得体验:
    http://www.j2medev.com/bbs/dispbbs.asp?boardid=3&id=3835&star=1&page=3

    http://www.sentom.net/list.asp?id=76
      
    lang.*
        String字符串处理-StringUtils,StringEscapeUtils,RondomStringUtils,Tokenizer,WordUtils.
        RandomStringUtils 顾名思义,它提供了一段文本,常用来做默认密码的值。 StringEscapeUtils 包含了escape和unescape "java,javascript,html,xml和sql"的方法。 Tokenizer 是java.util.StringTokenizer的改良。
       另外,WordUtils是另一个String处理类。他在String的单词层次上工作,比如,WordUtils.capitalize方法会将一段文本中的每个单词都首字母大写。WordUtils也包含了包装文本的方法。
       字符处理- CharSetUtils, CharSet, CharRange, CharUtils
    字符的处理也很重要,CharUtils因此而存在。CharSetUtils则是为了对字符串作批处理。注意,尽管CharSetUtils接受一个String参数,但却把它当成一组字符。比如:CharSetUtils.delete("testtest", "tr")将删除所有的t和所有的r,而不仅仅是tr这个字符串。
    CharRange和CharSet是CharSetUtils内部将要用到的类。
    JVM交互-SystemUtils, CharEncoding
    SystemUtils是个很小的类,他将使你获得你的JVM平台信息变得更为简单。比如:SystemUtils.isJavaVersionAtLeast(1.3f) 。CharEncoding也是被用来做和jvm的交互,可能会被用来查看特定的环境上支持那种字符编码。
    序列化-SerializationUtils, SerializationException
     序列化并不难!一个简单的工具类就可以刈除你的痛苦。而且,他提供一个方法通过反序列化和重序列化来克隆对象,这是个很老的java诀窍。
    Assorted functions -ObjectUtils,ClassUtils,ArrayUtils,BooleanUtils
      ObjectUtils提供了许多对对象便利的操作,以及大部分的对java.lang.Object的方法的null-safe实现。
       ClassUtils提供了一套用于反射的帮助函数。值得留意的是在ClassUtils隐含的comparators,他可以对Class和package按名称进行排序。这个排序仅仅是字典排序。
       接下来,我们介绍ArrayUtils.他有很多方法和这些方法的重载方法。这个类值得我们深入的了解一下。开始之前,我们假设所有的被提及的方法都被重载(无论是基本类型还是对象类型)。而且,‘xxx’代表了一个基本类型,有时候也包含了对象。
    • ArrayUtils 为基本类型提供了一个单态的空疏组.这些将被Collections API的toArray()方法中用到, 也可以在用在那些希望在发生错误时返回空数组的方法中.
    • add(xxx[], xxx) 添加一个原始类型到一个数组, 自动调整数组的大小. 对象类型可以用.
    • clone(xxx[]) 克隆一个基本类型或者对象数组.
    • contains(xxx[], xxx) 在一个基本类型或者对象类型的数组中查找一个基本类型或者对象类型.
    • getLength(Object) 返回一个数组的大小.如果参数不是一个数组,将会返回一个IllegalArgumentException异常。
    •  hashCode(Object), equals(Object, Object), toString(Object)
    • indexOf(xxx[], xxx)indexOf(xxx[], xxx, int) 是仿照String的相关方法, 但是他用来处理primitive/Object数组. 另外, lastIndexOf 系列的方法也存在.
    • isEmpty(xxx[]) 判断一个数组是否为null或者空.
    • isSameLength(xxx[], xxx[]) 判断2个数组的大小是否相等.
    • 除了添加的方法, 这里也提供了2类删除的方法. 第一种是根据索引删除:remove(xxx[], int), 第二种删除数组中的第一个值:remove(xxx[], xxx)
    •  reverse(xxx[]) 翻转一个数组.
    • The subarray(xxx[], int, int) 取出一个大数组的一部分.
    • 基本类型和基本类型的包装类之间的转换可以通过 toObject(xxx[])toPrimitive(Xxx[]) 方法.
       ArrayUtils.toMap(Object[])用来将一个数组转化为一个map,比如:
           Map colorMap = MapUtils.toMap(new String[][] {{
               {"RED", "#FF0000"},
               {"GREEN", "#00FF00"},
               {"BLUE", "#0000FF"}
           });
         BooleanUtils,对这个类,或许你有时候会对他的BooleanUtils.toBoolean(String)方法感兴趣。
    异常-IllegalClassException, IncompleteArgumentException, NotImplementedException, NullArgumentException, UnhandledException

     lang.builder.*
      
    提供了HashCodeBuilder,EqualsBuilder, CompareToBuilder, ToStringBuilder。笔者在项目中经常用到HashCodeBuilder,具体用法参照文章前面给出的连接。
    lang.enums.* (formerly lang.enum)
       
    他主要的功能就是为你的常量赋值,并且给定他们的顺序. For example:
    public final class ColorEnum extends Enum {
         public static final ColorEnum RED = new ColorEnum("Red");
         public static final ColorEnum GREEN = new ColorEnum("Green");
         public static final ColorEnum BLUE = new ColorEnum("Blue");
    
         private ColorEnum(String color) {
              super(color);
         }
    
         public static ColorEnum getEnum(String color) {
              return (ColorEnum) getEnum(ColorEnum.class, color);
         }
    
         public static Iterator iterator() {
              return iterator(ColorEnum.class);
         }
    }
    

     

    posted @ 2006-05-26 12:48 binge 阅读(473) | 评论 (0)编辑 收藏