天空

 
 

常用链接

  • 我的随笔
  • 我的评论
  • 我的参与
  • 最新评论

留言簿(12)

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔分类

  • Database (rss)
  • JSP(4) (rss)
  • Linux(2) (rss)
  • XML(5) (rss)
  • 其它(1) (rss)
  • 竞赛题(1) (rss)

随笔档案

  • 2006年9月 (2)
  • 2006年7月 (2)
  • 2006年6月 (3)
  • 2006年4月 (5)
  • 2006年3月 (6)

文章分类

  • Linux(1) (rss)

.Net

  • .Net
  • 华育国际
  • 江南白衣

友情链接

  • 搬家公司
  • 讨债公司

搜索

  •  

最新评论

  • 1. re: 使用 JTidy 协助抽取网页内容
  • 你好,样式表怎么写呢?一点都不会,问题可能比较笨,拜托了急用。
  • --听海
  • 2. re: 使用 JTidy 协助抽取网页内容
  • 评论内容较长,点击标题查看
  • --jiangix11
  • 3. re: 使用 Java 生成 MD5 编码[未登录]
  • fomat 字节为负数生成的结果对吗
  • --无名
  • 4. re: VMware, Fedora 5 安装问题
  • 你好我也遇到了No X Install Found的问题,能否发个vmware-config-tools.pl 给我。谢谢了
  • --wh8908
  • 5. re: 字符编码的奥秘
  • 不错
  • --lymin

阅读排行榜

  • 1. 使用 Java 生成 MD5 编码(56322)
  • 2. 使用 JTidy 协助抽取网页内容(7957)
  • 3. 字符编码的奥秘(5637)
  • 4. 详细介绍在tomcat中配置数据源以及数据源的原理 (3887)
  • 5. 配制 eclipse 3.1 使用中文 JavaAPI (2570)

评论排行榜

  • 1. 使用 JTidy 协助抽取网页内容(19)
  • 2. 字符编码的奥秘(10)
  • 3. 用于解析 sina 新闻页面的 XSLT 文件 (10)
  • 4. 使用 Java 生成 MD5 编码(10)
  • 5. 配制 eclipse 3.1 使用中文 JavaAPI (5)

Powered by: 博客园
模板提供:沪江博客
BlogJava | 首页 | 发新随笔 | 发新文章 | 联系 | 聚合 | 管理

2006年9月17日

在Fedora 5中安装Vmware Tools
http://blog.csdn.net/freewind88/archive/2006/07/17/931666.aspx

由于FC5算是比较新的一个Linux版本(现在FC6的Test1刚发布),所以Vmware(我用的版本号是5.5.1 build-19175,写这篇文章时是最新的版本)还没有直接支持FC5的Vmware Tools安装。为了正确安装Fedora和Vmware Tools,我在里面缠了几天的时间,有时的确比较郁闷。现在把几个关键点总结一下,方便后来人参照。
1.安装FC5时选择Linux版本号时选Red Hat Enterprise Linux 4,如果选择其它版本可能会造成FC安装文件找不到硬盘,这是由于Vmware默认推荐使用虚拟SCSI硬盘,而其它版本Linux配置没有为SCSI硬盘设置驱动。解决方法非常简单,只要在安装过程提示添加设备时选择添加Buslogic就行了。个人感觉还是使用自定义配置向导比较好,很多地方都可以自己调整设置。
2.安装Vmware Tools需要的一些必要软件。
安装编译工具:yum -y install gcc gcc-c++ kernel-devel
更新kernel:yum -y update kernel
检查:rpm -qa | grep kernel
更新完后重启一下,使更新生效。
之所以要下载更新这么多东西是因为FC5有个很奇怪的现象,在安装时我已经勾选了全部开发工具,但是后期它还是会提示找不到匹配你内核的C头文件。提示如下。估计大多数人都是卡在这,看见这句话肯定已经很窝火了
What is the location of the directory of C header files that match your running kernel? [/usr/src/linux/include]
The path "/usr/src/linux/include" is not an existing directory.
整个下载过程非常慢,可能是由于我是宽带且连到国外服务器下载,更新完大概耗去了我一个白天的时间。可以通过yum的配置文件,设置镜象服务器来改进下载速度,具体方法就要各位自己上网查了,偶不会
3.安装Vmware Tools,此时会被卡在上面所说的缺少头文件的那一步,不用管它,Ctrl+C中断安装。
4.去http://ftp.cvut.cz/vmware/下载更新
我下载时最新的补丁是vmware-any-any-update101.tar.gz。
解压缩然后执行:./runme.pl
接着一路照默认设置安装下去就ok了。
Vmware Tools安装完成,终于可以看见共享文件夹了。其实安装Vmware Tools一方面是为了改善显示,但在FC5中倒好像也无所谓,因为它在虚拟机里直接就能调到1024的分辨率,显示正常,不如前面的几个版本,在我机子上只要分辨率调高显示就不正常,会自动切换回来。另一方面主要还是为了要那个共享文件夹,这样和Windows交换文件时就方便了。

BTW:本文参考了网上的诸多文献,对作者们表示感谢

posted @ 2006-09-17 09:43 haogj 阅读(824) | 评论 (0) | 编辑 收藏
 
VMware, Fedora 5 安装问题
安装的问题
http://www.5ang1ou.com/2006/03/26/vmware-fedora-5/

11:56 pm on Sunday, March 26, 2006

早些没赶上Fedora 5的发布,今天特地下载下来玩玩,整个DVD碟4.5G,专门去学校花了半个小时拖了下来,再从工作那头窃取一张光碟刻录。回来后立马开动Vmware来安装。傻瓜界面,完全图片提示,本想着可以顺利收工。结果搜索完硬件后突然提示说硬盘找不到,给了两个选项,一手动安装,一跳过继续。心想估计Vmware的驱动没装,不是什么大问题,就选了跳过继续。结果到最后还是提示说磁碟找不到,然后就重启了。郁闷,再来,这次选个手动安装,进入列表后却死都找不到驱动的驱动。瞎撞了一器乱装了一通,最后到了安装画面又被弹了回来。心想这厮咋那变态乜,决定上网一探究竟。去红帽的主页潜伏了半天,终于发现一条线索,说是Fedora 5开始就不支持Bus Logic了,改为仅支持Lsi Logic。突然间茅塞顿开,恍然大悟,原来如此,回到Vmware里面,以自定义的方式选了Lsi Logic作为硬盘模式,重启一试,嘿,通过了,赞啊。至于这两种logic之间有虾米不同,偶就不去追究了,这些玩意还是留给高人来探讨比较合适,偶这种底层用户只要能用就满足咯。七装八凑的终于把Fedora 5装好了,算是完全赤裸安装,上面除了KDE就啥都没有。设置好Yum后就开始遥遥无期的更新中,现在还在盯着那个咪表看。感觉上Fedora 5跑得比4要慢写,我几乎所有的服务都屏蔽了,还是感觉处理的时间要长写,也许是偶选了i386而不是X86_64的缘故?



vmtools 的问题
http://www.5ang1ou.com/2006/03/27/vmware-tool/


