Sparkle’s Workshop

Archive for January, 2008

Ibatis with MapBean

Posted on January 29, 2008 - Filed Under Java

用了两年的Hibernate之后,对ORM深有感触。一方面,ORM可以令到我们从OO角度来思考数据,屏蔽了数据库的差异(其实Hibernate被吹的最厉害就是那个分页,其实分页没什么技术含量,而且ROR都把分页从核心抽离了)。另一方面,性能问题,例如必须select才能update,必须select全部,必须update全部,cache带来的后遗症,javabean关联问题(一对多,多对一,多对多等),lazyload问题。当然,小型项目是很有优势的
Hibernate一直说,他生成的sql比一般程序员的要好,可以减少很多问题。但是,我倒是认为用Hibernate反而因为对程序员的要求更高导致更多问题。而且我现在认为,SQL才是王道,至少目前是。
于是在新项目中启用Ibatis,这一年来的使用感觉很不错,全程使用细粒度的SQL语句,虽然多写了很多SQL语句,但是感觉到项目在自己的控制中
我只用了Ibatis 40%不到的功能,可能大家会觉得不可思议。我没有用cache,没有用关联,没有用resultMap,甚至,连JavaBean也没有用
在大家都在讨论PO,VO,DTO的时候,我的系统里面一个JavaBean都没有
首先我问问,JavaBean是用来做什么的,存储数据,每一个PO,其实就约等于一个表里面的一行数据
我举一个真实一点的例子,一个user表

public class User {
private int id;
private String name;
 
// 省略getter/setter一大段
}

不知道大家有没有用eclipse生成JavaBean getter/setter的痛苦,至少非常枯燥。整个JavaBean实现了什么功能?完全没有
好了我开谜底了,我用的是HashMap
什么,HashMap?是不是听错了
没听错,请问有什么事情是上面那个那么普通的JavaBean能做到的,而HashMap不能做到的呢
用HashMap没有具体属性的类型啊,那不是变成动态语言一样了,而且我要在JavaBean里面加逻辑怎么办
好吧,这是我想到的两个问题(如果你也有别的问题可以留意提出来)
首先,现在不同以前了,动态语言的优势慢慢提高了,像动态语言有什么不好,我从ROR里面学了很多不错的思想
其次是要加逻辑怎么办,这个问题,之前在Javaeye讨论充血模型还是贫血模型不可开交,最后还是没什么结论,目前还是一片贫血的情况,你可以翻一下你的项目里面的JavaBean,至少大多数的Bean都是没有意义的getter/setter。BO跟PO混杂在一起也很多人不建议的。至于逻辑,大可以写在util包里面,我都把整个model包去掉了,强化一下util不成么,呵呵
再次,数据库的列,跟JavaBean的属性两者,本来就是冗余的,如果我们修改数据库结构,就还要修改相应的JavaBean,或者影射文件。当然我这种做法更依赖数据库。另外,ROR的名字转换功能可以令到代码中的调用名字更好看一些,我觉得也不是非常有必要的实现
直接使用HashMap不太方便,尤其是类型转换上,于是我实现了一个MapBean的类,其实这个类很简单,关键是用HashMap代替JavaBean的思想

