Shao Fan

关于JAVA与软件工程
posts - 31, comments - 71, trackbacks - 0, articles - 4
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2006年3月1日

目前开发人员对系统开发的一个共识是使用三层架构,分为表示层,业务层,和持久层。而这三层之间的依赖关系如何?比较常见的一种看法是

表示层 --> 业务层 --> 持久层

这表明了层与层之间的调用关系,表示层通过调用业务层来完成任务,而业务层则调用持久层。从另一个角度来看,一种依赖关系是

表示层 --> 领域模型(Domain Model) <-- 持久层

表示层和持久层都应该理解(recognize)领域模型。而领域模型则是业务层的一部分。业务层正是系统的价值所在。虽说表示和持久也很重要,在某些系统中可以说是很关键,但是它们的最终目的都是为业务服务,所以业务层应该是系统的核心

基于以上的认识,在系统设计的时应首先分析需求得到领域模型,找出系统中的实体、对象(静态的一面),并明确大致的业务流程(动态的一面)。 而另两层应尽最大努力为业务层服务,且尽量减少业务层受另两层的限制。


各层的职责:

表示层:负责显示信息,及从系统外部得到输入。表示层的设计决定系统界面的可用性,及信息输入和展示的可靠性。表示层只知道如何展示信息,及收集用户输入,并不知道该如何对这些输入进行处理来完成业务。

业务层:完成业务逻辑。业务层设计决定客户价值是否能够得到实现。这是系统的关键。外在的表现是功能性。业务层设计和实现的失误表现在用户端即功能缺失,功能不可靠等。如果需要对业务层的业务规则进行解耦,则可以使用规则引擎如Drools,把业务规则分离出来。但分离后的业务规则仍属于业务层。业务层知道如何对用户输入进行处理,能够应用业务规则完成用户所需的业务,但它不知道数据如何读取和保存。

持久层:负责用户信息的持久化。持久层的失误表现在外即数据处理(储存,展示等)不可靠。持久层完全不知道业务,只专注于数据存储和读取。所谓持久化并不一定是指数据库,任何方式的持久化(通过文件,网络的持久化等)都应由持久层完成。

各层的设计都会直接影响系统性能。

三层的体积大小和复杂度在不同的系统中可能会有很大的不同。比如说GOOGLE的搜索引擎,它的界面很简单,可以想像表示层是比较容易实现的,而它的业务层,关系到处理关键字,分析搜索结果,决定排名等,而持久层则要负责处理超大量的数据。业务层和持久层则相当复杂。而有的系统持久层会很小,比如杀毒软件,媒体播放软件等。业务层小而另两层大的例子暂时还没有想到:)


posted @ 2007-09-08 19:45 shaofan 阅读(5113) | 评论 (2)编辑 收藏

help是一个内置函数,所谓内置函数,就是在Python中被自动加载的函数,任何时候都可以用。参数分两种:

  • 如果传一个字符串做参数的话,它会自动搜索以这个字符串命名的模块,方法,等。
  • 如果传入的是一个对象,就会显示这个对象的类型的帮助。

比如输入help(’print’),它就会寻找以’print’为名的模块,类,等,找不到就会看到提示信息。而print在python里是一个保留字,和pass,return同等,而非对象,所以help(print)也会出错((kkkkkkk))。

举个例子:

1 help(’sys’) #会列出sys模块的帮助
2 = [1,2,3]
3 help(a) #会显示list的帮助
4 help(a.append) #会显示list的append方法的帮助

python安装自带的library reference,2.1节是关于内置函数的。

Reference Manual的6.6节可以找到关于print的东东。

posted @ 2007-06-05 06:28 shaofan 阅读(2753) | 评论 (0)编辑 收藏

Struts2默认theme是xhtml,它用表格来对表单中的控件进行排版。它也提供一个客户端的js验证功能,但是它的js脚本却有些问题,在某些情况下,前次验证的提示信息无法被清除,提示信息会不断的累积显示在屏幕上。而按照设计,每次提交表单时应只显示每次验证的出错信息。

它的客户端验证的流程大概是这样,用户提交表单时,对各个控件的输入按预先设置的规则进行验证,如果有问题,则清除表单里原有的出错提示信息,并写入新的提示。其设计的功能是把出错信息写表格里出错控件的上方,以便用户看得更加清楚。问题就出在其用来清除原出错信息的函数,其代码是这样的(在struts.jar的template/xhtml目录下可以找到):

 1 function clearErrorMessages(form) {
 2 
 3     var table = form.childNodes[1];
 4     iftypeof table == "undefined" ) {
 5         table = form.childNodes[0];
 6     }
 7 
 8     // clear out any rows with an "errorFor" attribute
 9     var rows = table.rows;
10     var rowsToDelete = new Array();
11     if (rows == null){
12         return;
13     }
14 
15     for(var i = 0; i < rows.length; i++) {
16         var r = rows[i];
17         if (r.getAttribute("errorFor")) {
18             rowsToDelete.push(r);
19         }
20     }
21 
22     // now delete the rows
23     for (var i = 0; i < rowsToDelete.length; i++) {
24         var r = rowsToDelete[i];
25         table.deleteRow(r.rowIndex);
26         //table.removeChild(rowsToDelete[i]);
27     }
28 }


看这个函数的前三行,它试图取得form的第1个或第2个子节点,并把它作为table来处理(看接下来的几行)。要想清除表格里的错误信息,首先要取得表格本身,这没错,但是如果第1个或第2个子节点不是table的话,脚本就会出错,造成原出错信息无法清除,这样每次提交后的提示信息就会累积在屏幕上。

要解决这个问题有两个办法:
  • 写代码时要小心,保证form的第1或2个子节点是table,不要在生成table前加其他代码。
  • 或,修改xhtml的validation.js,使它总能获得正确的table元素,重新打包到struts.jar。