继续昨天的奋斗,今天装完 Fedora 5 后准备装 Vmware Tool 的时候又出现问题。Vmware Tool这个东西顾名思义地就是为了Vmware这个软件才存在地,有了它你的linux就可以设定显示大小,内存优化和其他鼠标键盘等优化设置。不装 Vmware Tool 的话鼠标就会被锁定在Vmware 程序里面,要切换出来非常麻烦,装了以后只要移到边上就自己弹出来了,回去也一样,移到边上就自己弹进去了。也许是 Fedora 5 太新的缘故,Vmware Tool 死活都装不进去。一开始说找不到 kernel 的源文件,安装了以后又说文件版本不对号。去 Vmware 的官方讨教,发现有问题的不止偶一个,几乎所有装了 Fedora 5 的都碰见了。随后发现一达人发了一解决办法的帖子,顿时敬仰起来,然后马上进去顶一个顺便留名。他用了个第三方补丁脚本,让 Vmware Tool 的检测程序通过版本侦测。这个程序在这里可以下到,解压后需要对 runme.pl 脚本进行修改,然后运行,运行完毕以后再来运行 Vmware Tool 的设定安装程序就可以了。

一切都蛮顺利的,可是编译到最后出现 “No X Install Found” 的错误,这下连显示大小都没得选了。继续找人求救,终于有好心人指了条路。原来 Fedora 5 用了 X7版本,而Vmware Tool 检测不到这个,所以认为没有X。解决方法当然除了修改脚本没其他办法咯。要修改的地方暴多,也乱的很,都在 vmware-config-tools.pl 里面。好在偶很幸运,一次过通过编译,成功检测到 X7,也顺利地更改了显示大小。今天特此留下此贴给自己以后查账用,下面给出了需要修改的两个文件下载,覆盖运行就可以了。爽。

[ runme.pl ] [ vmware-config-tools.pl ]

posted @ 2006-09-17 09:34 haogj 阅读(1592) | 评论 (1) | 编辑 收藏
 

2006年7月6日

利用JSP 2.0开发Web应用程序
http://www.phome.net/document/java/200504/java111245789013746.html
posted @ 2006-07-06 22:44 haogj 阅读(442) | 评论 (0) | 编辑 收藏
 

2006年7月4日

使用 Java 生成 MD5 编码

    MD5即Message-Digest Algorithm 5(信息-摘要算法5),是一种用于产生数字签名的单项散列算法,在1991年由MIT Laboratory for Computer Science(IT计算机科学实验室)和RSA Data Security Inc(RSA数据安全公司)的Ronald L. Rivest教授开发出来,经由MD2、MD3和MD4发展而来。MD5算法的使用不需要支付任何版权费用。它的作用是让大容量信息在用数字签名软件签私人密匙前被"压缩"成一种保密的格式(将一个任意长度的“字节串”通过一个不可逆的字符串变换算法变换成一个128bit的大整数,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。)
   
   在 Java 中,java.security.MessageDigest 中已经定义了 MD5 的计算,所以我们只需要简单地调用即可得到 MD5 的128 位整数。然后将此 128 位计 16 个字节转换成 16 进制表示即可。

    代码如下:

package com.tsinghua;

/**
 * MD5的算法在RFC1321 中定义
 * 在RFC 1321中,给出了Test suite用来检验你的实现是否正确:
 * MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
 * MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
 * MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
 * MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
 * MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
 *
 * @author haogj
 *
 * 传入参数:一个字节数组
 * 传出参数:字节数组的 MD5 结果字符串
 */
public class MD5 {
 public static String getMD5(byte[] source) {
  String s = null;
  char hexDigits[] = {       // 用来将字节转换成 16 进制表示的字符
     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',  'e', 'f'};
   try
   {
    java.security.MessageDigest md = java.security.MessageDigest.getInstance( "MD5" );
    md.update( source );
    byte tmp[] = md.digest();          // MD5 的计算结果是一个 128 位的长整数,
                                                // 用字节表示就是 16 个字节
    char str[] = new char[16 * 2];   // 每个字节用 16 进制表示的话,使用两个字符,
                                                 // 所以表示成 16 进制需要 32 个字符
    int k = 0;                                // 表示转换结果中对应的字符位置
    for (int i = 0; i < 16; i++) {          // 从第一个字节开始,对 MD5 的每一个字节
                                                 // 转换成 16 进制字符的转换
     byte byte0 = tmp[i];                 // 取第 i 个字节
     str[k++] = hexDigits[byte0 >>> 4 & 0xf];  // 取字节中高 4 位的数字转换, 
                                                             // >>> 为逻辑右移,将符号位一起右移
     str[k++] = hexDigits[byte0 & 0xf];            // 取字节中低 4 位的数字转换
    }
    s = new String(str);                                 // 换后的结果转换为字符串

   }catch( Exception e )
   {
    e.printStackTrace();
   }
   return s;
 }
}


    测试代码如下:

import com.tsinghua.*;

public class TestMD5
{
 public static void main( String xu[] )
 { // 计算 "a" 的 MD5 代码,应该为:0cc175b9c0f1b6a831c399e269772661
  System.out.println( MD5.getMD5("a".getBytes()) );
 }
}


 

posted @ 2006-07-04 22:25 haogj 阅读(56322) | 评论 (10) | 编辑 收藏
 

2006年6月25日

彻底解决 Tomcat 5 下文字乱码问题

使用 tomcat 时,相信大家都回遇到中文乱码的问题,具体表现为通过表单取得的中文数据为乱码。

一、初级解决方法

通过一番检索后,许多人采用了如下办法,首先对取得字符串按照 iso8859-1 进行解码转换,然后再按照 gb2312 进行编码,最后得到正确的内容。示例代码如下:

String  para = new String( request.getParameter("para").getBytes("iso8859-1"), "gb2312");

具体的原因是因为美国人在写 tomcat 时默认使用 iso8859-1 进行编码造成的。

 然而,在我们的 servlet 和 jsp 页面中有大量的参数需要进行传递,这样转换的话会带来大量的转换代码,非常不便。

二、入门级解决方法

后来,大家开始写一个过滤器,在取得客户端传过来的参数之前,通过过滤器首先将取得的参数编码设定为 gb2312 ,然后就可以直接使用 getParameter 取得正确的参数了。这个过滤器在 tomcat 的示例代码
jsp-examples 中有详细的使用示例,   其中过滤器在 web.xml 中的设定如下,示例中使用的是日文的编码,我们只要修改为 gb2312 即可

    <filter>
        <filter-name>Set Character Encoding</filter-name>
        <filter-class>filters.SetCharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>EUC_JP</param-value>
        </init-param>
    </filter>

过滤器的代码如下:
public class SetCharacterEncodingFilter implements Filter {

    // 编码的字符串
    protected String encoding = null;

   // 过滤器的配置
    protected FilterConfig filterConfig = null;

   // 是否忽略客户端的编码
    protected boolean ignore = true;

   // 销毁过滤器
    public void destroy() {

        this.encoding = null;
        this.filterConfig = null;

    }

   // 过滤方法
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
          throws IOException, ServletException {

        // 如果使用过滤器,忽略客户端的编码,那么使用通过过滤器设定编码
        if (ignore || (request.getCharacterEncoding() == null)) {
            String encoding = selectEncoding(request);
            if (encoding != null)
                request.setCharacterEncoding(encoding);
        }

        // 传送给下一个过滤器
        chain.doFilter(request, response);

    }


    // 初始化过滤器
    public void init(FilterConfig filterConfig) throws ServletException {

        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        if (value == null)
            this.ignore = true;
        else if (value.equalsIgnoreCase("true"))
            this.ignore = true;
        else if (value.equalsIgnoreCase("yes"))
            this.ignore = true;
        else
            this.ignore = false;

    }

