15年后,第一次看《泰坦尼克号》

April 17th, 2012

titanic
泰坦尼克沉船100年的日子,我到电影院看了《泰坦尼克》,这是我第一次看她。

15年前她风靡全球,那时我读初一。每天晚上回家路过一家音像店,回回都能赶上“my heart will go on”,连续几个月都是如此。开始以为是缘分,后来才知道是单曲循环。正值叛逆的年纪,你们觉得热门的东西,我就偏不去看。

一晃15年过去,杰克在我的印象中已经是《盗梦空间》那张发福老态的国字脸,露丝是《朗读者》里边风韵渐远的中年妇。我自己呢,也成了别人眼中的胖子。《泰坦尼克》重映的消息传来,不知不觉就想起了杰克和露丝在船头摆的经典飞翔动作。由这个动作,我又想起了自己的中学和大学。就算没有看过她,她已成为一个符号,融进你我的青春里。3D不是走进影院的缘由,寻找青春才是心照不宣。

伟大的电影,经得起时间考验。在见识世间百态后,我还是为杰克和露丝的爱情感动;在看过众多噱头大片后,我还是为泰坦尼克的特效震撼;在笑点日渐麻痹的情况下,我还是为其中的桥段包袱开怀一笑。最让我动容的是杰克在晚宴上的自白:“因为我需要的我全都有了。一个健康的身体,还有几张画纸,哈!我喜欢这种生活,每天早上起来,想做什么事情就做什么事情,想去哪儿就去哪儿,想到哪里就到哪里。昨天夜里,我还在大桥下面。今天就来到巨轮豪华的餐厅,跟诸位在一起就餐。好,再来一杯,人生短暂,我不想虚度年华。未来的命运要顺其自然,有了机遇就要抓住。”平庸的生活、乏味的工作,让我觉得窒闷,却无法超脱,想也不敢想,做也不敢做,只有羡慕他人的豪情洒脱。

杰克和露丝落水后,杰克不断地给露丝打气,解闷。妻子问我,要是有一天也遇到这样的情景,我会不会像杰克那样鼓励她。我脱口而出肯定不会,我这么爱吐槽的人,一定会骂天骂地。是呀,我这个人,又胆小又爱抱怨。绝对不敢像杰克那样鼓起勇气勾搭富家女,也就是说无法把握生活中的机会。遇到麻烦事,本能地先吐槽抱怨,口舌之快后才开始想解决办法,也就是说不够沉稳冷静,宽容大度。一瞬间我仿佛也掉进了冰洋里,浑身刺骨,性格决定命运,我就是被锁在三等舱的屌丝。

爱情之所以感人,似乎总要伴随着某一方的牺牲。如果没有泰坦尼克的沉没,杰克和露丝上岸后,可能只是千千万万生活窘迫小夫妻中的一对,这样的爱情还令人羡慕称颂吗?沉船那段时间,我握着妻子的手就在想,我不要什么轰轰烈烈可歌可泣的爱情,在这荒唐的年代,有个互相理解互相鼓励的人儿,为了更有质量更加理想的生活而一起努力,就可以了。

写到这里不免有些遗憾,如果15年前走进影院,是不是会写下纯真爽朗一些的观后感?

[转载]如何在公众面前表现出自信心

February 7th, 2012

从惠普“HP 技术助力 工作随心”订阅邮件中看来,很不错。应该是从国外博客翻译过来的。

http://h30458.www3.hp.com/cn/zh/smb/1126904.html?jumpid=em_taw_CN_dec11_across-xbu_1512840_hpgl_zhs_1070928_0&DIMID=1170073580&DICID=null&mrm=1-4BVUP

是否发现自己在其他人面前讲话时感到过分紧张? 是否担心您犯下愚蠢错误而给人留下负面印象?

害怕公开演讲是很正常的,许多人都必须努力克服这种恐惧。 实际上,如果您感到紧张和不自信,这才是您将传达给您的观众的印象。 您的想法可能很了不起,您的演讲也无懈可击,但是如果您缺乏自信,您就会显得对自己的观点不太确定。