刚看了一下Struts的JIRA,已经有人报告了这个问题(id WW-1802),而且这个bug在2.1版本中已经解决了。

posted @ 2007-06-03 17:56 shaofan 阅读(2527) | 评论 (3)编辑 收藏

假设:用两者写一个最小的WEB程序。
过程可以参照:
1.struts的就太多了,随便哪个都可以
2.python/django可以看limodou写的Django step by step

 

Java/Struts/JSP  Python/Django
开发步骤 1.在web.xml里配置struts的servlet
2.在struts-config.xml里配置URL和action的映射
3.写action
4.写JSP
1.在urls.py里配置URL到方法的映射
2.写相应的方法
3.写HTML模板
调用过程 1.根据web.xml的映射调用struts的servlet controller
2.servlet controller根据struts-config.xml的映射调用相应的action
3.action处理请求
4.JSP渲染显示
1.根据urls.py的映射调用相应的方法
2.方法处理请求
3.HTML渲染显示


相比之下前者用了两层才把一个HTTP请求映射到实际处理的方法:第一次是servlet的映射,第二次是struts action的映射。
而django则一次就从URL映射到相应的方法了。

另外一个比较显著的区别,也是基于java和python的语言上的区别吧,java的所有方法必需包含在一个类中,因此action mapping配置时是映射到类,而action在实现类则应实现事先约定的方法(通过继承或实现接口)。而django则直接得多,可以直接在配置里写明处理请求的方法名。


posted @ 2007-04-06 19:11 shaofan 阅读(4964) | 评论 (0)编辑 收藏

DOM (Document Object Model)是一套语言无关的XML解析的接口定义。它定义了在XML解析中需要的类型,方法,以及属性,比如如何获得一个XML标签,如何改变标签的内容,如何改变它的属性,等等。

DOM只是一个定义,并不是具体的实现,它的目的就是为了让大家在各个平台上都能用相同的方式来处理XML,这样一来,我只要了解DOM,基本上在各个平台上都可以方便的处理XML,而不用重新学习了。比如说,Java, JavaScript, Python都有DOM的实现,用它们来处理XML,方式基本上都是一样的(当然也有非DOM的XML解析方式)。在Java下,实现DOM的类库就有很多,比如JDom,Xerces, 用GOOGLE一搜就一大把。现在Java 5.0内置的就是Xerces。而JavaScript本身就内置了DOM的实现。Python也默认安装了DOM的库。

正因为DOM致力于实现各个平台上对XML一致的处理方式,它定义了一堆自己的接口。因此在用DOM的时候,会有很多非NATIVE的东东。比如说,返回节点的子节点的方法,childNodes,返回的类型是NodeList。我第一次在Java上用,就以为是返回一个List,然后用get(n)方法来取得某元素。而实际上NodeList是用item(n)的方法来取得某元素的。这就让我觉得很怪。而DOM正是用这种方式来获得“语言无关”的能力的。

DOM是用IDL(Interface Definition Language)来定义的。完整的定义可以在这里找到 http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html。IDL也很容易看懂。定义的1.1节列出了所有的接口。

这些接口里,最重要而且常用的是Node,NodeList,Document,Element,Text,Attr这几个。DOM把XML文档看作一棵树,树上的每个元素都是Node。每个Node都属于某个类型,比如Element,attribute,text等。这些类型就表明这个节点在XML文档里的类型了。

比如Node里有个属性:

  readonly attribute unsigned  short   nodeType;

根据这个定义,对于取得的节点,我们就可以通过读取nodeType这个属性来判断这个节点的类型。在Java里,所有的属性都是用getter来取得的,因此对某节点n,就可以用n.getNodeType()取得它的类型。Node接口里也定义了类型常量:

  const unsigned short      ELEMENT_NODE                   = 1;
  const unsigned short      ATTRIBUTE_NODE                 = 2;
  const unsigned short      TEXT_NODE                      = 3;
  const unsigned short      CDATA_SECTION_NODE             = 4;
  const unsigned short      ENTITY_REFERENCE_NODE          = 5;
  const unsigned short      ENTITY_NODE                    = 6;
  const unsigned short      PROCESSING_INSTRUCTION_NODE    = 7;
  const unsigned short      COMMENT_NODE                   = 8;
  const unsigned short      DOCUMENT_NODE                  = 9;
  const unsigned short      DOCUMENT_TYPE_NODE             = 10;
  const unsigned short      DOCUMENT_FRAGMENT_NODE         = 11;
  const unsigned short      NOTATION_NODE                  = 12;

用这些常量和和n.getNodeType()的结果比较,就可以知道它是不是某种类型。

Node接口中也定义了一些方法,比如:

 Node     appendChild(in Node newChild)    raises(DOMException);

表明appendChild方法需要一个Node类型的参数,返回一个Node。 具体的说明可以点文档上的链接进去,也很容易看懂。

Node接口里定义了操纵节点的方法,比如增加子节点,返回父节点,插入新节点,返回节点类型,等等。Document,Element等接口都继承Node接口,因此在它们上面都可以使用操纵节点的方法。

Document:代表整个XML文档。所有DOM元素都不能用类似Java里new的方式来生成,而是要通过调用Document里的相应方法来生成。因此它提供了生成诸如Element, Attr, Text的方法。比如createElement, createTextNode, createComment等。它也提供了名为getElementsByTagName的方法,用来通过标签名称来取得其对象。比如getElementByTagName("ul")就可以获得所有ul标签。它也提供一些文档的属性,比如xmlEncoding,inputEncoding等。它的一个属性,documentElement代表文档的根节点。所有对XML元素的操作,基本上都是从Document开始的。

