每日一得

不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速开发
最近关心的内容:SSH,seam,flex,敏捷,TDD
本站的官方站点是:颠覆软件

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  220 随笔 :: 9 文章 :: 421 评论 :: 0 Trackbacks

2006年9月21日 #

     摘要: 你每天经常访问哪些站点?

你的收藏夹里有多少收藏的站点?  阅读全文
posted @ 2008-08-09 14:42 Alex 阅读(2364) | 评论 (2)编辑 收藏

     摘要: 上次参加open party朋友拿了一本《开源技术选型手册》,翻了一下,整理成脑图(图的效果还是比文字好哦)  阅读全文
posted @ 2008-08-06 10:30 Alex 阅读(2475) | 评论 (5)编辑 收藏

     摘要: 从svn版本上checkout出来的新的版本,dwr部分的xml配置文件是红色提示错误,一开始以为是jsp的普通验证错误,后发现不是那么回事。  阅读全文
posted @ 2008-08-04 15:00 Alex 阅读(1549) | 评论 (0)编辑 收藏

1.很多人喜欢用代码开发工具的debug功能来跟踪问题,虽然最终可以解决问题,但是从方向或者思想上不建议这样做,我依然记得最初我的技术经理对我说过 “代码不是调出来的”。

2.不是调出来的那是怎么出来的呢? “写出来的。” 呵呵,别扭,但是想想看,是否有点道理?

3.从另一个层面,我们需要加强代码的规范的写法,这就好比设计,先尽量将设计(在敏捷的年代似乎谈设计不太入流,那么你可以认为那是一种思考吧)做的到位一点

4.回到一个大的命题:战略如果错误,执行的越快死的越快;同理,思路或者方向如果有问题,做的越带劲,你越难受。

5.让我们朝这个目标挺进:代码一次编写就通过! 我见过一些这样的高人,只要你努力,是可以做到的。

posted @ 2008-08-03 20:56 Alex 阅读(2432) | 评论 (23)编辑 收藏

     摘要: 又一阵热风吹过来了,犹如当初的asp,犹如近段时间的SOA  阅读全文
posted @ 2008-08-03 01:02 Alex 阅读(1986) | 评论 (2)编辑 收藏

     摘要:   阅读全文
posted @ 2008-07-03 14:13 Alex 阅读(1584) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2008-07-03 14:12 Alex 阅读(2946) | 评论 (1)编辑 收藏

     摘要:   阅读全文
posted @ 2008-07-03 14:11 Alex 阅读(3498) | 评论 (5)编辑 收藏

//本站点内容来自于 颠覆软件

1.机器的ip经常改变,到公司一个ip,到客户那一个ip,到家又是一个ip,不知怎么搞的,今天到家oracle的dbconsole就启动不了了.

2.用命令行的方式启动 emctl.bat start dbconsole,结果还提示ORACLE_SID 还没有设置,晕,这个怎么没有了,set 一个吧 set ORACLE_SID=dggmcc (我的数据库实例)

3.还是有错,提示找不到192.168.0.52.这个地址,应该是ip和当初装数据库的时候IP不一样的缘故,将hosts设置一下 192.168.0.52   IDEA

4.OK

posted @ 2008-07-03 14:10 Alex 阅读(1018) | 评论 (0)编辑 收藏

1.架构的分类:业务架构、数据库架构、软件设计架构,正在流行的所谓soa架构也算吧

2. 涉及到的主要内容:

  • 需求分析
  • 领域分析
  • UML建模
  • 文档设计管理
  • 设计模式
  • 基于javaEE5的设计(jsf+EJB3)[个人感觉jboss seam是最好的代表了]

3.今天一同事说在网上看到统计数据说基于soa的架构做的项目比传统的做法成功率确实高,可能性是存在的,不过也不排除这些统计数据是某些大厂赞助的结果 :)

4.今年打算有机会的话培训一下软件设计师的课程,内容摘要如下:(来自国信培训)

一、面向对象分析设计与UML

Ø 面向对象分析与设计OOAD

Ø UML建模与ICONIX进程

Ø 领域建模与用例建模

Ø 需求分析与UseCase

Ø 健壮性分析

Ø 时序图

Ø 对象图、状态图、活动图与协作图

Ø 类图、包图与组件图

Ø 部署图

Ø UMLRUP

Ø 设计进度和设计粒度的控制

二、设计模式

Ø GOF设计模式

Ø 创建型模式

Ø 结构型模式

Ø 行为型模式

Ø 模式扩展

Ø 开源项目中的设计模式

Ø 模式与交流

三、软件设计管理

Ø 软件设计文档

Ø 软件流程改进策略

Ø 软件设计风险管理

四、相关软件设计案例集

posted @ 2008-07-03 14:08 Alex 阅读(1559) | 评论 (0)编辑 收藏

//本站点内容来自于www.foxlog.org


1.中国还没有真正伟大的软件公司,就当自己做一下白日梦了

2.需要一个协同软件,比如oracle协作套件,或者IBM的Lotus,目的,提供邮件、文档、工作空间、门户、网络会议、移动办公等,让公司的所有资源在一个统一的平台上实施;当然,出于成本考虑,我也可以选择google的企业套件,最直接的方式了,而且效果不错,不过没有网络会议和门户功能,可以考虑使用webEx等 (近期,流行的一个观点是在协作平台里引入web2.0的相关技术)

3.需要一个学习平台,比如oracle ilearing.用于员工的入职须知,技能培训,为学习型组织提供一个最有力的帮助,最大的问题可能不是学习平台本身,而是学习内容的规划和设计,必要的时候需要购买 .  学习平台最终的目的就是一是培训员工,另一个就是知识共享。现在很多公司有这么一个毛病,公司运营了很多年,但是随着员工的逐步更换和流失,很多以前精华的东西都不见了,如果主意了知识的共享和积累(通过软件平台),这个问题就是另一种情况了.

4.需要一个 oa平台,主要基于公司的业务流程,目前大多数oa是基于工作流的机制来实现。事实上,oa的发展历程已经比较长了,也相对比较成熟,但是究竟能发挥多大作用或者该如何发挥最大的作用还依然是一个问题。

5.建立一个项目管理系统平台,所有项目都在上面监控,它应该是动态的,可以看到每一天的进度,最好能从上面能对项目的各个组员的工作作出评估,作出即时的沟通和修正。

6.软件开发过程系统:包含架构设计管理、开发动态控制管理、版本控制、测试管理 .这些内容的主要目的是保证开发的规范话、文档化

7.会议系统管理. 每个公司都需要开会,但是开会的层次差别太大了,存在的问题主要有:会议目标不明确,会议过程没有效率,会议结果不明确,会议结束后没有后期跟踪管理.关于这方面可以推荐一篇文章 九段秘书

8.以上好像偏重于技术的层面比较多,实际上一个公司的老总最看重的其实必然是市场,所以一个适合自己公司的ERP或者CRM系统也许是必要的,注意,我这里说的是也许。

9.最后,所有的软件仅仅提供了一个平台,它是“死”的,或者说其本身并不会发生什么作用,更关键的是看不见的“软件”——企业文化,一切的效率与创新都来自于公司的文化氛围,在这个基础上,软件才会有推波助澜的作用。

posted @ 2008-07-03 14:07 Alex 阅读(1056) | 评论 (3)编辑 收藏

     摘要: 很多东西是拿来被利用的,被 Fuck的,不是让你消磨时间的.  阅读全文
posted @ 2007-09-01 12:42 Alex 阅读(2534) | 评论 (5)编辑 收藏

     摘要: 项目,是一个范围很广的概念,三峡大坝是一个项目,IT企业的一次开发任务也是一个项目,个人某个时间段的活动安排仍然可以看作是一个项目.

  阅读全文
posted @ 2007-08-19 13:15 Alex 阅读(1801) | 评论 (7)编辑 收藏

     摘要: 经常用到update语句,不过很少用到其他表的数据来更新当前表,这次用到了,总结一下

  阅读全文
posted @ 2007-08-19 12:49 Alex 阅读(2242) | 评论 (1)编辑 收藏

key words: plsql,导出数据,大数据量

最近的账务的项目中需要导出Excel报表,数据量比较大,解决方案如下 :

1.通过plsql在服务器端查询出符合要求的纪录,然后直接写到文本文件中

2.在web端通过流的方式读文本文件,通过POI写到Excel,将生成的Excel流写到respoonse实现下载

这样做的好处是不必一次性将满足条件的纪录全部取出来,而是通过流的方式.

这个方式原来在处理Blob类型的字段时有直接的getStream来支持的,这次普通的数据只好通过文件的方式来实现.

贴一段sample的代码


sql 代码
 
  1. create or replace procedure alex_table_to_txt(filepath varchar2,filename varchar2) is  
  2. --var  
  3. v1 alex2.name%type;  
  4. v2 alex2.address%type;  
  5. v3 alex2.groupname%type;  
  6.   
  7. output varchar2(200);  
  8.   
  9. --file var  
  10. file_handle UTL_FILE.FILE_TYPE;  
  11.   
  12. cursor readtable is select t.name,t.address,t.groupname from alex2 t;  
  13. begin  
  14. file_handle:=utl_file.fopen(filepath,filename,'w',6000);  
  15. open readtable;  
  16.   
  17. loop  
  18. fetch readtable into v1,v2,v3;  
  19. exit when readtable%notfound;  
  20. output:=v1 || ',' || v2 || ',' || v3 ;  
  21. utl_file.put_line(file_handle,output);  
  22.   
  23. end loop;  
  24.   
  25. close readtable;  
  26. utl_file.fclose(file_handle);  
  27. end alex_table_to_txt;  
  28. /  

 

欢迎讨论你的方案

posted @ 2007-08-18 12:46 Alex 阅读(4248) | 评论 (1)编辑 收藏

     摘要: 一般来说,我们碰到问题都是无非google,看相关文档,请教专家,问圈子里的朋友,等等。我这里说的主要是个人自己的解决思路。

  阅读全文
posted @ 2007-08-18 12:17 Alex 阅读(1353) | 评论 (2)编辑 收藏

好久没有来这里了,blogjava的朋友们你们还好吗。

我的 blog搬家了,以后将主要在这里维护: www.foxlog.org 

需要和我交换连接的朋友请联系我 mail to me :  idea.wang@gmail.com,或者在我 blog留言
http://www.foxlog.org/%E7%BB%99%E6%88%91%E7%95%99%E8%A8%80
posted @ 2007-07-27 15:21 Alex 阅读(655) | 评论 (0)编辑 收藏

1.查看系统Swap空间使用

[root@jumper usr]# free
             total       used       free     shared    buffers     cached
Mem:        513980     493640      20340          0     143808     271780
-/+ buffers/cache:      78052     435928
Swap:      1052248      21256    1030992

2.在空间合适处创建swap文件

[root@jumper usr]# mkdir swap
[root@jumper usr]# cd swap
[root@jumper swap]# dd if=/dev/zero of=swapfile bs=1024 count=10000
10000+0 records in
10000+0 records out
[root@jumper swap]# ls -al
total 10024
drwxr-xr-x    2 root     root         4096  7月 28 14:58 .
drwxr-xr-x   19 root     root         4096  7月 28 14:57 ..
-rw-r--r--    1 root     root     10240000  7月 28 14:58 swapfile


[root@jumper swap]# mkswap swapfile
Setting up swapspace version 1, size = 9996 KiB


3.激活swap文件
[root@jumper swap]# swapon swapfile
[root@jumper swap]# ls -l
total 10016
-rw-r--r--    1 root     root     10240000  7月 28 14:58 swapfile
[root@jumper swap]# free
             total       used       free     shared    buffers     cached
Mem:        513980     505052       8928          0     143900     282288
-/+ buffers/cache:      78864     435116
Swap:      1062240      21256    1040984
[root@jumper swap]#  

 

 

Swap,即交换区,除了安装Linux的时候,有多少人关心过它呢?其实,Swap的调整对Linux服务器,特别是Web服务器的性能至关重要。通过调整Swap,有时可以越过系统性能瓶颈,节省系统升级费用。 

本文内容包括: 


Swap基本原理 

突破128M Swap限制 

Swap配置对性能的影响 

Swap性能监视 

有关Swap操作的系统命令 
Swap基本原理 

Swap的原理是一个较复杂的问题,需要大量的篇幅来说明。在这里只作简单的介绍,在以后的文章中将和大家详细讨论Swap实现的细节。 

众所周知,现代操作系统都实现了"虚拟内存"这一技术,不但在功能上突破了物理内存的限制,使程序可以操纵大于实际物理内存的空间,更重要的是,"虚拟内存"是隔离每个进程的安全保护网,使每个进程都不受其它程序的干扰。 

Swap 空间的作用可简单描述为:当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap空间中,等到那些程序要运行时,再从Swap中恢复保存的数据到内存中。这样,系统总是在物理内存不够时,才进行Swap交换。 

计算机用户会经常遇这种现象。例如,在使用Windows系统时,可以同时运行多个程序,当你切换到一个很长时间没有理会的程序时,会听到硬盘"哗哗"直响。这是因为这个程序的内存被那些频繁运行的程序给"偷走"了,放到了Swap区中。因此,一旦此程序被放置到前端,它就会从Swap区取回自己的数据,将其放进内存,然后接着运行。 

需要说明一点,并不是所有从物理内存中交换出来的数据都会被放到Swap中(如果这样的话,Swap就会不堪重负),有相当一部分数据被直接交换到文件系统。例如,有的程序会打开一些文件,对文件进行读写(其实每个程序都至少要打开一个文件,那就是运行程序本身),当需要将这些程序的内存空间交换出去时,就没有必要将文件部分的数据放到 Swap空间中了,而可以直接将其放到文件里去。如果是读文件操作,那么内存数据被直接释放,不需要交换出来,因为下次需要时,可直接从文件系统恢复;如果是写文件,只需要将变化的数据保存到文件中,以便恢复。但是那些用malloc和new函数生成的对象的数据则不同,它们需要Swap空间,因为它们在文件系统中没有相应的"储备"文件,因此被称作"匿名"(Anonymous)内存数据。这类数据还包括堆栈中的一些状态和变量数据等。所以说,Swap 空间是"匿名"数据的交换空间。 

突破128M Swap限制 

经常看到有些Linux(国内汉化版)安装手册上有这样的说明:Swap空间不能超过128M。为什么会有这种说法?在说明"128M"这个数字的来历之前,先给问题一个回答:现在根本不存在128M的限制!现在的限制是2G! 

Swap 空间是分页的,每一页的大小和内存页的大小一样,方便Swap空间和内存之间的数据交换。旧版本的Linux实现Swap空间时,用Swap空间的第一页作为所有Swap空间页的一个"位映射"(Bit map)。这就是说第一页的每一位,都对应着一页Swap空间。如果这一位是1,表示此页Swap可用;如果是0,表示此页是坏块,不能使用。这么说来,第一个Swap映射位应该是0,因为,第一页Swap是映射页。另外,最后10个映射位也被占用,用来表示Swap的版本(原来的版本是Swap_space ,现在的版本是swapspace2)。那么,如果说一页的大小为s,这种Swap的实现方法共能管理"8 * ( s - 10 ) - 1"个Swap页。对于i386系统来说s=4096,则空间大小共为133890048,如果认为 1 MB=2^20 Byte的话,大小正好为128M。 

之所以这样来实现Swap空间的管理,是要防止Swap空间中有坏块。如果系统检查到Swap中有坏块,则在相应的位映射上标记上0,表示此页不可用。这样在使用Swap时,不至于用到坏块,而使系统产生错误。 

现在的系统设计者认为: 

1.现在硬盘质量很好,坏块很少。 

2.就算有,也不多,只需要将坏块罗列出来,而不需要为每一页建立映射。 

3.如果有很多坏块,就不应该将此硬盘作为Swap空间使用。 

于是,现在的Linux取消了位映射的方法,也就取消了128M的限制。直接用地址访问,限制为2G。 

Swap配置对性能的影响 

分配太多的Swap空间会浪费磁盘空间,而Swap空间太少,则系统会发生错误。 

如果系统的物理内存用光了,系统就会跑得很慢,但仍能运行;如果Swap空间用光了,那么系统就会发生错误。例如,Web服务器能根据不同的请求数量衍生出多个服务进程(或线程),如果Swap空间用完,则服务进程无法启动,通常会出现"application is out of memory"的错误,严重时会造成服务进程的死锁。因此Swap空间的分配是很重要的。 