    // 返回过滤器设定的编码
    protected String selectEncoding(ServletRequest request) {

        return (this.encoding);

    }
}

然而在 tomcat5 中,即使使用过滤器,仍然可能取得乱码,原因何在呢?

三、高级解决方法

这是因为,在 tomcat4 和 tomcat5 中对参数的处理是不一样的,在 tomcat4 中 get 与 post 的编码是一样的,所以只要在过滤器中通过 request.setCharacterEncoding 设定一次就可以解决 get 与 post 的问题。然而,在 tomcat5 中,get 与 post 的处理是分开进行的

在 tomcat 5 中,为了解决编码问题,tomcat 的作者作了很多努力,具体表现为在 tomcat 的配置文件 server.xml 中对 Connector 元素增加了如下的配置参数,专门用来对编码进行直接的配置

URIEncoding   用来设定通过 URI 传递的内容使用的编码,tomcat 将使用这里指定的编码对客户端传送的内容进行编码。

什么是 URI 呢?
java doc 的说明中如下说明:URI 是统一资源标识符,而 URL 是统一资源定位符。因此,笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。

也就是说,我们通过 get 方法提交的参数实际上都是通过 uri 提交的,都由这个参数管理,如果没有设定这个参数,则 tomcat 将使用默认的 iso8859-1 对客户端的内容进行编码。

useBodyEncodingForURI 使用与 Body 一样的编码来处理 URI, 这个设定是为了与 tomcat4保持兼容,原来在 tomcat4 和 tomcat5 中队参数的处理是不一样的,在 tomcat4 中 get 与 post 的编码是一样的,所以只要在过滤器中通过 request.setCharacterEncoding 设定一次就可以解决 get 与 post 的问题。然而,在 tomcat5 中,get 与 post 的处理是分开进行的,对 get 的处理通过 前面的 URIEncoding 进行处理,对 post 的内容依然通过 request.setCharacterEncoding 处理,为了保持兼容,就有了这个设定。

将 useBodyEncodingForURI 设定为真后,就可以通过 request.setCharacterEncoding 直接解决 get 和 post 中的乱码问题。

这样,我们可以通过在 server.xml 中设定 URIEncoding 来解决 get 方法中的参数问题,使用过滤器来解决 post 方法中的问题。

或者也可以通过在 server.xml 中设定 useBodyEncodingForURI 为 true ,配合过滤器来解决编码的问题。

在这里,我强烈建议在网站的创作过程中,全程使用 utf-8 编码来彻底解决乱码问题。

具体操作如下:
1、页面内容使用 utf-8 格式保存,在页面中加入 <mete http-equiv="contentType" content="text/html;charst=utf-8">

2、服务器端的 server.xml 中设定 useBodyEncodingForURI = true

3、使用过滤器,过滤器设定编码为 utf-8




posted @ 2006-06-25 22:04 haogj 阅读(1462) | 评论 (2) | 编辑 收藏
 

2006年6月5日

百度之星程序设计大赛初题目

1.百度语言翻译机
百度的工程师们是非常注重效率的,在长期的开发与测试过程中,他们逐渐创造了一套独特的缩略语。他们在平时的交谈、会议,甚至在各种技术文档中都会大量运用。

为了让新员工可以更快地适应百度的文化,更好地阅读公司的技术文档,人力资源部决定开发一套专用的翻译系统,把相关文档中的缩略语和专有名词翻译成日常语言。

输入要求:
输入数据包含三部分:
1. 第一行包含一个整数N(N<=10000),表示总共有多少个缩略语的词条;
2. 紧接着有N行的输入,每行包含两个字符串,以空格隔开。第一个字符串为缩略语(仅包含大写英文字符,长度不超过10字节),第二个字符串为日常语言(不包含空格,长度不超过255字节);
3. 从第N+2开始到输入结束为包含缩略语的相关文档(总长度不超过1000000个字节)。例:
6
PS 门户搜索部
NLP 自然语言处理
PM 产品市场部
HR 人力资源部
PMD 产品推广部
MD 市场发展部
百度的部门包括PS,PM,HR,PMD,MD等等,其中PS还包括NLP小组。
样例:in.txt

输出要求:
输出将缩略语转换成日常语言后的文档。(将缩略语转换成日常语言,其他字符保留原样)。例:
百度的部门包括门户搜索部,产品市场部,人力资源部,产品推广部,市场发展部等等,其中门户搜索部还包括自然语言处理小组。
样例:out.txt

2.饭团的烦恼
“午餐饭团”是百度内部参与人数最多的民间组织。
同一个部门的、同一所大学的、同一年出生的、使用同一种型号电脑的员工们总是以各种理由组织各种长期的、临时的饭团。


参加饭团,不仅可以以优惠的价格尝到更加丰富的菜式,还可以在吃饭的时候和同事们增进感情。
但是,随着百度的员工越来越多,各个饭团的管理变得繁杂起来。特别是为了照顾员工们越来越挑剔的胃,饭团的点菜负责人的压力也越来越大。现在,这个任务就交给“百度之星”了,因为,你将要为所有的百度饭团设计一个自动点菜的算法。


饭团点菜的需求如下:
1.经济是我们要考虑的一个因素,既要充分利用百度员工的午餐补助,又不能铺张浪费。因此,我们希望最后的人均费用越接近12元越好。
2.菜式丰富是我们要考虑的另一个因素。为简单起见,我们将各种菜肴的属性归结为荤菜,素菜,辛辣,清淡,并且每个菜只能点一次。
3.请谨记,百度饭团在各大餐馆享受8折优惠。


输入要求:
1.输入数据第一行包含三个整数N,M,K(0<N<=16,0<M<=N,0<K<=12),分别表示菜单上菜的数目,饭团需要点的菜的数目,就餐的人数;
2.紧接着N行,每行的格式如下:
菜名(长度不超过20个字符) 价格(原价,整数) 是否荤菜(1表示是,0表示否) 是否辛辣(1表示是,0表示否);
3.第N+2行是 a b c d 四个整数,分别表示需要点的荤菜,素菜,辛辣,清淡菜的数目。例:
3 2 2
水煮鱼 30 1 1
口水鸡 18 1 1
清炖豆腐 12 0 0
1 1 1 1
样例:in.txt


输出要求:
对于每组测试数据,输出数据包含M+1行,前M行每行包含一个菜名(按菜名在原菜单的顺序排序)。第M+1行是人均消费,结果保留两位小数。例:
口水鸡
清炖豆腐
12.00
样例:out.txt

3.变态比赛规则
为了促进各部门员工的交流,百度举办了一场全公司范围内的“拳皇”(百度内部最流行的格斗游戏)友谊赛,负责组织这场比赛的是百度的超级“拳皇”迷W.Z。W.Z不想用传统的淘汰赛或者循环赛的方式,而是自己制定了一个比赛规则。


由于一些员工(比如同部门或者相邻部门员工)平时接触的机会比较多,为了促进不同部门之间的交流,W.Z希望员工自由分组。不同组之间的每两个人都会进行一场友谊赛而同一组内的人之间不会打任何比赛。


比如4个人,编号为1~4,如果分为两个组并且1,2一个组,3,4一个组,那么一共需要打四场比赛:1 vs 3,1 vs 4,2 vs 3,2 vs 4。 而如果是1,2,3一组,4单独一组,那么一共需要打三场比赛: 1 vs 4,2 vs 4,3 vs 4。


很快W.Z意识到,这样的比赛规则可能会让比赛的场数非常多。W.Z想知道如果有N个人,通过上面这种比赛规则,总比赛场数有可能为K场吗?比如3个人,如果只分到一组则不需要比赛,如果分到两组则需要2场比赛,如果分为三组则需要3场比赛。但是无论怎么分都不可能恰需要1场比赛。


相信作为编程高手的你一定知道该怎么回答这个问题了吧? 那么现在请你帮助W.Z吧。


输入要求:
每行为一组数据,包含两个数字 N, K(0<N<=500, K>=0)。例:
2 0
2 1
3 1
3 2
样例:in.txt


输出要求:
对输入的N,K 如果N个员工通过一定的分组方式可以使比赛场数恰好为K,则输出"YES",否则输出"NO"(请全部使用大写字母),每组数据占一行。例:
YES
YES
NO
YES
样例:out.txt


4.蝈蝈计分
蝈蝈小朋友刚刚学会了0~9这十个数字,也跟爸爸妈妈来参加百度每周进行的羽毛球活动。但是他还没有球拍高,于是大人们叫他记录分数。聪明的蝈蝈发现只要记录连续得分的情况就可以了,比如用“3 2 4”可以表示一方在这一局中连得三分后,输了两分,接着又连得到四分。可是,后来大人们发现蝈蝈只会用0~9这十个数字,所以当比赛选手得分超过9的时候,他会用一个X来表示10完成记分。但问题是,当记录为“X 3 5”的时候,蝈蝈自己也记不起来是一方连续得到十三分后,再输五分;还是先赢十分输三分再赢五分。

因为百度内部就要开始进行羽毛球联赛了,要先摸清大家的实力才好分组比赛呢~于是,大人们想知道以前每局的比分是怎样的,以及谁获得了胜利。要是遇到了根据比赛记录无法确认比赛过程的情况,也要输出相应的提示哦。

需要进一步说明的是,比赛是五局三胜的,每局先获得二十一分的为胜,但是胜方必须领先对手两分或以上,否则必须继续比赛直到一方超出对手两分为止,比分多的一方获胜。任何一方先获胜三局后就获得最终胜利,比赛也相应的结束。而且蝈蝈保证是完整的无多余信息的记录了比赛。

输入要求:
1.文件中第一行只有一个整数M,表示蝈蝈记录了多少场比赛的分数;
2.在接下来的2M行里,每场比赛用两行记录,第一行是一个整数N(N<=1000)表示当前这个记录中有多少个字符,第二行就是具体的N个字符表示记录的分数(相邻字符用空格隔开)。例:
3
23
9 7 3 6 2 4 7 8 3 2 7 9 X 2 2 1 2 1 X 1 X 1 1
25
9 3 8 5 4 8 3 9 8 4 X X X X 2 X X X X 2 8 4 9 2 4
43
7 7 7 7 7 3 4 5 6 7 6 5 4 2 1 3 5 7 9 7 5 3 1 3 0 9 9 3 9 3 2 1 1 1 5 1 5 1 5 1 5 5 1
样例:in.txt


输出要求:
对应每一个分数记录,输出相应的每局分数,每局分数都使用两个整数表示,表示两个选手的得分,中间用":"分隔开;每组分数记录间使用一个空行分隔开。如果相应的比赛结果无法预测,以“UNKNOWN”一个单词独占一行表示(请全部使用大写字母)。例:
21:17
24:22
21:3

UNKNOWN

21:14
20:22
21:23
21:16
21:9
样例:out.txt

5.座位调整
百度办公区里到处摆放着各种各样的零食。百度人力资源部的调研发现,员工如果可以在自己喜欢的美食旁边工作,效率会大大提高。因此,百度决定进行一次员工座位的大调整。

调整的方法如下:
1.首先将办公区按照各种零食的摆放分成N个不同的区域(例如:可乐区,饼干区,牛奶区等等);
2.每个员工对不同的零食区域有不同的喜好程度(喜好程度是1~100的整数, 喜好程度越大表示该员工越希望被调整到相应的零食区域);
3.由于每个零食区域可以容纳的员工数量有限,人力资源部希望找到一个最优的调整方案使得总的喜好程度最大。


输入要求:
文件第一行包含两个整数N,M(N>=1,M<=300)。分别表示N个区域和M个员工;
第二行是N个整数构成的数列a,其中a[i]表示第i个区域可以容纳的员工数(1<=a[i]<=M,a[1]+a[2]+...+a[N]=M);
紧接着是一个M*N的矩阵P,P(i,j)表示第i个员工对第j个区域的喜好程度。例:
3 3
1 1 1
100 50 25
100 50 25
100 50 25
样例:in.txt


输出要求:
对于每个测试数据,输出可以达到的最大的喜好程度。例:
175
样例:out.txt


6.剪刀石头布
N个小孩正在和你玩一种剪刀石头布游戏(剪刀赢布,布赢石头,石头赢剪刀)。N个小孩中有一个是裁判,其余小孩分成三组(不排除某些组没有任何成员的可能性),但是你不知道谁是裁判,也不知道小孩们的分组情况。然后,小孩们开始玩剪刀石头布游戏,一共玩M次,每次任意选择两个小孩进行一轮,你会被告知结果,即两个小孩的胜负情况,然而你不会得知小孩具体出的是剪刀、石头还是布。已知各组的小孩分别只会出一种手势(因而同一组的两个小孩总会是和局),而裁判则每次都会随便选择出一种手势,因此没有人会知道裁判到底会出什么。请你在M次剪刀石头布游戏结束后,猜猜谁是裁判。如果你能猜出谁是裁判,请说明最早在第几次游戏结束后你就能够确定谁是裁判。

输入要求:
输入文件包含多组测试数据,每组测试数据第一行为两个整数N和M(1<=N<=500,0<M<=2000),分别为小孩的个数和剪刀石头布游戏进行的次数。接下来M行,每行两个整数且中间以一个符号隔开。两个整数分别为进行游戏的两个小孩各自的编号(为小于N的非负整数)。符号的可能值为“=”、“>”和“<”,分别表示和局、第一个小孩胜和第二个小孩胜三种情况。例:
3 3
0<1
1<2
2<0
3 5
0<1
0>1
1<2
1>2
0<2
4 4
0<1
0>1
2<3
2>3
1 0
样例:in.txt


输出要求:
1.每组测试数据输出一行,若能猜出谁是裁判,则输出裁判的编号,并输出在第几次游戏结束后就能够确定谁是裁判,小孩的编号和游戏次数以一个空格隔开;
2.如果无法确定谁是裁判,输出-2;如果发现剪刀石头布游戏的胜负情况不合理(即无论谁是裁判都会出现矛盾),则输出-1。例:
-2
1 4
-1
0 0
样例:out.txt

posted @ 2006-06-05 23:02 haogj 阅读(704) | 评论 (2) | 编辑 收藏
 

2006年6月4日

配制 eclipse 3.1 使用中文 JavaAPI

Sun 官方的中文版 Java API 文档发布了,地址为:http://gceclub.sun.com.cn/download/Java_Docs/html_zh_CN.zip, 下载后请参考如下步骤配合 eclipse3.1 使用

1. 点击菜单 <窗口> - > <设定>
2. 点击左边项目列表中的 <Java> ->  <已安装的 JRE>
3. 选中你已经安装好的 JRE5.0 ,单击右边的编辑
4. 点击对话框下边的库列表中的 rt.jar 左边的加号 “+”,展开 rt.jar 的配置
5. 选中第二项,JavaDoc Location ,单击右边的编辑,如果右边的编辑是灰色的,将库列表上边的“使用默认的系统库” (use default system libraries) 的复选框取消选择。
6. 在弹出的对象框中,上边是使用解压后的文件来进行帮助,下面使用未解压的压缩包帮助。
7. 我们使用未解压的压缩包,选择下面的 javaDoc in Archive.
8. 需要输入两个内容,一个是压缩包所在的位置 (Archive Path ), 可以选择右边的浏览选择,第二个是压缩包里面的路径 ( Paht within Archive),也可以使用右边的浏览进行选择,一直到 api 文件夹为止。完成后,在浏览的下面有一个检验的按钮 (validate) 可以进行检查。
9. 完成后,确定关闭。

现在,在 Java 编辑器中选中一个系统的方法,按 F1 即可在帮助窗口中看到对应的 JavaDoc 的帮助入口,点击后,就可以直接看到对应的 JavaAPI 的 Doc 了。




posted @ 2006-06-04 23:42 haogj 阅读(2570) | 评论 (5) | 编辑 收藏
 

2006年4月24日

详细介绍在tomcat中配置数据源以及数据源的原理
作者:baggio785
来源:http://blog.csdn.net/baggio785
日期:2006-4-24
关键词:DataSource(数据源),Tomcat ,连接池

前言


本文根据实例详细介绍了如何在tomcat中配置数据源。网上此类文章很多,但是基本都是雷同的,而且对一些特殊问题以及原理并未详细阐述,所以想根据自己的实际经验,并结合例子写一篇详细的文章。
本文是偶的一些拙见,有不正确的地方请大家多多评论指正 。

开发环境

本文的环境:JDK1.4.2,TOMCAT5.0.28,Oracle9i

JDBC简介

提到数据源,那就不能不说JDBC。JDBC是Java Database Connectivity的缩写。在java.sql包中提供了JDBC API,定义了访问数据库的接口和类。但是JDBC API不能直接访问数据库,必须依赖于数据库厂商提供的JDBC驱动程序,即JDBC DRIVER。
Java.sql 中常用的接口和类如下:
       Driver 接口和 DriverManager 类
       Connection
       Statement
       PreparedSataement