Element:代表一个XML标签。它可以有属性,子标签,等。比如<ul id="booklist"><li>hello</li></ul>。标签ul是一个Element,它有一个属性叫id,属性的值是booklist。它有一个子结点li。li也是一个标签,它也有个子节点hello,是一个Text类型的节点。这个接口提供操纵其标签属性的方法,比如getAttribute,setAttribute,removeAttribute等。它也提供了和Document中一样的getElementsByTagName的方法,用来获得在这个节点下的元素。

Attr:代表标签中的属性。比如上面的id。它也是一个Node。它有名字,值,也可以获得它的所属标签。

Text:代表一段文字,比如上面的hello,它也一个Node,但比较特殊,它不是直接继承Node,而是继承CharacterData接口,后者继承了Node。但是它不能有子节点。

用JavaScript给一个例子。假设有一个HTML文档:

< html >< head >< title > Try DOM </ title ></ head >< body >
< ul >
< li > hello </ li >
< li > world </ li >
</ ul >
</ body ></ html >

下面是增加一个li的JavaScript方法:

ulList  =  document.getElementsByTagName( " ul " );
ul     
=  ulList.item( 0 );
txt    
=  document.createTextNode( " I am new li " );
li     
=  document.createElement( " li " );
li.appendChild(txt);
ul.appendChild(li);

用Java来写,是这样:

NodeList ulList  =  document.getElementsByTagName( " ul " );
Node        ul      
=  ulList.item( 0 );
Text          txt      
=  document.createTextNode( " I am new li " );
Element    li        
=  document.createElement( " li " );
li.appendChild(txt);
ul.appendChild(li);

可以看到处理方式和数据类型都是一样的。如果要了解更多,可以看看DOM的定义,都是IDL。

posted @ 2007-04-01 18:45 shaofan 阅读(843) | 评论 (0)编辑 收藏

我的博客已搬家,请移步到 http://shao-fan.com/blog 阅读最新内容!


Ubuntu/Debian中的update-alternative用来对系统中不同版本的同个软件进行管理。
比如,系统中可能装有GNU的Java编译器,和SUN的Java编译器。可以用update-alternatives来设置当前使用它们中的哪一个。

它的原理是在/usr/bin中建立一个link,指向/etc/alternatives中的一个文件,而些文件又是一个link,指向当前使用的命令。比如java命令,查看如下:

 $ which java
/usr/bin/java
$ ls -l /usr/bin/java
lrwxrwxrwx /usr/bin/java -> /etc/alternatives/java
$ ls -l /etc/alternatives/java
lrwxrwxrwx /etc/alternatives/java -> /usr/lib/j2re1.5-sun/bin/java
$ ls -l /usr/lib/j2re1.5-sun/bin/java
-rwxr-xr-x /usr/lib/j2re1.5-sun/bin/java

参数--display可以某个软件的当前配置,如:

 $ /usr/sbin/update-alternatives --display java
java - status is auto.
link currently points to /usr/lib/j2re1.5-sun/bin/java
/usr/lib/kaffe/bin/java - priority 300
slave java.1.gz: /usr/share/man/man1/java.kaffe.1.gz
/usr/lib/j2re1.5-sun/bin/java - priority 315
slave java.1.gz: /usr/lib/j2re1.5-sun/man/man1/java.1.gz
Current `best' version is /usr/lib/j2re1.5-sun/bin/java.

status有auto和manual两种。一旦用户更改了系统的默认设置,它就变为manual。在auto的状态下,系统会根据几套配置的priority来判断当前应该使用哪套配置。

每套配置可以设定多个link,它们被称为slave。上面的例子中,有两套java的配置。一套是/usr/lib/kafe/bin/java,另一套是/usr/lib/j2re1.5-sun/bin/java,它们各有一个slave。在些例中这些slave设置的是java命令的 manual。当更改了配置时,用man命令查看的帮助也会相应更改。

参数--config可以用来更改当前的配置。

 $ sudo /usr/sbin/update-alternatives --config java 
There are 2 alternatives which provide `java'.
Selection Alternative
-----------------------------------------------
1 /usr/lib/kaffe/bin/java
*+ 2 /usr/lib/j2re1.5-sun/bin/java
Press enter to keep the default*, or type selection number: 1
Using `/usr/lib/kaffe/bin/java' to provide `java'.

参数--install用来设置一套新的配置。具体参见 http://blog.stevenkroon.com/2006/08/29/debian-update-alternatives/

posted @ 2006-12-25 01:43 shaofan 阅读(6302) | 评论 (1)编辑 收藏

Web开发真是越来越有意思了。现在居然可以在JavaScript里直接调用Java写的方法。大水牛Buffalo的最新版1.2.3发行离现在已有半年时间了,现在才注意到。在客户端的代码相当简单:

buffalo.remoteCall("userService.listAll",[],function(reply){
 // 不用担心,reply.getResult会从聪明的判断服务器端远程调用的结果类型。
 var userList = reply.getResult(); 
 var firstUserFamilyName = userList[0].name.familyName;
});

给Web程序加上Buffalo也相当容易。只要下载几个jar文件放到lib目录下,外加几个JS文件,然后在web.xml里加一个Servlet即可。用的时候是需要有个properties文件来定义哪些JAVA方法可以被JS调用。而服务器端的JAVA代码不需要做任何改动。

暂时手头上还想不起来哪些地方会用,但是这个东东可是我很久以前曾经想过的,现在有人实现了,还是很激动人心的啊。Buffalo的主页是 http://www.amowa.net/buffalo/zh/index.html 。


posted @ 2006-09-08 03:59 shaofan 阅读(8907) | 评论 (6)编辑 收藏