通常情况下,Swap空间应大于或等于物理内存的大小,最小不应小于64M,通常Swap空间的大小应是物理内存的2-2.5倍。但根据不同的应用,应有不同的配置:如果是小的桌面系统,则只需要较小的Swap空间,而大的服务器系统则视情况不同需要不同大小的Swap空间。特别是数据库服务器和Web服务器,随着访问量的增加,对Swap空间的要求也会增加,具体配置参见各服务器产品的说明。 

另外,Swap分区的数量对性能也有很大的影响。因为Swap交换的操作是磁盘IO的操作,如果有多个 Swap交换区,Swap空间的分配会以轮流的方式操作于所有的Swap,这样会大大均衡IO的负载,加快Swap交换的速度。如果只有一个交换区,所有的交换操作会使交换区变得很忙,使系统大多数时间处于等待状态,效率很低。用性能监视工具就会发现,此时的CPU并不很忙,而系统却慢。这说明,瓶颈在 IO上,依靠提高CPU的速度是解决不了问题的。 
系统性能监视 

Swap空间的分配固然很重要,而系统运行时的性能监控却更加有价值。通过性能监视工具,可以检查系统的各项性能指标,找到系统性能的瓶颈。本文只介绍一下在Solaris下和Swap相关的一些命令和用途。 

最常用的是Vmstat命令(在大多数Unix平台下都有这样一些命令),此命令可以查看大多数性能指标。 

例如: 
# vmstat 3 
procs memory swap io system cpu 
r b w swpd free buff cache si so bi bo in cs us sy id 
0 0 0 0 93880 3304 19372 0 0 10 2 131 10 0 0 99 
0 0 0 0 93880 3304 19372 0 0 0 0 109 8 0 0 100 
0 0 0 0 93880 3304 19372 0 0 0 0 112 6 0 0 100 
............ 

命令说明: 
vmstat 后面的参数指定了性能指标捕获的时间间隔。3表示每三秒钟捕获一次。第一行数据不用看,没有价值,它仅反映开机以来的平均性能。从第二行开始,反映每三秒钟之内的系统性能指标。这些性能指标中和Swap有关的包括以下几项: 


procs下的w 
它表示当前(三秒钟之内)需要释放内存、交换出去的进程数量。 

memory下的swpd 
它表示使用的Swap空间的大小。 

Swap下的si,so 
si表示当前(三秒钟之内)每秒交换回内存(Swap in)的总量,单位为kbytes;so表示当前(三秒钟之内)每秒交换出内存(Swap out)的总量,单位为kbytes。 
以上的指标数量越大,表示系统越忙。这些指标所表现的系统繁忙程度,与系统具体的配置有关。系统管理员应该在平时系统正常运行时,记下这些指标的数值,在系统发生问题的时候,再进行比较,就会很快发现问题,并制定本系统正常运行的标准指标值,以供性能监控使用。 

另外,使用Swapon-s也能简单地查看当前Swap资源的使用情况。例如: 
# swapon -s 
Filename Type Size Used Priority 
/dev/hda9 partition 361420 0 3 

能够方便地看出Swap空间的已用和未用资源的大小。 

应该使Swap负载保持在30%以下,这样才能保证系统的良好性能。 

有关Swap操作的系统命令 


增加Swap空间,分以下几步: 
1)成为超级用户 
$su - root 

2)创建Swap文件 
# dd if=/dev/zero of=swapfile bs=1024 count=65536 

创建一个有连续空间的交换文件。 

3)激活Swap文件 
#/usr/sbin/swapon swapfile 

swapfile指的是上一步创建的交换文件。 4)现在新加的Swap文件已经起作用了,但系统重新启动以后,并不会记住前几步的操作。因此要在/etc/fstab文件中记录文件的名字,和Swap类型,如: 
/path/swapfile none Swap sw,pri=3 0 0 

5)检验Swap文件是否加上 
/usr/sbin/swapon -s 


删除多余的Swap空间。 
1)成为超级用户 

2)使用Swapoff命令收回Swap空间。 
#/usr/sbin/swapoff swapfile 

3)编辑/etc/fstab文件,去掉此Swap文件的实体。 

4)从文件系统中回收此文件。 
#rm swapfile 

5)当然,如果此Swap空间不是一个文件,而是一个分区,则需创建一个新的文件系统,再挂接到原来的文件系统上。

posted @ 2007-06-18 14:27 Alex 阅读(1011) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-06-13 16:43 Alex 阅读(3738) | 评论 (4)编辑 收藏


come from here

如果将需求分析阶段的工作归结为编写需求规格说明书,这种简化的做法往往是导致项目后期层出不穷问题的罪魁祸首。建议采用以下步骤形成软件需求:获取用户需求→分析用户需求→编写需求文档→评审需求文档→管理需求。下面我们先来讨论前两个步骤(获取用户需求、分析用户需求)的做法。

获取用户需求

  这是该阶段的一个最重要的任务。以下为获取用户需求需要执行的活动(如图1所示)。

  ● 了解客户方的所有用户类型以及潜在的类型。然后,根据他们的要求来确定系统的整体目标和系统的工作范围。

  ● 对用户进行访谈和调研。交流的方式可以是会议、电话、电子邮件、小组讨论、模拟演示等不同形式。需要注意的是,每一次交流一定要有记录,对于交流的结果还可以进行分类,便于后续的分析活动。例如,可以将需求细分为功能需求、非功能需求(如响应时间、平均无故障工作时间、自动恢复时间等)、环境限制、设计约束等类型。

  ● 需求分析人员对收集到的用户需求做进一步的分析和整理。下面是几条常见的准则:

  ⑴对于用户提出的每个需求都要知道“为什么”,并判断用户提出的需求是否有充足的理由;

  

  图1 获取用户需求的活动

  ⑵将那种以“如何实现”的表述方式转换为“实现什么”的方式,因为需求分析阶段关注的目标是“做什么”,而不是“怎么做”;

  ⑶分析由用户需求衍生出的隐含需求,并识别用户没有明确提出来的隐含需求(有可能是实现用户需求的前提条件),这一点往往容易忽略掉,经常因为对隐含需求考虑得不够充分而引起需求变更。

  ● 需求分析人员将调研的用户需求以适当的方式呈交给用户方和开发方的相关人员。大家共同确认需求分析人员所提交的结果是否真实地反映了用户的意图。需求分析人员在这个任务中需要执行下述活动:

  ⑴明确标识出那些未确定的需求项(在需求分析初期往往有很多这样的待定项);

  ⑵使需求符合系统的整体目标;

  ⑶保证需求项之间的一致性,解决需求项之间可能存在的冲突。

分析用户需求

  在很多情形下,分析用户需求是与获取用户需求并行的,主要通过建立模型的方式来描述用户的需求,为客户、用户、开发方等不同参与方提供一个交流的渠道。这些模型是对需求的抽象,以可视化的方式提供一个易于沟通的桥梁。用户需求的分析与获取用户需求有着相似的步骤,区别在于分析用户需求时使用模型来描述,以获取用户更明确的需求。分析用户需求需要执行下列活动:

  ● 以图形表示的方式描述系统的整体结构,包括系统的边界与接口;

  ● 通过原型、页面流或其它方式向用户提供可视化的界面,用户可以对需求做出自己的评价;

  ● 系统可行性分析,需求实现的技术可行性、环境分析、费用分析、时间分析等;

  ● 以模型描述系统的功能项、数据实体、外部实体、实体之间的关系、实体之间的状态转换等方面的内容。

  

  图2 DFD示意图

  用于需求建模的方法有很多种,最常用的包括数据流图(DFD)、实体关系图(ERD)和用例图(Use Case)三种方式。DFD作为结构化系统分析与设计的主要方法,已经得到了广泛的应用,DFD尤其适用于MIS系统的表述。DFD使用四种基本元素来描述系统的行为,过程、实体、数据流和数据存储。DFD方法直观易懂,使用者可以方便地得到系统的逻辑模型和物理模型,但是从DFD图中无法判断活动的时序关系。图2描述的是某个项目的DFD示意图。

  ERD方法用于描述系统实体间的对应关系,需求分析阶段使用ERD描述系统中实体的逻辑关系,在设计阶段则使用ERD描述物理表之间的关系。需求分析阶段使用ERD来描述现实世界中的对象。ERD只关注系统中数据间的关系,而缺乏对系统功能的描述。如果将ERD与DFD两种方法相结合,则可以更准确地描述系统的需求。

  在面向对象分析的方法中通常使用Use Case来获取软件的需求。Use Case通过描述“系统”和“活动者”之间的交互来描述系统的行为。通过分解系统目标,Use Case描述活动者为了实现这些目标而执行的所有步骤。Use Case方法最主要的优点,在于它是用户导向的,用户可以根据自己所对应的Use Case来不断细化自己的需求。此外,使用Use Case还可以方便地得到系统功能的测试用例。

编写需求文档

  需求文档可以使用自然语言或形式化语言来描述,还可以添加图形的表述方式和模型表征的方式。需求文档应该包括用户的所有需求(功能性需求和非功能性需求)。

评审需求文档

  需求文档完成后,需要经过正式评审,以便作为下一阶段工作的基础。一般的评审分为用户评审和同行评审两类。用户和开发方对于软件项目内容的描述,是以需求规格说明书作为基础的;用户验收的标准则是依据需求规格说明书中的内容来制订,所以评审需求文档时用户的意见是第一位的。而同行评审的目的,是在软件项目初期发现那些潜在的缺陷或错误,避免这些错误和缺陷遗漏到项目的后续阶段。

管理需求

  

  图1 需求变更流程

  需求的变更是不可避免的,如何以可控的方式管理软件的需求,对于项目的顺利进行有着重要的意义。如果匆匆忙忙地完成用户调研与分析,则往往意味着不稳定的需求。所以需求管理要保证需求分析各个活动都得到了充分的执行。对于需求变更的管理,则主要使用需求变更流程和需求跟踪矩阵的管理方式。需求变更流程和需求跟踪矩阵分别如图1和图2所示。

  

  图2 需求跟踪矩阵

  常见问题及建议

  Q、客户与最终用户的区别是什么?

  A、可以借助图3来说明它们之间的区别。

  

  图3 需求获取渠道示意图

  软件需求来自系统工程与客户两个方面,其中客户是主要的需求提供者(系统工程需求也来自于客户)。客户需要搜集其最终用户的需求并考虑自身的需求,然后再提供给开发方。假如客户并未去认真搜集最终用户的需求,开发方便需要做到这一点,因为系统最终要满足最终用户的需求。

  Q、如何进行用户访谈?

  A、首先,一定要事先确定访谈的目的和提纲。其次,因为用户往往并不知道应该提供哪些方面的需求,所以需要开发人员引导。

  Q、用户访谈内容是什么?

  A、首先,请用户描述他们如何完成自己当前的工作,并与用户一起抽象出一个工作流程或工作模型。然后,在得到用户的认可后,向用户解释自己是怎样来实现这些功能的,并说明哪些环节可以用自动化方式实现等。

  Q、采用哪一种方式做需求分析最好?

  A、不同的需求分析有不同的特点。还没有哪一种方法可以完全替代别的方法,否则,现在就不会存在不同的需求建模方式了。一般来说,可以使用DFD+ERD来描述那些功能层次比较清晰的需求;而USE CASE则适于描述功能结构复杂的需求。做需求分析的目的是为了建立需求的模型,不同的子系统有可能使用不同的建模方法。

  Q、怎样做原型,原型的目的是什么?

  A、通常使用原型分析方法来帮助开发方进一步获取用户需求或让用户确认需求。开发方往往先向用户提供一个可视界面作为原型,并在界面上布置必要的元素以演示用户所需要的功能。可以使用第四代语言(例如Visual Basic、Delphi等)来快速生成用户界面,也可以使用FrontPage等网页制作工具来生成用户可视的页面流。

  原型的目的往往是获取需求。但有时也使用原型的方式来验证关键技术或技术难点。对于技术原型,界面则往往被忽略掉。

posted @ 2007-06-12 17:47 Alex 阅读(982) | 评论 (0)编辑 收藏

echo "begin to start oracle"
lsnrctl start
sqlplus /nolog 
<<EOF
connect /as sysdba
startup
exit
exit
echo "oracle have started"
posted @ 2007-06-12 09:13 Alex 阅读(1145) | 评论 (0)编辑 收藏

已经打印了,晚上看一下,感觉不错。

download

posted @ 2007-06-11 18:24 Alex 阅读(664) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-06-04 00:18 Alex 阅读(2070) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-06-02 11:50 Alex 阅读(962) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-05-29 11:32 Alex 阅读(1485) | 评论 (5)编辑 收藏

     摘要:   阅读全文
posted @ 2007-05-24 09:52 Alex 阅读(1205) | 评论 (2)编辑 收藏

     摘要:   阅读全文
posted @ 2007-05-14 09:05 Alex 阅读(13369) | 评论 (8)编辑 收藏

     摘要:   阅读全文
posted @ 2007-05-13 17:15 Alex 阅读(1921) | 评论 (3)编辑 收藏

     摘要:   阅读全文
posted @ 2007-05-13 16:41 Alex 阅读(5645) | 评论 (13)编辑 收藏

key words: jstl,struts,log4j

1.jstl
jstl的配置参考这篇文章:
http://foolmouse.cnblogs.com/archive/2006/04/20/380695.html

在iAS904服务器上的jstl的版本只能用1.0 的
"standard.jar和jstl.jar文件拷贝到\WEB-INF\lib\
"

2.struts
struts的配置主要是把 相关jar文件(struts.jar,struts-legacy.jar)拷贝到\WEB-INF\lib
,另外,struts需要用到一些apache的commons的包(commons-beanutils.jar,commons-collections-2.1.1.jar,commons-digester.jar)

3.log4j
log4j经常有莫名其妙的问题,有时候能出来log有时候又不能出来log,最后把log4j.xml统一改为log4j.properties,暂时看好像有效果。

4。web.xml配置

<taglib>
        
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
        
<taglib-location>/WEB-INF/c-1_0.tld</taglib-location>
    
</taglib>
    
<taglib>
        
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
        
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
    
</taglib>
    
<taglib>
        
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
        
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
    
</taglib>
    
<taglib>
        
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
        
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
    
</taglib>


今天终于先在iAS里部署完了struts,下一步把hibernate放进去,上次部署过一次,没有成功,据说是和toplink有点冲突。 知道的兄弟分享下oc4j中部署hibernate
posted @ 2007-05-08 19:11 Alex 阅读(1341) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-04-11 16:09 Alex 阅读(7782) | 评论 (8)编辑 收藏

     摘要:   阅读全文
posted @ 2007-03-30 08:34 Alex 阅读(805) | 评论 (0)编辑 收藏

key words: contentType,meta

come from here


 

在经典同时看到两个关于ContentType的问题

http://bbs.blueidea.com/thread-2729935-1-1.html

http://bbs.blueidea.com/thread-2729945-1-1.html

所以查了下资料,copy了一份详细的ContentType的列表

 

不同的ContentType 会影响客户端所看到的效果.

默认的ContentType为 text/html  也就是网页格式.

代码如:

<% response.ContentType ="text/html" %> 
<!--#i nclude virtual="/ContentType.html" -->

显示的为网页,而

<% response.ContentType ="text/plain" %> 
<!--#i nclude virtual="/sscript/ContentType.html" -->

则会显示html原代码.

以下为一些常用的 ContentType

GIF images
<% response.ContentType ="image/gif" %> 
<!--#i nclude virtual="/myimage.gif" -->
JPEG images
<% response.ContentType ="image/jpeg" %> 
<!--#i nclude virtual="/myimage.jpeg" -->
TIFF images
<% response.ContentType ="image/tiff" %> 
<!--#i nclude virtual="/myimage.tiff" -->
MICROSOFT WORD document
<% response.ContentType ="application/msword" %> 
<!--#i nclude virtual="/myfile.doc" -->
RTF document
<% response.ContentType ="application/rtf" %> 
<!--#i nclude virtual="/myfile.rtf" -->
MICROSOFT EXCEL document
<% response.ContentType ="application/x-excel" %> 
<!--#i nclude virtual="/myfile.xls" -->
MICROSOFT POWERPOINT document
<% response.ContentType ="application/ms-powerpoint" %> 
<!--#i nclude virtual="/myfile.pff" -->
PDF document
<% response.ContentType ="application/pdf" %> 
<!--#i nclude virtual="/myfile.pdf" -->
ZIP document
<% response.ContentType ="application/zip" %> 
<!--#i nclude virtual="/myfile.zip" -->

 