有些人的自信与生俱来。 其他人则必须“学会自信”,就像学习任何其他技能一样。 幸运的是,我们可以为您提供一些技巧,以便帮助您保持镇定并带来自信的感觉。

1. 确保您准备充分

充分准备演示之前的演讲内容,然后在家反复练习。 如果您的材料准备得很充分,而且您对具体细节了如指掌,那就确实没什么好担心的了。

2. 积极思考

在您进入会议之前,告诉自己:

  • 您要讲一些有趣的事情,而且这些事情也是其他人希望听到的
  • 他们不会在这里进行评判或批评,他们只是想倾听您的发言内容
  • 您不一定要做到完美,只要做到足够好就行
  • 他们是跟您一样的人,有着同样的忧虑和恐惧,而且他们希望您成功,不要失败
  • 使您感到紧张的肾上腺素还会使您表现得很出色

3. 呼吸和放松

这可能是最重要的规则。 呼吸是保持镇静的关键,镇静是出色的当众演讲的关键。 因此,在您勇敢地站出来演讲之前:

  • 让自己舒适地坐在椅子上
  • 挺直身子坐着,但不可僵硬,让后背接触椅背
  • 不要交叉双腿; 放松肩膀
  • 闭上双眼
  • 尽量放松肌肉,尤其是手臂和面部肌肉
  • 用鼻子慢慢地吸气,大约两秒钟
  • 然后用嘴或(如果用嘴声音太大)用鼻子将气呼出,呼气时稍快一点
  • 一、二 – 吸气,一、二 – 呼气

如果您认为您不能在会议中闭上双眼,万一大家认为您要睡着了怎么办,那么就向下看您的笔记。 关键是您不应该看其他任何人。 这是您自己收拢想法的时刻。

4. 不要害怕

尽量让自己保持镇静。 您不是要做可怕的事情,只是跟一些人谈一下您知道的一些事情。

  • 举止轻松
  • 不要交叉双臂,那样看起来很不友好
  • 缓慢而有规律呼吸
  • 想象自己讲话时的声音很大、很清晰
  • 想象自己成功 – 您就会成功

5. 自信地思考

现在该你了。 环顾您的观众。 或许您已经认识其中的某些人或认识所有人。 请记住: 他们是和您一样的人; 他们想倾听您的发言内容。 他们希望您有良好的表现。 因此,当您开始讲话时,请记住以下规则:

  • 不要提到自己感到紧张
  • 如果您不提,没有人会注意到
  • 专注于您的演讲内容,而不是您的演讲方式
  • 演讲时的语速要比正常语速慢一些
  • 张开嘴巴,大声清晰地演讲
  • 看看您的观众,做个眼神交流

如果您的讲话声太小或太快,会给人以紧张的印象,使您看上去对演讲内容不太确定。 为了表现出自信心,您必须“自信地思考”! 只有这样,您才能让其他人感受到您的自信心。 大声、缓慢而又清晰地讲话并给予眼神交流,自然会给人留下更好、更自信的印象。

世界上的一些最有名的公众演讲者都会(或曾经会)紧张。 这是完全正常的。 但是,如果您尝试按我们的规则去做,当您下次给大家做演讲时,您一定会发现更加容易了。 请记住: 保持冷静、保持镇静并控制自己。

2012新年愿望

February 7th, 2012

除夕夜过年时,在老家的床上想了想自己的2011年,写下了下面的话。

新的一年重在修身,习惯决定性格,这毋庸置疑。碌碌无为的2011年,让我看到自身品行上诸多不足,如果没有一一纠正,养成健康向上的习惯,那末我会变成一个乏味的“三明治”。

