ActionForm中动态长度的List
July 26th, 2008

某些情况下,一个表单中提交的内容数量是不一定的。比如Facebook的编辑照片界面,可以把整个相册的照片(最多60张)放在一起进行批量编辑,或者把一次上传的若干张照片一起编辑。这种情况下,如何用ActionForm来获取这些数据呢?

这个ActionForm(假设名为PhotoForm)应该有一个字段:

List<Photo> photos;

生成这个表单的时候很简单,服务器端当然清楚有多少张照片要被编辑,于是对这些照片遍历一遍,生成表单。实际上,struts form的设计考虑了链表数据的提交。以照片编辑页面为例,生成表单时,可以这样:

<logic:iterate id=”photo” name=”photos”>
<html:hidden name=”photo” property=”id” indexed=”true” />
<html:text name=”photo” property=”name” indexed=”true” />
</logic:iterate>

indexed属性便是专为链表设计的。这样的jsp代码生成的HTML类似:

<input type=”hidden” value=”5″ name=”photo[4].id”/>
<input type=”text” value=”编辑前的名字” name=”photo[4].name”/>

然而在用户将修改过的信息提交的时候,由于HTTP协议的stateless特性,服务器端已经“忘记”有多少张照片了(除非你在session中记录了这个数字,不过处于性能考虑大多数人在避免使用session,另外,假如用户在编辑信息的途中出去玩了几小时,回来继续提交的话,session已经不存在了)。

photos这个List即使放在对应的ActionForm中也无济于事,因为用户看到表单时,这个ActionForm对象已经消失了(当然,不要在那个mapping中设置scope=”session”)。

究其源,溯其本,很容易解决这种问题。请求提交给struts,struts首先根据mapping创建一个对应的ActionForm对象,当它看到表单中的属性名为photo[4].id,就会调用PhotoForm的getPhoto(4).setId(xxx)来填充表单。

注意,struts不是生成一个Photo对象,把id、name填充进去,再加到photos这个List中,它不知道要生成Photo对象。它只知道利用发射机制调用getPhoto(4).setId(xxx)。

所以我们应该在PhotoForm的getPhoto这个方法里做文章,根据参数将List扩展到适当的大小避免IndexOutOfBoundException,并且生成Photo对象保证不出现NullPointerException. 示例如下:

public Photo getPhoto(int index) {
	// 如果链表不存在则创建
	if (photos == null) {
		photos = new ArrayList<Photo>(index + 1);
	}

	// 如果链表长度不够,扩展
	if (photos.size() < index + 1) {
		for (int i = photos.size(); i < index + 1; i++) {
			photos.add(null);
		}
	}

	// 取得photo,如果为空则创建
	Photo photo = photos.get(index);
	if (photo == null) {
		photo = new Photo();
		photos.set(index, photo);
	}
	return photo;
}

这样就可以了,没有用到session. 看起来比较繁琐,其实道理很简单,明白了struts form的填充方式,就没什么困难了。

另一个例子是客户端可以用JavaScript生成一堆这样的file input:

<input type=”file” name=”file[0]” />
<input type=”file” name=”file[1]” />
<input type=”file” name=”file[2]” />
<input type=”file” name=”file[3]” />

struts怎么填充呢?它会首先读取文件数据,创建FormFile对象,然后调用对应的ActionForm的setFile(index, file)方法填充,index就是那个“数组下标”。所以你需要写一个setFile方法来正确处理。

用pinyin4j将汉字转化为拼音
July 25th, 2008

在合肥的时候,靠骗钱维生的电脑学校很多,而且确实骗到了许多钱,于是形成了良性循环,在电视上打广告,骗更多的钱。有个广告的末尾就是一憨厚的老大爷高兴地说:只有正规,才有机会啊!

某些情况下这句话很对。那些在网上被到处转贴的代码片段,我就不敢信赖,而且格式很乱也看不清楚。在找汉字转拼音程序的时候,我还是选择了pinyin4j,Source Forge上的项目,相对值得信赖。哦对了,这是Java的library.

一个简单的实例方法,使用pinyin4j转换字符串中的汉字为拼音:

public static String toPinyin(String input) {
	StringBuilder sb = new StringBuilder();
	for (int i = 0; i < input.length(); i++) {
		char c = input.charAt(i);
		if (c <= 255) {
			sb.append(c);
		} else {
			String pinyin = null;
			try {
				String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, PINYIN_FORMAT);
				pinyin = pinyinArray[0];
			} catch (BadHanyuPinyinOutputFormatCombination e) {
				logger.error(e.getMessage(), e);
			} catch (NullPointerException e) {
				// 如果是日文,可能抛出该异常
			}
			if (pinyin != null) {
				sb.append(pinyin);
			}
		}
	}
	return sb.toString();
}