下面是更详细的ContentType

application/andrew-insetez
application/mac-binhex40hqx
application/mac-compactprocpt
application/mathml+xmlmathml
application/msworddoc
application/octet-streambin dms lha lzh exe class so dll
application/odaoda
application/oggogg
application/pdfpdf
application/postscriptai eps ps
application/rdf+xmlrdf
application/smilsmi smil
application/srgsgram
application/srgs+xmlgrxml
application/vnd.mifmif
application/vnd.mozilla.xul+xmlxul
application/vnd.ms-excelxls
application/vnd.ms-powerpointppt
application/vnd.wap.wbxmlwbxml
application/vnd.wap.wmlc.wmlc wmlc
application/vnd.wap.wmlscriptc.wmlsc wmlsc
application/voicexml+xmlvxml
application/x-bcpiobcpio
application/x-cdlinkvcd
application/x-chess-pgnpgn
application/x-cpiocpio
application/x-cshcsh
application/x-directordcr dir dxr
application/x-dvidvi
application/x-futuresplashspl
application/x-gtargtar
application/x-hdfhdf
application/x-httpd-php.php .php4 .php3 .phtml
application/x-httpd-php-source.phps
application/x-javascriptjs
application/x-koanskp skd skt skm
application/x-latexlatex
application/x-netcdfnc cdf
application/x-pkcs7-crl.crl
application/x-shsh
application/x-sharshar
application/x-shockwave-flashswf
application/x-stuffitsit
application/x-sv4cpiosv4cpio
application/x-sv4crcsv4crc
application/x-tar.tgz tar
application/x-tcltcl
application/x-textex
application/x-texinfotexinfo texi
application/x-trofft tr roff
application/x-troff-manman
application/x-troff-meme
application/x-troff-msms
application/x-ustarustar
application/x-wais-sourcesrc
application/x-x509-ca-cert.crt
application/xhtml+xmlxhtml xht
application/xmlxml xsl
application/xml-dtddtd
application/xslt+xmlxslt
application/zipzip
audio/basicau snd
audio/midimid midi kar
audio/mpegmpga mp2 mp3
audio/x-aiffaif aiff aifc
audio/x-mpegurlm3u
audio/x-pn-realaudioram rm
audio/x-pn-realaudio-pluginrpm
audio/x-realaudiora
audio/x-wavwav
chemical/x-pdbpdb
chemical/x-xyzxyz
image/bmpbmp
image/cgmcgm
image/gifgif
image/iefief
image/jpegjpeg jpg jpe
image/pngpng
image/svg+xmlsvg
image/tifftiff tif
image/vnd.djvudjvu djv
image/vnd.wap.wbmp.wbmp wbmp
image/x-cmu-rasterras
image/x-iconico
image/x-portable-anymappnm
image/x-portable-bitmappbm
image/x-portable-graymappgm
image/x-portable-pixmapppm
image/x-rgbrgb
image/x-xbitmapxbm
image/x-xpixmapxpm
image/x-xwindowdumpxwd
model/igesigs iges
model/meshmsh mesh silo
model/vrmlwrl vrml
text/calendarics ifb
text/csscss
text/html.shtml html htm
text/plainasc txt
text/richtextrtx
text/rtfrtf
text/sgmlsgml sgm
text/tab-separated-valuestsv
text/vnd.wap.wml.wml wml
text/vnd.wap.wmlscript.wmls wmls
text/x-setextetx
video/mpegmpeg mpg mpe
video/quicktimeqt mov
video/vnd.mpegurlmxu
video/x-msvideoavi
video/x-sgi-moviemovie
x-conference/x-cooltalkice
posted @ 2007-03-29 09:25 Alex 阅读(1948) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-03-28 16:55 Alex 阅读(4567) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-03-26 22:18 Alex 阅读(36098) | 评论 (7)编辑 收藏

     摘要:   阅读全文
posted @ 2007-03-20 16:23 Alex 阅读(3377) | 评论 (1)编辑 收藏

key words : jsp防盗链 header

最近碰到盗链的问题,即复制一个url地址,在另一个地方也能访问。

index.jsp页面
<html>
  
<head><title>Simple jsp page</title></head>
  
<body>Place your content here

  here is index jsp
    get header info
  
<href="a.jsp">a.jsp</a>
  
</body>
</html>

a.jsp页面
<html>
  
<head><title>Simple jsp page</title></head>
  
<body>Place your content here

  here is a. jsp
    get header info
  
<%=request.getHeader("Referer")%>
  
