zkruby主要用于哪些领域方面

神黄中医智库
导读:刘完素是河间派的开山祖师,他的火热论主要是什么内容?这里从两方面谈。一是火热为病的广泛性,刘完素认为许多病都脱离不了火热,是广泛地存在的。二是他认为六气皆能化火,这更是火热论的中心思想。正因为六气都能化火,所以发病才有广泛性。虽然是从这两方面来总结刘完素的火热论,并不等于这两个问题是割裂的,这是有密切联系的两个问题。一、火热为病的范畴《素问?至真要大论》中讲病机十九条,属火热的就有9条,包括17个病症。刘完素在《素问玄机原病式》中把“火热”大大地扩展了,有50多个病症。?&识别上方二维码,开始阅读《素问》刘完素还把五运六气的理论引用到对火热的研究中(刘完素所言的五运六气,和刘温舒著的《素问入式运气论奥》不二样),他把诸风掉眩,皆属于肝,归为木;诸痛痒疮,皆属于心,一归为火;诸湿肿满,皆属于脾,归为土;诸气脸郁,皆属于肺,归为金;诸寒收引,皆属于肾,归为水。把属于肝、属于心、属于脾、属是用五运六气来为病机分类,并没有像运气学说那样通过甲子来计算,只是分类而已。从刘完素的代表著作中可以看出,他认为火热存在于广泛的病症中。这一认识是受到《黄帝内经》的启发,当然更重要的还是他从临床实践中体验出来的。他在临床上遇到不少由火热造成的病症,大量的临床实践,逐渐对火热有了理性的认识。《素问?至真要大论》的病机十九条中,气喘、气郁仅属于肺,肿满、呕吐,属于脾。刘完素则认为这些都是由“火”引起的,他说:“热则息数气粗而为喘,热火为阳,主乎急数也。胃月晶热甚则为呕,火气炎上之象也。”这是刘完素在《素问》病机理论的基础上,把气喘、呕吐的病机进一步地具体化了。他认为喘是肺之火热,火热为阳邪,阳则向上急数,所以呼吸增快;呕吐是胃气上炎,火气上冲的结果。讲义中举了两个例子,这些体会都是从实践当中得出来的。不过话要说回来,不是所有喘、吐都属于火热。肺有火热,可以造成喘,但不能说凡是喘都由火热而来;胃上有火热,可以造成呕吐,但不能说凡是呕吐都由火热而生。比如说《金匮要略》大黄甘草汤证,那是胃上的火热,大黄甘草汤主治食人即吐症,凡是食人即吐的,热证居多,所以要泻胃的火热。但是临床上还有朝食暮吐、暮食朝吐的,这种呕吐十有八九不是热的问题,饮食人到胃十多个小时,吐出来还是好好的,这是脾肾阳虚的呕吐。即使是食人即吐,也不是百分之百的因于火热,如现在诊断为神经性的呕吐,其表现是喝点水也吐,多见于身体虚弱的患者,这也不是热的问题。?&识别上方二维码,开始阅读《金匮要略》所以刘完素这种说法,只能是限于从火热的范畴来分析疾病,这一点很重要,如果将其扩大到其他病因的范畴来讨论,完素的火热学说就没有什么价值了,也没有讨论的意义了。要理解他所说的火热病的广泛性,是限于火热为因的病症范畴来发挥的,这点要明确。当然对疾病的研究来说,也可以从其他任何角度来总结一些病症的规律,以及治疗的经验,这样就有现实意义了。二、六气皆能化火说六气皆能化火,这是河间学说的中心思想。首先是风气化火,风气化火是由于阳邪的亢盛,热盛生风嘛,亢盛则流动性大了,就成风的现象,所以风化的火,主要是由于阳邪的亢盛,也从外感、内伤两方面来分析。从外感来讲,如吴塘的桑菊饮(杏仁、连翘、薄荷、桑叶、菊花、桔梗、甘草、苇根),这是治太阴(肺)的风温、风热,临床表现为有轻微的发热、咳嗽、口渴等,这是风生的热,风化的火,因此以祛风、平肝为主,风息、肝平,体温就下来了,口干、咳嗽就没有了,这是外感的风热。从内伤来讲,如钱乙的泻青丸(当归、川芍、龙胆草、桅子、大黄、羌活、柴胡),主治肝胆的实热,临床表现为阵发惊惕,不能控制自己,脾气大,甚至两眼红肿(严重的结膜炎患者可以出现这些表现),在儿童甚至还会抽搐,眼睛上视,这是风生的火,是肝风动了,煽动火热,所以要用泻青丸。泻青,即泻肝,用龙胆草泻肝。惊惕、抽搐、眼睛上视等,都是风的表现,这个方子是用柴胡、羌活散其外,当归、川芎疏其里。我在用这个方的时候,当归、川芎是不用的,用牡丹皮、丹参,因为泻青丸是泻肝的火热,息肝的风动,尽管当归、川芎是入肝的药,人血分的药,但我认为这二味药性辛温,毕竟是肝有火热,辛热药、辛窜药,不利于止抽搐,当归还可以考虑,川芎在这里确实不好用,所以我用丹参、牡丹皮,这二味药也是人血分,这个时候应该是清血凉血,不好用辛温、辛窜的药再助风火。这个方子关键的一味药是“龙胆草”,钱乙之所以敢用当归、川芎,就在于龙胆草的大苦、大寒,有泻火、降火之功,龙胆草被称为有直折火邪之用(但是阴不足的人也不能重用,大苦大寒的药有燥性,有伤津的一面)。其他桅子、大黄引火从大便、小便而泻出,所以涤风泻火。所以刘完素说风能化火,不是抽象空洞的理论,是有实际意义的。不管从内伤来讲,还是从外感来讲,都是临床上经常可以见到的。临床上有一句很形象话:风乘火势,火借风威。风越大,火越燃,对这种火就要先息风,风不息,火就不能灭。息风,对内伤来说,首先要柔肝,如果不去养血柔肝,这个风没法息。还有一句话叫“树欲静而风不息”,树要想静,首先风要停,柔肝是息风的重要途径。柔肝常用的药有:芍药、丹参、牡丹皮、当归、地黄等。对外风来说,常用的药桑叶、菊花等,特别是霜桑叶。风与火的关系,不管是从外感、内伤来讲确实是很密切的,刘完素对此的体会是比较深刻的。湿气化火的基本原理是由水气郁滞而成,在病机里属于郁滞证。水湿之气要以通畅为主,水湿之气能够流通无阻,这是生理之常。如果水湿之气不流通了,郁滞而不得发散,营气、卫气都要受到湿气的阻滞,营卫阻滞而化生火热。解决这种火热的问题,就要解郁导滞。湿化的火,主要解决湿郁、湿滞的问题。试举一例,朱震亨有个方子名“二妙散”,只有苍术、黄柏二味药,治下肢红肿热痛,凡是有热象的都可以用,包括现在医学诊断的下肢风湿热证。苍术味苦而气辛,其特点是能散湿、燥湿,针对水湿郁滞的病机,是主药,是君药。黄柏的功用是熄火,黄柏与苍术相比不是第一位的。这种湿热证临床上也是不少见的,有湿有热,这种病治湿是主要的,主要矛盾在湿的方面,不在火的方面。大家可以看看薛雪的著作,他是专治湿热的大家。燥邪可以化火,燥邪最易伤津、伤气,气枯津涸,火热就产生了。气津不足,不能润养皮肤,皮肤粗糙,治疗燥热的方法,总不外乎一个“润”字。《温病条辨》有个桑杏汤,由桑叶、杏仁、沙参、贝一母、香豉、桅子皮、梨皮组成,治秋天外感的燥气、燥热。秋燥易伤太阴气分,所以桑杏汤的主要特点就是润燥,可以说除桅子是泻火、清热的之外,没有一味药不带润的。燥热该如何用呀,燥热用钱乙的泻青丸不行,用朱震亨的二妙散更不行,只能考虑用桑杏汤这种方法。《温病条辨》中有好几个治燥热的方子都不错,如沙参麦冬汤也是治燥热的,还有喻昌的清燥救肺汤也是润燥的,方歌云:“清燥救肺参草把,石膏胶杏麦芝麻,经霜收下干桑叶,解郁滋干效可夸。”由燥化的火总是伤津伤气,人体营卫之气失去津液的润养,燥火就产生了,治疗方法是滋润津液,要在润的基础上去泻火热。?&识别上方二维码,开始阅读《温病条辨》寒可以化火,寒与火好像是绝对对立的,从临床来看多见于闭证,可见于表证也可见于里证。寒邪的特点是收引、收敛,如果寒邪收敛在表,就会因表闭而发热、无汗,这是寒化的火,那就是麻黄汤证,要散寒解表,用杏仁、桂枝、麻黄、问题。尽管有发热,但是由于寒闭,所以就要用辛温散寒的办法,炙甘草解决问题。这就是寒邪闭于表化的火。寒邪闭于里也可以化火,《伤寒论》259条云:“伤寒发汗已,身目为黄,所以然者,以寒湿在里不解故也。以为不可下,当于寒湿中求之。”这里看到的黄疽,是寒湿化热的表现,当于寒湿中求之,要温化寒湿,同时寒湿已化火也要清热,要用茵陈、五荃类,用五菩去散寒湿,用茵陈去清热。需注意的是,这不是湿热证,不是阳明热证,不可下,当于寒湿中求之。刘完素六气化火说,在临床上有深刻的意义,强调不要只看到“化热”这一表面的现象,而不去深究化热的病因,这里有辩证法思想。表面都有热象,但要查出火热的不同成因,是风化火?是寒化火?是湿化火?还是燥化火?要透过现象看本质,中医强调辨证,就是辨这本质的东西,这样才能正确立法。有人责备刘完素一不辨证,实际这正是很精细的辨证,所以说六气化火是火热论的核心内容。刘完素的火热论给我们以启示,中医临床强调辨证,就是要通过临床的表现来分析内在的病机,这个病变的本质所在,这就是我们说的“证”,通过复杂的症状体征(候)分辨出来其属于某性质的“证”,这就是中医的辨证。三、火热病的治法刘完素的火热治法,可以说是完全根据《素问?热病》来的,这一点与张仲景发挥《黄帝内经》的热论有别。刘完素在临床上完全用了《素问二热病》的思想,他主要分辨热证是在表,还是在里,从表里两方面来讨论治法。火热在表,刘完素主张用辛、凉、甘、寒的药来解表,明确提出不能用桂枝、麻黄类,热证当然不适合用桂枝汤、麻黄汤等辛温剂,这和仲景用桂枝、麻黄针对风寒证是不同性质的病症。刘完素强调:“阳热郁遏于表,虽亦见恶寒战栗诸症,实为阳热郁极而产生的假象,不能辛热解表以助其热,而应以石膏、滑石、甘草、葱、豉等以开发其郁结,必须从脉证上细心分辨。”患者发冷、寒战,是发热的前奏,这样的恶寒是不能用桂枝、麻黄的,只能用石膏、滑石、甘草、葱、豉等以开发其郁结。(刘完素提到的甘草、滑石是甘寒药,滑石六钱,甘草一钱,称为“六一散”,这是从分量上来命名,这个方子又叫“天水散”,这个水是天一化生之水,六一散就是天一生水,地六承之,这是从处方的立意来命名的。)刘完素认为单纯的表热证要用葱豉汤、天水散等来治疗,葱豉汤辛凉,天水散甘寒,而禁用辛温。热邪不在表而入于里,里热郁结即成里热证。刘完素清里热的方子主要有两个:一个是三一承气汤,另一个是黄连解毒汤。三一承气一汤是把大承气、小承气、调味承气等三介承气汤合成为一个方子,实际就是大承气汤加炙甘草,如果表热没有了,而里热郁结,就用三一承气来泻里热,泻郁结。如果里热很深,成为热毒之势,要用黄连解毒汤来清热,就是三黄加桅子,即黄连、黄答、黄柏、黄桅子,也可以说是四黄。如果里热已清,余热不退,也可以用小剂量的黄连解毒汤来清余热。如果既有表热又有里热,表里俱热证,刘完素用表里双解法,常用的处方有防风通圣散(防风通圣大黄硝,荆芥麻黄桅芍翘,甘桔芍归膏滑石,薄荷答术力偏饶)、双解散、天水一凉隔半散(一剂天水散半剂凉隔散)、天水凉隔各半汤(天水散凉隔散各一半)。双解散、防风通圣散都是刘完素很著名的方子。北京中医医院皮肤科的赵炳南大夫,常用防风通圣散,解决不少表里热的问题,皮肤表面大小不同的疮疥,很多都是内热造成的,所以赵老习惯用防风通圣散,他得到了河间学术的这个精神。河间学术从临床来看并不复杂,热邪在表就用葱豉汤、天水散等,热邪在里就用三一承气汤、黄连解毒汤等,表里俱热用防风通圣散、双解散、天水散、凉隔散等,主要就是用这么几个方子进行表里分治,关键是要学习刘完素六气化火的学术思想,这对临床是大有帮助的。四、刘完素的主要著作刘完素的门人就不谈了,他们的师承关系讲义上都有,这里简单介绍一下刘完素的几部著作。《素问玄机原病式》这是刘完素火热论最主要的著作,六气化火说都在这里面的;《宣明论方》记载了刘完素治杂病的经验,是引用《素问》中50多种杂病来归纳的;《素问病机气宜保命集》记载的也是刘完素治杂病的经验,其中三分之一内容是治火热病的;《伤寒标本心法类萃》、《三消论》、《伤寒直格》这三部书基本都是以火热论为主题的,尤其是《三消论》值得看一看,这本书介绍了消渴病的治疗,上焦热、中焦热、下焦热等的治法。《伤寒直格》是讲表里热证的分治,马宗素的《伤寒医鉴》、馏洪的《伤寒心要》这两部书与《伤寒直格》出入不大,基本上就是《伤寒直格》的内容。总之,刘完素的书主要就是看这三部:《素问玄机原病式》、《宣明论方》、《三消论》,基本就抓住刘完素火热论的主要学术思想了。来源:周仲英临床经验辑要,版权归原作者所有。点击查看:点击图片,阅读近期精彩好文请先关注微信公众号:zk120回复“应用”:下载App,古籍1800本、医案4万、方剂30万回复“伤寒论”:微信读古籍,启蒙六经辨证回复“神农本草经”:微信读古籍,最早中药专著回复“素问”:微信读古籍,中医始祖之作回复“病历夹”:在线管理病历,你的病人你做主回复“诊疗”:针对疾病和症状,推荐权威可靠的治疗方案点击“阅读原文”,免费获得神黄中医智库VIP特权!
阅读原文和更多同类文章
可关注微信公众帐号
还可知道有多少人阅读过此篇文章哦
(微信号和暗号可长摁复制)
猜你感兴趣您现在的位置: >
会员咨询:010-
技术咨询:010-
展会合作/友情链接:010-
传真:010-
地址:北京市海淀区彩和坊路10号(1+1大厦)5层(501-506)
深圳分公司***:1 传真:7 邮编:518118 地址:深圳市龙岗区吉华路393号英达丰科技园A栋4层
Email:(使用时请把#换成@)> ZK开发要害知识点
ZK开发要害知识点
sdwazhian & &
发布时间: & &
浏览:346 & &
回复:0 & &
悬赏:0.0希赛币
ZK开发关键知识点  前言
  本文是对ZK开发过程中必须掌握的关键知识点的总结,针对目前对新版本zk-6.5.2
  关于ZK是什么参见前一篇博客 《ZK(The leading enterprise Ajax framework)入门指南》
1. 页面布局
  ZK具有非常高的开发效率(以至于可以取代HTML用来完成高质量的Fast Prototyping),最主要缘自它采用的页面布局技术----ZUL;
  采用XML语言以声明式的方式创建用户界面----XML UI技术并不是ZK的独创,Android&UI、JavaFX、Microsoft&Silverlight和Mozilla&XUL等开发
  框架都采用了这种技术,这是目前最先进的构造用户界面技术;
  ZUL只不过是为所有ZK组件指定了一个对应的XML Element,然后通过这些Element以声明式的方式定义页面由哪些组件以什么样的方式构成。
  相对于Java编程式方式,这种声明式方式的优点十分明显:
直观:ZUL代码结构与页面布局完全一致(而且必须一致),ZUL元素的嵌套关系就是页面组件的嵌套关系,ZUL元素的前后并列关系就是页面组件的前后摆放;而Java编程方式与最终页面却没有这种一致性;代码简洁:由于XML在表达页面布局时语义的先天优势(一致性),同样的页面用ZUL比Java代码量要少得多;
  直观、简洁的代码意味着容易理解、容易编写、容易修改维护、不容易出错,因此带来开发效率上的巨大优势。
  值得注意的是,上述ZUL相对于Java编程的优势也适用于JS,比如EXT、DOJO等JS UI框架。
1.1. 布局组件
1.1.1. 东西南北中布局Borderlayout
  Borderlayout将屏幕划分成东西南北中五个区域,如下图所示,其灵活性可以实现绝大多数系统的首页整体布局。
  首先纵向看,要指定N和S的高度,剩下中间部分就是W C E的高度;然后水平看,N S宽度百分百,中间部分指定W E的宽度后,
  剩下的部分就是C了。
  由于Center大小不是自己决定的,当里面摆放组件过多显示不全时,可以指定autoscroll=&true&产生滚动条。
1.1.2. 基本布局
  Borderlayout适合于实现大的页面结构布局,在页面局部最常见的需求就是如何将各种组件有序的摆放:有时需要水平摆放有时需要垂直摆放,
  还要考虑居中居左居右问题、摆不下的问题(摆放不下时要有滚动条);
  ZK提供了更细粒度的布局组件----hbox/vbox/hlayout/vlayout用于实现这些常见需求;
  hlayout和hbox(h代表horizon水平)用于水平布局,vlayout和vbox(v代表vertical垂直)用于垂直布局,它们是最常用的的容器组件,里面可以
  放任意多的组件;
  hbox vbox与hlayout vlayout的区别:
  Hbox and Vbox provide more functionalities such as splitter, align and pack.
  However, their performance is slower,
  so it is suggested to use Hlayout and Vlayout if you'd like to use them a lot in a UI, unless you need the features that only Hbox and Vbox support.
1.2. 各种容器组件
1.2.1. groupbox
  企业应用往往需要在一个页面中显示大量信息或组件,如果随意摆放或只是简单的罗列,会让用户感觉很混乱难以使用,用户体验不好。
  groupbox顾名思义就是用来分组布局的组件,它就像收纳盒一样可以把页面组件分门别类的摆放,标题栏可以清晰的标识分类名称,而且可收缩。
  &groupbox width=&50%&hflex=&true&closable=&true&mold=&3d&&
  &caption label=&基本信息&/&
  &textbox id=&userIdLongbox&value=&@bind(fx.id)&visible=&false&/&
  ………………
1.2.2. tabbox页签
  像ZK这样的RIA框架做出来的系统基本上SinglePage的(整个系统只有一个页面,其它都是组件和AJAX),
  同时企业应用不同于网站,用户需要打开很多视图查看各种数据和表单,因此普遍采用“多页签布局”来保证系统的方便易用。
  ZK提供了tabbox组件方便的实现多种形式的页签:
  默认水平排列页签
  &tabboxid=&tb&height=&300px&&
  &tabsid=&tabs&&
  &tabid=&A&label=&Tab
  &tabid=&B&label=&Tab
  &/tabs&
  &tabpanels&
  &tabpanel&This is panel A&/tabpanel&
  &tabpanel&This is panel B&/tabpanel&
  &/tabpanels&
  &/tabbox&
  纵向排列页签
  &tabboxid=&tb&height=&300px&orient=&vertical&&
  &tabsid=&tabs&&
  &tabid=&A&label=&Tab
  &tabid=&B&label=&Tab
  &/tabs&
  &tabpanels&
  &tabpanel&This is panel A&/tabpanel&
  &tabpanel&This is panel B&/tabpanel&
  &/tabpanels&
  &/tabbox&
  最新zk-7支持下方的水平排列页签。
  另外只需设置属性 mold=&accordion&就可以把页签变成可纵向滑动伸缩的“抽屉”式页签:
  纵向排列页签
  &tabboxid=&tb&height=&300px&mold=&accordion&&
  &tabsid=&tabs&&
  &tabid=&A&label=&Tab
  &tabid=&B&label=&Tab
  &/tabs&
  &tabpanels&
  &tabpanel&This is panel A&/tabpanel&
  &tabpanel&This is panel B&/tabpanel&
  &/tabpanels&
  &/tabbox&
1.2.3. window与panel
  window和panel是GUI最常见的容器形式,可以在里面放置任意多的组件;
  它们不同于其它容器之处在于可以关闭、最小化、最大化、模态显示(始终显示在最前面,除非最小化或关闭)、可拖动;
  但是window和panel也有两个很小的区别:
window是一个独立的idspace,而panel不是;因此panel内部的组件与panel外部的是一样的;panel智能在自己的parent组件范围内移动,而window可以在整个页面移动;
  在ZK中创建一个窗口并以模态显示,代码如下:
  //create a window programmatically and use it as a modal dialog.&&&&&&&
  Window window = (Window)Executions.createComponents(&/widgets/window/modal_dialog/employee_dialog.zul&,null,null);
  window.doModal();
  一个简单的窗口页面:
  &windowid=&modalDialog&title=&Coffee
Order&border=&normal&width=&460px&apply=&demo.window.modal_dialog.EmployeeDialogController&
  position=¢er,center&closable=&true&action=&show:
slideDhide: slideUp&&
  &vlayout&
  ………………
  &/vlayout&
  &/window&
1.3. Messagebox对话框
Warning :&&&&& Messagebox.show(&Warning is pressed&, &Warning&, Messagebox.OK, Messagebox.EXCLAMATION);Question:&&&&& Messagebox.show(&Question is pressed. Are you sure &, &Question&, Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION);Information:&&&&& & Messagebox.show(&Information is pressed&, &Information&, Messagebox.OK, RMATION);Error:&&&&&&& &&&&&&&& Messagebox.show(&Error is pressed&, &Error&, Messagebox.OK, Messagebox.ERROR);Confirm Dialog:详见
  ZK虽然支持在ZUL脚本语言编程,但显然更正规也更有效的开发模式是把交互逻辑放到后台Java代码中实现,MVC模式正是这样的风格。
  ZK MVC很简单:页面apply指定Controller、Controller中注入页面组件、Controller方法***页面事件并修改操纵页面组件;
2.1. MVC基本原理示例
  public
class SearchController extendsSelectorComposer&Component& {
  @Wire&&&privateTextbox keywordB//注入页面组件
  @Wire&&&privateListbox carL//注入页面组件
  @Listen(&onClick = #searchButton&)&&&//***页面事件
  publicvoidsearch(Event event){
  Button searchButton = (Button) event.getTarget();
  String keyword = keywordBox.getValue();
  List&Car& result = carService.search(keyword);
  carListbox.setModel(newListModelList&Car&(result));//操纵页面组件(显示数据或改变状态)
  其中2、3行代码将页面中id为keywordBox和carListbox的组件注入Controller作为实例变量,后面方法中对它们进行的修改将被ZK框架自动同步到前端页面上去;
  第5行代码为方法注册了页面事件***器----页面中id为searchButton的组件的onClick事件发生时调用此方法,
  组件以及事件***的表达式详见:omposer_For_MVC
2.2. MVC forward事件处理
  当页面组件很多时,如果只用onClick等少数内建事件进行***会显得混乱。
  forward可以用来将某个组件上发生的内建事件转发到外层并取别名,示例如下:
  &windowid=&mywin&&
  &buttonlabel=&Save&forward=&onSave&/&
  &buttonlabel=&Cancel&forward=&onCancel&/&
  &listitemself=&@{each=p1}&forward=&onDoubleClick=mywin.onDetail(each.prop1)&&
  &/window&
  controller事件处理代码
  @Listen(&onDetail= #mywin&)//***mywin的onDetail事件
  publicvoidonDetail(ForwardEvent e) {
  MouseEvent me = (MouseEvent) e.getOrigin();//获取源事件
  System.out.println(me.getData());//获取参数
3.1. MVVM Binding
3.1.1. Binding绑定概述
  Binding(绑定)是Web框架最重要特性之一,Binding没有一个统一的定义,通常的Binding是指:
  在 页面元素 与 后台(Controller)组件字段 之间建立起链接,使得后台数据(及其变化)可以显示(同步更新)到页面,
  同时用户在页面的输入(修改)也可以传递(更新)到后台;
  从这个定义可以看出,Binding是很常见的需求,如果不采用Binding技术,那么手工完成上述工作(如request.getParameter或setAttribute)
  会十分的繁琐无聊,产生大量重复代码;
3.1.2. 复杂类型Binding
  幸好ZK的MVVM数据绑定非常强大----支持任意复杂类型,例如枚举类型:
  &comboboxselectedItem=&@bind(fx.userTypeForCc)&readonly=&true&model=&@load(vm.userTypeForCcList)&itemRenderer=&com.xxx.boitemRenderer4UserTypeCc&/&
  class ComboitemRenderer4UserTypeCc implements ComboitemRenderer&USER_TYPE_FOR_CC& {
  @Override
  public void render(Comboitem item, USER_TYPE_FOR_CC data, int index) throws Exception {
  item.setLabel(data.getText());
3.1.3. Binding标签
  而且用起来很简单----只要三个标签(@load、@save、@bind)就可以实现各种类型的数据绑定:
@load 用来从后台读数据显示在页面;@save 用来将页面输入的信息传递给后台绑定的组件字段;@bind 是@load加@save;
3.1.4. Binding表达式
  标签中还可以运用复杂表达式,例如:
日期格式转换:&label value=&@load(vm.modelA.crtDttm) @converter('formatedDate', format='yyyy-MM-dd HH:mm')& /&比较运算:&listcell label=&@load(item.quantity)& style=&@load(item.quantity lt 3 'color:red':'')&/&绑定集合:&listbox selectedItems=&@bind(vm.selected)& model=&@load(vm.model)&&根据条件动态选择Template循环:
  &gridmodel=&@bind(vm.orders) @template(vm.type='foo' 'template1':'template2')&&
  &templatename=&template1&&
  &!-- child components --&
  &/template&
  &templatename=&template2&&
  &!-- child components --&
  &/template&
  &/grid&
  &gridmodel=&@bind(vm.orders) @template(each.type='A' 'templateA':'templateB')&&
  &templatename=&templateA&&
  &!-- child components --&
  &/template&
  &templatename=&templateB&&
  &!-- child components --&
  &/template&
  &/grid&
3.1.5. 表单整体Binding
  对于表单提交场景,我们通常不希望表单中的各个字段单独进行Binding(那会导致每输入一个字段都会产生一次后台交互,
  而且无法进行整体校验),
  更好的做法是把表单所有元素要作为一个整体,在最后提交时才绑定到后台组件(的Model字段上),这样也使得架构更清晰更OO;
  ZUL示例如下:
  &groupboxwidth=&50%&hflex=&true&closable=&true&mold=&3d&
  form=&@id('fx') @load(vm.user) @save(vm.user, before='submit') @validator(vm.validator)&&
  &textboxvalue=&@bind(fx.userName)&readonly=&${not
empty arg.userId }&/&
  &textboxtype=&password&value=&@bind(fx.password)&/&
  &textboxtype=&password&value=&@bind(fx.confirmPassword)&/&
  ………………
  ………………
  &buttonid=&btn_submit&label=&提交&onClick=&@command('submit')&/&
  ………………
  更多参考 0Binding
3.2. MVVM前后台通信
  binding只是在在前后台之间建立起了一个链接,但是还需要一个命令机制来通知框架什么时候以及如何在前后台同步状态;
3.2.1. 前台触发后台动作
  页面使用@command标签调用后台组件,示例:
  &menuitemlabel=&创建Xxx&onClick=&@command('openXxxForm',id=each.id)&/&
  后台组件示例:
  @Command
  public
void openXxxForm(@BindingParam(&id&) String roleId) {
3.2.2. 后台通知前台刷新
  只需在后台组件方法上声明@NotifyChange({ &property1& }),页面中的@load(vm.property1)就会刷新获取最新的值;
3.2.3. MVVM跨页面调用
  页面中的@command只能触发当前页面对应的后台组件的方法调用,要想通知其它页面的后台组件调用需要使用@GlobalCommand(&refreshDataList&);
  调用也不是发生在页面,而是在后台显式调用:BindUtils.postGlobalCommand(null, null, &refreshDataList&, null);
3.3. MVVM Validation
3.3.1. Validation概述
  Web框架最重要的职责之一就是Validation校验----对客户端提交的数据进行合法性检查(长度、类型、取值范围等),
  如果校验失败,则返回错误信息并在前端界面中友好清晰的显示错误信息。
3.3.2. MVVM Validation典型步骤
  前面binding章节的表单整体绑定中已经包含了validation:
  &windowid=&winEditUser&apply=&org.zkoss.bind.BindComposer&
  viewModel=&@id('vm') @init('com.xxx.ctrl.UserFormDialogCtrl')&validationMessages=&@id('vmsgs')&
  &groupbox width=&50%&hflex=&true&closable=&true&mold=&3d&
  form=&@id('fx') @load(vm.user) @save(vm.user, before='submit') @validator(vm.validator)&&
  &textboxtype=&password&value=&@bind(fx.password)&/&
  &labelvalue=&@load(vmsgs['password'])&sclass=&red&/&
  &textboxvalue=&@bind(fx.contactInfo.email)&/&
  &labelvalue=&@load(vmsgs['contactInfo.email'])&sclass=&red&/&
  ………………
validationMessages=&@id('vmsgs')&为校验失败时的错误信息集合指定别名vmsgs其中@validator(vm.validator)指定了表单提交后用来校验的Validator校验器;&label value=&@load(vmsgs['contactInfo.email'])& sclass=&red& /& 用来在校验失败时显示错误信息。
  ViewModel
  public
org.zkoss.bind.Validator getValidator() {
3.3.3. MVVM Validation集成JSR303
  JSR303是专门针对JavaBean Validation的规范,hibernate-validator是它的一个实现:
  &dependency org=&org.hibernate& name=&hibernate-validator& rev=&4.3.0.Final& conf=&runtime& /&
  借助这一框架,可以在JavaBean类中添加对应的Annotation声明校验规则,非常简便而强大;
4. 列表与分页
4.1. 列表内存分页
  ZK列表listbox组件只需配置mold属性为paging即可实现分页,但这样的分页属于内存分页----数据一次性加载到服务端然后每次翻页把当前页数据显示在前台;
  &listboxid=&dataListbox&mold=&paging&pageSize=&20&multiple=&true&checkmark=&false&emptyMessage=&搜索结果为空&width=&100%&vflex=&true&&
  &listheadmenupopup=&auto&width=&100%&sizable=&false&&
  ………………
  &/listhead&
  &templatename=&model&&
  &listitemstyle=&cursor:cursor:&&
  &labelvalue=&${forEachStatus.index+1}&/&
  &labelvalue=&${each.userName}&/&
  然后Controller中只要设置dataListbox的model即可显示列表数据:
  List carsModel =
new ListModelList&Car&(carService.findAll());
  dataListbox.setModel(carsModel);
  Demo见
4.2. 列表数据库分页
  上面的内存分页无法用于真正的生产系统,因为一次加载出所有数据会耗尽服务器内存;
  解决方法是数据库分页,每次请求只查询出一页数据然后显示到页面;但是这就不能简单的通过一个配置实现了。
  参考 /wiki/Small_Talks/2011/March/Sorting_huge_data_using_ZK
  动态树
  &hlayoutheight=&90%&vflex=&true&&
  &!-- 设置vflex=&true&否则没有垂直滚动条,导致显示不全;设置hflex=&true&否则会出现讨厌的水平滚动条 --&
  &treeid=&orgTree&vflex=&true&hflex=&true&height=&100%&width=&100%&
  model=&@bind(vm.organTreeModel)&multiple=&false&checkmark=&false&zclass=&z-tree&&
  &treecols&
  &treecolhflex=&7&label=&名称&/&
  &treecolhflex=&3&label=&描述&/&
  &treecolhflex=&1&label=&用户数&align=¢er&/&
  &/treecols&
  &templatename=&model&&
  &treeitemopen=&@load(each.data.open)&selected=&@bind(each.data.selected)&&
  &treerowonClick=&@command('selectOrganNode',organId=each.data.id)&&
  &treecelllabel=&${eacanName}&/&
  &treecelllabel=&${each.data.description}&/&
  &treecelllabel=&${each.data.userAmount}&/&
  &/treerow&
  &/treeitem&
  &/template&
  &/tree&
  &/hlayout&
和listbox类似的,只需为tree提供model数据,然后内部通过template循环即可打印出一颗动态的树;设置treeitem的属性open和selected属性即可控制树节点是否展开以及是否选中;
6. 右键菜单
  首先在页面中隐藏一个menupopup如下:
  &menupopupid=&treeMenupopup&&
  &menuitemlabel=&展开&onClick=&@command('expandDir')&/&
  &menuitemlabel=&创建子目录&onClick=&@command('newDir')&/&
  &menuitemlabel=&修改名称&onClick=&@command('editDir')&/&
  &menuitemlabel=&删除&onClick=&@command('deleteDir')&/&
  &/menupopup&
  然后为需要右键弹出菜单的组件注册事件:
  &treerowonRightClick=&@command('openTreeMenu', paramEvent=event,
reportId=each.data.id, image=each.data.image)&&
  处理右键事件:
  @Command
  publicvoidopenTreeMenu(@BindingParam(¶mEvent&)
Event paramEvent,@BindingParam(&reportId&) String reportId,
  @BindingParam(&image&) String image) {
  if(StringUtils.isEmpty(image)) {
  treeMenupopup.open(paramEvent.getTarget(),&after_end&);//在鼠标光标所在的组件后面弹出菜单
  reportIdForRightClick = reportId;
  然后就是处理菜单的点击事件,没什么特别的了。
7. Spring集成
  ZK与Spring集成非常简单,只需在MVC的Controller或MVVM的ViewModel类上面声明@VariableResolver(DelegatingVariableResolver.class)即可,
  然后就可以通过Annotation声明实例变量注入Spring Bean,代码如下:
  @VariableResolver(DelegatingVariableResolver.class)
  public
class AbcCtrl extendsSelectorComposer&Window& {
  @WireVariable
  privateAbcService&&& abcS
8. SpringSecurity集成
8.1. ZK集成SpringSecurity原理
  SpringSecurity是最主流的Web安全框架,框架中封装了一个Web应用通用的典型认证与授权流程,以及安全上下文、session管理、cookie管理等服务;
  同时框架为那些不通用的部分留下了扩展点和配置点,例如用户信息获取、权限数据获取、登录页面、登录后跳转、出错页面等;
  ZK应用也是Web应用,因此可以直接置于SpringSecurity的保护之下。
  但ZK应用又有特殊之处:大量采用AJAX交互并且请求URL不规则,因此为了对ZK应用进行细粒度的权限控制需要借助zkspring-security这个库的帮助;
8.2. ZK集成SpringSecurity配置步骤
  依赖的第三方lib:zkspring-security
  ivy.xml
  &dependencyorg=&org.zkoss.zk&name=&zkspring-security&rev=&3.1.1&conf=&runtime&transitive=&false&/&
  &dependencyorg=&org.springframework.security&name=&spring-security-core&rev=&3.1.4.RELEASE&conf=&runtime&/&
  &dependencyorg=&org.springframework.security&name=&spring-security-acl&rev=&3.1.4.RELEASE&conf=&runtime&/&
  &dependencyorg=&org.springframework.security&name=&spring-security-taglibs&rev=&3.1.4.RELEASE&conf=&runtime&/&
  &dependencyorg=&org.springframework.security&name=&spring-security-config&rev=&3.1.4.RELEASE&conf=&runtime&/&
  &dependencyorg=&org.springframework.security&name=&spring-security-web&rev=&3.1.4.RELEASE&conf=&runtime&/&
  web.xml配置:
  &listener&
  &listener-class&org.springframework.security.web.session.HttpSessionEventPublisher&/listener-class&
  &/listener&
  ……………………
  &filter&
  &filter-name&springSecurityFilterChain&/filter-name&
  &filter-class&org.springframework.web.filter.DelegatingFilterProxy&/filter-class&
  &/filter&
  &filter-mapping&
  &filter-name&springSecurityFilterChain&/filter-name&
  &url-pattern&/*&/url-pattern&
  &/filter-mapping&
  SpringSecurity配置:
  & xmlversion=&1.0&encoding=&UTF-8& &
  &beans:beansxmlns=&;xmlns:beans=&;
  xmlns:xsi=&;xmlns:zksp=&;
  xsi:schemaLocation=&
  &intercept-urlpattern=&/images/**&access=&IS_AUTHENTICATED_ANONYMOUSLY&/&
  &intercept-urlpattern=&/login.html*&access=&IS_AUTHENTICATED_ANONYMOUSLY&/&
  &intercept-urlpattern=&/pages/admin/**&access=&ROLE_ADMIN&/&
  &intercept-urlpattern=&/pages/**&access=&IS_AUTHENTICATED_ANONYMOUSLY&/&
  &intercept-urlpattern=&/**&access=&IS_AUTHENTICATED_ANONYMOUSLY&/&
  &form-loginlogin-page=&/login.html&authentication-failure-url=&/login.html login_error=1&
  default-target-url=&/main.html&always-use-default-target=&true&/&
  &!-- Following is list of ZK Spring Security custom filters. They needs to be exactly in the same order as shown below
  in order to work. --&
  &custom-filterref=&zkDesktopReuseFilter&position=&FIRST&/&
  &custom-filterref=&zkDisableSessionInvalidateFilter&before=&FORM_LOGIN_FILTER&/&
  &custom-filterref=&zkEnableSessionInvalidateFilter&before=&FILTER_SECURITY_INTERCEPTOR&/&
  &custom-filterref=&zkLoginOKFilter&after=&FILTER_SECURITY_INTERCEPTOR&/&
  &custom-filterref=&zkError403Filter&after=&LOGOUT_FILTER&/&
  &/http&
  &authentication-manager&
  &authentication-provider&
  &user-serviceproperties=&classpath:/properties/security-users.properties&/&
  &/authentication-provider&
  &/authentication-manager&
  &zksp:zk-eventlogin-template-close-delay=&1&path-type=&ant&&
  &zksp:intercept-eventevent=&onClick&path=&//**/cmdBtn_*&access=&ROLE_ADMIN&/&
  &zksp:intercept-eventevent=&onClick&path=&//**/menu_*&access=&ROLE_ADMIN&/&
  &zksp:intercept-eventevent=&onClick&path=&//**/treemenu_*&access=&ROLE_ADMIN&/&
  &zksp:intercept-eventevent=&onClick&path=&//**/btn_*&access=&ROLE_USER&/&
  &zksp:intercept-eventpath=&/**&access=&IS_AUTHENTICATED_ANONYMOUSLY&/&
  &zksp:form-loginlogin-page=&/login.html&/&
  &/zksp:zk-event&
  &/beans:beans&
9. ZK全局配置
9.1. 按钮防止连击
  在zk.xml配置:
  &language-config&
  &addon-uri&/WEB-INF/lang-addon.xml &/addon-uri&
  &/language-config&
  在lang-addon.xml添加配置:
  &component&
  &component-name&button&/component-name&
  &extends&button&/extends&
  &property&
  &property-name&autodisable&/property-name&
  &property-value&self&/property-value&
  &/property&
  &/component&
9.2. Theme换肤
  在lang-addon.xml添加配置:
  &library-property&
  &name&org.zkoss.theme.preferred&/name&
  &value&sapphire&/value&
  &/library-property&
10. 国际化i18n
  设置当前用户的local
  &listbox id=&localSelector&mold=&select&rows=&1&width=&80px&&
  &listitem label=&语言/Local&value=&&/&
  &listitem label=&English&value=&en&/&
  &listitem label=&简体中文&value=&zh_CN&/&
  &/listbox&
  @Listen(&onSelect = #localSelector&)
  publicvoidonSelectLocal(Event event) {
  Object localName = ((Listbox) event.getTarget()).getSelectedItem().getValue();
  logger.debug(&选择语言区域&);
  CookieUtils.setLocal(Executions.getCurrent(), (String) localName);
  Locale locale = Locales.getLocale((String) localName);
  Executions.getCurrent().getSession().setAttribute(Attributes.PREFERRED_LOCALE, locale);
  Executions.sendRedirect(null);
  zk.xml
  &listener&
  &listener-class&com.xxx.base.LocalInterceptor&/listener-class&
  &/listener&
  LocalInterceptor.java
  public
class LocalInterceptor implementsRequestInterceptor {
  @Override
  publicvoidrequest(org.zkoss.zk.ui.Session sess, Object request, Object response) {
  String localName = CookieUtils.getLocal((HttpServletRequest) request);
  Locale locale = Locales.getLocale(localName);
  ((HttpServletRequest) request).getSession().setAttribute(Attributes.PREFERRED_LOCALE, locale);
  public
class CookieUtils {
  * 添加名为zktheme的cookie就可以改变当前用户的theme
  staticString&&& THEME_COOKIE_KEY&&& =&zktheme&;
  staticString&&& LOCAL_COOKIE_KEY&&& =&zkLocal&;
  publicstaticString getLocal(HttpServletRequest request) {
  Cookie[] cookies = request.getCookies();
  if(cookies ==null)
  return&&;
  for(inti =0;
i & cookies. i++) {
  Cookie c = cookies[i];
  if(LOCAL_COOKIE_KEY.equals(c.getName())) {
  String theme = c.getValue();
  if(theme !=null)
  return&&;
  publicstaticvoidsetLocal(Execution exe, String localName)
  Cookie cookie =newCookie(LOCAL_COOKIE_KEY, localName);
  cookie.setMaxAge(60*60*
24*30);// store 30 days
  String cp = exe.getContextPath();
  // if path is empty, cookie path will be request path, which causes problems
  if(cp.length() ==0) {
  cp =&/&;
  cookie.setPath(cp);
  ((HttpServletResponse) exe.getNativeResponse()).addCookie(cookie);
  资源文件zk-label.properties
  welcome=Welcome
  theme.sapphire=sapphire
  theme.silvertail=silvertail
  资源文件zk-label_zh_CN.properties
  welcome=欢迎
  theme.sapphire=蓝色
  theme.silvertail=银灰
  页面中用标签显示信息
  &listitemlabel=&${labels.theme.sapphire}&value=&sapphire&/&
11. 文件上传
  在ZUL页面中,通过指定upload属性就可以把一个按钮或菜单变成文件上传组件了,并且可以设置附件大小限制,如下:
  &menuitemlabel=&添加附件&image=&/images/attachment_16.png&upload=&true,native,maxsize=10240&onUpload=&@command('boardUploadFile')&/&
  &buttonlabel=&添加附件&upload=&true,native,maxsize=10240&onUpload=&@command('formUploadFile')&/&
  然后在ViewModel中处理上传的文件,如下:
  @Command
  @NotifyChange({&boardAttachmentList&,&boardAuditInfoList&})
  publicvoidboardUploadFile(@ContextParam(ContextType.TRIGGER_EVENT)
UploadEvent event)throwsIOException {
  Media media = event.getMedia();
  logger.debug(&文件名为&);
  logger.debug(&文件大小为&);
  logger.debug(&文件类型为&);
  QualityPlanAttachment qualityPlanAttachment =newQualityPlanAttachment();
  qualityPlanAttachment.setFileName(media.getName());
  qualityPlanAttachment.setFileSize((long) media.getByteData().length);
  qualityPlanAttachment.setContent(media.getByteData());
12. 文件下载
  很简单,只需调用ZK相关API Filedownload.save;另外要注意不同浏览器对中文文件名可能产生乱码问题;
  @Command
  publicvoidboardDownloadFile(@BindingParam(&fileId&)
String fileId)throwsUnsupportedEncodingException {
  ………………
  String fileName = attachment.getFileName();
  byte[] content=attachment.getByteArray();
  Filedownload.save(content,null, ZkUtils.encodingFileName(fileName));
  //解决文件名乱码问题
  public
static String encodingFileName(String fileName)
throws UnsupportedEncodingException {
  HttpServletRequest httpRequest = (HttpServletRequest) Executions.getCurrent().getNativeRequest();
  String browserName = Servlets.getBrowser(httpRequest);
  if(StringUtils.equalsIgnoreCase(&gecko&, browserName))
{//firefox
  fileName =newString(fileName.getBytes(&UTF-8&),&ISO8859-1&);
  }else{//ie浏览器
  fileName = URLEncoder.encode(fileName,&UTF-8&);
  returnfileN
13. CKEditor
  ZK的子项目ckez实现了对CKEditor(一款流行的在线文本编辑器)的封装,可以方便的集成到ZK应用中实现在线编辑复杂格式文档;
  ivy.xml
  &dependencyorg=&org.zkoss.zkforge&name=&ckez&rev=&3.6.4.0&conf=&runtime&/&
  然后zul中只需像textbox一样去用就可以了:
  &ckeditortoolbar=&Basic&value=&@bind(fx.content)&hflex=&true&width=&90%&height=&95px&/&
14. Chart图表
  ZK自带的chart图表参考在线demo :
  另外ZK的子项目zhighcharts对higncharts-js(用于绘制各种常见图表的js库)进行了封装,可以方便的集成到ZK应用,详见:
15. 自定义组件
  zul中声明以及使用
  & componentname=&progressBar&extends=&hlayout&class=&coponent.ProgressBarHlayout& &
  &progressBarprogress=&@load(vm.plan1.progressPercentageValue)&widthValue=&120&height=&9px&/&
  Java代码
  public
class ProgressBarHlayout extendsHlayoutimplementsIdSpace {
  privatestaticfinalint&&&
VALUE_LABEL_WIDTH&&& =0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//30
  Div&&&&&&&&&&&&&&&&&&&&&&&&&&& progressD
  Div&&&&&&&&&&&&&&&&&&&&&&&&&&& grayD
  String&&&&&&&&&&&&&&&&&&&&&&& defaultStyle&&&&&&& =&position:left:0z-index:1;background:&;
  publicProgressBarHlayout() {
  Executions.createComponents(&/pages/common/progressBar.zul&,this,null);
  Selectors.wireVariables(this,this,
Selectors.newVariableResolvers(getClass(), Hlayout.class));
  Selectors.wireComponents(this,this,false);
  this.setSpacing(&0&);
  ………………
  publicvoidsetProgress(intprogress)
  progressDiv.setWidth(progress * (widthValue - ProgressBarHlayout.VALUE_LABEL_WIDTH) /100+&px&);
  this.setTooltiptext(progress +&%&);
  //&&&&&&& progeressValueLabel.setValue(progress + &%&);
  //&&&&&&& progeressValueLabel.setWidth(ProgressBarHlayout.VALUE_LABEL_WIDTH + &px&);
  //&&&&&&& progeressValueLabel.setStyle(&font-size:11px&);
  if(progress &=30) {
  progressDiv.setStyle(defaultStyle +&#CD3D38;&);
  }elseif(progress &=80)
  progressDiv.setStyle(defaultStyle +ECD4B;&);
  }else{
  progressDiv.setStyle(defaultStyle +&#CF9E25;&);
  对应的zul模板
  &!-- &label id=&progeressValueLabel& vflex=&true& /& --&
  &divid=&progressDiv&
  style=&position:left:0z-index:1;background:;&/&
  &divid=&grayDiv&style=&position:top:0left:0background:#D5CCBE;&/&
  声明:
  & componentname=&myImage&class=&XX.MyImage& &
  定义组件:
  public class MyImage extends Image implements AfterCompose {
  public void setMycontent(byte[] mycontent) {
  if (null!=mycontent) {
  this.setContent(new AImage(&t&, mycontent));
  } catch (IOException e) {
  e.printStackTrace();
  使用组件:
  &myImagemycontent=&@load(item.photo)&width=&300px&height=&300px&/&
15.3. include宏式自定义组件
  跟前面taglib风格正好相反,采用include方式,然后在被include页面里面就是正常的MVVM模式。
  优点是可以使用MVVM,适合于复杂页面;示例如下:
  使用方式就是include一个zul页面
  &includechartInfo=&@load(node)&hflex=&true&vflex=&true&width=&@load(node.boxWidthPx)&src=&@load('/pages/common/componentAbc.zul')&/&
  然后被include的页面componentAbc就是一个普通的MVVM页面,
  ViewModel实现如下(注意其中的init方法用来从外层页面传入参数):
  import
org.zkoss.bind.annotation.I
  ………………
  @VariableResolver(DelegatingVariableResolver.class)
  public
class ComponentAbc {
  publicvoidinit(@ExecutionArgParam(&chartInfo&)
IndicatorChartInfo chartInfo,
  @ExecutionArgParam(&maxMold&) Boolean maxMold) {
  this.chartInfo = chartI
  this.maxMold = maxM
  然后就没什么特别的了。
16. ZATS集成测试
16.1. ZATS概述
  ZATS是用来对ZK应用进行自动化功能测试的一套测试框架。
  Web应用的自动化功能测试非常重要(可以有效的保证发布质量,同时节省大量的手工回归测试成本),因此出现了很多相关技术框架和工具,
  最常用的的包括QTP、Selenium;
  但这些工具有两个致命的弱点:
运行缓慢:传统的测试工具都是跨进程通讯的,运行测试时需要起至少三个进程----AppServer、浏览器、测试框架本身的Server,导致运行缓慢、准备工作繁琐、容易出错;测试脚本不稳定容易出错:另外由于传统测试框架是针对系统最终界面(HTML)进行测试,测试用例与页面HTML高度耦合,为复杂页面编写的测试脚本也很复杂繁琐,而且页面稍有改动脚本就会出错,开发和维护成本都很高。
  这两个弱点严重制约了自动化测试的进行。
  相对于Selenium等测试框架,ZATS具有很大优势(当然这只限于ZK Web应用),它解决了传统自动化测试框架的两个最大软肋:
轻便快速:ZATS测试与被测页面运行在同一进程内,不需要起server和浏览器,运行起来方便快速,跟普通的JUnit单元测试基本没有区别;测试脚本稳定、可维护性好:ZATS是针对ZUL的测试,由于ZUL比最终生成的HTML要简洁的多(代码量大概只有10%),因此测试开发和维护成本很低,而且稳定;
16.2. ZATS典型测试案例
  首先扩展测试框架基类,以便在每个ZATS测试用例运行前做一些统一的准备工作,如下:
  protectedstaticZatsEnvironment&&&
  @BeforeClass
  publicstaticvoidinit() {
  env =newDefaultZatsEnvironment(&./zats&);//加载zats目录下的web.xml
  env.init(&./web&);
  @AfterClass
  publicstaticvoidend() {
  Zats.end();
  @After
  publicvoidafter() {
  Zats.cleanup();
  通常我们需要为ZATS准备一个简单的web.xml----例如这里可以去掉SpringSecurity等配置、加载测试专用的spring配置等;
  然后就可以扩展这个基类来开发真正的ZATS测试了,基本套路如下:
连接被测页面;定位要操作的组件;断言页面的变化或后台数据的变化;
  示例:
  import
java.util.L
  import
junit.framework.A
  import
org.apache.log4j.L
  import
org.junit.T
  import
org.zkoss.zats.mimic.C
  import
org.zkoss.ponentA
  import
org.zkoss.zats.mimic.DesktopA
  public
class HomeTest extendsBaseZatsTestCase {
  Logger&&& logger&&& = LoggerUtil.getLogger();
  publicvoidtestHome() {
  Client client = env.newClient();
  DesktopAgent desktop = client.connect(&/pages/home.zul&);//打开首页home.zul
  ComponentAgent mainTabsAgent = desktop.query(&#topWindow&).query(&#center&).query(&#mainTabbox&)
  .query(&#mainTabs&);
  logger.debug(mainTabsAgent);
  List&ComponentAgent& menuAgentList = desktop.queryAll(&tree treechildren treeitem treechildren treeitem&);
  logger.debug(menuAgentList.size());
  Assert.assertEquals(9, menuAgentList.size());
  menuAgentList.get(0).click();//点击打开west第一个菜单
  logger.debug(&mainTabsAgent size:&+ mainTabsAgent.getChildren().size());
  Assert.assertEquals(&mainTabsAgent包含tab个数&,2,
mainTabsAgent.getChildren().size());
  publicvoidtestProjectApply() {
  Client client = env.newClient();
  DesktopAgent desktop = client.connect(&/pages/projectCodeApply.zul&);
  ComponentAgent listboxAgent = desktop.query(&#dataListbox&);
  logger.debug(listboxAgent);
  Assert.assertNotNull(listboxAgent);
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&

参考资料

 

随机推荐