其中用到的常量PINYIN_FORMAT是这样初始化的(输出时去除声调标记,发音“驴”的那个韵母用v表示):

PINYIN_FORMAT = new HanyuPinyinOutputFormat();
PINYIN_FORMAT.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
PINYIN_FORMAT.setVCharType(HanyuPinyinVCharType.WITH_V);

因为汉字有多音字,所以PinyinHelper.toHanyuPinyinStringArray返回一个数组。这个方法图省事,就直接选择了第一个读音。如果可能的话,可以将遇到这种多音字的地方提出来,人工进行处理。

为什么用Eclipse而不是NetBeans
July 23rd, 2008

在当下这个项目开始的时候,我们尝试使用NetBeans作为开发工具。也许是由于之前一直在用Eclipse,先入为主了,我总是发现NetBeans在一些地方似乎有先天的不足。于是在一周后,项目移到了Eclipse中进行开发,到现在依然在为没有太晚做这个决定而庆幸。

先从表面现象来比较。Eclipse的图形界面是SWT,而NetBeans作为Sun的产品,当然不好意思不用Swing了,于是给人第一印象就不好。某些系统上,dockable的窗口标题字体与标题栏高度明显不符,很不协调。输入中文时,候选窗也不能跟随光标移动——现在的Web开发一般都使用大屏幕显示器,你需要不时地看看屏幕的角落。别人可能会觉得奇怪——你有什么急事吧?要不然怎么不停地看时间呢?

在Eclipse中我习惯打开一个资源管理器窗口,从中复制一些文件,然后切换到Eclipse窗口直接粘贴到Package Explorer合适的目录。这一习惯在NetBeans里行不通,只能在IDE内部复制、粘贴。

然后透过现象看看本质。在NetBeans选中一个文件,按F2,你就发现,文件后缀是不能修改的!如果你想把一个.jspf改为.jsp,只能在资源管理器中做。看来NetBeans的理念就是傻瓜——比Windows还要傻瓜。

SVN集成。NetBeans默认集成了SVN,乍一听很让人兴奋。确实,当我看到单个文件中都有图形化的svn diff的时候,兴奋地跑到隔壁去找人倾诉。不过等到commit的时候我就开始沮丧了,完全没有subclipse方便、直观(subclipse 1.4不好,到现在我仍然在用1.2)。

最让人郁闷的是,J2EE项目中,在资源管理器里新加一个文件,在NetBeans刷新出来,部署时仍然会被忽略掉!仔细想想才明白,原来是要执行svn add才可以……合理乎?不合理乎?这svn集成,用一个词来形容就是“天衣无缝”。Web application部署都考虑到svn了,真是周到,佩服,佩服。

NetBeans的项目配置文件太过复杂,不适合作代码管理。nbproject下一堆文件,大部分是ant build file. 如果有library引用,肯定是绝对路径。在Eclipse里,即使有定制classpath,只要手动改成相对目录就一劳永逸了,svn co到任何地方都直接打开没有任何问题。NetBeans可不一般,改成相对目录可以,只要再新加入一个jar包,已改为相对目录的还会变成原来的绝对路径。

这不由得让人怀疑,NetBeans傻瓜吗?不,它很强大,很灵活,要不然配置文件怎么会一大坨。那这么复杂的配置文件,svn怎么管理啊?哦……svn集成很完美——web app部署都会考虑到代码管理。

x坐标一端是傻瓜,一端是灵活;y坐标一端是天衣无缝的svn集成,一端是复杂到天衣无缝的svn集成都无能为力的配置文件。天才的NetBeans在这个二维空间里找到了那个独一无二的完美的点,就像宇宙中只有一个地球一样。我错了,我是火星人。

Refactoring. Refactor - Encapsulate field,没有全选、取消全选的按钮。同时已有getter/setter的方法没有体现出来,但是你硬要选上的话,它又会抛出exception.

Refactor - Rename,没有同时重命名getter/setter的选项。

从某种程度上说,NetBeans很像MS的产品——大部分用户做傻瓜,小部分人是精英,为傻瓜们解决不应该是问题的问题。我做不了精英,却不想做傻瓜,于是还有一条路——我逃了。

嘿嘿,有许多人推崇NetBeans。确实,NetBeans某些方面比Eclipse做得好,比如上面提到的文件内svn diff,还有对于web开发很重要的——更好的JavaScript编辑器、HTML编辑器。还有其它的我还没来得及发现就放弃了。本文也就是发发牢骚,顺带给想比较这二者的同仁们抛砖引玉。

Eclipse 3.4 web开发方面的改进
July 19th, 2008