<%if(null == request.getHeader("Referer") || request.getHeader("Referer").indexOf("yourdomain.com"< 0){%>
     做人要厚道
  
<%}else{%>
  合法访问
  
<%}%>
  
</body>
</html>


即从内部访问可以,直接粘贴地址在另一个浏览器里访问禁止
posted @ 2007-03-13 10:01 Alex 阅读(5926) | 评论 (8)编辑 收藏

     摘要:   阅读全文
posted @ 2007-03-12 00:40 Alex 阅读(12389) | 评论 (18)编辑 收藏

     摘要:   阅读全文
posted @ 2007-02-25 00:20 Alex 阅读(407) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2007-02-24 23:37 Alex 阅读(1891) | 评论 (2)编辑 收藏

key words: pd, powerdesigner,外建

在PD中建立外键碰到一个问题,如: forum(id,name)表,forum_thread(id,forum_id)表,需要将forum的id设为forum_thread的外建,指向forum_id,默认的在 PD中是将主键设为外建.

需要如下设置才可以:

foreign_key.png
posted @ 2007-01-31 10:42 Alex 阅读(1305) | 评论 (0)编辑 收藏

key words: 上传文件

目里面有上传文件的需求,我想了一下不外乎下面两种处理方法:

1. 在数据库表中建立一个blob字段存放用户上传文件.
2. 在服务器上建立一个文件夹保存用户上传文件,数据库表中只存放该文件的url地址.

我本人现在比较倾向于第2种方案, 主要原因是担心方案1的效率(我用的是mysql数据库)。 但是处理过程中除了维护数据库中表的字段还要维护上传的文件,稍微麻烦一点。

大家在项目里面又是怎么做呢? 给我点建议!谢谢


讨论内容见: javaeye

robin更建议第二种方案,放在数据库中主要的问题是 AppServer吃不消,开销比较大.

上面是摘录,不过我们这里用的是Oracle9i AS,在Oracle的协作套间里一般文档或者上传的文件都是保存在数据库里,还把这个特性作为Oracle 与别的协作套件之间不同的卖点。

大家以为如何? 我直觉是Oracle的DB和oc4j的AppServer对付这个似乎没有开销上的担心,但是没有实际检测过。

换句话说,文件的管理是放在文件夹里方便还是数据库里方便? 有点为难

update (2007-5-13):
还有一种方案结合了数据库和IO,我认为比较可行,就是文件存在数据库,但是下载的时候第一次从数据库下载,然后第一次这个文件保存在一个临时文件夹下面,以后每次下载的时候总是先检查此临时文件夹,如果已经存在则直接下载,如果没有则从数据库重复这个动作。当然,保存在临时文件夹下的文件的命名需要唯一,这个应该没有问题。
posted @ 2007-01-31 09:06 Alex 阅读(1953) | 评论 (4)编辑 收藏


这个年代的偶像很多,值得学习的也很多,,如果让我说,我觉得在现在这个急功近利的所谓2.0时代,阿甘精神更值得我们学习。

什么是阿甘精神?
1。奔跑。 不停的奔跑,不要停下来
2。不断地重复,如果你做的不够好,那就说明你还重复的不够多。
3。执着。 不要相信权威,按自己的意志去做。

现在,聪明的人很多,但是小聪明似乎更多,包括我。

你认可阿甘精神么? 如果是,顶一下。

刚看到关于阿甘精神的另一个有意思的摘录:



"
阿甘就是看到一个目标就走过去了,别的人是,看见一个目标,先订一个作战计划,然后匍匐前进,往左闪,往右躲,再弄个掩体…一辈子就看他闪转腾挪活得那叫一个花哨,最后哪儿也没到达。
"

很形象哦。

祝各位在2007年工作进步。

posted @ 2007-01-30 08:59 Alex 阅读(1222) | 评论 (2)编辑 收藏

key words: js,javascript,检查上传文件大小

有时需要在客户端获得待上传得文件大小,google了一下,发现下面这个用法.

<html>  
<input type="file" name="file1" onchange="ShowSize(this.value)">  
<script language="JavaScript">  
<!--  
function ShowSize(files)  
{  
  
var fso,f;  
  fso
=new ActiveXObject("Scripting.FileSystemObject");  
  f
=fso.GetFile(files);
  
var mySize = f.size/1024;
  alert(mySize
+" K ");  
}
  
//-->  
</script>  
</html>


BTW: 奇怪,COS上传组件里怎么没有获得上传文件大小的方法?  MultipartRequest里是没有,有知道的兄弟通知下哦
posted @ 2007-01-25 17:16 Alex 阅读(10410) | 评论 (4)编辑 收藏

     摘要: key words : hibernate spring daocome from : http://lpacec.javaeye.com/blog/46220   1.  package infoweb.dao;         2.         3. import java.util.List;         4. import java.util.Iterator;         5...  阅读全文
posted @ 2007-01-25 09:24 Alex 阅读(914) | 评论 (0)编辑 收藏

key words: REST webservice

转自廖宇雷的Weblog

REST 是由 Roy Fielding 在他的论文《Architectural Styles and the Design of Network-based Software Architectures》中提出的一个术语。

REST 是英文 Representational State Transfer 的缩写,有中文翻译为“具象状态传输”(参考:《SIP/IMS网络中的Representational State Transfer (REST)和数据分布》)。

—————————————

前面的内容比较枯燥,我说说我自己的理解。

但是 REST 到底是什么呢?论文我看不懂,不过找到一篇更简单易懂的东西:《Building Web Services the REST Way》

根据这篇文章,我整理了一下我自己对 REST 的理解:

REST 首先只是一种架构样式,不是一种标准。这点和 Ajax 类似,两者都是利用现有的成熟技术。

在 REST 的定义中,一个 Web 应用总是使用固定的 URI 向外部世界呈现(或者说暴露)一个资源

URI 是英文 Uniform Resource Identifier 的缩写,中文翻译“通用资源标志符”。

“通用资源标志符”是指唯一标识一个资源(xhtml 文件、图片、css 样式表)的字符串。当然了,RFC 中定义的 URI 复杂得多,不过我们此处将 URI 想象成一个人的身份证号码就行了(你不能有两个同时有效的身份证号码,一个号码也不可能同时对应两个人)。而我们天天挂在嘴边的 URL 地址就是 URI 的一种表现形式(个人理解,有错请纠正)。

知道什么是 URI 后,我们来看一个实际例子:

http://www.example.com/photo/logo 指向 example.com 网站(可以视为一个 Web 应用)中类型为 photo,名字为 logo 的资源。我们用浏览器访问这个 URI,看到的将可能是一个 xhtml 文档,其中用 <img src=”……” /> 来显示实际的照片。

http://www.example.com/photo/logo 很容易让你想到 URL 重写。事实上,这个地址很可能会在服务器内部处理为 http://www.example.com/photo.php?name=logo 这样的地址。photo.php 是服务器端的一个动态脚本文件,根据 name 参数生成 xhtml 文档返回给浏览器。

现在假设我们要获取这张照片的 XML 文档。XML 文档中包含照片的文件名、文件大小、拍摄日期等等信息。也就是说我们要获取“同一个资源的不同表现形式的数据”。对于这个要求,我们可以很容易的用另一个 URL 地址达到:http://www.example.com/xml/logo。

但是,这就违背了“URI 唯一标识一个资源”的定义。如果我们要获取同一个资源的多种表现形式,那么就要使用更多的 URL,从而给一个资源指定了多个不同的 URI。

而在 REST 中,不管是获取照片的 xhtml 文档还是 XML 文档,或者照片文件本身,都是用同一个 URI,就是 http://www.example.com/photo/logo。

那这是怎么办到的呢?Ruby On Rails 中是通过分辨 HTTP Request Header 信息来分辨客户端是想要取得资源的哪一种表现形式的数据。

当我们用浏览器访问一个网址时,浏览器会构造一个 HTTP 请求。这个请求有一个头信息,其中包括了本次请求接受何种类型的数据。通常浏览器发送的 HTTP 请求头中,Accept 的值都是 */*,也就说接受服务器返回的任何类型的数据。

看到这里,聪明的家伙应该知道了。只要我们指定一个特定的 Accept 参数,那么服务器就可以通过判断该参数来决定返回什么类型的数据。所以在一个采用 REST 架构的应用中,要获取同一个资源的不同表现形式的数据,只需要使用不同的 HTTP 请求头信息就行了。

如果考虑为 Web 应用增加 Web Services,这种技术的价值就体现出来了。比如我写了一个 Delphi 程序,现在只需要构造一个包含 Accept: text/xml 的 HTTP 请求头,然后将请求发送到 http://www.example.com/photo/logo 就可以了。返回的结果就是一个 XML 文档,而不是 xhtml 文档。

因为我们的 HTTP 请求头信息有不同的状态,从而可以获得不同的数据,所以叫做“具象状态传输” :)

—————————————

除了上面的用法,REST 还有进一步的扩展。

我们在 Web 应用中处理来自客户端的请求时,通常只考虑 GET 和 POST 这两种 HTTP 请求方法。实际上,HTTP 还有 HEAD、PUT、DELETE 等请求方法。而在 REST 架构中,用不同的 HTTP 请求方法来处理对资源的 CRUD(创建、读取、更新和删除)操作:

  • POST: 创建
  • GET: 读取
  • PUT: 更新
  • DELETE: 删除

经过这样的一番扩展,我们对一个资源的 CRUD 操作就可以通过同一个 URI 完成了:

http://www.example.com/photo/logo(读取)
仍然保持为 [GET] http://www.example.com/photo/logo

http://www.example.com/photo/logo/create(创建)
改为 [POST] http://www.example.com/photo/logo

http://www.example.com/photo/logo/update(更新)
改为 [PUT] http://www.example.com/photo/logo

http://www.example.com/photo/logo/delete(删除)
改为 [DELETE] http://www.example.com/photo/logo

从而进一步规范了资源标识的使用。

通过 REST 架构,Web 应用程序可以用一致的接口(URI)暴露资源给外部世界,并提供对资源的操作服务。这对于以资源为中心的 Web 应用来说非常重要。例如照片共享网站、用户社区等。

—————————————

Ruby On Rails 1.2 版对 REST 有很好的支持,但要在 PHP 中应用 REST 还需要解决不少问题:

  • 如何在服务端判断 PUT、DELETE 请求方法;
  • 如何获取用 PUT、DELETE 请求方法中传递的数据;
  • 如何获取 HTTP 请求头信息中的 Accept 参数值;
  • 如何在浏览器端发起 PUT 和 DELETE 请求。

不过我仔细看了 PHP 文档,我觉得上面几个问题都是可以解决的。

服务端综合使用 $_SERVER[’HTTP_ACCEPT’]、$_SERVER[’REQUEST_URI’]、$_SERVER[’REQUEST_METHOD’]、$_SERVER[’QUERY_STRING’] 这些变量应该可以搞定前面三个问题。而第四个问题则可以用 JavaScript 的 XMLHttpRequest 对象来实现。

不过我想 REST 的真正价值在于 Web Services,而不是通过浏览器操作的应用程序。

—————————————

参考:

posted @ 2007-01-23 08:30 Alex 阅读(445) | 评论 (0)编辑 收藏

key words : web快速开发

web快速开发是一个值得期待的东西,最早我接触过codecharge,是一个商业软件,功能据说很强大,我试用过,支持php,asp,jsp等多语言,但是感觉对java的支持不是很顺手,接着就是asp,这个好也不好,原因就不说了,因为我对java关注。

2. 接着就是dorado ,刚看到的,感觉也不错,有asp的风格,不过更适合j2ee的环境 ,这里是他们的在线演示demo,有兴趣的可以看一下

3. 最后,刚google了一下,Oracle也有一个基于Oracle数据库的快速开发产品  : APEX,基于浏览器做DB 开发,原来的名字叫做HTML DB,名字很直观,据说Oracle的metalink就是用这个实现的,应该功能不赖。

4.对了,再补充一个现在很热的,Ror,听说javaeye的网站要重新用ruby1.2开发,试用过一点,感觉确实令人震惊,值得关注。

java的技术其实是看着很热闹,比较大的东西也不少,但是真正关注web这一块的其实不多,无论是struts还是webwork,离我们所说的真正的“快速开发”的距离很远,而以上一些工具的出现也许会逐步改善j2ee在这一领域的现状。

我之所以对这个目前有点兴趣,确实有一种强烈的反差在折磨着我,因为我相信在j2ee的web开发里确实存在本来要开发1周多的工作量很可能用一个好的工具几个小时就搞定了,这是一件多么荒唐搞笑的事情?如果dorado在它的产品中真的能做到这样那我们的java开发那么坑吃坑吃的折腾个什么劲啊? 也许真的有奇迹,我宁愿相信有这样的奇迹。

大家有什么好的想法可以讨论一下。
posted @ 2007-01-20 22:56 Alex 阅读(3772) | 评论 (7)编辑 收藏

key words: powerdesign,power , design

引言:
发现powerdesign的文档真的是不多,不过powerdesign还是很有用的,见到此类文档就收藏下吧.

转自edeed

 附上一些使用pd11的心得:

1、安装PD v11.0版

2、由pdm生成建表脚本时,字段超过15字符就发生错误(oracle)
原因未知,解决办法是打开PDM后,会出现Database的菜单栏,进入Database - Edit Current DBMS -script-objects-column-maxlen,把value值调大(原为30),比如改成60。出现表或者其它对象的长度也有这种错误的话都可以选择对应的objects照此种方法更改!
或者使用下面的这种方法:
生成建表脚本时会弹出Database generation提示框:把options - check model的小勾给去掉,就是不进行检查(不推荐)!
或者可以修改C:\Program Files\Sybase\PowerDesigner Trial 11\Resource Files\DBMS\oracl9i2.xdb文件
修改好后,再cdm转为pdm时,选择“Copy the DBMS definition in model”把把这个资源文件拷贝到模型中。

3、生成的建表脚本中如何把对象的双引号去掉?
打开cdm的情况下,进入Tools-Model Options-Naming Convention,把Name和Code的标签的Charcter case选项设置成Uppercase或者Lowercase,只要不是Mixed Case就行!
或者选择Database->Edit current database->Script->Sql->Format,有一项CaseSensitivityUsingQuote,它的 comment为“Determines if the case sensitivity for identifiers is managed using double quotes”,表示是否适用双引号来规定标识符的大小写,可以看到右边的values默认值为“YES”,改为“No”即可!
或者在打开pdm的情况下,进入Tools-Model Options-Naming Convention,把Name和Code的标签的Charcter case选项设置成Uppercase就可以!

4、建立一个表后,为何检测出现Existence of index的警告
A table should contain at least one column, one index, one key, and one reference.
可以不检查 Existence of index 这项,也就没有这个警告错误了!
意思是说没有给表建立索引,而一个表一般至少要有一个索引,这是一个警告,不用管也没有关系!

5、创建一个表在修改字段的时候,一修改name的内容,code也跟着变化,如何让code不随着name变化
Name和Code 的右侧都有一个按钮“=”,如果需要不同步的话,把这个按钮弹起来就可以了。
Tools->General Options->Dialog->Name to Code Mirroring (去掉)

6、由CDM生成PDM时,自动生成的外键的重命名
PDM Generation Options->Detail->FK index names默认是%REFR%_FK,改为FK_%REFRCODE%,其中%REFRCODE%指的就是CDM中Relationship的code!另外自动生成的父字段的规则是PDM Generation Options->Detail->FK column name template中设置的,默认是%.3:PARENT%_%COLUMN%,可以改为Par%COLUMN%表示是父字段!

7、如何防止一对一的关系生成两个引用(外键)
要定义关系的支配方向,占支配地位的实体(有D标志)变为父表。
在cdm中双击一对一关系->Detail->Dominant role选择支配关系

8、修改报表模板中一些术语的定义
即文件:C:\Program Files\Sybase\PowerDesigner Trial 11\Resource Files\Report Languages\Chinese.xrl
Tools-Resources-Report Languages-选择Chinese-单击Properties或双击目标
修改某些对象的名称:Object Attributes\Physical Data Model\Column\
        ForeignKey:外键
        Mandatory:为空
        Primary:主键
        Table:表
用查找替换,把“表格”替换成“表”
修改显示的内容为别的:Values Mapping\Lists\Standard,添加TRUE的转化列为是,FALSE的转化列为空
另外Report-Title Page里可以设置标题信息
posted @ 2007-01-17 09:55 Alex 阅读(3157) | 评论 (3)编辑 收藏

key words : beanShell ,动态脚本

原来第一次是在osworkflow中听说过beanShell,最近又碰到,感觉还是挺有用的,比如对于我来说我就想有一些class文件拿过来直接调用看看,但有不想搭建一个麻烦的环境,而beanshell就可以满足我这个需求。

假设我欲调用的java为MyShit
package com.app;

public class MyShit
{
    
static{
        System.out.println(
"this is in static blog");
    }

    
public static void main(String[] args){
        System.out.println(
"this is in main method : hello shit");
    }

    
public void shit(){
        System.out.println(
"hello shit!!!");
    }


    
public static void haha(){
        System.out.println(
"this is static method haha");
    }

}


javac ...
java ..

在dos中设置classpath,指向该class文件

set classpath=%classpath%;c:\beanshell

编写一个 bsh的bat文件,便于dos直接调用beanshell脚本
 
java bsh.Interpreter %1


编写一个test.bsh脚本
//mytest
import com.app.*;

print(
"hello,it's a beanShell test");

List list  
= new ArrayList();
list.add(
"111");
list.add(
"222");
list.add(
"333");

print(
"the list = " + list);

Date date 
= new Date();
print(
"the date = " + date);

//method test

add( a, b ) 
{
    
return a + b;
}


foo 
= add(12);            // 3
print("foo = " + foo);
foo 
= add("Oh"" baby");   // "Oh baby"
print("foo = " + foo);

//about object
foo() {
    print(
"foo");
    x
=5;

    bar() 
{
        print(
"foo's method bar()");
    }


    
return this;
}


myfoo 
= foo();    // prints "foo"
print( myfoo.x ); // prints "5"
myfoo.bar();      // prints "bar"

MyShit shit 
= new MyShit();
shit.shit();
shit.main(
null);
print(
"do you shit");

//MyShit.haha();


在dos下运行 bsh test.bsh就OK了

另外,beanshell作为动态脚本语言可以结合 spring2.0的新特性,你新写的业务类可以直接修改而不用重新发布,怎么样,是不是比较方便,详细操作请参考Springframework 2.0 与 ZK 混合开发实例

试一试!

详细使用请参考官方文档
posted @ 2007-01-09 20:01 Alex 阅读(6511) | 评论 (7)编辑 收藏

key words: 连接池 数据库

发现一个有意思的现象,好多人在开发过程中不知道是出于训练自己编码还是为了重新发明轮子,总之明明已经存在的功能他非要自己实现一遍。

今天又碰到一个。

jdbc的连接,好多人也喜欢自己实现一个连接池,但是对于app server来说本身一般都有支持连接池的,为什么不用呢?
写了一通又长又臭的代码,自己以为牛B的很,其实算个球啊。

不要浪费,不要自己发明轮子,你不是最牛的,一定还有比你更牛的!

对于weblogic或者oracle以及ibm的产品来说,大家还是比较习惯于用容器的jndi,但是即使对于tomcat,我个人也建议用tomcat自带的。

附: jndi连接数据库

public final static synchronized Connection getConnection(String inputJNDI) throws
      DBMException 
{
    Connection conn 
= null;
    String strConnJNDI 
= null;
    
try {
      Context ctx 
= new InitialContext();
      _log.debug(ctx);

      
if (null != inputJNDI) {
        
if(inputJNDI.length() > 0)
          strConnJNDI 
= inputJNDI;
        
else
          strConnJNDI 
= dbJndiName;
      }

      
else {
        strConnJNDI 
= dbJndiName;
      }

      DataSource ds 
= (DataSource) ctx.lookup(strConnJNDI);
      _log.debug(ds);
      conn 
= ds.getConnection();
    }

    
catch (Exception ex) {
      _log.error(
"It's error to get connection", ex);
      
throw new DBMException("Error to get connection");
    }

    _log.debug(conn);
    
return conn;
  }


以此类推,类似于xml解析等的工作也没有必要自己一步一步地用dom或者什么乱七八糟的sax自己去搞一遍,搞了半天就使为了得到其中的一个value,何苦来着?    如果你不是为了做研究,那么,效率第一,安全第一.

随便说说,也许有人不同意我的观点,没关系,尽管谈谈,哈哈  :)
posted @ 2007-01-04 20:58 Alex 阅读(1942) | 评论 (8)编辑 收藏

key words: 2007 plans

新的一年开始了,制定一个计划吧

说说你有什么计划

如图:

2007-plans.png
posted @ 2007-01-03 23:31 Alex 阅读(1492) | 评论 (12)编辑 收藏

key words: tomcat,数据源配置,datasource

把一个应用从4.1移到5.5数据源死活不出来,用probe察看了一下居然datasource配置错误.

4.x的配置如下:

<Context path="/cpms" docBase="cpms"   debug="99" privileged="true">
            
<Resource name="jdbc/report" auth="Container" type="javax.sql.DataSource"/>
            
<ResourceParams name="jdbc/report"> 
                
<parameter>
                    
<name>username</name>
                    
<value>root</value>
                
</parameter>
                
<parameter>
                    
<name>password</name>
                    
<value>XXX</value>
                
</parameter>
                
<parameter>
                    
<name>driverClassName</name> 
                    
<value>org.gjt.mm.mysql.Driver</value>
                
</parameter>
                
<parameter>
                    
<name>url</name> 
                    
<value>jdbc:mysql://localhost/app</value>
                
</parameter> 
                
<parameter>
          
<name>RemoveAbandoned</name>
          
<value>true</value>
        
</parameter>
        
<parameter>
          
<name>LogAbandoned</name>
          
<value>true</value>
        
</parameter>
        
<parameter>
          
<name>RemoveAbandonedTimeout</name>
          
<value>60</value>
        
</parameter>
              
</ResourceParams> 
    
</Context>  


5.x的配置如下:

<Context path="/app" docBase="cpms"
        debug
="5" reloadable="true" crossContext="true">



  
<Resource name="jdbc/report" auth="Container" type="javax.sql.DataSource"
               maxActive
="100" maxIdle="30" maxWait="10000"
               username
="develop" password="XX" driverClassName="com.mysql.jdbc.Driver"
               url
="jdbc:mysql://localhost:3306/app?autoReconnect=true"/>
</Context>


没有具体看原因.知道的兄弟可以发表高见

tomcat的管理和监控推荐用probe,自带的那个admin管理太滥了。

posted @ 2006-12-22 12:04 Alex 阅读(1715) | 评论 (1)编辑 收藏

key words: sql server,单用户,master恢复

 作者:jankie
日期:2006-12-1

一、MASTER数据库备份与恢复
   1、数据库master正常情况下对master进行(完全)备份;
若要恢复:
   2、停止SQL Server服务;
   3、以单用户实例的方式启动SQL Server,启动时不要把窗口关闭;(具体看二)
   4、然后再对MASTE数据库进行恢复即可;

二、MSSQL单用户实例的启动方法:
  如何在单用户模式下启动SQL Server的命名实例(命令提示符)   
  在单用户模式下从命令提示符启动SQL Server 的命名实例     
  从命令提示符输入:     
  sqlservr.exe -c  -m   -s   {instancename}   

例1:
  1、sqlserver.exe -c -m 回车(默认实例)
  2、sqlserver.exe -c -m -s benet (实例名为benet)
   
  说明在启动 sqlservr.exe之前,必须在命令窗口中切换到适当的目录
如:c:\program files\microsoft sql server\mssql\bin目录下
posted @ 2006-12-21 15:08 Alex 阅读(498) | 评论 (0)编辑 收藏

key words: dll,ocx,注册控件

最近项目中用到了收银,需要在顾显上显示金额.


1.将.dll、.ocx等考到system32下。
2.用命令注册regsvr32.exe  .dll。(eg:regsvr32.exe  OWC11.dll)
3.在注册表中查看:利用名称或与其唯一对应的clsid("clsid:0002E55D-0000-0000-C000-   000000000046")可查找到相关信息
posted @ 2006-12-20 15:13 Alex 阅读(685) | 评论 (0)编辑 收藏

     摘要: key words: bea world2006 ,workshop studio, 快速开发

bea world 2006 北京已经过去好几天了,早就想记录一下一直忙 :)
  阅读全文
posted @ 2006-12-20 11:39 Alex 阅读(2650) | 评论 (10)编辑 收藏

key words: commons log,log4j,apache log

前言: 对于log4j虽然在用,但是也存在一个疑问,怎么有的用apache的commons logging有的直接用log4j,下面的这篇文章解释了我的疑问.

转自 here

Apache组织开发了一套用于支持Logging的Log4J,Java 1.4版本也引入了一套内置的 Logging框架,如果开发者想在这两套Logging系统之间自由的切换,该怎么办呢?答案就是,使用Commons Logging。 Commons Logging定义了一套抽象的Logging接口,用户可以通过配置,使这些接口指向任何一个已存在的Logging系统。

•使用抽象Logging接口
问题:
你在编写一个可以重复使用的库,需要写入Log信息,但你不想使你的Logging功能绑定在Apache Log4J或者JDK 1.4 Logging框架上。
解决方案:

public static void main(String[] args) {//自己替换[]

  System.setProperty("org.apache.commons.logging.Log",
      "org.apache.commons.logging.impl.Jdk14Logger");
  Log log = LogFactory.getLog("com.discursive.jccook.SomeApp");

  if (log.isTraceEnabled()) {
    log.trace("This is a trace message");
  }

  if (log.isDebugEnabled()) {
    log.debug("This is a debug message");
  }

  log.info("This is an informational message");
  log.warn("This is a warning");
  log.error("This is an error");
  log.fatal("This is fatal");

}


LogFactory.getLog方法会根据底层环境返回一个适当的Log实现。如果用户想指定一个具体的Logging系统实现,可以设置org.apache.commons.logging.Log系统属性。例如:
System.setProperty("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.Log4JLogger");
这样就会使用Log4J作为Logging系统。
org.apache.commons.logging.Log可以设定为:
•org.apache.commons.logging.impl.Log4JLogger  使用Log4J
•org.apache.commons.logging.impl.Jdk14Logger  使用JDK 1.4 Logging框架
•org.apache.commons.logging.impl.SimpleLog  使用Commons Logging内置的简单Log实现
其他:
总结一下,Commons Logging会按照下列顺序来指定具体的Log实现。
•如果定义了org.apache.commons.logging.Log系统参数,实用指定的Logging实现。
•如果在CLASSPATH里发现了Log4J,使用Log4J。
•如果使用的是JDK1.4,使用JDK1.4内置的Logging框架。
•如果都没有找到,则使用Commons Logging内置的简单Log实现。
posted @ 2006-12-18 15:38 Alex 阅读(708) | 评论 (0)编辑 收藏

key words : 职业规划  高薪

原文见robbin的pdf,我整理了一下脑图

职业规划与高薪之路.png
posted @ 2006-12-17 13:25 Alex 阅读(3447) | 评论 (6)编辑 收藏

注意:这篇文章是由无人工介入的自动的机器翻译系统翻译完成。这些文章是微软为不懂英语的用户提供的, 以使他们能够理解这些文章的内容。微软不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的使用所引起的任何直接的, 或间接的可能的问题负责。

概要

Microsoft SQL Server 2000 支持同一计算机上同时运行的多个 SQLServer 数据库引擎实例。 以下是两种类型的 SQLServer 数据库引擎实例: 默认和命名。 只能有, 任何计算机上运行一个默认实例并且由默认实例运行计算机上的名称标识它。 通常指定以下列格式: 计算机名和实例名称
computer_name\instance_name
要 MicrosoftSQLServer2000JDBC, 连接命名实例通过 SQL 服务器 2000 MicrosoftTextDriver 必须指定端口号与命名实例, 代替的命名实例名称相关联如前面。

更多信息

要查找 SQLServer 实例端口号, 请按照下列步骤:
1.在 Microsoft SQL Server 2000 服务器, 启动 SQL Server 网络实用工具。
2.要从 实例 下拉菜单实例依次, 常规 选项卡。
3.TCP/IP, 依次 属性 。 注意, 在 属性 对话框中出现端口号为此实例。

当您连接到 SQLServer 通过 JDBC 连接 URL 中使用只要有该值,。 下面是典型连接 URL 的示例:

jdbc:microsoft:sqlserver: / 1433; yourServerName / 用户 = yourUser ; 密码 = yourPwd :
在本示例, 使用默认端口是 1433。 将此默认替换端口号为您命名实例。
posted @ 2006-12-17 00:35 Alex 阅读(1230) | 评论 (0)编辑 收藏

key words: jsp,jstl,1.0,1.1,fn函数

原来一直用struts,最近项目里有人用jstl,我也就顺便拿来用,感觉还是不错。

过程中碰到一些小的问题总结如下:

一。版本问题
jstl存在1.0和1.1的差异问题,用EL建议需要在1.1的版本下,1.1的URI的标志为:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>

注意,1.0版本没有/jsp/.

如果用的1.0会出现如下异常
org.apache.jasper.JasperException: /public/left_tree.jsp(100,24) According to TLD or attribute directive in tag file, attribute items does not accept any expressions
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:
510)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:
375)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:
314)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:
264)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:
802)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:
75)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:
77)
    com.wellsoon.zfzw.webapp.common.VabAccessFilter.doFilter(VabAccessFilter.java:
43)


root cause 



二。打开EL

<%@ page contentType="text/html;charset=gb2312" language="java" isELIgnored="false" %>

前提是容器支持2.0,即使支持默认也未必打开,最安全的方式就是显示打开 isELIgnored="false"

三.fn的用法
对于Vo里的一个List作length的计算或判断很方便
<table width="160" border="0" cellspacing="0" cellpadding="4">
                        
<c:forEach items="${menuInfos}" var="m">
                            
<c:if test="${fn:length(m.subMenus)>0}">
                          
<tr>
                            
<td>
                                
<script language="JavaScript">
                                      
var tObj = new treeClass("A1")
                                      tObj.start();
                                     tObj.m_start(
"<c:out value="${m.menuModule}"/>",0);
                                    
<c:forEach items="${m.subMenus}" var="sub">
                                      tObj.add_Sub(
"<c:out value="${sub.menuName}"/>","<%=path%>
<c:out value=
"${sub.url}"/>","mymain");
                                    
</c:forEach>
                                     tObj.m_end();
                                      tObj.end();
                                      tObj.print();
                                 
</script>
                            
</td>
                        
</tr>
                            
</c:if>
                        
</c:forEach>

                    
</table>
 
四.tld的声明可以在web.xml作显式声明也可以用http作直接URL声明
推荐用本地的方式.

posted @ 2006-12-11 19:21 Alex 阅读(2793) | 评论 (2)编辑 收藏

key words: MiddleGen,hibernate,many to many,多对多

如果你有如下表结构

user(user_id,user_name)
role(role_id,role_name)

user_role(id,user_id,role_id)

那么默认MiddleGen生成的是两个一对多,但我们更多的情况是用many to many

需要修改middlegen的build.xml文件

<many2many>
            
<tablea generate="true" name="user"/>
            
<jointable name="user_role" generate="false"/>
            
<tableb generate="true" name="role"/>
         
</many2many>

posted @ 2006-12-07 20:26 Alex 阅读(907) | 评论 (0)编辑 收藏

越来越发现其实掌握 hibernate并不容易,Spring用起来其实简单多了,但是在用hibernate的时候真的是需要一定的时间积累,对一个项目组来说如果采用hibernate最好有一个对hibernate比较清楚的人否则碰到问题就会成为项目的风险。
我想告诉各位的是,掌握hibernate可能比你预期的难多了,当你轻松的告诉我,hibernate很简单的时候该是你自己多反省了. (只有一种情况例外,你是一个牛人)

好了,一个引子废话那么多,其实今天只是想先说一说hibernate里的Fetch的作用.

大家都知道,在hibernate里为了性能考虑,引进了lazy的概念,这里我们以Parent和Child为模型来说明,

public class Parent implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private List childs;

    
//skip all getter/setter method

  
}  



public class Child implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private net.foxlog.model.Parent parent;

    //skip all getter/setter method

}

在我们查询Parent对象的时候,默认只有Parent的内容,并不包含childs的信息,如果在Parent.hbm.xml里设置lazy="false"的话才同时取出关联的所有childs内容.

问题是我既想要hibernate默认的性能又想要临时的灵活性该怎么办?  这就是fetch的功能。我们可以把fetch与lazy="true"的关系类比为事务当中的编程式事务与声明式事务,不太准确,但是大概是这个意思。

总值,fetch就是在代码这一层给你一个主动抓取得机会.

Parent parent = (Parent)hibernateTemplate.execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q 
= session.createQuery(
                        
"from Parent as parent "+
                                
" left outer join fetch parent.childs " +
                                
" where parent.id = :id"
                );
                q.setParameter(
"id",new Long(15));
                
return (Parent)q.uniqueResult();
            }

        });

        Assert.assertTrue(parent.getChilds().size() 
> 0);


你可以在lazy="true"的情况下把fetch去掉,就会报异常. 当然,如果lazy="false"就不需要fetch了


有一个问题,使用Fetch会有重复记录的现象发生,我们可以理解为Fetch实际上不是为Parent服务的,而是为Child服务的.所以直接取Parent会有不匹配的问题.



参考一下下面的这篇文章
Hibernate集合初始化

======================================================================

update:以上有些结论错误,实际上在hibernate3.2.1版本下测试,可以不出现重复记录,

public void testNPlusOne() throws Exception{
        List list 
= (List)hibernateTemplate.execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q 
= session.createQuery(
                        
"select distinct p from net.foxlog.model.Parent p inner join fetch p.childs"
                );
                
return q.list();
            }

        });

        
//((Parent)(list.get(0))).getChilds();
        System.out.println("list size = " + list.size());
        
for(int i=0;i<list.size();i++){
            Parent p 
= (Parent)list.get(i);
            System.out.println(
"===parent = " + p);
            System.out.println(
"===parent's child's length = " + p.getChilds().size());
        }

    }


打印结果如下:
Hibernate: select distinct parent0_.id as id2_0_, childs1_.id as id0_1_, childs1_.parent_id as parent2_0_1_, childs1_.parent_id as parent2_0__, childs1_.id as id0__ from parent parent0_ inner join child childs1_ on parent0_.id=childs1_.parent_id
list size 
= 3
===parent = net.foxlog.model.Parent@1401d28[id=14]
===parent's child's length = 1
===parent = net.foxlog.model.Parent@14e0e90[id=15]
===parent's child's length = 2
===parent = net.foxlog.model.Parent@62610b[id=17]
===parent's child's length = 3

另外,如果用open session in view模式的话一般不用fetch,但首先推荐fetch,如果非用的话因为有N+1的现象,所以可以结合batch模式来改善下性能.


posted @ 2006-12-01 13:01 Alex 阅读(19362) | 评论 (7)编辑 收藏

LDAPChina序言:这篇文章是互联网上最流行的一篇介绍LDAP基础知识的文章,本文作者Michael DonnellyLDAPMAN.org的站长。由于本文译文较长,我们将其分为两部分,第一部分介绍LDAP概论,第二部分介绍LDAP基础知识。感谢网友Brimmer翻译此文。

如 果你在计算机行业工作,那么对LDAP可能早有耳闻了。想深入地了解LDAP吗?那么可以好好地读一下这篇文章。这篇介绍性的文章是一系列介绍如何在企业 中设计、实现和集成LDAP环境的文章的头一篇。主要是先让你熟悉一下LDAP的基本概念,那些比较困难的细节问题将放到以后讨论。在这篇文章中我们将要 介绍:

什么是LDAP?
什么时候该用LDAP存储数据?

现 在LDAP技术不仅发展得很快而且也是激动人心的。在企业范围内实现LDAP可以让运行在几乎所有计算机平台上的所有的应用程序从LDAP目录中获取信 息。LDAP目录中可以存储各种类型的数据:电子邮件地址、邮件路由信息、人力资源数据、公用密匙、联系人列表,等等。通过把LDAP目录作为系统集成中 的一个重要环节,可以简化员工在企业内部查询信息的步骤,甚至连主要的数据源都可以放在任何地方。如果Oracle、Sybase、Informix或 Microsoft SQL数据库中已经存储了类似的数据,那么LDAP和这些数据库到底有什么不同呢?是什么让它更具优势?请继续读下去吧!


什么是LDAP?

LDAP 的英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP。它是基于X.500标准的,但是简单多了并且可以根据需要定制。与X.500不同,LDAP支持TCP/IP, 这对访问Internet是必须的。LDAP的核心规范在RFC中都有定义,所有与LDAP相关的RFC都可以在LDAPChina.com RFC专栏中找到。

怎么使用LDAP这个术语呢?

在 日常交谈中,你可能会听到有些人这么说:“我们要把那些东西存在LDAP中吗?”,或者“从LDAP数据库中取出那些数据!”,又或者“我们怎么把 LDAP和关系型数据库集成在一起?”。严格地说,LDAP根本不是数据库而是用来访问存储在信息目录(也就是LDAP目录)中的信息的协议。更为确切和正式的说法应该是象这样的:“通过使用LDAP,可以在信息目录的正确位置读取(或存储)数据”。但是,也没有必要吹毛求疵,尽管表达得不够准确,我们也都知道对方在说什么。

LDAP目录是数据库吗?

就 象Sybase、Oracle、Informix或Microsoft的数据库管理系统(DBMS)是用于处理查询和更新关系型数据库那样,LDAP服务 器也是用来处理查询和更新LDAP目录的。换句话来说LDAP目录也是一种类型的数据库,但是不是关系型数据库。不象被设计成每分钟需要处理成百上千条数 据变化的数据库,例如:在电子商务中经常用到的在线交易处理(OLTP)系统,LDAP主要是优化数据读取的性能。

LDAP目录的优势

现在该说说LDAP目录到底有些什么优势了。现在LDAP的流行是很多因素共同作用的结果。我在这里说的不过是一些基本的原因,请你注意一下这不过是一小部分原因。

可能LDAP最大的优势是:可以在任何计算机平台上,用很容易获得的而且数目不断增加的LDAP的客户端程序访问LDAP目录。而且也很容易定制应用程序为它加上LDAP的支持。

LDAP 协议是跨平台的和标准的协议,因此应用程序就不用为LDAP目录放在什么样的服务器上操心了。实际上,LDAP得到了业界的广泛认可,因为它是 Internet的标准。产商都很愿意在产品中加入对LDAP的支持,因为他们根本不用考虑另一端(客户端或服务端)是怎么样的。LDAP服务器可以是任 何一个开发源代码或商用的LDAP目录服务器(或者还可能是具有LDAP界面的关系型数据库),因为可以用同样的协议、客户端连接软件包和查询命令与 LDAP服务器进行交互。与LDAP不同的是,如果软件产商想在软件产品中集成对DBMS的支持,那么通常都要对每一个数据库服务器单独定制。

不象很多商用的关系型数据库,你不必为LDAP的每一个客户端连接或许可协议付费。

大多数的LDAP服务器安装起来很简单,也容易维护和优化。

LDAP服务器可以用“推”或“拉”的方法复制部分或全部数据,例如:可以把数据“推”到远程的办公室,以增加数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配置。如果要在DBMS中使用相同的复制功能,数据库产商就会要你支付额外的费用,而且也很难管理。

LDAP 允许你根据需要使用ACI(一般都称为ACL或者访问控制列表)控制对数据读和写的权限。例如,设备管理员可以有权改变员工的工作地点和办公室号码,但是 不允许改变记录中其它的域。ACI可以根据谁访问数据、访问什么数据、数据存在什么地方以及其它对数据进行访问控制。因为这些都是由LDAP目录服务器完 成的,所以不用担心在客户端的应用程序上是否要进行安全检查。

LDAP对于存储下面这样的信息最为有用,也就是数据需要从不同的地点读取,但是不需要经常更新。例如,这些信息存储在LDAP目录中是十分有效的:

  • 公司员工的电话号码簿和组织结构图
  • 客户的联系信息
  • 计算机管理需要的信息,包括NIS映射、email假名,等等
  • 软件包的配置信息
  • 公用证书和安全密匙

什么时候该用LDAP存储数据?

大 多数的LDAP服务器都为读密集型的操作进行专门的优化。因此,当从LDAP服务器中读取数据的时候会比从专门为OLTP优化的关系型数据库中读取数据快 一个数量级。也是因为专门为读的性能进行优化,大多数的LDAP目录服务器并不适合存储需要经常改变的数据。例如,用LDAP服务器来存储电话号码是一个 很好的选择,但是它不能作为电子商务站点的数据库服务器。

如果下面每一个问题的答案都是“是”,那么把数据存在LDAP中就是一个好主意。

  • 需要在任何平台上都能读取数据吗?
  • 每一个单独的记录项是不是每一天都只有很少的改变?
  • 可以把数据保存在平面数据库(flat database)而不是关系型数据库中吗?换句话来说,也就是不管什么范式不范式的,把所有东西都存在一个记录中(差不多只要满足第一范式)。

最 后一个问题可能会唬住一些人,其实用平面数据库去存储一些关系型的数据也是很一般的。例如,一条公司员工的记录就可以包含经理的登录名。用LDAP来存储 这类信息是很方便的。一个简单的判断方法:如果可以把数据保存在一张张的卡片里,就可以很容易地把它存在LDAP目录里。


接上文

LDAP目录树的结构
单条LDAP记录
定制目录的对象类
一个LDAP单个条目的例子
LDAP复制
安全和访问控制

LDAP目录树的结构

LDAP 目录以树状的层次结构来存储数据。如果你对自顶向下的DNS树或UNIX文件的目录树比较熟悉,也就很容易掌握LDAP目录树这个概念了。就象DNS的主 机名那样,LDAP目录记录的分辨名(Distinguished Name,简称DN)是用来读取单条记录,以及回溯到树的顶部。后面会做详细地介绍。

为什么要用层次结构来组织数据呢?原因是多方面的。下面是可能遇到的一些情况:

  • 如果你想把所有的美国客户的联系信息都“推”到位于到西雅图办公室(负责营销)的LDAP服务器上, 但是你不想把公司的资产管理信息“推”到那里。
  • 你可能想根据目录树的结构给予不同的员工组不同的权限。在下面的例子里,资产管理组对“asset-mgmt”部分有完全的访问权限,但是不能访问其它地方。
  • 把LDAP存储和复制功能结合起来,可以定制目录树的结构以降低对WAN带宽的要求。位于西雅图的营销办公室需要每分钟更新的美国销售状况的信息,但是欧洲的销售情况就只要每小时更新一次就行了。

刨根问底:基准DN

LDAP目录树的最顶部就是根,也就是所谓的“基准DN”。基准DN通常使用下面列出的三种格式之一。假定我在名为FooBar的电子商务公司工作,这家公司在Internet上的名字是foobar.com。

o="FooBar, Inc.", c=US

(以X.500格式表示的基准DN)

在 这个例子中,o=FooBar, Inc. 表示组织名,在这里就是公司名的同义词。c=US 表示公司的总部在美国。以前,一般都用这种方式来表示基准DN。但是事物总是在不断变化的,现在所有的公司都已经(或计划)上Internet上。随着 Internet的全球化,在基准DN中使用国家代码很容易让人产生混淆。现在,X.500格式发展成下面列出的两种格式。

o=foobar.com

(用公司的Internet地址表示的基准DN)

这种格式很直观,用公司的域名作为基准DN。这也是现在最常用的格式。

dc=foobar, dc=com

(用DNS域名的不同部分组成的基准DN)

就 象上面那一种格式,这种格式也是以DNS域名为基础的,但是上面那种格式不改变域名(也就更易读),而这种格式把域名:foobar.com分成两部分 dc=foobar, dc=com。在理论上,这种格式可能会更灵活一点,但是对于最终用户来说也更难记忆一点。考虑一下foobar.com这个例子。当 foobar.com和gizmo.com合并之后,可以简单的把“dc=com”当作基准DN。把新的记录放到已经存在的dc=gizmo, dc=com目录下,这样就简化了很多工作(当然,如果foobar.com和wocket.edu合并,这个方法就不能用了)。如果LDAP服务器是新 安装的,我建议你使用这种格式。再请注意一下,如果你打算使用活动目录(Actrive Directory),Microsoft已经限制你必须使用这种格式。

更上一层楼:在目录树中怎么组织数据

在UNIX文件系统中,最顶层是根目录(root)。在根目录的下面有很多的文件和目录。象上面介绍的那样,LDAP目录也是用

posted @ 2006-11-30 20:45 Alex| 编辑 收藏

key words:jotspot,wiki,项目管理

最近听说了jotspot,这个东西确实很好,原来一直打算自己建立一个wiki,作一些公司项目资源的管理,进度管理,以及提供其他团队成员了解项目信息的窗口,原来打算用jspwiki,可是建在哪呢? 在我的笔记本上还是公司的服务器上,似乎都不是很好,还是建在jotspot上比较好。zheng
给我看了一个截图:

jotspot_project.gif


功能还挺强大,我想做我的日常项目管理应该够了


posted @ 2006-11-09 22:03 Alex 阅读(706) | 评论 (2)编辑 收藏


key words:google搜索技巧,in site,inurl,filetype

最常用的是下面这个

IDEA in site:blogjava.net inurl:Alex filetype:ppt


下面转录一篇
玩转GOOGLE的十九招秘技


第一招:

  在输入多个词的时候,Google默认的是并且式的查询,如果想使用或者式的查询,使用OR,例如:java OR c++

第二招
  google是不区分大小写的,搜索Java和搜索JAVA或者java是完全一样的。

  第三招
  逻辑关系优先级使用圆括号,例如查找包含java和(JVM或者虚拟机):Java (JVM或者虚拟机)。

  第四招
  要搜索词组需要使用引号括起来,例如搜索Java虚拟机可以使用:"Java虚拟机"。

  第五招
  要想在搜索结果中不包含某些结果可以使用减号,例如搜索java又不包含培训可以使用:java -培训。

  第六招
  一般情况下是不能使用通配符的,通配符只能使用在词组中,例如:"使用*模式"。

  第七招
  只在网页的标题(即html的title指定的部分)内搜索指定的内容,例如:intitle:java。
第八招
  只在网页的url内搜索指定的内容,例如:inurl:java。

  第九招
  只在网页的正文内搜索指定的内容(忽略链接文字、标题和url),例如:intext:java。

  第十招
  只在链接文字(链接Java研究组织的链接文字就是Java研究组织)内搜索指定的内容,例如:inanchor:java。

  第十一招
  只在指定的网站内搜索指定的内容,可以是某个具体的网站或者是某个域名分类,例如:site:javaresearch.org或者site:org。

  第十二招
  只在指定的文件格式内搜索指定的内容,需要注意google只能支持有限的常用文本格式,包含一些诸如doc,xsl,ppt,pdf之类的富文本格式,例如:filetype:htm。

  第十三招
  google在检索的时候对于输入的内容的顺序是敏感的,如果找不到合适的结果可以试试改变一下搜索的关键字的顺序。


  第十四招
  在搜索多个关键字构成的内容时可以试试加引号和不加引号两者情况,结果可能有很大的差异,例如:java虚拟机和"java虚拟机"。

  第十五招
  搜索的策略可以采用先多后少,假设你想搜索Java的的command模式的例子,可以先试试java command pattern,然后试试java pattern或者java command,每次减少的那个关键字应该是你认为相对不重要的一个。
第十六招
  对于搜索中文而言,搜索“虚拟机”和搜索“虚拟机”是不同的,后者一般比前者的结果多并且相关性差一些,一般情况下你应该在各个词之间加空格,而在词内不加空格,这样得到的结果一般更好。

  第十七招
  一个关键字可以重复两次,对结果的排名和数量也会有影响,重复两次以上好像就没有什么影响了,例如搜索"internet"和搜索"internet internet"的结果是不同的。

  第十八招
  搜索内容最多只能包含十个单词,包括搜索intitle之类的选项,多出的部分被忽略。

  第十九招
  对于intitle,inurl,intext,inanchor和site之类的搜索选项一次不要使用多次,否则要么不是你想要的结果,要么根本就没有结果,混合使用这些选项是合法的,但是规则很复杂。

posted @ 2006-11-09 21:49 Alex 阅读(975) | 评论 (0)编辑 收藏

key words:mappingResources,通配符,mappingDirectoryLocations

平时写mapping的文件需要一个一个的放到配置文件里,比如
   1. <property name="mappingResources">  
   2.             
<list>  
   3.                 
<value>net/foxlog/model/Classes.hbm.xml</value>  
   4.                 
<value>net/foxlog/model/Parent.hbm.xml</value>  
   5.                 
<value>net/foxlog/model/Child.hbm.xml</value>  
   6.                 
<value>net/foxlog/model/User.hbm.xml</value>  
   7.             
</list>  
   8.         
</property>  


可以用更一步到位的方法:

   1. <property name="mappingDirectoryLocations">  
   2.             
<list>  
   3.                 
<value>classpath*:/org/springside/bookstore/commons/model/hbm</value>  
   4.             
</list>  
   5.         
</property>  

posted @ 2006-11-09 21:00 Alex 阅读(5025) | 评论 (0)编辑 收藏

key words:hibernate,复合主键,composite-id



基于业务需求,您会需要使用两个字段来作复合主键,例如在User数据表中,您也许会使用"name""phone"两个字段来定义复合主键。

假设您这么建立User表格:

CREATE TABLE user (

    name 
VARCHAR(100NOT NULL,

    phone 
VARCHAR(50NOT NULL,

    age 
INT,

    
PRIMARY KEY(name, phone)

);

在表格中,"name""age"被定义为复合主键,在映像时,您可以让User类别直接带有"name""age"这两个属性,而Hibernate要求复合主键类别要实作Serializable接口,并定义equals()hashCode()方法:

User.java

package onlyfun.caterpillar;

 

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;

import org.apache.commons.lang.builder.HashCodeBuilder;

 

// 复合主键类的对应类别必须实作Serializable接口

public class User implements Serializable {

    
private String name;

    
private String phone;

    
private Integer age;

   

    
public User() {

    }

 

    
public Integer getAge() {

        
return age;

    }

 

    
public void setAge(Integer age) {

        
this.age = age;

    }

 

    
public String getName() {

        
return name;

    }

 

    
public void setName(String name) {

        
this.name = name;

    }

 

    
public String getPhone() {

        
return phone;

    }

 

    
public void setPhone(String phone) {

        
this.phone = phone;

    }

   

    
// 必须重新定义equals()与hashCode()

    
public boolean equals(Object obj) {

        
if(obj == this) {

            
return true;

        }

       

        
if(!(obj instanceof User)) {

            
return false;

        }

       

        User user 
= (User) obj;

        
return new EqualsBuilder()

                 .append(
this.name, user.getName())

                 .append(
this.phone, user.getPhone())

                 .isEquals();

       

    }

   

    
public int hashCode() {

        
return new HashCodeBuilder()

                 .append(
this.name)

                 .append(
this.phone)

                 .toHashCode();

    }

}

equals()hashCode()方法被用作两笔不同数据的识别依据;接着您可以使用<composite-id>在映射文件中定义复合主键与对象的属性对应:

User.hbm.xml

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping

    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

 

<hibernate-mapping>

 

    
<class name="onlyfun.caterpillar.User" table="user">

        
<composite-id>

            
<key-property name="name"

                          column
="name"

                          type
="java.lang.String"/>

            
<key-property name="phone"

                          column
="phone"

                          type
="java.lang.String"/>

        
</composite-id>

 

        
<property name="age" column="age" type="java.lang.Integer"/>

   

    
</class>

</hibernate-mapping>

在储存数据方面,复合主键的储存没什么区别,现在的问题在于如何依据复合主键来查询数据,例如使用load()方法,您可以创建一个User实例,并设定复合主键对应的属性,接着再透过load()查询对应的数据,例如:

User user = new User();

user.setName(
"bush");

user.setPhone(
"0970123456");

       

Session session 
= sessionFactory.openSession();

// 以实例设定复合主键并加载对应的数据

user 
= (User) session.load(User.class, user);

       

System.out.println(user.getAge() 
+ "\t" +

                                  user.getName() 
+ "\t" +

                                  user.getPhone());

session.close();

 

 

可以将主键的信息独立为一个类别,例如:

UserPK.java

package onlyfun.caterpillar;

 

import java.io.Serializable;

 

import org.apache.commons.lang.builder.EqualsBuilder;

import org.apache.commons.lang.builder.HashCodeBuilder;

 

public class UserPK implements Serializable {

    
private String name;

    
private String phone;

 

    
public String getName() {

        
return name;

    }

 

    
public void setName(String name) {

        
this.name = name;

    }

 

    
public String getPhone() {

        
return phone;

    }

 

    
public void setPhone(String phone) {

        
this.phone = phone;

    }

   

    
public boolean equals(Object obj) {

        
if(obj == this) {

            
return true;

        }

       

        
if(!(obj instanceof User)) {

            
return false;

        }

       

        UserPK pk 
= (UserPK) obj;

        
return new EqualsBuilder()

                 .append(
this.name, pk.getName())

                 .append(
this.phone, pk.getPhone())

                 .isEquals();

       

    }

   

    
public int hashCode() {

        
return new HashCodeBuilder()

                 .append(
this.name)

                 .append(
this.phone)

                 .toHashCode();

    }

}

现在User类别的主键信息被分离出来了,例如:

User.java

package onlyfun.caterpillar;

 

import java.io.Serializable;

 

public class User implements Serializable {

    
private UserPK userPK; // 主键

    
private Integer age;

   

    
public User() {

    }

 

    
public UserPK getUserPK() {

        
return userPK;

    }

 

    
public void setUserPK(UserPK userPK) {

        
this.userPK = userPK;

    }

 

    
public Integer getAge() {

        
return age;

    }

 

    
public void setAge(Integer age) {

        
this.age = age;

    }

}

在映像文件方面,需要指定主键类的信息,例如:

User.hbm.xml

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping

    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

 

<hibernate-mapping>

 

    
<class name="onlyfun.caterpillar.User" table="user">

        
<composite-id name="userPK"

                      class
="onlyfun.caterpillar.UserPK"

                      unsaved-value
="any">

            
<key-property name="name"

                          column
="name"

                          type
="java.lang.String"/>

            
<key-property name="phone"

                          column
="phone"

                          type
="java.lang.String"/>

        
</composite-id>

       

        
<property name="age" column="age" type="java.lang.Integer"/>

   

    
</class>

 

</hibernate-mapping>

在查询数据时,必须指定主键信息,例如:

UserPK pk = new UserPK();

pk.setName(
"bush");

pk.setPhone(
"0970123456");

      

Session session 
= sessionFactory.openSession();

// 以主键类实例设定复合主键并加载对应的数据

User user 
= (User) session.load(User.class, pk);

      

System.out.println(user.getAge() 
+ "\t" +

                                  user.getUserPK().getName() 
+ "\t" +

                                  user.getUserPK().getPhone());

session.close();

 


=================================================
再参考robbin的一篇文章
一个简单的复合主键的做关联类的例子  
posted @ 2006-11-09 19:22 Alex 阅读(12911) | 评论 (5)编辑 收藏

key words:jdk错误,Unsupported major.minor version

今天用一个工作流的产品,非要用jdk1.4的版本,没办法,只好切换回来,但是换回来后打开页面jsp出错,提示Unsupported major.minor version 49.0错误,到网上查了一下,49.0错误属于jdk1.5的错误,但是我的jdk1.5已经删除了啊?怎么回事呢?

最后想起来,可能是jboss中的1.5 版本产生临时文件class文件删除,删除后OK


资料:Unsupported major.minor version 49.0
posted @ 2006-11-08 10:13 Alex 阅读(574) | 评论 (2)编辑 收藏

key words:hibernate,load,session.get,session.load()

public class Parent implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private List childs;

    
/** full constructor */
    
public Parent(Long id, List childs) {
        
this.id = id;
        
this.childs = childs;
    }

    
/** default constructor */
    
public Parent() {
    }

    
/** 
     *            @hibernate.id
     *             generator-class="assigned"
     *             type="java.lang.Long"
     *             column="id"
     *
     
*/
    
public Long getId() {
        
return this.id;
    }

    
public void setId(Long id) {
        
this.id = id;
    }

    
/**
     *            @hibernate.set
     *             lazy="true"
     *             inverse="true"
     *             cascade="none"
     *            @hibernate.collection-key
     *             column="parent_id"
     *            @hibernate.collection-one-to-many
     *             class="net.foxlog.model.Child"
     *         
     
*/
    
public List getChilds() {
        
return this.childs;
    }

    
public void setChilds(List childs) {
        
this.childs = childs;
    }

    
public String toString() {
        
return new ToStringBuilder(this)
            .append(
"id", getId())
            .toString();
    }

    
public boolean equals(Object other) {
        
if ( !(other instanceof Parent) ) return false;
        Parent castOther 
= (Parent) other;
        
return new EqualsBuilder()
            .append(
this.getId(), castOther.getId())
            .isEquals();
    }

    
public int hashCode() {
        
return new HashCodeBuilder()
            .append(getId())
            .toHashCode();
    }

}