最近因为Globus的原因,不得不用Linux了。以前几次想学,都因为难得要领放弃了。这次装了Ubuntu,又碰巧在它的论坛上看到一篇很不错的教程,终于有些“入门”的感觉了。看来找到合适的教程真的是很重要啊。这几天用下来,感觉还真的很不错。用Python写了个显示目录树的小程序。也不知道有没有现成的,反正很简单,刚好就练练手,功能也够我自己用了:)

下载Python脚本


posted @ 2006-08-01 08:57 shaofan 阅读(1492) | 评论 (0)编辑 收藏

最近Firefox出了点问题。我这里用http proxy上网,连接设置里要设置相应的proxy。但发现每次重启ff,连接设置都被重置为“直接连接”。即使改回“通过proxy连接”,下次重启又被重置了。

马上google一把,发现类似的问题大致有两种解决办法:
1.进入safe mode,会出现一个对话框,把三个选项都勾上,重启。
2.在地址栏输入about:config,会出现所有的配置,把要改的改了即可。
3.直接修改prefs.js文件。

但这三个方法对偶的FF都不管用。

最后的解决方法是,删除
C:\Documents and Settings\<user name>\Application Data\Mozilla\Firefox\Profiles\<xxxxxxxx.default>\
下的user.js,然后再修改prefs.js。然后一切都正常了。

原来,ff最基本的配置文件是prefs.js。而user.js的优先级应该是比prefs.js高,因此每次重启它都从user.js读取配置。而通过正常途径,如在选项菜单里改设置,无法在user.js里保存(不知道为什么)。所以就造成了每次重启配置被重置的情况,其实就是设置无法被保存。把user.js删掉以后,ff就从prefs.js里读取配置了,而且新的设置也可以正常保存。

不管是从选项菜单里修改配置,还是以上的第二种方法,最终的结果都是配置被保存在prefs.js文件里,效果都是一样的。

目前已知的会私自修改FF配置的软件只有Hide IP Plantium,而以上情况正是在安装Hide IP Plantium以后出现的。用的时候要注意。

相关的讨论在mozillazine里有很多。不得不承认,这类的英文资源要比中文的多得多。看这里的详细讨论:
http://forums.mozillazine.org/viewtopic.php?t=413875&postdays=0&postorder=asc&postsperpage=15&start=15

posted @ 2006-07-24 18:21 shaofan 阅读(4574) | 评论 (2)编辑 收藏

1.理解页面流(flow),理解几种不同的定位方式:static, relative, absolute等
Positioning and other definitions:http://css.maxdesign.com.au/floatutorial/definitions.htm  

2.HTML页面表达内容逻辑,把样式控制写到CSS文件中

3.浮动(float)的DIV要配合width属性来用

4.怎样控制层的位置:用float,padding,width,height这些属性来控制
Float Tutorial: http://css.maxdesign.com.au/floatutorial/index.htm

5.设置可见的border或background-color来帮助排版

6.出现内层的DIV跑到外层之外的情况时,可以在外层DIV的</DIV>前加上一个clear层来解决问题。就是这样:
   <div class="container">
    ...
    ...
    <div class="clear"></div>
  </div>

  css:
  .clear{
    clear:both;
  }

7.样式表的选择符(Selector):
   Type/Class/ID等
  Selector Tutorial:http://css.maxdesign.com.au/selectutorial/index.htm

8.关于表单的样式设计:
让我们更好的设计表单:浅议Web的表单设计 http://tech.163.com/06/0529/04/2I8UPHTB0009158Q.html
用CSS制作具有亲和力的表单 作者:greengnn
http://www.jluvip.com/blog/article.asp?id=192

9.各种浏览器对各种标签用不同的方式渲染,如p, h1, ul等,它们会有不同的padding和margin,为了在各种浏览器下都正常的显示,可以把它们清零,如:
*{
    padding:0;
    margin:0;
}

10.使用list来显示数据或菜单
List Tutorial:
http://css.maxdesign.com.au/listamatic/
http://css.maxdesign.com.au/listamatic2/
http://css.maxdesign.com.au/listutorial/

11.关于各种标准,布局,技巧等的网站:
网页设计师:http://www.w3cn.org/
CSS教程:http://www.netvtm.com/w3s/css/
网页制作指导 - 致力于网页制作知识的普及:http://www.jianzhan8.cn/
当然还有必不可少的经典论坛blueidea:http://www.blueidea.com/bbs/list.asp?GroupName=%CD%F8%D2%B3%B1%EA%D7%BC%BB%AF%D7%A8%C0%B8

posted @ 2006-06-21 06:22 shaofan 阅读(927) | 评论 (0)编辑 收藏

如果你不幸装了NetBeans并且启用了外置的服务器,那么它会自动在你的web server的web.xml里添加一个filter,名叫HttpMonitorFilter。你用NetBeans时,它会过滤所有的http请求,这样NetBeans就可以显示所有的相关信息。但是如果不用NetBeans,比如我,用eclipse + Tomcat ,那就会得到这个异常:

NotifyUtil::java.net.ConnectException: Connection refused: connect
  at java.net.PlainSocketImpl.socketConnect(Native Method)
  at java.net.PlainSocketImpl.doConnect(Unknown Source)
  at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
  at java.net.PlainSocketImpl.connect(Unknown Source)
  at java.net.Socket.connect(Unknown Source)
  at java.net.Socket.connect(Unknown Source)
  at sun.net.NetworkClient.doConnect(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.http.HttpClient.(Unknown Source)
  at sun.net.www.http.HttpClient.(Unknown Source)
  at sun.net.www.http.HttpClient.New(Unknown Source)
  at sun.net.www.http.HttpClient.New(Unknown Source)
  at sun.net.www.http.HttpClient.New(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
  at org.netbeans.modules.web.monitor.server.NotifyUtil$RecordSender.run(NotifyUtil.java:237)



解决方法是

第一步. 删除 Tomcat目录中common\lib下的两个和netbeans有关的jar文件(以org-netbeans开头的)

第二步. 修改tomcat目录下的conf\web.xml,删除相关Filter的定义,就是这一段:

    <filter>
        
<filter-name>HTTPMonitorFilter</filter-name>
        
<filter-class>
            org.netbeans.modules.web.monitor.server.MonitorFilter
        
</filter-class>
        
<init-param>
            
<param-name>netbeans.monitor.ide</param-name>
            
<param-value>127.0.0.1:8082</param-value>
        
</init-param>
    
</filter>
    
<filter-mapping>
        
<filter-name>HTTPMonitorFilter</filter-name>
        
<url-pattern>/*</url-pattern>
        
<dispatcher>REQUEST</dispatcher>
        
<dispatcher>FORWARD</dispatcher>
        
<dispatcher>INCLUDE</dispatcher>
        
<dispatcher>ERROR</dispatcher>
    
</filter-mapping>

posted @ 2006-06-13 20:37 shaofan 阅读(1037) | 评论 (0)编辑 收藏

据英国的职位搜索引擎Workcircle的调查显示,93%的IT经理人和几乎所有的CEO和CTO会在英格兰队比赛的那天请病假。相比之下,程序员的请假的比例要低得多,JAVA程序员为86%,而最可怜的是SQL程序员,只有14%。更搞笑的是WikiHow上还有一个“怎样请病假”的教程。

原文如下:

Managers most likely to take a sickie to watch England play

9 June 2006, Cambridge UK – UK job site, Workcircle ran a survey this week asking how likely jobseekers are to take a sick day to watch an England World Cup match.

World cup surveyThe results show the deep divide between workers and management, just 14% of Engineers surveyed will take a sickie to watch a match, but a shocking 93% of managers will.

And it gets worse the higher you get – all CEOs and CTOs surveyed will take a day off.

As far as the developers go, Java programmers are the most patriotic – 86% would call in sick to watch a match, compared to 14% of hard-working SQL developers.

So when the boss is in an unexplained long meeting during the World Cup, check if there’s an England match on!

posted @ 2006-06-12 06:45 shaofan 阅读(681) | 评论 (0)编辑 收藏

适用于webwork 2.2.2,详见随包文档。源文件下载:Hello.rar

一共五步:

1.建立web应用程序的目录结构
2.拷贝库文件:ww安装目录下的lib\default中的所有jar,以及webwork-2.2.2.jar,复制到WEB-INF\lib下。
3.生成配置文件:web.xml在WEB-INF下, xwork.xml在WEB-INF\classes下

web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>My First Hello Webwork</display-name>

    
<filter>
        
<filter-name>webwork</filter-name>
        
<filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
    
</filter>

    
<filter-mapping>
        
<filter-name>webwork</filter-name>
        
<url-pattern>/*</url-pattern>
    
</filter-mapping>

    
<welcome-file-list>
        
<welcome-file>index.jsp</welcome-file>
    
</welcome-file-list>

    
<taglib>
        
<taglib-uri>/webwork</taglib-uri>
        
<taglib-location>/WEB-INF/lib/webwork-2.2.2.jar</taglib-location>
    
</taglib>
</web-app>


xwork.xml:
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.1.1//EN" "http://www.opensymphony.com/xwork/xwork-1.1.1.dtd">

<xwork>
    
<!-- Include webwork defaults (from WebWork JAR). -->
    
<include file="webwork-default.xml" />

    
<!-- Configuration for the default package. -->
    
<package name="default" extends="webwork-default">
    
</package>
</xwork>


4. 编写action和jsp
5. 在xwork.xml中添加相应配置,如在package之间加入:
        <default-interceptor-ref name="completeStack"/>
        
<action name="helloww" class="net.blogjava.shaofan.helloww.Hello">
            
<result name="success">greetings.jsp</result>
        
</action>


下步计划:
* 了解package
* ww的taglibs
* 在action和jsp间传递数据的机制(struts中使用formbean,利用session,request等)

posted @ 2006-06-04 09:13 shaofan 阅读(2290) | 评论 (7)编辑 收藏

     摘要: 在这篇文章里,Nick Afshartous描述了一种把HTML的内容转换为PDF格式的方法。这种方法相当有用,比如说,一个web程序可以在它的页面上提供如“下载为 PDF”的功能。这种功能方便了打印和储存,以供日后使用。Afshartous的转换方法只使用开源的组件。也有一些商业产业可供使用。因此,在这篇文章里描述的这种方法既在价格上可以承担,又能够获得所用组件的源码。(1600字;2006年4月10日)   阅读全文

posted @ 2006-06-01 07:56 shaofan 阅读(3534) | 评论 (10)编辑 收藏

     摘要: 在这篇文章里,Nick Afshartous描述了一种把HTML的内容转换为PDF格式的方法。这种方法相当有用,比如说,一个web程序可以在它的页面上提供如“下载为PDF”的功能。这种功能方便了打印和储存,以供日后使用。Afshartous的转换方法只使用开源的组件。也有一些商业产业可供使用。因此,在这篇文章里描述的这种方法既在价格上可以承担,又能够获得所用组件的源码。(1600字;2006年4月10日)
  阅读全文

posted @ 2006-05-30 06:15 shaofan 阅读(5675) | 评论 (7)编辑 收藏

天差点栽在JAVA路径设置上。

本来是想用ANT的。但是在命令行输入ant,得到了这样的提示:

Usage: java [-options] class [args...]
           (to execute a class)
   or  java [-options] -jar jarfile [args...]
           (to execute a jar file)

       ......
       ......

奇怪。想来是刚重装了系统,JAVA_HOME没有设好。于是检查了一遍。问题依旧。那是不是虚拟机的问题?虚拟机缷掉重装。折腾了半天,问题还是没有解决。

逼得我只能静下心来仔细想想问题所在了。ant的命令执行的是一个批处理文件,在这个批处理中它会调用java.exe来运行ant。出现这样的问题,必定是java.exe的用法格式不对了。于是打开ant.bat,发现它的执行有几个分支。在每个分支上加上一句echo b1, echo b2,再次运行,确定是哪个分支被执行。被运行的语句分支就是这个了:

:runAntWithClasspath
"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% -cp "%CLASSPATH%" %ANT_CMD_LINE_ARGS%
goto end

OK。现在几乎可以肯定是那一堆%%的变量里出了问题。拿出我们程序员百试不爽的绝招的时候了:打印每个变量。哈哈,问题出来了:

"D:\lib\apache-ant-1.6.5\\lib\ant-launcher.jar"

看到了吗?"lib"前面居然是两个反斜杠杠。OK。发现了问题所在,现在是解决的时候了。打开系统变量ANT_HOME,果然,它被设置为"D:\lib\apache-ant-1.6.5\"。把最后的反斜杠去掉。再试运行ant,得到:

Buildfile: build.xml does not exist!
Build failed

ant可以正常运行,问题解决了。

这个小小的问题前后用了我快一个小时的时间。但是最后真正发现并解决问题的时间也不过十分钟而已。看来还是太浮躁了。如果一开始就用心去想,也不会有这么多的浪费。想想,为什么那后面会多一个\,其实也很简单,从WINDOWS的地址栏直接拷贝的咯。Windows啊......我知道不能怪Windows,但总要找个出气桶,对不对?

自以为用了几年JAVA已经挺熟了,没想到差点栽到最低级的失误里了。反省反省。。。。。。

posted @ 2006-05-29 07:28 shaofan 阅读(2585) | 评论 (3)编辑 收藏

Sun 的Java EE 5终于发布了(上一版本称作J2EE)!这一版本可说是万众瞩目了,目前在SUN的站点上已经提供下载。值得关注的特点是:

"第一个商业的,比较完善的Java EE 5 实现

简化开发--对编程模式的重新组织
支持EJB3.0--POJO
支持Java Persistence API , ORM更简单
JAX-WS 2.0 以及 JAXB 2.0 使得开发web services 以及SOA应用更加便捷
JavaServer Faces 1.2--更简易开发AJAX
效率更高, 同时管理和部署功能更强大
启动速度提高30%, 占用内存减少30%.
web services 效率提高至少5倍.
web services 管理更强大
整合了NetBeans以及支持Eclipse plug-in
提供了整合NetBeans的可视化的SOA 开发以及部署
Sun's Java System Application Server PE 9.0是完全开源的"

                                                 ----摘自www.Matrix.org.cn

它的结构如下图:


Matrix上的相关文章:http://www.matrix.org.cn/resource/news/728_SUN+JavaEE5+SDK.html
SUN网站上的下载地址:http://java.sun.com/javaee/downloads/index.jsp

posted @ 2006-05-17 08:04 shaofan 阅读(675) | 评论 (0)编辑 收藏

Google好用吗?大概很多人会说"Yes"。

但是老外Don Norman去从另一个角度说明,Google的易用性只是一个假象。因为他的主页只放一个搜索框,要想使用Google的其他服务,比如Google Map, Google Earth,却要经过很多次不同的点击,给用户造成很大的不便。相比之下,其他的比如Yahoo,MSN,大家认为它们复杂,但实际上从他们的主页访问他们提供的各种服务都很方便。

要我说,就一个字:赞成。两个字:非常赞成!

全文请见:

英文原文:The truth about Google's so-called "simplicity"   by Don Norman
中文译文:关于 Google 界面所谓的“简洁性”的真实情况  翻译:张亮

posted @ 2006-05-14 06:24 shaofan 阅读(502) | 评论 (0)编辑 收藏

些天,不记得是用SOHU的邮箱注册了哪个网站了,现在每天都收到大量的垃圾邮件。不知道别人怎么样,反正我觉得SOHU的闪电邮件的反垃圾邮件功能基本是个摆设。而它的“垃圾邮件举报”的功能似乎也没什么作用。相比YAHOO和GOOGLE,这两位业界大佬提供的邮箱的反垃圾能力则明显要高一筹。

我也常用YAHOO的邮箱来注册网站BBS,它对垃圾邮件的识别率相当高,我收到的大部分垃圾邮件它都可以准确识别。此外,YAHOO还提供了“替身邮”的功能,就是可以注册一堆虚拟的邮件地址,每个地址其实都是指向你原来的那个。用这些替身地址去注册网站或者留言什么的,所有发到它的邮件都会自动到达原来的邮箱。以后从这个地址来的垃圾邮件多了,就可以把这个替身地址删掉,就再也不会收到从它发来的垃圾了。

这是个好想法。以前我所想到的方法是,注册一个邮箱,专门用来在注册网站用。然后给它设置自动转发,把邮件转到我原来的邮箱地址。替身邮和这个想法真有异曲同工之妙。但是替身邮有个缺点,一旦把替身地址删掉,那些有用的邮件也收不到了。我所希望的是,能为这些替身地址增加“白名单”的功能,只收指定地址寄来的邮件。如果是这样,那就完美了。

另外,SOHU闪电邮件的“自动转发”居然不起作用?开了好几天了,一封都没转发过,真是狂晕!!

posted @ 2006-05-03 18:22 shaofan 阅读(649) | 评论 (1)编辑 收藏

两周休假,不更新咯!休息一下!

posted @ 2006-03-20 10:30 shaofan 阅读(332) | 评论 (0)编辑 收藏

     摘要: 最近Business 2.0杂志发表了一篇文章,名为"Next net 25",介绍了五类25家新锐网站。它们大多为web2.0网站,它们的发展正体现了当今互联网的动向。有人敏锐地认识到了这篇文章的特别之处,并把它和 94年的状况进行了对比。认为web2.0开始从少数人面前跳上了大众舞台,而目前主流媒体也开始注意并认可这类站点和服务了。  阅读全文

posted @ 2006-03-13 08:13 shaofan 阅读(1693) | 评论 (3)编辑 收藏

本文译自Joel on Software,同时发表在其wiki上。关于作者本人,请看这里。由于Joel对于他人对其作品的转载有较严限制,转载及引用者请参阅其声明:Linking, Quotation, and Reprinting。这是我翻译的第一篇文章,有些地方我也不是很肯定,请多多指正!

(第一稿)


在飞机控制的设计中,糟糕的可用性会致使飞机发生CFIT:可控飞行撞地

可能可用性在你的产品中不是那么关键。如果幸运的话,你在可用性设计中的错误可能只会使人失去四肢,或甚至只是拇指。没什么更糟的了。

事实上,如果极端幸运,那么糟糕的可用性设计除了会使人难受,没有其他后果。用户试着去做一些事情,或者失败,或者挣扎着去用,很直接的后果就是他们会为此感到不悦。在将来的文章里,我会讲讲此事在心理上的原因,但现在,这样说就足够了:使用户不悦的原因,很可能并非完全如你所想。

可用性,确实是一个“好”设计的核心。在将来,我会花很多时间来讲述这个问题。

好消息是:我可以很轻松地教你关于可用性设计的话题。让我们开始吧:

当一件东西能够以被期待的方式运行,那它就是易用的。

就是这样!这就是关于可用性的一切!像Hillel所说,其它的一切都是解说词。

让我们来看一个简单的例子。


哪个更好用:Windows还是Mac?


在为人们设计产品时,有一个假想用户是很有帮助的。所设想的用户越是实际,提供的帮助越大。

我的假想用户就是彼特。

有一天,彼特的朋友,吉娜叫他来帮忙。吉娜有一台Macintosh的iBook,因为她喜欢白色的电脑。当彼特坐下开始试着用吉娜的Macintosh时,他很快就感到有点沮丧了。“我讨厌这些东西,”他说。虽然最后成功地帮吉娜解决了问题,他却觉得高兴不起来。“Macintosh的用户界面真是笨拙至极。”

笨拙?为什么会这样说呢?每个人都知道,Macintosh有着优雅易用的用户界面,对不对?难道它不是那种易用性的范例吗?

好吧。让我们来看看。

在Macintosh上,如果你想改变窗口的大小,你必须拖它的右下角。而在Windows上,在任何一个边上拖动鼠标,都可以改变窗口大小。当彼特帮吉娜时,他试着拖右侧的边来让窗口变宽。结果,整个窗口都跟着动了,而不是他想要的“改变大小”。

在Windows上,当出现一个消息框时,你只要按tab键移动焦点到所需的按钮上,然后按一下空格键就可以按到那个按钮。但在Mac上,空格键不起那样的作用。当彼特得到一个警告,他就试着像他过去六年里下意识的做的那样,按空格键来关掉消息框。第一次,机器没有任何反应,他以为是键盘有问题,于是更大力地又按了一次。结果还是一样。最后他只能用鼠标了。这是另一个小小的挫折。

彼特还习惯用Alt+F4来关闭窗口。在Mac上,这恰恰是用来调整声音音量的。这次,彼特想点击桌面上的IE图标,而这个图标刚好被另一个窗口遮住了一部份。于是他按Alt+F4关闭窗口的同时立即双击图标所在的位置。结果是声音音量变大了,而窗口并未被关掉。而他的双击点在了他想关掉的那个窗口的帮助按钮上,把帮助窗口打开了。好了,他现在需要关闭两个窗口了。

这也是一个小小的挫折吧,但是,这确实让彼特更加郁闷了。这天结束的时候,彼特的脾气很不好。他试着控制那些东西,却都没有反应。空格键和Alt+F4都“不起作用”----就像它们坏了一样。窗口也不听话,连调整大小都不行。真差劲。就算这些想法都是下意识的,这些“失去控制”的细微感受也最终使他感到不快。“我还是喜欢我自己的电脑”,彼特想,“它被我设置的完美无缺,总能按照我想的方式去运行。而这些Mac真是难用。真是让人不爽。如果Apple这些年多花些心思在MacOS上,而不是搞iPod那些那些玩意,他们的操作系统也不会这么糟糕了。”

好了。我们比彼特清楚。他虽然有这些种种感受,但事实上对Mac用户来说,Mac确实很好用。完全可以用任意键来关闭窗口。微软的程序员很可能觉得,让用户拖动任意边都可以调整窗口大小的功能真的很不错。而Apple程序员很可能认为,拖动任意边来移动窗口位置的功能很有创意。

那些盲目信仰某种OS的网站上的关于用户界面的争论,都没有说到点子上。Windows更好,是因为给你更多手段来调整窗口大小。那又怎样?这并不是问题所在。真正的问题是,UI是否以用户预期的方式来响应他们的操作。如果不是,那么用户就会觉得他们无法控制它,并觉得自己会难以达成目的。就是这样了。当一件东西能够以被期待的方式运行,那它就是易用的。你可以把这句话反着纹在你的额头上,这样你在镜子里就可以看到它。

如果你继续关注将来的文章,那么你会发现,我所告诉你的关于可用性设计的一切,都可以追溯到这个简单的法则。如果哪天外星人在你的花园里着陆,把你扔到了名叫Kij8zxwrk的星球,在那里你无法连接到地球的互联网,因为数据包传送到地球所花时间太长导致TCP/IP无法正常工作,那么你所知道的东西也足以让你找到一份相当体面的可用性设计师的工作了。

posted @ 2006-03-10 06:39 shaofan 阅读(1846) | 评论 (5)编辑 收藏

我有一个习惯,每次学门语言,总要自己写个List或Stack并加上Unit Test来试试。这次对Python也不例外。总体感觉有以下几点

1.这是我用过的唯一一个把代码行的缩进也做为语法的语言,就因为不正确的缩进,我的第一个Python程序让我吃尽了苦头。事情是这样的,我运行测试时,报告每次都说"Ran 0 test in 0.000s",找了半天,也找不出为什么只运行了0个测试,一直以为是unittest包的用法有问题,或我的语法有问题,直到花了大半个小时翻书,又对比其他的测试程序以后,才发现,天啊,原来是因为最后一行的缩进多缩了一层,被认为与上一个方法同一个block。

2.虽然在缩进上吃了苦头,但是代码看起来确实相当整洁清楚,感觉比java的动不动一堆大括号相比,实在多了。

3.Python的每个module(可以看作与java的包类似)都可以包含方法和类,而java的所有方法都要写在类里,包里只有类,这点相当不同。

4.因为Python是用c实现的,它的命名比较简单,使用很多缩写,与java的长长一串的命名是很强烈的对比

5.Python是动态类型的语言,变量不需声明类型可以直接使用,虽然方便,但缺点也很明显,那就是变量的类型信息不见了,经常搞不清楚方法的参数要传入什么,返回什么,挺不习惯的。

6.就因为缺少类型信息,Python的文档也没有Java的可读性强。比如java的 String foo(int a)一看就知道传入整形返回字符串,换成Python就变成了 foo(a),只能读文档才能搞清楚了。可能我还没习惯的原因吧,感觉有时文档对它们的类型也说的不太清楚。

总体感觉Python一些风格像C。写起代码来,感觉很快,很清楚,还是很不错的 I love the feeling :)


看看我写的Stack

posted @ 2006-03-09 20:31 shaofan 阅读(1035) | 评论 (0)编辑 收藏

     摘要: 过去的一年,Mustang 没能出来,EJB3刚刚才提交最终草案,Ajax兴起但是五花八门不知道应该用谁,Aspectj 5出来了,但是缺乏惊喜。
或许我们会说,过去的2005,Java界缺乏成绩,但是却毫无疑问,Java遥遥领先于其他语言。从11月的语言排行榜Java遥遥领先,到今年的Java图书销售统计上,Java图书销售总数是C#的2倍,PHP的2.5倍,Perl的4倍,Ruby/Python的9倍.
这足以让我们对2006充满想象。
不过,还是让我们先回顾下2005吧....  阅读全文

posted @ 2006-03-07 09:56 shaofan 阅读(493) | 评论 (0)编辑 收藏

     摘要: 总感觉只会JAVA似乎不够,不记得是哪位先人说的了,一个程序员起码要精通两门语言,所以这些天花了不少时间琢磨python,看了不少网站,查了不少资料,正想着把一些东西写下来,以免日后忘了,也可以和大家分享.先写一些下载安装和学习资源的东东.  阅读全文

posted @ 2006-03-05 09:30 shaofan 阅读(5345) | 评论 (7)编辑 收藏

     摘要: Design by Contract (DbC)的概念已经出现很长时间了,最先是在Eiffel的一个特色,通过DbC来提高软件质量,目前很多语言也都有相应的实现,但是在GOOGLE上搜索中文网页,得到的资源并不是很多.直觉上来说,DbC确实是一个很好的想法,本着拓宽眼界的原则,就简单了解一下吧.  阅读全文

posted @ 2006-03-02 00:55 shaofan 阅读(2053) | 评论 (4)编辑 收藏

        今天试着把大虾写的系统登录模块加到我们现有的模块里来,他写的时候因为有些试验的成分,所以没有按照我们项目的配置来写,也没有按照我们的模块来划分配置,加过来以后重新配置了模块信息,结果居然无法正常运行。显示错误:“cannot retrieve action mapping  。废了九牛二虎之力,都无法解决。web.xml、struts-config、模块配置,一切看起来都无比的正常,但就是运行不了。真搞不清楚是哪里出了问题。还以为搞不定,晚上要加班了,谁知道,踏破铁鞋无觅处,柳暗花明又一村,在google上搜索关键字"action mapping 找不到",第一个链接居然就是问题的答案!(还从来没有只点一次就可以找到问题答案的经验,所以兴奋无比^O^)

        总的来说,问题的原因就在于,struts是在第一次收到对action的请求(注意:不包括jsp的请求)时,提取这个请求的url的路径信息,把相应模块的mapping信息设置到请求中去。如果在进入一个模块时,第一次访问的是一个jsp页面,而在这个jsp页面中提交到该模块的一个action,就会出现找不到action mapping的情况。这就是因为,在进到这个模块时,访问的是jsp,这个模块的任何一个action都没有被访问到,所以struts的ActionServlet还没有来得及把这个模块的mapping设置到请求中,自然找不到该模块的action。

        因此,这就引出一个约定,就是系统中尽量避免对Jsp的直接访问,如果要访问也要通过action来forward。虽然看起来麻烦一点,但是安全性、健壮性都会有所提高。

        关于以上提到的模块mapping的设置原理,具体的文章在这里(不长),值得收藏:

        原文链接:http://202.100.72.44/news/itschool/pro/pro44134.htm

posted @ 2006-03-01 10:44 shaofan 阅读(2048) | 评论 (5)编辑 收藏