勤奋,勇敢,坚强,宽容,就是我在2012的小小心愿。思来想去,这四样品质,是我最迫切需要的。我不太聪明,唯有勤奋一些,多尝试几次。我不太敢做决定,容易错失机会,希望有魄力些勇敢些。我容易动摇,有事先考虑不充分,也有害怕负责的心态在其中,不如意事常八九,没有一颗坚强的心就走不远。我易怒易冲动,伤已又伤人,心怀宽容推己及人,方能怜惜身边人。

暂且定下几个前言不搭后语的目标,排名有分先后,年末再看。

  • 疼老婆。
  • 继续执行番茄时间,珍惜每一天,高效做事。
  • 有一个自己的小窝。
  • 更多阅读,更多思考。
  • 定期联系朋友,邮件短信电话明信片都可以。
  • 经手的项目,所涉及的领域,用心钻研,产出深入浅出的文档。
  • 系统学习摄影,熟练使用相机。
  • 练手某一理财工具。
  • 体重从78KG降到72KG,BMI落在正常范围18.5–24.9。
  • 学跳一种舞,学唱一首歌。
  • 拿到驾照。
  • 做一款android应用,做一款微博应用。

2012年,一起加油!

XMind零基础教程

December 18th, 2011

最近热衷于画框图,所谓纸短话长笨嘴拙舌,反倒不如一图胜千言。譬如以前,设计模式学了忘,忘了再学。但用Dia徒手画出UML图后,这回是真的记住了。看代码也是,先前习惯在一张纸上涂写类图,不能电子化的东西,面临遗失的尴尬,且修改起来颇为费力。于是想起来以前瞅过几眼的XMind。有人也似乎这么用它呢。

工欲善其事,必先利其器。花了一颗番茄时间寻找一些零基础入门资料。

首先对XMind有个基本的了解,可以参考明圣国小全瑞华老师的ppt。
以及台湾大学张文瀞老师的“XMind/FreeMind-心智圖的妙用

接下来可以看安南国中李蕙珍老师录制的“XMind心智图软体录影教学”(Windows下无需安装播放器)。
一共16支视频,每支大约1-2分钟,覆盖了XMind基础用法,快速上手通俗易懂。
看完视频后,记住这几个快捷键,可以提高画图效率。
平行主题:enter
子主题:tab
外框:ctrl+B
摘要:ctrl+]
全部收缩:/ (修改-全部收缩)
全部展开:*(修改-全部展开)
下钻:F6(视图-下钻)
上钻:Shift+F6(视图-上钻)
标签:F3
备注:F4

最后呢,就是在XMind官网上多看看他人的范例。
这里打包了几个简单和复杂的例子,可供观摩。

 

吐槽:
台湾教师在使用开源软件上持有更积极的态度,间接体现两岸教育水平差距。

more:
心智图导学使用手册

http://actsmind.com/blog/downloads/mind-map-tutor-handbook_tw.pdf

Filter之步步惊心

November 29th, 2011

好吧,标题很三俗。为了对得起踩关键字进来的同学,贴图一张!

另有传送门一扇。点我啊

 

Filter在MVC开发中十分普遍。想要做登录验证?想要做统一的编码转换?想要做日志审计?统统可以,只需依葫芦画瓢,实现Filter接口。

public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) ;
public void destroy();
}

init和destroy一般是摆设,doFilter里面才是我们关心的勾当。看各路code snippets总是这样的写法。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
// handle request or response, or something else
...
// invoke filterChain at last
filterChain.doFilter(request, response);
}

对于这种编程模型,总是有些疑问:
问题一:web.xml中定义的Filter,它是按照什么样的顺序来执行?
问题二:为什么每个Filter,总是在最后写上filterChain.doFilter,这样就神奇地交给了下一个Filter?

[先看问题一]
不看tomcat或者jetty等容器源码的情况下,准备通过实验获得答案。
Java EE项目的创建、打包、部署是个烦人的活,这里借助maven来省时省力。
实验的环境是maven-2.2.1和tomcat-6.0.29。

1.创建webapp项目