       ResultSet

 

1     Driver 接口和 DriverManager 类
       DriverManager
类用来建立和数据库的连接以及管理 JDBC 驱动程序,常用方法如下:
方法 描述
registerDriver(Driver driver) 在 DriverManager 中注册 JDBC 驱动程序
getConnection(String url,String user,String pwd) 建立和数据库的连接,返回 Connection 对象
setLoginTimeOut(int seconds) 设定等待数据库连接的最长时间
setLogWriter(PrintWriter out) 设定输入数据库日至的 PrintWriter 对象
2     Connection
       Connection
代表和数据库的连接,其常用方法如下:
方法 描述
getMetaData() 返回数据库的 MetaData 数据。 MetaData 数据包含了数据库的相关信息,例如当前数据库连接的用户名、使用的 JDBC 驱动程序、数据库允许的最大连接数、数据库的版本等等。
createStatement() 创建并返回 Statement 对象
PrepareStatement(String sql) 创建并返回 prepareStatement 对象
3      Statement
       Statement
用来执行静态 sql 语句。例如,对于 insert 、 update 、 delete 语句,调用 executeUpdate(String sql) 方法,而 select 语句可以调用 executeQuery(String sql) 方法, executeQuery(String sql) 方法返回 ResultSet 对象。
4      PrepareStatement
   PrepareStatement
用于执行动态的 sql 语句,即允许 sql 语句中包含参数。使用方法为:
   String sql = “select col1 from tablename where col2=? And col3=?”;
   PrepareStatement perpStmt = conn.preparestatement(sql);
   perpStmt.setstring(1,col2Value);
      perpStmt.setFloat(2,col3Value);
      ResultSet rs = perpStmt.executeQuery();
5      ResultSet
ResultSet
用来表示 select 语句查询得到的记录集,一个 StateMent 对象在同一时刻只能打开一个 ResultSet 对象。通过 ResultSet 的 getXXX() 方法来得到字段值。 ResultSet 提供了 getString() 、 getFloat() 、 getInt() 等方法。可以通过字段的序号或者字段的名字来制定获取某个字段的值。例如:在上例中 getString(0),getString(col1) 都可以获得字段 col1 的值。
 
事务处理

在实际应用中,我们会遇到同时提交多个
sql 语句,这些 sql 语句要么全部成功,要么全部失败,如果其中一条提交失败,则必须撤销整个事务。为此, Connection 类提供了 3 个控制事务的方法:
 
方法 描述
setAutoCommit(boolen autoCommit) 设置是否自动提交事务,默认为自动提交 。
commit() 提交事务
rollback() 撤销事务
参考例子:
try{
conn.SetautoCommit(false);
stmt = conn.createstatement();
stmt.executeUpdate(“delete form table1 where col1=1”);
stmt.eecuteUpdate(“delete from table2 where col2=1”);
conn.comm.it();
}catch(Exception e){
       e.printStackTrace;
try{
              conn.rollback();
} catch(Exception e1){
       e1.printStackTrace;
}
}
通过一个 JSP 例子来访问 oracle 数据库:
<%@ page import=”java.util.*”>
<%@ page import=”java.sql.*”>
<%
try{
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
// 加载 oracle 驱动程序
Class.forName(“oracle.jdbc.driver.OracleDriver.”);
// 注册 oracle 驱动程序
DriverManager.regidterDriver(new oracle.jdbc.driver.OracleDriver());
// 建立数据库连接
conn=DriverManager.getConnection(“jdbc:oracle:thin:@your db ip:your db port:sid”,dbuser,dbpassword);
stmt = conn.createStatement();
rs = stmt.executeQuery(“select * from tablename”);
while(rs.next){
       out.print(rs.getstring(“colname”));
}
}catch(Exception e){
}
finally{
rs.close();
stmt.close();
conn.close();
}
%>

 
数据源简介

JDBC2.0
提供了 javax.sql.DataSource 的接口,负责与数据库建立连接,实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。 Dataource 中事先建立了多个数据库连接,这些数据库连接保持在数据库连接池中,当程序访问数据库时,只需要从连接池从取出空闲的连接,访问数据库结束,在将这些连接归还给连接池。
DataSource 对象由容器( Tomcat )提供,不能使用创建实例的方法来生成 DataSource 对象,要采用 JAVA 的 JNDI ( Java Nameing and Directory Interface , java 命名和目录接口)来获得 DataSource 对象的引用。(另有一种说法:“其实从技术上来说,数据源连接方式是不需要目录服务的,我们同样可以通过序列化数据源对象直接访问文件系统。这点是需要明确的。”感兴趣的朋友可以试试。) JNDI 是一种将对象和名字绑定的技术,对象工厂负责生产出对象,这些对象都和唯一的名字相绑定。程序中可以通过这个名字来获得对象的引用。 Tomcat 把 DataSource 作为一种可配置的 JNDI 资源来处理,生成 DataSource 对象的工厂为 org.apache.comm.ons.dbcp.BasicDataSourceFactory 。  

配置数据源

配置数据源其实相当简单:
首先在 server.xml 中加入 <Resource> 元素,打开 server.xml ,在 <Context> 中加入以下代码(以 oracle 为例):
 
<Resource name="jdbc/ JNDI 名字 "
               auth="Container"
               type="javax.sql.DataSource"/>
 <ResourceParams name="jdbc/JNDI 名字 ">
    <parameter>
     <name>factory</name>
      <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
    </parameter>
    <parameter>
      <name>maxActive</name>
      <value>100</value>
    </parameter>
    <parameter>
      <name>maxIdle</name>
      <value>30</value>
    </parameter>
 
