我的博客什么时候回来?
我的博客什么时候回来?
目极世间之色,耳极世间之音,身极世间之鲜,
口极世间之潭,思极世间之道,悟极世间之理。
因实行绩效主义,职工逐渐失去工作热情。在这种情况下是无法产生“激情集团”的……公司为统计业绩,花费了大量的精力和时间,而在真正的工作上却敷衍了事,出现了本末倒置的倾向
2006年索尼公司迎来了创业60年。过去它像钻石一样晶莹璀璨,而今却变得满身污垢、暗淡无光。因笔记本电脑锂电池着火事故,世界上使用索尼产锂电池的约960万台笔记本电脑被召回,估计更换电池的费用将达510亿日元。
PS3游戏机曾被视为索尼的“救星”,在上市当天就销售一空。但因为关键部件批量生产的速度跟不上,索尼被迫控制整机的生产数量。PS3是尖端产品,生产成本也很高,据说卖一台索尼就亏3.5万日元。索尼的销售部门预计,2007年3月进行年度结算时,游戏机部门的经营亏损将达2000亿日元。
多数人觉察到索尼不正常恐怕是在2003年春天。当时据索尼公布,一个季度就出现约1000亿日元的亏损。市场上甚至出现了“索尼冲击”,索尼公司股票连续两天跌停。坦率地说,作为索尼的旧员工,我当时也感到震惊。但回过头来仔细想想,从发生“索尼冲击”的两年前开始,公司内的气氛就已经不正常了。身心疲惫的职工急剧增加。回想起来,索尼是长期内不知不觉慢慢地退化的。
“激情集团”消失了
我是1964年以设计人员的身份进入索尼的。因半导体收音机和录音机的普及,索尼那时实现了奇迹般的发展。当时企业的规模还不是很大,但是“索尼神话”受到了社会的普遍关注。从进入公司到2006年离开公司,我在索尼愉快地送走了40年的岁月。
我46岁就当上了索尼公司的董事,后来成为常务董事。因此,对索尼近年来发生的事情,我感到自己也有很大责任。伟大的创业者井深大的影响为什么如今在索尼荡然无存了呢?索尼的辉煌时代与今天有什么区别呢?
首先,“激情集团”不存在了。所谓“激情集团”,是指我参与开发CD技术时期,公司那些不知疲倦、全身心投入开发的集体。在创业初期,这样的“激情集团”接连开发出了具有独创性的产品。索尼当初之所以能做到这一点,是因为有井深大的领导。
井深大最让人佩服的一点是,他能点燃技术开发人员心中之火,让他们变成为技术献身的“狂人”。在刚刚进入公司时,我曾和井深大进行激烈争论。井深大对新人并不是采取高压态度,他尊重我的意见。
为了不辜负他对我的信任,我当年也同样潜心于研发工作。比我进公司更早,也受到井深大影响的那些人,在井深大退出第一线后的很长一段时间,仍以井深大的作风影响着全公司。当这些人不在了,索尼也就开始逐渐衰败。
从事技术开发的团体进入开发的忘我状态时,就成了“激情集团”。要进入这种状态,其中最重要的条件就是“基于自发的动机”的行动。比如“想通过自己的努力开发机器人”,就是一种发自自身的冲动。
与此相反就是“外部的动机”,比如想赚钱、升职或出名,即想得到来自外部回报的心理状态。如果没有发自内心的热情,而是出于“想赚钱或升职”的世俗动机,那是无法成为“开发狂人”的。
“挑战精神”消失了
今天的索尼职工好象没有了自发的动机。为什么呢?我认为是因为实行了绩效主义。绩效主义就是:“业务成果和金钱报酬直接挂钩,职工是为了拿到更多报酬而努力工作。”如果外在的动机增强,那么自发的动机就会受到抑制。
如果总是说“你努力干我就给你加工资”,那么以工作为乐趣这种内在的意识就会受到抑制。从1995年左右开始,索尼公司逐渐实行绩效主义,成立了专门机构,制定非常详细的评价标准,并根据对每个人的评价确定报酬。
但是井深大的想法与绩效主义恰恰相反,他有一句口头禅:“工作的报酬是工作。”如果你干了件受到好评的工作,下次你还可以再干更好的工作。在井深大的时代,许多人为追求工作的乐趣而埋头苦干。
但是,因实行绩效主义,职工逐渐失去工作热情。在这种情况下是无法产生“激情集团”的。为衡量业绩,首先必须把各种工作要素量化。但是工作是无法简单量化的。公司为统计业绩,花费了大量的精力和时间,而在真正的工作上却敷衍了事,出现了本末倒置的倾向。
因为要考核业绩,几乎所有人都提出容易实现的低目标,可以说索尼精神的核心即“挑战精神”消失了。因实行绩效主义,索尼公司内追求眼前利益的风气蔓延。这样一来,短期内难见效益的工作,比如产品质量检验以及“老化处理”工序都受到轻视。
“老化处理”是保证电池质量的工序之一。电池制造出来之后不能立刻出厂,需要放置一段时间,再通过检查剔出不合格产品。这就是“老化处理”。至于“老化处理”程序上的问题是否是上面提到的锂电池着火事故的直接原因,现在尚无法下结论。但我想指出的是,不管是什么样的企业,只要实行绩效主义,一些扎实细致的工作就容易被忽视。
索尼公司不仅对每个人进行考核,还对每个业务部门进行经济考核,由此决定整个业务部门的报酬。最后导致的结果是,业务部门相互拆台,都想方设法从公司的整体利益中为本部门多捞取好处。
团队精神消失了
2004年2月底,我在美国见到了“涌流理论”的代表人物奇凯岑特米哈伊教授,并聆听了他的讲演。讲演一开始,大屏幕上放映的一段话是我自进入索尼公司以来多次读过的,只不过被译成了英文。
“建立公司的目的:建设理想的工厂,在这个工厂里,应该有自由、豁达、愉快的气氛,让每个认真工作的技术人员最大限度地发挥技能。”这正是索尼公司的创立宗旨。索尼公司失去活力,就是因为实行了绩效主义。
没有想到,我是在绩效主义的发源地美国,聆听用索尼的创建宗旨来否定绩效主义的“涌流理论”。这使我深受触动。绩效主义企图把人的能力量化,以此做出客观、公正的评价。但我认为事实上做不到。它的最大弊端是搞坏了公司内的气氛。上司不把部下当有感情的人看待,而是一切都看指标、用“评价的目光”审视部下。
不久前我在整理藏书时翻出一封信。那是我为开发天线到东北大学进修时,给上司写信打的草稿。有一次我逃学跑去滑雪,刚好赶上索尼公司的部长来学校视察。我写那封信是为了向部长道歉。
实际上,在我身上不止一次发生过那类事情,但我从来没有受到上司的斥责。上司相信,虽然我贪玩,但对研究工作非常认真。当时我的上司不是用“评价的眼光”看我,而是把我当成自己的孩子。对企业员工来说,需要的就是这种温情和信任。
过去在一些日本企业,即便部下做得有点出格,上司也不那么苛求,工作失败了也敢于为部下承担责任。另一方面,尽管部下在喝酒的时候说上司的坏话,但在实际工作中仍非常支持上司。后来强化了管理,实行了看上去很合理的评价制度。于是大家都极力逃避责任。这样一来就不可能有团队精神。
创新先锋沦为落伍者
不单索尼,现在许多公司都花费大量人力物力引进评价体制。但这些企业的业绩似乎都在下滑。
索尼公司是最早引进美国式合理主义经营理论的企业之一。而公司创始人井深大的经营理念谈不上所谓“合理”。1968年10月上市的单枪三束彩色显像管电视机的开发,就是最有代表性的例子。
当时索尼在电视机的市场竞争中处于劣势,几乎到了破产的边缘。即便如此,井深大仍坚持独自开发单枪三束彩色显像管电视机。这种彩色电视机画质好,一上市就大受好评。其后30 年,这种电视机的销售一直是索尼公司的主要收入来源。
但是,“干别人不干的事情”这种追求独自开发的精神,恐怕不符合今天只看收益的企业管理理论。索尼当时如果采用和其他公司一样的技术,立刻就可以在市场上销售自己的产品,当初也许就不会有破产的担心了。
投入巨额费用和很多时间进行的技术开发取得成功后,为了制造产品,还需要有更大规模的设备投资,亦需要招募新员工。但是,从长期角度看,索尼公司积累了技术,培养了技术人员。此外,人们都认为“索尼是追求独特技术的公司”,大大提升了索尼的品牌形象。
更重要的是,这种独自开发能给索尼员工带来荣誉感,他们都为自己是“最尖端企业的一员”而感到骄傲。单枪三束彩色显像管电视机之所以能长期成为索尼公司的收入来源,是因为技术开发人员怀着荣誉感和极大热情,不断对技术进行改良。
具有讽刺意味的是,因单枪三束彩色显像管电视机获得成功而沾沾自喜的索尼,却在液晶和等离子薄型电视机的开发方面落后了。实际上,井深大曾说过:“我们必须自己开发出让单枪三束彩色显像管成为落伍产品的新技术。”包括我自己在内的索尼公司高管没有铭记井深大的话。
如今,索尼采取了极为“合理的”经营方针。不是自己开发新技术,而是同三星公司合作,建立了液晶显示屏制造公司。由这家合资公司提供零部件生产的液晶电视机“BRAVIA”非常畅销,从而使索尼公司暂时摆脱了困境。但对于我这个熟悉索尼成长史的人来说,总不免有一种怀旧感,因为索尼现在在基础开发能力方面,与井深大时代相比存在很大差距。今天的索尼为避免危机采取了临时抱佛脚的做法。
高层主管是关键
今天的索尼与井深大时代的最大区别是什么呢?那就是在“自豪感”方面的差别。当年创始人井深大和公司员工都有一种自信心:努力争先,创造历史。
当时索尼并不在意其他公司在开发什么产品。某大家电公司的产品曾被嘲讽为“照猫画虎”,今天索尼也开始照猫画虎了。一味地左顾右盼,无法走在时代的前头。
在我开发“爱宝”机器狗的时候,索尼的实力已经开始衰落了,公司不得不采取冒险一搏的做法,但是出现亏损后,又遭到公司内部的批评,结果不得不后退。
今天的索尼已经没有了向新目标挑战的“体力”,同时也失去了把新技术拿出来让社会检验的胆识。在导致索尼受挫的几个因素中,公司最高领导人的态度是其中最根本的原因。
在索尼充满活力、蓬勃发展的时期,公司内流行这样的说法:“如果你真的有了新点子,来。”也就是说那就背着上司把它搞出,与其口头上说说,不如拿出真东西来更直接。但是如果上司总是以冷漠的、“评价的眼光”来看自己,恐怕没有人愿意背着上司干事情,那是自找麻烦。如果人们没有自己受到信任的意识,也就不会向新的更高的目标发起挑战了。在过去,有些索尼员工根本不畏惧上司的权威,上司也欣赏和信任这样的部下。
所以,能否让职工热情焕发,关键要看最高领导人的姿态。索尼当年之所以取得被视为“神话”的业绩,也正是因为有井深大。但是,井深大的经营理念没有系统化,也没有被继承下来。也许是因为井深大当时并没有意识到自已经营理念的重要性。
我尝试着把井深大等前辈的经营理念系统化、文字化,出版了《经营革命》一书。在这本书中,我把井深大等人的经营称为“长老型经营”。所谓“长老”是指德高望重的人。德高望重者为公司的最高领导人,整个集团会拧成一股绳,充满斗志地向目标迈进。
在今天的日本企业中,患抑郁症等疾病的人越来越多。这是因为公司内有不称职的上司,推行的是不负责任的合理主义经营方式,给职工带来了苦恼。
不论是在什么时代,也不论是在哪个国家,企业都应该注重员工的主观能动性。这也正是索尼在创立公司的宗旨中强调的“自由,豁达,愉快”。
过去人们都把索尼称为“21世纪型企业”。具有讽刺意味的是,进入21世纪后,索尼反而退化成了“20世纪型企业”。我殷切希望索尼能重现往日辉煌。
按理说,这也不是什么新的话题。中国进入市场经济已经十几年了,进入世贸组织也三四年了,随着国内市场的国际化进程,这个问题应该迎刃而解了。但是,令人意外的是,不少中小企业还是徘徊在投机生意的怪圈中,迄今都痴迷不悟。最终“死”了都不知道怎么“死”的,总觉得没有抓住机会,总抱怨国家的不支持力度还不够。
市场环境在变,竞争格局在变,商业规则在变。在这个变革的世界里,中国中小型企业也应该变了。因为,今天的市场环境留给我们的机会已经不多了。
奶粉事件意味着什么
2004年4月,对中国奶粉行业来讲是个非同寻常的月份,也是整个行业发生历史性变革的月份。安徽阜阳婴儿奶粉事件掀起了全国范围严打劣质奶粉热潮,很多中小企业,甚至个别大企业产品都被媒体纷纷曝光,同时从货架上屡屡被撤下来。
事件的调查和处理过程,迄今都没有停下来,国家领导人也对此事件表示高度关注,由国家食品药品监督管理局、公安部、监察部、卫生部、商务部、质检总局、工商总局等部门参加的国务院联合调查组奔赴阜阳,继续对阜阳“劣质奶粉”一案展开深入调查。
很多传媒也都对此事展开了广泛评论。矛头更多聚焦在政府的监管力度不够、厂家的责任心太差、中间商的利益驱动等等。然而,我对此事件有个不同的看法。
我们可以仔细观察此事件,凡是心惊肉跳、忐忑不安的都是那些中小品牌。像伊利、雀巢、美赞臣等国内外大品牌却没有受到太大影响。反而,把事件当作抢占市场的机会来看待。那我们就应该思考了,这个事件到底意味着什么?
如果从供给与消费的角度来思考就会明白。此事件实际上是在穷人和穷人间发生的悲剧。从厂家的角度看,那些小厂家穷,眼下就要死掉了,于是就瞄准国家法律、法规的薄弱之处,搞出那些赚钱的把戏;从消费者角度看,其实大家都明白“一分钱一分货”的概念,但那些劣质奶粉便宜得都让人吃惊的地步,居然还有人买,为什么?再说,阜阳的消费者并不是没有机会购买大品牌奶粉,但为什么恰恰选择劣质奶粉呢?原因是穷。另外,从商家的角度看,正因为穷,所以贪图更大利润而偏偏代理那些劣质奶粉。有人为了生存而做“假”,有人贪图便宜而买“假”,还有人为了发财而售“假”,这样的“一脉相承”难道不发生悲剧吗?
国家的法律、法规是创造良好社会秩序的根本保障,但光有“警察”不行,“小偷”也要自律。这里所说的“自律”就是指那些中小企业需要建立品牌意识,按照市场经济的游戏规则做事。
不少企业一提品牌,就觉得离他很远,于是天天钻进“投机生意”的死胡同里,最后没赚到钱不说,把命也贴进去了,值吗?此次奶粉事件就意味着那些企业严重缺乏品牌意识、自律意识和持续赢利意识。
通过这场悲剧,消费者倒是有了“血”的教训,从此再也不买小品牌产品了,但中国有那么多中小企业该怎么办?生存还是消亡?维持还是发展?在命运的十字路上应如何抉择呢?在此本人建议一条出路,就是脚踏实地的实施品牌战略。在国内市场国际化的大趋势下,这可能是中国中小型企业“最后一顿晚餐”了。
几句致命的商业神话
美国一位管理学家曾说过,企业最初的形态是一种想法。他还说,企业的发展实质上是一种想法的发展。说得确实有道理。但是,企业在发展过程中经常遭遇各种各样的观念骚扰。尤其是那些商业神话,有时候,专家都觉得有道理。但仔细一琢磨就会明白,那些神话对企业发展有着致命的误导作用。下面我们来揭示几句:
1、“企业没有今天就没有明天”
听上去多有道理。地球自转一圈,我们把它定义为一天;绕太阳转一圈,我们把它定义为一年。从这个时间序列上看,确实是没有今天就没有明天,不可逾越。但将这种说法套到企业,就不一定带来好的结果。因为,很容易误导企业注重眼前利益,从而忽视长远发展,尤其是对中小企业危害更大。
我在伊利任全国市场总监的时候,经常走访市场。记得在2001年夏天,我去四川某市,和当地经销商访谈时,这位朋友跟我说:“现在你们这些大品牌都在天上飞,反而那些小品牌在地上跑”。意思是,大企业就知道做广告、新品研发等无聊的事情,而那些小企业却紧紧抓住通路建设,一步一个胶印地发展。当时,我不知道怎么回应好,只说了一句“各有特色吧”。其实,我知道他们认为解决“今天”问题最好的企业是山东一家奶粉品牌。这家企业为了调动中间商的积极性,将通路利润放大到极至。当时经销商给我算了一笔帐:卖这个品牌奶粉200箱相当于卖伊利奶粉2500箱。这是多么诱人的生意啊!正因为这样,这个品牌的奶粉很快就铺开了通路。货倒是挤进经销商的仓库了,“明天”会怎样呢?时隔一年,到2002年下半年时这家企业却遭遇了全国范围的大量退货,从此就失去了“明天”。
现在我们再反过来冷静审视那些“地上跑”的企业,有几个跑下来了?解决“今天”的那些企业拥有“明天”了吗?很显然,事情没那么简单。当时伊利也有能力那么做,但问题是不能那么做。
2、“先培育市场后获取利润”
有这样观点的企业喜欢举跨国公司的例子。雀巢在中国赔了多少年,柯达在印度赔了多少年等等。意思是赚钱不着急,先把市场占住了再说。
其实,这些企业忽略了两个很重要的概念:一是大企业与小企业的概念,一是渗透率与忠诚度的概念。
先来看第一个。我们把自己和人家相提并论的时候,最好看看我们有多大。再说,你看过人家的财务报表吗?有些跨国公司进入别国市场时确实有过一段不赢利的过程,但这是战略性亏损,目的很明确,就是把本土的“小弟兄”们全部端出市场。比如70年代柯达打印度市场就是典型案例。这么做必须有两个条件:第一,规模足够大,有成本优势;第二,市场集中度较高,处于有序竞争阶段。否则没有用的。中国中小型企业哪儿来的规模,绝大部分行业哪儿来的集中度,在这种市场上这么做不是找死吗?
再来看第二个。市场份额的大小基本取决于两个因素的影响:渗透率和忠诚度。渗透率衡量消费者的尝试情况,忠诚度衡量消费者的重复消费情况。你可以牺牲利润来做市场,但你必须清楚你的销量是靠渗透率来达成,还是靠忠诚度来达成。如果靠忠诚度来达成,且忠诚度达到了80%以上,可以说你前期的亏损是值得的;如果只有渗透率没有忠诚度,你就惨了,可能你的亏损将会无济于事。
况且,现在的竞争这么激烈,多家企业都虎视眈眈地盯住你的市场,培育后的市场是否一定属于你,基本没有因果关系。所以,连产品都没做出来就开始打广告,未免太天真了。
3、“小马拉大车”
这句话的意思是:品牌虽小,手笔可大,可借助大品牌的运作方法,玩儿大手笔,获取大回报。
这个观点,看上去明显缺乏市场细分的概念。“小马拉大车”,说的就是瞄准主流市场。但是,我们可以想想,在主流市场上真正留下来的品牌有几个?当年的彩电、VCD、矿泉水、茶饮料、果汁和现在的牛奶,冷静观察就知道,真正留下来的都是那些前3-5名的企业,剩下的基本都不见了。那么,当时在那些市场上活跃一时的那么多“小马”都哪儿去了?在实际运作中,小马拉大车,总有一天会“累死”的。因为从游戏规则的角度看,应该大企业做大市场,小企业做小市场。如果违背这个原则,要么就“饿死”,要么就“撑死”。那些“小马”肯定是“撑死”了呗!
有人会问,那小企业就不能做大市场吗?照你这么说,小企业永远是小企业,没有发展可言了吗?我的答案是可以。但是,必须遵循游戏规则,根据你企业目前规模和资源来判断,到底怎么走。一般的步骤是:企业过小的时候最好在一个细分市场上把它做透了;然后再看机会追随大企业;追随成功了、实力到了一定程度了,就可以挑战行业老大。当时的蒙牛就是这么干的。但你规模还不到1000万的时候就去挑战100亿的大企业,显然是以卵击石,肯定会一败涂地。
所以,我敬告广大的中小企业老总,“小马”就要拉“小车”,千万不要让你的“小马”去拉“大车”,太危险了。
4、“只有淡季思想,没有淡季产品”
天哪!怎么会这么想问题呢?这种想法是否有点像“法轮大法”?你可以没有淡季产品,但消费者的需求是客观存在的。冬天就是不喜欢喝冰镇的矿泉水,夏天就是不喜欢喝滚烫的二锅头。这就是规律。
有这种想法的企业家,一般难以看下去淡季的销售报表,心理总觉得压力挺大。所以就冥思苦想,怎能把淡季销量做上去。于是就在淡季大做大量的通路促销,还起个非常别致的名字叫“屯仓”。
百搭三、百搭五,甚至百搭十,颇具吸引力的通路政策就出去了。因为白送,谁想不要?于是,货也就出库了,报表也好看了。但这只是一种库存转移,并不等于销售。因此,真正到旺季的时候,这些产品日期却不新鲜了,经销商库里的货就卖不出去了,新的产品也没法再生产了,窜货也开始了,价格也乱套了。于是,这些“没有淡季产品”的企业便迎来了新一轮烦恼,即旺季不旺。最后一想,真正占便宜的都是那些经销商,而企业只能“吃不了兜着走”。
对中小企业来讲,资源相当有限,生存的压力也相当迫切。因此不要胡作非为,浪费你的资源。那些资源,对大企业来讲可能是“小雨点”,但对小企业来讲却是意味着生死存亡。我记得,有家冰淇淋大企业曾经试图开发冬天吃的冰淇淋,还叫做“火锅冰淇淋”,后来也没有成功。但这对他而言是小意思,错就错了,影响不会太大。但对小企业来讲就不一样了。因此,一定要慎重。
5、“销量是检验品牌的唯一标准”
这句话明显是抄袭“实践是检验真理的唯一标准”而来的。意思是你谈品牌就得看销量,销量上不去,品牌就无从谈起。听上去有点道理。销量确实是衡量一个品牌成功与否的重要指标。但是,我们再往深想一下,难道销量的大小就完全代表一个品牌的生命力吗?我们可以回顾一下,中国许多行业,销量大的品牌倒下去的例子还少吗?从秦池、三株、飞龙开始到现在,有多少大企业倒掉了?可谓数不胜数。那我们可以思考了,那些销量非常大的企业为什么会死掉?不说“销量是检验品牌的唯一标准”吗?
恰恰相反,可口可乐一位历任CEO评价其品牌时这样说过,可能大家也都知道:“假如我们可口可乐全球的生产厂一夜间被烧光了,只要有我们的品牌在,3年以后同样是现在的可口可乐”。国内哪个品牌敢这样喊呢?秦池敢吗?三株敢吗?
现在,很多传媒对脑白金的评价,从批评的极端正在走向赞扬的极端。说,脑白金的广告虽然俗点儿,但销量却不断上涨。因此,他们得到的结论是“销量说明一切”。但我们可以假设,脑白金这个品牌在美国保健品市场上这么操作会成功吗?肯定不行。这就说明,中国保健品市场透明度不高的特殊性造就了脑白金,而不仅是脑白金,也造就了很多其它品牌。但我们再想一下,脑白金如果再搞出一个新产品投放市场,还能这么火吗?谁敢说这个答案呢?因为黄金搭档就会让人看出一些眉目来。
因此,销量并不是衡量一个品牌的唯一标准,除了销量以外还有让消费者持续购买、连贯购买和推荐购买的能力以及企业创新能力、组织能力和抗风险能力等都是衡量一个品牌健康发展的重要指标。
6、“存在就是合理的”
表面上,真不错!但实际上这是一些人为了维护个人利益而提出的歪理邪说。这句话给企业带来的最大后果是什么?对错误行为找到一种解脱,并让这些错误继续蔓延下去。这次奶粉事件就是典型的案例。有需求就要满足吗?那些没有树立正确消费观的农民是企业、政府和媒体需要共同引导的,而不是利用他们的“无知”来骗取钱财。如果一个企业连这种品牌精神都没有,打造百年老店是绝对一句空话。
在现实生活中,不合理的“存在”很多。诸如“存在”的贫困、“存在”的污染、“存在”的犯罪、“存在”的欺骗、“存在”的仇恨、“存在”的失败、“存在”的错误、“存在”的短命等等。如果我们都去容忍这些“存在”,这个世界还有发展可言吗?强调“存在就是合理”的人总喜欢用恐龙和老鼠来证明。说,恐龙为什么从地球上消失?是因为他们失去了存在的合理性;而老鼠为什么迄今不灭亡?而且保持旺盛的胜利力,是因为他们仍然具备着存在的合理性。听上去多么好的解释呀?但这些风马牛不相及的例子能说明企业生存的道理吗?在这次奶粉事件中,那些“存在”的、“合理”的厂商还不像老鼠一样被消灭吗?
因此,“存在”不一定都是合理的,做企业一定要改进那些不合理的“存在”,解决那些不合理的“问题”,而不能为了短期利益,睁一只眼闭一只眼,容忍或掩盖那些致命的错误。
中小企业应如何实施品牌战略
不管怎么说,在死亡边上挣扎的中国中小型企业,大品牌梦想和大生意渴望还是有的。但有趣的是,一直解决不了一个矛盾,即短期与长期的矛盾。这些企业既想成为大品牌,又不想在品牌方面投入,总用“投机”的方法来求生。这可能与中国传统的“小农”意识有关。比如在这次奶粉事件中被封杀的规模相对比较大的企业,有些还是受当地政府所重视的企业。但为什么这次事件中遭遇如此命运呢?答案是:做企业的思路和方法不对。
那么,中国中小型企业到底应该怎么做?怎么实施品牌战略?又如何建立使企业更加长命的优势?这里本人建议做好两件事情:一是转变观念,一是掌握规则。转变观念是指那些企业必须从那些商业神话中解脱出来,用正常的思维和系统的观点来看问题;掌握规则却指的是要掌握品牌发展的潜在规律。对于转变观念,我不想多说,下面就如何掌握品牌创建规则方面谈谈我的观点。
麻雀随小五脏具全。我觉得,这句话再适合不过中小企业了。企业虽小,该做的事情要做,该建立的职能也要建立。说得再正规点,中小企业要实施品牌战略时,必须遵循品牌经营的游戏规则,从战略的规划到实施必须有良好的监督与管理机制。当然,这并不是误导大家像大企业或跨国公司那样运作,而提倡的是,不管做什么必须有个尺度,不能走入任何极端。有些人可能认为,小企业不需要战略。但我不同意这个观点。小企业当然没有必要邀请麦肯锡、罗兰贝格做战略规划,但企业老板必须有个“头绪”,也就是说,企业应往哪个方向发展、整合哪部分资源、营造什么样的优势、以什么样的方法来支撑企业持续赚钱等等。如果老板们连这些问题都不考虑,那中小企业确实无可救药了。
实施品牌战略方面本人提倡的一种方法是均衡原则。就像中国古代的八卦图那样,讲究阴阳均衡。既不能阴盛阳衰,也不能阳盛阴衰。下面推荐五种具体原则:
1、品牌规划与品牌传播要均衡
纵观中国企业发展史,不少企业都是“吹牛皮”吹出来的。只不过,当时的市场环境不透明,消费者不知道他们“吹牛”而已。但是,现在不一样了,随着人们生活水平和消费意识的提高,消费者判断能力也空前提升,光靠“吹牛”肯定无法生存下去了。再说,不管什么时代,我们都不能提倡这种做法。因此,一定要做到品牌规划和品牌传播行为的均衡性和匹配性。
品牌规划实际上是品牌战略的制定部分,一定要实事求是,充分考虑市场需求、竞争强度和自身资源来制定;品牌传播则是品牌战略的实施部分,要与规划保持一致,所有行为都要围绕品牌规划来展开。
举个经典的汽车案例。富豪汽车的品牌定位是安全,这谁都知道。但大家有所不知的是他们为了完成这个使命而所做的努力。今年富豪新推出了S80系列轿车,为了做到安全,车内共设置了27个安全气囊。这是在其它品牌汽车上是不可思议的事情。
再举个国内企业的案例。创维电视大家都知道,一直提倡保护视力的概念。他们有句广告语可能迄今还在用,即“不闪的才是健康的”。为了更进一步传播这个概念,他们今年组织开展了“创维健康光明行”活动,专门资助失明儿童,在全国欠发达地区治好不少患白内障的儿童,回复其视力。
这两个案例可以说明,企业一定要说什么,就要做什么。说得大,做的也要大,千万不要像那些劣质奶粉厂商那样,说的是一套,做的又是一套。
2、动机利益和差别利益要均衡
动机利益指的是消费者从你产品(或服务)上所获得的根本利益。如产品(或服务)质量、功能、技术含量等。差别利益则是消费者从你产品(或服务)上所获得的有别于其它品牌的特殊利益。如刚刚提到的富豪轿车的安全利益。从品牌战略的角度看,这两种利益也要均衡。就是说,你不能光有动机利益,没有差别利益;也不能光有差别利益,没有动机利益。举两个极端例子:我们日常所消费的米、面、酱油、醋等虽然有了一些品牌,却一直强调动机利益,忽略了差别利益;而每年中秋节各厂家所推出的月饼却是另一个极端,只注重差别利益,而严重忽视了动机利益。
在实战中,如果你产品动机利益过大于差别利益,你就缺乏比较优势;如果你产品差别利益过大于动机利益,则缺乏基本优势。因为,动机利益一般是你产品立足于这个市场的根本保证,差别利益则是你产品的独特卖点。所以这两个利益的均衡性是一个品牌健康发展的基础。
3、理性诉求和感性诉求要均衡
在品牌传播活动中,很多企业往往误入“宣传产品性能”的死胡同中,最后品牌失去消费者心目中的位置,只是成为消费者物质生活上的必须品,在其情感生活中基本没有地位。当同等性能的其它品牌产品出现时,非常容易被消费者抛弃。
目前很多药物品牌就是典型的例子。假如你和消费者沟通时,只注重消炎利胆的功能,而并没有别的沟通方式,就会导致另一个厂家推出同样性能的药物时消费者就会更换品牌。但是,你和消费者沟通的时候,既强调这个药物的消炎利胆之功效,也提倡一种健康生活的主张以及鲜明的性格,消费者也许就不会那么轻易的转换品牌了。为了证明这一点,再举个经典汽车案例。假如你是个富翁,很喜欢驾驶汽车,并喜欢刺激,岁数虽大,却有着一定的童真性格。那么你买车并选择奔驰和宝马时,我敢肯定你会选择宝马。因为,虽然同档次的奔驰和宝马在性能上没有太大区别,但奔驰所提倡的感性诉求不适合你。
所以,本人建议,不管你是做什么的,一定要在你品牌传播上注重理性和感性诉求的均衡性,不要走任何极端。
4、可变因素和不变因素要均衡
这也是企业经常犯的错误。而且很多企业分不清自己品牌的可变因素是什么,不变因素又是什么。从此,一个好端端的品牌就会误入歧途。
那么,什么是品牌的可变因素和不变因素?一般是品牌传播层面的东西,我们把它定义为品牌的可变因素,如新产品开发、功能升级、卖点更新、代言人更换等;而品牌的不变因素则是战略层面的东西,即品牌定位、品牌诉求、品牌性格、LOGO、基础颜色以及ICON等。这方面的案例实在是太多了。诸如,百事可乐产品包装不断更换,形象代言人也不断更换,但其“新生代选择”的定位始终没变;柯达几乎每两个月推出新产品或新包装,但其黄色的基调始终没变,“精彩、纯真”的诉求也始终没变;麦当劳在全球不断推出适合当地人口味的新产品,但其“快乐”的诉求始终没变等等。在品牌经营活动中,品牌的可变因素和不变因素一定要均衡。这是一个品牌健康发展的最好捷径。
中国不少企业都很注重视觉形象,从而搞出一套漂亮的VI手册。但是,产品几年不变,甚至几十年不变;连广告片都几年不变。消费者又不是傻子,其实我们也不是傻子,仔细琢磨就会明白,光有漂亮的视觉形象,没有产品和传播策略上的创新,是没有用的。可能有些人会提问:你说产品要更新,但可口可乐的配方怎么几十年不变呢?是的,可口可乐的配方确实没变。因为,它的配方是它经典的象征,所以不能变。但它的包装却年年在变,且在不同的国家变化的方法也不同。
掌握品牌因素的变与不变时,还要注意以下尺度,即品牌的细分市场特征、时代感和差异性。因为,这三点基本决定了一个品牌的持续生存能力。
5、品牌目标和企业资源要均衡
在中国,喊出“打造第一”的企业比比皆是,而喊“我是唯一”的企业却屈指可数。比如,早期的海尔喊出“中国家电第一品牌”,现在的伊利喊出“打造中国乳业第一品牌”等。然而,在一个细分市场上成为唯一的品牌几乎不见,近些年虽然有些企业开始探索,比如雅克V9等,但不突出,也不成熟。
我们看一下中国各行各业的集中度,难道中国企业的唯一出路是要做“第一”吗?中国大多数行业基本处于无序竞争状态,行业集中度极低。这就说明,中小企业占多数。试想一下,那么多的企业都走“第一”的路子会怎样呢?不用多说,当年的VCD大战就会说明一切。
因此,本人建议,尤其建议中小企业,一定要合理确定你的品牌发展目标,不要老眼高手低。一般的原则是,你有什么样的资源,就做什么样的事情,且确定什么样的目标。但有人会问,我这个企业什么资源优势都没有,但我就是想把企业做大,怎么办?我先讲个小故事,然后再回答这个问题。
有一天,天使降临人间,遇到两位濒临饿死的兄弟。天使出于慈悲之心,给这兄弟俩以两件东西:一条大鱼和一张渔网。兄弟俩虽然嫌少,但毕竟是救命之恩,表示感谢。接下来,兄弟俩就琢磨,怎么分配天使恩赐的这份礼物。假如一个要鱼,一个要渔网,可能出现的后果是:一个吃完鱼,没有钓鱼的工具,最终也会饿死;另一个带着渔网去找鱼,但短时间找不到鱼也会饿死。怎么办?兄弟俩想出一个合作的办法:先两个人分着吃鱼,然后一起去钓鱼。
这个故事说明什么呢?说明一个企业在资源相当有限的时候,一定要懂得怎能更加有效地利用资源。也就是说,你企业的资源不足以单打独斗的时候,就要懂得和别人联合,探索出“1+1>2”的模式。
所以,中国企业,尤其中小型企业要制定品牌目标时,一定要制定一套你可能实现的目标,不能在商业神话中所提的那样“小马拉大车”。并且,在你企业资源难以建立竞争优势的时候就要和别人联盟。这就是对刚才那个问题的回答。
2006年岁末之际,CMM/CMMI行业有两件事值得关注
一是SEPG中国大会在苏州“成功”召开,此次会议由于有SEI和苏州政府联合领衔,规格自然不在话下,各路人马云集苏州,好不热闹,会上发布消息——据统计,目前中国软件业在CMMI的运用上,排名世界第四(如果不是前两年部分政府补贴只给CMM而不给CMMI,这个排名相信还会靠前)。截止2006年3月,在中国已经进行了110多次的CMMI评估...
第二个消息是中国商务部制定了一个“千百十工程”(据说具体操作会由信息产业部来负责,相关细节可查询中国商务部网站),其中内容包括“力争五年内促进700家企业取得CMM/CMMI3级认证,300家企业取得CMM/CMMI5级认证” ,并且对这些企业提供最高不超过100万的资金补贴(中央财政50万+地方配套50万)
这无疑是给了真在高歌猛进的中国CMM/CMMI认证事业(实际上CMM/CMMI并不是认证而仅仅是评审,但在中国现在已经是一项彻头彻尾的认证事业了)又注入了一剂强心针,显然,我们国家的评估次数和排名有会有一个质的飞跃,然而,在这些数字的大跃进背后是我们现实的CMM/CMMI实施中面对的众多尖锐而不可回避的问题,试举如下:
前期过程改进需求分析不到位导致目的和结果的南辕北辙
过程改进和软件开发一样,前期的需求分析是否到位可以说很大程度上决定了项目的成败,CMM/CMMI的前期分析过程叫作"Gap Analysis"(差异分析或差距分析),目前国内咨询公司给出的CMM/CMMI咨询方案中比较典型的差距分析过程包括:2天的文档审查,2天的访谈和一天的编写报告。很显然,对于软件开发这样一个复杂的系统工程来说,短短3-5天的时间可能可以得出表明上的“差距”在哪里,但其实并不能真正了解导致这些“差距”产生的深层次的原因在哪里,而以简单量化的形式得出的差距分析报告(其主要内容是一张根据PA罗列了CMMI中所有SP的Excel大表格)更不能全面反映它们相互之间的各种约束关系。而整个CMM/CMMI过程改进就在这种头疼医头,脚疼医脚的表面文章中展开了。
一个软件企业过程改进的需求和CMM/CMMI的要求之间并不能划等号,所谓“种刮得瓜,种豆得豆”,前期机械的按照CMM/CMMI的PA来分析企业的过程改进需求,最终得到的结果往往和企业实际的情况相差甚远。
缺乏可操作的方法和有效的技术手段
再好的理论也是需要有效的方法来实现的,虽然我们可供选择的方法并不在少数,但这些方法在实际环境中的可操作性以及是否拥有有效的技术支撑手段手段,却是众多企业面对的一大难题。以下是软件企业经常会碰到的一些问题:
他们通常被告知需要根据员工的日志对项目任务的完成状态进行同步更新,以便随时能够根据项目进展提供一张漂亮的跟踪甘特图。但在缺乏有效工具平台(大多数企业并没有部署MS Project服务器版本)的情况下,QA们(或PM们)只能痛苦的埋头于一堆Excel日志表格和计划MPP中,重复着这种低级而极易犯错的工作——显然这种坚持并不能持久的
他们通常被告知需要从需求、设计、编码一直到测试建立有效的双向跟踪,但他们从咨询方获得的通常仅仅是一张由Excel编制的需求跟踪矩阵模板。鉴于需求之间的关联性和版本衍生导致的复杂性,我想我们用脚趾头都能想明白,任何一个稍具规模的应用的需求跟踪都是不可能仅用一张Excel表格来做到的。
他们通常被告知要在有效估算的前题下编制计划,并被推荐使用某个相对成熟的估算技术——如功能点,但是我们的估算人员要面对的往往是庞大而复杂的功能结构分解和有限的时间,在这种情况下即便是借助一些简单的工具也需要付出巨大的工作量,而如果是纯手工作业则基本上没有现实的可操作性。于是最终往往只能退而求其次选择一些基于经验的估算方法——如Delphi法,而Delphi法的应用在缺乏经验和有效约束的情况下最终慢慢变成了流于形式的“拍脑袋”——一切又重新回到了起点[/list]
虽然从国际知名厂商到国内一些企业都提供大量的过程管理工具,但工具作为一种辅助手段,其选型、部署、集成和使用都需要根据企业的实际情况做大量的工作,而这项工作,我们在大多数公司给出的咨询方案中却几乎看不到。
有效约束机制的缺位
光靠一堆文档建立起来的过程是很难被有效执行的,尤其是在中国,技术人员跳槽和岗位变换的频繁度远高于西方的软件企业,约束机制的缺位往往导致已经被定义好过程难以被有效的执行,并随着时间的推移逐渐放弃越来越多的已定以过程——企业拿到证书后,过程慢慢几乎又回到原点的案例并不在少数——换句话说,CMM/CMMI评审以前,是过程改进,评审以后则是过程倒退,这和过程改进的初衷是完全背道而驰的。
因此,如果没有可靠而有效的约束机制,定义得再好的过程最终也难免沦为一堆尘封的旧文件,而约束手段的建立必须从两个方面入手——管理制度的完善和有效技术手段的应用,而这也很少能在众多公司给出的方案中看到。
总结:
笔者粗略的算了一下,要完全兑现这个“千百十工程”中的CMM/CMMI补贴,中央财政加上地方政府的配套资金,大致要花掉7个亿左右的资金,如此巨大的资金对于整个CMM/CMMI行业来说无疑是天上掉下了的一块肥肉,然而,当我们准备举杯狂欢之际,是不是应该考虑除了不断窜升的数字之外还应该给整个中国软件产业多留下点什么,要不然某一天,整个中国软件行业的CMM/CMMI评估也许真的会被贴上一个“赝品”的标签——这应该不是危言耸听。
准备篇
1。白板(白板笔)。
1)需求阶段和客户讨论问题时分析、设计、客户在这里自由交流大家对问题的看法
2)在项目分析和设计阶段用来进行头脑风暴,是设计的最重要的工具。白板上画的可以是UML图,但也可以是项目团队能够理解的任意图形,或者就是简单的线条、图形都可以
3)无处不在的讨论,任何时候对需求的理解和对设计的讨论都在白板上进行
一般公司里面经常会出现白板笔太久没用水用光的时候,所以我一般都要提醒后勤人员买好充足的笔,用完笔以后要盖好盖子。
2卡片(和图钉)
1) CRC是除了白板以外第二重要的设计工具,这种卡片在中国很难买到,所以一般用文摘卡代替,CRC的重要作用在于可以进行角色扮演,验证设计的准确性。CRC的前面分别写责任和协作,背面可以进行备注
2) 用户故事卡,我回去定制一个泥印,直接盖在空白的用户故事卡上,这个卡片在需求阶段可以任意传递、撕毁、重写、合、分裂,卡上有故事卡编号、优先级、风险评估和当前的迭代序号,用户故事卡订在一个大家都能看到的离开发位置较远的墙壁上
3) 任务卡,任务卡从故事卡分裂而来,用图钉钉在开发员的电脑旁边
4) 编码卡,主要纪录需要实现的测试,需要注意的事项,等等,开发人员不断增加条目、划去条目,是对一个人物而言的备忘录和todolist
3.大坐标纸(长的直尺、各种颜色的笔)
我通常会在项目的进行过程中记录各种度量,这包括有效代码增长率、测试代码增长率、功能测试通过率、故事卡完成率、测试覆盖率(具体工具在后面介绍),悬挂在比较高的位置,大家一眼能够看到的地方
另外每个迭代的每个理想天都会检查每个人任务完成的情况,延迟、提前、原因、重新估计时间、剩余实践,根据不同情况用不同的颜色表达,画在一张大白纸上,不够的话可以慢慢接长,贴在显而易见的墙壁上
4、小桌子(香烟、绿茶、咖啡或水果)
工作一段时间,2个小时左右,开发人员可以三两成群地在小桌子(或者是吸烟区)旁边抽烟、喝茶、咖啡或者水果,交流相互的心得、讲讲笑话、谈谈碰到的问题。很多问题就在这里面谈出来、解决、得到线索等等,团队的气氛经常就是在这个时候变得慢慢融洽。
第2个卡片我想是否可以用便笺本,那种随处可以买到黄色便笺,写下内容,随意可以贴到办公桌前,墙壁上。
卡片一定要硬的,方便传递,有质地感,有一定的厚度
1。在CRC的扮演过程中,举起一张硬卡片和一张软软的纸感觉不同
2。在撕卡片的时候,要有声音有感觉,表示我们对需求的更改是非常欢迎的,不是说些下来的东西就完全算数了
3。在需求过程中,卡片需要在客户、程序员、分析人员之间传递,纸片太软
4。客户需要根据价值把卡片按优先级分堆,决定我们的迭代和发布,纸片不方便,容易遗漏和混淆,不太正式
5。故事卡可能一部分可能移到下一个迭代,不能在墙上贴了一段时间就变得破破烂烂
对于第3部分而言,这又是一个交流问题,重在交流和整体感觉,而不是具体的数据
客户、老板、项目开发人员、管理人员各位都希望知道现在进行的情况,开发人员也需要对项目中其他人员地进行情况有所了解,所以最好把这些东西放在最显而易见的地方。每个相关人员都可以一眼感觉到项目的“温度“
一般来说,我检查和度量的时间是在一个理想天,也就是3-4天的时间,一般采用的工具是JavaNCSS ,我有编写一个小小的工具,利用Javancss计算出源代码的统计信息,按照时间为横轴,画出增长的曲线,然后手工画到墙上的大纸上。一些例子
1。产品代码增长率,这个增长率应该在项目前期比较高,且比较稳定,如果某段时间的增长率出现异常情况,可能在设计或实现过程中碰到了某些问题。在项目后期应该逐渐降低(但不意味着故事完成增长率的下降,相反体现在故事增长率和测试增长率的相对提高),这是我们对重用的一个期望。代码增长率也是项目管理人员比较关心的问题。
2。单元测试代码增长率,一直保持在比较稳定的增长率,不同阶段和产品代码的增长之间保持一个相对比率,例如从1:1到1.5:1到2:1,
3。代码覆盖率,用clover可以很方便地生成,CLover的历史信息和增长信息特别有用,当然还需要手工摘录最重要的几条曲线
4。用户故事完成率,这是客户需关心的东东,只有所有的用户故事完成,才能号称迭代正确完成,不然写了多少代码读是没有意义的
5。功能测试增长率和Bug密度,功能测试反应的未通过的bug,这个最好是分界面、WEb曾或者数据库层、模型层,统计在不同模块的密度,这个Bug率最好加上估计的时间,例如1小时、2小时,半天等等。功能测试没有100%通过是正常的,但是必须纪录BUg的相对密度。
至于开发人员的进度模板,这个就比较复杂了,不同的项目也有所调整,我曾经用XPPlanner产生过报表,但太灵水了,所以不得已用excel画的,每1理想天更新一次,这是很重要的一个掌控工具,一个迭代周期内必须尽早估计到可能需要的延迟、客户需求变化的调整、一些人提早或落后需要开发人员之间相互调剂等等,据说2003年生产力奖的XPOne非常好,但没有评估版本,我每次只能用手工做。
这个象20个人的团队大约要花上3-4个小时左右,所有人都要参加,要充分交流分析体现或落后的原因、要及时调整后面的估计,同时尽量让每个人发表自己的意见,例如可能需要交换任务,重新调整任务的时间、加入新的任务、把某些任务延迟到后一个迭代、解决本天内的一些新发现的公共问题等等。
当然,最后还是要抄到墙上去
在XP和其他敏捷软件开发团队里面,交流和反馈不是一个空洞的概念,所有的工具(例如SCM)、纪律、度量、工作方式、环境都有为这个目的服务,交流的畅通是需要花费大量的时间、精力和很多习惯才能慢慢形成的,不是轻而易举就能达到的。这是一个无论怎么强调都不为过的重点。
Wiki
我是Snipsnap的老用户,所以项目开发的时候还是用SnipSnap,SnipSnap的好处是使用简单,配置方便,涉及到项目开发的具体应用,通用词汇表的建立、概念的交流、工作方式的讨论我喜欢在Wiki上进行,Wiki也是一个项目知识库实现的最佳方式,包括项目所需要的配置说明、项目用到的书籍、文章和相关的讨论
第二个Wiki是Fitness,这是做功能测试最好的工具之一
关于Wiki,我自己有项目管理中的新想法,不过很多相关的产品都不是开源的,太贵,所以目前还没有应用起来,等我自己了,呵呵
IssuerTracker
Jira,这是我少数选用的商业产品,举我自己的感觉,这是Issuer里面No.1的产品,可惜和XP的项目计划偏差较大,对于时间估计和流程配合不够流畅。
为什么用Wiki的原因,我在另一个帖子已经有些说明,主要的问题是WIKI的形式比较自由,能够充分发挥想象力,不需要非常正式,但是又容易在开发的过程中积累起很有意义的思考、文档和模式。总而言之,是非常利于不拘形式的自由的交流。
Wiki的简单和目前很多WIKI的可扩展性,使得我们能够把Wiki和其他软件,例如Issuer,CVS等方便地结合起来。
Wiki软件和Eclipse的结合可以产生很多对项目开发有益的想法和帮助,虽然这一块目前还不时有很多公司在做,但我觉得一些小小的结合就能产生很好的交流效果和文档组织。
使用Jira的原因是它是面向开发人员的一个tracker工具,在开发阶段它的表现要胜于其他跟踪系统,它的灵活性和新近的插件机制也能够方便我更好的扩展何时佩。
JUnit,这个没什么好说的,当然用法上自然是最偏向于KentBeck的用法。用Cactus测试感觉不是很方便。由于struts已经不用了,用JUnit就能够测试Webwork的Action,所以Web层我基本上已经不测了。
Clover,虽然TDD的覆盖率肯定是非常高的,但很多项目不做TDD的,我自己有一个小小的工具,自己用用还可以,但项目中没办法用, JCoverage是开源的,红工厂也有产品,但是我没用过
用户测试,目前我在第二个小项目中用Fit和Fitnesse,但没有在大项目使用的经验。以前是自己写excel到数据库转换,用JUnit测的,比较麻烦
大部分 web 以及企业级 Java 应用可被分成三部分:与用户交互的前台,与数据库这样的后台系统交互的服务层,以及它们之间的业务逻辑。最近这段时间,通常我们会使用框架来实现前台和后台的需求(例如:Struts, Cocoon, Spring, Hibernate, JDO, 以及实体 Beans),但是却没有一种标准手段很好的组织业务逻辑。像 EJB 和 Spring 这样的框架都以 high level 方式处理,这无助于组织我们的代码。除非我们改变这种凌乱,否则系统将不会健壮,框架中杂乱的 if...then 语句能带给我们可配置性、可读性的优点,以及在其他地方复用代码的愉悦吗?本文将介绍如何使用 Drools 规则引擎框架来解决这些问题。 我们经常写出类似的(甚至更复杂)业务逻辑。当这些用 Java 实现的业务逻辑成为标准方式时,将存在下列问题: 我们怎样解决问题呢?一种方案是通过规则引擎获取 traction。规则引擎是为组织业务逻辑应运而生的框架,它让开发者专注于做被认为正确的事情上,而不是以 low-level 方式作出决定。 假设有这样的场景:在阅读本文的数分钟后,你老板要求你做一个股票交易应用原型。这时,业务用户尚未被完全定义业务逻辑,你马上会想到最好的办法是用规则引擎实现。最终系统将可通过内部网访问,而且还要和后台数据库以及消息系统通讯。在着手行动前,先下载 Drools 框架(与支持库一起)。在你喜欢的 IDE 中创建新项目,确定所有 .jar 文件被引用进项目,如图 1 中所示。截图是基于 Eclipse 的,不过在其他 IDE 中创建也是相似的。 这是最基本的 JUnt 测试,我们知道我们的系统应该买所有低于 100 欧元的股票。很明显,要是没有数据持有类(StockOffer.java)和业务层类(BusinessLayer.java)它将无法编译。这两个类如下。 StockOffer 是这样: 通过 IDE 的 JUnit 插件运行 BusinessRuleTest。如果你不熟悉 JUnit,可在 JUnit 网站找到更多信息。不必惊讶,如图 2 所示第二个断言测试失败,这是因为还没把业务逻辑放在适当的地方。测试结果用高亮显示了模拟器/单元测试所出现的问题,这是很保险的。 这个类有些重要方法: 该规则文件有些有趣部分: 刚刚构建好应用,你就向业务用户示范上面的原型,他们却忽然想起先前并没有提出的规则。其中一个新规则是当数量是负数时(<0)不能进行股票交易。“没关系,”你说,接着回到办公桌上,紧扣已有知识,快速演化你的系统。 这个测试是为业务用户描述的新规则建立的。正如意料之中的,如果运行 JUnit 测试,我们的新测试将失败。所以,我们要添加新的规则到 .drl 文件: 这个规则的格式和前面的相似,除了 现在业务伙伴被打动了,并且开始考虑进行选择了。随即他们遇到了个 XYZ 公司股票的问题,那么我们来实现新规则吧:只有 XYZ 公司股票低于 10 欧元才可购买。 接下来向 BusinessRules.drl 中添加新 注意业务规则文件,在 rule name 后面,我们把 salience 设置成 -1(到目前为止了解的最低优先级)。大多数规则在系统中是冲突的,这意味着 Drools 必须为规则的执行顺序做判断,假设这些条件都与规则匹配。默认的判断方式是: 我们的简单应用由 JUnit 测试驱动,我们不必改变 Drools 处理规则冲突的方式。知道冲突解决方案怎样运作是很有用的,尤其当你的应用为了迎合更复杂、更苛刻的需求时。
下列的范例代码展示了我们正要试图努力避免的问题。展示了包含一些业务逻辑的 Java 典型应用。
&& user.isMemberOf(teleworkerGroup))
|| user.isSuperUser(){
// more checks for specific cases
if((expenseRequest.code().equals("B203")
||(expenseRequest.code().equals("A903")
&&(totalExpenses<200)
&&(bossSignOff> totalExpenses))
&&(deptBudget.notExceeded)) {
//issue payments
} else if {
//check lots of other conditions
}
} else {
// even more business logic
}
业务用户怎样在这些难以理解的代码基础上添加另一个条件(比如"C987")?一旦最初开发这些程序的员工离开了,你想成为维护这些代码的人吗?
我们怎样检查规则的正确性?对业务伙伴的技术人员来说都够复杂的了,更不要说检查。我们可以有系统的测试这些业务逻辑吗?
很用应用都有相似的业务规则--当其中的一个规则改变,我们能保证这一改变可贯穿整个系统?当新应用使用这些规则,该应用已经部分添加了新的规则,但不完全,我们要把逻辑重写过吗?
我们经常需要对每个细小调整所带来的改变进行重编译/重部署,而不是坚实的依靠 Java 代码,业务逻辑是否易于配置?
可否复用已存在的用其他(脚本)语言编写的业务规则逻辑?
J2EE/EJB 以及“IoC inversion of control”框架(比如 Spring,Pico,以及 Avalon)给我们带来的是 high level 代码组织能力。在提供良好复用性、可配置性、以及安全性的同时,没有一个能替代(解决)以上的“spaghetti 代码”范例出现的问题。理想地,无论选择何种框架,不仅仅适合 J2EE 应用,而且也可用于“normal”Java(J2SE)程序,以及大部分普遍采用的表现层以及持久层框架。这种理想框架应该允许我们这样做:
业务用户应该可以方便的阅读和校验业务逻辑。
业务规则应该可被复用,并可以通过程序进行配置。
这种框架应该是可升级的,并在高负载情况下运行。
Java 程序员可以像使用现有的前台(Struts,Spring)和后台(ORM object-relational mapping)框架一样方便地使用这个框架。
另外的问题是,有许多的 web 页面、数据库访问组织方式,业务逻辑在这两种应用中应趋于不同。而框架应该能应付这些并促进代码复用。理想的框架将能“frameworks all the way down.”,通过这种方式使用框架,我们能在应用中大量的“out of the box”,这样我们只为客户记录添加值的部分。
规则引擎前来救援
通常,业务用户舒适的表达他们知道的正确的事,而不是 if...else 格式的表达方式。你也许能从业务专家听见这些东西:
“FORM 10A 用来索取额外 200 欧元费用。(FORM 10A is used for expense claims over 200 Euro.)”
“我们只进行数量在 10,000 以上的贸易。”
“购买大于 €10m 的要经过公司董事批准。”
通过专注于我们认为正确的事情上,而不是只知道怎样用 Java 代码表达,那么上面的叙述将比之前的代码范例更清晰。我们仍然需要一种机制为我们知道和做决定的事实应用这些规则。这种机制就是规则引擎。
Java 中的规则引擎
JSR 94,如同 JBDC 允许我们与多种数据库交互一样,javax.rules 是一组与规则引擎交互的通用标准 API。为什么 JSR-94 没有详细说明实际的规则怎样书写,有下面大量的 Java 规则引擎可供选择:
Jess 或许是最成熟的 Java 规则引擎,有良好的工具支持(包括 Eclipse 插件)以及文档。但是,它是商业软件,而且用 Prolog-style 符号书写规则,对 Java 程序员来说是很晦涩的。
Jena 是一套开源框架,最初由惠普发起。虽然它有规则引擎以及在 Web 语义方面特别强大,但它并不与 JSR-94 兼容。
Drools 是与 JSR-94 兼容的规则引擎,并且在 Apache-style 许可下完全开源。它不仅用熟悉的 Java 和 XML 语法表述规则,而且它还有强大的用户、开发者社区。在本文中有范例,我们将使用 Drools,因为它有最容易使用的类似 Java 的语法以及完全开发许可。
利用 Drools 开始 Java 开发
图 1. 运行 Drools 所需要的库
如果我们的股票交易系统很混乱,将失去大量潜在客户(商机),所以在系统的整个步骤中放入一些模拟器(simulator)是至关重要的。这种模拟器给了你决心采用该系统的信心,甚至规则改变以后所带来的麻烦。我们将借助敏捷工具箱中的工具,以及 JUnit(http://www.junit.org/) 框架进行模拟。
如下,我们写的第一段代码是 JUnit 测试/模拟器。即使我们无法测试每个对应用有价值的输入组合,但有测试也比没有测试的好。在这个范例中,所有的文件和类(包括单元测试)都放入一个文件夹/包中,但实际上,你可能会用一种适当的包、文件夹结构。范例代码中我们用 Log4j 代替 System.out 调用。
/*
* JUnit test for the business rules in the
* application.
*
* This also acts a 'simulator' for the business
* rules - allowing us to specify the inputs,
* examine the outputs and see if they match our
* expectations before letting the code loose in
* the real world.
*/
public class BusinessRuleTest extends TestCase {
/**
* Tests the purchase of a stock
*/
public void testStockBuy() throws Exception{
//Create a Stock with simulated values
StockOffer testOffer = new StockOffer();
testOffer.setStockName("MEGACORP");
testOffer.setStockPrice(22);
testOffer.setStockQuantity(1000);
//Run the rules on it
BusinessLayer.evaluateStockPurchase(testOffer);
//Is it what we expected?
assertTrue(
testOffer.getRecommendPurchase()!=null);
assertTrue("YES".equals(
testOffer.getRecommendPurchase()));
}
}
* Facade for the Business Logic in our example.
*
* In this simple example, all our business logic
* is contained in this class but in reality it
* would delegate to other classes as required.
*/
public class BusinessLayer {
/**
* Evaluate whether or not it is a good idea
* to purchase this stock.
* @param stockToBuy
* @return true if the recommendation is to buy
* the stock, false if otherwise
*/
public static void evaluateStockPurchase
(StockOffer stockToBuy){
return false;
}
}
* Simple JavaBean to hold StockOffer values.
* A 'Stock offer' is an offer (from somebody else)
* to sell us a Stock (or Company share).
*/
public class StockOffer {
//constants
public final static String YES="YES";
public final static String NO="NO";
//Internal Variables
private String stockName =null;
private int stockPrice=0;
private int stockQuantity=0;
private String recommendPurchase = null;
/**
* @return Returns the stockName.
*/
public String getStockName() {
return stockName;
}
/**
* @param stockName The stockName to set.
*/
public void setStockName(String stockName) {
this.stockName = stockName;
}
/**
* @return Returns the stockPrice.
*/
public int getStockPrice() {
return stockPrice;
}
/**
* @param stockPrice The stockPrice to set.
*/
public void setStockPrice(int stockPrice) {
this.stockPrice = stockPrice;
}
/**
* @return Returns the stockQuantity.
*/
public int getStockQuantity() {
return stockQuantity;
}
/**
* @param stockQuantity to set.
*/
public void setStockQuantity(int stockQuantity){
this.stockQuantity = stockQuantity;
}
/**
* @return Returns the recommendPurchase.
*/
public String getRecommendPurchase() {
return recommendPurchase;
}
}
图 2. JUnit 测试结果
用规则编写业务逻辑
在这里,我们要写一些业务逻辑,来表达“一旦股票价格低于 100 欧元,就马上购买。” 要达到这个目的,需调整 BusinessLayer.java:
import org.drools.DroolsException;
import org.drools.RuleBase;
import org.drools.WorkingMemory;
import org.drools.event.DebugWorkingMemoryEventListener;
import org.drools.io.RuleBaseLoader;
import org.xml.sax.SAXException;
/**
* Facade for the Business Logic in our example.
*
* In this simple example, all our business logic
* is contained in this class but in reality it
* would delegate to other classes as required.
* @author default
*/
public class BusinessLayer {
//Name of the file containing the rules
private static final String BUSINESS_RULE_FILE=
"BusinessRules.drl";
//Internal handle to rule base
private static RuleBase businessRules = null;
/**
* Load the business rules if we have not
* already done so.
* @throws Exception - normally we try to
* recover from these
*/
private static void loadRules()
throws Exception{
if (businessRules==null){
businessRules = RuleBaseLoader.loadFromUrl(
BusinessLayer.class.getResource(
BUSINESS_RULE_FILE ) );
}
}
/**
* Evaluate whether or not to purchase stock.
* @param stockToBuy
* @return true if the recommendation is to buy
* @throws Exception
*/
public static void evaluateStockPurchase
(StockOffer stockToBuy) throws Exception{
//Ensure that the business rules are loaded
loadRules();
//Some logging of what is going on
System.out.println( "FIRE RULES" );
System.out.println( "----------" );
//Clear any state from previous runs
WorkingMemory workingMemory
= businessRules.newWorkingMemory();
//Small ruleset, OK to add a debug listener
workingMemory.addEventListener(
new DebugWorkingMemoryEventListener());
//Let the rule engine know about the facts
workingMemory.assertObject(stockToBuy);
//Let the rule engine do its stuff!!
workingMemory.fireAllRules();
}
}
loadRules(),从 BusinessRules.drl 文件加载规则。
更新后的 evaluateStockPurchase(),用于评估业务规则。这个方法的注解如下:
可以反复复用相同的 RuleSet(内存中的业务规则是无状态的)。
为每次评估构造新的 WorkingMemory,因为我们的知识知道这个时刻是正确的。使用 assertObject() 放置已知事实(作为 Java 对象)到内存中。
Drools 有个事件监听模式,允许我们“查看”事件模型中到底发生了什么。在这里我们用它打印 debug 信息。
working memory 类中的 fireAllRules() 方法评估和更新规则(在本例中是股票出价)。
再次运行该范例前,需要创建我们的 BusinessRules.drl 文件:
<rule-set name="BusinessRulesSample"
xmlns="http://drools.org/rules"
xmlns:java="http://drools.org/semantics/java"
xmlns:xs
="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation
="http://drools.org/rules rules.xsd
http://drools.org/semantics/java java.xsd">
<!-- Import the Java Objects that we refer
to in our rules -->
<java:import>
java.lang.Object
</java:import>
<java:import>
java.lang.String
</java:import>
<java:import>
net.firstpartners.rp.StockOffer
</java:import>
<!-- A Java (Utility) function we reference
in our rules-->
<java:functions>
public void printStock(
net.firstpartners.rp.StockOffer stock)
{
System.out.println("Name:"
+stock.getStockName()
+" Price: "+stock.getStockPrice()
+" BUY:"
+stock.getRecommendPurchase());
}
</java:functions>
<rule-set>
<!-- Ensure stock price is not too high-->
<rule name="Stock Price Low Enough">
<!-- Params to pass to business rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<!-- Conditions or 'Left Hand Side'
(LHS) that must be met for
business rule to fire -->
<!-- note markup -->
<java:condition>
stockOffer.getRecommendPurchase() == null
</java:condition>
<java:condition>
stockOffer.getStockPrice() < 100
</java:condition>
<!-- What happens when the business
rule is activated -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.YES);
printStock(stockOffer);
</java:consequence>
</rule>
</rule-set>
只有在 XML-Schema 定义 Java 对象之后,我们才能引用进规则。这些对象可以是来自于任何必须的 Java 类库。
接下来是 functions,它们可以与标准 Java 代码进行混合。既然这样,我们干脆混入些日志功能来帮助我们观察发生了什么。
再下来是我们的 rule set,rule set 由一到多个规则组成。
每个规则可持有参数(StockOffer 类),并需要实现一个或多个条件,当条件符合时,将会执行相应结果。
在修改和编译完代码后,再次运行 JUnit 测试。这次调用了业务规则,我们的逻辑进行正确地评估,并且测试通过,参看图 3。恭喜--你已经构建了第一个基于规则的应用!
图 3.成功的 JUnit 测试
使规则更聪明
首先要更新模拟器,把以下代码添加到 BusinessRuleTest.java:
* Tests the purchase of a stock
* makes sure the system will not accept
* negative numbers.
*/
public void testNegativeStockBuy()
throws Exception{
//Create a Stock with our simulated values
StockOffer testOffer = new StockOffer();
testOffer.setStockName("MEGACORP");
testOffer.setStockPrice(-22);
testOffer.setStockQuantity(1000);
//Run the rules on it
BusinessLayer
.evaluateStockPurchase(testOffer);
//Is it what we expected?
assertTrue("NO".equals(
testOffer.getRecommendPurchase()));
}
are not accepted-->
<rule name="Stock Price Not Negative">
<!-- Parameters we can pass into
the business rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<!-- Conditions or 'Left Hand Side' (LHS)
that must be met for rule to fire -->
<java:condition>
stockOffer.getStockPrice() < 0
</java:condition>
<!-- What happens when the business rule
is activated -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
</java:consequence>
</rule>
这时,如果你习惯于过程化编程(像大多数 Java 程序员一样),你也许要搔头皮了:在一个文件中包含两个独立的业务规则,而且我们也没告诉规则引擎哪个更重要。不管怎样,股票价格(对于 -22)都满足两个规则(也就是少于 0 和少于 100)。尽管这样,我们仍能得到正确结果,即使交换规则顺序。这是怎么做到的呢?
下面的控制台输出有助于我们了解到底怎么回事。我们看见两个规则都执行了([activationfired] 这行),Recommend Buy 第一次被设置为 Yes 接着又被设置成 No。Drools 怎么知道执行这些规则的正确顺序呢?如果你观察 Stock Price Low Enough 规则,将发现 recommendPurchase() 其中一个条件为空。通过这点,Drools 规则引擎足以判断 Stock Price Low Enough 规则应该在 Stock Price Not Negative 规则之前执行。这个过程称为 conflict resolution。
FIRE RULES
----------
[ConditionTested: rule=Stock Price Not Negative;
condition=[Condition: stockOffer.getStockPrice()
< 0]; passed=true; tuple={[]}]
[ActivationCreated: rule=Stock Price Not Negative;
tuple={[]}]
[ObjectAsserted: handle=[fid:2];
object=net.firstpartners.rp.StockOffer@16546ef]
[ActivationFired: rule=Stock Price Low Enough;
tuple={[]}]
[ActivationFired: rule=Stock Price Not Negative;
tuple={[]}]
Name:MEGACORP Price: -22 BUY:YES
Name:MEGACORP Price: -22 BUY:NO
如果你是一名过程化程序员,无论你用怎样聪明的方式考虑这些,你都不会完全相信。这就是为什么要进行单元/模拟器测试的原因:进行 "坚固的" JUnit 测试(使用一般 Java 代码)确保规则引擎所作出的决定是按照我们所想要的路线进行。(不会花费大量金钱在无价值的股票上)同时,规则引擎的强大和伸缩性允许我们快速开发业务逻辑。
稍后,我们将学习如何用更加精练的解决方案进行冲突处理。
冲突结局方案
像以前一样,添加测试到模拟器,接着在规则文件中包含新业务规则。首先在 BusinessRuleTest.java 中添加新方法:
* Makes sure the system will buy stocks
* of XYZ corp only if it really cheap
*/
public void testXYZStockBuy() throws Exception{
//Create a Stock with our simulated values
StockOffer testOfferLow = new StockOffer();
StockOffer testOfferHigh = new StockOffer();
testOfferLow.setStockName("XYZ");
testOfferLow.setStockPrice(9);
testOfferLow.setStockQuantity(1000);
testOfferHigh.setStockName("XYZ");
testOfferHigh.setStockPrice(11);
testOfferHigh.setStockQuantity(1000);
//Run the rules on it and test
BusinessLayer.evaluateStockPurchase(
testOfferLow);
assertTrue("YES".equals(
testOfferLow.getRecommendPurchase()));
BusinessLayer.evaluateStockPurchase(
testOfferHigh);
assertTrue("NO".equals(
testOfferHigh.getRecommendPurchase()));
}
<!-- Parameters we pass to rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<java:condition>
stockOffer.getStockName().equals("XYZ")
</java:condition>
<java:condition>
stockOffer.getRecommendPurchase() == null
</java:condition>
<java:condition>
stockOffer.getStockPrice() > 10
</java:condition>
<!-- What happens when the business
rule is activated -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
</java:consequence>
</rule>
Salience:赋予的值。
Recency:使用规则的次数。
Complexity:首先执行有复杂值的特定规则。
LoadOrder:规则载入的顺序。
如果没有显示的在规则中详细指明,将会发生:
XYZ 公司规则("当价格高于 10 欧元就不购买 XYZ 的股票")将先执行(Recommend Buy 标志被设置为 No)。
接着更多的一般规则("购买所有 100 欧元以下的股票")被执行,把 Recommend Buy 标志设置为 yes。
这会给我们一个不想要的结果。然而,一旦在范例中设置了 saliency 要素,最终的测试和业务规则将像预期的那样顺利运行。
大多数时间,编写清晰的规则和设置 saliency 将给 Drools 足够信息以选择合适的顺序执行规则,有时我们想改变整个规则冲突处理方式。下面的例子说明了如何改变,告诉规则引擎首先执行最简单的规则。要注意的是:改变冲突解决方案要小心,它可能从根本上改变规则引擎的行为。
ConflictResolver[] conflictResolvers =
new ConflictResolver[] {
SalienceConflictResolver.getInstance(),
RecencyConflictResolver.getInstance(),
SimplicityConflictResolver.getInstance(),
LoadOrderConflictResolver.getInstance()
};
//Wrap this up into one composite resolver
CompositeConflictResolver resolver =
new CompositeConflictResolver(
conflictResolvers);
//Specify this resolver when we load the rules
businessRules = RuleBaseLoader.loadFromUrl(
BusinessLayer.class.getResource(
BUSINESS_RULE_FILE),resolver);
结束
本文示范了大部分程序员不得不面对的问题:怎样安排复杂业务逻辑的顺序。我们示范了一个使用 Drools 作为解决方案并引入基于规则编程概念的简单应用,包括了怎样在运行时处理规则。接着,后续文章使用这些技术并展示了怎样在企业级 Java 应用中使用。
本文的预定读者首先要对j2ee有所了解,熟悉xml,tomcat等基本内容,本文主要是简单介绍一下web服务的基本内容,怎样在java web开发中构建SOAP服务:
一、SOAP(Simple Object Access Protocol)简单对象访问协议,要了解SOAP,首先就需要了解分布式计算的由来,随着下一代的分布式计算体系web服务的出现,SOAP成为了创建和调用通过网络发布的应用程序的实际通信标准。SOAP类似传统的二进制协议IIOP(CORBA)和JRMP(RMI),但它不采用二进制数据表示法,而是采用使用XML的,基于文本的数据表示法。
通过XML表示法,SOAP定义了一种小型有线连接协议和编码格式,以表示数据类型、编程语言和数据库,还可以使用各种Internet标准协议作为其消息传输工具,还可以提供表示RPC和文档驱动的消息交换等通信模型的约定。请注意,W3C正致力于SOAP的研究,http://www.w3c.org/2000/xp/Group/ ,并得到了主流供应商的积极响应,以便对于基于XML的协议相关的重要任务达成共识,并定义其关键要求和使用场景。
SOAP1.2的基本规范定义了以下基本内容:
1)用于将XML文档表示为结构化SOAP消息的语法和语义
2)在SOAP消息中表示数据的编码标准
3)用于交换SOAP消息的通信模型
4)SOAP传输等底层协议的绑定
SOAP消息主要包括了信封头,消息头,主体,附件几部分
一个简单的SOAP消息表示:
POST /StudentInfo HTTP/1.1
Host:anthropology.cun.edu
Content-Type: text/xml;charset="utf-8"
Content-Length: 640
SOAPAction: "GetStudentInfo"
<SOAP-ENV:Envelop xmlns:SOAP-ENV="http://www.w3c.org/2001/06/soap-envelope"
xmlns:xsi="http://www.w3c.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3c.org/2001/XMLSchema"
SOAP-ENV:encodingStyle="http://www.w3c.org/2001/06/soap-encoding">
<SOAP-ENV:Header>
<person:mail xmlns:person="http://www.cun.edu/Header">xyz@cun.edu
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<m:GetStudentInfo xmlns:m="http://www.cun.edu/jws.student.studentInfo">
<student_name xsi:type='xsd:string'>
Wang wen yin
</student>
</m:GetStudentInfo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelop>
以上是1.2版本命名空间,1.1的命名空间 SOAP ENVELOPE:http://schemas.xmlsoap.org/soap/envelop/ ,SOAP ENCODING: http://schemas.xmlsoap.org/soap/encoding/
关于SOAP编码规范请参阅www.w3c.org/TR/xmlschema-2/ 定义的编码值,其他的一些规范可以上http://www.w3c.org/ 上具体查看。
二、以下从实际例子来学习,这里我使用的是Apache的一个子项目Axis的具体例子,便于深入了解soap的运行:
1)下载Axis的相关内容http://ws.apache.org/axis/:
2)建立一个实例程序(遵守j2ee的web程序规范),如(WebServiceTest目录)
把axis中lib文件夹的内容拷到你的WebServiceTest/WEB-INF/lib下,同时上网下载xerces(下载地点:http://xml.apache.org/xerces-j/)解释器的包文件xerces.jar,也拷到WebServiceTest/WEB-INF/lib文件夹下,(若要配置log4j,请把属性文件log4j.properties拷到WebServiceTest/WEB-INF/classes文件夹下)
3)修改应用程序WebServiceTest/WEB-INF中的web.xml文件:主要servlet设置如下
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/servlet/TestServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AdminServlet</servlet-name>
<servlet-class>
org.apache.axis.transport.http.AdminServlet
</servlet-class>
<load-on-startup>100</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AdminServlet</servlet-name>
<url-pattern>/servlet/AdminServlet</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>wsdl</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>xsd</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
你现在可以在网址里输入http://localhost/WebServiceTest/servlet/TestServlet 看到了吗?Axis是使用axis.jar包里的org.apache.axis.transport.http.AxisServlet对应用程序进行处理的,基本配置就讲到这里。
三、接着我们来说Axis中的内核。
1)不使用Tomcat引擎运行Axis。
先建立一个脚步文件,对环境变量classpath进行设置要把lib下的那些包文件的路径全都包括进去,运行:java org.apache.axis.transport.http.SimpleAxisServer <port>
2)内部服务处理程序是org.apache.axis.providers.java.RPCProvider,标志出服务所需的方法,然后提供从SOAP请求消息组成部分的参数。
3)Axis的应用程序端管理功能:
java org.apache.axis.client.AdminClient 就会列出参数,可供你选择。我们的例子是:java org.apache.axis.client.AdminClient -l http://localhost/WebserviceTest/servlet/TestServlet list 就会显示出服务列表,返回的是xml文件
4)wsdl2java应用程序可以把wsdl文件创建基于java的程序,如占位程序等
java org.apache.axis.wsdl.WSDL2java <url>
Axis的基本内容说到这里
四、具体例子
1)编写逻辑程序,简单如:SoapTest.java
public class SoapTest{
public String getStr(String name){
return "Hello,"+name;
}
}
2) 部署服务,编写wsdd文件SoapTest_deploy.wsdd:
<deployment name="SimapleTest" xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<service name="SoapTest" provider="java:RPC">
<parameter name="className" value="SoapTest"/>
<parameter name="allowedMethods" value="getStr"/>
</service>
</deployment>
其中className参数是你的想部署的类名(全名),allowedMethods是调用的服务的方法,如果有多个方法的话可以用空格分开(如: <parameter name="allowedMethods" value="getStr getMoney"/>),当用*的时候表示全部。
好了现在准备部署了,确保环境路径classpath设置正确,运行:
java org.apache.axis.client.AdminClient -l http://localhost/WebserviceTest/servlet/TestServlet SoapTest_deploy.wsdd
(这里不懂的话,请参考以上的说明)
ok,呵呵,至此,我们已经完成了一个web服务的部署:测试http://localhost/WebServiceTest/servlet/TestServlet 看里面是否多了一个选择SoapTest服务?
如果不想要服务了那重新编写一个wsdd文件,内容改为:
<deployment name="SimapleTest" xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<service name="SoapTest"/>
</deployment>
和上面一样,对比一下就ok了。
五、客户端测试:
客户端我们也可以使用java来进行测试,网上也有资料的,你可以去学习,很简单的。现在为了体现web服务的魅力,我用.NET平台来测试吧,客户端使用c#编写(先要安装.net framework sdk):
1)通过wsdl生成web服务代理,在net平台下运行:
wsdl /l:CS /protocol:SOAP /out:SoapTestClient.cs http://localhost/WebserviceTest/services/SoapTest?wsdl
我们通过wsdl得到了一个cs文件SoapTestClient.cs(当前目录),你可以打开cs文件,研究一下里面的代码,那个getStr(string name)就是我们需要调用的方法,我们的客户端通过调用该方法就可以调用服务器端的方法,内部的转化wsdl.exe工具已经帮我们完成了,axis下的WSDL2Java工具也是一样的功能,可以参考我上面所说的关于Axis的内核内容
2)编译cs文件成程序集dll:
csc /target:library /r:System.Web.Services.dll /r:System.Xml.dll SoapTestClient.cs
最后我们等到了一个dll文件SoapTestClient.dll,客户端程序通过调用它就行了
3)编写客户端应用程序SoapTestClientApp.cs
using System;
namespache jws.client{
public class SoapTestClientApp{
public SoapTestClientApp(){
}
public static void Main(string[] args){
if(args.Length!=1){
Console.WriteLine("Usage:SoapTestClientApp <name>");
Environment.Exit(1);
}
SoapTestService st_service=new SoapTestService();
st_service.getStr("Wang wenyin");
}
}
}
4)编译文件csc /r:SoapTestClient.dll SoapTestClientApp.cs
运行SoapTestClientApp
输出结果:
Hello,Wang wenyin
与预期结果相符。
好了,关于soap开发web服务就说到这里了,希望这篇文章能对大家有所帮助,谢谢了:)有问题的话可以留言,也可以跟我联系 gdanthrowwy@126.com
标签: WebService