说到Eclipse 3.4,大部分人只会注意eclipse核心功能的改进和新特性比如Breadcrumb。

不久前发现Eclipse 3.4对于Web developer来说也有不少值得注意的改进,具体链接在这里

Web开发这一块功能属于Web tools platform. 我最关心的是这一段:

A new JavaScript IDE, called JSDT, provides the same level of support for JavaScript as the JDT provides for Java. Some of the new features include code completion, quick fix, formatting and validation. All the functions are, naturally, aware of libraries you specify for your project.

自带的JavaScript编辑器终于可以凑合用了。

另外,编辑XML/HTML/JSP页面时,编辑器会自动高亮匹配的标签,这一点太重要了,让我们不至于在复杂的标签中迷失。

不过,JSP的格式化依旧很烂,另外,回车时竟然不能保持缩进了!真是有得有失。

轻轻松松用代理 - IE自动代理(auto-proxy)
July 19th, 2008

相关文章:

虽然IE很难用——打倒IE!打到IE!——有时候还是得用它,比如国内的网上银行,还有某些垃圾网站。作为一个Web开发者,每天还得在IE下作修修补补的工作。就好像厕所虽然很臭,你也得每天进去一样——生活所迫啊。

Firefox有FoxyProxy可以灵活地配置代理切换,作为史上最臭名昭著的浏览器的IE怎么办呢?其实呢,IE也不是那么垃圾,写一个JavaScript(微软叫JScript)脚本就可以凑合着用了。

新建一个文件auto.pac,内容如下:

proxyDomains = [
'blogspot.com',
'facebook.com'
]
function isProxyDomain(host) {
	for (ii = 0; ii < proxyDomains.length; ii++) {
		if (dnsDomainIs(host, proxyDomains[ii])) {
			return true;
		}
	}
	return false;
}

function FindProxyForURL(url, host) {
	if (isProxyDomain(host)) {
		return 'PROXY localhost:8079';
	} else {
		return 'DIRECT';
	}
}

粗体的地方是代理地址,把它放在比如D盘根目录,然后在Internet 选项-链接-局域网设置那里如下配置:

重启IE后,就可以了。IE调用FindProxyForURL函数,我们判断一下被访问的域名是不是“特殊”的,如果是的话,就告诉IE通过代理访问,否则直接连接。

proxyDomains数组是需要通过代理访问的域名,可以自由添加。

可参考自动代理配置的官方文档

轻轻松松用代理 - FoxyProxy
July 19th, 2008

相关文章:

即使代理速度很快,一般情况下也不会快过直接连接。所以为了访问一两个特殊的网站(比如blockspot)而总是用代理连接有点不划算。最佳的方案是对一般的网站直接连接,而对于特殊的网站使用代理,不过频繁打开浏览器选项对话框进行配置也不办法。

我日常上网用的浏览器是Firefox。(打到IE!打到IE!)Firefox的代理扩展有许多,我习惯用FoxyProxy,功能强大,灵活自由。

安装后第一次启动Firefox,FoxyProxy会问你要不要配置Tor,如果你想使用Tor那就让它为你配置吧,不过如果像我一样使用的是Your Freedom等其它代理工具(还有一个叫JAP的代理我也用过一段时间,原理类似)就不要配置了。

接下来就是配置FoxyProxy的代理了。简单地说,FoxyProxy就是存储一组代理服务器,每次发起一个请求,它都会根据该链接的格式来寻找一个匹配的代理,这个匹配过程如何进行,就看你怎么配置了。

因为FoxyProxy的网站上有比较详细的文档,我就偷懒一下,就不在这里为互联网做太多贡献了。请看”configuring foxyproxy“和”pattern guide“两个页面。

一般情况下代理列表中只需要两项,一项是默认的直连,另一项自己建立一个代理。唯一需要注意的是这个代理的host name要写localhost,端口是Your Freedom配置的Web端口。

为这个代理添加必要的pattern后,就可以随意上网了。FoxyProxy为你实现透明的代理切换,配置好后就无需关心。

10号线开通,三里屯apple store开业
July 19th, 2008

经过不知道多少次的推迟之后,地铁10号线终于“抢”在单双号施行前开通了。我就住10号线站台不远,今天和弟弟闲着没事,就想去看看。到哪里去呢?正巧大陆第一家apple store开业,位置正好在10号线边上,这是最佳的目的地!

大约是周末的原因,进入地铁站发现乘客很少,空调又开得很大,让人感觉异常的冷,而里面的警察、保安数目却是异常的多。