mvn archetype:create -DartifactId=design-pattern -DgroupId=info.iloveolive -DarchetypeArtifactId=maven-archetype-webapp

这会得到一个最简单的webapp工程结构,但还缺少servlet规范相关的jar包。
在总pom.xml中加上

<![CDATA[
<dependency>
	<groupId>org.apache.geronimo.specs</groupId>
	<artifactId>geronimo-servlet_2.5_spec</artifactId>
	<version>1.2</version>
	<scope>provided</scope>
</dependency>
]]>

Geronimo是对servlet规范的apache实现。
作为一个完美主义者,加上了<scope>provided</scope>,表示不将Geronimo打包进最后的war包。因为运行war包的容器tomcat肯定含有servlet jar包。
运行mvn eclipse:eclipse,导入eclipse。
2.实现两个简单的Filter,主要是在filterChain.doFilter()前后打上调用日志。

package info.iloveolive.filter;
 
import java.io.IOException;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
 
/**
*
* @author atom
* @version $Id: FirstFilter.java, v 0.1 2011-11-23 下午7:49:24 atom Exp $
*/
public class FilterOne implements Filter {
 
/**
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
}
 
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException,
ServletException {
System.out.println("before invoke FilterOne's doFilter()");
arg2.doFilter(arg0, arg1);
System.out.println("after invoke FilterOne's doFilter()");
}
 
/**
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
}
 
}

FilterTwo类似,略。

3.写一个简单的jsp,仅仅为了接收请求,流通Filter。

<![CDATA[
<html>
	<head><title>Filter Trace</title></head>
	<body>
		<h2>Filters are working ...</h2>
		<p>now cat $CATALINA_HOME/logs/catalina.out to find how filters invoked</p>
	</body>
</html>
]]>

4.web.xml配置。

<![CDATA[
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
 
<web-app>
  <display-name>Archetype Created Web Application</display-name>
 
  <filter>
  	<filter-name>filterOne</filter-name>
  	<filter-class>info.iloveolive.filter.FilterOne</filter-class>
  </filter>
  <filter>
  	<filter-name>filterTwo</filter-name>
  	<filter-class>info.iloveolive.filter.FilterTwo</filter-class>
  </filter>
 
  <filter-mapping>
  	<filter-name>filterTwo</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter-mapping>
  	<filter-name>filterOne</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
 
  <servlet>
  	<servlet-name>filterTraceServlet</servlet-name>
  	<jsp-file>/trace.jsp</jsp-file>
  </servlet>
  <servlet-mapping>
  	<servlet-name>filterTraceServlet</servlet-name>
  	<url-pattern>/trace</url-pattern>
  </servlet-mapping>
 
</web-app>
]]>

在filter-mapping中,故意先写上filterTwo,再写filterOne。

5.打成war包,部署到tomcat
这里展示当代3种青年的做法。
普通青年:普通青年
运行mvn war:war,在simple-web/target目录下得到simple-web.war,将它复制到tomcat/webapps目录下人肉部署。

文艺青年:文艺青年
优雅地在pom.xml中添加上tomcat-maven-plugin插件

<![CDATA[
<properties>
	<finalName>simple-web</finalName>
</properties>
<build>
	<finalName>${finalName}</finalName>
	<plugins>
		<plugin>  
			<groupId>org.codehaus.mojo</groupId>  
			<artifactId>tomcat-maven-plugin</artifactId>  
		</plugin>
	</plugins>
</build>
]]>

运行mvn tomcat:run,完成打包、部署、启动tomcat。

二逼青年:2b青年
同样在pom.xml中添加上tomcat-maven-plugin插件

<![CDATA[
<properties>
	<finalName>simple-web</finalName>
</properties>
<build>
	<finalName>${finalName}</finalName>
	<plugins>
		<plugin>  
			<groupId>org.codehaus.mojo</groupId>  
			<artifactId>tomcat-maven-plugin</artifactId>
			<configuration>  
				<url>http://localhost:8080/manager</url>  
				<username>atom</username>  
				<password>power</password>  
				<path>/${finalName}</path>  
			</configuration>
		</plugin>
	</plugins>
</build>
]]>

额外多出来的配置部分configuration,让maven能够远程操纵tomcat。atom是具有manager角色的一个用户实例。
在tomcat/conf/tomcat-users.xml中,要有如下配置。

<![CDATA[
<tomcat-users>
	<role rolename="manager"/>
	<user username="atom" password="power" roles="manager"/>
</tomcat-users>
]]>

启动tomcat后(一定要先启动),二逼青年通过运行mvn tomcat:redeploy完成部署。

6.浏览器输入http://localhost:8080/simple-web/trace,看日志结果 trace-jsp filter-sequence

可见,<filter-mapping>的顺序,决定filter调用顺序。

再看问题二

Filter实际上是职责链设计模式(Chain of Responsibility)的修改版。

原始的职责链中,包含两个重要的元素,请求(Request)和处理器(Handler)。

当客户端提交一个请求时,请求沿着链传递。处理器面对一个请求,有两种选择:

  • 如果是它能够处理的类型,则进行处理,处理完毕后终止该链路传递,该请求的生命周期结束;
  • 如果不是它能够处理的类型,处理器“推卸责任”,把它丢给下一个处理器,请求会继续在链上传递。

同样创建一个标准的maven结构工程,来进行实验。

1.首先定义“请求”的接口,只简单定义了一个方法。

package info.iloveolive.cor.request;
 
/**
* 职责链的请求
* @author atom
* @version $Id: Request.java, v 0.1 Nov 27, 2011 9:18:09 PM atom Exp $
*/
public interface Request {
/**
* 返回请求类型
* @return
*/
String getRequestType();
}

实现一个具体的请求类型:“格式化”请求。

package info.iloveolive.cor.request;
 
/**
* "格式化"请求
* @author atom
* @version $Id: FormatRequest.java, v 0.1 Nov 27, 2011 9:27:25 PM atom Exp $
*/
public class FormatRequest implements Request {
 
/**
* @return
* @see info.iloveolive.cor.request.Request#getRequestType()
*/
@Override
public String getRequestType() {
return "request of format";
}
 
}

同理,实现另外两个请求,PrintRequest和SaveRequest。

2.定义处理器接口。

package info.iloveolive.cor.handler;
 
import info.iloveolive.cor.request.Request;
 
/**
* 职责链的处理器
* @author atom
* @version $Id: Handler.java, v 0.1 Nov 27, 2011 9:28:34 PM atom Exp $
*/
public interface Handler {
 
/**
* 处理一个请求,简单起见,不设置返回值
* @param request
*/
void handle(Request request);
}

实现“格式化”处理器

package info.iloveolive.cor.handler;
 
import info.iloveolive.cor.request.FormatRequest;
import info.iloveolive.cor.request.Request;
 
/**
*
* @author atom
* @version $Id: FormatHandler.java, v 0.1 Nov 27, 2011 9:30:34 PM atom Exp $
*/
public class FormatHandler implements Handler {
 
Handler succeesor;
 
public FormatHandler(Handler succeesor) {
super();
this.succeesor = succeesor;
}
 
/**
* @param request
* @see info.iloveolive.cor.handler.Handler#handle(info.iloveolive.cor.request.Request)
*/
@Override
public void handle(Request request) {
if(request instanceof FormatRequest) { // 是否是格式化请求
System.out.println(this.getClass().getSimpleName() + " handle " + request.getRequestType());
} else {
if(succeesor != null) { // 转交给后续者处理
System.out.println("can not handle, drop it to succeesor");
succeesor.handle(request);
}
}
}
 
}

FormatHandler中有个succeesor字段,指向下一个处理器。
指定的过程,出于简单起见,放在构造函数里面,比较2b。但这不影响职责链设计模式的理解。

同理实现另外两个处理器,PrintHandler和SaveHandler。

3.前期准备完成后,客户端终于登场。
装配顺序是任意的。

package info.iloveolive.cor.client;
 
import info.iloveolive.cor.handler.FormatHandler;
import info.iloveolive.cor.handler.Handler;
import info.iloveolive.cor.handler.PrintHandler;
import info.iloveolive.cor.handler.SaveHandler;
import info.iloveolive.cor.request.FormatRequest;
import info.iloveolive.cor.request.PrintRequest;
import info.iloveolive.cor.request.SaveRequest;
 
/**
*
* @author atom
* @version $Id: ClientMain.java, v 0.1 Nov 27, 2011 9:41:59 PM atom Exp $
*/
public class ClientMain {
 
public static void main(String[] args) {
/**
* 初始化三个处理器
* 通过初始化函数,装配了一个处理链路
* 格式化 -&gt; 保存 -&gt; 打印
*/
Handler handler3 = new PrintHandler(null);
Handler handler2 = new SaveHandler(handler3);
Handler handler1 = new FormatHandler(handler2);
 
// 职责链处理第1个请求
System.out.println("[ 1st request start ]");
handler1.handle(new SaveRequest());
System.out.println("[ 1st request end ]");
 
// 职责链处理第2个请求
System.out.println("[ 2nd request start ]");
handler1.handle(new FormatRequest());
System.out.println("[ 2nd request end ]");
 
// 职责链处理第3个请求
System.out.println("[ 3rd request start ]");
handler1.handle(new PrintRequest());
System.out.println("[ 3rd request end ]");
}
 
}

来看看最终运行的结果。

[ 1st request start ]
can not handle, drop it to succeesor
SaveHandler handle request of save
[ 1st request end ]
[ 2nd request start ]
FormatHandler handle request of format
[ 2nd request end ]
[ 3rd request start ]
can not handle, drop it to succeesor
can not handle, drop it to succeesor
PrintHandler handle request of print
[ 3rd request end ]

可见,职责链设计模式就是链式处理,推卸责任。它体现了单一职责原则,每个处理器只负责关心的请求处理。同时也体现了开放-封闭原则,想要增加对新请求的处理,只需要增加新的处理器即可。
客户端和处理链都没有对方的明确信息,链中的对象也不知道链的结构。职责链简化了对象的相互衔接,它们之间的耦合只在于保持一个指向后继者的引用。通过设置后继者,处理器能处理就处理,不行就往后推卸责任。

至此,你心生疑惑,纯粹的职责链模式,和web下的Filter开发有些不同。
是的,纯粹的职责链模式中,链是抽象存在的,并没有一个专门的对象结构来表示链。
以tomcat为例,改进的职责链中,它切断了前后处理器间的引用耦合,引入处理器持有者,来统一管理处理器。这个持有者,就是链。

一个web请求,发送到tomcat,和Filter处理有关的邂逅,是这样开始的:

// Get the FilterChain Here
ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain = factory.createFilterChain(request,wrapper,servlet);
// 开始职责链生命周期的处理
filterChain.doFilter(request, response);

ApplicationFilterChain中和职责链紧密相关的3个字段。

final class ApplicationFilterChain implements FilterChain, CometFilterChain {
/**
* Filters.
*/
private ApplicationFilterConfig[] filters =  new ApplicationFilterConfig[0];
 
/**
* The int which is used to maintain the current position
* in the filter chain.
*/
private int pos = 0;/**
* The int which gives the current number of filters in the chain.
*/
private int n = 0;
}

ApplicationFilterConfig数组含有FilterConfig,通过FilterConfig很容易得到Filter,所以它是处理器持有者。
n表示数组中长度,即含有多少个处理器。
pos表示当前处于“激活”状态的处理器序号。

每次执行filterChain.doFilter(request, response)方法时,ApplicationFilterChain会这样做。

// Call the next filter if there is one
if (pos &lt; n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = null;
try {
filter = filterConfig.getFilter();
...
filter.doFilter(request, response, this);
} catch (IOException e) {
}
}

它记录下当前链中的处理器位置,依次取出作为激活处理器。处理器执行filter.doFilter方法时,巧妙地把ApplicationFilterChain的指针传了进去(this部分)。这样,在Filter实现代码中,一旦自身有关的处理部分完工后,就可以通过filterChain.doFilter,把调度权再转交回ApplicationFilterChain,它根据pos标记,轻松选出下一个处理器,继续处理请求。

这种改进模式比较适合框架开发,链路的装配交给框架,客户端无需操心,只管定义处理器,而且每个处理器都有机会沾手请求。
体现在编程界面上,框架释出jar包,客户端配置好xml让框架读取。
在侧面上也可以看出,它的执行效率比较低,毕竟伴随大量的出栈入栈操作,所以才说,不要随意添加Filter。

参考链接
1.CoR 模式 (一种)

http://www.iteye.com/topic/411182

2.Design Pattern: Chain of Responsibility 模式

http://caterpillar.onlyfun.net/Gossip/DesignPattern/ChainofResponsibility.htm

3.filter的执行顺序

http://hi.baidu.com/good_pb/blog/item/e958e20f89b0b5236059f30c.html

4.代码下载

为IBM Developerworks代码片段添加高亮效果

November 2nd, 2011

我喜欢IBM developerworks上的文章,但是上面的代码片段只有对齐(indent),而没有高亮(highlight)。
缺乏色彩的代码让人心神不宁,甚至复制粘贴到文本编辑器求得视觉上的安慰。
这是web2.0的时代,攻城师们拿起我们的刀叉,将网页烹饪成自己中意的口味吧。

 

首先,寻找一个轻量级的高亮代码插件。
我找到了google-code-prettify
它小巧,使用也很简单起来,只需三板斧