Parent parent = (Parent)session.load(Parent.class,new Integer(7));

运行提示出错,"can't get Entity.."

知道是什么低级错误么?  其实很弱智的东西,但是不注意还就会出现,呵呵,答案如下:


posted @ 2006-11-07 19:28 Alex 阅读(1644) | 评论 (3)编辑 收藏

key words: mysql,外键,fm150

这次在mysql中建立外键关联时发现问题:
alter table CHILD add constraint FK3D1FCFC74B18345 foreign key (PARENTID) references PARENT;      


提示..fm150错误,最后发现是mysql的版本问题,我用的是4.1的,对外键不知道是不支持还是支持的有问题,下载5.0的解决.
posted @ 2006-11-07 09:44 Alex 阅读(432) | 评论 (0)编辑 收藏

     摘要: 什么玩意  阅读全文
posted @ 2006-11-06 12:00 Alex 阅读(3448) | 评论 (9)编辑 收藏

     摘要:   阅读全文
posted @ 2006-10-31 12:32 Alex 阅读(8493) | 评论 (7)编辑 收藏

访问控制背景

    访问控制技术是由美国国防部(Department of Defense, DoD)资助的研究和开发成果演变而来的。这一研究导致两种基本类型访问控制的产生:自主访问控制(Discretionary Access Control, DAC)和强制访问控制(Mandatory Access Control, MAC)。最初的研究和应用主要是为了防止机密信息被未经授权者访问,近期的应用主要是把这些策略应用到为商业领域。

    自主访问控制,允许把访问控制权的授予和取消留给个体用户来判断。为没有访问控制权的个体用户授予和废除许可。自主访问控制机制允许用户被授权和
