??xml version="1.0" encoding="utf-8" standalone="yes"?> 1. 常用服务器模?/strong> 2. 以上三类的服务器比较 3. 多进E的q发服务?/strong> 以上3U方式性能比较Q?br />
a.每个q接fork一个进E:处理smtp{状态较多,数据量比较大时比较简单实用,M性能不大好?br />
b.Preforkq程Q各个子q程竞争acceptQ比较简单,性能不错?br />
c.Preforkq程Q由父进EaccepthQ通过管道{发fd到子q程Q代码复杂,性能一般不如上一U?/p>
4. 多线E的q发服务?/strong> 5. 多进E与多线E的比较 6. 一些流行的|络服务器采用的模型 Sendmail: 采用多进E,每个q接fork一个进E? Apache1.3:采用多进E? preforkq程 UdQQ: Prefork多个q程Q竞争accept, http://blog.csdn.net/proad/archive/2008/04/16/2296925.aspx
a.q代服务器:只有一个进E?U程处理h。一般ؓ单进E?加上select多\复用,非阻塞socket?br />
b.q代/q发混合型服务器Q^时P代处理,Ҏ耗大的请求ƈ发处理。处理请求时讄一个超Ӟ当请求的处理旉时Ӟ创徏一个进E?U程Q把处理转给新的q程/U程处理Q主q程/U程l箋处理其他h?br />
c.q发服务器:多个q程/U程q发处理h?/p>
q代服务器:最单,性能不高?br />
q发服务器:性能较高Q但l构相对比较复杂Q开发难度中{?br />
q代/q发混合型服务器Q性能不错Q但l构通常比单U的q发服务器更复杂?/p>
a. 每个q接fork一个进E:主进Eaccpetq接Q有新连接到来时fork一个进E,然后l箋acceptQ等待新的连接。数据传输由子进E处理,处理完后子进Eexit。每个子q程只处理一个连接?br />
b. Preforkq程Q主q程预先fork一些进E,各个子进E竞争acceptQ然后处理数据传输。一个子q程可以处理一个连接,也可以同时处理多个连接(通过select{)?br />
c. Preforkq程Q由父进EaccepthQ通过管道{发fd到子q程Q子q程收到fd后,处理数据传输Q处理结束后通知父进E。父q程处理的事情比较简单,Ҏ监控子进E?/p>
a.每个q接一个线E?br />
b.Prethread多个U程Q各个线E互斥accept
c.Prethread多个U程Q主U程acceptq分发连接给子线E?/p>
使用U程的模型:性能比用进E要高,但代码比较复杂,对代码质量要求更高,U程出错后可能会影响到所有线E,多进E的模式一个进E出错一般不会媄响其他进E?br />
多线E模型共享数据比较简单有效,多进E模型共享数据比较麻烦,效率也不如线E?/p>
每个q接fork一个子q程
子进E只处理一个连?br />
子进Efork一个localmailq程Q可以由用户自己~写Q,通过道把数据{llocalmail处理Q把邮g处理业务逻辑独立出来
优点Q结构简单,不用l护复杂的状态机
子进E竞争acceptQ每ơ只处理一个连?br />
主进E不acceptQ根据负载情况调整子q程数量
子进E运行一D|间后Q主q程会让它退出,然后创徏一个新的进E,防止内存泄漏{?br />
主进E通过shared memory监控子进E?/p>
典型的一问一{TCP服务器,l构?br />
每个q程通过select可以同时处理多个q接
采用q种l构的原因有Q?br />
每秒h<1000Q可以满?br />
l构单,Ҏ开发、维?/p>
http://www.molss.gov.cn/gb/news/2007-06/30/content_184630.htm
B)?/span>?/span>人民共和?/span>力_合同?/span>?/span>施条?/span>(解释力_法实?/span>)
http://www.gov.cn/flfg/2008-09/19/content_1099500.htm
C)关于立力_关系有关事项的通知
http://www.law-lib.com/law/law_view.asp?id=92395
D)上v市女职工力_保护办法
http://www.shanghai.gov.cn/shanghai/node2314/node3124/node3125/node3133/userobject6ai655.html
· C)的相兛_容:
用h单位未与力_者签订劳动合同,认定双方存在力_关系时可参照下列凭证Q?/span>
(一)工资支付凭证或记?/span>(职工工资发放花名?/span>)、缴U_社会保险费的记录;
(?/span>)用h单位向劳动者发攄“工作?#8221;?#8220;服务?#8221;{能够证明n份的证gQ?/span>
· B) 的相兛_容:
W六?span style="font: 7pt 'Times New Roman'"> 用h单位自用工之日v过一个月不满一q?/span>未与力_者订立书面劳动合同的Q应当依?span style="color: blue">力_合同法第八十二条的规定向力_者每月支付两倍的工资Qƈ与劳动者补订书面劳动合?/span>Q劳动者不与用人单位订立书面劳动合同的Q用人单位应当书面通知力_者终止劳动关p,q依照劳动合同法W四十七条的规定支付l济补偿?/span>(1Q相当于l?/strong>2倍工资,2Q补合同Q?/strong>3Q如果辞退Q再按照有合同补偿)
W二十七条 力_合同法第四十七条规定?strong>l济补偿的月工资按照力_者应得工资计,包括计时工资或者计件工资以及奖?/strong>?/span>
· A)的相兛_容:
W四十二条 力_者有下列情Ş之一的,用h单位不得依照本法W四十条、第四十一条的规定解除力_合同Q?/span>
Q四Q女职工在孕期、期、哺x?/strong>
W四十七条 l济补偿按劳动者在本单位工作的q限Q?strong>每满一q支付一个月工资的标准向力_者支付。六个月以上不满一q的Q按一q计;不满六个月的Q向力_者支付半个月工资的经补ѝ?/span>
W八十二条 用h单位自用工之日v过一个月不满一q未与劳动者订立书面劳动合同的Q应当向力_者每月支付二倍的工资?/strong>
用h单位q反本法规定不与力_者订?strong>无固定期限劳动合?/strong>的,自应当订立无固定期限力_合同之日起向力_者每?strong>支付二倍的工资?/span>
W八十七条 用h单位q反本法规定解除或者终止劳动合同的Q应?strong>依照本法W四十七?/span>规定的经补?strong>标准的二?/span>向劳动者支付赔偉K?/span>
W十四条 无固定期限劳动合同,是指用h单位与劳动者约定无定l止旉的劳动合同?/span>
用h单位与劳动者协商一_可以订立无固定期限劳动合同。有下列情Ş之一Q劳动者提出或者同意箋订、订立劳动合同的Q除力_者提立固定期限劳动合同外Q应?strong>订立无固定期限劳动合?/strong>Q?/span>
Q一Q劳动者在该用人单?span style="color: red">q箋工作满十q?/strong>的;
Q二Q用人单位初ơ实行劳动合同制度或者国有企业改刉新订立劳动合同时Q劳动者在该用人单位连l工作满十年且距法定退休年龄不_q的Q?/span>
Q三Q?strong>q箋订立二次固定期限力_合同Q且力_者没有本法第三十九条和第四十条第一V第二项规定的情形,l订力_合同的?/span>
用h单位自用工之日v满一q不与劳动者订立书面劳动合同的Q视为用人单位与力_者已订立无固定期限劳动合?/strong>?/span>
· D) 的相兛_容:
W十一?/span>对妊娠期的女职工Q?strong>不应廉其劳动时?/strong>Q?/span>
W十四条奌工假分别按下列情况执行Q?/span>
Q一Q单胎顺产者,l予产假九十天,其中产前休息十五天,产后休息七十五天?/span>
W十五条奌工生育后Q在其婴儿一周岁内应照顾其在每班力_旉?span style="color: red">授^两次Q包括h工喂养)?span style="color: red">每次单胎U授x间ؓ三十分钟Q亦可将两次授^旉合ƈ使用。多胞胎生育者,每多生一胎,每次Z^旉增加三十分钟?/span>
W十八条奌工在产假期间的工资照发。按本规定n受的产前假和Z^假的工资按本人原工资?span style="color: red">癑ֈ之八十发l?/span>。单位增加工资时Q女职工按规定n受的产前假、假、哺乛_Q应作出勤对待?/span>
· l论Q?/span>
1Q?span style="font: 7pt 'Times New Roman'"> 认定力_关系Q工作证
2Q?span style="font: 7pt 'Times New Roman'"> 是否{?/span>
3Q?span style="font: 7pt 'Times New Roman'"> 如果没签合同Q怎么补偿Q?/span>1Q?strong>相当于给2倍工资,2Q补合同Q?/strong>3Q如果辞退Q再按照有合同补偿)
4Q?span style="font: 7pt 'Times New Roman'"> 如果是固定合同,怎么补偿Q?/span>N+1Q?/strong>
5Q?span style="font: 7pt 'Times New Roman'"> 如果是无期合同,2?/strong>
6Q?span style="font: 7pt 'Times New Roman'"> 孕妇怎么处理Q?/span>
1、公司辞退孕妇的补偿情冉|准是怎样Q?/span>
{:发放工资到哺x满;按工作年限计经补偉K?/span>
2、公司是否可以以我的考核和我是孕产妇不能胜Q工作为由Ҏq行降职降降薪处理Q?/span>
{:不可以?/span>
我们的工资分为基本工资(U占1/4)+岗位工资+l效工资{。是否可能出现只要不降低我的基本工资是合法的行为?
{:不合理。工资是包括了岗位工资和l效工资?/span>
3、如果公怾法破产,我是否有向集团主张赔偿的权利Q?/span>
{:破也可以主张权利,在破产胦产中优先演戏ѝ?/span>
4、如果可能需要诉诸法律,我应该准备哪些方面的举证Q?/span>
{:存在力_关系的证据最重要Q此外,工资条、怀孕的证据、结婚证、准生证
也比较重要?/span>Q?/span>按照力_?/span>42条,不得解除三期【孕期、期、哺x】妇奟뀂那么如果一定要q反力_法解除劳动关p,只能按照q反力_法,按照W八十七条进行二倍赔偿,也就?/span>3倍)
案例:
http://www.tianya.cn/publicforum/content/law/1/119373.shtml
案情Q?/span>A公司辞退B?/span>?/span>Q不?/span>?/span>B可能存在?/span>q错Q假?/span>A毫无道理毫无依据的辞退B?/span>?/span>Q?/span>
一审结果:?/span>?/span>?/span>?/span>孕期?/span>?/span>、全额期(?/span>?/span>q?/span>加了15天)?/span>?/span>?/span>75%的哺x?/span>?/span>Qƈ以入职时?/span>至三期届满ؓ力_合同?/span>pdl?/span>?/span>间计在职时?/span>Q然后以?/span>?/span>职时?/span>按照?/span>力_合同法》第八十七条?/span>?/span>?/span>赔偿金(卛_法解除的补偿金的双倍)。一?/span>不是我代理的?/span>
?/span>?/span>A公司扑ֈ我,我想当然的以?/span>Q按照?/span>力_合同法》第八十七条?/span>?/span>定,力_者可?/span>选择要求l箋履行Q不要求l箋履行的,?/span>?/span>?/span>支付双?/span>补偿卛_Q一?/span>判决属适用法律错误?/span>
先说几句废话Q自我感觉此Ҏq不错,臛_解决了安全性的问题Q也实现了统一dQ能跨^収ͼ跨服务期Q跨域名Q当焉要相应的联盟站点的支持,但从原理上绝对能跨^台。设计和具体实现的描q比较长Q今天先介绍一部分
详细说明单点dlg(SSO)的设计思想和实现方法,是日后该lgl护和扩展工作的基本依据文档。预期读者是要实现单点登?SSO)pȝ的系l设计h员,pȝ开发h员,pȝl护人员?
说明Q?
SSO是Single Sign
On的羃写,该技术主要用于用h合?br />
认证中心Q认证中心是用户注册Q成员站点管理,用户dQ验证登录信息,保存d
信息Q颁发登录认证的中心站点?nbsp;
成员站点:
成员站点是遵从认证中心规则,享用认证中心l一用户的站炏V?nbsp;
注册站点Q?/strong>如果x为成员站点,必须先在认证中心q行站点登记Q登记后Q认证中心会保存注册站点的配|信息,q将该配|信息发l注册站炏V注册站点也需保存q些配置信息Q供日后与认证中心交互时候用?nbsp;
联盟用户Q指在认证中心注册的用户Q这些用戯被所有的成员站点所׃n?br />
dhQ指成员站点向认证中心发出的带有站点配置的用L录请求信息?br />
dhQ只用户向认证中心发出的要求退出登录的h?nbsp;
dh验证Q?/strong>指的是认证中心根据存储的站点信息Ҏ员站点的dh信息q行?
源和真实性的验证?br />
dh验证Q?/strong>指认证中心在接受来自成员站点的登求的时候,对请求的来源和真实性进行的验证
d{复Q?/strong>指认证中心对l过验证的登录请求作出的{复信息。该{复包含用户的登录信息?br />
在线联盟用户?/strong>Q指的是在成员站点中Q在U的联盟用户数量?nbsp;
在线联盟用户列表Q指的是在成员站点中Q在U的联盟用户的列表信息?nbsp;
d站点清单Q?/strong>是由认证中心l护的用Ld站点信息Q当用户注销的时候,会遍历此清单Q逐个d?
本组件的设计和实现参考了下面的系l和书籍
本组件包括下面几个应用接口,分别如下Q?
它们的定义如下:
lg的工作流E描q如下:
ISite接口包括7个属性和2个方法,分别用于在认证中心用于描q和操作站点的配|?
信息?
其中Q各个属性的含义如下
属性名U?/span> |
cd |
含义 |
SiteID |
string |
站点~号Q用于表C站点的唯一性?/span> |
HomePage |
string |
当登录请求中未提供来源网址的时候,d{复发送的地址 |
LogOutUrl |
string |
在进行统一d的时候,回调的联盟站炚w面地址Q这个页面会负责销毁本站的d据信息?/span> |
PublicKey |
string |
用于数据交换时加密或{用的公钥 |
PublicAndPrivateKey |
string |
用于数据交换时加密或{用的U钥 |
FromUrlKey |
string |
用于指示联盟站点在发送登录请求和认证站点q行h验证的时候来源网址存储位置?/span> |
UidField |
string |
用于指示联盟站点在发送登录请求和认证站点q行h验证的时候用户信息的存储位置?/span> |
q包括两个方法,分别为:
Ҏ?/span> |
含义和作?/span> |
Add |
d新的联盟站点?/span> |
Validate |
验证联盟对象是否已经存在 |
该接口能在认证中心完成新联盟站点d操作Q添加之前可以验证站Ҏ否存在?
在SSOlg中,已经实现了一个默认的ISite对象。ؓDefaultServer/ DefaultSite.csQ它放|在认证中心根目录下的sites.config文g作ؓ存储介质Q通过AddҎd新联盟站点后的效果ؓQ附件中的site.config文gQ可自行下蝲文g后,看其l构?
IUser接口包括2个属性和2个方法,用于在认证中心端描和操作q联盟用戗?
其中Q各个属性的含义如下
属性名U?/span> |
cd |
含义 |
Uid |
string |
用户~号Q是用户的标?/span> |
Pwd |
string |
用户密码 |
q包括两个方法,分别为:
Ҏ?/span> |
含义和作?/span> |
Validate |
验证用户是否存在 |
Register |
d新用?/span> |
该接口能在认证中心完成新联用h加操作,d之前可以验证用户是否存在?
在SSOlg中,已经实现了一个默认的IUser对象。ؓDefaultServer/ DefaultUser.csQ它放|在认证中心根目录下的users.config文g作ؓ存储介质Q通过RegisterҎd新联盟用L效果为:附g中的users.config文gQ可自行下蝲文g后,看其l构?
IUserLoginList接口包括3个方法,用于在认证中心描q和操作用户d的站Ҏ单?
q包括三个方法,分别为:
Ҏ?/span> |
含义和作?/span> |
Add |
验证用户是否存在 |
GetLoginSites |
获取用户的登录站Ҏ?/span> |
DeleteUser |
删除用户的登录站Ҏ单数?/span> |
该接口在认证中心用于用户记录和维护用L录的站点清单
在SSOlg中,已经实现了一个默认的IUserLoginList对象。ؓDefaultServer/ UserLoginLog.csQ它通过一个Collection对象来实现用L录站Ҏ单的l护工作?
IServer接口包括2个属性和5个方法,用于接收Q验证登录请求,发送登录答复,接搜Q验证登求,创徏本地d据Q维护用L录清单?
两个属性ؓQ?
属性名U?/span> |
cd |
含义 |
Site |
ISite |
当前上下文处理请求和{复的站点对?/span> |
Uid |
string |
当前处理的上下文中的用户~号 |
q包括三个方法,分别为:
Ҏ?/span> |
含义和作?/span> |
CheckUser |
验证用户对象是否存在 |
CheckExistToken |
验证d据已经存在 |
SaveToken |
在认证中心本C存登录票?/span> |
Jump |
通过url跌{Q发送登录答?/span> |
LogOut |
l一d?/span> |
该接口在认证中心Q用于接Ӟ验证dhQ发送登录答复,接搜Q验证登求,创徏本地d据Q维护用L录清?
在SSOlg中,已经实现了一个默认的IServer对象。ؓDefaultServer/ LoginRequest.cs?
ILoginRequest接口包括2个属性,用于记录和描q联盟站点的dhQ这些信息在发出dh的时候创建,在收到登录答复的时候销毁。用于确保登录答复的不可复用性?
两个属性ؓQ?
属性名U?/span> |
cd |
含义 |
Identity |
string |
dh标志W,该标志符会发送给服务端,服务端在发送登录答复的时候会回传该标志,联盟站点会根据此标志来验证请求是否是伪造的?/span> |
TimeStamp |
DateTime |
h的时间戳 |
该接口在联盟站点Q用于记录和描述联盟站点的登录请求,q些信息在发出登录请求的时候创建,在收到登录答复的时候销毁。用于确保登录答复的不可复用性?.3 默认实现
在SSOlg中,已经实现了一个默认的ILoginRequest对象。ؓDefaultServer/ LoginRequest.cs?
ILoginRequestContainer接口包括3个方法,用于在联盟站点中记录和维护登录请?
Ҏ?/span> |
含义和作?/span> |
Add |
ddh信息 |
Check |
查登录请求是否存?/span> |
Remove |
销毁存在的dh |
该接口在联盟站点Q用于在联盟站点中记录和l护dh
在SSOlg中,已经实现了一个默认的ILoginRequestContainer对象。ؓDefaultServer/ LoginRequestContainer.cs?
IUserStateContainer接口包括5个方法,用于在联盟站点中记录和维护在U联盟用户信?
Ҏ?/span> |
含义和作?/span> |
Add |
dd用户 |
GetList |
获取在线用户清单 |
Check |
查某个用h否已l在U?/span> |
Remove |
U除某个在线用户?/span> |
GetUserCount |
获取在线用户个数 |
该接口在联盟站点Q用于在联盟站点中记录和l护在线联盟用户信息
在SSOlg中,已经实现了一个默认的IUserStateContainer对象。ؓDefaultServer/
UserState.cs?
IClient接口包括6个属性和2个方法,用于发出dh和登?
8个属性ؓQ?
属性名U?/span> |
cd |
含义 |
SiteID |
string |
站点~号 |
PrivateKey |
string |
数据交换时加密或者签名用的公?/span> |
LoginAddress |
string |
认证中心d地址 |
LogoutAddress |
string |
认证中心d地址 |
Uid |
string |
d的用L?/span> |
TimeOut |
int |
d{复的超时时_单位s |
UidField |
string |
ddh中的用户信息的存储位|?/span> |
FromUrlField |
string |
dh中的来源|址存储位置 |
2个方法ؓ
Ҏ?/span> |
含义和作?/span> |
Login |
发出dhQƈ处理d{复 |
LogOut |
d |
该接口在联盟站点Q用于发出登录请求和dh
在SSOlg中,已经实现了一个默认的IClient对象。ؓDefaultServer/ DefaultClient.cs
联盟站点向认证中心发送的dh格式如下Q?
站点信息+dh~号+旉?I用户信?对站点信息和d清秋L{信息?br /> 除了{信息之外的全部信息均为明文传送,但因为重要的数据均经q数字签名,l果是站点信息和dh~号是不能被改的,保证了认证中心收到的dh的真实性?
认证中心发给联盟站点的登录答复格式如?
d用户信息+dh~号+旉?对用户信息和dh号和旉戳的{信息
其中d用户信息是经q非对称加密的。请求号和时间戳因ؓl过{Q故也不能篡改,q样可以保证联盟站Ҏ到的d{复的真实性和完整性。ƈ且非正常联盟站点无法解密用户信息Q也无法从中获取好处?nbsp;
幅太大Q下面还有很长的内容要说Q先发布以下Q感兴趣的朋友可以先下蝲E序试使用。以后,我会逐渐dSql ?
Oracle的实现。您也可以根据接口规范,开发符合自ql需求的SSOpȝQ今天先到这?br />
E序文gQ?a href="/Files/jillzhang/SSO.rar">/Files/jillzhang/SSO.rar
更新Q新增登录流E图Q?br />
[原创]单点登陆(SSO)lg的设计与实现?d程?/a>
新增d程?2008-02-02
上面是整体流E图Q这个SSOlg在安全上有了很充分的考虑Q可以说是非常安全,那么下面看看dh数据的格式,和ؓ何它能保证真实性和完整?br />
q样Q当数据在传输过E中Q如果站点编P用户~号Q请求号L一做M的修改,当认证中心接收到数据之后Q均无法与签名信息进行匹配。凡是认证中心能验证通过的请求均为合法的Q真实的Q完整的h信息?br />
d{复的格式如下图所C?br />
因ؓdP旉戻I用户信息均加入数字签名信息,所以这些数据在传输中不能被伪造和改Q而用户信息经q非对称性加密,也防止非真正h发送者能解析出用户信息,q样在接受和发送请求和响应的时候,实Cl对的安全?br />
当然不是没有破熾Q破l在于当h{复未到达联盟站点之前,有h截获q先于正常用L录了联盟站点Q此时我们可以将用户的ip信息作ؓ{复数据的一部分Q加入签名,以此实现很高的安全保?br />
d程?br />
一直希望有一个电子化的工兯够方ѝŞ象的整理头脑中O无边际的杂ؕxQ就像铅W和白纸能够做到的那P但是又能避免写满东西的白U怸易传播和保存的缺炏V?/p>
最初通过一?a >介绍文章Q看CFreeMindQ著名的开源free思维理工具Q优势是明显的,比如Q?
使用的时候需要先安装java的运行库Q有炚w烦,而且关键是有一些操作方式,个h感觉不太手Q导致思\频频被打断,被迫开始摸索用的ҎQ这样对于一个普通的使用者来_学习的时间成本便上升了,后来不得不尝试了商业软gQ?a >MindManagerQ这ƾY件ƈ不开源,也不能跨q_Q只支持Windowsq一家系l,但是׃很好的迎合了windows软g的操作方式,大大降低了熟Ewindows软g用户的学习成本,更和officepd软g做到了紧密整合,数据在其中流动非帔R畅?/p>
W一个o我激动的MindManager应用是Web2.0周刊的制作,我当时的需要就是每天用最单的Ҏ攉相关信息Q包含链接、笔记或评论、分cȝ信息Q在周末的时候统一整理一下,直接输出相应的html面Q可以上传到服务器上供访问,MindManager刚好可以q乎完美的实玎ͼQ?a Save as Webpages..."中找到?/p>
实际上无需什么教E,安装完MindManager之后Q“help”和"Learning Center"都是非常的使用教程Q而且后者还是直观的视频模式Q快速浏览一下,可以对MindManagerq款软g有大致的了解了?/p>
在“Learn More”中的“提C和技巧”用了MindManager的格式来展示Q很有意思,在这里可以学到“生成图片格式”、“格式编排”、“浏览导䏀、“编辑技巧”等斚w的知识?/p>
MindManager6分ؓ基础版和专业版,两个版本共有的一些新Ҏ包括:
而只在MindManager6专业版中才有的特性如下:
如果你主要用Windowspȝ工作Q而且office也始l在你的电脑中占有一席之圎ͼ最后,你也不在乎花一些美刀或者勇于想办法不花q些刀Q来得到一个真正强大、全能的思维导图工具的话Q选择MindManager pro 6吧,应该不会后悔?/p>
上面已经说明了全路径覆盖的含义(目前Cover工具无法辑ֈ的功能)Q那么全路径覆盖是不是很有必要且一定要的呢Q答案是“YES?做到全\径覆盖的试是很痛苦的一件事情,但是Q当你从全\径覆盖中扑ֈ重大问题Ӟ才会回头来看“如果我做了全副该测试,q段路径的错误逻辑׃会出现的”?/p>
拿上篇"CheckedException VS UncheckedException"中的例子Q当代码l构逐渐演化为多出入口调用C模块Ӟ“C处不能决定具体的出错信息”。但是在代码中,如果恰恰是?C处误认ؓ可以军_错误消息"Ӟ对于q个“误操作”,可以通过全\径覆盖发现这个问题。if(a==b||c==d||e==f) {throw new MyException("error msg.")}Q这L一行代码,需要面对三U问题去报出错信息,其负担太重,情况复杂Q然后有了错误代码)?/p>
如果做了全\径覆盖,可以走到Qe==fQ的判断Q此时即可发现错误消息不正确的问题?/p>
如何才能保证完成全\径覆盖呢Q?br />1Q手工debug跟踪Q保证每一步都走到Q对于最后的(e==f)Q跟t的好辛苦阿Q创造这L条gQ走到e==fQ就好篏的?br />2Q利用Ncover的功能,对于q样的复杂逻辑Q手工进行debug跟踪?br />3)拆开代码Qؓ三行Q每个step为单独的一行)Q利用NCover自动分析?哈,老师教过?Q不允许出现q于复杂的代?q个原则被发挥到极致了?/p>
你可以想象的出,一个库函数的异怿息不完整Q对于他的用h_是多么不友好的事情。假?/span>
MSDN
?/span>
File.Open()
会抛?/span>
IOException
Q你的程序就很难惛_很规矩的?/span>
IOException
做了
catch
Q然后提C用h查相应位|的文g是否存在
/
被打开{。别指望
MSDN
的那些信息能够对l端用户有多大的帮助Q太多不懂计机的h在傻呆呆的握着鼠标了。再加上
MicroSoft
的提CZ息本w就存在着“答非所问”,“莫名其妙”的事情Q用L到这些情况就更不知道怎么解决问题了。再加上自己的应用程序中会弹Z个个“蹩脚”的q行旉误的错误框,真的不是一个很如意的创作?/span>
但是Q如果用的?/span>
Checked Exception
Q这时候编译器会强q你的外部接口的异常相当的完_最L可以做到?/span>
MSDN
的异常类型齐整?/span>
1.1
Q?/span>
.NET Framework 1.1
public StreamWriter( string path );
异常cd
|
条g
|
讉K被拒l?/span>
|
|
path
为空字符?/span>
("")
?/span>
|
|
path
为空引用Q?/span>
Visual Basic
中ؓ
Nothing
Q?/span>
|
|
指定的\径无效,比如在未映射的驱动器上?/span>
|
|
指定的\径、文件名或者两者都出了系l定义的最大长度。例如,在基?/span>
Windows
的^CQ\径必d?/span>
248
个字W,文g名必d?/span>
260
个字W?/span>
|
|
path
包含不正或无效的文件名、目录名或卷标的语法?/span>
|
|
调用Ҏ有所要求的权限?/span>
|
1.2 JDK 1.4.2 :
public FileWriter(String fileName) throws IOException
Constructs a FileWriter object given a file name.
Parameters:
fileName
- String The system-dependent filename.
Throws:
IOException
- if the named file exists but is a directory rather than a regular file, does not exist but cannot be created, or cannot be opened for any other reason
2
、解?/span>
.NET ?/span> Excetpion ?/span> Unchecked 异常Q客L不要求去 Check 代码Q但?/span> JAVA 的绝大部?/span> Checked 异常Q它要求客户端的代码异常?/span>
假设一个这L场景Q方?/span> OutMethod 调用 InnerMethod Q而内部方?/span> InnerMethod 抛出的异?/span> InnerException ?/span>
对于 Java ?/span> CheckedException Q或?/span> OutMethod L?/span> InnerException Q或?/span> OutMethod 捕捉 InnerException Q然后做处理Q?/span>
再来观察一?/span> JDK ?/span> FileWriter 的异常声明,我没有详l测试其在各U可能出错情况下抛出?/span> IOException 的消息,但是其分c远q不?/span> .NET ?/span> StreamWriter 。假?/span> Java 想照?/span> .NET ?/span> StreamWriter Q对?/span> Java 的用者来_无异于恶梦。外部的代码需要捕获如此多的异常消息(不捕捉就会在 OutMethod 抛出一大堆的异常,问题l箋传播下去Q这?/span> CheckException 的一个弱点)。也许正是出于这L问题Q所以此?/span> Java 接口的异常声明比较简单?/span>
那么假设我是一个库设计者,正在用到?/span> IO 。如果我使用 .NET q行开发,对于 IOException 来说Q我是否有必要捕捉呢Q捕捉的目的是ؓ了“处理”,那么对于库设计者,昄q时候需要通知其“客L序员”出错的原因Q所以这里的库设计者的行ؓ最好就是“不处理”。如果处理,那只能是?/span> catch 、再 throw ”。那么这L处理昄是无意义的,因ؓ原始异常已经以提醒客户E序员出错的原因了。如果捕捉,那代码会特别的丑陋(直接 catch Exception 的行为是不可取的Q?/span>
CheckedException 的另外一个缺点就是“将 Exceotion 加入?/span> Interface 的规格声明“。假?/span> OutMethod 调用?/span> InnerMethod Q此?/span> InnerMethod 的设计者需要增加一个异常,那么会直接媄响到 OutMethod 。当然这里的 InnerMethod 的设计者此时已l做了“修Ҏ口声明“的行ؓ?/span>
随后待箋......
您还记得以前大多数开发h员是如何q求代码质量的吗。在那时Q有技巧地攄 main()
Ҏ被视为灵zM适当的测试方法。经历了漫长的道路以后,现在自动试已经成ؓ高质量代码开发的基本保证Q对此我很感谢。但是这q不是我所要感谢的全部。Java?开发h员现在拥有很多通过代码度量、静态分析等Ҏ来度量代码质量的工具。我们甚臛_l设法将重构分类成一pd便利的模式!
![]() |
|
所有的q些新的工具使得保代码质量比以前简单得多,不过您还需要知道如何用它们。在q个pd中,我将重点阐述有关保证代码质量的一些有时看上去有点秘的东ѝ除了带您一L悉有关代码质量保证的众多工具和技术之外,我还ؓ您说明:
在这个月Q我首先看?Java 开发h员中最行也是最Ҏ的质量保证工具包Q测试覆盖度量?/p>
q是一个晚上鏖战后的早晨,大家都站在饮水机边上。开发h员和理人员们了解到一些经q良好测试的cd以达到超q?90% 的覆盖率Q正在高兴地互换着 NFL 风格的点心。团队的集体信心I前高涨。从q处可以听到 “放d重构吧?的声韻Ig~陷已成为遥q的记忆Q响应性也已微不道。但是一个很的反对声在_
奛_们,先生们,不要被覆盖报告所愚弄?/p>
现在Q不要误解我的意思:q不是说使用试覆盖工具是愚蠢的。对单元试范例Q它是很重要的。不q更重要的是您如何理解所得到的信息。许多开发团队会在这儿犯W一个错?/p>
高覆盖率只是表示执行了很多的代码Qƈ不意味着q些代码?i>很好?/i> 执行。如果您x的是代码的质量,必ȝ地理解试覆盖工具能做什么,不能做什么。然后您才能知道如何使用q些工具去获取有用的信息。而不是像许多开发h员那P只是满于高覆盖率?/p>
![]() ![]() |
![]()
|
试覆盖工具通常可以很容易地d到确定的单元试q程中,而且l果可靠。下载一个可用的工具Q对您的 Ant ?Maven 构徏脚本作一些小的改动,您和您的同事有了在饮水上谈论的一U新报告Q?i>试覆盖报告。当 foo
?bar
q样的程序包令h惊奇地显C?i>?/i> 覆盖率时Q您可以得到不小的安慰。如果您怿臛_您的部分代码可以保证?“没?BUG?的,您会觉得很安心。但是这样做是一个错误?/p>
存在不同cd的覆盖度量,但是l大多数的工具会x行覆?/i>Q也叫做语句覆盖。此外,有些工具会报?i>分支覆盖。通过用一个测试工h行代码库q捕h个测试过E中与被 “触及?的代码对应的数据Q就可以获得试覆盖度量。然后这些数据被合成盖报告。在 Java 世界中,q个试工具通常?JUnit 以及名ؓ Cobertura、Emma ?Clover {的覆盖工具?/p>
行覆?/i>只是指出代码的哪些行被执行。如果一个方法有 10 行代码,其中?8 行在试中被执行Q那么这个方法的行覆盖率?80%。这个过E在M层次上也工作得很好:如果一个类?100 行代码,其中?45 行被触及Q那么这个类的行覆盖率就?45%。同P如果一个代码库包含 10000 个非注释性的代码行,在特定的试q行中有 3500 行被执行Q那么这D代码的行覆盖率是 35%?/p>
报告分支覆盖 的工兯囑ֺ量决{点Q比如包含逻辑 AND
?OR
的条件块Q的覆盖率。与行覆盖一P如果在特定方法中有两个分支,q且两个分支在测试中都被覆盖Q那么您可以说这个方法有 100% 的分支覆盖率?/p>
问题是,q些度量有什么用Q很明显Q很Ҏ获得所有这些信息,不过您需要知道如何用它们。一些例子可以阐明我的观炏V?/p>
![]() ![]() |
![]()
|
我在清单 1 中创Z一个简单的cM具体表述cdơ的概念。一个给定的cd以有一q串的父c,例如 Vector
Q它的父cL AbstractList
Q?code>AbstractList 的父cd?AbstractCollection
Q?code>AbstractCollection 的父cd?Object
Q?/p>
清单 1. 表现cdơ的c?/b>
|
正如您看到的Q清?1 中的 Hierarchy
cd有一?baseClass
实例以及它的父类的集合。清?2 中的 HierarchyBuilder
通过两个复制 buildHierarchy
的重载的 static
Ҏ创徏?Hierarchy
cR?/p>
清单 2. cdơ生成器
|
![]() ![]() |
![]()
|
有关试覆盖的文章怎么能缺测试案例呢Q在清单 3 中,我定义了一个简单的有三个测试案例的 JUnit 试c,它将试图执行 Hierarchy
cd HierarchyBuilder
c:
|
因ؓ我是一个狂热的试人员Q我自然希望q行一些覆盖测试。对?Java 开发h员可用的代码覆盖工具中,我比较喜Ƣ用 CoberturaQ因为它的报告很友好。而且QCorbertura 是开放源码项目,它派生出?JCoverage 目的前w?/p>
![]() ![]() |
![]()
|
q行 Cobertura q样的工具和q行您的 JUnit 试一L单,只是有一个用专门逻辑在测试时查代码以报告覆盖率的中间步骤Q这都是通过工具?Ant d?Maven 的目标完成的Q?/p>
正如您在?1 中看到的Q?code>HierarchyBuilder 的覆盖报告说明部分代?i>没有 被执行。事实上QCobertura 认ؓ HierarchyBuilder
的行覆盖率ؓ 59%Q分支覆盖率?75%?/p>
?1. Cobertura 的报?/b>
q样看来Q我的第一ơ覆盖测试是p|的。首先,带有 String
参数?buildHierarchy()
ҎҎ没有被测试。其ơ,另一?buildHierarchy()
Ҏ中的两个条g都没有被执行。有的是,所要关注的正是W二个没有被执行?if
块?/p>
因ؓ我所需要做的只是增加一些测试案例,所以我q不担心q一炏V一旦我到达了所x的区域,我就可以很好地完成工作。注意我q儿的逻辑Q我使用试报告来了解什?i>没有 被测试。现在我已经可以选择使用q些数据来增强测试或者l工作。在本例中,我准备增强我的测试,因ؓ我还有一些重要的区域未覆盖?/p>
清单 4 是一个更新过?JUnit 试案例Q增加了一些附加测试案例,以试囑֮全执?HierarchyBuilder
Q?
|
当我使用新的试案例再次执行试覆盖q程Ӟ我得C如图 2 所C的更加完整的报告。现在,我覆盖了未测试的 buildHierarchy()
ҎQ也处理了另一?buildHierarchy()
Ҏ中的两个 if
块。然而,因ؓ HierarchyBuilder
的构造器?private
cd的,所以我不能通过我的试cL试它Q我也不兛_Q。因此,我的行覆盖率仍然只有 88%?/p>
?2. 谁说没有W二ơ机?/b>
正如您看到的Q用一个代码覆盖工?i>可以 揭露重要的没有相应测试案例的代码。重要的事情是,在阅L告(特别 是覆盖率高的Q时需要小心,它们也许隐含危险的信息。让我们看看两个例子Q看看在高覆盖率后面隐藏着什么?/p>
![]() ![]() |
![]()
|
正如您已l知道的Q代码中的许多变量可能有多种状态;此外Q条件的存在使得执行有多条\径。在留意q些问题之后Q我在清单 5 中定义一个极其简单只有一个方法的c:
|
您是否发C清单 5 中有一个隐藏的~陷呢?如果没有Q不要担心,我会在清?6 中写一个测试案例来执行 pathExample()
Ҏq确保它正确地工作:
|
我的试案例正确q行Q我的神奇的代码覆盖报告Q如下面?3 所C)使我看上d个超U明星,试覆盖率达C 100%Q?/p>
?3. 覆盖率明?
我想现在应该到饮水机边上去说了,但是{等Q我不是怀疑代码中有什么缺陷呢Q认真检查清?5 会发玎ͼ如果 condition
?false
Q那么第 13 行确实会抛出 NullPointerException
?i>YeeshQ这儿发生了什么?
q表明行覆盖的确不能很好地指C测试的有效性?/p>
![]() ![]() |
![]()
|
在清?7 中,我定义了另一个包?indirect 的简单例子,它仍然有不能容忍的缺陗请注意 branchIt()
Ҏ?if
条g的后半部分。(HiddenObject
cd在清?8 中定义。)
|
呀Q清?8 中的 HiddenObject
?i>有害?/i>。与清单 7 中一P调用 doWork()
Ҏ会导?RuntimeException
Q?/p>
清单 8. 上半部分Q?
|
但是我的可以通过一个良好的试捕获q个异常Q在清单 9 中,我编写了另一个好的测试,以图挽回我的明星光环Q?/p>
清单 9. 使用 JUnit 规避风险
|
您对q个试案例有什么想法?您也怼写出更多的测试案例,但是误想一下清?7 中不定的条件有不止一个的~短操作会如何。设惛_果前半部分中的逻辑比简单的 int
比较更复杂,那么?/i> 需要写多少试案例才能满意Q?/p>
现在Q对清单 7?? 的测试覆盖率的分析结果不再会使您感到惊讶。在?4 的报告中昄我达C 75% 的行覆盖率和 100% 的分支覆盖率。最重要的是Q我执行了第 10 行!
从第一印象看,q让我骄傌Ӏ但是这个报告有什么误导吗Q只是粗略地看一看报告中的数字,会导致您怿代码是经q?i>良好试?/i>。基于这一点,您也怼认ؓ出现~陷的风险很低。这个报告ƈ不能帮助您确?or
~短操作的后半部分是一个定时炸弹!
![]() ![]() |
![]()
|
我不止一ơ地_您可以(而且应该Q用测试覆盖工具作为您的测试过E的一部分。但?i>不要被覆盖报告所愚弄。关于覆盖报告您需要了解的主要事情是,覆盖报告最好用来检查哪些代?i>没有l过 充分的测试。当您检查覆盖报告时Q找低的|q了解ؓ什么特定的代码没有l过充分的测试。知道这些以后,开发h员、管理h员以?QA 专业人员可以在真正需要的地方使用试覆盖工具。通常有下列三U情况:
现在我可以断定对试覆盖报告的一些用方法会您引入歧途,下面q些最佛_践可以得测试覆盖报告可以真正ؓ您所用?/p>
对一个开发团队而言Q针对代码编写测试案例自然可以增加集体的信心。与没有相应试案例的代码相比,l过试的代码更Ҏ重构、维护和增强。测试案例因为暗CZ代码在测试工作中?i>如何 工作的,所以还可以充当内行的文档。此外,如果被测试的代码发生改变Q测试案例通常也会作相应的改变Q这与诸如注释和 Javadoc q样的静态代码文档不同?/p>
在另一斚wQ没有经q相应测试的代码更难于理解和安全?/i> 修改。因此,知道代码有没有被试Qƈ看看实际的测试覆盖数|可以让开发h员和理人员更准地预知修改已有代码所需的时间?/p>
再次回到饮水上,可以更好地阐明我的观炏V?/p>
市场部的 LindaQ“我们想让系l在用户完成一W交易时?x 工作。这需要多长时间。我们的用户需要尽快实现这一功能。?
理人员 JeffQ“让我看看,q个代码?Joe 在几个月前编写的Q需要对业务层和 UI 做一些变动。Mary 也许可以在两天内完成q项工作。?
LindaQ“JoeQ他是谁Q?
JeffQ“哦QJoeQ因Z不知道自己在q什么,所以被我解雇了。?
情况g有点不妙Q不是吗Q尽如此,Jeff q是Q务分配给?MaryQMary 也认够在两天内完成工?—?切地说Q在看到代码之前Ҏq么认ؓ的?/p>
MaryQ“Joe 写这些代码时是不?i>睡着?/i>Q这是我所见过的最差的代码。我甚至不能认q是 Java 代码。除非推倒重来,要不我根本没法修攏V?
情况?“饮水机?团队不妙Q不是吗Q但是我们假设,如果在这个不q的事g的当初,Jeff ?Mary 拥有一份测试报告,那么情况会如何呢Q当 Linda 要求实现新功能时QJeff 做的W一件事是查以前生成的覆盖报告。注意到需要改动的软g包几乎没有被覆盖Q然后他׃?Mary 商量?/p>
JeffQ“Joe ~写的这个代码很差,l大多数没经q测试。您认ؓ要支?Linda 所说的功能需要多长时_?
MaryQ“这个代码很混ؕ。我甚至都不想看到它。ؓ什么不?Mark 来做呢??
JeffQ“因?Mark 不编写测试,刚被我解雇了。我需要您试q个代码q作一些改动。告诉我您需要多长时间。?
MaryQ“我臛_需要两天编写测试,然后我会重构q个代码Q增加新的功能。我xd需要四天吧。?
正如他们所说的Q知识的力量是强大的。开发h员可以在试图修改代码之前 使用覆盖报告来检查代码质量。同P理人员可以使用覆盖数据更好C计开发h员实际所需的时间?/p>
开发h员的试可以降低代码中存在缺L风险Q因此现在很多开发团队在新开发和更改代码的同旉要编写单元测试。然而正如前面所提到?Mark 一Pq不L在编码的同时q行单元试Q因而会D低质量代码的出现?/p>
监控覆盖报告可以帮助开发团队迅速找Z断增长的没有 相应试的代码。例如,在一周开始时q行覆盖报告Q显C项目中一个关键的软g包的覆盖率是 70%。如果几天后Q覆盖率下降C 60%Q那么您可以推断Q?/p>
能够监控事情的发展,无疑是g好事。定期地查阅报告使得讑֮目标Q例如获得覆盖率、维护代码行的测试案例的比例{)q监控事情的发展变得更ؓҎ。如果您发现试没有如期~写Q您可以提前采取一些行动,例如对开发h员进行培训、指导或帮助。与其让用户 “在使用中?发现E序~陷Q这些缺h应该在几个月前通过单的试暴露出来Q,或者等到管理h员发现没有编写单元测试时再感到惊Ӟ和愤怒)Q还不如采取一些预防性的措施?/p>
使用覆盖报告来确保正的试是一伟大的实践。关键是要训l有素地完成q项工作。例如,使每晚生成ƈ查阅覆盖报告成ؓq箋累计 q程的一部分?/p>
假设覆盖报告在指?i>没有l过 _试的代码部分方面非常有效,那么质量保证人员可以使用q些数据来评定与功能试有关的关注区域。让我们回到 “饮水机?团队来看?QA 的负责h Drew 是如何评?Joe 的代码的Q?/p>
Drew ?Jeff _“我们ؓ下一个版本编写了试案例Q我们注意到很多代码没有被覆盖。那好像是与股票交易有关的代码。?
JeffQ“哦Q我们在q个领域有好些问题。如果我是一个赌徒的话,我会对这个功能区域给予特别的x。Mary 正在对这个应用程序做一些其他的修改 —?她在~写单元试斚w做得很好Q但是这个代码也太差了点。?
DrewQ“是的,我正在确定工作的资源和别,看上L没必要那么担心了Q我估计我们的团队会对股交易模块引赯够的x。?
知识再次昄了其强大的力量。与其他软g生命周期中的风险承担者(例如 QAQ配合,您可以利用覆盖报告所提供的信息来降低风险。在上面的场景中Q也?Jeff 可以?Drew 的团队提供一个早期的不包?Mary 的所有修改的版本。不q无论如何,Drew 的团队都应该x应用E序的股交易方面,与其他具有相应单元测试的代码相比Q这个地方似乎存在更大的~陷风险?/p>
![]() ![]() |
![]()
|
对单元测试范例而言Q测试覆盖度量工h一个有点奇怪的l成部分。对于一个已存在的有益的q程Q覆盖度量可以增加其深度和精度。然而,您应该仔l地阅读代码覆盖报告。单独的高覆盖率q不能确保代码的质量。对于减缺P代码的高覆盖q不是必要条Ӟ管高覆盖的代码的确更少 有缺陗?/p>
试覆盖度量的窍门是使用覆盖报告扑և未经 试的代码,分别在微观和宏观两个U别。通过从顶层开始分析您的代码库Q以及分析单个类的覆盖,可以促进深入的覆盖测试。一旦您能够l合q些原则Q您和您的组l就可以在真正需要的地方使用覆盖度量工具Q例如估计一个项目所需的时_持箋监控代码质量以及促进?QA 的协作?/p>
Who is Matt Raible?
. Developing websites since 1994 (before Netscape 1.0)
- Developing in J2EE webapps since 1999
. Committer on several open source projects:Roller
Weblogger, XDoclet, Struts Menu, Display Tag, AppFuse
. J2EE 5.0 Expert Group Member
. Author: Spring Live (SourceBeat) and contributor to
Pro JSP (Apress)
!ww.raibledesigns.co" !ww.springlive.co"
Framework Experience
. Struts: used since June 2001 - same time 1.0 was
released.
. Spring MVC: used since January 2004 - before 1.0
was released.
. WebWork: used since July 2004.
. Tapestry: used since July 2004.
. JSF: used since July 2004 - both Sun’s RI and
MyFaces.
!ww.raibledesigns.co"
Meet the Candidates
!ww.raibledesigns.co"
Struts
. Pros:
. The “Standard?- lots of Struts jobs
. Lots of information and examples
. HTML tag library is one of the best
. Cons:
. ActionForms - they’re a pain
. Can’t unit test - StrutsTestCase only does integration
. Mailing list volume is overwhelming
!ww.raibledesigns.co"
Spring MVC
!ww.raibledesigns.co"
. Pros:
. Lifecyle for overriding binding, validation, etc.
. Integrates with many view options seamlessly: JSP/JSTL,
Tiles, Velocity, FreeMarker, Excel, XSL, PDF
. Inversion of Control makes it easy to test
. Cons:
. Not many using it
. Requires writing lots of code in JSPs
. Almost too flexible - no common parent Controller
WebWork
!ww.raibledesigns.co"
. Pros:
. Simple architecture - easy to extend
. Tag Library is easy to customize - backed by Velocity
. Interceptors are pretty slick
. Cons:
. Documentation only recently written, few examples
. Client-side validation immature
Tapestry
!ww.raibledesigns.co"
. Pros:
. Very productive once you learn it
. Templates are HTML - great for designers
. Healthy and smart user community
. Cons:
. Documentation very conceptual, rather than pragmatic
. Steep learning curve - very few examples
. Impossible to test - page classes are abstract
JSF
!ww.raibledesigns.co"
. Pros:
. J2EE Standard - lots of demand and jobs
. Fast and easy to develop with
. Rich Navigation framework
. Cons:
. Tag soup for JSPs
. Immature technology - doesn’t come with everything
. No single source for implementation
Controllers and Views
. Struts: UserAction extends DispatchAction
. Spring MVC: UserFormController extends
SimpleFormController
. WebWork: UserAction extends ActionSupport
. Tapestry: UserForm extends BasePage
. JSF: UserForm
!ww.raibledesigns.co"
List Screens
. How easy is it to integrate a sortable/
pageable list of data?
. Struts, Spring MVC and WebWork can all
use Tag Libraries like the Display Tag
. Tapestry has a contrib:Table component
. JSF has a dataTable with no sorting - have
to write your own logic if you want it
!ww.raibledesigns.co"
Bookmarking and URLs
. Using container-managed authentication (or other filterbased
security systems) allow users to bookmark pages.
They can click the bookmark, login and go directly to the
page.
. WebWork has namespaces - makes it easy
. Struts and Spring allow full URL control
. Tapestry has ugly URLs - difficult to segment the app for
different roles
. JSF does a POST for everything
!ww.raibledesigns.co"
Validation
. Validation should be easy to configure, be robust on the
client side and either provide good out of the box messages
or allow you to easily customize them.
. Struts and Spring MVC use Commons Validator - a
mature solution
. WebWork uses OGNL for powerful expressions -
client-side support very new
. Tapestry has very robust validation - good messages
without need to customize
. JSF - ugly default messages, but easiest to configure
!ww.raibledesigns.co"
Testability
. Struts - can use StrutsTestCase
. Spring and WebWork allow easy testing with
mocks (i.e. EasyMock, jMock, Spring Mocks)
. Tapestry is impossible to test because page classes
are abstract
. JSF page classes can be easily tested and actually
look a lot like WebWork actions
!ww.raibledesigns.co"
Success Messages
. The duplicate-post problem, what is it?
. Easiest way to solve: redirect after POST
. Struts is the only framework that allows success
messages to live through a redirect
. Spring and WebWork require custom solutions
. Tapestry requires you to throw an Exception to redirect
. JSF requires a custom solution, i18n messages difficult to
get in page beans
!ww.raibledesigns.co"
Spring Integration
. All frameworks have integration with Spring
. Struts: ContextLoaderPlugin and Base classes
. WebWork: SpringObjectFactory
. Tapestry: override base engine, grab from servlet
context, put into global map
. JSF: DelegateVariableResolver or JSF-Spring Library
!ww.raibledesigns.co"
Internationalization
. JSTL’s <fmt:message> tag makes it easy
. No standard for getting i18n messages in
controller classes
. Struts, Spring and JSF encourage one
ResourceBundle per locale
. WebWork and Tapestry advocate separate
files for each page/action
!ww.raibledesigns.co"
Page Decoration
. Used Tiles since it first came out in 2001
. SiteMesh is much easier to setup and use
. Tiles can be used in Struts, Spring and JSF
. Requires configuration for each page
. SiteMesh can be used with all frameworks
. Requires very little maintenance after
setup
!ww.raibledesigns.co"
Tools
. Struts has a lot of IDE support and even has
frameworks built on top of it (i.e. Beehive’s
PageFlow)
. Spring has Spring IDE - only does XML validation,
not a UI/web tool
. WebWork has none
. Tapestry has Spindle - great for coders
. JSF has many, all cost money and hook into
proprietary app servers
!ww.raibledesigns.co"
Business/Marketing
. Struts is still in high-demand and widely-used
. Spring is getting more press, but mostly due to the
framework’s other features
. WebWork is gaining ground, but pretty scarce on
job boards
. Tapestry is even more scarce - needs more
marketing
. JSF is quickly becoming popular
!ww.raibledesigns.co"
Dice Job Count
October 15, 2004
0
375
750
1,125
1,500
Struts
Spring Framework
WebWork
Tapestry
JSF
!ww.raibledesigns.co"
My Opinion
. Struts is fast to develop with because most problems have
been solved. HTML tag library the best of the bunch.
. Spring is nice, but lack of form tags drops it down a notch
or two. JSP 2.0 tag files exist in issue tracker.
. I like WebWork a lot, but lack of of good client-side
validation support is a killer.
. Tapestry - I haven’t finished the learning curve.
. JSF - needs to listen to developers to see what they want
instead of tools vendors.
!ww.raibledesigns.co"
Which would I choose?
. Quick and dirty project?
. Struts because I know it best
. Massive enterprise project?
. Tapestry for its reusable components
. If I got a job as an open source developer?
. WebWork because using it requires you
to dig into the frameworks
!ww.raibledesigns.co"
Resources
. Download sample apps for this presentation
. http://equinox.dev.java.net/framework-comparison
. Struts - http://struts.apache.org
. StrutsTestCase: http://strutstestcase.sf.net
. Spring MVC - http://www.springframework.org
. Spring IDE: http://www.springframework.org/spring-ide/eclipse
. WebWork - http://opensymphony.org/webwork
. Eclipse Plugin: http://sf.net/projects/eclipsework
. IDEA Plugin: http://wiki.opensymphony.com/display/WW/IDEA+Plugin
!ww.raibledesigns.co"
Resources, cont.
. Tapestry - http://jakarta.apache.org/tapestry
. Spindle: http://spindle.sourceforge.net
. JSF - http://java.sun.com/j2ee/javaserverfaces and http://
myfaces.org
. Java Studio Creator: http://sun.com/software/products/jscreator
. MyEclipse: http://myeclipseide.com
. IDEA: http://www.jetbrains.com/idea
. SiteMesh: http://opensymphony.com/sitemesh
!ww.raibledesigns.co"
Resources, cont.
. Testing Frameworks
. JUnit: http://junit.org
. EasyMock: http://easymock.org
. jMock: http://jmock.org
. jWebUnit: http://jwebunit.sourceforge.net
. Canoo WebTest: http://webtest.canoo.com
. XDoclet - http://xdoclet.sourceforge.net
. AppFuse - http://appfuse.dev.java.net
!ww.raibledesigns.co"
Books
. Struts in Action, Ted Husted and Team
. Struts Live, Rick Hightower and Jonathan Lehr
. Spring Live, Matt Raible
. Spring in Action, Craig Walls and Ryan Breidenbach
. Professional Java Development with Spring, Rod
Johnson, Juergen Hoeller and Team
Books, cont.
. WebWork in Action, Patrick Lightbody and Team
. Tapestry in Action, Howard Lewis Ship
. Core JSF, David Geary and Cay Horstmann
. JSF in Action, Kito Mann
The End
...or is it just the beginning...
!ww.raibledesigns.co"
sitemesh是opensymphony团队开发的j2ee应用框架之一Q旨在提高页面的可维护性和复用性。opensymphony的另一个广Zh知的框架为webwork是用作web层的表示框架。他们都是开源的Q可以在www.sf.net下找到?/B>
应用于以下大目的例子:http://opensource.thoughtworks.com/projects/sitemesh.html
介: | ||||||||||||||||||||||||||||||||||
sitemesh应用Decorator模式Q用filter截取request和response,把页面组件head,content,bannerl合Z个完整的视图。通常我们都是用include标签在每个jsp面中来不断的包含各Uheader, stylesheet, scripts and footerQ现在,在sitemesh的帮助下Q我们可以开心的删掉他们了。如下图Q你惌杄辑ֈ复合视图模式Q那末看完本文吧?/FONT>
| ||||||||||||||||||||||||||||||||||
hello sitemeshQ?/FONT> | ||||||||||||||||||||||||||||||||||
最后访问index.jspQ将生成如下面Q?/FONT>
而且Q所有的面也会如同index.jsp一P被sitemesh的filter使用装饰模式修改成如上图般模P却不用再使用include标签?BR> 持久化框?Qhibernate/jdo 可糟p的是前端的面逻辑很难被复用,当你在每一个页面中用数之不的include来复用公qheader, stylesheet, scriptsQfooterӞ一个问题出C-重复的代码,每个面必须用copy来复用页面结构,而当你需要创意性的改变面l构ӞNq上了你?/FONT> sitemesh通过filter截取request和responseQƈl原始的面加入一定的装饰(可能为header,footer...)Q然后把l果q回l客LQƈ且被装饰的原始页面ƈ不知道sitemesh的装饎ͼq也pCp的目的?/FONT> 据说卛_新出台的Portlet规范会帮助我们标准的实现比这些更多更cool的想法,但可怜的我还不懂它到底是一个什末东东,有兴的人可以研I?BR>jetspeedQ或JSR (Java Specification Request) 168,但我想sitemesh如此单,我们不妨先用着?/FONT> Page Parsers Q负责读取stream的数据到一个Page对象中以被SiteMesh解析和操作?不太常用Q默认即? Decorator Mappers : 不同的装饰器U类Q我发现2U比较有用都列在下面。一U通用的mapper,可以指定装饰器的配置文g名,另一U可打印的装饰器Q可以允怽当用http://localhost/aaa/a.html?printable=true方式讉K时给出原始页面以供打?免得把header,footer{的花哨的图片也搭上) 范例Q?/B> decorators.xml Q定义构成复合视囄所有页面构件的描述(主要l构面Qheader,footer...)Q如下例Q?/FONT> 让我们来先看一看最单的用法Q其实最常用也最单的用法是我们的hello例子Q面对如此众多的技术,我想只要辑ֈ功能点到为止卛_Q没必要ȝI太?除非您有更深的需??/FONT> 我们在装饰器面只用?个标{: <decorator:title default="装饰器页?.." /> Q?把请求的原始面的title内容插入?lt;title></title>中间?/FONT> <decorator:body /> Q?把请求的原始面的body内的全部内容插入到相应位|?/FONT> 然后我们在decorator.xml中加入以下描q即可: <decorator name="main" page="main.jsp"> q样Q请求的所有页面都会被重新处理Qƈ按照main.jsp的格式重新展现在你面前?/FONT> 插入原始面(被包装页?的head标签中的内容(不包括head标签本n)?/FONT> 插入原始面(被包装页?的body标签中的内容?/FONT> <decorator:title [ default="..." ] /> 插入原始面(被包装页??A name=decorator:title>title标签中的内容Q还可以d一个缺省倹{?/FONT> 例: /_decorator/main.jsp?Q装饰器面Q? <title><decorator:title default="却省title-hello" /> - 附加标题</title> /aaa.jsp?(原始面)Q?lt;title>aaa面</title> 讉K/aaa.jsp的结果:<title>aaa面 - 附加标题</title> <decorator:getProperty property="..." [ default="..." ] [ writeEntireProperty="..." ]/> 在标{֤插入原始面(被包装页?的原有的标签的属?/A>中的内容Q还可以d一个缺省倹{?/FONT> sitemesh文档中的例子很好理解Q?/FONT> 注意Q?/STRONG> <decorator:usePage id="..." /> 例:可用<decorator:usePage id="page" /> Q?/STRONG><%= <page:applyDecorator name="..." [ page="..." title="..." ] > 应用包装器到指定的页面上Q一般用于被包装面中主动应用包装器。这个标{有点不好理解,我们来看一个例子: 包装器页?/_decorators/panel.jspQ?lt;p><decorator:title /></p> ... <p><decorator:body /></p> 最后会是什末结果呢Q除?page.jsp会被默认的包装页面包装上header,footer外,page.jsp面中还内嵌了date.jsp面Qƈ且此date.jsp面q会被panel.jsp包装Z个title加body的有2D늚面Q第1D|date.jsp的titleQ第2D|date.jsp的body内容?/FONT> 另外Q?A name=page:applyDecorator>page:applyDecorator中包含的page:param标签所声明的属性D可以在包装页面中?/FONT>decorator:getProperty标签讉K到?BR> 前面的文章已l以应用sitemesh来改善您的应用,但我发现q有一些其他的东东可能也会对大家有所帮助
让我们来看一看怎样实现他: 1.首先在WEB-INFO/sitemesh.xml中设|: 2.在WEB-INFO/decorators.xml中定义相应的printable装饰?BR> <decorator name="printable" page="printable.jsp"/> 3.最后编写printable装饰?decorators/printable.jsp q样可以让一个原始页面通过?printable=true开x切换不同的装饰器面?/FONT> 1.配置好环境,
2.在WEB-INFO/decroators.xml中描qC徏立的包装器?/FONT>
3.开发在decroators.xml中描q的包装器,最好存攑֜/_decorators目录?/FONT> 4.ok Q可以看看辛勤的成果?:) 资源Q?/B> 关于作者: 陈鹏Q西安东软公司。作Z名狂热的E序员希望每一天都能成长进步,q希望与大家分n快乐和知识?BR>L以下方式和他联系Qemail chen56@msn.com |
![]() | ||||||||||
| ||||||||||
![]() |
In the past, I used to build my web applications the old-fashioned way: handcrafting assembly, carefully building my raw byte handlers to work with Unicode, counting instructions, and using make files to target different CPUs.
OK, maybe not.
Although I've never actually felt the need to build my web application with assembly (CISC or RISC), I sometimes think my fellow developers are on a quest to make their development processes as painful as possible. In particular, I've seen many developers agonize over the best way to handle basic web application building blocks: things like headers, footers, navigation bars, support for printable pages, light-weight pages for handheld devices, and more. In the end, things like includes and brute-force copy-and-paste win out surprisingly often.
In my experience, I've been able to easily solve these problems cleanly, easily, and elegantly using the open source servlet filter SiteMesh, which is hosted on java.net. Instead of requiring a new templating language, XSLT, or "porting" your pages to a new system, using SiteMesh often allows you to dramatically simplify your pages while still using ordinary HTML, JSP, servlets (including Struts), and other familiar technologies.
SiteMesh implements a page filter, taking advantage of one of the lesser-known features of the servlet specification. Let's imagine you have a simple JSP that returns the current date and time. Ordinarily, the request for the page comes in to the application server, the page is rendered, and then the results are returned to the web browser. SiteMesh, as a page filter, takes the page after it is rendered and performs additional processing before returning the document to the web browser. This change is most simply described as the additional step shown between Figure 1 and Figure 2.
Figure 1. Normal Page Rendering
Figure 2. SiteMesh Page Rendering
Let's look at a simple example of this. Consider the following simple JSP:
<html>
<head>
<title>Simple Document</title>
</head>
<body>
Hello World! <br />
<%= 1+1 %>
</body>
</html>
You'll notice that the page has a title and a body (like any ordinary HTML page). You'll notice a tiny bit of JSP code -- this will be rendered just as you would expect. Indeed, you can use any and all features that you would expect, and you link between the various JSP and other resources just as you might expect.
Now, let's look at a simple SiteMesh "decorator" page. Listing 2 shows a JSP page, called by SiteMesh.
<%@ taglib uri="sitemesh-decorator"
prefix="decorator" %>
<html>
<head>
<title>
My Site - <decorator:title default="Welcome!" />
</title>
<decorator:head />
</head>
<body>
<h1><decorator:title default="Welcome!" /></h1>
<p><decorator:body /></p>
<p><small>
(<a
href="?printable=true">printable version</a>)
</small></p>
</body>
</html>
Looking at the decorator, we can see a few interesting things. First, a SiteMesh taglib is introduced in the first line. This taglib includes everything required to work with the original page. You can see that we use two of the SiteMesh declared tags, <decorator:title>
and <decorator:body>
. Not surprisingly, the <decorator:title>
returns the contents of the <title>
tag in the original page, and <decorator:body>
the content. We're making a few fairly radical changes to the page, including repeating the title both in the HEAD
element as well as the BODY
. We're also adding a link to a printable version of the page.
For comparison, Figure 3 shows the rendered original page and Figure 4 the rendered decorated page. Notice the appearance of the title text both in the browser window title bar and in the HTML of the page in the decorated page. You'll also notice that we added a printable page link, as well -- we'll come back to this later.
Figure 3. Original Undecorated Page
Figure 4. Decorated Page
Obviously, this is a much cleaner system for applying traditional header and footer content than using include directives (such as <jsp:include page="foo.jsp" flush="true" />
). It's much more flexible and natural, and encourages JSP pages with no navigation or other presentation data. I have found that a combination of decorators and CSS overrides of standard HTML tags allows me to virtually eliminate formatting information from my JSP pages.
Note that the screenshots, etc. are based on Windows XP Professional, Tomcat 5.0.19, and Java 2 SDK 1.4.2_03. I'm going to assume that you have installed and are able to get Tomcat working. You might have to tweak things slightly, but I've gotten all of this to work fine on Tomcat 4.1 and WebLogic as well, and SiteMesh lists many other supported web application servers.
SiteMesh 2.0.1, the version described in this article, can be downloaded here. There are four files available for download from SiteMesh's java.net project repository. The sitemesh-2.0.1.jar file is just the core JAR file, sitemesh-2.0.1-sources.zip is self-describing, and sitemesh-example.war provides a complex example showing some of SiteMesh's more advanced features.
To keep things simple, we'll start with the sitemesh-blank.war file, building and modifying as we go along. Instead of just dropping the WAR file into our Tomcat webapps directory, we'll crack open the WAR open and drop it in uncompressed, as shown in Figure 5.
Figure 5. SiteMesh Blank WAR Contents
There are a number of files here, so let's take a moment to describe what they do.
First, the WEB-INF/web.xml file, shown in Listing 3, contains directives to install the SiteMesh filter and the taglib libraries. If you're adding SiteMesh to an existing web application, you'll need to add these directives to your WEB-INF/web.xml file.
<?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>
<!-- Start of SiteMesh stuff -->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<taglib>
<taglib-uri>sitemesh-page</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-page.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>sitemesh-decorator</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-decorator.tld</taglib-location>
</taglib>
<!-- End of SiteMesh stuff -->
</web-app>
Note: you'll notice that I've flagged the url-pattern
line -- if you are using Tomcat 5 (instead of Tomcat 4) you'll need to change the pattern from the default *
to something like *.jsp
. The *
pattern is not allowed under the latest servlet specification.
The WEB-INF/decorators.xml file is used to bind a decorator name to a specific JSP decorator file. So, for example, we might bind a decorator named handheld
to the JSP page decorator minimal.jsp
.
<decorators defaultdir="/decorators">
<decorator name="main" page="main.jsp">
<pattern>*</pattern>
</decorator>
<decorator name="panel" page="panel.jsp"/>
<decorator name="printable" page="printable.jsp"/>
</decorators>
As we can see in this code listing, we define three decorators, and then bind them to three similarly named JSP pages. We also see that the default decorator, main.jsp
, will be applied for files by default.
By default, SiteMesh will use the following logic to determine what decorator to apply:
This logic is expressed in described in the sitemesh-2.0.1.jar file at \com\opensymphony\module\sitemesh\factor\sitemesh-default.xml. You can override this behavior with a wide variety of built-in mappers for things like language, client operating system, web browser/user agent, etc. by creating a WEB-INF\sitemesh.xml file. You'll find an example of this included in the sitemesh-example.war file. |
printable=true
parameter> (If so, use the printable decorator.)
Conceptually, the first rule that evaluates to true determines the decorator that is used. In the example above, when the printable=true
parameter is present, the printable.jsp
decorator (rule #3) is used instead of the main.jsp
(matched in rule #5). In SiteMesh, these rules are described as mappers.
The three files in the decorators directory are the various decorator JSP files, as described by decorators.xml. We saw an example of a simple decorator above, and we'll look at a more sophisticated example later in this article.
This is the main SiteMesh binary, typically installed in the WEB-INF/lib directory. You can find the Javadoc for this library at www.opensymphony.com/sitemesh/api.
SiteMesh uses two tag libraries, but most users will only need the decorator tags (sitemesh-decorator.tld). You can find documentation on these at www.opensymphony.com/sitemesh/tags.html. We've already touched on the main tags, used to retrieve the head, title, and body. We'll look at the remaining tag, getProperty
, in the next section.
One of the more powerful abilities of SiteMesh is to use the ordinary HTML meta
tag (for example, <meta name="foo" content="bar">
) to pass information from the base page to the decorator. For example, let's say that we would like to define the author of an HTML page using a meta
tag, as shown below.
<html>
<meta name="author" content="test@example.com">
<head>
<title>Simple Document</title>
</head>
<body>
Hello World! <br />
<%= 1+1 %>
</body>
</html>
We can make a decorator "smart" enough to know to look for this meta
tag, and if present, generate the appropriate HTML:
<%@ taglib uri="sitemesh-decorator" prefix="decorator" %>
<decorator:usePage id="myPage" />
<html>
<head>
<title>My Site -
<decorator:title default="Welcome!" />
</title>
<decorator:head />
</head>
<body>
<h1><decorator:title default="Welcome!" /></h1>
<h3>
<a href="mailto:<decorator:getProperty property="meta.author"
default="staff@example.com" />">
<decorator:getProperty property="meta.author"
default="staff@example.com" />
</a></h3><hr />
<decorator:body />
<p><small>
(<a href="?printable=true">printable version</a>)
</small>
</p>
</body>
</html>
You'll notice that we use a default attribute in the getProperty
tag -- if no author is specified, we'll just assume that it was written by the staff. If you decide to use this model for storing page metadata, you'll want to work with your content developers and other team members to determine what tags you want to use and how you'll be using them. At the simple end, you may want to use meta
tags to describe things like the author and page timestamp. At the complex end, you may do things like standardize on an XML file to manage your site navigation and use a meta
tag to pass the page's node to the decorator.
The page that results from applying this decorator to the JSP page above is shown in Figure 6.
Figure 6. meta
Tag Displayed
These page attributes are powerful, and you can retrieve many different properties, not just the meta
tags (here's a list of generated page properties). After using SiteMesh for a while, you'll start thinking about HTML and JSP as a mechanism for generating simple markup -- closer to the original intent of HTML -- without having to make a full switch to an XML/XSL or other template engine.
As we've seen, SiteMesh provides for a powerful, easy-to-use, non-intrusive mechanism for applying page templates. It's easy to envision a wide range of possible uses. For example, you might define a decorator that emits extra debugging information about the page, as determined by the browser (this is especially powerful when combined with a web browser that lets you set an arbitrary user-agent). You might define a decorator with a stripped-down XML output, allowing for easier automated testing. You can even use the decorator to grab content from other pages, for example, to simple portal-like capability.
Once you've gotten comfortable with sitemesh-blank.war, I'd suggest looking at sitemesh-example.war for more features and ideas.
Regardless of how you use SiteMesh, I've found that it lets me centralize a tremendous amount of code, moving it out of my presentation layer and into my decorators, without having to learn a new programming language or templating system.
Oh, and as a final note for those of you still interested in building web pages in assembly, check out home.worldonline.dk/viksoe/asmil.htm.
Good luck and happy coding!
Will Iverson served as Developer Relations Manager for the VisualCafé group at Symantec, as the Java & Runtimes Product Manager at Apple Computer and has led Cascade Technology Group, a private consulting firm, since 1999.