  • ·引入js和css(prettify.js和prettify.css)
  • ·将需要高亮的代码文本用<pre></pre>标签包括起来
  • ·文档加载的时候调用prettyPrint()

接下来,观察IBM developerworks 网页源码,寻找插入点
不费什么劲就找到了。developerworks上的代码片段都用<pre>标签包裹。

查看css,只是简单地设置了边框。

最后祭出我们心爱的Grease Monkey,代码如下:

// ==UserScript==
// @name            highlighting IBM developerworks
// @author            Atom Chen
// @namespace        http://www.iloveolive.info
// @include             http://www.ibm.com/developerworks/*
// @description        syntax highlighting of source code at IBM developerworks
// @version            0.1
// ==/UserScript==
 
function loadScript(url){
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = url;
    document.body.appendChild(script);
}
 
function loadCss(url){
    var css = document.createElement("link");
    css.href = url;
    css.type = "text/css";
    css.rel = "stylesheet";
    document.body.appendChild(css);
}
 
loadScript("http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js")
loadCss("http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css")
 
var allPres = document.getElementsByTagName("pre");
for(var i = 0; i &lt; allPres.length; i++) {
    if(allPres[i].getAttribute("class") == "displaycode") {
        allPres[i].setAttribute("class", "prettyprint");
    }
}
 
document.body.setAttribute("onload", "prettyPrint()");

使用方法
Firefox需要安装Grease Monkey扩展(Chrome无需安装)

进入 http://userscripts.org/scripts/show/117032
单击右边的install按钮按照提示操作即可。

贴一个对比效果图

避免将表格用于布局

October 17th, 2011

设计人员将表格用于页面布局,这种设计方式源于旧浏览器(90年代中期到2000年早期)对css支持的不一致。那时所有浏览器基本以相同的方式支持表格,所以web设计人员利用了基于表格的内容创建方法来完成所有浏览器中相同的视觉效果。但是,现在所有主流浏览器对css的支持相对接近,设计人员不应当再将表格用于页面布局。