相对1号线、2号线,10号线运行起来相当平稳。不过由于刚开始运行,难免出些小差错。上车后连续两站都是在进站前就停下,因为我坐第一节车厢,透过玻璃看见前面一辆车还停在站台上没走。第二次遇到这种情况后,列车故意延迟了一会出站。车头仪表盘:

还有一点非常让人郁闷的是不光隧道内部,刚进地铁站,手机就一点信号都没有了。这一点比较致命,相信以后会改的,到时候应该会覆盖所有区域。

————-一定要有个分割线————-

在团结湖站下车,出站后顺工体北路向西,没多远就到了Adidas的商店,从旁边进去,就看见传说中的apple store了。

商店旁边还专门有一个做活动用的大厅,似乎比商店本身还大:

从门口进去,店员给每个人戴一个手环,上面是排队号码:

昨天就在网上看到有人在排队了,真是够辛苦。好在地铁10号线是下午两点以后才开通,这时排队的人相对来说已经比较少了,我们等了十几二十分钟,就进入了商店。主要是玩了玩iPod touch,看了看Macbook Air. 店里没有iPhone,不过iPod touch上面的firmwire已经是2.0版本了,主界面上有app store. 在safari中输入网址的时候,按住.com键不放,就会出来.edu, .org, .net这些选择,这个改进很不错。Air是第一次见,除了薄之外,实在是没什么吸引力。

apple store开到中国来,还是很让人兴奋的。可是,关税啊关税……是让人从美国带回来(或者买水货)免掉高额的关税,还是在这里多花几千大洋得到优质的售后服务呢?许多用户估计都得做这个选择。也许光靠这个商店的销售是收不回高额的成本(雇员薪水、地租、明星出场费)的,不过这个商店可以让更多的人了解苹果的产品,对于扩大中国的市场,还是很有作用的。但是销售额如何也不能过早下定论,中国人平均购买力是低了点,苹果的产品是贵了点(尤其是过了中国海关),不过十几亿的人口摆在那里,富人还是很多的。

轻轻松松用代理 - Your Freedom
July 12th, 2008

由于网络环境不太好,时不时都得用一下代理,要不然日子没法过。比如有一次查一个Flash AS 3的问题,Google第一条结果我懒得看,因为它在blockspot上,得用代理。结果过了几天之后发现,blockspot上这一条才是正解。这严重地坚定了我寻找一个好的代理的决心。

代理,有的人用套,有的人用梯子,还有的人SSH到国外的虚拟主机。我有虚拟主机也可以SSH,不过主机商说这是滥用资源,要罚50刀。50刀啊,肯定得砍死我,还是算了。

写这篇文章,主要是发现好多同志还生活在水深火热之中,连代理怎么用都不知道。难道还有人找个普通的代理服务器,然后再浏览器选项中设置?这种同志需要严厉地批评,都社会主义了,怎么还是封建社会的脑筋呢?

今天就推荐一下我用了很久的Your Freedom。首先需要到它网站去注册一个用户名,然后下载客户端。如果用的是Windows系统,就下载那个windows installer,用这个可以最小化到托盘,省得占地方。

安装好以后,启动Your Freedom客户端。在主界面上中部最左边点击Configure按钮,然后在弹出的对话框里选择Use Wizard。Wizard里有一步的大标题是”Proxy Server”,这个要跳过,直接next。一直next到出来一个服务器列表的地方,选择一个pref高的服务器(最高分10.0)。这之前查询列表的过程可能有点慢(1分钟以内),需要耐心等待。下一步里,你可能需要输入用户名、密码来验证。

选择好服务器后,按下Start connection键,代理服务器就可以用了。实际上默认情况下它是在你自己机器的8080端口开了一个代理。在浏览器里设置代理为localhost:8080就可以使用它了。浏览网页时查看Your Freedom主界面,Downlink图里面有流量,说明代理在正常工作。Your Freedom主界面截图:

如何设定语言?

在选择服务器时,如果选择的是非英语语言的国家,Your Freedom会在下次重启的时候自动设置成该语言!乖,不哭不哭。

在没有连接的情况下,可以点击主界面上的Configure按钮,弹出选项对话框,选择Account Information选项卡,那里有语言选项,如图:

你还可以在其中发掘其它的配置项。

如何选择端口?

对于web开发者来说,8080端口可能是比较重要的,比如Tomcat的默认端口就是8080.

在Your Freedom主界面上,有一个选项卡是”ports”,在里面可以选择HTTP端口。有的时候显示不可改状态,只要把前面的勾选取消一下就可以了:

这个代理的速度,我还是比较满意的。当然你不能在服务器列表里面挑pref低的选 :)

下一篇文章,我可能会写怎么在Firefox里舒舒服服地有选择地使用代理,我用的是FoxyProxy.

另外一篇文章,怎么为IE配置自动代理