取 消访问其控制之下的任何客体(object),换句话说,用户就是他们控制下的客体的拥有者。然而,对于多数组织来说,最终用户对所访问的信息没有拥有 权。对于这些组织,公司或代理机构是事实上的系统客体和处理他们的程序的拥有者。访问优先权受组织控制,而且也常常基于雇员功能而不是数据所有权。

   强制访问控制,在美国国防部 Trusted Computer Security Evaluation Criteria (TCSEC) 中定义如下:“一种限制访问客体的手段,它以包含在这些客体中的信息敏感性和访问这些敏感性信息的主体的正式授权信息(如清除)为基础”。
  
   以上访问控制策略对于处理一些无需保密但又敏感的信息的政府和行业组织的需求并不是特别的适合。在这样的环境下,安全目标支持产生于现有法律、道德规范、 规章、或一般惯例的高端组织策略。这些环境通常需要控制个体行为的能力,而不仅仅是如何根据信息的敏感性为其设置标签从而访问这一信息的个人能力。
    


什么是基于角色访问控制(Role-Based Access Control, RBAC)?NIST 有如下定义。
  
   访问是一种利用计算机资源去做某件事情的的能力,访问控制是一种手段,通过它这种能力在某些情况下被允许或者受限制(通常是通过物理上和基于系统的控 制)。基于计算机的访问控制不仅可规定是“谁”或某个操作有权使用特定系统资源,而且也能规定被允许的访问类型。这些控制方式可在计算机系统或者外部设备 中实现。
  
    就基于角色访问控制而言,访问决策是基于角色的,个体用户是某个组织的一部分。用户具有指派的角色(比如医生、护士、出纳、经理)。定义角色的过程应该基于对组织运转的彻底分析,应该包括来自一个组织中更广范围用户的输入。
   
    访问权按角色名分组,资源的使用受限于授权给假定关联角色的个体。例如,在一个医院系统中,医生角色可能包括进行诊断、开据处方、指示实验室化验等;而研究员的角色则被限制在收集用于研究的匿名临床信息工作上。
   
    控制访问角色的运用可能是一种开发和加强企业特殊安全策略,进行安全管理过程流程化的有效手段。
     


