|
2008-06-12
《Professional ruby on rails》这本书里面,第一章就有个例子, 它有两个model,一个是recipe,一个是 ingredient,将 recipe和 ingredient做为父子关系,为了使得test case能通过,就需要改很多地方。 原料是菜谱的一部分,所以它在routes当中把搞成 recipe/1/ingredient/1 这样的URL。而自动生成的functional test里面,都是按照缺省的route来处理的。 所以我要在所有碰到 ingredient_path的地方改成 recipe_ingredient_path。 很多地方,包括test, controller,view 都要改,包括增加 :recipe_id=>1 这样的参数,以及把@recipe 这个参数添加到 path 或者 link_to 的参数当中。 改了很多地方,这个恐怕不能算是DRY吧。 2008-05-19
rails当中,如果要实现类似于组件的开发,需要使用 render partials 这种机制来实现。 现在,又多了一种方法: cells, http://cells.rubyforge.org/ cells 其实还是类似于 controller ,只不过它自带了view,而且可以继承,这一点比 controller 强。另外,如果当前cell的view找不到,还可以找父类的view,从而使得 在rails当中,拥有类似于组件的开发机制。不过现在还刚开始没多久,文挡不是很多。 2008-05-05
http://migrate4j.sourceforge.net/ 上一篇刚刚说到有模仿 acts_as_versioned 的东西出现,现在又来了一个模仿 db:migrate 的东西。虽然以前也有 liquibase http://www.liquibase.org/ 做 类似的事情,不过那个是用xml来定义的,我不是很喜欢。而这个migrate4j,则 纯粹是 java 的方式调用。有点类似于以前哪个老大说的,完全取代ant的一个build 工具,用纯java替代xml的方式,我个人比较喜欢这个。不仅不用去了解xml的schema, 而且还可以依赖编译检查来避免错误。前不久 ZhongHaoming 还提到,由于在xml当中不小心将 jelly 写成 jetty,导致调试了很长时间的事情。如果是使用java来调用的话,这种情况就可以 在很大程度上避免了。 2008-04-27
在rails里面用 acts_as_versioned 感觉很不错,这里还有 hibernate 版本的一个: http://www.jboss.org/envers/quickstart.html 说白了就是在 hibernate的事件当中来做这个事情,不错,有机会可以试一下。 Currently, the library has the following features:
2008-04-24
我的笔记本是双操作系统,ubuntu和windows xp。前一段时间一直在ubuntu上用,由于需要使用一些即时通讯工具, 例如QQ,所以在ubuntu里面有用virtualbox虚拟了另一个winxp。这样一来,搞得有一个真实的xp系统,一个虚拟的 xp系统。这还不算头疼。最近因为一些原因,回到真实的xp系统上,发现有些ubuntu上用习惯了的东西又没有了。 这个时候,要么再virtualbox一个ubuntu,要么装cygwin。这两种方案,都不爽。而且,由于平常用的一些文件在几个真真 假假的系统之间换来换去,很难保持一致性,比较头痛。 后来想到,干脆把物理硬盘当做虚拟机的硬盘,这样,不管是把xp当做host,还是把ubuntu当做Host,我都是只有两套系统。 只不过是哪个系统为 host,哪个系统为 guest 而已。我使用的virtualbox 版本是1.5.6,参考它的手册9.9 要注意的是,文档中也指出,这是个比较危险的动作,可能会造成硬盘数据的丢失。有个原则,就是这两个系统,都不直接访问 另一个系统的分区。我就是一块硬盘,四个分区,1为xp,2和3是ubuntu,4是swap。 首先,在ubuntu上,这个比较简单,参考文档,使用命令: VBoxManage internalcommands createrawvmdk -filename ~/winxp.vmdk -rawdisk /dev/sda -partitions 1 -relative -register 这里有个权限的问题,因为/dev/sda 和 /dev/sda1 对普通用户是不可读的,所以需要修改一下权限。我是直接用 777,虽然不安全,不过省事。这里用 relative参数,就是说不用其他分区,因此只要这两个device的权限就行。 随后是mbr的问题。我给这个虚拟机让它直接使用自己的mbr,首先用 sudo apt-get install mbr,然后 install-mbr -f -p 1 winxp-pt.vmdk 这样就使得它有独立的mbr了。不过因为我不重装系统,所以这个步骤的意义其实不是很大。随后就很简单了, 启动virtualbox,新建一个xp的虚拟机,使用这块新做出来的硬盘。这里注意,有个选项必须要选上,在属性-> 常规->高级->启用IO APIC 刚开始我没选这个属性,每次启动虚拟机,虚拟机都黑屏,选上就好了。 其次,在winxp上,也使用命令行,差别不大,不过有一点,因为ubuntu使用分区2,3,光使用这两个分区做虚拟机, 启动的时候总是停留在 MBR 1FA这个地方,查了半天也没查出个所以然来。后来想算了,干脆把全盘当做虚拟机的 硬盘好了,只要在winxp下面不要去直接访问分区2,3,应该就没事。命令行如下: vboxmanage internalcommands createrawvmdk -filename ubuntu.vmdk -rawdisk \\.\PhysicalDrive0 -register 然后就可以了。这样我就可以把双操作系统随时都一起启动起来,比较好玩。:D 2008-03-13
见: http://simile.mit.edu/timeline/ Timeline is a DHTML-based AJAXy widget for visualizing time-based events. It is like Google Maps for time-based information. Below is a live example that you can play with. Pan the timeline by dragging it horizontally. 按照它的文档,使用起来还是很简单的,自己只需要写一个 servlet 来产生 simile 所需要的那个 xml 文档就行。 当然,由于我的 weblog 很多(接近3000),一次返回,不仅会很慢,而且拉动起来对于浏览器的负载也不小,时不时 的就把我的ie给搞死了,firefox倒基本上没问题。 因此,重点就是如何“局部地”显示weblog。也就是说,只返回当前能看到的时间段当中的 weblog 集合。simile 的 wiki 上也有,不过语焉不详,我把用到的javascript 贴出来:
<script language="javascript">
var tl;
var oldMinDate;
var oldMaxDate;
function onLoad() {
var eventSource = new Timeline.DefaultEventSource();
var bandInfos = [
Timeline.createBandInfo({
eventSource: eventSource,
width: "80%",
intervalUnit: Timeline.DateTime.DAY,
intervalPixels: 100
}),
Timeline.createBandInfo({
eventSource: eventSource,
width: "20%",
intervalUnit: Timeline.DateTime.MONTH,
intervalPixels: 500,
showEventText: false
})
];
bandInfos[1].syncWith = 0;
bandInfos[1].highlight = true;
tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
tl.getBand(0).addOnScrollListener(function(band) {
var minDate = band.getMinDate();
var maxDate = band.getMaxDate();
if ( oldMinDate != minDate.toDateString() || oldMaxDate != maxDate.toDateString()) {
oldMinDate = minDate.toDateString();
oldMaxDate = maxDate.toDateString();
eventSource.clear();
Timeline.loadXML("/wipo/event.xml?minDate=" + minDate + "&maxDate="+ maxDate,
function(xml, url) { eventSource.loadXML(xml, url); });
}
});
Timeline.loadXML("/wipo/event.xml", function(xml, url) { eventSource.loadXML(xml, url); });
}
Timeline.DurationEventPainter.prototype._showBubble = function(x, y, evt) {
document.location.href=evt.getLink();
}
var resizeTimerID = null;
function onResize() {
if (resizeTimerID == null) {
resizeTimerID = window.setTimeout(function() {
resizeTimerID = null;
tl.layout();
}, 500);
}
}
</script>
这里有两个需要注意的,其一是 _showBubble 被我重载了,因为ie弹出那个bubble 实在是太慢了。 我干脆让它直接打开新链接。 其二是 不能用 date 直接进行比较,我发现 minDate == oldMinDate 总是等于false。后来发现用 string 来做比较就没事。 2008-03-11
做一个日期字符串的parser,按说是很简单的,但是偏偏出错:
SimpleDateFormat parser = new SimpleDateFormat( "EEE MMM dd HH:mm:ss zzzzzzz yyyy"); System.out.println( parser.parse( "Sat Feb 9 03:42:44 UTC 0800 2008"));这个报错: java.text.ParseException: Unparseable date: "Sat Feb 9 03:42:44 UTC 0800 2008"为了排除这个错,用排除法,把日期和月份换成数字之后就对了,然后才想起来,是 locale的问题。因为我的 系统是Locale.SIMPLIFIED_CHINESE,所以它只能解析 “星期六 二月 9 03:42:44 UTC 0800 2008” 这样的 字符串,而对于英文的 Sat Feb 就不认识了。解决的办法就是把locale设置为ENGLISH就可以了。 本来是去看 simile的那个 timeline 的: http://simile.mit.edu/timeline/ 结果看到了其他有意思的项目,其中比较有意思的就是 http tracker: http://simile.mit.edu/dist/httptracer/ 这个东西可以监视http的往来信息,说白了就是一个proxy,只不过替你把 request和 response 个拼起来了。对于web开发当中的一些调试,还是很有作用的。 2008-03-05
异常
PropertyAccessException: IllegalArgumentException occurred while calling setter
of Category children;
@Entity
public class Category implements DataTreeObject<Category> {
...
Set<Category> children = new HashSet<Category>();
...
@Override
@OneToMany(mappedBy="parent", cascade = {CascadeType.ALL})
public Collection<Category> getChildren() {
return children;
}
public void setChildren(Set<Category> children) {
this.children = children;
}
....
}
左看右看都没觉得hibernate的定义有问题。单步跟踪,发现hibernate试图往children里面 写一个Bag,这时候才发现,原来是 getChildren 这个方法,由于是从 DataTreeObject 接口 继承下来的,所以返回值不是 Set 而是一个 Collection。这么一点看起来不起眼的小错误,又 花了半个小时进行调试。郁闷。 2008-03-04
前面也提到过,wicket 有一个和 hibernate 进行绑定的东西叫做 binder: http://databinder.net/ 然后又发现一个支持将 bean 绑定到 wicket 的项目 http://wicketwebbeans.sourceforge.net/ 重要的是,发现 wicketwebbeans 支持 databinder。 也就是说,可以用 wicketwebbeans + databinder,实现一个 dynamic scaffold。只要给一个Class, 就可以实现自动的增加、删除、修改、查询。 参考了一下 wicketwebbeans 的例子,做了一个Scaffold。对于最简单的 Entity,还是很方便的, 效果也还凑合。不过对于稍微复杂一点,关联关系多一些的实体,就经常性的抛出一些异常,大概是对wicketwebbeans 的掌握还不够吧。 不过最可怕的还是一个 stackoverflow 的异常。而且,这个异常应该不是逻辑问题,而是 wicketwebbeans 对内存 管理的问题。如果只有10条记录,这个异常不会出现。如果到了20条,这个异常就开始往外抛了。由于不是很了解wicketwebbeans 在里面做了什么动作,现在这个问题还没有解决。 不过总的来说,用 wicketwebbeans 应该是可以做到一个不错的 scaffold的。只不过还不够完善,它的这个思路还是很不错的。 正在考虑是继续使用它还是另起炉灶自己做一个。毕竟 wicketwebbeans 看起来也不是很完善。 2008-02-29
http://www.coolcode.cn/archives/?article-238.html 找了大半天,终于找到一个比较不错的方案了。 所谓text overflow,其实就是文字超长时自动加 …的办法。 一开始没有想到 overflow 这个关键字,一直用 truncate 这个 关键字找,结果确实也找到了一些,包括 jquery 的几个 truncate 插件,都没有这个好使。可见搜索的时候,找对关键字很重要。 这个也不错: http://www.hedgerwow.com/360/dhtml/text_overflow/ 似乎使用起来更容易一些。 2008-02-25
loosejar: http://code.google.com/p/loosejar/ 这个功能挺有意思,关键是使用起来也简单:
loosejar can only be used on Java 1.5 or higher JVMs. The project is developed and maintained by Kyrill Alyoshin. 最近经常能看到 dvcs 这个名词,也就是分布式版本控制系统。说来最早还是 Skyin 告诉过我一种分布式的vcs: darcs,当时感觉很神奇。没有中央控制服务器,也可以进行版本控制。 基本的工作原理就是在每个开发者本地保留一个本地的vcs,然后在进行合并。而现在有不少 的分布式版本控制系统基本已经成熟了,其中比较强的几个是: Git,linux kernel在使用;Mercurial,mozilla 在使用;Bazaar,Ubuntu在使用。 对我个人而言,其实使用svn也还算满意,使用dvcs 的意愿不是很强烈。不过这里有篇文章, 有对这几个dvcs的比较: http://www.dribin.org/dave/blog/archives/2007/12/28/dvcs/ 值得注意的是,其中 git 有一个对svn的支持叫 git-svn。注意它不是一个转换工具,而是直接支持 本地为svn,而整体是git的这种情况。mercurial 则只支持一个对 svn 只读的功能支持。 2008-02-23
Mylyn 是eclipse 3.3当中自带的一个task list的东西,它有个很好很强大的特点 就是支持context。也就是说,你可以针对其中的某个task来进行开发,而mylyn会记录 这个task的context,也就是与之相关的一些文件。这样你就可以在多个task之间进行 切换,而不会每次都要重新去找几个你上次为了某个task而编辑过的文件。 google code 所提供的 Project host 也不错,提供免费的svn空间,也包括wiki和 文件下载以及issue tracking 之类的。而通过 mylyn 对 google code 的支持,就 可以在 eclipse 当中显示 google code 上的issue了。还是很方便的。具体实现方式 见: http://www.jroller.com/alexRuiz/entry/using_mylyn_with_google_code 不过遗憾的是,目前其实只是一个query而已。也就是说,只能从google code 上同步下来, 而不能在eclipse修改它的状态以及添加comment。实际上也可以,只是通过一个内嵌的浏览器 去做这个工作而已。不过也不错了,知足了,呵呵。 2008-02-22
Wicket 的 hot reload 其实很简单,只要在web.xml当中不放 WicketFilter,
而放 ReloadingWicketFilter,然后在static当中,将需要关注的package注册进去,如下代码所示:
static {
ReloadingClassLoader.excludePattern("org.apache.wicket.*");
ReloadingClassLoader.includePattern("org.apache.wicket.examples.*");
ReloadingClassLoader.includePattern("org.simcom.*");
Bundle[] bundles = Activator.getDefault().getBundle().getBundleContext().getBundles();
for (Bundle bundle : bundles) {
// 跳过 eclipse 本身的插件
if ( bundle.getSymbolicName().startsWith( "org.eclipse")) continue;
URL url = bundle.getEntry( "/bin/");
try {
if ( url != null)
ReloadingClassLoader.addLocation( FileLocator.toFileURL( url));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
因为我做的工作是要将插件当中的class也进行hot reload,因此还要遍历各个bundles,然后将这些 bundle的bin目录当做需要Hot reload的url entry。 |
.Copyright © 2006, SimonLei