    <parameter>
      <name>maxWait</name>
      <value>10000</value>
    </parameter>
 
    <parameter>
     <name>username</name>
     <value> 用户名 </value>
    </parameter>
    <parameter>
     <name>password</name>
     <value> 密码 </value>
    </parameter>
 
    <parameter>
       <name>driverClassName</name>
       <value>oracle.jdbc.driver.OracleDriver</value>
    </parameter>
 
    <parameter>
      <name>url</name>
      <value>jdbc:oracle:thin:@ip: 端口 :sid </value>
    </parameter>
 </ResourceParams>
<Resource> 元素的属性如下:
属性 描述
name 指定 Resource 的 JNDI 的名字
auth 指定管理 Resource 的 Manager ,由两个可选值: Container 和 Application 。 Container 表示由容器来创建和管理 Resource , Application 表示由 WEB 应用来创建和管理 Resource 。如果在 web application deployment descriptor 中使用 <resource-ref> ,这个属性是必需的,如果使用 <resource-env-ref> ,这个属性是可选的。
type 指定 Resource 所属的 java 类名
<ResourceParams> 元素的属性如下:
属性 描述
name 指定 ResourceParams 的 JNDI 的名字,必须和 Resource 的 name 保持一致
factory 指定生成 DataSource 对象的 factory 的类名
maxActive 指定数据库连接池中处于活动状态的数据库连接最大数目, 0 表示不受限制
maxIdle 指定数据库连接池中 处于 空闲状态的数据库连接的最大数目, 0 表示不受限制
maxWait 指定数据库连接池中的数据库连接处于空闲状态的最长时间(单位为毫秒),超过这一事件,将会抛出异常。 -1 表示可以无限期等待。
username 指定连接数据库的用户名
password 指定连接数据库的密码
driverClassName 指定连接数据库的 JDBC 驱动程序
url 指定连接数据库的 URL

其他文章说以上配置就OK了,对于web.xml的配置可有可无,其实不是这样子的。如果在web应用中访问了由Servlet容器管理的某个JNDI Resource,则必须在web.xml中声明对这个JNDI Resource的引用。表示资源引用的元素为<resource-ref>,该元素加在<wepapp></ wepapp >中。

<resource-ref>
     <descryiption>DB Connection</descryiption>
<res-ref-name>jdbc/JNDI 名字 </ res-ref-name>
<res-type>javax.sql.DataSource </ res- type>
<res-auth>Container </ res- auth>
</resource-ref>

<resource-ref>
元素的属性如下:

属性 描述
description 对所引用的资源的说明
res-ref-name 指定所引用资源的 JNDI 名字,与 <Resource> 元素中的 name 属性保持一致
res-type 指定所引用资源的类名字,与 <Resource> 元素中的 type 属性保持一致
res-auth 指定所引用资源的 Manager ,与 <Resource> 元素中的 auth 属性保持一致

到这里,数据源就已经配置成功了。但是我在测试的时候除了一点小麻烦,主要原因是对DataSource的概念没搞清楚。我是这么测试的,写一个测试类,然后在eclipse中进行junit测试,
捕获的异常为:
javax.naming.NoInitialContextException : Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initia l 。
同样的代码在JSP文件中正常运行,后来翻了一些资料,终于找到了问题的所在了。原来DataSource是由容器(TOMCAT)提供的,所以我的测试会抛出异常。为了再次验证想法是否正确,在jsp文件中import刚才抛出异常的类,在进行连接数据库,结果一切正常。
下面的例子是实际应用中使用 DataSource ,在 jsp 文件中连接 oracle 。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="java.sql.*"%>
<%@ page import="javax.naming.*"%>
<%@ page import="javax.sql.*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 </head>
<body>
<%
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
DataSource db = (DataSource)envContext.lookup("jdbc/javablogorl");
// javablogorl 为 <Resource> 元素中 name 属性的值
Connection conn = db.getConnection( ); 
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM blog_systemadmin");
while(rs.next()){
       out.print(rs.getString("admin_name")+" ");
       out.print(rs.getString("admin_password")+"<br>");
}
rs.close();
stmt.close();
conn.close();
%> 
 </body>
</html>
 


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=674822

posted @ 2006-04-24 21:21 haogj 阅读(3887) | 评论 (3) | 编辑 收藏
 
ANT十五大最佳实践
 