用户(User)和角色(Role)

    用户指访问系统中的资源的主体,一般为人,也可为 Agent 等智能程序。角色指应用领域内一种权力和责任的语义综合体,可以是一个抽象概念,也可以是对应于实际系统中的特定语义体,比如组织内部的职务等。针对角色 属性的不同,某些模型中将角色进一步细分为普通角色和管理员角色(可理解为全局角色)。

 

许可(Permissions)和权限(Permission)

    许可描述了角色对计算机资源的访问和操作所具有的权限,其反映的是授权的结果。比如授予某个角色对计算机资源有读的权限,则代表了一个许可的存在,这个许 可表示:角色获取了对计算机资源的读许可。针对操作来说,其描述的是许可和操作之间的一种关联关系,而这层关系则表示了某一角色对某一操作所具有的权限及 权限状态。


     
角色和指派(Assignment)

    指派包含两个方面,用户指派和许可指派。用户指派表示的是,将用户指派给特定的角色。许可指派表示的是为角色指派计算机资源的访问和操作许可。

 

会话(session)

    会话表示的是用户和角色之间的关系。用户每次必须通过建立会话来激活角色,得到相应的访问权限。

 

角色和角色等级(Role Hierarchies)

    角色本身仅仅只是一个名词,其本身并不能代表权限的大小。比如,我们可以定一个“Director”的角色,也可以定一个“Project Leader”的角色。对于现实中我们来说,看到这样两个角色,就清楚 DIR 的权限要比一个 PL 的权限级别高。但是对计算机来说,这两个角色仅仅是两个“词语”,是等同的。可以采用分等级角色,在角色上实现层次化来解决这些问题。也可以采用复合角色 (其表示的就是一个角色组的概念),对角色实现一定的分组和复合,以便于权限指派。在一些 OA 产品中经常出现分等级角色。
   


限制(Constraints)
   
    模型中的职责分离关系(Separation of Duty),用于控制冲突(Conflict)。静态职责分离(Static SD)指定角色的互斥关系,用于用户指派阶段。避免同一用户拥有互斥的角色。实现简单,角色互斥语义关系清楚,便于管理不够灵活,不能处理某些实际情况。 动态职责分离(Dynamic SD)指定角色的互斥关系,用于角色激活阶段。允许同一用户拥有某些互斥的角色,但是不允许该用户同时激活互斥的角色。更灵活,直接与会话挂钩,适应实际 管理需要,实现复杂,不易管理。

             

 

 

参考文献

《AN INTRODUCTION TO ROLE-BASED ACCESS CONTROL》 NIST

《工作流授权控制模型》        胡长城

《基于角色的权限管理综述》 俞诗鹏

 

 

最后,感谢宏云博士对本文翻译提供的指导。   


请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处:http://www.blogjava.net/rosen

posted @ 2006-10-26 21:31 Alex 阅读(477) | 评论 (0)编辑 收藏

     摘要: 前言 : 权限往往是一个极其复杂的问题,但也可简单表述为这样的逻辑表达式:判断“ Who 对 What(Which) ...  阅读全文
posted @ 2006-10-26 21:28 Alex 阅读(367) | 评论 (0)编辑 收藏

转自 javaEye


很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。
我的经验主要来自hibernate2.1版本,基本原理和3.0、3.1是一样的,请原谅我的顽固不化。

hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。

二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询缓存,加上
hibernate.cache.use_query_cache=true

缓存可以简单的看成一个Map,通过key在缓存里面找value。

Class的缓存
对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是 iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:
<cache usage="read-write"/>
如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如 果eternal="false",超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put 的元素超过500个时,如果overflowToDisk="true",就会把缓存中的部分数据保存在硬盘上的临时文件里面。
每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。
当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。
这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候 是第一次,而且每次查询的条件通常是不一样的,假如数据库里面有100条记录,id从1到100,第一次list的时候出了前50个id,第二次 iterate的时候却查询到30至70号id,那么30-50是从缓存里面取的,51到70是从数据库取的,共发送1+20条sql。所以我一直认为 iterate没有什么用,总是会有1+N的问题。
(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只select id比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页20条的话,iterate共需要执行21条语句,list虽然选择 若干字段,比iterate第一条select id语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是 list快。)
如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了

查询缓存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
然后
query.setCacheable(true);//激活查询缓存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可选
第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

对于查询缓存来说,缓存的key是根据hql生成的sql,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
参数是"tiger%",那么查询缓存的key*大约*是这样的字符串(我是凭记忆写的,并不精确,不过看了也该明白了):
select * from cat c where c.name like ? , parameter:tiger%
这样,保证了同样的查询、同样的参数等条件下具有一样的key。
现在说说缓存的value,如果是list方式的话,value在这里并不是整个结果集,而是查询出来的这一串ID。也就是说,不管是list方 法还是iterate方法,第一次查询的时候,它们的查询方式很它们平时的方式是一样的,list执行一条sql,iterate执行1+N条,多出来的 行为是它们填充了缓存。但是到同样条件第二次查询的时候,就都和iterate的行为一样了,根据缓存的key去缓存里面查到了value,value是 一串id,然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。
可以看出来,查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候,都是既填充查询缓存又填充class缓存的。
这里还有一个很容易被忽视的重要问题,即打开查询缓存以后,即使是list方法也可能遇到1+N的问题!相同条件第一次list的 时候,因为查询缓存中找不到,不管class缓存是否存在数据,总是发送一条sql语句到数据库获取全部数据,然后填充查询缓存和class缓存。但是第 二次执行的时候,问题就来了,如果你的class缓存的超时时间比较短,现在class缓存都超时了,但是查询缓存还在,那么list方法在获取id串以 后,将会一个一个去数据库load!因此,class缓存的超时时间一定不能短于查询缓存设置的超时时间!如果还设置了发呆时间的话,保证class缓存 的发呆时间也大于查询的缓存的生存时间。这里还有其他情况,比如class缓存被程序强制evict了,这种情况就请自己注意了。

另外,如果hql查询包含select字句,那么查询缓存里面的value就是整个结果集了。

当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢?
hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时 间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这 些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。

Collection缓存
需要在hbm的collection里面设置
<cache usage="read-write"/>
假如class是Cat,collection叫children,那么ehcache里面配置
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。
这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新。

缓存策略
只读缓存(read-only):没有什么好说的
读/写缓存(read-write):程序可能要的更新数据
不严格的读/写缓存(nonstrict-read-write):需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好
事务缓存(transactional):缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过

读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。
在hibernate2.1的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到60秒后超时。
不严格读写缓存不锁定缓存中的数据。