public class MapBean extends HashMap<String, Object> {
public MapBean() {
}
 
public MapBean(Object… args) {
put(args);
}
 
public int getInt(Object key) {
return getInt(key, 0);
}
 
public int getInt(Object key, int defaultInt) {
Integer i = (Integer) get(key);
return i == null ? defaultInt : i;
}
 
public String getString(Object key) {
return [...]

Read More..>>

架设你的CruiseControl

Posted on January 28, 2008 - Filed Under Uncategorized

说实在话,07年最大的感悟就是重新认识了TDD和持续集成的意义,这个下次有机会再说。这次要说的是部署一个持续集成服务器。
持续集成服务器的作用其实很简单,就是check out最新的代码,然后运行指定的script,然后把结果记录下来,还可以将结果(尤其是错误的结果)通过email等手段发给程序员。
事情倒是很简单,但是我们为什么要专门的软件呢,当然你也可以自己写bash script来做这些事情,做着做着你就会发现差不多实现一个CruiseControl出来了,呵呵,无谓重复发明轮子。
常用的持续集成服务器有CruiseControl、Luntbuild 和 Anthill等,相对来说CruiseControl比较老牌,支持度也比较好,不过实际使用的时候还是觉得不太好使(最近又发现了一个软件Hudson,Netbeans在使用)
下面是安装和配置过程,可能有一些细节不是很准确,因为已经是比较早之前安装的
从官方网站下载最新版的CruiseControl 2.7.1,我选用的是exe的版本,因为我的服务器是windows的,相对来说,exe版本有一些预设的参数,配置会简单些
运行安装程序,默认装在C:\Program Files\CruiseControl,可以不改动,而实际的项目文件可以放在其他盘上面的
安装成功之后运行cruisecontrol.bat,就能看到一个dos窗口运行,这个时候访问本机8080端口就可以看到一个示范项目
接下来修改配置文件
打开config.xml,可以看到示范例子的配置,把它都注释掉,不过其实我最后的配置也跟它差不多
直接贴我的配置吧,然后再来解释

<project name="xxx-xxx">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
<bootstrappers>
[...]

Read More..>>

优化你的Eclipse VM参数

Posted on January 26, 2008 - Filed Under Uncategorized

最近dzone在讨论eclipse的VM参数
引用了一篇2004年的帖子

Here are the best options that I’ve found so far for my 2-processor Windows machine running JDK5.0 and Eclipse3.1:
-vmargs -XX:+UseParallelGC

2004年就用两个CPU都颇奢侈了吧
我现在的机器是双核+2G内存,于是我修改了一下eclipse的VM参数
打开eclipse.ini
修改或加入如下内容

-vmargs
-Xmx512m
-XX:+UseParallelGC

Read More..>>

我与Mercurial

Posted on January 25, 2008 - Filed Under Uncategorized

最初知道 Mercurial这个工具其实是因为去年6月份看了cyfdecyf的一篇blog分布式版本管理工具:git & mercurial(作者搬迁了blog,新地址是这里).然后断断续续有在使用,一直想把一些经验写出来.最近刚好遇到云风在研究分布式版本管理,还是动手把一些经验写下来吧
一直一来都是用CVS,然后是SVN来做版本管理,最初认识分布式版本管理,是一个叫SVK的工具,是一个台湾人的作品,本身基于SVN,令到SVN可以分布式工作.当时觉得安装非常麻烦就没有研究下去了,而且本身对这样的功能需求也不大.后来Linus因为不满现有版本管理软件的问题,自己花了两个星期写了一个分布式版本管理Git,现在Linux kernel等源代码已经完全工作在Git的管理之上了.但是Git本身非常晦涩难懂,而且只能在Linux下运行,我本身也主要用Windows来工作,因此也没有深入研究.
直至看到 cyfdecyf的文章,这篇文章有坚定我研究分布式版本管理的信心.集中式版本管理的缺陷, cyfdecyf和云风都有描述了一些例子,我认为那些例子都很典型.如果所有开发人员都在一个房间里面,集中式版本管理是最好的,最明显的例子就是公司的开发,大家都能直接访问到服务器,网络不会中断.这种情况下,使用分布式版本管理反而增加了复杂性.但是,如果开发人员不是在同一个房间,甚至在不同的国家.当然你也可以在Internet上假设一个SVN服务器.但是,开发人员不一定有网络,或者网络不一定很好.而每次提交,或者同步,都要花上好几分钟或者更长时间,这非常影响开发.又或者你只是私人的项目,而你有没有能力假设公开的SVN服务器.而且我只是一个人,为什么每次都要提交到外边的服务器.当然也可以在自己的机器上面架设一个SVN,但是如果你有两台以上的机器就会觉得很麻烦了.
所有的这些场景,其实你需要一个分布式版本管理.cyfdecyf的文章最后在选择Git的代替品,定了用Mercurial.那我也从Mercurial开始吧.不过Mercurial的中文资料非常少,我始终不理解分布式版本管理的原理.最后,非常搞笑的情况是,我其实是看了Git的一份中文资料才真正明白的,也推荐大家从Git的中文资料入手.
待续…

Read More..>>

如何用Java进行3DES加密解密

Posted on January 5, 2008 - Filed Under Uncategorized

最近一个合作商提出使用3DES交换数据,本来他们有现成的代码,可惜只有.net版本,我们的服务器都是Linux,而且应用都是Java。于是对照他们提供的代码改了一个Java的版本出来,主要是不熟悉3DES,折腾了一天,终于搞定。
所谓3DES,就是把DES做三次,当然不是简单地DES DES DES就行了,中途有些特定的排列。这个我可不关心,呵呵,我的目的是使用它。
在网上搜索了一下3DES,找到很少资料。经过朋友介绍,找到GNU Crypto和Bouncy Castle两个Java扩充包,里面应该有3DES的实现吧。
从GNU Crypto入手,找到一个TripleDES的实现类,发现原来3DES还有一个名字叫DESede,在网上搜索TripleDES和DESede,呵呵,终于发现更多的资料了。
Java的安全API始终那么难用,先创建一个cipher看看算法在不在吧

Cipher cipher = Cipher.getInstance("DESede");

如果没有抛异常的话,就证明这个算法是有效的
突然想看看JDK有没有内置DESede,于是撇开Crypto,直接测试,发现可以正确运行。在jce.jar里面找到相关的类,JDK内置了。
于是直接用DES的代码来改&测试,最后代码变成这样

SecureRandom sr = new SecureRandom();
DESedeKeySpec dks = new DESedeKeySpec(PASSWORD_CRYPT_KEY.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return new String(Hex.encodeHex(cipher.doFinal(str.getBytes())));

需要留意的是,要使用DESede的Spec、Factory和Cipher才行
事情还没完结,合作商给过来的除了密钥之外,还有一个IV向量。搜索了一下,发现有一个IvParameterSpec类,于是代码变成这样

SecureRandom sr = new SecureRandom();
DESedeKeySpec dks = new DESedeKeySpec(PASSWORD_CRYPT_KEY.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey securekey = keyFactory.generateSecret(dks);
IvParameterSpec iv = new IvParameterSpec(PASSWORD_IV.getBytes());
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
return new [...]

Read More..>>

如何用Java进行DES加密解密

Posted on January 5, 2008 - Filed Under Uncategorized

这篇其实是引子,直接贴代码,不多解释了

SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(PASSWORD_CRYPT_KEY.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return new String(Hex.encodeHex(cipher.doFinal(str.getBytes())));

SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(PASSWORD_CRYPT_KEY.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
return new String(cipher.doFinal(Hex.decodeHex(str.toCharArray())));

Read More..>>