 ANT十五大最佳实践

在Ant出现之前,构建和部署Java应用需要使用包括特定平台的脚本、Make文件、各种版本的IDE甚至手工操作的“大杂烩”。现在,几乎所有的开源Java项目都在使用Ant,大多数公司的内部项目也在使用Ant。Ant在这些项目中的广泛使用自然导致了读者对一整套Ant最佳实践的迫切需求。

本文总结了我喜爱的Ant技巧或最佳实践,多数是从我亲身经历的项目错误或我听说的其他人经历的 “恐怖”故事中得到灵感的。比如,有人告诉我有个项目把XDoclet 生成的代码放入带有锁定文件功能的版本控制工具中。当开发者修改源代码时,他必须记住手工检出(Check out)并锁定所有将要重新生成的文件。然后,手工运行代码生成器,只到这时他才能够让Ant编译代码,这一方法还存在如下一些问题:

  • 生成的代码无法存储在版本控制系统中。
  • Ant(本案例中是Xdoclet)应该自动确定下一次构建涉及的源文件,而不应由程序员手工确定。
  • Ant的构建文件应该定义好正确的任务依赖关系,这样程序员就不必为了完成构建而不得不按照特定顺序调用任务。

当我开始一个新项目时,我首先编写Ant构建文件。Ant文件明确地定义构建的过程,并被团队中的每个程序员使用。本文所列的技巧基于这样的假定:Ant构建文件是一个必须仔细编写的重要文件,它应在版本控制系统中得到维护,并被定期进行重构。下面是我的十五大Ant最佳实践。

1. 采用一致的编码规范

Ant用户有的喜欢有的痛恨其构建文件的XML语法。与其跳进这一令人迷惑的争论中,不如让我们先看一些能保持XML构建文件简洁的方法。

首先也是最重要的,花费时间格式化你的XML让它看上去很清晰。不论XML是否美观,Ant都可以工作。但是丑陋的XML很难令人读懂。倘若你在任务之间留出空行,有规则的缩进,每行文字不超过90列左右,那么XML令人惊讶地易读。再加上使用能够高亮XML语法的优秀编辑器或IDE工具,你就不会有阅读的麻烦。

同样,精选含意明确、容易读懂的词汇来命名任务和属性。比如,dir.reports就比rpts好。特定的编码规范并不重要,只要拿出一套规范并坚持使用就行。

2. 将build.xml放在项目根目录中

Ant构建文件build.xml可以放在任何位置,但是放在项目顶级目录中可以保持项目简洁。这是最常用的规范,开发者能够在顶级目录中找到预期的build.xml。把构建文件放在根目录中,也能够使人容易了解项目目录树中不同目录之间的逻辑关系。以下是一个典型的项目目录层次:

[root dir]
  | build.xml 
  +--src 
  +--lib (包含第三方 JAR包) 
  +--build (由 build任务生成) 
  +--dist (由 build任务生成)

当build.xml在顶级目录时,假设你处于项目某个子目录中,只要输入:ant -find compile 命令,不需要改变工作目录就能够以命令行方式编译代码。参数-find告诉Ant寻找存在于上级目录中的build.xml并执行。

3. 使用单一的构建文件

有人喜欢将一个大项目分解成几个小的构建文件,每个构建文件分担整个构建过程的一小部分工作。这确实是看法不同的问题,但是应该认识到,将构建文件分割会增加对整体构建过程的理解难度。要注意在单一构建文件能够清楚表现构建层次的情况下不要过工程化(over-engineer)。

即使你把项目划分为多个构建文件,也应使程序员能够在项目根目录下找到核心build.xml。尽管该文件只是将实际构建工作委派给下级构建文件,也应保证该文件可用。

4. 提供良好的帮助说明

应尽量使构建文件自文档化。增加任务描述是最简单的方法。当你输入ant -projecthelp时,你就可以看到带有描述的任务清单。比如,你可以这样定义任务:

<target name="compile"  
   description="Compiles code, output goes to the build dir.">

最简单的规则是把所有你想让程序员通过命令行就可以调用的任务都加上描述。对于一般用来执行中间处理过程的内部任务,比如生成代码或建立输出目录等,就无法使用描述属性。

这时,可以通过在构建文件中加入XML注释来处理。或者专门定义一个help任务,当程序员输入ant help时来显示详细的使用说明。

<target name="help" description="Display detailed usage information">
  <echo>Detailed help...</echo></target>

5. 提供清除任务

每个构建文件都应包含一个清除任务,用来删除所有生成的文件和目录,使系统回到构建文件执行前的初始状态。执行清空任务后还存在的文件都应处在版本控制系统的管理之下。比如:

<target name="clean"
    description="Destroys all generated files and dirs.">
  <delete dir="${dir.build}"/>
  <delete dir="${dir.dist}"/>
</target>

除非是在产生整个系统版本的特殊任务中,否则不要自动调用clean任务。当程序员仅仅执行编译任务或其他任务时,他们不需要构建文件事先执行既令人讨厌又没有必要的清空任务。要相信程序员能够确定何时需要清空所有文件。

6. 使用ANT管理任务从属关系

假设你的应用由Swing GUI组件、Web界面、EJB层和公共应用代码组成。在大型系统中,你需要清晰地定义每个Java包属于系统的哪一层。否则任何一点修改都要被迫重新编译成百上千个文件。糟糕的任务从属关系管理会导致过度复杂而脆弱的系统。改变GUI面板的设计不应造成Servlet和EJB的重编译。

当系统变得庞大后,稍不注意就可能将依赖于客户端的代码引入到服务端。这是因为典型的IDE项目文件编译任何文件都使用单一的classpath。而Ant能让你更有效地控制构建活动。

设计你的Ant构建文件编译大型项目的步骤:首先,编译公共应用代码,将编译结果打成JAR包文件。然后,编译上一层的项目代码,编译时依靠第一步产生的JAR文件。不断重复这一过程,直到最高层的代码编译完成。

分步构建强化了任务从属关系管理。如果你工作在底层Java框架上,偶然引用到高层的GUI模板组件,这时代码不需要编译。这是由于构建文件在编译底层框架时在源路径中没有包含高层GUI面板组件的代码。

7. 定义并重用文件路径

如果文件路径在一个地方一次性集中定义,并在整个构建文件中得到重用,那么构建文件更易于理解。以下是这样做的一个例子:

<project name="sample" default="compile" basedir=".">
  <path id="classpath.common">
    <pathelement location="${jdom.jar.withpath}"/>
    ...etc  </path>
  <path id="classpath.client">
    <pathelement location="${guistuff.jar.withpath}"/>
    <pathelement location="${another.jar.withpath}"/>
    <!-- reuse the common classpath -->
    <path refid="classpath.common"/>
  </path>
  <target name="compile.common" depends="prepare">
    <javac destdir="${dir.build}" srcdir="${dir.src}">
          <classpath refid="classpath.common"/>
          <include name="com/oreilly/common/**"/>
    </javac>
  </target>
</project>

当项目不断增长构建日益复杂时,这一技术越发体现出其价值。你可能需要为编译不同层次的应用定义各自的文件路径,比如运行单元测试的、运行应用程序的、运行Xdoclet的、生成JavaDocs的等等不同路径。这种组件化路径定义的方法比为每个任务单独定义路径要优越得多。否则,很容易丢失任务从属关系的轨迹。

8. 定义恰当的任务从属关系

假设dist任务从属于jar任务,那么哪个任务从属于compile任务哪个任务从属于prepare任务呢?Ant构建文件最终定义了任务的从属关系图,它必须被仔细地定义和维护。

应该定期检查任务的从属关系以保证构建工作得到正确执行。大的构建文件随着时间推移趋向于增加更多的任务,所以到最后可能由于不必要的从属关系导致构建工作非常困难。比如,你可能发现在程序员只需编译一些没有使用EJB的GUI代码时又重新生成了EJB代码。

以“优化”的名义忽略任务的从属关系是另一种常见的错误。这种错误迫使程序员为了得到恰当的结果必须记住并按照特定的顺序调用一串任务。更好的做法是:提供描述清晰的公共任务,这些任务包含正确的任务从属关系;另外提供一套“专家”任务让你能够手工执行个别的构建步骤,这些任务不提供完整的构建过程,但是让那些专家用户在快速而恼人的编码期间能够跳过某些步骤。

9.使用属性

任何需要配置或可能发生变化的信息都应作为Ant属性定义下来。对于在构建文件中多次出现的值也同样处理。属性既可以在构建文件头部定义,也可以为了更好的灵活性而在单独的属性文件中定义。以下是在构建文件中定义属性的样式:

<project name="sample" default="compile" basedir=".">
  <property name="dir.build" value="build"/>
  <property name="dir.src" value="src"/>
  <property name="jdom.home" value="../java-tools/jdom-b8"/>
  <property name="jdom.jar" value="jdom.jar"/>
  <property name="jdom.jar.withpath"
                    value="${jdom.home}/build/${jdom.jar}"/>
    etc...
</project>

或者你可以使用属性文件:

<project name="sample" default="compile" basedir=".">
  <property file="sample.properties"/>
   etc...
</project>

在属性文件 sample.properties中:

dir.build=build
dir.src=src
jdom.home=../java-tools/jdom-b8
jdom.jar=jdom.jarjdom.jar.withpath=${jdom.home}/build/${jdom.jar}

用一个独立的文件定义属性是有好处的,它可以清晰地定义构建中的可配置部分。另外,在开发者工作在不同操作系统的情况下,你可以在不同的平台上提供该文件的不同版本。

10. 保持构建过程独立

为了最大限度的扩展性,不要应用外部路径和库文件。最重要的是不要依赖于程序员的CLASSPATH设置。取而代之的是,在构建文件中使用相对路径并定义自己的路径。如果你引用了绝对路径如C:\java\tools,其他开发者未必使用与你相同的目录结构,所以就无法使用你的构建文件。

如果你部署开放源码项目,应该提供包含编译代码所需的所有JAR文件的发行版本。当然,这是在遵守许可协议的基础上。对于内部项目,相关的JAR文件都应在版本控制系统的管理中,并捡出(check out)到大家都知道的位置。

当你必须引用外部路径时,应将路径定义为属性。使程序员能够用适合他们自己的机器环境的参数重载这些属性。你也可以使用以下语法引用环境变量:

<property environment="env"/>
<property name="dir.jboss" value="${env.JBOSS_HOME}"/>

11. 使用版本控制系统

构建文件是一个重要的制品,应该像代码一样进行版本控制。当你标记你的代码时,也应用同样的标签标记构建文件。这样当你需要回溯到旧版本并进行构建时,能够使用相应版本的构建文件。

除构建文件之外,你还应在版本控制中维护第三方JAR文件。同样,这使你能够重新构建旧版本的软件。这也能够更容易保证所有开发者拥有一致的JAR文件,因为他们都是同构建文件一起从版本控制系统中捡出的。

通常应避免在版本控制系统中存放构建成果。倘若你的源代码很好地得到了版本控制,那么通过构建过程你能够重新生成任何版本的产品。

12. 把Ant作为“最小公分母”

假设你的开发团队使用IDE工具,当程序员通过点击图标就能够构建整个应用时为什么还要为Ant而烦恼呢?

IDE的问题是一个关于团队一致性和重现性的问题。几乎所有的IDE设计初衷都是为了提高程序员的个人生产率,而不是开发团队的持续构建。典型的IDE要求每个程序员定义自己的项目文件。程序员可能拥有不同的目录结构,可能使用不同版本的库文件,还可能工作在不同的平台上。这将导致出现这种情况:在Bob那里运行良好的代码,到Sally那里就无法运行。

不管你的开发团队使用何种IDE,一定要建立所有程序员都能够使用的Ant构建文件。要建立一个程序员在将新代码提交版本控制系统前必须执行Ant构建文件的规则。这将确保代码是经过同一个Ant构建文件构建的。当出现问题时,要使用项目标准的Ant构建文件,而不是通过某个IDE来执行一个干净的构建。

程序员可以自由选择任何他们习惯使用的IDE工具或编辑器。但是Ant应作为公共基线以保证代码永远是可构建的。

13. 使用zipfileset属性

人们经常使用Ant产生WAR、JAR、ZIP和 EAR文件。这些文件通常都要求有一个特定的内部目录结构,但其往往与你的源代码和编译环境的目录结构不匹配。

一个最常用的方法是写一个Ant任务,按照期望的目录结构把一大堆文件拷贝到临时目录中,然后生成压缩文件。这不是最有效的方法。使用zipfileset属性是更好的解决方案。它让你从任何位置选择文件,然后把它们按照不同目录结构放进压缩文件中。以下是一个例子:

<ear earfile="${dir.dist.server}/payroll.ear"
    appxml="${dir.resources}/application.xml">
  <fileset dir="${dir.build}" includes="commonServer.jar"/>
  <fileset dir="${dir.build}">
    <include name="payroll-ejb.jar"/>
  </fileset>
  <zipfileset dir="${dir.build}" prefix="lib">
    <include name="hr.jar"/>
    <include name="billing.jar"/>
  </zipfileset>
  <fileset dir=".">
    <include name="lib/jdom.jar"/>
    <include name="lib/log4j.jar"/>
    <include name="lib/ojdbc14.jar"/>
  </fileset>
  <zipfileset dir="${dir.generated.src}" prefix="META-INF">
    <include name="jboss-app.xml"/>
  </zipfileset>
</ear>

在这个例子中,所有JAR文件都放在EAR文件包的lib目录中。hr.jar和billing.jar是从构建目录拷贝过来的。因此我们使用zipfileset属性把它们移动到EAR文件包内部的lib目录。prefix属性指定了其在EAR文件中的目标路径。

14. 测试Clean任务

假设你的构建文件中有clean和compile的任务,执行以下的测试。第一步,执行ant clean;第二步,执行ant compile;第三步,再执行ant compile。第三步应该不作任何事情。如果文件再次被编译,说明你的构建文件有问题。

构建文件应该只在与输出文件相关联的输入文件发生变化时执行任务。一个构建文件在不必执行诸如编译、拷贝或其他工作任务的时候执行这些任务是低效的。当项目规模增长时,即使是小的低效工作也会成为大的问题。

15. 避免特定平台的Ant封装

不管什么原因,有人喜欢用简单的、名称叫做compile之类的批文件或脚本装载他们的产品。当你去看脚本的内容你会发现以下内容:

ant compile

其实开发人员都很熟悉Ant,并且完全能够自己键入ant compile。请不要仅仅为了调用Ant而使用特定平台的脚本。这只会使其他人在首次使用你的脚本时增加学习和理解的烦扰。除此之外,你不可能提供适用于每个操作系统的脚本,这是真正烦扰其他用户的地方。

总结

太多的公司依靠手工方法和特别程序来编译代码和生成软件发布版本。那些不使用Ant或类似工具定义构建过程的开发团队,花费了太多的时间来捕捉代码编译过程中出现的问题:在某些开发者那里编译成功的代码,到另一些开发者那里却失败了。

生成并维护构建脚本不是一项富有魅力的工作,但却是一项必需的工作。一个好的Ant构建文件将使你能够集中到更喜欢的工作——写代码中去!

参考