使用二级缓存的前置条件
你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过 hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大批量更新和删 除是不更新二级缓存的,但是据说3.1已经解决了这个问题。
这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。
SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有3个查询缓存会用到这个表,用evictQueries (String cacheRegion)移除了3个查询缓存,然后用evict(Class persistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的 jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?

----------------------------------------------------

总结:
不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。
如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。
在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为 底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。

终于写完了,好累……

posted @ 2006-10-23 14:30 Alex 阅读(623) | 评论 (1)编辑 收藏

在Struts或别的框架中集成Spring的时候,Spring向我们提供了获得context的方法 getApplicationContext,那在jsp中如何获得呢?

ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext
(
this.getServletConfig().getServletContext());

建议在项目中开发的时候提供一个singleton对外公布统一的applicationContext,毕竟不是每个人都一定能获得web环境或servlet.

posted @ 2006-10-23 11:03 Alex 阅读(2529) | 评论 (0)编辑 收藏

碰到一个奇怪的问题,Spring在启动的时候得listener提示启动失败,打开log也没有任何信息,最后把log4j打开 :

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        
<layout class="org.apache.log4j.PatternLayout">
            
<param name="ConversionPattern"
                   value
="%p - %C{1}.%M(%L) | %m%n"/>
        
</layout>
    
</appender>

    
<logger name="org.apache">
        
<level value="WARN"/>
    
</logger>


    
<logger name="net.sf.hibernate">
        
<level value="WARN"/>
    
</logger>

    
<logger name="org.springframework">
        
<level value="DEBUG"/>
    
</logger>
    
<!--
    <logger name="org.appfuse">
        <level value="DEBUG"/>
    </logger>
-->
    
<root>
        
<level value="DEBUG"/>
        
<appender-ref ref="CONSOLE"/>
    
</root>

</log4j:configuration>

提示说applicationContext.xml的编码有问题,最后改为UTF-8解决
posted @ 2006-10-23 10:57 Alex 阅读(1380) | 评论 (0)编辑 收藏

打印可以用控件实现,保存为excel也可以用POI实现,不过如果仅仅是对当前页面的指定区域作打印或者Excel导出可以用js实现,还是挺简单的.

保存为Excel:

function saveAsExcel(HeadName, DivName) {
            
var s = "<center>" + HeadName + "</center>" + "\r\n";
            s 
+= DivName.innerHTML;
            
var xlsWindow = window.open("""_blank""width=1,height=1,scrollbars=no,toolbar=no");
            xlsWindow.document.write(s);
            xlsWindow.document.close();
            xlsWindow.document.execCommand('Saveas', 
true, '%homeDrive%\\Data.xls')
            xlsWindow.close();
        }


打印当前页面:

function PrintDataSoure(HeadName1,HeadName2,HeadName3,DivName,TailName1) {
  
var oldBody=document.body.innerHTML;
  
var Div1=DivName.innerHTML;
  
var css = '<style type="text/css" media=all>+
  'p { line
-height: 120%}' +
  '.fhead {   font
-size: 9pt; text-decoration: none; color: 104A7B}' +
  '.ftitle { line
-height: 120%; font-size: 18px; color: #000000}' +
  'td { font
-size: 10px; color: #000000}' +
  '
</style>' ;

  
var body ='<table width="640" border="0" cellspacing="0" cellpadding="5">+
  ' 
<tr> ' +
  ' 
<td class="fbody">+
  ' 
<b><div align="center">'+'<font size="+1" class=fhead>'+ HeadName1 + '</div>'+'</font></b>'+
  ' 
<b><div align="center">'+'<font size="+1" class=fhead>'+ HeadName2 + '     ' + HeadName3 +'</div></font></b>'+
  ' 
</td>+
  ' 
</tr>+
  ' 
<tr> ' +
  ' 
<td class="fbody">+
  ' 
<div align="center" class=ftitle>+ Div1 + '</div>'+
  ' 
<b><div align="right">'+'<font size="+1" class=fhead>'+ '      </div>'+'</font></b>'+
  ' 
<b><div align="right">'+'<font size="+1" class=fhead>'+ TailName1 + '</div>'+'</font></b>'+
  ' 
</td>+
  ' 
</tr>+
  '
</table>';
document.body.innerHTML 
= '<center>+ css + body +'<OBJECT classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2" height=0 id=wb name=wb width=0></OBJECT>'+'</center>';
wb.execwb(
6,6);
document.body.innerHTML
=oldBody;
}




posted @ 2006-10-21 12:19 Alex 阅读(3136) | 评论 (0)编辑 收藏

     摘要: key words:Spring,jdbcTemplate 注:因为Spring是以后的一个趋势,Hibernate的集成已经很好了,对于单独的jdbc的操作用DBUtils感觉已经没有什么必要,不如全部转到Spring的jdbc支持,从成本来考虑似乎更合适。 本文转自 这里 ...  阅读全文
posted @ 2006-10-16 16:28 Alex 阅读(2743) | 评论 (0)编辑 收藏

     摘要:   阅读全文
posted @ 2006-10-10 11:09 Alex 阅读(2052) | 评论 (3)编辑 收藏

Facade用的非常的广了,以前刚接触的时候有个误解,总觉得Facade是简单的,而它后面的支撑服务是复杂的,对于客户来说却是简单的,现在来看,不完全对,或者说只是说对了一半,因为有时候恰恰是Facade是复杂的.

我们举一个例子,比如发送短信,我们一般就定义一个MessageService的服务类,里面只提供一个方法就行了,sendToUser(String phone,String content)
但是到了客户端的时候有了自己的 "方言",比如它不是关心一个抽象的用户,它只知道向教师发送短信,或者向学生发送短信,或者向家长发送短信。

示例如下:

facade.png
由图中可以看到,Facade的内容非常丰富,而支撑它的服务类却很简单,在开发过程中我们一般先实现通用的ServiceA,然后根据进一步的需求做一个面向具体复杂的Facade.



在Spring提供的sample里发现一个小技巧,就是Facade和ServiceA都是接口,然后提供一个实现二者的支撑类:


public class PetStoreAnnotationImpl implements PetStoreFacade, OrderService {

    
private AccountDao accountDao;

    
private CategoryDao categoryDao;

    
private ProductDao productDao;

    
private ItemDao itemDao;

    
private OrderDao orderDao;


    
//-------------------------------------------------------------------------
    
// Setter methods for dependency injection
    
//-------------------------------------------------------------------------

    
public void setAccountDao(AccountDao accountDao) {
        
this.accountDao = accountDao;
    }

    
public void setCategoryDao(CategoryDao categoryDao) {
        
this.categoryDao = categoryDao;
    }

    
public void setProductDao(ProductDao productDao) {
        
this.productDao = productDao;
    }

    
public void setItemDao(ItemDao itemDao) {
        
this.itemDao = itemDao;
    }

    
public void setOrderDao(OrderDao orderDao) {
        
this.orderDao = orderDao;
    }


    
//-------------------------------------------------------------------------
    
// Operation methods, implementing the PetStoreFacade interface
    
//-------------------------------------------------------------------------

    
public Account getAccount(String username) {
        
return this.accountDao.getAccount(username);
    }

    
public Account getAccount(String username, String password) {
        
return this.accountDao.getAccount(username, password);
    }

    
public void insertAccount(Account account) {
        
this.accountDao.insertAccount(account);
    }

    
public void updateAccount(Account account) {
        
this.accountDao.updateAccount(account);
    }

    
public List getUsernameList() {
        
return this.accountDao.getUsernameList();
    }

    
public List getCategoryList() {
        
return this.categoryDao.getCategoryList();
    }

    
public Category getCategory(String categoryId) {
        
return this.categoryDao.getCategory(categoryId);
    }

    
public List getProductListByCategory(String categoryId) {
        
return this.productDao.getProductListByCategory(categoryId);
    }

    
public List searchProductList(String keywords) {
        
return this.productDao.searchProductList(keywords);
    }

    
public Product getProduct(String productId) {
        
return this.productDao.getProduct(productId);
    }

    
public List getItemListByProduct(String productId) {
        
return this.itemDao.getItemListByProduct(productId);
    }

    
public Item getItem(String itemId) {
        
return this.itemDao.getItem(itemId);
    }

    
public boolean isItemInStock(String itemId) {
        
return this.itemDao.isItemInStock(itemId);
    }

    
public void insertOrder(Order order) {
        
this.orderDao.insertOrder(order);
        
this.itemDao.updateQuantity(order);
    }

    
public Order getOrder(int orderId) {
        
return this.orderDao.getOrder(orderId);
    }

    
public List getOrdersByUsername(String username) {
        
return this.orderDao.getOrdersByUsername(username);
    }

}


看起来似乎不错,不过仔细想想个人认为还是不是太好,总的感觉就是层次不清晰,因为很多时候Facade和Service之间是被服务与服务的关系,所以理当分开。 同时,这个类有点倾向于"万能类"了,能分还是分开好.这和我们以前提到的dao又背离过来了(以前我们提倡一个业务一个dao,现在觉得只用一个通用的dao更合适),这个并不矛盾,具体问题具体看待.

欢迎各位拍砖.
posted @ 2006-10-09 22:27 Alex 阅读(1370) | 评论 (2)编辑 收藏

设计模式之Visitor

板桥里人 http://www.jdon.com 2002/05/05(转载请保留)

模式实战书籍《Java实用系统开发指南》

Visitor访问者模式定义
作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.

在Java中,Visitor模式实际上是分离了collection结构中的元素和对这些元素进行操作的行为.

为何使用Visitor?
Java的Collection(包括Vector和Hashtable)是我们最经常使用的技术,可是Collection好象是个黑色大染缸,本来有 各种鲜明类型特征的对象一旦放入后,再取出时,这些类型就消失了.那么我们势必要用If来判断,如:


Iterator iterator = collection.iterator()
while (iterator.hasNext()) {
   Object o = iterator.next();
   if (o instanceof Collection)
      messyPrintCollection((Collection)o);
   else if (o instanceof String)
      System.out.println("'"+o.toString()+"'");
   else if (o instanceof Float)
      System.out.println(o.toString()+"f");
   else
      System.out.println(o.toString());
}
在上例中,我们使用了 instanceof来判断 o的类型.

很显然,这样做的缺点代码If else if 很繁琐.我们就可以使用Visitor模式解决它.

如何使用Visitor?
针对上例,定义接口叫Visitable,用来定义一个Accept操作,也就是说让Collection每个元素具备可访问性.

被访问者是我们Collection的每个元素Element,我们要为这些Element定义一个可以接受访问的接口(访问和被访问是互动的,只有访问者,被访问者如果表示不欢迎,访问者就不能访问),取名为Visitable,也可取名为Element。

public interface Visitable
{
   public void accept(Visitor visitor);
}

被访问的具体元素继承这个新的接口Visitable:

public class StringElement implements Visitable
{
   private String value;
   public StringElement(String string) {
      value = string;
   }

   public String getValue(){
      return value;
   }


   //定义accept的具体内容 这里是很简单的一句调用
   public void accept(Visitor visitor) {
      visitor.visitString(this);
   }
}


上面是被访问者是字符串类型,下面再建立一个Float类型的:

public class FloatElement implements Visitable
{
   private Float value;
   public FloatElement(Float value) {
      this.value = value;
   }

   public Float getValue(){
      return value;
   }


   //定义accept的具体内容 这里是很简单的一句调用
   public void accept(Visitor visitor) {
      visitor.visitFloat(this);
   }
}


我 们设计一个接口visitor访问者,在这个接口中,有一些访问操作,这些访问操作是专门访问对象集合Collection中有可能的所有类,目前我们假 定有三个行为:访问对象集合中的字符串类型;访问对象集合中的Float类型;访问对象集合中的对象集合类型。注意最后一个类型是集合嵌套,通过这个嵌套 实现可以看出使用访问模式的一个优点。

接口visitor访问者如下:

public interface Visitor
{

   public void visitString(StringElement stringE);
   public void visitFloat(FloatElement floatE);
   public void visitCollection(Collection collection);

}

访问者的实现:

public class ConcreteVisitor implements Visitor
{
   //在本方法中,我们实现了对Collection的元素的成功访问
   public void visitCollection(Collection collection) {
      Iterator iterator = collection.iterator()
      while (iterator.hasNext()) {
         Object o = iterator.next();
         if (o instanceof Visitable)
            ((Visitable)o).accept(this);
      }
   }

   public void visitString(StringElement stringE) {
      System.out.println("'"+stringE.getValue()+"'");
   }
   public void visitFloat(FloatElement floatE){
      System.out.println(floatE.getValue().toString()+"f");
   }

}

在上面的visitCollection我们实现了对Collection每个元素访问,只使用了一个判断语句,只要判断其是否可以访问.

StringElement只是一个实现,可以拓展为更多的实现,整个核心奥妙在accept方法中,在遍历Collection时,通过相应的accept方法调用具体类型的被访问者。这一步确定了被访问者类型,

如果是StringElement,而StringElement则回调访问者的visiteString方法,这一步实现了行为操作方法。

客户端代码:

Visitor visitor = new ConcreteVisitor();

StringElement stringE = new StringElement("I am a String");
visitor.visitString(stringE);

Collection list = new ArrayList();
list.add(new StringElement("I am a String1"));
list.add(new StringElement("I am a String2"));
list.add(new FloatElement(new Float(12)));
list.add(new StringElement("I am a String3"));
visitor.visitCollection(list);

客户端代码中的list对象集合中放置了多种数据类型,对对象集合中的访问不必象一开始那样,使用instance of逐个判断,而是通过访问者模式巧妙实现了。

至此,我们完成了Visitor模式基本结构.

使用Visitor模式的前提
使用访问者模式是对象群结构中(Collection) 中的对象类型很少改变。

在两个接口Visitor和Visitable中,确保Visitable很少变化,也就是说,确保不能老有新的Element元素类型加进来,可以变化的是访问者行为或操作,也就是Visitor的不同子类可以有多种,这样使用访问者模式最方便.

如果对象集合中的对象集合经常有变化, 那么不但Visitor实现要变化,Visistable也要增加相应行为,GOF建议是,不如在这些对象类中直接逐个定义操作,无需使用访问者设计模式。

但是在Java中,Java的Reflect技术解决了这个问题,因此结合reflect反射机制,可以使得访问者模式适用范围更广了。

Reflect技术是在运行期间动态获取对象类型和方法的一种技术,具体实现参考Javaworld的英文原文.
posted @ 2006-09-28 09:30 Alex 阅读(530) | 评论 (0)编辑 收藏

key words:软件设计 建模 UML

这篇文章以前就看到了,后来再想看的时候居然找不到了,感觉写的不错,作为想把软件开发往深里整地朋友有借鉴作用。

转自这里

前段时间把一个界面框架完成了,今天基于这个框架开发一个小模块,在这里把这个模块设计的全过程记录下来,希望大家讨论并指正。

一、起因

公 司交给我一个任务,为测试员写一个手机模拟界面,以方便她们的手机短信测试。过去她们都是用MC4J直接调用公司服务器的MBean服务来模拟进行测试, 以验证我们整个系统平台。这种测试主要是检查收发短信是否正常,而我的要做的工作就是,让她们在测试的时候更方便更直观。

二、需求

我和测试员陈MM(也就是软件的使用者)约定了一个时间,大家一起来讨论这个软件的需求。

1、首先,我大概了解了一下她们的测试工作,知道我要做个什么东东。

2、然后我回去思考了一下,再次找她详细了解其测试的具体步骤,并在一张白纸上以UML用例图的方式,记录下需求的功能。用例是什么?用例就是需求,就是你的软件应该具有的功能,当然用例图只是概括性的对功能进行了描述。

3、最后,我坐在我的电脑前开始用MagicDraw UML来画用例图(我不喜欢用Rose,那玩意太笨重了,界面友好性也不好)。在画用例图的时候,我发现了一些隐含的功能,这些是陈MM在和我做需求时没有考虑到的(注:开发者应该为用户挖掘隐含需求)。我和陈MM一一确定了这些我新发现的需求,最后得到如下的用例图。

(1)手机前台测试操作的用例图(说明:include是指某用例包含(include)子用例)

[用例]手机.jpg
 (2)后台管理
[用例]后台管理.jpg


三、界面设计

接下来是界面设计。既然是手机模拟,我很自然就拿我的motorola手机的操作界面来做参考。不过这里应该注意到,手机操作环境和电脑操作环境不尽相同(比如说电脑有鼠标,还有键盘可以输入文字),所以没有必要唯妙唯肖的完全模枋,还是以使用者操作方便为主。

界 面设计是很重要的一步,不要一上来就写程序,一定要先做到心中有个大概,否则返工的可能性就很大。而且,把界面拿出来给客户看,客户也就能做到心中有数, 还能尽早提出一些新需求和意见来。千万不要等到软件做完了再拿给客户看,到时客户看了如果要修改,那就做太多白费工了。

由于软件界面相对简单,陈MM基本没有提修改意见,但这不是个好兆头。不过极限编程就是要拥抱变化不是^_^。咱不怕她改,只要大致的界面她能定下来就行了。

界面我喜欢用Visio来画,当然也听说有人喜欢用VB来快速构建界面原型的,看个人喜好了。整个界面如下:
[界面设计]手机.jpg



这个是后台管理界面
[界面设计]号码管理.jpg



四、类图

类图反映了软件的数据模型。在设计数据模型,我参考了界面设计图和用例图,找出一个个的类。然后参照用例图的一个个功能,设计出了各类的属性和方法。设计初始的类图当然不可能很详细,但至少应该看到个大概。有错误不要紧,后期可以慢慢修正,但大体关系就算定下来了。

Neil(公司CTO,一个40岁左右的真正的资深程序员)说:看一个软件的设计主要看两个类:类图和时序图。类图确定了软件数据模型的静态关型,时序图则是数据模型的动态关系。

类图如下,看英文大致可以知道类/属性/方法的含义和作用了,就不一一介绍了。


[类图].jpg



五、时序图

时序图是本文最后一个图,时序图表明了用例图中各功能的实现方案,同时也反应了类图中各类的交互关系。以后程序的逻辑和时序图基本一致。不过,有些人会去画得很详细的时序图,详细到都快赶上伪代码级别了,我觉得这没必要。我把时序图看做反映自己思路的大概过程,所以也就画个大概。

我认为时序图要简洁易懂,这样以后你的后继维护者,拿到这个软件的时序图(当然也包括用例图、类图),就能明白你的大概设计思路。另外,画时序图也能整理自己的思路,同时还可以对类图的设计进行验证。在画这个时序图的过程中,我就纠正了在类图中的几处考虑不周的地方。

总结:时序图可以(1)整理思路(2)验证类的设计(3)是很好的软件文档,对维护者理解代码很有帮助。

这里仅给出其中几个时序图(实际上我也没有把用例都画完,有些类似的简单的,就忽略了)

(1)新增一个手机号码
[时序图]add phone number.jpg

(2)关机
[时序图]power off.jpg
(3)开机
[时序图]power on.jpg
(4)发送短信
[时序图]send message.jpg



到这里设计阶段就完成了,用时一天。下一步是编码,将应用TDD先写测试代码的方式来写代码,下次再介绍了。


作者简介

陈刚,广西桂林人,著作有《Eclipse从入门到精通》
您可以通过其博客了解更多信息和文章:http://www.ChenGang.com.cn
版权声明:本博客所有文章仅适用于非商业性转载,并请在转载时注明出处及作者的署名。

posted @ 2006-09-22 13:16 Alex 阅读(934) | 评论 (0)编辑 收藏

key words:软件架构师
转自here

现在软件架构师满天飞,是个写代码的都称自己为软件架构师,就象开个公司管上四五号人就给自己按个CEO头衔一样,着实让人好笑。于是到网上GOOGLE了一下看看软件构架师具体是个啥东东,有想做货真价实的构架师,就朝着那方向努力吧。网摘如下:

软件架构师的职责:将客户的需求转换为规范的开发计划及文本,并制定这个项目的总体架构,指导整个开发团队完成这个计划。

软件架构师的具体工作:
    (
1)在需求阶段,软件架构师主要负责理解和管理非功能性系统需求,比如软件的可维护性、性能、复用性、可靠性、有效性和可测试性等等,此外,架构师还要经常审查和客户及市场人员所提出的需求,确认开发团队所提出的设计;
    (
2)在需求越来越明确后,架构师的关注点开始转移到组织开发团队成员和开发过程定义上;
    (
3)在软件设计阶段,架构师负责对整个软件体系结构、关键构件、接口和开发政策的设计;
    (
4)在编码阶段,架构师则成为详细设计者和代码编写者的顾问,并且经常性地要举行一些技术研讨会、技术培训班等;
    (
5)随着软件开始测试、集成和交付,集成和测试支持将成为软件架构师的工作重点;
    (
6)在软件维护开始时,软件架构师就开始为下一版本的产品是否应该增加新的功能模块进行决策。
 
软件架构师的要求
      (
1)必须对开发技术非常了解,具有丰富的软件设计与开发经验,关键时候能对技术的选择作出及时、有效的决定。
      (
2)有良好的组织管理能力:沟通、领导、团队协作
      (
3)构件通信机制方面的知识:远程调用、JAVARMI、CORBA、COM/DCOM、各种标准的通信协议、网络服务、面对对象数据库、关系数据库等等

成长为软件架构师的几个阶段:
      (
1)构架师胚胎(程序员):语言基础、设计基础、通信基础等,内容包括java、c、c++、uml、RUP、XML、socket通信(通信协议)
      (
2)构架师萌芽(高级程序员):分布式系统组建等内容,包括分布式系统原理、ejb、corba、com/com+、webservice、网络计算机、高性能并发处理等
      (
3)构架师幼苗(设计师):透彻掌握设计模式,包括设计模式(c++版本、java版本)、ejb设计模式、J2EE构架、UDDI、软件设计模式等。此期间,最好能够了解软件工程在实际项目中的应用以及小组开发、团队管理
posted @ 2006-09-22 13:14 Alex 阅读(644) | 评论 (0)编辑 收藏

key words: DAO模式

今天在看一篇文章时提到了DAO,这个东西以前也经常接触,突然想回顾一下,于是打开Appfuse里看看dao模式(记忆中appfuse里就是很多的dao)

截图如下:
appfusedao.png

很清楚,左边的部分是基础模块,原意是想让右边的DAO和实现能够重用左边的,可是我找了半天也没看到需要重用左边的东西,因为在client调用的所有方法中都是明确的getUser或removeUser,就是没有getObject或者removeObject,那么不禁要问,左边的基础dao和它的实现还有什么意义呢?所以我的第一想法就是把左边的去掉得了,还好,果然有支持我想法的做法,打开springside,我们看到如下的结构:
截图2
springside.png
这里的做法更厉害,连interface也不要了,不过效果确实是很简洁,在bookmanager里完全重用了左边的基本方法 :
public Book get(Integer id) {
        
return (Book) super.get(id);
    }

    
public void save(Book book) {
        
super.save(book);
        logger.info(
"保存图书.图书详情:" + book.toString());
    }

    
public void remove(Integer id) {
        
super.remove(id);
        logger.info(
"删除图书.图书ID:" + id);
    }

这是一个更务实的做法,如果你的项目并不是那么那么的复杂完全可以这么做,当然要说其有什么缺点显然和没有了interface的天生属性决定了的,不可强求,若你对测试隔离面向接口以及你能想到的所有关于interface的好处,那就用你自己的方式吧。

现在我在想一个问题,难道appfuse里的继承的基本关于object的做法就没有地方可用了么?


其时正好碰到java视线这一篇文章有点相关,你可以参考一下:
用DAO模式有什么好处?


ps:
以前是一个基本的dao,然后n个业务dao继承于这个基本dao,现在提供一个通用dao,每个要用到的地方直接继承用就是了,更务实了!
不过,有一个小小的瑕疵,就是对于service中类似getUserByName或者getPeopleByEmail方法中需要提供给dao一个sql语句,从mvc的角度看,在service中看到了db层,有点不雅,不过综合来看这个还是可以或略,不要专牛角尖嘛  :)

posted @ 2006-09-21 16:05 Alex 阅读(2439) | 评论 (0)编辑 收藏

key words: VSS IDEA

vss实在是太恶心了,提交各东西还不支此右键,要是要在开发一段时间后提交多个不同的目录下的文件费死劲了,我压根不知道哪个文件还没有提交,Fuck Microsoft!

至少,我们还有IDEA  :)  在开发工具里提交的一个好处就是直观和简便.Let's go!

具体指导请看这里
你需要填写关于VSS的相关信息 ,截图如下:
vss.png

其中的vss project可能有点困难,属于vss自己的术语,你自己实际上是不知道的,方法是打开vss客户端,通过这个工具查找到你所在的项目的vss project到底是什么,右键项目名称,出现如下dialog
vss2.png

OK了

在IDEA里看看效果,截图如下:
vss3.png


Fine.
posted @ 2006-09-21 11:40 Alex 阅读(3023) | 评论 (3)编辑 收藏