    避免将表格用于布局的主要原因包括以下几点:

  1. 将内容与表现混合——css和兼容标准的web设计的目标之一是将表现层与内容层分离。
  2. 毫无必要地造成重新设计困难——为了修改基于表格的布局,你可能必须修改网站的每一页上基于表格的布局。
  3. 可访问性问题——读屏软件在表格上查找内容,所以常常将布局表格当作内容表格读取。在移动设备上的呈现——表格布局通常不够灵活,不能缩小以适应屏幕。

more:why tables for layout is stupid

最近在翻《 html与css入门经典》,读到上面的话深有感触。参与的一个项目,后台管理页面全部用table布局。这个项目启动的时候,没有一位专职的前端同学。有人把页面框架搭出来大家已经很满足了,虽然用的是table。在迭代过程中,功能性需求一直被放在首位,展示性需求放在次要,再加上后台管理页面是自己人内部用用,一个迭代下来,常常是没时间去改善它。这样粗生粗养一年多,最后演变成原生数据展示的table与布局table交织一块暧昧不清的窘境,正中上面的1、2条。

从天苑到北村

May 15th, 2011

从落脚了一年的二十二楼搬到一座老居民楼的二楼,从半空降落到地面,忽然发现,生活里从此出现了很多声响:南面一幢楼里儿童英语培训班哇啦啦的读书声,北面的小平房里高压锅哧哧哧的蒸汽声,隔壁阳台上木棒捶打被子的声音,小区外面的街市上来往车辆的声音,拖鞋踩到房间中某一块木地板时会发出的吱呀一声。我坐在堆满了各种纸箱和编织袋的屋子里,百废待兴。

一年之约

May 8th, 2011

和MM做了个一年的约定。
一年后我们一起做一件事情。做这件事情之前,我们需要一些基本条件,主要是技能上的,另外就是身体健康与一点钱。
我们把约定写在咖啡厅的餐巾纸上。
在这一年里,我们的生活便有了目标。
今天是一年的开始,勿相忘。

如何在velocity中格式化时间

April 19th, 2011
1
2
3
4
5
6
7
// 代表一种收集规则
public class GatherDO {
	int gatherId; // id
	String name;  // 名称
	String group; // 分组
	Date gmtModify; // 修改时间
}
1
2
3
4
5
6
7
8
// 后台controller代码片段
@RequestMapping(method = RequestMethod.POST, params = "method=search")
public String search(ModelMap map, HttpServletRequest request) {
	List<GatherDO> gathers = gatherDAO.getAllGathers();
	map.addAttribute("gathers", gathers);
 
	return DEFAULT_VM;
}
// 前台vm模板代码片段

#forEach ($gather in $gathers)


#end
$!gather.id" $!gather.name $!gather.group $!gather.gmtModify

代码片段很简单,后台从数据库中捞取所有的GatherDO对象,在前台用velocity进行展示。GatherDO中有一个时间属性,不做处理的话,在前台默认是用toString()方式,得到的诸如“Tue Apr 19 00:20:45 CST 2011”这样难看的时间格式。

如何在前台得到格式化的时间字符串呢?
后台转换搞,前台JS凿,仁者见仁,智者见智。
同事教我的一种方法,最能体现velocity的精髓——Velocity是一个基于Java 的模板引擎(template engine). 它可以让视图的设计者在web页面中引用java 代码中定义的数据对象和命令。

1
2
3
4
5
6
7
8
@RequestMapping(method = RequestMethod.POST, params = "method=search")
public String search(ModelMap map, HttpServletRequest request) {
	List<GatherDO> gathers = gatherDAO.getAllGathers();
	map.addAttribute("gathers", gathers);
	map.addAttribute("simpleDateFormat", new SimpleDateFormat("yyyy-MM-dd HH:mm"));
 
	return DEFAULT_VM;
}
// 前台vm模板代码片段

#forEach ($gather in $gathers)


#end
$!gather.id" $!gather.name $!gather.group $!simpleDateFormat.format($!gather.gmtModify)