  • Ant
  • AntGraph: Ant依赖性的可视化工具
  • Ant: The Definitive Guide, O'Reilly
  • Java Extreme Programming Cookbook, O'Reilly


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=675230

posted @ 2006-04-24 21:19 haogj 阅读(518) | 评论 (1) | 编辑 收藏
 

2006年4月18日

奇怪的 Java 日期

  Calendar cal = Calendar.getInstance();
  cal.set(1999, 12, 31);
  System.out.println( cal.get(Calendar.YEAR) +"");

这三行代码的执行结果是什么?

是 1999 吗?

但是它没有,结果是 2000。是千年虫问题吗?

        事情比我们想象的还要糟糕:这是致命的 Date/Calendar 问题。在 Java 1.0 发布的时候,,它唯一支持的日历计算类就是 Date 类。由于这个类有许多的问题,因此,在 1.1 版的时候,Calendar 类被添加到 Java 中,以纠正 Date 的缺点,不幸的是,问题更多了。
 
        我们习惯上将第一个月当作 1,因此 12  可以用来表示 12 月,不幸的是,Date 的月份表示从 0 开始,因此 12 月将用 11 来表示,而且 Calendar 继续延续了这个错误。因此上面的代码将月份设置为了 13 月,但是实际的月份只有 12 个月,代码应该抛出一个异常,通知我们发生了什么,他应该这么做,可是,它没有,它直接认为这应该是下一个月,也就是 2000 年的 1 月。因此我们上面的代码输出结果为 2000。

Date d = cal.getTime();
System.out.println( d.getDay());

再看这两行代码的结果是什么?

是 31 吗?

结果是 1

        我们在前面将日期设为了 31 日,在 cal.getTime() 中返回了一个 Date 类型的日期,这个日期也应该是 31 ,为什么是 1 呢?

        还是查一下 JavaDoc 吧, Date.getDay 返回的实际上是日期的星期数,也就是返回的结果是星期几,而不是月份中的日期。这个值从星期天开始计算,从 0 开始,因此,打印 1  表示 2000年12月31日是星期一。注意一下吧, Calendar 的方法 get( Calendar.DAY_OF_WEEK) 不知道为什么返回的是基于 1 开始的星期日期,而不是基于 0 开始的星期日期。

    以上内容取自 《Java 解惑》 P144
       


posted @ 2006-04-18 21:04 haogj 阅读(454) | 评论 (0) | 编辑 收藏
 
仅列出标题  下一页