如鹏网 大学生计算机学习社区

CowNew开源团队

http://www.cownew.com 邮件请联系 about521 at 163.com

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  363 随笔 :: 2 文章 :: 808 评论 :: 0 Trackbacks

2006年6月2日 #

首期费用5800元,杨中科老师在线客服QQ:杨老师

最强悍的师资!最强悍的课程!想成为强悍程序员的最强悍选择

3大真实项目循序渐进、环环相扣、逐步加深!

3大独有优势(师资强、项目真、课程深)不但能让你找到工作,还能让你找到好工作


培训目标


本课程重点培养掌握ASP.Net、WinForm、ADO.net、Microsoft SQLServer数据库、Oracle数据库的实战与理论双结合型工程师。通过本课程多个真实项目的训练,学员还可掌握软件架构设计思想、搜索引擎优化、缓存系统设计、网站负载均衡、系统性能调优等软件编程高级技术。让学员毕业后真正具备两年左右软件开发经验。

招生对象


本课适合于了解c#基本语法,对.net编程有着浓厚兴趣的人士。

课程特色

一、强悍的师资:微软一线高级软件工程师亲自授课,教授的绝非三脚猫功夫
当今社会,为了特显师资实力,众多培训机构都打着“我们的老师来自微软、IBM”之类的话,但实际上大多都是“水货”。传智播客的.Net教师真真实实来自于微软公司,是绝对的行货,能够经受得起全社会的考证。传智播客的.Net教师不但是微软一线高级软件工程师,同时也是众多技术书籍的作者。由这样的原创作者讲课可想而知课程条理清晰、讲解清楚,知识面广、深度足够!下面是我们.Net教师杨中科在微软工作时的照片及其出版的书籍。
杨中科在微软时的工作照 《专家手记——AJAX开发实战 》 《程序员的SQL金典》 《自己动手写开发工具》 《JavaScript网页开发-体验式学习教程 》
 
二、独家微软内部技术资料,率先讲解.Net4.0(WF、WCF、Linq)
随着微软推出.Net 4.0和Visual Studio 2010,掌握.Net 4.0中WF、WCF、Linq等新技术的学员将在职业竞争中具有更大的竞争优势,传智播客的老师因为之前就职于微软,因此得到了微软.Net4.0技术和VisualStudio2010的内部资料,保证我们的学员掌握的知识都是领先于他人的。
 
三、真实的项目:让你切身感受到什么才是真实的商业项目
当今在到处都是大忽悠的环境下,传智播客拒绝忽悠,教学所用的项目来自于真实的商业项目。现在不少培训机构为了招生,都打上论坛系统、通讯录系统、教学管理系统等项目,但很多都只是演示的demo,离真实的项目还远着呢,所以建议大家,你可以不选择传智播客,但一定要对培训机构进行检验,忽悠的话,只要文笔好的人都会写,但真实的项目是吹不出来的。
 
四、课程深:方能让你在职业竞争中鹤立鸡群,不但能找到工作,更能找到一份好工作
受全球金融危机的影响,IT行业萎缩、人才需求下滑,现在的情况是:一个工作岗位往往几佰人竞争,队伍中更是不缺乏具有一、二年工作经验的开发人员。如何让自己在几佰人的竞争中脱颖而出?没有他途,只有把技术学的更深入,更牛,方能取胜。传智播客的课程不但可以让你找到工作,更能让你找到一份好工作。那么传智播客毕业的学生,有没有没找到工作的?可以肯定地说:“有”。由于传智播客的课程较深入,每个班偶尔会有一两个同学坚持不下来,睡懒觉,9点上课,10点才来,课下也不动手练习。试想,如果自己不付出努力,再强大的师资,再好的课程也是无法帮助他就业的。对于这些个别同学,传智播客只能建议他复读,一些愿意回来复读的同学经过认真学习后都能找到工作。
 
五、业界认可:SOHU、用友、神州数码等在职软件工程师均推荐自己的亲戚朋友到传智播客学习
传智播客是CSDN下属子公司,借助CSDN平台,传智播客聚集了一批业界精英。有相当一部分老师在IT业界是颇有知名度的,而且有些老师还是推动某个技术普及的先行者(如果你认为我们是吹牛的话,就用baidu/google去检验吧)。由这些精英共同制定的课程不但反映了业界的主流技术,还具有前瞻性。正因为传智播客在软件界内被广泛认可,所以在招收的学生当中,就有相当一部分是在职软件工程师推荐过来的。
 

课程安排    


第一阶段:C#编程基础/Windows编程基础
[ 注:我们一直处于主流技术的最前沿,别人还在讲.net3.5的时候,我们已经在讲.net4.0了,国内也只有传智播客才能做到 ]
核心技术课程 C#编程基础:面向对象编程(类、继承、接口、设计模式、异常、反射)、枚举、Attribute、C#新特性(隐式类型、using、对象初始化器、集合初始化器、匿名类型、扩展方法、自动属性、LINQ、动态类型、可选参数)、常用数据结构(List、IDictionary、Array)、常用.net类库、泛型、.Net高级技术(Assembly、AppDomain、CLR、IL)等。 Windows编程基础:常用WinForm控件(TextBox、CheckBox、Button、RadioButton、ListBox、ComboBox、通用对话框、Menu、Timer等)、控件布局。

 

第二阶段:WinForm+WCF+Oracle+呼叫中心项目
[ 注:我们一直处于主流技术的最前沿,传智播客是第一个讲解基于微软最新WCF技术的机构 ]
核心技术课程 Oracle数据库开发基础:Oracle数据库基础管理、数据库备份/恢复、SQL语言(SELECT、INSERT、UPDATE、DELETE、JOIN、UNION等)、数据库函数、PL/SQL语言、视图、存储过程、触发器、数据库设计范式、数据库调优。
WinForm高级技术:WinForm高级控件(DataGridView、ListView、TreeView、WebBrowser、CheckedListBox、TabControl、NotifyIcon、SplitContainer、PropertyGrid等)的使用、多线程编程(Thread、BackgroundWorker、线程池)、自定义控件、Windows核心编程(ActiveX、进程管理、PInvoke)、报表与打印。
ADO.Net技术:ADO.Net的基本概念、DBConnection、DBCommand、DataReader、DataSource、DataAdapter、DataSet、DataTable、DataView、数据绑定、数据库连接池、SQL注入漏洞攻击的防护。
WCF开发技术:Socket套接字编程、MSMQ、WCF、SOAP与WebService。
阶段案例 省级汽车4S连锁店呼叫中心系统(项目金额35万、耗时5个月):本系统是一个C/S模式的分布式系统,一个核心服务器程序挂接20多个坐席端程序,坐席人员分布于3个核心客服中心,并且使用VOIP系统将10余个地市的4S连锁店的业务专家连接为专家坐席,为全省上万名车主提供报修、救援、保险理赔、回访关怀等服务。包含来电信息提示、CRM、历史信息自动跟踪、报修单、回访、来电屏蔽、历史通话跟踪、FAQ知识库管理、黑名单、转接、报表统计等模块。虽然基于B/S模式的系统越来越多,但是由于C/S模式有B/S所不具有的一些优点,因此在呼叫中心、银行系统、企业生产内网系统等应用中C/S模式仍然是不可替代的,因此熟悉WinForm技术的开发人员仍然非常吃香。这个项目将ADO. Net技术融入到开发中,并且采用了微软力推的新技术WCF进行分布式开发,通过这个项目,学员可以获得WinForm、ADO. Net、Oracle、WCF分布式开发等开发技能,并且获得了价值35万元、耗时5个月真实项目的业务系统开发经验。

 

第三阶段:ASP.net+VSS+SQLServer+WF+进销存项目
[ 注:我们一直处于主流技术的最前沿,传智播客是第一个讲解基于微软最新工作流引擎技术WF的机构 ]
核心技术课程 ASP.Net开发:常用ASP.net控件(AdRotator、BulletedList、Button、Calendar、CheckBox、DropDownList、HiddenField、HyperLink、Image、ImageButton、LinkButton、ListBox、Literal、MultiView、PlaceHolder、RadioButton、RadioButtonList、Substitution、Table、TextBox等)、文件上传下载、数据绑定、数据验证(RequiredFieldValidator、CompareValidator、RangeValidator、CustomValidator、自定义Validator、ValidationSummary)、GridView(分页、排序、过滤、自定义列、选择、编辑、删除、添加、自定义模板)、Repeater、ListView、DataPager、多层开发、WebControl、UserControl。
SQLServer数据库开发基础: SQLServer数据库基础管理、T-SQL语言、SQL Server Management Studio。
工作流开发:WF技术基础、WF与ASP.net的集成。
协同开发:VSS/CVS/SVN/TFS、团队开发、Bug管理、需求管理、持续构建、敏捷开发
阶段项目 进销存项目(项目是一个金额600万的项目中的核心模块):本系统将企业的采购、仓储、销售等一系列核心流程有机的整合起来,保证物流、资金流与信息系统的畅通无阻。提供包含了数据导入导出、批量数据处理、异构系统集成、订单号生成、分录、级联选择、红冲、勾稽、结账、反操作、入库、盘点、审批流程、报表等功能在内的企业内部信息系统常见的功能模块。这个项目使用最流行的ASP.Net多层式开发,使用微软主推的最新工作流引擎技术WF进行审批流程模块的开发,并且使用VSS进行团队协同开发。通过这个项目,学员不仅能够学会ASP.Net、WF等技术,而且进一步获得了使用.net技术进行大型企业级信息系统开发的经验。
 
 
第四阶段:ASP.net+VSS+SQLServer+CodeSmith+大型网站优化技术+网站内容管理系统CMS+站内搜索引擎
核心技术课程 ASP.Net高级技术:MasterPage、AJAX(UpdatePanel、ScriptManager、AJAX Control Toolkit‎、JQuery)、安全机制(Membership、Forms验证、AD验证、Login控件、CreateUserWizard控件)、ASP.Net核心对象(Request、Response、Cookie、Session、Profile)、导航控件(SiteMapPath、Menu、TreeView)、缓存技术、主题、国际化。搜索引擎技术:Lucene、多线程开发、爬虫技术、网页分析、正则表达式。大型网站开发技术:代码生成、SEO、网站调优、采集器、RSS/XML、网站防黑(防XSS攻击、防注入漏洞攻击、防CC攻击、防挂马、防盗链、防敏感词)、IIS管理与调优。
阶段项目 如鹏网项目(项目是已经上线近两年的网站,日访问量最高18000人次,网址www.rupeng.com):本系统旧版本基于PHP、J2EE技术,由如鹏网开发者亲手操刀用.net重写新版本。系统分为前台Web界面、后台管理界面、站内搜索、监控客户端四个子系统,包含栏目管理、文章管理、采集器管理、评论管理、投票管理、敏感词过滤、用户管理、友情链接管理、站内搜索、模型管理、缓存管理、广告管理、RSS输出、水印设置、搜索引擎优化设置、数据备份恢复等模块。通过这个项目,学员不仅可以在实战中巩固对前面学习的ASP.Net、ADO.Net、WinForm、WCF等知识的掌握,还可以掌握缓存、SEO、搜索引擎技术、AJAX等大型互联网开发中涉及到的技术,更可以获得系统架构师级别的开发人员对系统进行架构、设计和实现的能力。
 
第五阶段:传智播客特色课程
[ 注:我们的老师均来自企业一线高级技术主管,更了解企业对简历的要求,因此我们学员投放的简历命中率很高 ]
项目名称 总结以往所学知识,介绍面试、沟通等个人发展所需的知识和技巧。


培训方式


培训时间:3个月
培训方式:全日制脱产,每周5天上课,早9:00-晚 8:00 。
posted @ 2010-02-02 00:12 CowNew开源团队 阅读(1307) | 评论 (2)编辑 收藏

 

微软借助它在桌面领域的垄断地位不断推广它的最新技术,特别是做为微软最核心技术的.Net更是得到了最大力度的推广,社会上对掌握.net技术的开发人员的需求也越来越多。

为了帮助用最短的时间学到尽可能多的知识、掌握真实项目的开发经验,从而找到满意的工作,传智播客开办了“.Net 就业培训班”。“.Net 就业培训班”由任职于微软中国的杨中科老师担任主讲,重点培养掌握ASP.NetWinFormADO.netMicrosoft  SQLServer数据库、Oracle数据库的实战与理论双结合型工程师。通过本课程呼叫中心、进销存、如鹏网CMS等多个真实项目的训练,学员还可掌握软件架构设计思想、搜索引擎优化、缓存系统设计、网站负载均衡、系统性能调优等软件编程高级技术。让学员毕业后真正具备两年左右软件开发经验。

我们的课程有如下几个优点:

1、价格低

市面上很多.net培训班的收费都要上万元,为了帮助更多的同学掌握实实在在的就业技能,传智播客决定改变这种培训暴利的行业“潜规则”,让同学们得到真正的实惠,我们的“.Net 就业培训班”学费仅需5800。同时我们保证“低价高质”,降低价格并不会使得您学到的东西打折扣,学更多的东西花更少的钱,怎么算怎么划算!

2、师资强

传智播客拥有非常强的师资力量。比如著名的培训大师张孝祥、著名Java培训讲师黎活明。

值得一提的是,本次的“.Net 就业培训班”的领衔主讲老师杨中科,他曾经任职于微软中国、金蝶软件等公司,著有《自己动手写开发工具》、《程序员的SQL学习笔记》、《J2EE开发全程实录》、《专家手记——AJAX开发实战》等技术图书,主持或参与过招商局集团、中国工商银行、深圳发展银行、湖南烟草局、力诺集团等大中型企业的信息系统建设,他创建了专门为计算机专业在校生提供学习指导的网站如鹏网(www.rupeng.com ),他撰写的文章和录制的视频教程帮助无数的同学走出迷茫,也因此获得了“CSDN学生大本营2009年度十佳老师”的称号。

下面是一些学生给杨中科老师的评价“听杨老师讲课有一种醍醐灌顶的感觉”、“杨老师讲课真牛B”、“讲课很认真,每个学生可能犯的错误都考虑到了”、“我觉得杨老师讲的非常的好,很适合初学者来学习,我很喜欢老师的讲课方式”、“我觉得杨老师比现实中的某些老师尽职多了, 这才是老师!”

3、项目真

传智播客的培训课程中用的项目案例都是真实的项目,而不是那些玩具级别的演示项目。要知道同样叫“客户信息管理系统”,有的可能是一个初学者花了3天写出来的玩具级别的,有的则是多名资深软件工程师耗时几个月开发出来的,做为要参加培训的人一定不能被“客户信息管理系统”等这样的名字忽悠,要看看它是不是实际的项目。本次“.Net 就业培训班”采用的三个项目都是真实的项目,分别是合同额35万的省级呼叫中心、省级进销存系统、运营两年的网站。

4、课程内容领先

传智播客紧跟行业最新技术的动态,将行业中应用最广的最新的技术引入课堂教学,传智播客是目前唯一一个将微软最新.Net 4VisualStudio 2010技术引入教学的培训机构,并且将WFWCFWPF/Silverlight等微软主推的新技术融入到项目案例中,保证学员学习的时候就站在了行业的最高点。

杨中科老师任职于微软公司,能够接触到微软的内部资源,从而先一步得到微软的最新技术动向、最新的开发工具、内部的技术资料等,从而保证学员学到的是微软最新、最主力推广的技术。

教学方式:实地培训,人手一机;

培训地点:北京;

开班时间:20104月;

培训周期:3个月;

课程内容、报名方式等点击此处查看招生简章

最低的价格、最强的师资、最真实的项目、最新的课程内容,还等什么,快来报名学习吧!

posted @ 2010-02-02 00:11 CowNew开源团队 阅读(1165) | 评论 (0)编辑 收藏

这两天一张“有图有真相”的图片在各大论坛和QQ群中疯传,内容如下:

目前热播的电视剧《蜗居》第24集3:30秒截图,在小贝 的 桌子上那本书放大看是《大规模C++程序设计》,说明小贝是程序员。小贝被宋思明(市长秘书)戴了绿帽子。为无数想为 软件开发献身的人士叹惜呀。搞了一辈子C++,结果老婆跟了宋思明。 这部电视剧深刻揭露了程序员的悲剧性。相信这个重大发现将彻底粉碎那些少年们对程序员这个职业的向往,这个时代女生不会因为你写了一个搞笑程序而嫁给你。
建议广大程序们建议你们周围的少男们看一下蜗居,如果他以你为荣,以后想当程序员。你可以告诉他,小贝就是程序员,然后告诉他宋思明是公务员。相信他就会重新考虑自己人生的选择了!!!!!!!!!!


本以为发帖子的人只是拿来开玩笑
    但是看了很多网友、同学的回帖却明显感觉气氛不对,很多同学竟然貌似很严肃的对待了这件事情,纷纷说“嗨,搞计算机真没前途,还是当官好”、“当程序员没前途哇,都被人当绿帽子了”、“不学计算机了,看似是白领,没想到房都买不起,自己女朋友被宋思明拐跑了”、“不学编程了,去考公务员吧!”。本以为这些网友会“放下程序,拿起公务员考试题”呢,没想到在另外一个帖子里又开始再跟别人讨论魔兽攻略了。我才明白小贝不是可悲的,这些人才是可悲的。

    在这些人心中“当程序员的小贝被当公务员的宋思明抢走老婆”只是他不去学计算机、不在计算机行业深入研究的增加一个借口而已。“反正毕业也找不到工作不学习了”,这样就有借口不去上课了;“搞计算机的是吃青春饭的,没前途”,所以就蒙起被子继续睡大觉挥霍用来吃饭的青春;“宿舍老三的老爸是局长,人家毕业后直接回家当科长,咱们好好学不还是失业吗?算了”,然后继续在电脑上打WOW; “如鹏网里经常和我聊那个function321拿到一大堆公司的offer,那是人家有计算机天赋呀”,然后继续看着《火影忍者》等待天赋降临;“隔壁宿舍老大人家在学校里自己就开公司,现在赚的钱都自己买了别克商务车了,嗨,咱们毕业还要写代码混饭吃”,放下翻了没有两页的《C程序设计》仰天长叹。逃避奋斗总会有理由的!

    有人说“这个社会是不公平的”,我却说“这个社会是非常公平的”。“宿舍老三的老爸是局长,人家毕业后直接回家当科长”那是人家老爸奋斗的结果; “隔壁宿舍老大人家在学校里自己就开公司,现在赚的钱都自己买了别克商务车了”,那是人家自己钻研经商之道奋斗出来的结果;“宋思明有能力帮海藻买房、买衣服,给小贝戴绿帽子”, 那是人家宋思明在没有硝烟的官场上出生入死当上市长秘书的结果。成功的人总是有成功的理由,理由不尽相同;失败的人失败的理由却永远永远相同,那就是——懒惰。

    还是我以前在《【解惑】专科生在IT的发展之路》这篇文章中说的那句话“社会上有成功的人永远都是少数人,做任何事情都是只有20%的人成功,另外80%的人都是失败的”。以《蜗居》中的宋思明为例,大家都认为宋思明当了公务员,走上了仕途,所以才现在风风光光,可是你知不知道有大把的公务员熬了一辈子临退休连个最小的副科长都没熬上的,有很多人好不容易考上公务员没过几年却由于自己后台不硬、没讨好领导、得罪有背景的同僚被淘汰……,最后能走上宋思明那样地位的人少之又少。而且宋思明也并不是真的那样风风光光,他要防着别人捅刀子,要保证自己的那些违法乱纪的勾当不被揭穿,宋思明容易嘛?

    有人总是说“搞计算机毕业就失业”、“搞计算机的小贝买不起房子”,先不说网易的丁磊、巨人的史玉柱、金山的求伯君、CSDN的蒋涛、江民杀毒的王江民、discuz的戴志康、金蝶的袁红岗等等这些计算机技术出身的成功人士,就是在中关村混了三五年、年薪十万以上、能全款买下一套好房的程序员也一大堆,当然更多的程序员是混了三五年还是月薪三四千的月光族。非常正常!正符合我说的“做任何事情都是只有20%的人成功,另外80%的人都是失败的”的这个说法。公务员中混的好和IT认识中混得好的一样,公务员中混的差和IT认识中混得差的也没什么不同。
    别让“当程序员的小贝被当公务员的宋思明抢走老婆”这样的话成为你逃避的理由,如果想在IT这行混下去,继续努力,即使成不了求伯君,也至少能弄个年薪十万。如果没有在IT行业混下去的想法,希望成为下一个宋思明的话,那么抓紧关掉魔兽、叠好被子,拿起公务员考试的书,然后发动你七大姑八大姨看看有没有亲戚当局长的,当上公务员以后把握风向、跟对队伍,早日完成你光宗耀祖的目标。


成功的人是不同的,失败的是却是相同的!

posted @ 2009-12-15 16:36 CowNew开源团队 阅读(14430) | 评论 (43)编辑 收藏

php中可以使用strlen或者mb_strlen计算字符串的长度,但是这些长度计算的都是在计算机中表示的长度,并不是实际在屏幕上显示的宽度。如下图(使用的是arial字体):


最理想的实现方式是使用imagettftext计算字符串使用特定字体显示的宽度:
function tf_strlen($str)
{
 return ceil(tf_strwidth($str)/tf_strwidth('测'));
}
function tf_strwidth($str)
{
 $im=imagecreatetruecolor(10,10);
 $r=imagettftext($im, 12, 0, 5, rand(14, 16),0, 'arial.ttf', $str);
 return $r[2]-$r[0];
}

需要在本地计算机的字体文件夹中找到'arial.ttf',然后上传到php页面同级的目录下。这样调用tf_strlen得到的就是字符串在屏幕上的显示宽度了。但是因为imagettftext是GD级别的操作,因此效率非常低,编写下面的程序验证

$begin=microtime(true);
$im=imagecreatetruecolor(1000,1000);
for($i=0;$i<10000;$i++)
{
imagettftext($im, 12, 0, 5, rand(14, 16),0, 'arial.ttf', "rupeng.com 如鹏网 在校不迷茫,毕业即辉煌");
}
$t1=microtime(true)-$begin;
echo 'imagettftext:'.$t1.'<br/>';
$begin=microtime(true);
for($i=0;$i<10000;$i++)
{
strlen("rupeng.com 如鹏网 在校不迷茫,毕业即辉煌");
}
$t2=microtime(true)-$begin;
echo 'strlen:'.$t2.'<br/>';

echo $t1/$t2.'<br/>';

运行后发现imagettftext的运行时间是strlen的4000多倍,太慢了,而且CPU占用率非常高,因此被否定。

经过观察发现arial字体下,汉字的宽度是一致的,而1、i、l等字符的宽度大约是汉字的0.4倍,而阿拉伯数字(除了1)的宽度则是汉字的约0.7倍,小写字母(除了i、l等)的宽度是汉字的约0.7倍,大写字母则是汉字的0.8倍,其他字符也可以得出相应的倍率。因此我编写了下面程序用来计算字符串占的宽度(单位是1/2的中文宽度)。

function arial_strlen($str)
{
 $lencounter=0;
 for($i=0;$i<strlen($str);$i++)
 {
  $ch=$str[$i];
  if(ord($ch)>128)
  {
   $i++;
   $lencounter++;
  }
  else if($ch=='f'||$ch=='i'||$ch=='j'||$ch=='l'||$ch=='r'||$ch=='I'
  ||$ch=='t'||$ch=='1'
  ||$ch=='.'||$ch==':'||$ch==';'||$ch=='('||$ch==')'
  ||$ch=='*'||$ch=='!'||$ch=='\'')
  {
   $lencounter+=0.4;
  }
  else if($ch>='0'&&$ch<='9')
  {
   $lencounter+=0.7;
  }
  else if($ch>='a'&&$ch<='z')
  {
   $lencounter+=0.7;
  }
  else if($ch>='A'&&$ch<='Z')
  {
   $lencounter+=0.8;
  }  
  else
  {
   $lencounter++;
  }
 }
 return ceil($lencounter*2);
}

经过大量的测试,发现和imagettftext的运行结果非常接近,而速度则比imagettftext高很多,CPU占用率也低很多。
解决思路对于其他语言,比如C#、Java等都适用。

posted @ 2009-11-15 14:06 CowNew开源团队 阅读(3909) | 评论 (5)编辑 收藏

今天和一位朋友(微软的资深架构师,按照年龄、阅历分,我叫他老师)吃饭,聊到他的爱好,他喜欢国学和习武,聊到国学的时候,他就说现在他在做一个网站,就是传播真正的国学,而不是像易中天那样披着学术的名义说评书。我问他搞这种真正的国学会不会不像易中天那样“大话国学”那么流行、那么赚钱,他说“我只是想传播一种正确的思想,相信大家都会有能力辨别正确的思想,当大家知道那些人是在恶搞国学而我是在真正的弘扬国学的时候,人的趋向争取东西的本性就会使得他接受我的正确的东西,而且会把这种正确的东西传播给其他人”。想一想这和我在如鹏网的工作也是有相似点的,现在主流的宣传口号都是“大学里学的东西过时了,没用了”,因为这是符合宣传这种想法的人们的利益的,而我在传播的“大学里学的东西永远不过时,只是需要同学们多动手”也是“非主流”的,但是是我认为正确的,这种正确的思想也在使越来越多的同学"趋向争取东西的本性就会使得他接受我的正确的东西",而且有很多同学都是靠“正确的东西传播给其他人”的这种方式知道我的这些想法的。

又谈到哲学的问题,说到很多人学哲学的时候都是死记硬背那些哲学的原理,背了半天什么真正的东西都没学到;而有的人则是看了古今中外的很多史料、案例,悟出一些道理,然后再来看那些哲学的原理,发现这些哲学原理都很容易的和之前学的史料对应上,这样轻松的就从本质上掌握了这些哲学的原理。我又联想到同学们学计算机,很多人把编程语言当成理论学,背关键字、背函数、背代码片段,到头来什么都没学到,而有的人则一边学一边练程序,练过大量程序以后再来看书指导自己的实践,反正掌握的更牢靠。

接着又谈到了关于武术的问题。他说在练武术的时候很多人都去学那些套路、招式,最后学到的只是花拳绣腿,真正的武术大家是不看重那些招式的,他们那些招式都是在实战中悟出来的,没有定法,灵活运用,两次不同的实战中用到的都是不同的招式。而那些招式只是给想“学学玩”、“学一学到别人面前显摆”的人用的,让他们学上两招去唬人,是一个玩具而已,其实什么用都没有,要想学到真正的武术必须下苦功自己练,多实战,然后自己悟。和学计算机一样,很多人学黑客,其实就是拿一些真正的黑客开发出来的黑客工具“玩一玩”,满足一下虚荣心而已;有的人学编程则学一大堆MFC、Struts之类的框架、工具,到处炫耀自己“懂得高级编程技术”,到最后却连最基本的一个for循环都写不好。

最后还谈到了学哲学中的“只和一个师傅学”,他的一个朋友去学哲学,问师傅世界上这么多哲学的书什么时候能看完,师傅告诉他只看一本书就可以,他用了五年的时间看这一本书,然后五年后师傅把其他的哲学书拿到他面前,他翻了翻就说“师傅我明白了,这么多不同的书其实本质上都是说的一样的道理,不用看其他的书了”。我又联想到同学们学计算机,有的同学刚学C++的时候就惊呼“听人说有好多C++的经典书《Essential C++》、《Thinking in C++》 、《C++ Primer》 、《Exceptional C++》、《More Effective C++”》……是不是要都学完才是掌握了C++,这要学到身边么时候呀?”,我和他说“你把你现在学的C++的教材学好了,每个程序都能熟练的写出来,然后再回头看这么多不同的书其实都不值得看了”,事实也是如此,经过半年多的苦练,等他回来再翻这些书他说了一句话“这些当年我想像的大部头现在翻起来都大同小异,每本书能挑出5页对我不同的东西都很难”。

万物通一理!

posted @ 2009-11-04 18:51 CowNew开源团队 阅读(3261) | 评论 (5)编辑 收藏

昨天和朋友去吃饭,本打算去海底捞吃的,没想到还需要排号,很多人都在等着排号,太火爆了。当时和朋友开玩笑说“这个店要是我的我就发达了”。
以前就听说过海底捞的故事,说他们的管理文化是多么的特别,才造就了现在的火爆场面。那天根本没有在那里吃,人太多,转了一圈就出来了,但是就是转这一圈就感触颇深:由于外面冷,里面热,进了门眼睛立即就一片雾蒙蒙,没想到服务员立即就递上来一片擦镜布,这种做法绝对不是总部传下来的“旨意”,而是一线的服务员发现的问题,立即就能想到更好服务顾客的办法,是一线员工在做决策,而不是靠一个领导来做决策;在等坐的时候服务员把你引到等坐区域,上来热饮,还告诉傍边的小吃、水果都是免费的,随意取,看旁边还有等坐的人在打牌、下棋,对于很多“利润为王”的餐厅来说,绝对不会让一个等坐的客人随意喝热饮、随意吃小吃,甚至只是在那坐了一下没吃饭也要收服务费,因为在他们心中“那都是成本”,而海底捞做到了,所以海底捞火爆了;在我们因为人太多,决定不在海底捞吃的时候,服务员竟然还主动送上一包火锅底料做为道歉,这就是传说中的“只要把顾客服务高兴了,一线员工有权利支配餐厅的资源,无需请示主管”。


岂有不火爆的道理。以前我总是崇拜西方科学的管理方式,现在慢慢感觉到曾仕强先生的《中国式管理》是有一定道理的。

引用一些网络上关于海底捞的资料:

虽然早已对海底捞的火暴有所耳闻,但在炎热的夏季夜晚,围绕着数十张小方桌的上百位等位者所制造出的喧闹气氛和巨大声浪,还有他们似乎超出常人的耐心,还是显得令人讶异。

凡来过海底捞的人,恐怕都很难不对细致入微的服务留下强烈的印象,有人夸张地称之为“变态伺候”:顾客入座后,立马会送上绑头发用的皮筋、围裙、手机套,就餐期间会有服务员不时递上热毛巾。更深的感触是服务员个个精神饱满,快乐感染了每位顾客。在“大众点评网”上,很多顾客对这种贴心服务感到“受宠若惊”, 感慨“终于找到了做上帝的感觉”。

  到目前为止,海底捞无疑是一个成功的商业故事,有管理学教授跟踪探访海底捞的商业智慧。在餐饮业中,火锅是对食物烹调要求相对较低的一种。缺乏差异化使得火锅业竞争异常激烈,经营者往往会尽量降低运营成本而与竞争对手区分开。但这些途径往往很快被整个行业复制,包括曾经被披露的反复使用锅底等行业黑幕。海底捞的菜品在顾客中以干净、新鲜以及分量适宜而著称。结合他们的超品质服务,我们不免好奇海底捞的利润如何,又来自哪里?

  也许正如海底捞自己的广告语:“好火锅自己会说话”,它每年3亿元的营业额来自这些表象下面埋藏着的未知的内在驱动力。

  被误解的海底捞

  所有顾客都是“上帝”吗?

  在张勇看来,顾客满意度和忠诚度要远比简单的利润加减法重要得多。他们所提供的无与伦比的服务,似乎也证明了他们在争取每一位顾客时付出的努力。 海底捞的北京分店大部分时间能保持每晚高达3到5桌的翻台率,堪称餐饮界的奇迹。海底捞不断在菜品与服务上创新,以求为顾客带来意想不到的体验,但并非每一位等待要求被满足的顾客都能在海底捞如愿。

  有人曾经借机问过张勇:“3个小时的等位时间对一些人来说未免太漫长,他们不在乎免费茶水,也不需要擦鞋美甲,你将如何吸引这些顾客?”

  张勇的回答简单而干脆:“对时间过于敏感的顾客不会选择吃火锅,也就不会选择海底捞。”

 海底捞的一线服务员都拥有免单权,既简化了流程也加强了服务员应对特殊情况的能力。但也有一些顾客曾利用海底捞这一特色蛮横强行要求免单,这些人的要求当然就不会被满足,同时也不会被任何企业或个人所欢迎。

 给顾客不可替代的非常体验,令其非常满意,并不是件容易的事,但恰恰激发了员工的创造性。在海底捞的企业内刊上,有很多员工亲自撰写的工作感受,其中有很多是对提高顾客忠诚度的感悟。北京七店的客户经理被员工亲切地称为“干妈”。她的能耐让很多新员工佩服,一问今天哪儿有老顾客?干妈都会顺畅地回答道:“大厅96号,苏打水宋哥;大厅1号,爱美甲的张姐⋯⋯” 任何关于老顾客的问题,她都能倒背如流地回答。

     海底捞的员工很少从社会招聘,大部分是现有员工介绍来的亲戚朋友。在大家彼此都熟悉的环境里,无论好的或是坏的,都容易蔓延和生长。作为公司的创始人,张勇在极力推行一种信任平等的价值观。在接受采访的当天,袁华强刚刚召开了一个会议,起因是一些门店发现酒水的管理不够完善,晚上盘点时发现时多时少。有人提议应该加大对相关员工的惩罚力度。袁华强觉得这事可能是客人要酒,服务员太忙,忘了;后来客人再要的时候,服务员为了避免客人不满,就来不及在系统里下单,直接从吧台提酒了。如果不问原因,一律加大惩罚力度,那么对员工来说,很简单,为了不被惩罚,就照章办事,让客人等着呗。“不要因为这点小事情把员工的积极性给挫伤了,一个服务员的积极性比一瓶五粮液值钱多了!”袁华强相信,这种事大多是员工偶然疏忽造成的。最后确定的处理办法还是具体事情要具体分析处理。基于一切以为客户服务为重和对员工的信任,海底捞给一线服务员的授权很大,包括可以为客户免单的权力。每个员工都有一张卡,员工在店里的所有服务行为,都需要刷卡,记录在案。这种信任,一旦发现被滥用,则不会再有第二次机会。

  “公司给你的总是超出预期,所以就会死心塌地地为公司干。”2007年7月通过猎头公司进入海底捞的现任物流中心副总的高岩峰,这样谈出自己的体会。刚进入公司一个月,他就参加了公司安排的西交大MBA为期1年的学习,每次上课来回的飞机票和其他费用都由公司方面支付。今年年初,公司又把比较核心的技术部门交给过去并无经验的他来管理,对于他这个“外人”而言,“实在是没想到”。高岩峰在公司里被大家称为“高老师”,因为有些员工拜他为师,学习采购和物流管理。

  经朋友介绍,小厉进入公司才一个多月,脸上的笑容很由衷,“生活上没什么好担心的,只要好好干就行了。”年轻的她已经听到公司里很多从普通的服务人员升到领班甚至店经理的例子。一位顾客想再要一个火锅小料,开玩笑地问她:“能送吗?”迅速地思考了一下,小厉爽快地说,“能,我去给您拿!”

  鼓励每位基层员工参与创新,是海底捞信任平等的价值观里的重要组成部分。公司总经理办公会为此专门下了文件,员工提出的每项创新建议都会有专门的记录和片区经理的意见及总经理评价。因为这项工作,诞生了诸如“鱼滑”、“虾滑”等专门的制作模具,这些已被公司广泛推广。

      海底捞对干部的考核非常严格,在张勇的办公室墙上,张贴着对店长以上干部的考核表,考核分了多个项目,除了业务方面的内容之外,还有创新、员工激情、顾客满意度、后备干部的培养,每项内容都必须达到规定的标准。"我们优秀店长的产生不跟他所管理店的命运成正比,评选优秀店长不看他赚了多少钱,看的是员工激情,看的是顾客满意度,看的是后备干部的培养。他哪怕赚很多钱,他的利润始终是公司最高,也很可能由于在这几个问题上出了漏洞而被撤掉,比如不久前牡丹园的店长被撤掉了,他在我们公司的业绩也很好,但就是员工激情和顾客满意度达不到。"

    这几项不易评价的考核内容,海底捞都有自己衡量的标准。例如"员工激情",总部不定期的会对各个分店进行检查,看员工的注意力是不是放在客人的身上,看员工的工作热情和服务的效率。如果有员工没有达到要求,就要追究店长的责任,"你平时是怎么要求的?你是怎么带动的?"一次可以原谅,可以给机会,几天后再派人检查,员工的服务是否快速、准确、热情,是否能够马上完成顾客的要求,是否快速准确,大方得体。

    海底捞的店长都有很大的权利。总部每月会拿出利润的一部分作为每个店的奖金,这些奖金全部由店长来分配,他必须全面考察下属的业绩,如是大家都没有达到要求,不分也可以,只是唯独不能分给自己。海底捞目前的直营分店已有17家,分布于西安、北京、郑州、上海,这么多分店,分配结果又都是各店自己报告上来的,如何保证每位管理者都能真正做到公平公正?张勇告诉记者,"有不公正的可能,但是千万不要太明显,他的一切作为必须让绝大多数员工接受,如果大家不能接受的话,他的领导力与影响力会下滑、业绩会下滑。"并且,海底捞有一个公开信息源监督制度,每一个分店都会选举两个普通员工做信息源,对本店管理方面出现的一些问题以书面形式向总部反映,每个月都必须要有,张勇看过后,再转到监察部备案、核实。如果确定反映的问题属实,就会转给该部门的领导进行处理。

    尊重与关爱,创造和谐大家庭

    海底捞的管理层都是从最基层提拔上来的,他们都有切身的体会,都了解下属的心理需求,这样,他们才能发自内心地关爱下属,并且给予员工工作与生活上的支持和帮助,同时也得到员工的认可。张勇笑着举例,"如果将北京区的总经理换成一个从美国回来的博士,相信不到半年就乱套了。员工不认可你,你讲的再好,你的理念再好,员工与你不是一条心,不听你的,没办法!"

    海底捞的员工,大部分来自农村,他们的需求非常简单,有时候管理层多冲他笑一笑,给他一个领班,给他一个机会,他就满足了。

    在海底捞,尊重与善待员工始终被放在首位。从2003年7月起,海底捞实行了"员工奖励计划",给优秀员工配股,以西安东五路店作为第一个试点分店,规定一级以上员工享受纯利率为3.5%的红利。2005年3月,又推出第二期"员工奖励计划",以郑州三店作为员工奖励店给优秀员工配股,并且经公司董事会全体董事一致同意,从郑州三店开始计算,公司每开办的第三家分店均作为员工奖励计划店。

    海底捞的管理人员与员工都住在统一的员工宿舍,并且规定,必须给所有员工租住正式小区或公寓中的两、三居室,不能是地下室,所有房间配备空调、电视,电脑,宿舍有专门人员管理、保洁,员工的工作服、被罩等也统一清洗。若是某位员工生病,宿舍管理员会陪同他看病、照顾他的饮食起居。

    海底捞的所有岗位,除了基本工资之外,都有浮动工资与奖金,作为对员工良好工作表现的鼓励。同时,考虑到绝大部分员工的家庭生活状况,公司有针对性的制定了许多细节上的待遇:在海底捞工作满一年的员工,若一年累计三次或连续三次被评为先进个人,该员工的父母就可探亲一次,往返车票公司全部报销,其子女还有3天的陪同假,父母享受在店就餐一次;工作年满一年以上的员工可以享受婚假及待遇;工作满3个月以上的员工父母去世,该员工可以享受丧假及补助;工作3年以上的员工可享受产假及补助;若夫妻在同一地区工作,只要有一方工作满半年,在外租房就可以享受每月60元的补助,已婚的店经理则可享受400元以内的住房补助;店经理小孩3岁以下随本人生活的,还可享受每月300元的补助……

    在尊重与善待员工的问题上,海底捞还有不少"创意".例如,将发给先进员工的奖金直接寄给他的父母。张勇说,"这不仅仅是400块钱的事情,400块钱对于农村也许很重要,但更重要的是,他父母有了荣耀。

    海底捞的员工,有很多都是亲属,这在许多企业都是禁止的。张勇却认为,"正因为员工在海底捞获得了尊重和认可,同时他也认可了这里的工作环境与和谐的氛围,他才会介绍亲戚朋友们来。"

    关于员工的夫妻生活、子女教育问题,许多企业规定,服务员不能和厨师谈恋爱,高级管理人员配偶不能与其在同一个地区同一个城市,"这种规定是很不人道的,我们的做法相反,会尽量把他们吊在一块儿,让他们一起工作,一起生活。公司会发给他们补贴,鼓励他们住在一起,并且把孩子带着身边,自己照顾和教育孩子。"不仅如此,海底捞店长以上的干部,公司还会帮助他们联系其子女入学,并且代交入学赞助费。

posted @ 2009-11-04 18:50 CowNew开源团队 阅读(2049) | 评论 (2)编辑 收藏

现在有的网站为了防止其他人转帖他们的内容而不写“转帖自。。。”,在你复制它网页内容的时候会自动增加“本文来自于如鹏网”这样的额外的文字。这本来无可厚非,但是它们的原理是首先监听用户的复制事件,当复制动作发生的时候取得用户选择的内容,在内容后添加“本文来自于如鹏网”,然后在用clipboardData.setData设置新的粘贴板内容,但是clipboardData.setData只支持Text、URL两种格式,无法设置HTML格式的粘贴板内容,因此造成复制出来的内容粘贴的时候一些html格式都丢失了,比如字体颜色、表格等等,非常麻烦。
如果使用Maxthon浏览器,有如下两种解决思路:
1、思路1
(1)选中要复制的部分,点击右键选择“查看选定区域源代码”;
(2)在弹出的记事本中将文件另存为htm文件,也就是文件名中输入“1.htm”之类的带htm后缀的文件名。
(3)用浏览器打开刚才保存的htm文件,全选,复制就可以了。
2、思路2(推荐方法)
(1)选择主菜单的【工具】→【内容控制】→【禁止运行Javascript】,然后就可以任意的复制而没有“零碎”了
(2)复制完了再次选择主菜单的【工具】→【内容控制】→【禁止运行Javascript】,将【禁止运行Javascript】前的勾选去掉即可。

使用普通的IE浏览器有如下两种解决思路:
1、思路1
(1)选中要复制的部分;
(2)在地址栏中输入
javascript.:var bjSelection = document.selection;var bjTxtRange=objSelection.createRange();clipboardData.setData("text",objTxtRange.htmlText);alert("复制成功");
然后回车,这时候IE7、IE8浏览器可能会提示是否允许操作剪贴板,点击【允许访问】即可。
(3)打开记事本,Ctrl+V粘贴,然后另存为一个htm文件,也就是文件名中输入“1.htm”之类的带htm后缀的文件名。
(4)用浏览器打开刚才保存的htm文件,全选,复制就可以了。
原理就是地址栏中的javascript代码会被执行,这段代码的作用就是将选中部分的HTML拷贝到剪切板中(关于代码的详细解释参考这篇文章《 取得网页选中部分HTML的方法 》 ),由于添加“零碎”的代码没有对此进行控制(也无法控制),因此复制出来的HTML就是没有零碎的了,保存成htm再复制就带格式同时没有零碎了。

2、思路2 禁用javascript
(1)打开internat选项,选择安全标签,
(2)点击下方的自定义级别,这时会弹出安全设置对话框,拖动滚动条找到图示脚本-活动脚本,并选择禁用;
(3)再复制内容就不会有零碎了。

原理:因为添加“零碎”的原理是监听用户的复制事件,然后向复制的内容中添加“零碎”,这些逻辑都是javascript代码,我们禁用IE的javascript,这样那些代码就不会执行了。

很显然Maxthon中的两种方法和IE中的两种方法原理都是一样的,不过Maxthon的功能帮我们省了很多事情。
posted @ 2009-10-22 16:40 CowNew开源团队 阅读(1032) | 评论 (0)编辑 收藏

昨天网站虚拟主机提供商发送提醒邮件说我的网站“如鹏网”流量超标了,很奇怪,上个月流量用了一半多一点儿,这个月网站访问量并没有明显的上升,怎么会这个月才过20天就流量超标了呢?到网站后台查看流量报表才发现agent.php消耗了31%的流量,将近1/3呀。

agent.php就是为“如鹏助手” 提供数据的api页面,默认如鹏助手每10秒钟就会向这个页面请求最近50条新帖和50条新回复。当时开发的时候也考虑过这个功能会不会对网站流量有非常大的消耗,但是当时没有进行科学的计算,想当然的认为不会。但是现在仔细一算,50条新帖、50条新回复的信息估计有100K,那么每分钟请求6次,假设每天监控15小时,每个月30天,那么一个月的流量就是100K*6*60*15*30=16200000k=16200M=16.2G,恐怖呀!!!网站每月限定流量是45G,正好是16.2/45=36%,估算和报表中的31%差不多。

因为网站流量已经超标,因此必须买额外的流量才能保证网站正常运行,10G的流量一个月20元,买流量就要买足剩下10个月的,10个月就是200元,本来这部分花费是可以避免的。当初花几分钟算一下就不至于犯这种错误!

不要再拍脑袋,要科学的计算!!!!!!!!!

为了减少如鹏助手流量消耗,我做了如下的优化:
1、agent.php不再传输全部的帖子内容,帖子正文只传输前50个字。
2、去掉agent.php传输帖子中的空格等无意义字符。
3、因为如鹏网现在发帖量不大,没必要每次显示50条最新贴,因此改为只传输10条最新贴。
4、在agent.php头部加入“Ob_Start('ob_gzhandler');”,也就是启用GZip压缩网页,减少网页的流量传输。
5、降低如鹏助手的刷新频率,由10秒刷新一次改为60秒刷新一次
经过本次优化,10条新帖、10条新回复的信息估计有6K,6K*1*60*15*30=162000K=162M=0.162G。这样流量消耗基本可以忽略不计了。

不要再拍脑袋,要科学的计算!!!!!!!!!
posted @ 2009-10-20 12:06 CowNew开源团队 阅读(2309) | 评论 (5)编辑 收藏

修改于http://blog.csdn.net/majianan/archive/2008/12/30/3646565.aspx
使用的这个TabPane已经有了TabPane的所有功能。
不过我想增加一个功能,就是:
1、每隔一段时间,选项卡自动切换到下一页。
2、当用户点击TabPane内任意一个选项卡的时候自动切换停止。

代码下载: http://bbs.blueidea.com/viewthread.php?tid=2952907&page=1&extra=page%3D1

使用方法参考附件rupengtabpane.zip中的test.htm
TabPane类构造函数有三个参数,第一个参数是占位div的id,第二个、第三个都是可选参数,第二个为自动切换的时间间隔,单位为秒,默认值为10,第三个为是否启用自动切换,默认值为true
tabPane.js中还提供了一个function randint(m,n)函数,用于产生一个changeTabInterval的随机数,防止页面上TabPane过多,如果设置的changeTabInterval都一样的话会产生整齐划一的切换的效果,不好看,因此用它产生随机的Interval给TabPane类构造函数的第二个参数。

                                   <script>
                                 var tp = new TabPane("divGlobalNew",15);
                                 tp.addTabPage({title:"论坛新帖" ,width:80 ,panel:"divGlobalNewThreads"});
                                 tp.addTabPage({title:"论坛新回复" ,width:80 ,panel:"divGlobalNewReplies"});     
                                   </script>  
       
演示地址:http://www.rupeng.com/forum
posted @ 2009-10-14 13:45 CowNew开源团队 阅读(1907) | 评论 (1)编辑 收藏

假设Jetty监听的端口是8080,
1、首先修改/etc/lighttpd/httpd.conf,查找

server.modules=部分
不要动"mod_proxy_core"等前面的注释,在之前插入"mod_proxy",
保存,退出。
2、进行代理设置,修改/etc/lighttpd/httpd.conf(如果使用的是kloxo之类的虚拟主机管理系统,那么修改/etc/lighttpd/conf/kloxo中相应虚拟目录下的可能更好,比如我修改的就是/etc/lighttpd/conf/kloxo/lighttpd.so.rupeng.com)
在尾部增加:
$HTTP["host"]=="so.rupeng.com"{
proxy.server=(""=>(("host"=>"127.0.0.1","port"=>8080)))
}

3、执行“/etc/init.d/lighttpd restart”重启lighttpd即可。



posted @ 2009-10-10 16:15 CowNew开源团队 阅读(1117) | 评论 (0)编辑 收藏

看很多人在乐此不疲的找卡巴斯基的Key。其实kav一年的key才30块钱,花几十块钱买个key够用1年的,省得浪费时间再去找key。浪费找key的时间不止30块钱吧?
就按月薪9000算,一天平均300元,平均一小时30元,想一下一年时间用来找key的时间早就超过1小时了吧,看起来是省钱了,其实是浪费了
posted @ 2009-10-01 15:06 CowNew开源团队 阅读(779) | 评论 (2)编辑 收藏

有时候需要在discuz基础上增加一些自定义的功能,不免要自己建表,自己建表就涉及到数据备份的问题,一般情况下就要写自己的备份功能。不过在discuz中只要自定义表的表名以discuz表名的前缀开头(一般都是cdb_),那么discuz就会自动将其加入discuz的备份体系。不用单独维护了,:)

如鹏网 http://www.rupeng.com 在校不迷茫,毕业即辉煌
posted @ 2009-09-25 15:41 CowNew开源团队 阅读(324) | 评论 (0)编辑 收藏

前一阵子看我以前一位同事的MSN签名是“面对它,处理它”,感觉收获非常大。以前做事情经常会拖延,以为逃避问题的话问题就说不定自己就解决了,现在每次要给自己拖延理由的时候我都会想起这句话“问题怎么逃避也逃避不了,面对它,处理它”。

比如前两天由于不知道的原因我提交给公司财务部的报销票据财务部找不到了,没法报销,一开始就想“反正就几百块钱,认倒霉了,再去折腾肯定特麻烦,不管它了”。但是朱老师一直催促我说“抓紧办,麻利的!”,我就联系财务部、联系主管领导,用了工作间隙的几个小时时间就办好了,打了几个电话就办成了,根本没有之前想象的那么复杂。
问题没什么大不了的,碰到问题不要想着怎么躲开它,而是用积极的心态去处理它,“面对它,处理它”。

由此想到以前上大学的时候有一段时间学《自动控制原理》的时候看着那些公式推导就头大,碰到一道难题就像“不管它了,先跳过去”,一个晚自习竟然发现自己整晚上都在“跳过去”,根本没做什么事情,后来调整了自己的心态,“蚂蚁啃骨头”一样的啃那些题,发现很快就明白了,其实离以前我“跳过去”的理解程度也没差不多,只不过多努力了一点儿而已。

又想到很多同学学编程的时候,碰到一个难写的程序、莫名的bug,只要稍微解决不了了,就开始抓狂,并且质疑自己“是不是处理不了这个问题了”,然后就放弃或者去论坛上求助别人,但是很有意思的是看到很多同学在论坛发的提问帖后没几分钟就又自己回复帖子“问题已经解决了”,呵呵,其实遇到问题的时候不要抓狂、不要放弃,“面对它,处理它”,没什么大不了的!

如鹏网上的hackhou同学去年春节的时候一直不找工作,我和他交流,发现他的想法是“找工作太麻烦,不想去想,还是自己在家里写程序能忘掉烦恼”,我就劝他“现在的主要问题是去找工作,而不是用写程序麻醉自己;你躲着求职并不会使你找工作的问题得到解决,也不会使得工作自己找上门来,快去找工作!”,听了我的建议他出去找工作了,没想到没几天时间就找到了满意的工作!

面对它,处理它;不逃避,直面问题解决问题,问题终将会得到解决的!
posted @ 2009-09-25 11:24 CowNew开源团队 阅读(1700) | 评论 (2)编辑 收藏

package com.rupeng.search.discuz;

import java.net.URLConnection;

import org.htmlparser.Parser;
import org.htmlparser.Tag;
import org.htmlparser.tags.Div;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;
import org.htmlparser.visitors.NodeVisitor;

public class DiscuzDefaultStyleHTMLParser
{
 private String title;
 private String bodyText;

 public DiscuzDefaultStyleHTMLParser(URLConnection urlConnection) throws ParserException
 {
  Parser parser = new Parser(urlConnection);
  HtmlPage visitor = new HtmlPage(parser);
  parser.visitAllNodesWith(visitor);
  this.title = visitor.getTitle();
  NodeList nodeList = visitor.getBody();
  final StringBuffer sb = new StringBuffer();
  nodeList.visitAllNodesWith(new NodeVisitor() {

   @Override
   public void visitTag(Tag tag)
   {
    //因为主题、回帖都是包含在Div里,而且主题、回帖的divid都是以“postmessage_”开头
    if (tag instanceof Div)
    {
     Div div = (Div) tag;
     String divId = div.getAttribute("id");
     if (divId != null&& divId.startsWith("postmessage_"))
     {
      sb.append(div.getStringText());
     }
    }
   }
  });

  this.bodyText = sb.toString();
 }

 public String getTitle()
 {
  return title;
 }

 public String getThreadText()
 {
  return bodyText;
 }
}

posted @ 2009-08-13 19:26 CowNew开源团队 阅读(687) | 评论 (0)编辑 收藏

一、关于 realtek hd audio 装不上驱动的问题:
首先,要针对你的操作系统打上微软的音频补丁,本文针对 XP SP2系统。对于SP2系统,请你先打上KB888111补丁,这个网上有下载!搜索一下吧!

打上补丁以后,在设备管理器的系统设备里面出现一个带“!”的“PCI bus”设备,手动安装驱动找到HdaudBus.sys(这个微软的KB888111补丁里面有带的,如果不能自动找到就将KB888111XPSP2解压,commonfiles里可以找到。)开始安装,安装完后会在系统设备里面多出一个微软的UAA BUS 的设备驱动,重启以后自动安装驱动就可以了。

这时,驱动安装就已经完成。

其实sp2以后的系统这个貌似可以自动驱动!

下面说说麦克风无声的问题!

二、安装好驱动后,有时会发现麦克风是灰色的,不能说话的问题:

这个可能是你设置的问题,如何解决呢?

HD audia 是一种新的音频规范,不同于以前的AC97,驱动安装好以后在你的控制面板里和系统的任务栏里面都有一个配置程序。

在这里,我们要先打上HD的声卡补丁,把rtkhdaud.dat文件复制到C:\WINDOWS\system32\drivers下,并必须重新启动计算机。

补丁下载:点击下载

重启后,让我们来看一下realtec的设置,在这里或者在右下角点打开。

然后就到这里。

点上图中的混频器,我们就可以看到,打完补丁后的录制界面会变成下图这样,也就是,下面四项可调了。我产把这四项的声音全部都调到最大,然后选中麦克风(麦克风下面的那个黄点选中)。

接下来看音频输出项(HD Audio output),也就是上一排的重放栏。通过 < 和 > 我们可以看到全部项,注意用红色框圈住的那两项,请取消静音,去掉这两个X,并且音量调到最大。

接着,我们点一下最上面的,和混频器一排的,音频IO,按下图标示1的位置,将喇叭数设为选择8CH,这样设声音会大一些。然后再点2的位置,进入3,接头设置,禁用前面板检测,也就是,在前面打上对勾。

最后,重新插一下耳机和麦克风,注意这里,这也是容易被大家忽视的,一定不能勾选错,选错了同样不能用,具体是这样的:

当你插入耳机时会弹出来下图,一定要选耳机。

 

当你插入麦克风时会弹出来下图,一定要选麦克风。

打开控制面板--声音设备--声音和音频设备

 

高级 -选项--属性

 

选中rear pink in (麦克风要插在后面板的粉红色插口中,插在前面板相应设置Front pink in)

 

这时候麦克风的音量就可以设置了,还可以点高级使用 麦克风加强 (小心震耳朵)

 

这时候再点选项--属性--选中 Audio input 如下图所示

 

确定之后,把录音音量调到最大

 

这时候打开QQ的音量调节,声音输入输出按照下图设置,试试效果吧



http://www.blogjava.net/Files/huanzhugege/Realtek%20HD%20Audio录音声音小的解决方法.zip

posted @ 2009-07-28 23:38 CowNew开源团队 阅读(2309) | 评论 (0)编辑 收藏

远离新版本软件,拒当小白鼠

本文是专门为在校生写的,是看到了很多同学把很多精力放到折腾这种各样的新软件而忽略了正路的学习有感而发,不是针对那些有太多时间研究新东西、有志于改善世界上所有软件、要解放全人类的牛人。
=================================================================================================

刚才帮一个同学解决一个在IE8下在如鹏论坛无法发帖的问题。由于如鹏论坛使用的Discuz系统的验证问答功能对IE8支持有Bug,所以新用户无法发帖。验证问答功能是防止垃圾广告的一个有效手段,但是对IE8、Opera、chrome等非主流浏览器支持有Bug。刚才为了能让这个同学发帖,我就暂时关闭了验证问答功能,但是刚关闭了,就来了一大堆垃圾广告贴。所以我就赶紧又把验证问答功能打开了。所以以后使用IE8、Opera、chrome等非主流浏览器访问如鹏论坛的时候会有这样那样的问题,现在也没有精力解决这些问题,只能满足大多数同学的需求了。
    我以及很多同事都有一个新习惯,绝对不拿新软件尝鲜。因为新软件千好万好,但是经验证明新软件会给我带来麻烦而不是方便。当年XP刚推出的时候,我还在上学,很多同学抢着装,我就还是Win2000坚持不动摇,当时大部分软件都能在Win2000下跑的很好,而很多软件对XP兼容性不是很好,所以他们一直在跟XP做斗争,我则用着Win2000做着该做的事,编着该编的代码。碰到问题当时网上介绍的方法都是在Win2000下的解决方案。这节省了很多时间。毕竟操作系统、电脑只是工具,是要工具为你服务,不是给你添乱。
    还有当初IE7推出的时候,很多人尝鲜用IE7,可是很多网站都对IE7支持有问题,到最后干什么都干不了。而那些用IE6的人则干着该干的事情,一点时间、精力都没浪费。
    IE8推出来了,我相信它很好,我相信它比IE6、IE7都好,比别的浏览器都好,可是有一点,很多网站用IE8看都有问题,那我用IE8干什么,给自己找那个麻烦干什么。有同学说“IE8用起来快”,由于网站对IE8支持有问题导致你你一个帖子半个小时都发不出去,节省的那点时间早就浪费没了。浏览器的目的是上网,不是给别人当小白鼠。我估计早晚有用IE8的那一天,但是那一天是所有网站都对IE8支持没问题我再用IE8。我不当小白鼠。
    Vista推出来了,同学们争着用,可是各个软件在Vista上装的都有问题,那不是给自己找闲事儿吗?竟然还有同学用Windows7,Win7和IE8现在都是测试版,各个软件的兼容程度可想而知,给自己找那个麻烦干什么?等主流软件都支持他们在说吧。有同学说Windows7兼容性可好了,可是再好有XP好吗?只要没有的话你就有可能运行一个别人能跑你不能跑的软件,给自己添那个麻烦干什么。别人在拿着书在运行着代码,你却在为着开发工具和操作系统的兼容性艰苦奋斗着,何必活的那么累呢。
    我现在从事的银行系统软件开发中,一个新技术推出以后必须经过其他客户至少三年的验证和升级以后才会考虑使用,就是基于这样的考虑,毕竟工具是给人用的,不是给人添麻烦的。

远离新版本软件,拒绝当小白鼠!
==================================================
本文是专门为在校生写的,是看到了很多同学把很多精力放到折腾这种各样的新软件而忽略了正路的学习有感而发,不是针对那些有太多时间研究新东西、有志于改善世界上所有软件、要解放全人类的牛人。

posted @ 2009-06-11 10:31 CowNew开源团队 阅读(2245) | 评论 (27)编辑 收藏

首先说一下我的网站(www.rupeng.com)的结构,discuz论坛放在了网站根目录的forum目录下,论坛的附件目录并没有使用默认的/forum/ attachments,而是我把论坛附件也挪到了网站根目录的“/forum_attachments”下,因此我在discuz后台将【附件保存位置】修改为“./../forum_attachments”(discuz文档中说“相对目录务必以 "./" 开头”)。然后同时启用了“远程附件”。
经过上面的修改以后我发现当上传的附件超过“附件尺寸下限”的时候提示“附件文件无法保存到远程服务器,请与管理员联系”,也就是上传远程附件失败。经过调试discuz代码发现了问题所在,确认是discuz的Bug。
Bug在include/post.func.php的ftpupload函数中,如果是上传的远程附件,那么假设$source参数传过来的是“/www/users/cownew.com/forum/./../forum_attachments/month_0906/20090602_8af8as9dfas8du9823898898.rar”,后面的代码把$source传递给了dftp_put函数,但是好像dftp_put函数对这种有点复杂的路径“/www/users/cownew.com/forum/./../forum_attachments/month_0906/20090602_8af8as9dfas8du9823898898.rar”识别有Bug,因此我在ftpupload函数的一开始加入一句“$source=realpath($source)”来将这个复杂的相对路径转换为绝对路径。这样问题就解决了。

我采用的是康盛的虚拟主机,昨天晚上康盛的技术人员整个晚上都在帮我解决这个问题,虽然最终还是我自己发现discuz的这个Bug,但是还是非常感谢康盛的虚拟主机技术人员,他们非常尽职,而且服务器也非常稳定,用康盛的主机一年以来只碰到过两次持续时间不超过半小时的服务器被DDOS攻击和一次MYSQL故障,相对其他IDC来说稳定性已经非常好了,推荐大家使用康盛的IDC。
posted @ 2009-06-02 22:21 CowNew开源团队 阅读(1759) | 评论 (0)编辑 收藏

以前一直使用卡巴斯基杀毒软件,用过半年360安全卫士赠送的卡巴斯基授权文件,又用了一个月的试用版,今天试用到期。看到网上很多人在费劲找授权码,我也试着找了找,但是最终还是决定购买授权码,做一个“正版人”。

我是基于以下几点考虑的:
1、人家千辛万苦开发出来的软件不容易,做为软件从业者的我们更知道开发一个软件的艰辛和耗费巨大的财力,卡巴斯基是非常优秀的杀毒软件,为它的服务付费理所应当;
2、我们是未来的计算机从业者,如果连我们都不尊敬同行,使用盗版软件,以后难道能要求别人尊敬我们的劳动成果吗;
3、也许浪费几个小时能找到能用的授权码,但是浪费这几个小时我可以看看书,可以去做一点其他事情,获得的收入比那几十块钱的正版软件费用多得多。
4、软件的生产商要吃饭,没人会饿着肚子为你开发软件,大家都不肯购买暴风影音,所以暴风影音只有靠在软件中放广告赚广告费,有的人竟然骂暴风影音放广告是“流氓行为”,真不知道谁是流氓。暴风影音在这次DNS事件中的唯一责任就是软件中不应该频繁的重试连接自己的服务器,仅此而已。不花钱用软件人家就要放广告,难道要人家替你免费打工?
5、用盗版软件是违法的;

我购买的是“卡巴斯基反病毒软件2009”一年的授权,全价40元,太便宜了,5月份使用优惠券代码为:232346472323385738 还可以打九折,也就是36元,有购买的同学记得使用这个优惠代码。
posted @ 2009-05-28 14:26 CowNew开源团队 阅读(326) | 评论 (0)编辑 收藏

修改discuzcode.func.php中discuzcode方法,
修改最后一行的return $htmlon || $allowhtml ? $message : nl2br(str_replace(array("\t", '   ', '  '), array('&nbsp; &nbsp; &nbsp; &nbsp; ', '&nbsp; &nbsp;', '&nbsp;&nbsp;'), $message));


 $tempstr= $htmlon || $allowhtml ? $message : nl2br(str_replace(array("\t", '   ', '  '), array('&nbsp; &nbsp; &nbsp; &nbsp; ', '&nbsp; &nbsp;', '&nbsp;&nbsp;'), $message));
 $tempstr= str_replace("&amp;#160;","&nbsp;",$tempstr);//code标签在粘贴一些代码的时候会把一些空格替换成"&amp;#160;"从而出现乱码,这是暂时性的解决策略,不严谨,不过一般没问题 by 杨中科
 return $tempstr;
 

posted @ 2009-05-22 23:29 CowNew开源团队 阅读(279) | 评论 (0)编辑 收藏

1、编写rewrite脚本,编辑/etc/lighttpd/local.lighttpd.conf内容如下:
url.rewrite-once = (
        "^/forum/archiver/((fid|tid)-[\w\-]+\.html)$" => "forum/archiver/index.php?$1",
        "^/forum/forum-([0-9]+)-([0-9]+)\.html$" => "forum/forumdisplay.php?fid=$1&page=$2",
        "^/forum/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$" => "forum/viewthread.php?tid=$1&extra=page%%53D$3&page=$2",
        "^/forum/space-(username|uid)-(.+)\.html$" => "forum/space.php?$1=$2",
        "^/forum/tag-(.+)\.html$" => "forum/tag.php?name=$1"
)
这里假设论坛装在forum目录下,如果是装在根目录下则是:
url.rewrite-once = (
        "^/archiver/((fid|tid)-[\w\-]+\.html)$" => "archiver/index.php?$1",
        "^/forum-([0-9]+)-([0-9]+)\.html$" => "forumdisplay.php?fid=$1&page=$2",
        "^/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$" => "viewthread.php?tid=$1&extra=page%%53D$3&page=$2",
        "^/space-(username|uid)-(.+)\.html$" => "space.php?$1=$2",
        "^/tag-(.+)\.html$" => "tag.php?name=$1"
)

2、重启lighttpd,重启方法:/etc/init.d/lighttpd restart

posted @ 2009-05-16 21:41 CowNew开源团队 阅读(1146) | 评论 (0)编辑 收藏

RewriteEngine on

RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^http://rupeng.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://rupeng.com$ [NC]
RewriteCond %{HTTP_REFERER} !^http://www.rupeng.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://www.rupeng.com$ [NC]
RewriteCond %{HTTP_REFERER} !^http://www.tinyosstudy.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://www.tinyosstudy.com$ [NC]
RewriteRule .*.(jpg|jpeg|gif|png|bmp|rar|zip|exe|pdf|attach|chm)$      http://www.rupeng.com


一定要注意保存为Unix格式。有的版本的IE“另存为”发送的referer为空,所以加上第一行“RewriteCond %{HTTP_REFERER} !^$ [NC]”
posted @ 2009-05-04 13:37 CowNew开源团队 阅读(357) | 评论 (0)编辑 收藏

付费解决疑难问题:

杨中科是国内知名的技术图书作者和IT培训讲师,经验丰富,详见百度百科:http://baike.baidu.com/view/1607669.htm 

杨中科在各种主流语言和技术平台上都有过丰富的经验,善于处理各种疑难问题,把您的技术难题提交给我,包您满意。
支付方式: http://item.taobao.com/auction/item_detail.jhtml?item_id=040979d74ff665498567ed0848fc5bf7
支付后和我连接解决问题,对于特别疑难的问题不排除加价的可能。

开源收费服务:

负责解决CowNew开源相关产品的问题,包括使用咨询、产品定制、二次开发、培训等。

服务费以500元为单位,具体费用需要协商。


支付方式:http://item.taobao.com/auction/item_detail.jhtml?x_id=0db2&item_id=237dfa9931ab86dcdd6a2a7a9179c05d
posted @ 2009-03-14 00:07 CowNew开源团队 阅读(274) | 评论 (0)编辑 收藏

     摘要: 第一部分 AppWizard及其工作原理 AppWizard即应用程序向导,它是Visual Studio开发环境中强大的编程工具之一,用它可以创建各种不同类型的程序。比如Win32应用、ATL、MFC应用等等。在Windows的术语中,向导(wizard)一词指得是一个应用程...  阅读全文
posted @ 2009-03-08 00:04 CowNew开源团队 阅读(964) | 评论 (0)编辑 收藏

当自定义的应用程序向导生成一个项目时,则它只是不能替换自动创建的.dsp 项目设置文件。 .dsp 文件中的项目设置由假定所有生成的项目为 MFC 项目的内部规则设置。 但是,Visual C++ 5.0 的新对象模型允许修改工具设置,以便从生成的项目中删除所有依赖 MFC 的自定义 AppWizards。

Visual C++5.0 CCustomAppWiz 类现在具有名为 CustomizeProject 在虚拟重写。 CustomizeProject 提供与 IBuildProject 接口自定义向导。 IBuildProject 配置方法提供了一个的 IConfiguration 界面,用于在项目中每个生成配置。 IConfiguration 可以添加和删除如编译器提供给工具的设置。 在使用这些方法自定义向导可以删除在 MFC 上添加依存关系的设置。

示例代码

以下是示例 CustomizeProject 重写的演示 MFC 依赖项的删除:
   #import "c:\Program Files\DevStudio\SharedIDE\bin\ide\devbld.pkg"
void CNoMfcCustWizAppWiz::CustomizeProject(IBuildProject* pProject)
{
using namespace DSProjectSystem;
long lNumConfigs;
IConfigurationsPtr pConfigs;
IBuildProjectPtr pProj;
// Needed to convert IBuildProject to the DSProjectSystem namespace
pProj.Attach((DSProjectSystem::IBuildProject*)pProject, true);
pProj->get_Configurations(&pConfigs);
pConfigs->get_Count(&lNumConfigs);
//Get each individual configuration
for (long j = 1 ; j < lNumConfigs+1 ; j++)
{
_bstr_t varTool;
_bstr_t varSwitch;
IConfigurationPtr pConfig;
_variant_t varj = j;
pConfig = pConfigs->Item(varj);
// Remove Preprocessor def for MFC DLL specifier, _AFXDLL
varTool   = "cl.exe";
varSwitch = "/D \"_AFXDLL\"";
pConfig->RemoveToolSettings(varTool, varSwitch, varj);
varTool   = "rc.exe";
varSwitch = "/d \"_AFXDLL\"";
pConfig->RemoveToolSettings(varTool, varSwitch, varj);
// OPTIONAL
// Add Libs that MFC headers would have pulled in automatically
// Feel free to customize this listing to your tastes
varTool = "link.exe";
varSwitch = "kernel32.lib user32.lib gdi32.lib winspool.lib "
"comdlg32.lib advapi32.lib shell32.lib ole32.lib "
"oleaut32.lib uuid.lib odbc32.lib odbccp32.lib";
pConfig->AddToolSettings(varTool, varSwitch, varj);
}
}
本代码示例使用 Visual C++ 5.0 的新 COM 编译器支持功能的说明。 # import 语句导入,并创建 DEVBLD.PKG 类型库的所有类型的定义。 这将允许使用窗体 IInterfacePtr 的 COM 智能指针,以及新的 _ bstr _ t 和 _ variant _ t 类型代码。 这些新类型的所有自动清理使用的内存,并在超出范围时释放保持的接口指针。

此外请注意标准的自定义应用程序向导将使用预编译的头文件 StdAfx.h。 应当将放 # import # 结尾处的语句 StdAfx.h 中包含列表。

注意: DevBld.pkg 路径将不同,如果您使用 Visual C++ 版本 6.0。 假设 Visual C++ 版本 6.0 已安装到 C: 驱动器上的默认目录,# import 语句应阅读,如下所示:
   #import "C:\Program Files\Microsoft Visual Studio\Common\MsDev98\Bin\IDE\DevBld.Pkg"
注意: 上面 </a0>-# import 行必须在代码中相同的行。

请参阅有关 Visual C++ 文档。

警告

  • 请注意没有编程的方法可用于删除内部的项目将该控件设置"Microsoft 基础类"设置在常规的项目设置由包含上述代码的自定义向导生成的方式项目仍将显示"使用 MFC 共享 DLL 中"。 您可以更改此设置,唯一方法是不支持修改.dsp 项目设置文件。 但是,此设置仅用于某些 DevStudio MFC 用户界面元素如类向导和一些基于 MFC 的组件库组件。 它应该有一个非 MFC 项目没有影响。
  • 即使后修改项目设置使用 AddToolSettings 和与上面的 RemoveToolSettings,默认项目设置将仍然保持相同 Visual C++ 版本 5.0 中。 如果项目生成此自定义应用程序向导的用户打开项目设置,并单击重置,已还原的项目设置将包含已删除的 MFC 引用。 再次,防止出现这种唯一的方法是使不支持的更改生成的.dsp 项目设置文件手动自定义应用程序向导已创建项目后。

    Visual C++ 版本 6.0 提供新的自动化方法更改默认项目设置的。 配置对象支持 MakeCurrentSettingsDefault 方法。 此方法更改成为当前的设置配置的默认项目设置。
  • 当您使用 RemoveToolSettings 时,删除一次的只有一个工具设置。 在上面示例中进行另一调用 RemoveToolSettings CL.EXE 命令行而不是附加到同一个 varSwitch 语句的末尾删除定义中删除另一个的预处理器定义。 此外,请记住,工具设置的是大小写区分"/ d"和"/ D"不是相同的操作。
  • 遗憾的是,AddToolSettings、 RemoveToolSettings,和 AddCustomBuildStep (另一个 IConfiguration 方法) 运行仅在 Visual C++ 版本 5.0 在整个项目上,他们不能进行工具设置或创建自定义生成步骤单个文件。 是例如最好通常添加处理使用 MIDL 文件并生成 TLB 和其他所需的项目文件的一个项目的 IDL 文件的自定义生成步骤。 在 Developer Studio 97 对象模型不支持此。 单个文件的自定义生成步骤需要自定义应用程序向导生成项目后手动添加。

    Visual C++ 版本 6.0 对象模型不会支持若要更改的方法文件设置,并添加自定义生成步骤的文件。 请参阅 Visual C++ 版本 6.0 文档的下列方法配置对象:
    AddFileSettings
    RemoveFileSettings
    AddCustomBuildStepToFile

转载自:http://support.microsoft.com/kb/173483

大学生计算机学习社区
posted @ 2009-03-08 00:00 CowNew开源团队 阅读(589) | 评论 (0)编辑 收藏

  2005年的时候我大学毕业来到深圳工作,公司负责解决户口,因此户口也就落到了深圳。为啥我要说找个呢?难道我要做“深户担保”?哈哈,我不会贴小广告,具体原因后面你就明白了。

  05年春节我开办了一个开源技术研发组织,因此就创建了第一个网站cownew.com,也就立即备案了,一个礼拜备案就下来了。

  06年底我离开了深圳来到北京发展。转眼到了2008年,我准备创建一个为计算机相关专业提供学习指导服务的网站,所以申请了域名jsj321.com(含义是“计算机321”),然后申请了备案,但是一个多月过去了备案还是没有通过,无奈之下只好花了几十块钱在淘宝网上通过网上那些宣传“快速备案”进行了备案,10分钟就“获得了备案”,6个月之后终于收到哦啊了,计算机321没有通过备案的通知,然后我去备案中心一查原来计算机321买的那个“快速备案”也是上了备案骗子的当了,他们完全是用自己ISP的权限在修改自己手头已有的备案的域名,没过几天他又用这个备案号帮别人“快速备案”了。希望光大站长以后一定不能上这帮人的当,咱们也一起祝愿这些“备案骗子”生孩子没屁眼儿!一气之下计算机321就一直没有备案,2009年随着网站的发展壮大,越来越感到原有域名传播力太差,而且怎么看怎么像垃圾站的域名,所以在会员的帮助下改用了现在的新域名www.rupeng.com (如鹏网),立即备案了,一个礼拜备案就下来了。

  说了一通,到底为啥cownew和如鹏网这么容易备案通过,而计算机321就不容易通过呢?还记得前面我提到的我的户口落在了深圳吗?cownew这个域名备案的时候主办人所在地我当然填的是深圳。而jsj321.com备案的时候由于我在北京,所以主办人所在地我填的是北京,而身份证当然还是深圳的。在备案如鹏网的时候我就想为什么一个备案快一个备案慢的要命呢?我猜是户口的原因,因此我在备案如鹏网的时候主办人所在地也填的是深圳,没想到确实很快就批准下来了。

  这只是我的一个猜想,不过联想到目前的户籍制度,应该是有一定道理的,不是结婚都要回户籍所在地办理的吗?网站备案“回自己家备案”当然会容易很多了。希望正在准备备案的站长可以试一试,也验证一下我的猜想。

posted @ 2009-03-06 23:14 CowNew开源团队 阅读(464) | 评论 (2)编辑 收藏

1、SS在后台:系统设置→搜索优化设置→站点链接URL方式修改为“简短Apache模式”
2、discuz在后台:全局→优化设置→搜索引擎优化→URL 静态化下的几项全部选中。
用记事本建立如下内容文件(要另存为,不能重命名,因为重命名无法重命名为只有后缀的文件名):

RewriteEngine On

# 修改以下语句中的 /discuz 为你的论坛目录地址,如果程序放在根目录中,请将 /discuz 修改为 /
RewriteBase /forum

# Rewrite 系统规则请勿修改
RewriteRule ^archiver/((fid|tid)-[\w\-]+\.html)$ archiver/index.php?$1
RewriteRule ^forum-([0-9]+)-([0-9]+)\.html$ forumdisplay.php?fid=$1&page=$2
RewriteRule ^thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ viewthread.php?tid=$1&extra=page\%3D$3&page=$2
RewriteRule ^space-(username|uid)-(.+)\.html$ space.php?$1=$2
RewriteRule ^tag-(.+)\.html$ tag.php?name=$1


保存到网站根目录。

默认CuteFTP是不会显示.htacess文件的,因为它被Linux认为是隐藏文件,所以需要在cuteftp的过滤器中在弹出的窗口中选中“启用过滤”和“启用服务器端过滤”,并在"远程过滤"中填写"-a"。

posted @ 2009-02-06 00:09 CowNew开源团队 阅读(1013) | 评论 (0)编辑 收藏

1、Validator
2、IsPostBack
3、AutoPostBack。控件离开焦点的时候自动Post。
4、repeater控件的使用。:Repeater控件比以前版本的asp.net好用了,只要 Eval就可以了,不用DataBinder.Eval(container.DataItem,"***"):了,只要Eval("Name")就可以,注意不能丢了前面的“#”。
    <asp:Repeater ID="Repeater1" runat="server">
        <HeaderTemplate>
            嘎嘎嘎
        </HeaderTemplate>
        <ItemTemplate>
        <%# Eval("Name")%>
        <%# Eval("Desc")%>
        </ItemTemplate>
    </asp:Repeater>

        protected void Button3_Click(object sender, EventArgs e)
        {
            List<Person> list = new List<Person>();
            list.Add(new Person(){Name="芭芭拉",Desc="白牙呗"});
            list.Add(new Person(){Name="奥巴马",Desc="黑黝黑"});
            Repeater1.DataSource = list;
            Repeater1.DataBind();
        }
5、DataList控件:
(1)行的高亮选中
     <asp:DataList ID="DataList1" runat="server" >
        <SelectedItemStyle BackColor="#FF6666" />
    <ItemTemplate>
        <%# Eval("Name")%>
        <%# Eval("Desc")%>    
        <asp:LinkButton ID="LinkButton1" runat="server" Text="选择" CommandName="select" />  
    </ItemTemplate>
    </asp:DataList>
核心是CommandName这个属性,可选值还有edit、delete等可选值,当按钮被点击的时候将会执行EditCommand、DeleteCommand等事件。
(2)行的在位编辑:
    <asp:DataList ID="DataList1" runat="server"
        oneditcommand="DataList1_EditCommand">
        <SelectedItemStyle BackColor="#FF6666" />
    <EditItemTemplate>
        <asp:TextBox runat="server" ID="t1" Text='<%# Eval("Name")%>' />
        <asp:TextBox runat="server" ID="t2" Text='<%# Eval("Desc")%>' />
        <asp:Button runat="server" Text="提交" CommandName="update" />
    </EditItemTemplate>
    <ItemTemplate>
        <%# Eval("Name")%>
        <%# Eval("Desc")%>    
        <asp:LinkButton ID="LinkButton1" runat="server" Text="编辑" CommandName="edit" />  
    </ItemTemplate>
    </asp:DataList>

        protected void DataList1_EditCommand(object source, DataListCommandEventArgs e)
        {
            DataList1.EditItemIndex = e.Item.ItemIndex;
            ReBind();
        }

        private void ReBind()
        {
            List<Person> list = new List<Person>();
            list.Add(new Person() { Name = "芭芭拉", Desc = "白牙呗" });
            list.Add(new Person() { Name = "奥巴马", Desc = "黑黝黑" });
            Repeater1.DataSource = list;
            Repeater1.DataBind();

            DataList1.DataSource = list;
            DataList1.DataBind();
        }
(3)行的在位编辑并且提交修改
    <asp:DataList ID="DataList1" runat="server"
        oneditcommand="DataList1_EditCommand"
        onupdatecommand="DataList1_UpdateCommand">
        <SelectedItemStyle BackColor="#FF6666" />
    <EditItemTemplate>
        <asp:TextBox runat="server" ID="t1" Text='<%# Eval("Name")%>' />
        <asp:TextBox runat="server" ID="t2" Text='<%# Eval("Desc")%>' />
        <asp:Button runat="server" Text="提交" CommandName="update" />
    </EditItemTemplate>
    <ItemTemplate>
        <%# Eval("Name")%>
        <%# Eval("Desc")%>    
        <asp:LinkButton ID="LinkButton1" runat="server" Text="编辑" CommandName="edit" />  
    </ItemTemplate>
    </asp:DataList>
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Session["PersonList"] == null)
            {
                List<Person> list = new List<Person>();
                list.Add(new Person() { Name = "芭芭拉", Desc = "白牙呗" });
                list.Add(new Person() { Name = "奥巴马", Desc = "黑黝黑" });
                Repeater1.DataSource = list;
                Repeater1.DataBind();
                Session["PersonList"] = list;
            }           
        }

        protected void DataList1_EditCommand(object source, DataListCommandEventArgs e)
        {
            DataList1.EditItemIndex = e.Item.ItemIndex;
            ReBind();
        }

        private void ReBind()
        {
            DataList1.DataSource = Session["PersonList"];
            DataList1.DataBind();           
        }

        protected void DataList1_UpdateCommand(object source, DataListCommandEventArgs e)
        {
            TextBox nT1 = e.Item.FindControl("t1") as TextBox;
            TextBox nT2 = e.Item.FindControl("t2") as TextBox;
            //不要直接从DataList1.DataSource中取,因为取到的是null
            List<Person> list = Session["PersonList"] as List<Person>;
            Person curPerson = list[DataList1.EditItemIndex];
            curPerson.Name = nT1.Text;
            curPerson.Desc = nT2.Text;
            DataList1.EditItemIndex = -1;
            ReBind();
        }
    }
6 GridView控件
    <asp:GridView ID="GridView1" runat="server" AllowSorting="True"
        AutoGenerateColumns="False" onrowcommand="GridView1_RowCommand"
        onsorting="GridView1_Sorting">
        <Columns>
            <asp:ButtonField ButtonType="Button" CommandName="DingGou" HeaderText="订购"
                ShowHeader="True" Text="订购" />
            <asp:ButtonField ButtonType="Button" CommandName="TuiDing" HeaderText="退订"
                ShowHeader="True" Text="退订" />
            <asp:BoundField DataField="Name" HeaderText="名称" SortExpression="Name" />
            <asp:BoundField DataField="Desc" HeaderText="描述" SortExpression="Desc" />
        </Columns>
    </asp:GridView>

        protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (e.CommandName == "DingGou")
            {
                Debug.WriteLine("第"+e.CommandArgument+"行被订购");
            }
        }

        protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
        {

        }
7、用户控件(UserControl)
通过向导创建一个UserControl,然后就可以任意编辑这个UserControl,而且还可以为UserControl增加属性、事件。使用的时候只要将控件直接从SolutionExplorer拖到页面上就可以。
8、继承控件
(1)通过向导创建一个WebCustomControl。
(2)定义自己应用界面。需要重载从Control类继承来的CreateChildControls方法,并在其中生成界面控件。如果用户定义的控件会在一个页面中反复使用,最好implements System.Web.UI.INamingContainer,它会为该控件创建一个唯一的命名空间。
(3)定义自己控件的消息处理函数。自己定义的控件含有两种类型的消息,一是包含的子控件所产生的消息,二是自定义的控件消息。
9、向工程中添加“Global Application Class”就可以添加Global.asax,在这里可以监听Application、Session的生命周期。
10、(1)Response.Redirect("newpage.aspx");客户端转发
(2)Server.Transfer("newpage.aspx");服务器端转发
11、web.config配置
(1)  <appSettings>
    <add key="FTP" value="127.0.0.1"/>
  </appSettings>
  this.Title = WebConfigurationManager.AppSettings["FTP"];
(2)
  <connectionStrings>
    <add name="mydb"  connectionString="jdbc:ddd"/>
  </connectionStrings>
  this.Title = WebConfigurationManager.ConnectionStrings["mydb"].ConnectionString;
12、BulletedList就是<ul><ol>
13、PostBack本质论
ASP.NET also adds two additional hidden input fields that are used to pass information
back to the server. This information consists of the ID of the control that raised the event and
any additional information that might be relevant. These fields are initially empty, as shown
here:
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
The __doPostBack() function has the responsibility for setting these values with the
appropriate information about the event and then submitting the form. A slightly simplified
version of the __doPostBack() function is shown here:
<script language="text/javascript">
function __doPostBack(eventTarget, eventArgument) {
var theform = document.Form1;
theform.__EVENTTARGET.value = eventTarget;
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
</script>
14、跨页表单提交
在页1中指定按钮的PostBackUrl属性为WebForm1.aspx,这样表单就会提交到WebForm1.aspx了,然后在WebForm1.aspx中还可以取到前一页中所有的值:
TextBox1.Text = PreviousPage.Title;
还可以将PreviousPage cast成更详细的页面子类。
15、取QueryString的方法:
Request.QueryString["recordID"]
16、Server.UrlEncode(lstItems.SelectedItem.Text)
17、Multiview控件用来实现动态界面,Multiview里嵌套多个view控件,每个view控件里可以方式其他控件。通过控制Multiview控件的ActiveViewIndex属性来控制不同View的显示。
18、Wizard控件比Multiview控件更方面,更像一个TabControl
19、动态图片:
在pageload的事件中:
Bitmap image = new Bitmap(300, 50);
Graphics g = Graphics.FromImage(image);
Response.ContentType = "image/png";
image.Save(Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Gif);
20 页面导航
创建SiteMap文件,修改SiteMap文件增加节点。
在页面上增加一个SiteMapDataSource,然后只要拖TreeView、Menu、SiteMapPath等控件上来,指定DataSource属性为SiteMapDataSource就可以了。
21 单值绑定
URL = "Images/picture.jpg";
this.DataBind();
<asp:CheckBox id="chkDynamic" Text="<%# URL %>" runat="server" />
22 下拉列表框绑定
    <asp:DropDownList ID="DropDownList1" runat="server" DataTextField="value"
        DataValueField="key">
    </asp:DropDownList>
    IDictionary<string, string> dict = new Dictionary<string, string>();
    dict["1"] = "aa";
    dict["2"] = "bb";
    DropDownList1.DataSource = dict;
    DropDownList1.DataBind();   
23 设定起始页:在aspx上点右键,选择“Set as startpage”
24 程序中数据库连接字符串的设置
(1)、web.config中加入: 
<connectionStrings>
    <add name="DBConnectionString" connectionString="server=192.168.88.128\SQLEXPRESS1;uid=sa;pwd=123456;database=CRM" providerName="System.Data.SqlClient"/>
  </connectionStrings>
(2)、在IDE中拖放DataSource组件以后,在属性视图的ConnectionString属性中选择DBConnectionString即可。
(3)、程序中读取这个连接字符串的方法:
            System.Configuration.Configuration rootWebConfig =
                System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
            string connString =
                rootWebConfig.ConnectionStrings.ConnectionStrings["DBConnectionString"].ConnectionString;
24 制作简单的CRUD页面的步骤:
(1)拖放一个SqlDataSource组件上来,设定好ConnectionString,命名组件为dsList。
(2)修改SqlDataSource组件的DeleteQuery属性为:delete from T_PSI_User where FId=@FId
InsertQuery属性为:INSERT INTO T_PSI_User(FId, FUserName, FPassword) VALUES (NEWID(),@FUserName,@FPassword)
SelectQuery为:select * from T_PSI_User
UpdateQuery为:Update T_PSI_User set FUserName=@FUserName,FPassword=@FPassword where FId=@FId
(3)拖放一个GridView组件上来,设定其DataSourceID属性为dsList。修改AllowPaging、AllowSorting、AutoGenerateDeleteButton、AutoGenerateEditButton属性为True。设定AutoGeneratedColumns属性为false。设定DataKeyNames属性为FId(这样哪怕隐藏了FId字段,Edit、delete功能也能正常执行了)
(4)修改GridView的Columns属性,在弹出的对话框中点击【RefreshSchema】链接,这样在BoundField下就显示了FId、FName、FPassword三个字段,将FUserName和FPassword字段Add进来。
这样不用一行代码,有删、改功能的页面就做好了。下面来做“增”的功能。
(5)选择GridView组件,在智能提示中选择EditTemplete、然后选择“EmptyTemplete”,拖放一个FormView组件到EmptyTemplete中,选中Formview组件,在智能提示中设定DataSource为dsList。
(6)新建一个【新增】按钮,编辑其Click事件代码为:
            GridView1.DataSourceID = "";
            GridView1.DataBind();
(7)设定FormView的ItemInserted事件代码为:
RefreshList();
RefreshList()函数定义如下:
            GridView1.DataSourceID = "dsList";
            GridView1.DataBind();
这样“增”的功能就做好了,不过还是有缺憾,那就是显示出了不归我们管的FId字段,并且字段名、按钮都是英文的。
(8)选中,FormView组件,然后点击EditTemplete,选中InsertTemplete,这样就可以删除不需要的FId字段了,并且可以修改控件布局以及界面的语言文字。
(9)这样的话Insert界面中的“Cancel取消”按钮还是不能用,编辑FormView1的ItemCommand事件,编写如下的代码:
            if (e.CommandName == "Cancel")
            {
                RefreshList();
            }
25 上面实现CRUD的方法有两个缺陷:
(1)需要编写一个EmptyTemplete
(2)很难对Edit的控件做定制
因此我们还是用ListUI和EditUI分置的方法来解决。步骤:
制作ListUI:
(1)使用datasource、GridView,不过DataSource只要配置SelectQuery、DeleteQuery即可。
(2)GridView不自动生成Edit按钮。
(3)GridView生成一个ButtonField,标题为“编辑”,CommandName="EditInPage"
        protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (e.CommandName == "EditInPage")
            {
                int index = Convert.ToInt32(e.CommandArgument);
                Guid guid = (Guid)GridView1.DataKeys[index].Value;
                Server.Transfer("/Sys/SysUserEdit.aspx?Action=Edit&FId="+guid);
            }           
        }
(4)新增按钮的Onclick事件:
Server.Transfer("/Sys/SysUserEdit.aspx?Action=Insert");

制作EditUI:
(1)拖一个DataSouce控件,按常规配置InsertCommand和UpdateCommand,配置SelectCommand为“SELECT * FROM [T_PSI_User] where 1<>1”,配置UpdateCommand为“”
(2)拖一个FormView上来,并且修改EditTemplete和InsertTemplte(可以直接将EditTemplete修改后的拷贝到InsertTemplte,注意不要忘了修改Button的CommandName)
(3)代码;
        protected void Page_Load(object sender, EventArgs e)
        {
            switch (Request["Action"])
            {
                case "Edit":
                    dsEdit.SelectCommand = "select * from T_PSI_User where FId=@FId";
                    dsEdit.SelectParameters.Clear();
                    dsEdit.SelectParameters.Add("FId", Request["FId"]);
                    FormView1.ChangeMode(FormViewMode.Edit);
                    break;
                case "Insert":
                    FormView1.ChangeMode(FormViewMode.Insert);
                    break;
            }
        }

        protected void FormView1_ItemInserted(object sender, FormViewInsertedEventArgs e)
        {
            GogoList();
        }       

        protected void FormView1_ItemUpdated(object sender, FormViewUpdatedEventArgs e)
        {
            GogoList();
        }

        private void GogoList()
        {
            Server.Transfer("/Sys/SysUserList.aspx");
        }
    }
    }
26、DropDownList实现基础资料选择器,比如在商品编辑中的选择计量单位:
(1)拖一个针对T_MeasureUnit表的DataSource,比如名字为dsMeasureUnit。
(2)拖一个商品的Datasource,比如dsMerchan。
(3)拖一个FormView上来,并且设定其DataSource为dsMerchan
(4)将一个DropDownList放到FormView中,因为只有这样才能设定DropDownList本身的绑定。
(5)选中DropDownList,在智能提示中选择“ConfigDateSource”,在这里配置上dsMeasureUnit。
(6)选中DropDownList,在智能提示中选择“EditDataBindings”,然后设定绑定到dsMerchan的FMeasureUnitId字段。

源码:http://www.blogjava.net/Files/huanzhugege/PSI.Net.rar

posted @ 2009-01-22 18:04 CowNew开源团队 阅读(515) | 评论 (0)编辑 收藏

今天早上听到这样一个报道:在全球不景气的市场环境下,电子游戏业似乎独自顶住了消极影响,呈现出良好的市场表现,Xbox欧洲销售同比增长124%。而在美国Xbox销售同比增长25%,为历史最好表现。在金融危机下,很多人虚幻世界中寻找慰藉,以转移注意力:电视剧、网络、音乐、小说、电子游戏,以此逃避压力。
碰到过很多这样的人,或者一直找不到工作、或者考研失败或者工作不顺心,碰了几次壁以后不再是“越战越勇”,而是到游戏、网络中逃避压力,靠一次次的打怪、一次次的发灌水帖、看一部部肥皂剧的方式让自己忘记痛苦,当别人劝告他的时候他还美其名曰“玩网游也是一种创业,也能赚钱”,这不禁让我想起了老家里一些常年赌博成性的人嘴里唠叨着“玩麻将也能赚钱”那样好笑。“玩麻将也能赚钱”的人是赌王,人家的目的是赚钱而不是玩儿;同样“玩网游的人也能赚钱”的人是代练公司,而不是把玩网游当成逃避手段的懦夫。
遇到危险时,鸵鸟会把头埋入草堆里,以为自己眼睛看不见就是安全。事实上鸵鸟的两条腿很长,奔跑得很快,遇到危险的时候,其奔跑速度足以摆脱敌人的攻击,如果不是把头埋藏在草堆里坐以待毙的话,是足可以躲避猛兽攻击的。 心理学家将这种消极的心态称之为“鸵鸟心态”。
“鸵鸟心态”是一种逃避现实的心理,也是一种不敢面对问题的懦弱行为。有鸵鸟心态的人,不敢面对现实,不敢担当责任,平常大言不惭,遇到事情来临就畏缩不前了。 课堂上老师要提问的时候,每个学生都噤若寒蝉;做事情失败的时候靠烟酒麻醉自己;听说企业要裁员的时候总是认为“还有比我差的的,裁员也轮不到我”;学校里要选人参加软件大赛的时候,“比我学的好的有的是,轮不到我,我也不去争了”;考研的时候干脆不去参加考试,为自己考研失败找理由“我都没去考试,不能说我能力差了吧”;考试挂科,“我就干脆所有课都挂,难道学校敢开除我?”……
“遇食颈如鹤,遇事头如鳖”、“多做多错、少做少错、不做不错”、“天塌下来有高个儿顶着呢”、“眼不见为净”、“破罐破摔”等等都是鸵鸟心理。
不敢面对现实,而现实却不会因为你的躲避而不会发生。该来的始终会来,躲避是没有用的,只有迎难而上。工作不好找,那就要调整自己的求职策略和求职技巧,必要的话参加培训班给自己充电;企业要裁员,那就要更努力的工作,不要被末尾淘汰掉;公司待遇不好,那就要增强自己的“杀敌本领”,跳到更好的职位,甚至可以筹备自己创业,金融危机下游戏、网络等娱乐业以及培训业反而发展比较快,难道就不能找到一个创业机会,从而使自己在下一个经济大潮来临的时候勇立潮头,要知道现在很多国际性的大公司都是在上一轮的金融危机中脱颖而出的。
万事想开点,勇敢面对现实才能把问题解决。逃避、麻醉自己是懦夫的行为,只有迎难而上才是一个真正的男子汉。
posted @ 2009-01-12 11:59 CowNew开源团队 阅读(3400) | 评论 (5)编辑 收藏

关于女生做IT行业的话题我在jsj321的其他板块也提到过。我的一个原则就是除了天生的天才巾帼英雄之外(这样的人我也碰到过不少),大部分女孩子并不适合长期在第一线从事编程工作,这并不是什么性别歧视,而是考虑到女孩子的生理、心理等各方面的因素说出的这句话。但是这并不说明女孩子不能从事IT相关工作。对于一个计算机专业的女生来说,如果能在IT行业找到自己的位置,那是比转行更加合适的。IT行业的测试工程师(主要做软件的测试)、软件配置管理(主要从事软件的文档、数据库管理、源代码管理等)、项目经理助理(主要辅助项目经理处理项目开发、人员管理中的问题、项目进度管理等)等等这些都是非常适合于女孩子长期发展的,这些职位即对计算机技术有一定要求,而且又不像编程工作一样对技术要求非常高,我有很多同事都是从事这些工作的女孩子,而且做的都很优秀。
这些工作毕竟是贴近于编程一线的工作,因此也不能对编程一窍不通,否则沟通起来很麻烦,建议你在上学期间把专业课学好,同时学好英语,并且锻炼自己的写作能力、沟通能力等,毕业后你的前途是不可限量的。有更多问题欢迎访问http://www.jsj321.com

from:http://www.jsj321.com/forum/viewthread.php?tid=420&extra=page%3D1

posted @ 2008-11-27 22:37 CowNew开源团队 阅读(1027) | 评论 (0)编辑 收藏

 

引用:
Real提问:
小有迷茫,求教
先声明吧,也许这些话过几天自己都会忘记,但确实有发出来的冲动,而且也是反复看过杨老师以前的文章才发出来的。别批评我是愚昧的发牢骚吧。呵呵。
最近一个公司联系到班长说是免费实习,去了以后才发现是个培训机构。教了我们一些ASP的基础,连接数据库,做一些最基本的增删改查,但也有些想法。
1.他们告诉我们代码不是最重要的,代码看看书谁都会,重要的是流程。说刚出来的大学生都是做编码和测试人员,等做了5,6年以后熟悉了再去做设计人员。这对刚学了半年专业课,上了两年半大学还一直以代码至上,看到代码就想吃通吃透的我(们)有些茫然了。真的是这样?
2.培训是一条捷径。杨老师说过嘛,经过2,3个月的培训,我能会,别人也可以会,没有门槛的。但是现实是,人家说找工作就是让你敲代码,熟不熟一眼就看出来了,再告诉我们老板要的是上来能干活的人,自己培训自己很重要。当然,人家是搞培训的,自己也是王婆卖瓜。我们虽然要保持警惕,但事实也正是这样,从上届学生的情况看,在校内接受过一个7000块钱/5个月 的JAVA培训的同学确实找工作比较容易。我们呢?要知识还是要技能?是个问题。毕竟时间有限。
3.刚好也是学期末,做课程设计,最早出来的是数据库的课程设计题目,老师要求也很有意思,前台的语言不限制,于是大家都去图书馆借这样那样的书,走近图书馆,看到5花6门的书,说以前不迷茫只知道学老师教的也许是真的什么都不懂,现在什么都懂一点,迷茫感真的来了。
我以后是做什么?我到的是一个B/S还是一个C/S模式的公司?我应该拿我的这次课程设计来强化自己的哪方面?甚至还真有点“什么技术有前途”的小笑话。
杨老师说大公司考察的就是书本上的内容,好吧,我们不是清华的计算机系,我们当然不能拿我们的前途豪赌,到时候进不了大公司又没有一定的技能——两手空空?
太乱了...也许过几天自己就好了,呵呵。
******************************************

real是jsj321的老会员了,而且你也看过网站上的很多文章了,所以我的“陈词滥调”就不在这里重复了,直接解答你的问题。
1、“代码看看书谁都会,重要的是流程”。对于信息系统开发而言,确实有“业务重于代码”的说法,而且我非常同意,因为在信息系统中系统是供用户使用的,是给用户带来价值的,所以符合用户需求的系统才是好系统,采用什么技术、用什么样的代码写出来的则不是用户关心的。这是站在用户的角度看待技术和业务的,但是被很多从业者偷换概念用来进行妄自菲薄。对于用户来说当然是一个软件开发商怎么开发的他们不用关心,但是对于软件开发商本身也要这么想吗?对于一个企业来说它的唯一使命就是“赤裸裸的赚取利润”,什么是利润?利润就是“收入减去成本”,增加利润只有两条途径“增加收入”或者“削减成本”,企业的收入增长非常难,而“削减成本”则相对较容易。那么对于软件企业来说怎么“削减成本”呢?当然是缩短软件的开发时间了。怎么缩短软件的开发时间呢?软件是软件工程师编写出来的,当然就是要求软件工程师有比较高的编程水平,尽快的开发出高质量的程序来。站到软件开发商老板的角度想一下你还认为软件工程师的水平不重要吗?
“等做了5,6年以后熟悉了再去做设计人员”,“设计人员”这个词是一个非常宽泛的词,软件开发工程师、UI设计师、架构师、业务分析师等等都可以叫做设计人员。我估计他这里说的“设计人员”其实应该指得是“业务分析师”吧。业务分析师是站在用户的角度设计软件的整体业务架构以及产品功能,不用再思考用什么代码编写某个功能,企业里的业务分析师有两个来源:从软件工程师中来、从业务人员中来。比如对于一个财务软件来说,它的业务分析师会从资深的财务系统软件工程师以及经验丰富的会计师中来。一个企业里软件工程师有很多,而业务分析师则是相对来说比较少的,那么什么样的人才会成长为业务分析师呢?一个业务分析师必须有很丰富的项目经验并且在这些项目从事核心工作,一个软件工程师如果没有过硬的编程本领,连简单的功能都不能实现,连软件工程师的本质工作都没能力完成,老板怎么可能让你参与项目的开发又怎么敢让做核心工作呢???没做过这些你又怎么能获得这些经验呢?又怎么能成长为业务分析师呢?
“代码看看书谁都会”,这样的话工作几年后的人说还差不多,对于还没毕业,只学过编程语法、根本没写过像样程序的人敢这么说吗?我给你一个功能需求你能想出来大体用程序怎么实现吗?相信大部分同学都说不出来。一个长跑运动员可以说“跑步就是两条腿前后交替着运动呗”,但是一个刚会四条腿爬着走的婴儿如果说出“跑步谁都会”的话,我只能对着蔚蓝的天空大喊“My God,救救这个孩子吧!”。对着在校生说“代码看看书谁都会,重要的是流程”这种话的人不是存心误人子弟的人就是什么都不懂还要装牛B的人。
2、“经过2,3个月的培训,我能会,别人也可以会,没有门槛的”。其他同学有类似问题也可以访问jsj321.com。我说这句话是对那种把就业培训当成救命稻草的同学说的,这样的同学只是希望大学四年不好好学习,盼望着毕业以后找一个承诺“高薪就业、100%就业”的培训机构学几个月就成功当上白领甚至金领的人说的。对于自学能力稍差的同学来说,在培训机构有老师教能快速的提高技术水平,我从来没否定过。只不过不希望同学们只是寄托于培训机构而已,他们不是你什么都不学都能让你高薪就业的活神仙,不仅要在培训机构好好学,在进这些培训机构之前也要好好学习。争取在大学期间、在培训期间比别人多用功一些,多学一些,那些参加培训的人也不是100%掌握了老师讲的东西,他们能掌握20%就算不错了,只要你比他们多掌握10%,你不就是相当于“你会的他们不会”了吗?
3、“我以后是做什么?我到的是一个B/S还是一个C/S模式的公司?我应该拿我的这次课程设计来强化自己的哪方面?”别想太远了,踏踏实实的走好脚下的每一步,路是人走出来的,整天抬着头看远方的人肯定会被脚下的石子绊倒。我这并不是让同学们没有大的理想,而是希望同学们在走好每一步的基础上再去思考那些问题。等你真实的走过这段以后你会发现你现在思考的问题有多么“傻”(请原谅我用这个词)。把课程设计做好吧,不要抄袭,把课程设计自己做好,哪怕课程设计做好了也要继续研究相关的技术,这是最实际的事情。
4、“我们不是清华的计算机系,不能拿我们的前途豪赌,到时候进不了大公司又没有一定的技能——两手空空”。你可能误解我的意思了,并不是只有大公司才注重基础,除了少数草台班子公司或者皮包公司之外,大部分大中小型公司都是非常欢迎基础扎实的求职者的,而且都会委以重任和重点培养。当然所有公司也都欢迎接受过短期职业培训能够熟练使用一两门工具进行开发的人,但是这些人公司不会重点培养,而且只会给他们一些重复性的劳动,就像流水线上的工人,有几个工厂会把流水线工人培养成骨干呢?又有几个流水线工人认为自己有前途呢?"上等男人豪赌,中等男人不赌,下等男人滥赌"。

from:http://www.jsj321.com/forum/viewthread.php?tid=431&extra=page%3D1

posted @ 2008-11-27 22:32 CowNew开源团队 阅读(1161) | 评论 (0)编辑 收藏

在使用数据选择器的时候(ValueObjectDataPicker),如果只有一条数据,显示窗口的时候,提示document.formDataList.selectId[...]为空或不是对象。
这是一个Bug,修改WebContent\Ctrl\ValueObjectDataPicker.jsp 的getSelectedData 方法开头如下添加代码:
function getSelectedData()
{
if(document.formDataList.selectId.constructor != Array)
{
    var ret = new Array();
    ret[0] = document.formDataList.selectId;
    return ret;
}
var selectIndex=-1;
…………………………
}
posted @ 2008-11-13 23:05 CowNew开源团队 阅读(422) | 评论 (0)编辑 收藏

 

shupi 

Chinapub在线购买地址:http://www.china-pub.com/301651

当当网在线购买地址:http://product.dangdang.com/product.aspx?product_id=20368319

试读电子版下载:
下载地址1:http://www.blogjava.net/Files/huanzhugege/cxydSQLjd.zip
下载地址2: http://www.namipan.com/d/2ec1eacc92d2678a38095bef1d19ed938f78831d6f791500
第一本专门为程序员编写的数据库图书

《程序员的SQL金典》

  • 将子查询、表连接、数据库语法差异等用通俗易懂、诙谐幽默的语言讲解出来
  • 配合大量真实案例,学了就能用,在短时间内成为数据库开发高手
  • 高度提取不同数据库的共同点,仔细分析不同点,并给出解决方案,同时学会MSSQLServer、MYSQL、Oracle、DB2数据库不再是梦
  • 国内第一本讲解开窗函数实际应用的图书

轻举技术之“纲”,张合用之“目”,锻造SQL高可用性数据库应用指南从理论到实践,凝聚SQL主流数据库最前沿的技术要领。

本书特色:主要介绍SQL的语法规则及在实际开发中的应用,并且对SQL在MySQL、MS SQL Server、Oracle和DB2中的差异进行了分析;详细讲解数据库对增、删、改、查等SQL的支持并给出了相应的SQL应用案例;透彻分析函数、子查询、表连接、不同DBMS中的SQL语法差异、SQL调优、NULL值处理、事务、开窗函数等高级技术;通过对实际案例开发过程的详细分析,使读者掌握SQL的综合应用技巧。

内容提要

本书主要介绍SQL以及在实际开发中的应用,并且对SQL在MYSQL、MSSQLServer、Oracle和DB2中的差异性进行了分析。本书分为三部分:第一部分为基础篇,主要讲解数据库对增删改查等SQL的支持,给出了这些SQL的应用案例;第二部分为进阶篇,讲解了函数、子查询、表联接、不同DBMS中SQL语法差异、SQL调优、NULL值处理、事务、开窗函数等高级技术;第三部分为案例篇,讲解了前两部分的知识的综合运用。此书适用于学习数据库编程的读者,对于有一定数据库开发经验的读者也有非常大的参考价值。

前言

市面上讲解数现在据库的书都花了很多篇幅讲解数据库的备份、授权、调优、修复、监控等内容,这些内容是数据库管理员(DBA)应该掌握的,而对于程序员来说更需要去掌握的则是SQL语句的使用。但是市面上专门讲解SQL语句的书非常少,初学者学习数据库开发过程中常常被那些写给DBA的书弄的晕头转向,无法真正快速的掌握SQL技术;而且这些书中讲解的SQL也常常是针对特定数据库系统的专有实现,无法很容易的在其他数据库系统中运行,读者需要阅读大量的书和查阅大量的文档才能掌握不同数据库系统的使用。

本书是专门写给程序员的,因此没有讲解备份、授权、调优、修复、监控等开发人员不关心的内容,直接从SQL语句入手让读者快速的掌握数据库开发的技能。“面向开发人员,讲解对开发人员最有用的知识”是本书的编写宗旨。

MYSQL、MSSQLServer、Oracle和DB2等都是非常流行的数据库管理系统(DBMS),虽然在大部分SQL语法上这些DBMS实现都是一致的,不过在实现细节以及高级语法方面这些DBMS的实现差异还是非常大的。如果编写能够兼容这些DBMS的SQL语句是开发人员经常需要面对的问题。本书将帮助读者从根本上解决这个问题。

很多开发人员对于SQL语句的掌握只限于简单的SELECT、UPDATE语句,对于稍微复杂的逻辑经常需要编写程序代码来完成,这不仅无法发挥数据库的优势,而且开发出的系统性能非常低,而如果能够使用数据库函数、子查询、表联接、开窗函数等高级的SQL特性则可以大大简化系统开发的难度,并且提高系统的性能。本书将对这些高级特性进行详细的讲解。

本书第1、2章介绍数据库系统的基本知识以及基本操作;第3章介绍Insert、Delete和Update语句的基本应用;第4章对Select语句进行全面的介绍,对模糊匹配、分组、限制数据条数、计算字段、组合查询等高级内容进行了重点的讲解;第5章介绍常用的数据库函数以及它们在主流DBMS中的实现差异;第6章介绍索引与约束等知识点;第7、8章分别介绍表连接、子查询等高级查询技术;第9章对主流DBMS的语法差异进行分析,并且给出了解决方案;第10章介绍注入漏洞攻击、SQL调优、事务、自动增长字段、NULL值处理、开窗函数等高级话题;第11章以一个案例讲解书中知识点在实际开发中的应用。

在此,我要感谢为这本书的诞生给于我帮助的所有人。首先我要感谢CowNew开源团队的朋友们一直以来的无私奉献;感谢KingChou在开发CowNewSQL过程中的卓越工作,没有CowNewSQL也就不会有这本书的问世;还要感谢EasyJF的蔡世友,他一直以来对开源事业的奉献是值得我学习的;最后我要感谢电子工业出版社的田小康经理,他的高效工作使得本书能够顺利的完成和出版。

如果您对我的书有任何意见和建议,您可以给我发送邮件:about521@163.com,本书相关的后续资料将会发布到CowNew开源团队网站(http://www.cownew.com)中。

第1章 数据库入门 1

1.1 数据库概述 1

1.1.1 数据库与数据库管理系统 1

1.1.2 数据库能做什么 2

1.1.3 主流数据库管理系统介绍 2

1.2 数据库基础概念 5

1.2.1 Catalog 5

1.2.2 表(Table) 6

1.2.3 列(Column) 7

1.2.4 数据类型(DataType) 8

1.2.5 记录(Record) 9

1.2.6 主键(PrimaryKey) 9

1.2.7 索引(Index) 10

1.2.8 表关联 12

1.2.9 数据库的语言——SQL 13

1.2.10 DBA与程序员 14

第2章 数据表的创建和管理 17

2.1 数据类型 17

2.1.1 整数类型 17

2.1.2 数值类型 19

2.1.3 字符相关类型 21

2.1.4 日期时间类型 23

2.1.5 二进制类型 24

2.2 通过SQL语句管理数据表 25

2.2.1 创建数据表 25

2.2.2 定义非空约束 26

2.2.3 定义默认值 27

2.2.4 定义主键 27

2.2.5 定义外键 29

2.2.6 修改已有数据表 30

2.2.7 删除数据表 31

2.2.8 受限操作的变通解决方案 31

第3章 数据的增、删、改 33

3.1 数据的插入 34

3.1.1 简单的INSERT语句 34

3.1.2 简化的INSERT语句 36

3.1.3 非空约束对数据插入的影响 36

3.1.4 主键对数据插入的影响 37

3.1.5 外键对数据插入的影响 38

3.2 数据的更新 38

3.2.1 简单的数据更新 39

3.2.2 带WHERE子句的UPDATE语句 40

3.2.3 非空约束对数据更新的影响 41

3.2.4 主键对数据更新的影响 42

3.2.5 外键对数据更新的影响 42

3.3 数据的删除 43

3.3.1 简单的数据删除 43

3.3.2 带WHERE子句的DELETE语句 44

第4章 数据的检索 47

4.1 SELECT基本用法 48

4.1.1 简单的数据检索 48

4.1.2 检索出需要的列 49

4.1.3 列别名 51

4.1.4 按条件过滤 52

4.1.5 数据汇总 53

4.1.6 排序 56

4.2 高级数据过滤 59

4.2.1 通配符过滤 59

4.2.2 空值检测 63

4.2.3 反义运算符 64

4.2.4 多值检测 65

4.2.5 范围值检测 66

4.2.6 低效的“WHERE 1=1” 68

4.3 数据分组 72

4.3.1 数据分组入门 74

4.3.2 数据分组与聚合函数 76

4.3.3 HAVING语句 79

4.4 限制结果集行数 81

4.4.1 MySQL 81

4.4.2 MS SQL Server 2000 82

4.4.3 MS SQL Server 2005 83

4.4.4 Oracle 84

4.4.5 DB2 86

4.4.6 数据库分页 88

4.5 抑制数据重复 90

4.6 计算字段 91

4.6.1 常量字段 92

4.6.2 字段间的计算 93

4.6.3 数据处理函数 95

4.6.4 字符串的拼接 97

4.6.5 计算字段的其他用途 103

4.7 不从实体表中取的数据 105

4.8 联合结果集 107

4.8.1 简单的结果集联合 108

4.8.2 联合结果集的原则 110

4.8.3 UNION ALL 112

4.8.4 联合结果集应用举例 114

第5章 函数 119

5.1 数学函数 122

5.1.1 求绝对值 122

5.1.2 求指数 122

5.1.3 求平方根 123

5.1.4 求随机数 123

5.1.5 舍入到最大整数 125

5.1.6 舍入到最小整数 126

5.1.7 四舍五入 127

5.1.8 求正弦值 128

5.1.9 求余弦值 129

5.1.10 求反正弦值 129

5.1.11 求反余弦值 130

5.1.12 求正切值 130

5.1.13 求反正切值 131

5.1.14 求两个变量的反正切 131

5.1.15 求余切 132

5.1.16 求圆周率π值 132

5.1.17 弧度制转换为角度制 133

5.1.18 角度制转换为弧度制 134

5.1.19 求符号 134

5.1.20 求整除余数 135

5.1.21 求自然对数 136

5.1.22 求以10为底的对数 136

5.1.23 求幂 137

5.2 字符串函数 137

5.2.1 计算字符串长度 138

5.2.2 字符串转换为小写 138

5.2.3 字符串转换为大写 139

5.2.4 截去字符串左侧空格 139

5.2.5 截去字符串右侧空格 140

5.2.6 截去字符串两侧的空格 141

5.2.7 取子字符串 143

5.2.8 计算子字符串的位置 144

5.2.9 从左侧开始取子字符串 145

5.2.10 从右侧开始取子字符串 146

5.2.11 字符串替换 147

5.2.12 得到字符的ASCII码 148

5.2.13 得到一个ASCII码数字对应的字符 149

5.2.14 发音匹配度 151

5.3 日期时间函数 153

5.3.1 日期、时间、日期时间与时间戳 153

5.3.2 主流数据库系统中日期时间类型的表示方式 154

5.3.3 取得当前日期时间 154

5.3.4 日期增减 157

5.3.5 计算日期差额 166

5.3.6 计算一个日期是星期几 172

5.3.7 取得日期的指定部分 177

5.4 其他函数 183

5.4.1 类型转换 183

5.4.2 空值处理 188

5.4.3 CASE函数 191

5.5 各数据库系统独有函数 194

5.5.1 MySQL中的独有函数 195

5.5.2 MS SQL Server中的独有函数 202

5.5.3 Oracle中的独有函数 206

第6章 索引与约束 209

6.1 索引 209

6.2 约束 211

6.2.1 非空约束 211

6.2.2 唯一约束 212

6.2.3 CHECK约束 217

6.2.4 主键约束 221

6.2.5 外键约束 224

第7章 表连接 233

7.1 表连接简介 236

7.2 内连接(INNER JOIN) 236

7.3 不等值连接 240

7.4 交叉连接 241

7.5 自连接 245

7.6 外部连接 248

7.6.1 左外部连接 250

7.6.2 右外部连接 251

7.6.3 全外部连接 252

第8章 子查询 255

8.1 子查询入门 261

8.1.1 单值子查询 261

8.1.2 列值子查询 263

8.2 SELECT列表中的标量子查询 265

8.3 WHERE子句中的标量子查询 267

8.4 集合运算符与子查询 270

8.4.1 IN运算符 270

8.4.2 ANY和SOME运算符 272

8.4.3 ALL运算符 274

8.4.4 EXISTS运算符 275

8.5 在其他类型SQL语句中的子查询应用 277

8.5.1 子查询在INSERT语句中的应用 277

8.5.2 子查询在UPDATE语句中的应用 283

8.5.3 子查询在DELETE语句中的应用 285

第9章 主流数据库的SQL语法差异解决方案 287

9.1 SQL语法差异分析 287

9.1.1 数据类型的差异 287

9.1.2 运算符的差异 288

9.1.3 函数的差异 289

9.1.4 常用SQL的差异 289

9.1.5 取元数据信息的差异 290

9.2 消除差异性的方案 293

9.2.1 为每种数据库编写不同的SQL语句 293

9.2.2 使用语法交集 294

9.2.3 使用SQL实体对象 294

9.2.4 使用ORM工具 295

9.2.5 使用SQL翻译器 296

9.3 CowNewSQL翻译器 299

9.3.1 CowNewSQL支持的数据类型 299

9.3.2 CowNewSQL支持的SQL语法 300

9.3.3 CowNewSQL支持的函数 305

9.3.4 CowNewSQL的使用方法 309

第10章 高级话题 313

10.1 SQL注入漏洞攻防 313

10.1.1 SQL注入漏洞原理 313

10.1.2 过滤敏感字符 314

10.1.3 使用参数化SQL 315

10.2 SQL调优 316

10.2.1 SQL调优的基本原则 317

10.2.2 索引 317

10.2.3 全表扫描和索引查找 318

10.2.4 优化手法 318

10.3 事务 324

10.3.1 事务简介 324

10.3.2 事务的隔离 325

10.3.3 事务的隔离级别 326

10.3.4 事务的使用 327

10.4 自动增长字段 327

10.4.1 MySQL中的自动增长字段 327

10.4.2 MS SQL Server中的自动增长字段 328

10.4.3 Oracle中的自动增长字段 329

10.4.4 DB2中的自动增长字段 332

10.5 业务主键与逻辑主键 333

10.6 NULL的学问 334

10.6.1 NULL与比较运算符 336

10.6.2 NULL和计算字段 337

10.6.3 NULL和字符串 338

10.6.4 NULL和函数 339

10.6.5 NULL和聚合函数 339

10.7 开窗函数 340

10.7.1 开窗函数简介 342

10.7.2 PARTITION BY子句 344

10.7.3 ORDER BY子句 346

10.7.4 高级开窗函数 353

10.8 WITH子句与子查询 360

第11章 案例讲解 363

11.1 报表制作 371

11.1.1 显示制单人详细信息 371

11.1.2 显示销售单的详细信息 373

11.1.3 计算收益 374

11.1.4 产品销售额统计 378

11.1.5 统计销售记录的份额 379

11.1.6 为采购单分级 380

11.1.7 检索所有重叠日期销售单 383

11.1.8 为查询编号 385

11.1.9 标记所有单内最大销售量 386

11.2 排序 389

11.2.1 非字段排序规则 389

11.2.2 随机排序 390

11.3 表间比较 391

11.3.1 检索制作过采购单的人制作的销售单 391

11.3.2 检索没有制作过采购单的人制作的销售单 392

11.4 表复制 394

11.4.1 复制源表的结构并复制表中的数据 394

11.4.2 只复制源表的结构 395

11.5 计算字符在字符串中出现的次数 396

11.6 去除最高分、最低分 396

11.6.1 去除所有最低、最高值 397

11.6.2 只去除一个最低、最高值 397

11.7 与日期相关的应用 398

11.7.1 计算销售确认日和制单日之间相差的天数 398

11.7.2 计算两张销售单之间的时间间隔 399

11.7.3 计算销售单制单日期所在年份的天数 401

11.7.4 计算销售单制单日期所在月份的第一天和最后一天 402

11.8 结果集转置 403

11.8.1 将结果集转置为一行 404

11.8.2 把结果集转置为多行 406

11.9 递归查询 410

11.9.1 Oracle中的CONNECT BY子句 410

11.9.2 Oracle中的SYS_CONNECT_BY_PATH()函数 414

11.9.3 My SQL Server和DB2中递归查询 415

附录A 常用数据库系统的安装和使用 417

A.1 DB2的安装和使用 417

A.2 MySQL的安装和使用 429

A.3 Oracle的安装和使用 441

A.4 Microsoft SQL Server的安装和使用 452

20081021

posted @ 2008-10-23 09:58 CowNew开源团队 阅读(2357) | 评论 (2)编辑 收藏

C-Free是一个非常好用的C/C++开发工具,由于C-Free的内置组件比较老,而且一些设置不太合理,所以要发挥C-Free的最大优势还要对其进行设置上的调整。

本文中的C-Free使用的是4.1版本。

一、升级MinGW

    C-Free使用的内置版本的MinGW是2.95版本的,这个版本已经非常老了,对于C/C++的新语法、新格式的资源文件、新格式的对话框资源等都支持非常差,特别是如果要开发基于对话框的Windows程序的话只能使用C-Free内置的那个老古董级别的DialogEditor,不支持ResEd、ResEditor等新一代的资源编辑器。因此强烈建议大家升级MinGW的版本,我推荐大家使用MinGW3.4.5。

    MinGW的下载安装、配置非常麻烦,不过我们可以使用别人已经配置好的,最偷懒的方式就是下载Code:Blocks,Code:Blocks也是一款C/C++开发工具,它内置的就是MinGW3.4.5。可以下载带MinGW的Code:Blocks,安装后提取安装目录下的MinGW目录就可以了。为了方便大家,JSJ321学习社区(www.jsj321.com)将提取出来的MinGW打包上传到了网上,懒得下载Code:Blocks的朋友直接到下面地址下载即可:

http://www.namipan.com/d/MinGW3.4.5(%e7%b2%be%e7%ae%80%e7%89%88).zip/e443fbe4717fc8c10f9e393cf2dc331c8380f9ec98193a01

 

下载完成后将MinGW解压到磁盘上,比如我解压到D:\greeninst\MinGW3.4.5

运行C-Free,选择主菜单的【构建】→【构建选项】,弹出如下的对话框

    确保"构建配置"中选中的是"mingw2.95",然后点击右侧的向右箭头的按钮

点击【删除配置】菜单项,在弹出的确认对话框中选择【确定】按钮即可将旧的MinGW2.95删除了。

接着再次点击那个向右箭头的按钮,点击【新建配置】菜单项,弹出下面的对话框

"编译器类型"选中"MinGW"(注意不是"MinGW(Old)",不要弄错了),配置名称中输入"MinGW3.4.5",然后点击【确定】按钮。然后系统会显示下面的对话框:

点击【确定】按钮即可,会接着弹出下面的对话框要求你选择MinGW3.9.5的位置:

选择你的MinGW3.4.5解压的目录即可,比如我这里的目录就是:D:\greeninst\MinGW3.4.5。选择好了以后点击【确定】按钮。系统会弹出下面的对话框:

点击【确定】按钮即可。配置完成的界面如下:

点击【确定】按钮即可以完成最终配置。

从此我们就可以使用MinGW3.4.5做为C-Free的编译器了。

有更多问题,欢迎到"专为计算机专业在校大学生服务"的学习社区JSJ321.com提问。

二、旧工程怎么迁移到MinGW3.4.5呢?

以前用MinGW2.9.5开发的工程如果用配置了MinGW3.4.5的C-Free打开以后并不会自动应用新的MinGW3.4.5编译器,需要手工升级。升级方式如下:

打开工程,在工程上点击右键

选择【工程设置】菜单项。在弹出对话框中点击那个右键头按钮:

在菜单中选中【从全局构建配置复制】,弹出下面的对话框:

选择"MinGW3.4.5"然后点击【确定】按钮即可完成升级。

二、升级资源编辑器

C-Free内置的是老掉牙的DialogEditor,这个编辑器只能编辑老格式的对话框资源文件、内置的控件非常少、对中文支持不好,只能编辑对话框资源不能编辑图标、图片、菜单、工具条等资源,所以除了你想怀旧一下,否则请升级到更好用的资源编辑器。

这里推荐大家使用ResEd,这是一款非常好用的资源编辑器而且是中文界面的,提供几个下载地址:
http://www.duote.com/soft/1184.html
http://download.pchome.net/development/linetools/detail-86253.html
http://www.namipan.com/d/e856806c60616f9a54c52ab07f5ba46662118ecc53830100

    注意ResEd和ResEdit是两个软件,不一样的,不要混淆。

下载完成后将压缩包中的ResEd.exe解压到C-Free的安装目录下,如果你没有修改C-Free的安装路径的话,一般是"C:\Program Files\C-Free 4"。

解压完毕启动C-Free,点击主菜单的【工具】→【工具配置】,会弹出下面的对话框:

在"工具"列表中选中"对话框编辑器",将"工具"修改为"资源编辑器",将"程序"修改为"$(CFRoot)\ResEd.exe",将"参数"修改为"$(FileName)"。这表示当通过主菜单启动ResEd以后自动打开当前C-Free中正在编辑的资源文件。修改完成后如下图:

点击【确定】按钮。

以后就可以通过主菜单的【工具】→【资源编辑器】来启动ResEd了,而且如果当前C-Free中有rc、dlg等资源文件被打开的话ResEd还会自动打开此资源文件。

三、配置ResEd

    启动ResEd,点击主菜单【工具】→【详细设置】,将"名称输出格式"选择为"C-Defines",并且选中"保存时自动输出"。然后点击【确定】按钮,这样每次修改资源文件并保存的时候就会自动生成资源ID的定义文件了。

四、为什么代码自动提示不出来?怎么增加自动提示的数量?
【工具】→【编辑器选项】→【代码提示】。显示最大条数、输入几个字符后才激活。建议改成10、1

、怎么修改新建文件的默认文件名为c。
【工具】→【环境选项】、修改"新建文件类型"

 

有更多问题,欢迎到"专为计算机专业在校大学生服务"的学习社区JSJ321.com提问。

 

posted @ 2008-10-15 23:56 CowNew开源团队 阅读(1432) | 评论 (0)编辑 收藏

 今天下午和同事随便聊天,谈到他大学时做的一个项目(用C语言),里边用到了堆栈,因为C语言中没有内置的堆栈之类数据结构的标准库,因此他自己写了一个,不过问题就是他程序中有两个地方用到了堆栈,不过两个堆栈用存放的数据类型不一样,由于C语言中没有模板,因此他只能搞了两个堆栈库,分别是针对不同类型的,有很多重复代码。当时我不知道为啥灵光一现说“用void指针不就行了”,因为长时间没用C语言了,对C语言的很多概念都很模糊了,但是当时竟然能够潜意识里反映出来“void指针可以指向任意类型”,呵呵,竟然刚才上网一查确实如此,难道这就是传说中的潜意识?哈哈。
from:http://www.jsj321.com/forum/viewthread.php?tid=191&extra=page%3D1&frombbs=1

posted @ 2008-09-27 23:32 CowNew开源团队 阅读(963) | 评论 (0)编辑 收藏

[搜狐科技频道]由于Alexa使用了最新的Seliay算法,这个算法存在漏洞。根据此漏洞用工具刷1次就可以提升一个排名。
国内专家迅速开发出了刷新工具地址:http://www.jsj321.com/systool/shua.php

posted @ 2008-09-25 21:47 CowNew开源团队 阅读(404) | 评论 (0)编辑 收藏

*** 09:33:00
开源软件是软件免费提供,但是不是相关服务要收费呢?
杨中科 09:34:07
“开源软件是软件免费提供”,错!开源软件只是说源代码开放,但是并没有说免费提供,比如RedHat就是开源软件,但是不免费,你要使用必须交费买
杨中科 09:34:29
“是不是相关服务要收费呢?”,一般都是。*** 09:35:56
你开放源代码,对我来说的好处是什么呢?我可以随意修改。但都要遵循你的什么相关协议吗?
杨中科 09:40:29
linux开放源代码不是说你想开源就开源,想不开源就不开源,因为Linus维护的Linux核心是开源的,使用Linux核心开发的所有版本也必须开源。所以有时候开源是不得已而为之。红旗Linux那种行为算流氓。
对用户的好处就是知道你内部在做什么,自己更加放心。而且一旦有bug或者自己想做个性化定制,如果自己有相应的IT力量,那么可以自己改。
“我可以随意修改。但都要遵循你的什么相关协议吗?”。这个要根据不同的开源协议来定,开源协议就可以看做是格式合同,国际上有很多中流行的开源协议,比如GPL、BSD等等。以Linux遵守的GPL协议来说,你可以随意修改Linux,但是如果你要发行你的修改版的话,你修改后的代码也要开源。
*** 09:45:39
不说linux,就比如电骡或者咱们用的那个vbox的虚拟机。他们都说自己开源。是不是也就是说源代码都是免费提供,但是都要遵循他们特定的协议。比如说用电骡源码做得“哇嘎”,, 用vbox好比咱们也做了个靠牛虚拟机但是咱们在网上卖这个软件是不是就算侵权了。
杨中科 09:46:29
要它它用的什么协议了
杨中科 09:47:13
常用开源协议的详细解析
http://www.yuanma.org/data/2006/0410/article_234.htm
*** 09:47:21
哦,这么说,开源的泛意是免费提供源代码。
杨中科 09:48:25
开源里不要提“免费”两个字,这是误解,没人说要免费。我只说我的代码是Open的
杨中科 09:48:38
对谁open、怎么open是另外一回事
杨中科 09:49:06
比如微软的所谓开源协议也是通过国际认证的,它的所谓开源就是你买了微软的产品以后才给你开源吗
杨中科 09:49:23
才给看源码,而且只能看不能改。数据结构有什么用?*** 09:51:48
那你说像eclipes这个开源ide,他的盈利方法是什么呢?也是靠卖服务。还有什么开源社区,他们靠什么呢
杨中科 09:53:36
eclipse的盈利模式主要有:靠eclipse把开发者聚集到IBM旗下,有了人气剩下的钱就好赚了,比如可以推他们的商业产品
*** 09:55:40
啊,这么说ibm搞eclipes完全是义务劳动了。当然后期的推产品是后话。就单搞eclies来说他是根本不靠这个ide来赚钱的?杨中科 09:55:49

杨中科 09:57:16
它也有自己的商业产品的开发工具是基于eclipse的,这样一来熟悉eclipse的开发人员用他们的开发工具非常方便,二来可以靠社区的力量完善他们的商业化产品
杨中科 09:57:23
互联网时代人气就是财富
*** 09:57:34
所以说中国开源路慢慢,你给他开了,他搞个东西卖钱,但他也不管你协议不协议的。
本聊天记录是“计算机321”:http://jsj321.com内部交流实录,因为隐私的缘故隐去了QQ号码。

posted @ 2008-09-23 22:53 CowNew开源团队 阅读(369) | 评论 (0)编辑 收藏

今天看到两篇文章,都是谈软件开发方向的大学生应该学什么的。总是在网上看到大面积的在吹嘘“计算机专业高校教的已经过时了,企业要求掌握开发经验的大学生,培训机构异常火爆”之类的话,我突然意识到这些其实都是那些培训机构的本位主义的炒作而已。其实大部分企业招聘应届生的时候并不是要求学生有太多的所谓项目经历,但是要求最高的是应届生对专业课的掌握程度,企业的笔试题也是以专业课的题目为主。这是企业的校园招聘和社会招聘不同的地方。有人可能会举出反例,我只能说那样要求应届生有这样那样项目经历的公司都是草台班子小公司,不在我们考虑的范围之内。有的公司招聘应届生的时候如果看到你有太多项目经验的时候甚至怀疑你在校期间是否有认真学习专业课。不能忽视的一个事实是很多高校的任课教师并没有很丰富的开发经验,因此也不能教给学生关于“这门课有什么实际用途”之类的问题,这一直困惑着我们。可以看到像jsj321.com这样的网站已经开始在向这方面努力了,搞了很多针对在校计算机专业大学生的免费在线课程,请了很多有项目经验以及扎实理论基础的工程师来讲课,这样与学校的课程同步学习,“白天听大学老师讲理论,晚上听网上老师讲实战”,两者相结合就能培养出有实战经验,同时又不失理论基础的软件精英。
下面是这两篇文章的摘录:

写给还在大学的兄弟姐妹

FROM:http://www.cnblogs.com/hanxianlong/archive/2008/09/17/1292446.html

基础很重要

许多企业招聘,要求大学本科毕业生有一定的工作经验。而现实是,当今的大学教育使得有工作经验的本科生少之又少。从大学过来的人都应该清楚大学生活是什么样子:要么很努力的学习——这是考研一族,要么外出找兼职——这是工作一族,要么就过一天少一天——这是混日子一族。其他的情况当然也有,在此暂且只分为这几类学生。考研的学生,若是考研成功便进一步的去深造,若失败则面临着求职。而他们学习是如此的刻苦,何来工作经验?兼职的学生,有些同学可能做的很好,能够很好的处理兼职与学习的关系,而某些认为兼职就是“赚钱”的学生可能处理的并不是那么好,认为“能让我毕业就行”,殊不知毕业时找工作别人对于兼职所带来的工作经验向来是不太认可的。混日子一族就不说了,天天要么游戏要么网吧要么睡觉,习没学好,更别提什么经验。
那么,我们大学毕业生就果然不能找到工作了么?答案当然是否定的!虽说每年的毕业生都在增加,每年的就业压力都在加大,但是我们应该看到,为什么就业压力会加大,应从我们自身多找一些原因。试问,哪个IT公司愿意招一个连冒泡排序都不知道的人?你可能抱怨毕业生真的太多竞争真的太激烈,并且自己也一点经验都没有,但是也应该看到,每年的招聘会上签约的同学还是很多的。仔细分析一下那些能够成功把自己“卖”出去同学的“卖”出自己的原因——他们的基础一定很不错,至少在求职那段时间内他们把课堂上学习的知识又一次巩固了——这一点是毫无疑问的。校园招聘毕竟与社会招聘有很大的区别,企业也对当前大学教育状况有一定的了解,因此招聘的流程是先笔试,当然一般是一些和书本上学习过的知识相关的笔试题目,比如排序算法,数据的类型等等,笔试通过你才有机会去面试。既然笔试的题目是基础,那么一个连基础都不明白的大学生还有什么理由有机会进入面试,还有什么理由进入公司呢?
所以说,重视基础!不要说大学中的课本没用,打算毕业后走技术方向的你一定要重视几门基础课的学习,其中包括C语言、数据库、数据结构,至少这三门应该是能够掌握的非常熟练。要是问,什么叫“熟练”呢?去到网上找一些笔试题做一下去,看看自己能够得多少分然后就知道什么叫“熟练”了。
应届生求职最重要的一点,就是需要有扎实的基础。

有了经验,还需要什么

我提到,有些同学是“兼职”,当然也可能是“全职”。比如我自己,从大三开始便到一家软件公司5×8的工作,所以到毕业之后也就有两年的实际开发经验。求职之时底气也足,简历上也不仅仅是空虚的“掌握某某语言”,而是一些自己负责开发的一些项目。
当然,经验并不等于全部。求职之前先仔细的审核一下“有经验的自己”的基础是否牢固。一个有经验的应届生去应聘当然会比没有经验的同届学生有优势,但是如果你基础不牢固的话,那么这所谓的“优势”会成为你求职路上的绊脚石。
举个例子说,你做了两年的开发,当面试官问你引用类型与值类型的区别时你若不知道,那么面试官心中肯定会想,这基础的知识都不懂这两年是如何开发的?进而可能会想到你仅仅是做一些非常简单的编码工作或者认为你的经验是捏造的……这时候你就处于被动了,虽然实际开发中你不知道引用类型和值类型的区别一样可能开发出能够运行的程序来,但面试官的面试往往是从理论开始。一旦你理论上不行,那么面试官对你的耐心就会大打折扣。
我此次求职过程中就遇到了这样的问题。因为开始时并没有注重基础的学习而认为仅仅是能够实现某项功能即可,结果导致笔者在理论上很是欠缺。在求职某家公司时因基础知识不牢固而被pass之后就利用一周的时间狠补以前就应该掌握的理论知识,再在其后的无论是笔试还是面试过程中就一路绿灯了。
其实就算不为了求职,我们也应该把理论知识掌握牢固。如果说经验是躯体的话,那么理论便是灵魂。躯体总是在灵魂的支配下活动的,没有灵魂的躯体只能说是……行尸走肉。也就是说,一个不懂理论的程序员永远只能是代码编写者,不可能成为优秀的软件设计师。
一句话,有了经验,还需要有理论的护航才能走得更高更远。

有了经验,也有了能力,求职一定会成功么?

如果你前两点都已经具备,那么就一定会在求职的过程中很顺利么?答案显然也是否定的。面试有一定的技巧,虽然说面试仅仅那短短的几分钟,或者时间长的能达到半个小时,你需要在这短短的几分钟到半个小时之间把自己的优点和拥有的经验全面的推销给你的面试者,让他真正相信你是一个经验和能力具备的人。
大四上学期,我曾经作为所在的软件公司的技术面试官到一些大学去招聘,我很奇怪有些学生会在面试的时候显得非常紧张,可能和个人性格或者其他什么方面有关。这一点请你记住:面试官也是人,或许说不定和你同龄也不一定,不要对他产生畏惧的心理。尽可能详尽地介绍你自己的优点,当然当面试官问到你的缺点时,你应该能够用一种积极的态度去评价自己的缺点,而不是说“我怎么怎么不行”,应该让面试官知道你能够正确地认识自身的缺点并努力的改正也是增加自己面试分的一种途径。
有了经验和能力的你,在求职时应多注意自己在面试时的表现,包括你的衣着,你的言行,还有你对某些问题的看法等等。

题外话

其实一个真正优秀的毕业生,他从刚入大学时就会去考虑自己毕业之后如何找工作,会考虑到找工作时需要哪些知识并以此为动力在自己的大学生活中朝着自己的方向努力。
看到那些成天只知道玩的学弟学妹,有时笔者会感到一丝的难过与凄凉。他们或许还体会不到就业的压力,或者还体会不到大四毕业时找工作的艰难与无奈。嗨,只希望读到本篇文章的大校大学生们能够珍惜自己的时光,多做一些有意义的事情,而不要每天在魔兽中生活。不能让自己在毕业之后后悔。

软件专业毕业生之一个月攻略

from:http://www.cnblogs.com/wsgpd/archive/2008/09/17/1292428.html

因为毕业生本来没有什么开发经验,所以我们很少考毕业生什么具体的技术例如aspx、Ajax、Hibernate、ADO什么的,考了也做不出来,做出来也是垃圾。这些具体的技术可以在工作中学习。如果面试官一上来就问你会不会Ajax什么的,肯定是个烂公司,没打算长期培训你。
我们要的人最基本的要求是态度好+逻辑清晰,否则写出来的代码是垃圾,以后没人敢维护。
计算机逻辑不清楚的人最好不要做计算机,宁可去坐坐小生意好了,否则越做越累,真是耽误自己的前途。
给毕业生的建议如下,估计狂补课一个月应该能大大提高自己的能力:
1. 多学学数据结构和算法。
     把书上的练习题全部用C/C#/Java做一遍,保证自己逻辑清楚。
2.数据库基本原理。
     把微软SQL Server的教材的练习做一遍,SQL的基本概念就很清楚了。
3.HTML
    做做一个网上商店的例子,过一遍HTML就行了。不见得一定是PetShop这种级别的,PetShop对于新毕业生估计理解不透,还是做好基本功再说。
4.不要天天跟技术潮流
    技术潮流会天天变的,你跟不过来,看看就行了。把以上几门课学学好已经能够混饭吃了。等基础打好了,再去看潮流。
    所以不建议毕业生天天追着CSDN、CNBlogs看,还是多做练习。dudu不会骂我吧。[这段话很多人不满,解释下,我很希望大家都去学习框架和新技术,但是前提是你的数据结构和算法要学好是吧]
5. 态度和责任感
    如果工作态度不够好,到哪里都会做不好。不要骂公司,优秀的人长期下来大家都看得到,会越来越多机会和名声。以后年纪大了,都是靠名声吃饭的。名声臭了,必定没啥前途的。
“计算机321”评论:永远不能忽视专业课的学习,大学书本上的东西永远不过时。

posted @ 2008-09-18 16:14 CowNew开源团队 阅读(2043) | 评论 (4)编辑 收藏

BT全名为BitTorrent,是一个p2p软件,你在下载download的同时,也在为其他用户提供上传upload,因为大家是“互相帮助”,所以不会随着用户数的增加而降低下载速度。
下面是一般用ftp,http等分享流程:


1.JPG

下面是用BitTorrent分享的流程:


2.JPG

其实跟ED也十分相似,ED跟BT不同的地方有:
  ED--要连上一个固定server BT--没有固定server,只要分享者制作出该分享档案的.torrent档公布出来便可
  ED--分享的人越多速度越快? BT--种子seed越多速度越快
  ED--世界性的分享 BT--团体性的分享(可做到速度保证)
  ED--知道在分享者的user name &速度 BT--没显示使用者/分享者名字
比起其它的P2P软件,BT有个独特的地方,它存在一个中间的WEB服务器,就是我们在发布的时所填写的announce。 该服务器提供了发布的统一管理,不像其它P2P软件那样到处去找哪些非常不稳定的个人服务器,相对起来让人安心的多。
该WEB服务器更大的作用是内网用户可以做 Send(下面会说明原理),这是其它软件无法做到的,但不好的地方是announce当机的时候就无法下载了。要知道P2P下载关键是要人气要高,announce停一下就搞到人气全没有了。
.torrent 的作用
大家都知道我们要用BT下载 ,就要先下载一个.torrent文件,这个文件到底有甚么呢:
首先是 announce 纪录了发布服务器的位置,让BT知道是那个WEB服务器发布的,然后是一些文件信息,文件名,目录名,长度等等,最后是片段长度,和片段的 Sha1 校验码,(BT为了事现续传和文件校验,就把文件分成若干个片段),大家可以用写字板打看torrent文件看看,就是知道个大概,后面的乱码是片段 Sha1 校验码。
开始-续传的实现 sha校验
BT 打开一个 torrent文件后,先要你选择文件保存那里。然后判断文件不存在的话就建立新文件,存在的话就用 Sha1 校验码去校验文件---错误的就是还没下载的,这样就可以实现续传了,但128位校验,想不慢都不行
得到 peer
现在知道要下载甚么了,到那里下载呢?这就要寻找有谁提供上传了,这里BT是通过WEB服务器来实现的,首先BT会通过分析 torrent 来得到下面一串网址
http://btfans.3322.org:6969/announce?info_hash=%CDg%D4%19%AD%96%9D%93%03%DB%E4%FFXA%C6%5D%043%17O&peer_id=%00%00%00%00%00%00%00%00%00%00%00%00%A3E%E0%9BeB%90d&port=6882&uploadED=0&downloadED=0&left=19171922&event=startED
http://BTfans.3322.org:6969/announce 是发布服务器的地址
info_hash 是torrent文件中的 info 部分的Sha校验码,WEB通过它在发布列表找到对应的纪录
peer_id 是自身的标识,它是12个0和当前时间+全球的唯一标识码(GUID)的Sha校验的前八位,共20位
port 你提供上传的 port
IP 你的ip地址,没有的话服务器会自己找到
uploadED downloadED 你上传和下载了多少,服务器可以用它来做流量分析
left 你还要下载多少个字节
event 状态,告诉服务器你是准备开始下载,还是停止,还是下载完成了
以上这个操作默认 5 分钟做一次,或由服务器设定
服务器会做什么
服务器中有个一个 track 程序来管理这些请求,得到这一串代码后就会用 info_hash 来查找列表,找到你就可以下载,找不到就对不起啦。接着它会反连(NatCheck)你的 IP 和 Port这样就可以知道你是内网用户还是共网用户(如果你是内网用户,它是连不通的,因为它会连到你的服务器上,你的服务器当然没有这个端口啦),然后服务器返回现在正在下载这个文件的所有公网用户的IP和port,就像是:d8:intervali1800e5eersld2:ip14:xxx.xxx.xx.xxx7eerid20:00180531904b7e3abdd74orti6881eeee
interval 1800 是告诉 BT 隔多少秒来查询一次这里是 30 分钟 (有点过分了),最后如果你是公网用户它会把你提交的 IP 和 Port 放到info_hash 对应的列表中,这样其它人就可以找到你
下载
得到这些 peer IP后,BT就可以找到对应的IP下载了,BT会到所有的peer去寻找自己要下载的东西,不是一定要到seed下载。BT每找到一个peer就和建立一个Socket来下载,所以下载的人越多,速度就越快。
“计算机321”评论:大家用软件的过程中一定要分析其原理,因为未来这些软件有可能会要我们来开发,我们不是普通的用户,而是未来的开发人员,比如像这篇文章就分析的很透彻。给大家留一个习题:分析一下为什么有人说BT软件毁硬盘,要从操作系统、网络原理等方面进行分析,要分析到硬盘的工作原理、网络数据的发送接收,又想到的同学请到“计算机321”(http://jsj321.com)发表自己的看法,也可以听老师在线讲相关原理。
内网用户可以做Send的原理
上面说到服务器只会返回公网的ip的,那内网用户怎么可以做Send呢,这是因为BT是一个主动连接的软件(即使你已经下载完了,也不也会主动连接他人)下面是一个仿真流程:
1 内网用户开始做 seed,
2 服务器收到请求,由于是第一个所以也没有peer返回
3 公网用户提交请求,由于seed是内网用户所以也没有peer返回,等待下载,但服务器会把它的IP放到列表中
4 内网经过 interval 时间间隔后,再向服务器放出请求,得到上面得公网IP
5 得到公网IP后,内网马上进行连接
6 公网用户建立连接,数据开始传输 (注意现在是公网用户做服务器,内网用户做客户端,是不是有点怪)
7 其它内网用户去上面公网用户下载数据
所以,内网用户做 seed 一定要有公网用户得参与,否则其它内网用户无法下载。如果全部是内网用户,那个所有连接都不会成立,当然这是比较极端的情况。
以上可见,内网用户不能和内网用户连接,其它用户无法从服务器查到你,所以无法主动连接你,你只能每隔30分钟从服务器找到公网用户一个个进行连接。
由于中国很多用户的是内网用户(我从服务器上查回来的peer还没试过超过10个的),所以内网用户用BT的确要比公网用户要慢很多。

posted @ 2008-09-18 16:03 CowNew开源团队 阅读(652) | 评论 (0)编辑 收藏

今天上午我们报道了:三鹿公司网站被黑
下午三鹿公司的网站很快恢复,但是速度非常慢。今晚当我们再次访问的时候发现三鹿公司网站再次被黑,并且不再像上午那样只改了网页的title,而是将首页全部换了,截图如下:

攻击者在首页上写到:
小黑们对中国社会责任心片面一窥 by racle@sky5+1.com

某old passby,楼主继续黑,偶打酱油路过~

诚心诚意恳求三鹿公司不要草菅人命!~

聊天别占主要地方SA..我就是看你改人家东西才来的.毕竟他行为太可耻了.出事了似乎还不愿意坦白承认错误..很害人的,所以还得管一管.

草菅人命固然可恶,但改首页貌似不厚道!.

落伍者到此一游


塔沟学员到此一游

原帖:http://www.jsj321.com/viewthread.php?tid=72&extra=page%3D1

posted @ 2008-09-12 20:55 CowNew开源团队 阅读(317) | 评论 (0)编辑 收藏

今天上网搜东西,无意中发现我上大学时为了创建开源团队而发的帖子,好熟悉的感觉,好像一切都在眼前一样:
http://bbs.sdu.edu.cn/bbsgcon.php?board=Math&num=174

截图:


熟悉的曾ID:lincosoft ,熟悉的内线电话:93142 ,熟悉的IP地址:211.87.215.43。
已经四年多过去了,时间好快!

 
FROM:http://www.jsj321.com/viewthread.php?tid=71&extra=page%3D1&frombbs=1

posted @ 2008-09-12 20:36 CowNew开源团队 阅读(291) | 评论 (0)编辑 收藏

http://www.jsj321.com/viewthread.php?tid=70&page=1&extra=page%3D1

查看网站代码:

<title>三聚氰胺集团</title>
<meta name="description" content="石家庄三鹿集团是集奶牛饲养、三聚氰胺加工、科研开发为一体的大型企业集团,是中国食品工业百强、中国企业500强、农业产业化国家重点龙头企业!三鹿奶粉产销量连续14年实现全国第一,酸牛奶进入全国第二名,液体奶进入全国前四名。三鹿奶粉、液态奶被确定为国家免检产品,并双双再次荣获“中国名牌产品”荣誉称号。2007年被商务部评为最具市场竞争力品牌。“三鹿”商标被认定为“中国驰名商标”;产品畅销全国31个省、市、自治区。2006年位居国际知名杂志《福布斯》评选的“中国顶尖企业百强”乳品行业第一位。经中国品牌资产评价中心评定,三鹿品牌价值达149.07亿元。
posted @ 2008-09-12 13:25 CowNew开源团队 阅读(509) | 评论 (3)编辑 收藏

上午下载试用了一下Google chrome,让我眼前一亮的是它的多进程功能。每打开一个页面,chrome都会开启一个新的进程,这可以通过“任务管理器”看出来。这样的优势就是各个页面之间不会互相影响,因此不会出现IE中浏览Ajax泛滥的网页的时候出现的整个浏览器假死的情况,极端情况下,当一个页面中的chrome崩溃的时候其他页面不会受影响。
我尝试分析chrome的实现机理,一开始我认为每个页面就是一个进程窗口,只不过chrome将这些窗口通过SetParent这样的方式展示到一个父窗口中而已。但是使用Spy++进行探测后我大吃一惊,每个页面以及主窗口页面的ProcessId是同一个,也就是显示界面还是一个进程。因此我猜测chrome只是把每个页面对应的运行引擎放到单独的进程了,渲染和交互的界面还是同一个进程。
看来Google chrome还是受限于界面只能是一个进程、线程的约束,啥时候操作系统图形引擎能够支持每个子Window都可以运行在不同的进程、线程中就好了,呵呵。

给chrome来个暴力测试:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>TestMe</title>
    <meta http-equiv="content-type" content="text/html; charset=GBK">
  </head> 
  <body>
   <script>
 function ok()
 {
  while(true)
  {
  }
 }
 </script>
    <button onclick="javascript:ok()">ok</button>
  </body>
</html>

上面的HTML页面在IE、FF中运行都会提示“会消耗系统资源,是否继续”,一旦继续浏览器就死掉了,其他页面也无法打开,而用chrome就没有这个问题,其他页面照样跑的欢。我以前试用一些复杂的网页游戏的时候,这些游戏中使用JavaScript进行的AI运算如果非常耗时,那么IE就会弹出讨厌的“会消耗系统资源,是否继续”提示,有了chrome就再也不担心这个问题了,是否意味着以后大量的运算逻辑可放在浏览器端了呢?期待!!!

posted @ 2008-09-03 15:46 CowNew开源团队 阅读(2143) | 评论 (10)编辑 收藏

经常需要把自己电脑操作录制成视频,然后放到youku、ku6等网站,这样就能与别人共享了。youku的单个视频限制大小为200M,因此如何制作比较清晰并且占用尽可能少的空间的视频就是一个非常重要的事情。
由于在电脑操作过程中我们的注意力一般集中在鼠标所在的区域,因此Camtasia Studio提供了一个SmartFocus技术,也就是它会把当前鼠标所在的区域放大,这样就看起来清晰了。操作方式如下:
   新建一个工程,然后将camrec导入,然后将camrec添加到时间线,添加的时候在弹出的对话框中选中Web(也就是640*480大小),并且保证选中“Smart Focus”(这个技术会将屏幕的当前焦点自动放大。),然后导出成WMV格式“ScreenView and Audio Medium”,尺寸同样为640*480,或者使用现成配好的“ForYouku”。
posted @ 2008-08-28 12:52 CowNew开源团队 阅读(3211) | 评论 (0)编辑 收藏

《乡村教师》
刘慈欣

 


  这篇小说同我以前的作品相比有一些变化,主要是不那么“硬”了,重点放在营造意境上。不要被开头所迷惑,它不是你想像的那种东西。我不敢说它的水准高到哪里去,但从中你将看到中国科幻史上最高奇最不可思议的意境。   ——作者前言 


  他知道,这是最后一课要提前讲了。
  又一阵巨痛从肝部袭来,几乎使他晕厥过去。他已经没有力气下床了,便艰难地移向床边的窗口。月光映在窗纸上,银亮亮的,使小小的窗户看上去像是通向另一个世界的门,那个世界的一切一定都是银亮亮的,像用银子和不冻人的雪做成的盆景。他颤颤地抬起头,从窗纸的破洞中望出去,幻觉立刻消失了,他看到了远处自己度过了一生的村庄。
  村庄静静地卧在月光下,像是百年前就没人似的。那些黄土高原上特有的平顶小屋,形状同村子周围的黄土包没啥区别,在月色中颜色也一样,整个村子仿佛已融入这黄土坡之中。只有村前那棵老槐树很清楚,树上干枯枝杈间的几个老鸦窝更是黑黑的,像是滴在这暗银色画面上的几滴醒目的墨点……其实村子也有美丽温暖的时候,比如秋收时,外面打工的男人女人们大都回来了,村里有了欢声笑语,家家屋顶上是金灿灿的玉米,打谷场上娃们在秸杆堆里打滚;再比如过年的时候,打谷场被汽灯照得通亮,在那里连着几天闹红火,摇旱船、舞狮子。那几个狮子只剩下咔嗒咔嗒响的木头脑壳,上面油漆都脱了,村里没钱置新狮子皮,就用几张床单代替,玩得也挺高兴……但十五一过,村里的青壮年都外出打工挣钱去了,村子一下没了生气。只有每天黄昏,当稀稀拉拉几缕炊烟升起时,村头可能出现一两个老人,扬起山核桃一样的脸,眼巴巴望着那条通向山外的路,直到老槐树挂住的最后一抹夕阳消失。天黑后,村里早早就没了灯光,娃娃和老人们睡得都早,电费贵,现在到了一块八一度了。
  这时村里隐约传出了一声狗叫,声音很轻,像是狗在说梦话。他看着村子周围月光下的黄土地,突然觉得那好像是纹丝不动的水面。要真是水就好了,今年是连着第五个旱年了,要想有收成,又要挑水浇地了。想起田地,他的目光向更远方移去,那些小块的山田,月光下像一个巨人登山时留下的脚印。在这只长荆条和毛蒿的石头山上,田地只能是这和么东一小块西一小块的,别说农机,连牲口都转不开身,只能凭人力种了。去年一家什么农机场到这儿来,推销一种微型手扶拖拉机,可以在这些巴掌大的地里干活。那东西真是不错,可村里人说他们这是闹笑话哩!他们想过那些巴掌地能产出多少东西来吗?就是绣花似的种,能种出一年的口粮就不错了,遇上这样的旱年,可以种子钱都收不回来呢!为这样的田买那三五千一台的拖拉机,再搭上两块多一升的柴油?唉,这山里人的难处,外人哪能知晓呢?
  这时,窗前走过几个小小的黑影,这几个黑影在不远的田垅上围成一圈蹲下来,不知要干什么。他知道这都是自己的学生,其实只要他们在近旁,不用眼睛他也能感觉到他们的存在,,这直觉是他一生积累出来的,只是在这生命的最后时间里更敏锐了。
  他甚至能认出月光下的那几个孩子,其中肯定有刘宝柱和郭翠花。这两个孩子都是本村人,本来不必住校的,但他还是收他们住了。刘宝柱的爹十年前买了个川妹子成亲,生了宝柱,五年后娃大了,对那女人看得也松了,结果有一天她跑回了四川,还卷走了家里所有的钱。这以后,宝柱爹也变得不成样了,开始是赌,同村子里那几个老光棍一样,把个家折腾得只剩四堵墙一张床;然后是喝,每天晚上都用八毛钱一斤的地瓜烧把自己灌得烂醉,拿孩子出气,每天一小揍三天一大揍,直到上个月的一天半夜,抡了根烧火棍差点把宝柱的命要了。郭翠花更惨了,要说她妈还是正经娶来的,这在这儿可是个稀罕事,男人也很荣光了,可好景不长喜事刚办完大家就发现她是个疯子,之所以迎亲时没看出来,大概是吃了什么药。本来嘛,好端端的女人哪会到这穷得鸟都不拉屎的地方来?但不管怎么说,翠花是生下来了,并艰难的长大。但她那疯妈妈的病也越来越重,犯起病来,白天拿菜刀砍人,晚上放火烧房,更多的时间还是在阴森森地笑,那声音让人汗毛直竖……
  剩下的都是外村的孩子了,他们的村子距这里最近的也有十里山路,只能住校了。在这所简陋的乡村小学里,他们一住就是一个学期。娃们来时,除了带自己的铺盖,每人还背了一袋米或面,十多个孩子在学校的那个大灶做饭吃。当冬天降临时,娃们围在灶边,看着菜面糊糊在大铁锅中翻腾,灶膛里秸秆橘红色的火光映在他们脸上……这是他一生中看到过的最温暖的画面,他会把这画面带到另一个世界的。
  窗外的田垅上,在那圈娃中间,亮起了几点红色的小火星星,在这一片银灰色的月夜的背景上,火星星的红色格外醒目。这些娃娃们在烧香,接着他们又烧起纸来,火光把娃们的形象以橘红色在冬夜银灰色的背景上显现出来,这使他又想起了那灶边的画面。他脑海中还出现了另一个类似的画面:当学校停电时(可以是因为线路坏了,但大多数时间是因为交不起电费),他给娃们上晚课,手里举着一棵蜡烛照着黑板。“看见不?”他问。“看不显!”娃们总是这样回答。那么一点点亮光,确实难看清,但娃们缺课多,晚课是必须上的。于是他再点上根蜡,手里举着两根。“还是不显!”娃们喊。他于是再点上一根,虽然还是看不清,娃们不喊了,他们知道再喊老师也不会加蜡了,蜡太多了也是点不起的。烛光中,他看到下面那群娃们的面容时隐时现,像一群用自己的全部生命拼命挣脱黑暗的小虫虫。
  娃们和火光,娃们和火光,总是娃们和火光,这是这个世界深深刻在他脑子中的画面,但始终不明其含义。
  他知道娃们是在为他烧香和烧纸,他们以前多次这么干过,只是这次,他已经没有力气像以前那样斥责他们迷信了。他和尽了一生在娃们心中燃起科学和文明的火苗,但他明白,同笼罩着这偏远山村的愚昧和迷信相比,那火苗是多么弱小,像这深山冬夜中教室里的那根蜡烛。半年前,村里的一些人来到学校,要从本来已经很破旧的校宿取下橼子木,说是修村头的老君庙用。问他们校舍没顶了,娃们以后住哪?他们说可以睡教室晨嘛。他说那教室四面漏风,大冬天能住?他们说反正都是外村人。他拿起一根扁担和他们拼拿,结果被人家打断了两根肋骨。好心人抬着他走了三十多里山路,送到了镇医院。
  就是在那次检查伤势时,意外发现他患了食道癌。这并有稀奇,这一带是食道癌高发区。镇医院的医生恭喜他因祸得福,因为他的食道癌现处于早期,还未扩散,动手术就能治愈。食道癌是手术治愈最高的癌症之一,他臬拣了条命。
  于是他去了省城,去了肿瘤医院,在那里他问医生动一次这样的手术要多少钱,医生说像你这样的情况可以住我们的扶贫病房,其它费用也可适当减免,最后下来不会太多的,也就两万多元吧。想到他来自偏远山区,医生接着很详细地给他介绍住院手续怎么办,他默默地听着,突然问:“要是不手术,我还有多长时间?”
  医生呆呆地看了他好一阵儿,才说:“半年吧。”不解地看到他长出了一口气,好像得到了很大安慰。
  至少他能送走这届毕业班了。
  他真的拿不出这两万多元。虽然民办教师工资很低,但干了这么多年,孤身一人了无牵挂,按说也有攒下一些钱了。只是他把钱都花在娃们身上了,他已记不清给多少学生代交了学杂费,最近的就有刘宝柱和郭萃花;更多的时候,他看到娃们的饭锅里没有多少油星星,,就用自己的工资买些肉和猪油回来……反正一现在,他全部的钱也只不过手术所需的十分之一。
  沿着省城那条宽长的大街,他向火车站走去。这时天已黑了,城市的霓虹灯开始发出迷人的光芒,那光芒之绚丽之斑斓,让他迷惑;还有那些高楼,一入夜就变成了一盏盏高耸入云的巨大彩灯。音乐声在夜空中飘荡,疯狂的,轻柔的,走一段一个样。
  就在这个在属于他的世界里,他慢慢地回忆起自己不算长的一生。他很坦然,各人有各人的命,早在二十年前初中毕业回到山村小学时,他就选定了自己的命。再说,他这条命很大一部分是另外一位山村教师给的,他就是在自己现在任教的这所小学时度过童年的。他爹妈死得早,那所简陋的山村小学就是他的家,他的小不老师把他当亲儿子待,日子虽然穷,但他的童年并不缺少爱。那年,放寒假了,老师要把他带回自己的家里过冬。老师的家很远,他们走了很长的积雪的山路,当看到老师家的村子的一点灯光时,已是半夜了。这时他们看到身后不远处有四点绿荧荧的亮光,那是两双狼眼。那时山里狼很多,在学校周围就能看到一堆堆狼屎。有一次他淘气,把那灰白色的东西点着扔进教室里,使浓浓的狼烟充满了教室,把娃们都呛得跑了出来,让老师很生气。现在,那两只狼向他们慢慢逼近,老师折下一根粗树枝,挥动关它拦住狼的来路,同时大声喊着让他向村里跑。他当时吓糊涂了,只顾跑,只想着那狼会不会绕过老师来追他,只想着会不会遇到其他的狼。当他上气不接下气地跑进村子,然后同几个拿枪的汉子去接老师时,发现老师躺在一片已冻成糊状的血泊中,半条腿和整只胳膊都被狼咬掉了。老师在被送往镇医院的路上就断了气。当时在火把的光芒中,他持到了老师的眼睛,老师的肋帮被深深的咬掉一大块,已说不出话,但用目光把一种心急如婪的牵挂传给了他。他读懂了那牵挂,记住了那牵挂。
  初中毕业后,他放弃了在镇政府里一人不错的工作机会,直接回到了这个举目无亲的山村,回到了老师牵挂的这所乡村小学。这时,学校已经因为没有教师荒废好几年了。
  前不久,教委出台新政策,取消了民办教师,其中的一部分经考试考核转为公办,当他拿到教师证时,知道自己已经成为一名国家承认的小学教师了,,很高兴,但好只是高兴而已,不像虽的同事们那么激动。他不在乎什么民办公办,他只在乎那一批又一批的娃们,从他的学校读完的小学,走向生活。不管他们是走出山去还是留在山里,他们的生活和那些没有上过一天学的娃们总是有些不一样。
  他所在的山区,是空虚国家最贫困的地区之一。但穷不是最可怕的,最可怕的是那里的人们对现状的麻木。记得那是好多年前了,搞包产到户,村里开始分田,然后又分其他的东西。对于村里唯一的一台拖拉机,大伙对油钱和出机怎么分配的问题总也谈不拢,最后唯一都能接受的办法就是把拖拉机分了。真的分了,你家拿一根轮子他家拿一根轴……再就是两个月前,一家工厂来扶贫,给村里安了一台水泵,考虑到用电贵,人家还给带了一台小柴油机和足够用的柴油。挺好的事儿,但人家前脚走,村里后脚就把机器都卖了,连泵带柴油机,只卖了一千五百块钱,全村好吃了两顿,算是过了个好年……后来,一家皮革厂来买地建厂,大家糊里糊涂把地给卖了,那厂子建起后,硝皮子的毒水流进了河里,渗进了井里,人一喝了那水浑身起红疙瘩,就这也没人在乎,还沾沾自喜那地买了个好价钱……看村里那些聚不上媳妇的光棍汉们每天除了赌就是喝,但不去种地,他们能算清:穷到了头县里每年总会有些救济,那钱算下来也比在那巴掌大的山地里刨一年土坷垃挣得多……没有文化,人都变得下作了。那里的穷山恶水固然让人灰心,但真正让人感到没指望的,是山里人那呆滞的目光。
  他走累了,就在人行道边坐下来。他面前,是一家豪华的大餐馆,那餐馆靠街的一整堵墙全是透明玻璃,华丽的枝形吊灯把灯光投射到外面。整个餐馆像一个巨大的鱼缸,里面穿着华贵的客人们则像一群多彩的观赏鱼。他看到在靠街的一张桌子旁坐着一个胖男人,这人头发和脸似乎都在冒油,使他看上去像用一大团表面涂了油的蜡做的。两旁各坐着一个身材高挑穿着暴露的女郎,那男人转头对一个女郎说了句什么,把她逗得大笑起来,那男人跟着笑起来,而另一个女郎则娇嗔地用两个小拳头捶那个男的……真没想到还有个子这么高的女孩子,秀秀的个儿,大概只到她们的一半……他叹了口气,唉,又想起秀秀了。
  秀秀是本村惟一一个没有嫁到山外的姑娘,也许是因为她从未出过山,怕外面的世界,也许是别的什么原因。他和秀秀好过两年多,最后那阵子好像就成了,秀秀家里了通情达理,只要一千五百块的肚疼钱----这是西北一些农村收彩礼的一个名目,意思是作为娘生女儿肚子疼的补偿。但后来,一些出去打工的人赚了些钱回来,和他同岁的二蛋虽不识字但脑子活,去城里干起了挨家挨户清洗抽油烟机的活,一年下来竟能赚个万把块。前年回来呆了一个月,秀秀不知怎的就跟这个二蛋好上了。秀秀一家全是睁眼瞎,有里粗糙的干打垒墙壁上,除了巾着一团一团用泥巴和起来的瓜种子,还划着长长短短的道道儿,那是她爹多少年来记的帐……秀秀没上过学,但自小对识文断字的人有好感,这是她同他好的主要原因,但二蛋的一瓶廉价香水和一串镀金项链就把这种好感全打消了。“识文断字又不能当饭吃。”秀秀这样对他说。虽然他知道识文断字是能当饭吃的,但具体到他身上,他吃得确实比二蛋差好远,所以他也说不出什么。秀秀看他那样,转身走了,只留下一股让他皱鼻子的香水味。
  和二蛋成亲一年后,秀秀生娃死了。他还记得那个接生婆,把那些锈不拉叽的刀刀铲铲放到火上烧一烧就往里捅,秀秀可倒霉了,血流了一铜盆,在送镇医院的路上就咽气了。成亲办喜事的时候,二蛋花了三万块,那排场在村里可真是风光死了,可他怎的就舍不得花点钱让秀秀到镇医院去生娃呢?后来他一打听,这花费一般也就二三百,就二三呀。但村里历来都是这样,生娃是从来不去医院的,所以没人怪二蛋,秀秀就这命。后来他听说,比起二蛋妈来,她还算幸运的。生二蛋时难产,二蛋爹从产婆那得知是个男娃,就决定只要娃了。于是二蛋妈被放到驴子背上,让那驴子一圈圈走硬是把二蛋挤压出来。听当时看见的人说,院子里血流了一圈……
  想到这里他长出了一口气,笼罩着家乡的愚昧和绝望使他窒息。
  但娃们还是有指望的,那些在冬夜寒冷的教室中,对于那些盯着烛光照着的黑板的娃们来说,他就是那蜡烛,不管能点多长时间,发出的光有多亮,他总算是人头点到尾了。
  他站起身来继续走,没走了多远就拐进了一家书店,城里就是好,还有夜里开门的书店。除了回程的路费,他把身上所有的钱都买了书,以充实他的乡村小学里那小小的图书室。半夜,提着那两捆沉重的书,他踏上了回家的火车。

 


  在距地球五万光年的远方,在银河系的中心,一场延续了两万年的星际战争已接近尾声。
  那里的太空中渐渐隐现出一个方形区域,仿佛灿烂的群星的背景被剪出一个方口,这个区域的边长约十万公里,区域的内部是一种比太空更黑的黑暗,让人感到一种虚空中的虚空。从这黑色的正方形中,开妈浮现出一些实体,它们形状各异,都有月球大小,呈耀眼的银色。这些物体越来越多,并组成一个整齐的立方体方阵。这银色的方阵庄严地驶出黑色正方形,两者构成了一幅挂在宇宙永恒墙壁上的镶嵌画,这幅画以绝对黑体的正方形天鹅绒为衬底,由纯净的银光耀眼的白银小构件整齐地镶嵌而成。这又仿佛是一首宇宙交响乐的固化。渐渐地,黑色的正方形消融在星空中,群星填补了它的位置,银色的方阵庄严地悬浮在群星之间。
  银河系碳基联邦的星际舰队,完成了本次巡航的第一次时空跃迁。
  在舰队的旗舰上,碳基联邦的最高执政官看关眼前银色的金属大地,大地上面满了错综复杂的纹路,像一块无限广阔的银色蚀刻电路板。不时有几个闪光的水滴状的小艇了现在大地上,沿着纹路以令人目眩的速度行驶向秒钟,然后无声地消失在一口突然出现的深井中。时空跃迁带过来的太空尘埃被电离,成为一团团发着暗红色光的云,笼罩在银色大地的上空。
  最高执政官以冷静著称,他周围那似乎永远波澜不惊的淡蓝色智能场就是他人格的象征,但现在,像周围的人一样,他的智能场也微微泛出黄光。
  “终于结束了。”最高执政官的智能场振动了一下,把这个信息传送给站在他两旁的参议员和舰队统帅。
  “是啊,结束了。战争的历程太长太长,以至我们都忘记了他的开始。”参议员回答。
  这时,舰队开始了亚光速巡航,它们的亚光速发支机同时启动,旗舰周围突然出现了几千个蓝色的太阳,银色的金属大地像一面无限广阔的镜子,把蓝太阳的数量又复制了一倍。
  远古的记忆似乎被点燃了,其实,谁能忘记战争的开始呢?这记忆虽然遗传了几百代,但在碳基联邦的万亿公民的脑海中,它仍那么鲜活,那么铭心刻骨。
  两万年前的那一时刻,硅基帝国从银河系外围对碳基联邦发动全面进攻。在长达一万光年的战线上,硅基帝国的五百多万艘星际战舰同时开始恒星蛙跳。每艘战舰首先借助一颗恒星的能量打开一个时空蛀洞,然后从这个蛀洞时空跃迁至另一个恒星,再用这颗恒星的能量打开第二个蛀洞继续跃迁……由于打开蛀洞消耗了恒星大量的能量,使得恒星的光谱暂时向红端移动,当飞船从这颗恒星完成跃迁后,它的光谱渐渐恢复原状。当几百万艘战舰同时进行恒星蛙跳时,所产生的这种效应是十分恐怖的:银河系的边缘出现一条长达一万光年有红色光带,这条光带向银河系的中心移过来。这个景象在光速视界是看不到的,但在超空间监视器上能显示出来。那条由变色恒星组成的光带,如同一道一万光年长的血潮,向碳基联邦的疆域涌来。
  碳基联邦最先接触硅基帝国攻击前锋的是绿洋星,这颗美丽的行星围绕着一对双星恒星运行,她的表面全部被海洋覆盖。那生机盎然的海洋中漂浮着由柔软的长藤植物构成的森林,温和美丽、身体晶莹透明的绿洋星人在这海中的绿色森林间轻盈地游动,创造了绿洋星伊甸园般的文明。突然,几万道刺目的光束从天而降,硅基帝国舰队开始用激光蒸发绿洋星的海洋。在很短的时间内,绿洋星变成了一口沸腾的大锅,这颗行星上包括五十亿绿洋星人在内的所有生物在沸水中极度痛苦的死去,它们被煮熟的有机物质使整个海洋变成的绿色的浓汤。最后海洋全部蒸发了,昔日美丽的绿洋星变成了一个由厚厚蒸汽包裹着的地狱般的灰色行星。
  这是一场几乎波及整个银河的星际大战,是银河系中碳基和硅基文明之间惨烈的文明竞争,但双方谁都没有料到战争会持继两万银河年!
  现在,作了历史学家,谁也记不清有百万以上战舰参中的大战役有多少次了。规模最大的一次超级战级战役是第二旋臂战疫,战疫在银河系第二旋臂中部进地,双方投入了上千万艘星际战舰。据历史记载在那广漠的战场上,被引爆的超新星就达两千多颗,那些超新星像第二旋臂中部黑暗太空中怒放的焰火,使那里变成超强辐射的海洋,只有一群群幽灵似的黑洞漂行于其间。战役的最后,双方的星际舰队几乎同归于尽。一万五千的过去了,第二旋臂战疫现在听起来就像上古时代飘渺的神话,只有那仍然存在的古战场证明它确实发生过。但很少有飞船真正进入过古战场,那里是银河系中最恐怖的区域,这并不仅仅是因为辐射和黑洞。当时,双方数量多得难以想像的战舰群为了进行战术机动,进行了大量的超短距离时空跃迁,据说当时的一些星际歼击机,在空间格斗时,时空跃迁的距离竟短到令人难以置信的几千米!这样就把古战场的时空结构搞得千疮百孔,像一块内部被老鼠钻了无数长洞的在乳酪。飞船一旦误入这个区域,可能在一瞬间被畸变的空间扭成一根细长的金属绳,或压成面积有几亿平方公里但厚度只有几个原子的薄膜,立刻被辐射狂风撕得粉碎。但更为常见的是飞船变为建造它们时的一块块钢板,或者立刻老得只剩下一个破旧的外壳,内部的一切都变成古老灰尘;人在这里也可能瞬间顺到胚胎状态或变成一堆白骨……
  但最后的决战不是神话,它就发生在一年前。在银河系第一和第二旋臂之间的荒凉太空中,硅基帝国集结了最后的力量,这支有一百五十万艘星际战舰组成的舰队在自己周围构筑了半径一千光年的反物质云层屏障。反物质云虽然十分稀薄,但对战具有极大的杀伤力,碳基联邦的战舰立刻变成一个个刺目的火球,但它们仍然奋冲向目标。每艘战舰都拖着长长的火尾在后面留着一条发着荧光的航迹这由三十多万个火流星组成的阵列形成了碳硅战争中最为壮观最为惨烈的画面。在反物质云中,这些火流星渐渐缩小,最后在距硅基帝国战舰阵列很近的地方消失了,但它们用自己的牺牲为后续的攻击舰队在反物质云中打开了一条通道。在这场战役中,硅基帝国的舰队最后被赶到银河最荒凉的区域:第一旋臂的顶端。
  现在,这支碳基联邦舰队将完成碳硅战争中最后一项使命:他们将在第一旋臂中部建立一条五百光年宽的隔离带,隔离带中的大部分恒星将被摧毁,以制止硅星帝国的硅星蛙跳。硅星蛙跳是银河系中大吨位战舰进行远距离快速攻击的惟一途径,而一次蛙跳的最大距离是二百光年。隔离带一旦产生,硅基帝国的重型战舰要想进入银河系的中心区域,就只能以亚光速跨越这五百光年的距离,这样,硅基帝国实际上被禁锢在第一旋臂顶端,再也无法对银河系中心的碳基文明构成任何威胁。
  “我带来了联邦议会的意愿。”参变色镜员用振动的智能场对最高执行官司说,“他们仍然强烈建议;在摧毁隔离带中的恒星前,对它们进行生命级别的保护甄别。”
  “我理解议会。”最高执行官司说,“在这场漫长的战争中,各种生命流出的血足够形成一千颗行星的海洋了,战后,银河系中最迫切需要重建的是对生命的尊重。这种尊重不仅是对碳基生命的,也是对硅基生命的,正是基于这种尊重,碳基联邦才没有彻底消灭硅基文明。但硅基帝国并没有这种对生命的感情,如果说碳硅战争之前,战争和征服对于它人还仅仅是一种本能和乐趣和话,那么现在这种东西已根植于它们的每个基因和每行代码之中,成为它们生存的终极目的。由于硅基生物对信息的存贮和处理能力大高于我们,可以预测硅基帝国在第一旋臂顶端的恢复和发展将是神速的,所以我们必须在碳基帝国和硅基帝国之间建成足够宽的隔离带。在这种情况下,对隔离带中数以亿计的恒星进行生命级别的保护甄别的不现实的,第一旋臂虽属银河系中最荒凉的区域,但其带有生命行星的恒星数量仍可能达到蛙跳密度,这种密度足以使中型战舰进行蛙跳,而即使只有一艘硅基帝国的中型战舰进入碳基联邦的疆域,可能造成的破坏也是巨大的,所以在隔离带中只能进行文明级别的甄别。我们不得不牺牲隔离带中某些恒星周围的低级生命,是为了拯救银河系中更多的生命。这一点我已经向议会说明。
  参议员说:”议会也理解您和联邦孩子御委员会,所以我带来的只是建议而不是立法。但隔离带中周围已形成3C级文明的恒星必须被保护。”
  “这一点无须置疑,”最记执行官司的智能场闪现出坚定的红色,”对隔离带中带有行星的恒星的文明检测将是十分严格的!”
  舰队统帅的智能场第一次发出信息:”其实我觉得你们多虑了,第一旋臂是银河系中最荒凉的荒漠,那里不会有3C级以上文明的。”
  “但愿如此。”最高执政官和参议员同时发妯了这个信息,他们智能场的共振使一道弧形的等离子体小组纹向银以金属大地的上空扩散开去。
  舰队开始了第二次时空跃迁,以近乎无限的速度奔向银河系的第一旋臂。

 


  夜深了,烛光中,全班的娃们围在老师的病床前。
  “老师歇着吧,明儿个讲也行。”一个男娃说。
  他艰难地苦笑了一下:”明儿个有明儿上的课。”
  他想,如果真能拖到明天当然好,那就能再讲一堂课。但直觉告诉他怕是不行了。
  他做了个手势,一个娃把一块小黑板放在他胸前的被单上,这最后一个月,他就是这样把课讲下来的。他用软弱地力的手接过娃递过的半截粉笔,吃力地把粉笔头放到黑板上,这时又一阵剧痛袭来,手颤抖了几下,粉笔哒哒的在黑板上敲出了几个白点。从省城回来后,他再也没去过医院。两个月后,他的肝部疼了起来,他知道癌细胞已经移到那了,这种疼痛越来越厉害,最后变成了压倒一切的痛苦。他一只手在枕头底下摸索着,找出了一些止痛片,是最常见的用塑料长打包装的那种。对于癌症晚期的巨痛,这药已经没有任何作用,可能是由于精精神暗示,他吃了后总觉得好一些。杜冷丁倒是不算贵,但医院不让带出来用,就是带回来也没人给他注射。他像往常一样从塑料条上取下两片药来,但想了想,便把所剩下的12片全剥出来,一把吞下去,他知道以后再也用不着了。他又挣扎着想向黑板上写字,但头突然偏向一边,一个娃赶紧把盆接到他嘴边,他吐出一口黑红的血,然后虚弱地靠在枕头上喘息着。
  娃们中传出了低低的抽泣声。
  他放弃了在黑板上写字的努力,无力地挥了一下手,让一个娃把黑板拿走。他开始说话,声音如游丝一般。
  “今天的课同前两天一样,也是初中的课。这本来不是教学大纲上要求的,我是想到你们中的大部分人,一辈子永远也听不到初中的课了,所以我最后讲一讲,也让你们知道稍深一些的学问是什么样子。昨天讲了鲁迅的《狂人日记》,你们肯定不大懂,不管懂不懂都要多看几遍,最好能背下来,等长大了,总会懂的。鲁迅是个很了不起的人,他的书每一个中国人都应该读读的,你们将来也一定找来读读。”
  他累了,停下来喘息着歇歇,看着跳动的烛光,鲁迅写下的几段文字在他的脑海中浮现出来。那不是《狂人日记》中的,课本上没有,他是从自己那套数不全已经番料的鲁迅全集上读到的,许多年前读第一遍时,那些文字就深深地刻在他脑子里。
  “假如一间铁屋子,是绝无窗子而万难破毁的,里面有许多熟睡的人们,不久都要闷死了,然则是从昏睡入死灭,并不感到就死的悲哀。现在你俩大嚷起来,惊起了较为清醒的几个人,使这不幸的少数者来受无可挽救的苦楚,你倒以为对得起他们吗?”
  “然而几个人既然起来,你不能说决没有毁坏这铁屋的希望。”
  他用尽最后的力气,接着讲下去。
  “今天我们讲初中的物理。物理你们以前可能没有听说过,它讲的是物质世界的道理,是一门很深很深的学问。”
  “这课讲牛顿三定律。牛顿是从前的一个英国大科学家,他说了三句话,这三句话很神的,它把人间天上所有东西的规律都包括都包括进去了,上到太阳月亮,下到流水括风,都跑不出这三句话划定的圈圈。用这三句话,可以算出什么时候日食,就是村里老人说的天狗吃太阳,一分一秒都不差的;人飞是月球,也要靠这三句话,这就是牛顿三定律。”
  “下面讲第一定律:当一个物体没有受到外力作用时,它将保持静止或匀速直线运动不变。”
  娃们在烛光中默默地看着他,没有反应。
  “就是说,你猛推一下谷场上那个石碾子,它就一直滚下去,滚到天边也不停下来。宝柱你笑什么?是啊,它当然不会那样,这是因为有磨擦力,磨擦力让它停下来,这世界上没有磨擦力环境可是没有的……”
  是啊,他人生的磨擦力就太大了。在村里他是外姓人,本来就没什么份量,加上他是个倔脾气,这些年把全村人都得罪完了。他挨家挨户拉人家的娃入学,跑到县里,把跟着爹做买卖的娃拉回来上学,拍着胸脯保证垫学费……这一切并没有赢得多少感激,关键在于,他对过日子的看法同周围人太不一样,成天想的说的,都是些不着边际的事,这是最让人讨厌的。在他查出病来之前,他曾跑到县里,居然从教育局跑回一笔维修学校的封款子,村子里只拿出了一小部分,想过节请个戏班子唱两天戏。结果让他搅了,愣从县里拉来个副县长,让村里把钱拿出来,可当时戏台子都搭好了。学校倒是修了,但他扫了全村人的兴,以后的日子更难过。先是村里的电工----村长的侄子,把学校的电掐了,接着做饭取暖和的秸杆村里也不给了,害得他扔下自己的地下不了种,一人上山打柴,更别提后来诉校舍的房橼子那事了……这些磨擦力无所不在,让他心力交瘁,让他无法做匀速直线运动,他不得不停下来了。
  也许,他就要去的那个世界是没有磨擦力的,那里的一切都是光滑可爱的,但那有什么意义?在那边,他心仍留在这个充满灰尘和磨擦力的世界上,留在这所他倾注了全部生命的乡村小学里。他不在了以后,剩下了两个教师也会离去,这所他用力推了一辈子的小学校就会像谷场上那个石碾子一样停下来。他陷入了深深的悲哀,但不论在这个世界或是那个世界,他都无力回天。
  “牛顿第二定律比较难懂,我们最后讲,下面先讲牛顿第三定律:当一个物体对第二个物体施加一个力,这第二个物体也会对第一个物体施加一个力,这两个力大小相等,方向相反。”
  娃们又陷入了长时间的沉默。
  “听懂了没?谁说说?”
  班上学习最好的赵拉宝说::“我知道是啥意思,可总觉得说不通:晌午我和李权贵打架,他把我的脸打得那么疼,肿起来了,所以作用力肯定不相等的,我受的肯定比他大嘛!”
  喘息了好一会,他才解释说:“你痛是因为你的腮帮子比李权贵的拳头软,它们相互的作用力还是相等的……”
  他想用手比划一下,但手已抬不起来了。他感到四肢像铁块一样沉,这沉重感很快扩散到全身,他感到以自己的躯体像要压塌床板,陷入地下似的。
  时间不多了。

 


  “目标编号:1033715,绝对目视星等:3。5,演化阶段:主星序偏上,发现两颗行星,平均轨道半径分别为1。3和4。7个距离单位,在一号行星上发现生命,这是69012舰报告。”
  碳基联邦星际舰队的十万艘战舰目前已散布在一条长一万光年的带状区域中,这就是正在建立的隔离带。工程刚刚开始,只是试验性地摧毁了五千颗恒星,其中带有行星的只有137颗,而行星上有生命的这是第一颗。
  “第一旋臂真是个荒凉的地方啊。”最高执行官司感叹道。他的智能场振动了一下,用全息图陷去了脚下的旗舰和上方的星空,使他、舰队统帅和参议员悬浮于无际的黑色虚空中。接着,他调出了探测器发出的图像:虚空出现了一个发着蓝光的火球,最高执行官司的智能场产生了一个白色的方框,那方框调整大小,圈住了这颗恒星并把它的图像隐去了,他们于是又陷入了无边的黑暗之中。但这黑暗中有一个小小的黄色光点,图像的焦距开始大幅度调整,行星的图像以令人目炫的速度推向前来,很快占满了半个虚空,三个人都沉浸在它反射的橙黄色光芒中。
  这是一颗被浓密大气包裹着的行星,在它那橙黄色的气体海洋上,汹涌的大气运动描绘出了羰复杂的不断变幻的线条,行星图像继续向前移来,直到占据了整个宇宙,三个人被橙黄色的气体海洋吞没了。控测器带关他们在这浓雾中穿行,很快雾乞稀薄了一些,他们看到这颗行星上的生命。
  那是一群在浓密大气上层飘浮的气球状生物,表面有着美丽的花纹,那花纹不停在变幻着色彩和形状,时而呈条纹状,时而呈现斑点状,不知这是不是一种可视语言。每个气球都有一条长尾,那长尾的尾端不时炫目地闪烁一下,光沿着长尾传到气球上,化为一片弥漫的荧光。
  “开始四维扫描!”红69012舰上的一名上尉值勤军官说。
  一束极细的光波开始从上至下飞快地扫描那群气球。这束波只有几个原子粗细,但它的波管内的空间维度比外部宇宙多一维。扫描数揣传回舰上,在主计算机的内存中,那群气球被切成了几亿亿个薄片,每个薄片的厚度只有一个原子的尺度,在这个薄片上,每个夸史的状态都被精确地记录下来。
  “开始数据镜像组合!”
  主计算机的内存中,那几亿亿个薄片按原有须序叠加起来,很快,组合成一群虚拟气球。在计算机内部广漠的数字宇宙中,这个行星上的那群生物体有了精确的复制品。
  “开始3C文明测试!”
  在数字宇宙中,计算机敏锐地定位了气球的思维感官,它是悬在气球内部错综复杂的神经丛中间的一个椭圆体。计算机在瞬间分析了这个大脑的结构,并越过所有低级感官,直接向它建立了高速信息接口。
  文明测试是从一个庞大的数据库中任意地选取试题,测试对象如果能答对其中三道,则测试通过。如果头三道题没有答对,测试者有两种选择:可以认为测试没通过;或者继续测试,题数不限,直到被测试者答对的题数达到三道,这时可认为其通过测试。
  “3C级文明测试试题1号:请叙述你们已探知的组成物质的最小单元。”
  “滴滴,嘟嘟嘟,滴滴滴滴。”气球回答。
  “1号试题测试未通过。3C级文明测试试题2号:你们观察到物体中热能的流向有什么特点?这种传流是否可逆?”
  “嘟嘟嘟,滴滴,滴滴嘟嘟。”气球回答。
  “2号试题测试未通过。3C级文明测试试题3号:圆的周长和它的直径比是多少?”
  “滴滴滴滴嘟嘟嘟嘟嘟。”气球回答。
  “3号试题测试未通过。3C级文明测试试题4号:……”
  “到此为止吧,”当测试题数达到10道时,最高执行官司说:“我们时间不多。”他转身对旁边的舰队示意了一下。
  “发射奇点炸弹!”舰队统帅命令。
  奇点炸弹实际上是没有大小的,它是一个严格意义上的几何点,一个原子同它相比都是无穷大,虽然最大的奇点炸弹质量有上百亿吨,最小的也有几千万吨。但当一颗奇点炸弹沿着长长的导轨从红69012的武器舱中滑出时,却可以看到一个直径达几百米的发着幽幽荧光的球体,这荧光是周围太空尘埃被吸入这个微型黑洞时产生的辐射。同那些恒星引力坍缩形成的黑洞不同,这些小黑洞在宇宙创世之初就形成了,它们是大爆炸前的奇点宇宙的微缩模型。碳基联邦和硅基帝国都有庞大的船队,游弋在银河系银道面外的黑暗芒漠搜集这些微型黑洞,一些海洋行星上的种群把它们戏称为“远洋捕鱼船队”而这些船队带回来的东西,是银河系中最具威慑力的武器这一,是迄今为止惟一能够摧毁恒星的武器。
  奇点炸弹脱离导轨后,沿一条由母舰发出的力场束加速,直奔目标恒星。过了不长的一段时间,这颗灰尘似的黑洞高速射入了恒星表面的火的海洋。想像在太平洋的中部突然出现一个半径一百公里的深井,就可以大概把据这时的情形。巨量的恒星物质被吸入黑洞,那汹涌的物质洪流从所有方向会聚到一点并消失在那里,特质吸入时所产生的辐射在恒星表面产生一团刺目的光球,仿佛恒星戴上一个光彩夺目的钻石戒指。随着黑洞向恒星内部沉下去,光团暗淡下来,可以秆到它处于一个直径达几百万公里的大旋涡正中,那巨大的旋涡散射着光团的强光,缓缓转动着,呈现现出飞速变幻的色彩,使恒星从这个方向看去仿佛是一张狰狞的巨脸。很快,光团消失了,旋涡渐渐消失,恒星表面似乎又恢复了它原来的色彩和光度。但这只是毁灭前归后的平静,随着黑洞向恒星中心下宙,这个贪婪的  者更疯狂地吞食周围密度急剧增高的物质,它在一秒钟内吸入的恒星物质总量可能有上百个中等行星。黑洞巨量吸入时产生的超强辐射向恒星表面蔓延,由于恒星物质的阻滞,只有一小部分到达了表面,但其余的辐射把它的的能量留在了恒星内部,这能量快速破坏着恒星的每一个细胞,从整体上把它飞快的拉离平衡态。从外部看,恒星的色彩在缓缓主化,由浅红色变为明黄色,从明黄色变为鲜艳的绿色,从绿色变为如洗的碧蓝,从碧蓝变为恐怖的紫色。这时恒星中心的黑洞产生的辐射已远远大于恒星本身辐射的能量,随着更多的能量以非可见光形式溢出恒星,这紫色在加深加重,这颗恒星看上去像太空中一个在忍受着超级痛苦的灵魂。这痛苦在急剧增大,紫色已深到了极限,这颗恒星以不到一个小时的时间走完了它未来几十亿年的旅程。
  一团似乎吞没整个宇宙的强光闪起,然后慢发电量消失,在原来恒星所在的位置上,可以看到一个急剧膨胀的薄层球,像一个被吹大的气球,这是被炸飞的恒星表面。随着薄层球体积的增大,它变得透明了,可以看到它内部的第二个膨胀的薄层球,然后又可以看到更深的第三个薄层球……这个爆炸中的恒星,就像宇宙中突然显现的一个套一个的一组玲珑剔透的镂花玻璃球,其中最深处的一个薄层球的体积也是原来恒星原来的体积的几十万倍。当爆炸的恒星的第一层膨胀外壳穿过那个橙黄色行星时,它立刻被汽化了。其实在这整个爆炸的壮丽场面中根本就看不到它,同那膨胀的恒星外壳相比,它只是一粒微不足道的灰尘,其大小甚至不能成为那几层镂花玻璃上的一个小点。
  “你们感到消沉?”舰队统帅问,他看到是高执行官和的参议员的智能场暗下来了。
  “又一个生命世界毁灭了,像烈日下的露珠。”
  “那你就想想伟大的第二旋臂战役,当两千多颗超新星被引爆时,有十二万个这样的世界同碳硅双方的舰队一起化为蒸汽。阁下,时至今日,我们应该为超越这种无谓的多愁善感了。”
  参议员没有理会舰队统帅的话,也对电高执行官司说:“这种对行星有面取随机点的检测方式是不可靠的,可能漏行星表面的文明特征,我们应该进行面积检测。”
  最高执行官说:“这一点我了同议会讨论过,在隔离带中我们要摧毁的行星有上亿颗,这其中估计有一千万个行星系,行星数量可能达五千万颗,我们时间紧迫,对每颗行星都进行面积检测不现实的。我们只能尽量加宽检测波束,以增大随机点覆盖的面积,除此之外,只能祈祷隔离带中那些可能存在的文明在其星球表面的分布尽量均匀了。”
 
  “下面我们讲牛顿第二定律……”
  他心急如焚,极力想在有限的时间里给娃们多讲一些。
  “一个物体的加速度,与它所受的力成正比,与它的质量成反比。首先,加速度,这是速度随时间的变化率。它与速度是不同的,速度大加速度不一定大,加速度大速度也不一定大。比如:一个物体现在的速度是110米每秒,2秒后它的速度是120米每秒,那么它的加速度就是120减110除2,5米每秒,呵,不对,5米每秒的平方;另一个物体现在的速度是10米每秒,2秒后的速度是30米每秒,那么它的加速度就是30减10除2,10米每秒平方;看,后面这个物体虽然速度小,但加速度大!呵,刚才说到平方,平方就是一个数自个儿乘自个儿……”
  他惊奇自己的头脑如此清晰,思维如此敏捷。他知道,自己生命的蜡烛已烯到根上,棉芯倒下了,把最后一小块蜡全部引燃了,一团比以前的烛苗亮十倍的火焰熊熊燃烧起来。剧痛消失了,身体也不再沉重,其实他已感觉不到身体的存在,他的全部生命似乎只剩下那个在疯狂运行的大脑,那个悬在空中的大脑竭尽全力,尽量多尽量快的把自己存贮的信息输出给周围的娃们,但嗓子是个该死的瓶颈,他知道来不及了。他产生了一个幻象:一把水晶样的斧子把自己的大脑无声地劈开,他一生中积累的那些知识,虽不很多但他很看重的,像一把发光的小珠子毫无保留地落在地上,发出一阵悦耳的呆当声,娃们像见到过年的糖果一样抢那些小珠子,抢得摞成一堆……这幻象让他有一种幸福的感觉。
  “你们听懂了没有?”他焦急地问。他的眼睛已看不到周围的娃们了,但还能听到他们的声音。
  “我们懂了!老师快歇着吧!”
  他感觉到那团最后的火焰在弱下去,“我知道你们不懂,但你们把它背下来,以后会慢慢懂的。一个物体的加速度,与它所受的力成正比,与它的质量成反比。”
  “老师,我们真懂了,求求你快歇着吧!”
  他用尽最后的力气喊道:“背呀!”
  娃们抽泣着背了起来:“一个物体的加速度,与它所受的力成正比,与它的质量成反比。一个物体的加速度,与它所受的力成正比,与它的质量成反比……”
  这几百年前就在欧洲化为尘土的卓越头脑产生的思想,以浓重西北方言的童音在二十世纪中国最偏僻的山村中回荡,就在这声音中,那烛苗灭了。
  娃们围着老师忆没有生命的躯体大哭起来。
 
  “目标编号:500921473,绝对目视星等:4。71,演化阶段:主星序正中,带有九颗行星。这是蓝84210号舰报告。“
  “一个精致完美的行星系。”舰队统帅赞叹。
  最高执政官司很有同感:“是的,它的固态小体积行星和气液态大体积行星的配置很有韵律感,小行星带的位置恰到好处,像一条美妙的装饰链。还有最外侧那颗小小的甲烷冰行星,似乎是这首音乐最后一个余音未尽的音符,暗示着某种新周期的开始。
  “这是蓝84210号舰,将对最内侧1号行星进行生命检测,检测波束发射。该行星没有大气,自转缓慢,温差悬殊。1号随机点检测,白色结果;2号随机点检测,白色结果……10号随机点检测,白色结果。蓝84210号报告,该行星没有生命。”
  舰队统帅不以为然地说:“这颗行星的表面温度可以当冶炼炉了,没必要浪费时间。”
  “开始对2号行星进行生命检测,波束发射。该行星有稠密的大气,表面温度较高且均匀,大部分为酸性云层覆盖。1号随机点检测,白色结果;2号随机点检测,白色结果……10号随机点检测,白色结果。蓝84210号报告,该行星没有生命。”
  通过四维通讯,最高执政官对一千光年这外蓝84210号舰上的值勤军官说:“直觉告诉我,3号行星有生命可能性很大,在它上面检测30个随机点。”
  “阁下,我们时间很紧了。”舰队统帅说。
  “照我说的做。”最高执政官坚定地说。
  “是,阁下。开始3号行星检测,波束发射。该行星有中等密度的大气,表面大部分为海洋覆盖……”
 
  来自太空的生命检测波束落到了亚洲大陆靠南一些的一点上,波束在地面上形成了一个约五千米的圆形。如果是在白天,用肉眼有可能觉察到波束的存在,因为当波束到达时,在它的覆盖范围内,一切无生命的物体都将变成透明状态。现在它格的中国西北的这片山区,那些黄土坡在观察者的眼中如同水晶的山沪,阳光在这些山肪中折射,将是一幅十分奇异壮观的景象,观察者还会看到脚下的大地也变成深不可测的深渊;而被波束判断为生命的物体则保持原状态不变,人、树木和草在这水晶世界中显得格外消晰醒目。但这效应只持续半秒钟,这期间检测光束自动完成初始化,之后一切恢复原状。观察者肯定会认为自己产生了一瞬间的幻觉。而现在,这里正是深夜,自然难以觉察到什么了。
  这所山村小学,正好位于检测波束圆形覆盖区的圆心。
 
  “1号随机点检测,结果……绿色结果,绿色结果!蓝84210号舰报告,目标编号:500921473,第3号行星发现生命!”
  检测波束对覆盖范围内的众多种类生命体进行分类,在以生命结构的复杂度和初步估计的智能等级进行排序的数据库中,在一个方形掩蔽物下的那一簇生命体排在首位。于是波束迅速收缩,会聚到那座掩蔽物上。
  最高执政官司的智能场接收到蓝84210号舰上发回的图像,并把它放大到整个太空背景上,那所山村小学的影像在瞬间占据了整个宇宙。图像处理系统已经隐去了掩蔽物,但那簇生命体的图像仍不清晰,这些生命全的外形太不醒目了,几乎同周围行星表面的以硅元素为主的黄色土壤融为一体。计算机只好把图像中所有无生命部分,包括这些生命体中间的那具体形较大的已没有生命的躯体,全部隐去,这样那一簇生命体就仿佛悬浮在虚空之中。即使如此,他们看上去仍是那么平淡和缺乏色彩,像一簇黄色的植物,一看就知是那种在他们身上不会发生任何奇迹的生物。
  一束纤细的四维波束从蓝84210号舰发射,这艘有一个月球大小的星际战舰正停泊在木星轨道之外,使太阳系暂时多了一颗行星。那束四维波束在三维太空中以接近无限的速度接近地球,穿过那所乡村小学校舍的屋顶,以基本粒子的精度对这十八个孩子进行扫描。数据的洪流以人类难以想像的速率传回太空,很快,在蓝84210号舰主计算机那比宇宙更广阔的内存中,孩子们的数字复制体形成了。
  十八个孩子悬浮在一个无际的空间里,那空间呈现一种无法形容的色彩,实际上那不是色彩,虚无是没有色彩的,虚无是透明中的透明。孩子们都不由想拉住旁边的伙伴,他们看上去很正常但手从他们身体里毫无阻力的穿过去了。孩子们感到了难以形容的恐惧,计算机觉察到了这一点,它认为这些生命体需要一些熟悉的东西,于是在自己的内存宇宙的这一部分模拟这个行星天空的颜色。孩子们立刻看到了蓝天,没有太阳没有云更没有浮尘,只有蓝色,那么纯净,那么深邃。孩子们的脚下没有大地,也是与头顶的蓝天,他们似乎置身于一个无限的蓝色宇宙中,而他们是这宇宙惟一的实体。计算机感觉到,这些数字生命体仍然处于惊恐中,它用了亿分之一秒想了想,终于明白了:银河系中大多数生命体并不惧怕悬浮于是虚空之中,但这些生命体不同,他们是大地上的生物。于是它给了孩子们一个大地,并给了他们重力感。孩子们惊奇地看着脚下突然出现的大地,它是纯白色的,上面有黑线划出的整齐方格,他们仿佛站在一个无限广阔的语文作业本上。他们中有人蹲下来摸摸地面,这是他们见过的最光滑的东西,他们迈开双脚走,但原地不动,这地面是绝对光滑的,磨擦力为零,他们很惊奇自己为什么不会滑倒。这时有个孩子脱下自己的一只鞋子,沿着地面扔出去,那鞋子以匀速直线动行向前滑去,孩子们呆呆地看着它们以恒定的速度渐渐远去。
  他们看到了牛顿第一定律。
  有一个声音,空灵而悠扬,在这数字宇宙中回荡。
  “开始3C级文明测试,3C级文明测试试题1号:请叙述你所在星球生物进化的基本原理,是自然淘汰型还是基因突变型?”
  孩子们茫然地沉默着。
  ……
  “3C级文明测试试题10号:请说明构成你们星球上海洋的液体的分子构成。”
  孩子们仍然茫然地沉默着。
  那只鞋在遥远的地平线处变成一个小黑点消失了。
  “到此为止吧!”在一千光年之外,舰队统帅对最高执行官说,“不能再耽误时间了,否则我们肯定不能按时完成第一阶段的任务。”
  最高执行官的智能场发出了微弱的表示同意的振动。
  “发射奇点炸弹!”
  载有命令信息的波束越过四维空间,瞬间到达了停泊在太阳系中的蓝84210号舰。那个发着幽幽荧光的雾球滑出了战舰前方长长的导轨,沿着看不见的力场束急剧加速,向太阳扑去。
  最高执行官、参议员和舰队统帅把注意力转向了隔离带的其它区域,那里,又发现了几个有生命的行星系,但其中最高级的生命是一种生活在泥浆中的无脑蠕虫。接连爆炸的恒星像宇宙中怒放的焰火,使他们想起了史诗般的第二旋臂战役。
  不知过了多长时间,最高执行官智能场的一小部分下意识地游移到太阳系,他听到了蓝84210号舰长的声音。
  “准备脱离爆炸威力圈,时空跃迁准备,三十秒倒数!”
  “等一下,奇点炸弹到达目标还需多长时间?”最高执行官说,舰队统帅和参议员的注意力也被吸引过来。
  “它正越内侧1号行星的轨道,大约还有十分钟。”
  “用五分钟,再进行一些测试吧。”
  “是,阁下。”
  接着听到了蓝84210号舰值勤军官的声音:“3C级文明测试试题11号:一个三维平面上的直角三角形,它的三条边的关系是什么?”
  沉默。
  “3C级文明测试试题12号:你们的星球是你们行星系的第几颗行星?”
  沉默。
  “这没有意义,阁下。”舰队统帅说。
  “3C级文明测试试题13号:当一个物体没有受到外力作用时,它的运行状态如何?”
  数字宇宙广漠的蓝色空间中突然响起了孩子们清脆的声音:“当一个物体没有受到外力作用时,它将保持静止或匀速直线运动不变。”
  “3C级文明测试试题13号通过!3C级文明测试试题14号……”
  “等等!”参议员打断了值勤军官,“下一道试题也出关于甚低速力学基本近似定律的。”他又问最高执行官,“这不违反测试准则吧。”
  “当然不,只要是测试数据为中的试题。”舰队统帅代为回答,这些令他大感意外的生命体把他的注意力全部吸引过来了。“3C级文明测试试题14号:请叙述相互作用的两个物体间力的关系。”
  孩子们齐声回答说:“当一个物体对第二个物体施加一个力,这第二个物体也会对第一个物体施加一个力,这两个力大小相等,方向相反。”
  “3C级文明测试试题14号通过!3C级文明测试试题15号:对于一个物体,请说明它的质量、所受外力和加速度之间的关系。”
  孩子们又齐声说:“一个物体的加速度,与它所受的力成正比,与它的质量成反比!”
  “3C级文明测试试题15号通过,文明测试通过!确定目标恒星500921473的3号行星上存在3C级文明。”
  “奇点炸弹转向!脱离目标!”最高执行官的智能场急剧闪动着,用最大的能量把命令通过超空间传送到蓝84210号舰上。
  在太阳系,推送奇点炸弹的力场束弯曲了,这根长几亿公里的力场束此时像一根弓起的长杆,努力把奇点炸弹挑离射向太阳的轨道。蓝84210号舰上的力场发动机以最大功率工作,巨大的散热片由暗红变为耀眼的白炽色。力场束向外的推力分量开始显示出效果,奇点炸弹的轨道开始弯曲,但它已越过水星轨道,距太阳太近了,谁也不知道是否能成框图。通过超空间直播,全银河都在盯着那个模糊的雾团的轨迹,并看到它的亮度急剧增大。这是一个可怕的迹象,说明炸弹已能感觉到太阳外围空间粒密度的增大。舰长的手已放到那个红色的时空跃迁启动按钮上,以在奇点炸弹击中前的一刹那脱离这个空间。但奇点炸弹最终像一颗子弹一样擦过太阳的边缘,当它以仅几万米的高度掠过太阳表面上空时,由于黑洞吸入太阳大气中大量的物质,亮度增到最大,使得太阳边缘出现了一个刺眼的蓝白色光球,使它在这一刻看上去像一个紧密的双星系统,这奇观对人类将一直是个难解的迷。蓝白色光球飞速掠过时,下面太阳浩瀚的火海暗然失色。像一艘快艇掠过平静的水面,黑洞的引力在太阳表面划出了一道V型的划痕,这划痕扩展到太阳的整个半球才消失。奇点炸弹撞断了一条日珥,这条从太阳表面升起的百万公里长的美丽青纱在高速冲击碎成一群欢快舞蹈着的小小的等离子体旋涡……奇点炸弹掠过太阳后,亮度很快暗下来,最后消失在茫茫太空的永恒之夜中。
  “我们险些毁灭了一个碳基文明。”参议员长出一口气说。
  “真是不可思议,在这么荒凉的地方竟会存在3C级文明!”舰队统帅感叹说。
  “是啊,无论是碳基联邦还是硅基帝国,其文明扩展和培植计划都不包括这一区域,如果这是一个自己进化的文明,那可是一件很不寻常的事。”最高执政官说。
  “蓝84210号舰,你们继续留在那个行星系,对3号行星进行全表面文明检测。你舰其余的任务将由其他舰只接替。”舰队司令命令道。
  同他们在木星轨道之外的数字复制品不一样,山村小学中的那些娃们丝毫没有觉察到什么,在那间校舍晨的烛光下,他们只是围着老师的遗体哭啊哭。不知哭了多长时间,娃们最后安静下来。
  “咱们去村里告诉大人吧。”郭翠花抽泣着说。
  “那又咋的?”刘宝柱低头说,“老师活着时村里人都腻歪他,这会儿肯定连棺材钱都没有给他出呢!”
  最后,娃们决定自己掩埋自己的老师。他们拿了锄头铁锹,在学校旁边的山地上开始挖墓坑,灿烂的群星在整个宇宙中静静地看着他们。
 
  “天啊!这颗行星上的文明不是3C级,是5B级!!”看着蓝84210号舰从一千光年之外发回的检测报告,参议员惊呼起来。
  人类城市的摩天大楼群的影像在旗舰上方的太空中显现。
  “他们已经开始使用核能,并用化学推进方式进入太空,甚至已登上他们所在行星的卫星。”
  “他们的基本特征是什么?”舰队统帅问。
  “你想知道哪些方面?”蓝84210号上的值勤军官问。
  “比如,这个行星上生命体记忆遗传的等级是什么?”
  “他们没有记忆遗传,所以记忆都是后天取得的。”
  “那么,他们的个体相互之间的信息交流方式是什么?”
  “极其原始,也十分罕见。他们身体内有一种很薄的器官,这种器官在这个行星以氮氧为主的大气中振动时可产生声波,同时把要传输的信息调制到声波之中,接收方也用一种薄膜器官从声波中接收信息。”
  “这种方式信息传输的速率是多大?”
  “大约每秒1至10比持。”
  “什么?!”旗舰上听到这话的所有人都大笑起来。
  “真的是每秒1至10比特,我们开始也不相信,但反复核实过。”
  “上尉,你是个白痴吗?”舰队统帅大怒,“你是想告诉我们,一种没有记忆遗传,相互间用声波进行信息交流,并且是以令人难以至信的每秒1至10比特的速率进行交流的物种,能创造出5B级文明?而且这种文明是在没有任何外部高级文明培植的情况下自行进化的!”
  “但,阁下,确实如此。”
  “但在这种状态下,这个物种根本不可能在每代之间积累和传递知识,而这是文明进化所必需的!”
  “他们有一种个体,有一定数量,分布于这个种群的个个角落,这类个体充当两代生命之间知识传递的媒介。”
  “听起来像神话。“
  “不,”参议员说,“在银河文明的太古时代,确实有过这个概念,但即使在那时也极其罕见,除了我们这些星系文明进化史的专业研究者,很少有人知道。”
  “你是说那种在两代生命体之间传递知识的个体?”
  “他们叫教师。”
  “教——师?”
  “一个早已消失的太古文明词汇,很生僻,在一般的古词汇数据库中都查不到。”
  这时,从太阳系发回的全息影像焦距拉长,显示出蔚蓝色的地球在太空中缓缓转动。
  最高执政官说:“在银河系联邦时代,独立进化的文明十分罕见,能进化到5B级的更是绝无仅有。我们应该让这个文明继续不受干扰地进化下去,对它的观察和研究,不仅有助于我们对太古文明的研究,对今天的银河文明也有启示。”
  “那就让蓝84210号舰立刻离开那个行星系吧,并把这颗恒星周围一百光年的范围列为禁航区。”舰队统帅说。

 


  北半球失眠的人,会看到星空突然微微抖动,那抖动从空中的一点发出,呈现圆形向整个星空扩展,仿佛星空是一汪静水,有人用手指在水中央点了一下似的。
  蓝84210号舰跃迁时产生的时空击波到达地球时已大大衰减,只使地球上所有的时钟都快了3秒,但在三维空间中的人类是不可能觉察到这一效应的。
  “很遗憾,”最高执政官说,“如果没有高级文明的培植,他们还要在亚光速和三维时空中被禁锢两千年,至少,还需一千年时间才能掌握和使用湮灭能量,两千年后才能通过多维时空进行通讯,至少通过超空间跃迁进行宇宙航行,可能是五千年后的事了。至少要一万年,他们才具备加入银河系碳基文明大家庭的起码条件。”
  参议员说:“文明的这种孤独进化,是银河系太古时代才有的事。如果那古老的记载正确,我那太古的祖先生活在一个海洋行星的深海中。在那黑暗的世界中的无数个王朝后,一个庞大的探险计划开始了,他们发射了第一个外空飞船,那是一个透明浮力小球,经过漫长的路程浮上海面。当时正是深夜,小球中的先祖第一次看到了星空……你们能够想像,那对他们是怎样的壮丽和神秘啊!”
  最高执政官说:“那是一个让人向往的时代,一粒灰尘样的行星对先祖都是一个无限广阔的世界,在那绿色的海洋和紫色的草原上,先祖敬畏地面对群星……这感觉我们已丢失千万年了。”
  “可我现在又找回了他!”参议员指着地球的影像说,她那蓝色的晶莹球体上浮动着雪白的云纹,他觉得她真像一种来自他祖先星球海洋中的美丽的珍珠,“看这个小小的世界,她上面的生命体在过着自己的生活,做着自己的梦,对我们的存在,对银河系中的战争和毁灭全然不知,宇宙对他们来说,是希望和梦想的无限源泉,这真像一首来自太古时代的歌谣。”
  他真的吟唱起来,他们三人的智能场合为一体,荡漾着玫瑰色的波纹。那从遥远得无孔不入法想像的太古时代传下来的歌谣听起来悠远、神秘、苍凉,通过超空间,他传遍了整个银河系,在这团由上千亿颗恒星组成的星云中,数不清的生命感到了一种久已消失的温馨和宁静。
  “宇宙的最不可理解之处在于它是可以理解的。”最高执政官说。
  “宇宙的最可理解之处在于它是不可理解的。”参议员说。  


  当娃们造好那座新坟时,东方已经放亮了。老师是放在从教室抗拆下来的一块门板上下葬的,陪他入土的是两盒粉笔和一套翻破的小学课本。娃们在那个小小的坟头上立了一块石板,上面用粉笔写着:李老师之墓。
  只要一场雨,石板上那稚拙的字迹就会消失;用不了多长时间,这座坟和长眠在里面的人就会被外面的世界忘得干干净净。
  太阳从山后露出一角,把一抹金辉投进仍沉睡着的山村。在仍处于阴影中的山谷草地上,露珠在闪着晶莹的光,可听到一两声怯生生的鸟鸣。
  娃们沿着小路向村里走去,那一群小小的身影很快消失在山谷中淡蓝色的晨雾中。
  他们将活下去,在这块古老贫瘠的土地上。收获虽然微薄,但确实存在着希望。

posted @ 2008-08-26 13:00 CowNew开源团队 阅读(1736) | 评论 (1)编辑 收藏

由于周末课程延迟,因此将上周末的课程移到本周三(2008-08-27)
2008-08-27晚上9:00-11:00
课程安排:通过面试题讲C#语法、数据类型转换。
大家课前请把以前学过的算法(冒泡排序、计算阶乘等等)用C#语言翻写一遍,加深理解,到时候听课就方便了。

 

posted @ 2008-08-25 23:00 CowNew开源团队 阅读(451) | 评论 (1)编辑 收藏

Macromedia Captivate
用来将屏幕操作录制成Flash格式的,比Camtasia Studio 5速度快,而且录制的尺寸小,而且有生成的操作提示。
posted @ 2008-08-16 23:57 CowNew开源团队 阅读(469) | 评论 (0)编辑 收藏

今天无意中上了CSDN,看到有人评论我的《自己动手写开发工具》,还为我写了一首诗,原文如下:

一本乱书,内容和介绍相去太远,挂羊头卖狗肉一个,仿李商隐<<泪>>题诗一律,刺之.

操贼挥鞭梅几多,刘公摔孩意如何?

官渡犹存半载粮,彝陵初流七月火.

是日公瑾宴子翼,当时仲达怨诸葛.

读尽三国骗中骗,未抵老周信中科.


这是我这辈子得到的第一首诗,而且上网一查,哎哟,还是原创!谢谢你抽时间为我写诗。谢谢了啊,还把我跟三国中的人物比,咋说呢,啥都别说了,缘分呀!
posted @ 2008-08-09 11:30 CowNew开源团队 阅读(529) | 评论 (9)编辑 收藏

ASP.net调试时那个WebServer是可以单独使用的,在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727下WebDev.WebServer.exe,
WebDev.WebServer /port:8080 /path:"c:\inetpub\wwwroot\MyApp" /vpath:"/MyApp"
可以用来做嵌入式Web服务器,免IIS。
反编译了一下,估计只要将GAC目录下的WebDev.WebHost.dll拷贝出来和WebDev.WebServer.exe放在一起就可以脱离VS使用。
posted @ 2008-08-07 17:06 CowNew开源团队 阅读(502) | 评论 (0)编辑 收藏

做为一个过来人(装装腔壮壮土气,其实再过一个月我也才30岁,只是17岁就入行),电脑应该是怎么学的,我对时下的肓从跟风有非常大的意见。。

所谓的专业技术其实际是业务模型的实现,而业务模型是市场需求总结出来的。。
所以技术的本质在于利益。。怎么做学什么符合目标(业务模型)就那么做,这是不可抵抗的原则,如果违反了,就会伤心,骂某人不识货,其原因是因为违反了这个不可抵抗的原则。

因为除去利益,技术什么也不是,它可以推动火箭上天,但若没有喝彩,汗水唯有黄土识。。
电脑就是这么学的。。

但是有几个误区一定不要掉进去。。

关键问题,值钱的技术是什么?
某些人,自以为自己很历害,VC、GCC都很牛(比喻了解和有能力生产core),但他始终只能拿工资,听不懂业务模型。。更笑谈项目设计及所谓的构架。。
其实值钱的是标准、协议,精之那他是CTO,如果再加上业务逻辑,那他就是副总(搞技术的去当老总就不算技术人员了,所以不在此列,因为马上要变质了,就象门口卖苹果的,专业知识只会用来吹牛),如果只拥有实现机理及构架能力的,那他是项目经理,如果只是会编程,那他只是程序员,如果编程还只是入门,那他就是打字员。。Microsoft Office 是由打字员+程序员搞出来的,对吧?然而金字塔的精妙会有人说是奴隶的功劳吗?

某天,我老婆叫我帮她刷投票,我的notebook上没有Windows 我执长的一些语言无从发挥,只有linux,为求简便不打算用gcc、java,想试用简便的shell脚本,可是我对shell 一无所知,咋办呢?于是我从网上下了一台参考手册,实际上我只要查一下 if 和 while的语法结构,不用一会,我就搞定这件事。。当不少朋友时刻在背那些命令、语法时,我正躺在床上看郑少秋的VCD。。(这也只是一个比喻,形容编译语言并不重要,最科学的完全任务是首要的)

首先我们分析一下,if while 在多如牛毛的编程语言里都是存在的,因为所谓的语言就只有这些东西和一些类库扩展函数(就象VBS 和 ASP,就象.Net Framework和API)。。这就是一种变相的潜标准,正如我要写数据库应用程序了,我知道,它肯定是由 “动作 目标 条件” 来组成,我无须去牢记那些不同数据库各自的命令,它一文不值,因为那是人家定的,人家想怎么说就怎么说,不如用的时候去check 就行了。。当然这只是一种形容,一种对交集的对待,并不是说不应该去学习各种不同特色,至少我面试MS SQL数据库人员时,不明白聚焦列的立即中止,命令记得再多再熟也是空谈。。因为它是一种基本机理,机理不明白,就只是打字员。。

所以学技术必须先学标准,要学标准必须先学习机理,考虑它如何做,为什么这么做,就可以了。背书完全没必要。。正如我看电视,我看的是艺人们怎么去回避那些尖锐问题,领导们是怎么博彩表现,演讲的人怎么去制造浮华噪影,考虑他每一句话的必要性、目的性和它的机理,故曰:三人行,皆有我师也。。就连苹果怎么卖也有很大的学问要让我们去学习,其根本原因是我们求知的方向和方法不同,导致的层次不同。。如果小板凳坐腻了,也考虑改变一下方式,将视野拉长一些,想的更复杂一些,虽然要少活了几年。。

换个角度,学网络开发必须学TCP而不是背sock,搞移动应用必须学GSM而不是背AT指令。。这就是标准和协议,我的大脑里装的仅仅是这些。。在掌握这些标准时,再去探索物理实现,广习机理可以帮助改善开发出来的成品的质量。

共享原则
03 年底,我初到北京入行从未涉足的SP行业,经过半年的奋斗,我的系统运作的很成功,另一个老总跟我说,拷贝一份给我吧,省得我们再劳动。。当时我始终不理解也不赞成。。因为我顾及的是影响竞争力的关键技术(我们用最便宜的机器跟着最快最稳定的MMS联盟平台,及后来的利用移动信道SMS成本发MMS)。。直到去年底,我才真正理解这个共享意义,我提供了一些无损竞争力的核心代码和机理给别人,人家借以加速了开发进度,缩减了开发成本并提早产生了利润并占领市场。而我,也从他们那里得到了更多(比如 codeproject,sf.net),我后面的团队进度比之前提升了整整一倍。。
软件无用论
很多非专业朋友在报怨Linux 平台的不是,Windows 的宏伟,亦或反之,实际上,完全忽略了,软件与OS是二回事,好,不争跨平台,就算各自组合成个体,正好我在回复一个朋友的贴子说为什么要用linux要用ubuntu 呢,我的回贴是:

能创造利润是我们出发点,不管是什么平台,对我们而言是划算的,那就可行的,不管是linux众多的发行版还是Windows、MAC都只是我们赚钱的工具而已,哪个好用容易达到目的就用哪个,它们只是抽像一些的工具。。对某些人,它可能是VCD是视频电话,但除此之外,啥也不见,当我按下power 键,一切都还是原来那样,而此刻才是真实的。。

那么用linux 之所以选择ubuntu,因为它是linux 里的一个最轻松快捷的系统,有很多的东西,不需要我们操心,一个快捷的apt-get 完全解决了我关键的时间问题,当我们用上gentoo 时,就会明白,我必须分秒必争,就算坐在马桶上也得事先安排一些代码让它去编译。。。如果我们面临的是一个集体,我们得有多少倍的时间花费在编译以及解决依赖问题上面?(这也是一个比喻,尽管我用的就是gentoo)

某一天,我们的国民象美国象日本那样的工作量和压力,我们就完全理解这些道理,可惜的是我们的人民太闲了,闲到象弥衡一样到处溜达。。。

上市的不少产品,尽管有不少是使用Visual Studio 开发的(多数团队选择使用它是因为开发人员的上阵成本较低且人才充足),然而这一切成绩,与Microsoft 一点关系也没有,没有人认为网易和新浪的成功与Apache有任何关联,它只是我们的一个工具,这也是为什么我们要付钱买它们的原因。。所以不要为它投入任何情绪,我们才是主要实体,想怎么用它就怎么用它。。

所谓的软件性能、特色,更加无谓的系统优化,什么也不是。。那完全是因为我们实在太闲了。。成天瞅那些所谓的高人学会这一些,也只能证明你了解原作者的意图或者对某作者的作品比较有共鸣了。。但是千万不要忘了,软件是人家写的,语言是人家撰的,我们除了报怨什么也做不了,很多年前,那时bill 还刚从IBM出来没多久,我习惯的是int xx mov ah 这样的写程序,现在却连VC的 printf 语法都已经不记得了,记得只是C#的 Console.Wrtile,这是微软安排的,不是你我能改变的,所以牢记它没有任何价值,只需要了解就已经足够(碰上猪头面试官就只好投其所好了,韩信碰上项羽都只能站岗,何况是我们呢)。。

标准和协议才是属于大家的。。就拿华为搞的无线运营商工程(尽管写的非常野蛮和漏洞100 出),没有强硬的国际标准协议的深度研习,靠1000个c高手也只是游通散兵,等同于1000个张飞,只能落草为寇,勇是必要的,但保命即可(形容程序只是次要的,因为有路由协议才有openwrt而不是因为有linux才有路由),关键的时候还可以共享前辈们的成果,这就是Linux 的开源、Microsoft 的 MSDN 的好处。。

总结:实践是不难的,但要建立在了解机理的基础上,OS和编程语言都是次要的,科学的组合利用实现业务目标才是首要的。坚持这个原则,有一天,会发现技术使用和应用的发展是有终点的(甚至在更高层次的见识下看到的都是冷菜热炒)只有领域是无极限的,因为“创新”一个领域是计算机事业的利润的基础,它永远不会停息。

之所以称此为“缪”论,是因为它还需要咀嚼,有高见可以来反驳,我很高兴有人来开导我。。

from:http://blog.163.com/scofield_cnh/blog/static/518753922007929104921607/
posted @ 2008-08-06 22:17 CowNew开源团队 阅读(349) | 评论 (0)编辑 收藏

要做一个项目负责人,首先要做一个好人。最自己负责,对领导负责,对组员负责,而如果想形成一个好的团队对组员负责是一个关键的问题。93年我第一次带团队的时候,我们在江苏开发一个项目,有一次,我的领导找到我谈工作,在谈到一个组员的时候,我问他为什么自己花钱给那个人买皮鞋。领导对我说,你难道没有看到他的手和脚都长冻疮了吗?你作为项目组长,你的组员才大学毕业,就和我们一起出差,第一次独身在外,你难道不能更加关心他吗?这件事情给我感触很大。作为一个项目负责人,不但要在专业上关心你的组员,在平时的生活中也要关心他们。这样才能形成一个好的团队。  

        关心组员,有几个方面,其中一个是注意组员可能的发展方向,比如我原来的领导建议我做测试或者QA,说我比较适合做个工作.开始的时候个人认为测试并没有什么重要的,还是喜欢做开发,后来因为一些偶然的原因作测试和QA工作,的确很爽.(不过要没有那些年的开发经验会这么爽吗?),在我自己的项目组里也出现这种情况,比如我原来的一个开发人员就是不愿意做开发,搞锝我很难受,后来和他交流发现他想做网络管理,在项目结束后,给他找了一个会做单位的网络系统管理员,他又自学了CCNP什么,干得不错.所以,作为一个项目组长,在关心你的组员的时候,要注意他们的特长和潜质,如果我的组员愿意做开发工作,我会为他们订制一个培养计划,然后给他们提一些要求,这样可以帮他们快速提高开发水平.而如果他们他们不愿意做开发工作,就要及时获得他们的真实想法,并帮助他们去实现他们的目标.这样开发组的内的气氛会很好。

对新参加工作的同志的关心要细致  

        新参加工作的同志和老同志的差别很大,我们这里的新同志都是刚毕业的大学生或者研究生.社会经验都比较少,对他们的关心就需要格外细致,比如在他们刚来的时候,机器设备的配置,软件的安装,各部门情况的介绍,都要和他们讲得比较细,这样比较容易消除他们的陌生感,很快的融合到集体中来,另外一个要注意的是,对他们的工作的安排和检查要细致.一般来说,我对他们工作的安排一般一个阶段不会超过两天,也就是说,两天比检查他们工作一次,在检查工作的时候,首先要表扬他们的成绩,然后告诉他们存在的问题,以及问题的解决方法.在让他们去试验(不可包办代替,让他们自己去做,这样才可以积累他们的工作经验).而且在检查的过程中尽量保持谈话环境的轻松愉快,(可以讲一些我们原来的臭事,避免单纯的说教式的检查方法),这样新同志一般都会接受我们建议,同时为以后的工作打下一个好的工作氛围,工作要细致的另外一个体现是要根据不同的人安排工作.比如我们今年招的测试人员,其中一个是计算机专业的本科,又在单位实习了3个月,我安排他的工作就是学习TD和QTP进行测试,原因很简单.他在单位做过测试,对测试理论的认识也比较到位,而且有一定的开发经验,那么如何早日将他培养成一个优秀的测试人员就是我的目标。

而测试工作的使用实施对他的个人发展就显得很重要了.另外一个是本科非计算机专业,他的主要工作就是不断重复的作一个系统的测试.每测试一次,我都要给他讲解一次,没有办法,他累我也累.但他没有开发经验也没有测试经验,如果一下上太复杂的东西,他不但不能掌握所学的知识,而且对工作会产生一种畏惧心理,这对他以后的发展是很不利的.所以我对他的安排就是在3个月内不断的进行实际的测试,并且不断总结经验,这样三个月的时间内,他基本就可以掌握测试的基本方法和理论,而在三个月之后,他也要开始测试工具的学习,而那时我的第一个测试人员已经记基本掌握了QTP,可以帮助他了.对不同开发人员测试人员的具体情况进行分析,让他们做适合他们做的工作,并且在每一次工作中都让他们不断增强自信心,而且提高自己的技术水平,你的组员怎么会不听你的指挥。 

作为一个项目要勇于决断 

        作为一个项目组长要勇于决断,项目组长是最了解项目的管理人员,无论是用户,组员还是测试人员和质量保证人员以及客户都是以项目组长为中心的,这个地位决定了项目组长应该是对项目最了解的人,那么他在关键时刻的判断和决断就对项目起着关键的作用.而作为项目组长如果不敢和不能决断的话,必然给项目的开发造成极大的困难,说两个故事。

        一个是我的哥们,有一次他去客户那里没有参加技术讨论会,回来的时候,他的开发人员的讨论会还在激烈的争吵着,见他回来了,分成两派的开发人员就让他来判断那个算法更好,我的哥们听了一会说,我来告诉你们如何取舍,于是从兜里掏出一个硬币,正面用A方案,背面用B方案,然后一扔,于是结果出来了.当时我听了这个故事直笑.问他为什么这么做.他说,我不搞技术很多年了,但听他们说得,两个方案差别不多,不过是A+B=C还是B+A=C的问题,这个时候如果你去参加参加讨论,无论采用A还是B都要费很多的口舌,而有那个时间早开发出来了,于是就想了这个方法.当然采用这个方案的时候,开发人员都看傻了,别忘了给你的开发人员讲解一下你为什么采用这样的选择方法  。

        另外一个项目就很有意思了,表面上这个项目组长很尊重开发人员,每周都要开一次周会,而且开会的时间还不短,可很快开发人员就不在会议上发言了,有一次和他们组的开发人员闲谈的时候,问他们为什么不在会上发言了,那个开发人员告诉我,每一次提出问题,组长都是侃侃而谈一番,没有任何实质内容,最好的情况是说这个问题下面让某某,于是坐在一边不说话了,更多的情况是说这个问题很重要,我们先放一放.下回讨论.可是问题既没有记录,也没有安排人去做专门的研究,往往是不了了之.一次两次,慢慢的开发人员都认为提的问题不可能得到解决,于是每次的周会就成了项目组长的独角戏,而其他人员的手机发短信的水平,以及图画水平倒提高了很多。

        很多项目组长往往感觉自己的权威性不够,经常会说给我这个权力那个权力,我就可以怎么怎么样,其实,项目组长的权威不是建立在对开发人员的工资或者其他的控制上,而是建立在你的做事方法,开发能力等这些软件水平上的,如果在你的组员遇到问题的时候,你可以为他们解决,提出可行的解决方法,什么和他们一起同甘共苦的去完成那些最艰难的问题,你的组员怎么会不信服你,你又怎么会没有威信呢。

对不同的人员采用不同工作的方法 

        作为项目组长最重要的一个特点是要细致,在安排和检查工作的时候尤其要细致。对待刚参加工作的工作人员和老工作人员也要区别对待,一般来说刚参加工作的人员工作热情都比较高,但工作方法的掌握都会有一些这样或者那样的缺陷,如何做到既不打击他们的工作热情,又防止他们的工作走偏是一个很重要的事情,我带项目组的时候,有一次给了我四个刚毕业的工作人员。我给自己定了几个原则,1要大胆使用他们,要帮助他们解决主要的开发问题,3检查工作要仔细,防止工作出现大的偏差,4分层次,区别使用,尽量作到用对他们。  

        先说1大胆使用他们,新同志一般工作都会存在这样或那样的问题,而且有时候问题比较明显,我原来也觉得使用他们不如自己开发快,所以总是越俎代庖,这样的结果就是我自己累得够呛,开发人员闲得要命,而且工作情绪不高i。为了防止这个问题的发生。这回我努力克制自己开发的欲望,将所有的设计、编码的任务都安排给他们,自己只负责总体设计、关键技术问题的解决和工作的检查。事实证明,只要你控制得好,开发人员都会比较好的完成开发任务,而且在开发过程中进步也是很明显的。我的这几个开发人员由于我敢于放权,不但开发完成的比较好,而且经验的积累也比同时间来的开发人员要快,很快成为了单位的开发骨干。

        放权不是不管,而是该管的管,不该管的不管。对于新同志他们都有一定的开发能力的欠缺,但主要问题体现在两个地方,一个是设计能力,一个是开发的规范性。总体设计是我来做的,然后给他们逐步讲解,使他们了解我这么设计的目的和方法。再让他们做自己部分的设计,开始这是很困难的事情。因为我们的系统需要很强的可扩充性和维护性,所以很多方面的设计方法和他们原来的开发有很大的区别。而他们在学校做的设计根本不用考虑系统的可扩充性和维护性,所以在很多设计思路上彼此差别很大,我不但要完成设计,讲解给他们听,而且要让他们接受我的观点,说实在的真是很困难的,我采用了和实际相结合的方法,告诉他们每一个设计的目的和实现的方法,如果他们有不同的设计也可以,大家一起讨论,如果他们的设计可以满足系统的需求那么我也很乐意接受。

另外一个是开发的规范性,我们的同志在学校的时候基本上都没有接受过规范性开发的培训,而这是在实际工作中必须特别强调的东西,比如代码的规范性、文档格式的规范性等,我就作为强制执行。当然如果一味的强调这是规范必须执行还是不够的(容易产生逆反心理),在具体执行过程,还要和他们去交流。比如如何写文档效果会比较好,如何避免有话说不出来的问题,一般来说,我都采用他们先写文档(或代码),我来检查,然后讲解,他们再修改。再检查、讲解,(编码也是一样),一般来说,第一次的文档他们会写4-6次,但经过一次这种训练,他们的文档撰写水平和编写代码的规范性就可以过关了。  

        新同志的工作周期我一般安排是1.5---2天的时间。一般来说。新同志的工作我都安排得比较细,他们的工作都在一天之内可以完成,这样主要是防止工作出现比较大的偏差。而且即使出现了问题,我也可以及时发现和调整,不至于对工作造成太大的危害。工作检查不是一个简单的评判过程,更是对他们的一个培养过程。一些工作方法,工作技巧都是在这个时候教授的。在这个环节要特别注意简单粗暴地对待开发人员,一定要将问题讲透讲清楚,最后还要让开发人员再讲一遍你的讲解内容和后面的工作安排(很重要的,在你听他们叙述的时候,往往会发现他们的理解和你的想法有很大的差别),防止交流的无效性发生,一般来说新参加工作的人员如果真接受了你的观点,使会主动改正他自己的问题的(虽然会有反复) 。

        即使是新工作人员,也会有很大的差别,作为项目负责人,要善于发现发现这些差别。比如在这个项目中,有一个工作人员作过OA项目(毕业设计),对OA的理解比较多,那我就让他负责系统最重要部分的设计,有的人比较细心,就让他负责配置管理,有的人比较善于钻研,就让他负责权限管理部分的设计(那部分比较难),总之,没有不可用的人,关键是看你是否用的对地方。只要用对地方,便可以达到事半功倍的效果。 

学会向用户汇报工作 

        当然了,也包括领导汇报工作。道理基本一样。说一个在科委项目的课题的故事吧,那个课题是一个做的不太好的项目。用户对我们很不满意。项目组长被撤了,开发人员也都走了,让我接手这个项目,我的目标是完善项目,我到项目经费(还有40%),其中的开发工作就不多说了,只说说向用户汇报的事情,用户的领导是一个50多岁的大妈(大妈是很聪明的,否则也不会在那里做到这个职位),对我们很不满意,开始的时候,我坚决承认错误,绝不隐瞒(获得对方的认可),其次在后来的时候每次去用户那里,我都会琢磨一下是否要去向她汇报,如果没有太重要的事情,就想想最近在做什么事情,这样在见到大妈的时候,可以汇报,如果真是需要汇报,就要特别考虑一下几个问题,1我现在的工作进展,2我遇到的问题,3问题那些是我可以解决的,什么时候会有答复,4什么问题需要用户配合。(比如硬件设备的改善等)具体配合的内容是什么。在汇报的时候,我会私下掰手指头,一个问题一个问题说,防止遗漏,同时要记住对方的回答。这样几回之后,大妈对我的感觉很好,后边的工作就好做了,后来项目顺利完成。经费自然也回来了,所以在和用户汇报工作的时候要特别注意几点:

        1项目是最重要的,无论你采用什么作客户关系的方法,项目或产品必须过关,否则一切都是无用功(国家项目不一定)  

        2在汇报的时候,态度要认真。特别是出现问题的时候不要一味推卸责任,讲理由,这是没有效果的(在单位汇报工作的时候也一样,没有人会理会你的理由)  

        3汇报之前一定要准备,这样条例清楚,事情完整。防止因为一点小事情连续打扰客户。要让客户在每一次交流时都有很大的成果。

        4汇报的时候要掰手指头,主要是防止问题的遗忘,特别是大家在就具体问题讨论的时候容易干扰你的思路,使你遗忘事情 。 

        5在汇报之后要将所有问题都过一遍,是否所有的问题都有解决方法了,如果什么事情不清楚,马上问,这样总比再次来好,在说出来,和用户一起确认问题的解决方法 。

        6实在怕遗忘,最好带一个录音笔,但千万不要让用户看到,也不要用这个东西作为以后争执的证据用(没有好处的),只是作为资料整理的一个备份,否则用户会反感而不配合你以后的工作。



from:http://news.csdn.net/n/20080804/117869.html
posted @ 2008-08-04 20:48 CowNew开源团队 阅读(515) | 评论 (1)编辑 收藏

做雷兔的群主将近一年了,在这一年里,有好多初学者都问过同样的问题,“哪种技术有发展前景,以后赚钱多呢?”我每次听到有人问我这个问题的时候都很茫然,觉得这是一个不是问题的问题。

 

我记得我最初学吉他的时候,我问过老师一个问题,“我想买一把好用的琴,每天练习”,老师的回答很经典。“在你没学会以前,哪把琴都好用”,这句话在我日后的学习和工作中始终影响着我。

 

其实不管是学习什么,都分为两个阶段,入门阶段和提高阶段,初学者首先要做的是通过一种途径进入这扇门,然后再想未来发展的问题,一步一步的来,如果非要超越这个步骤的话,等待他的只有失败。这种想法我也能够理解,毕竟社会压力那么大,中国经济形势目前出现了前所未有的局面,房价物价飞涨,股市大跌……,对于我们每个人来说,生存的压力都非常大。这个时候人很容易产生一个误区,好像学习一项以后将用来吃饭的技术是在赌博,赌赢了可以赢得很光彩,很体面,高官得作骏马得骑,赌输了,竹篮打水一场空。其实大可不必这样,如果确定自己真的对一门技能有兴趣的话,那么学就好了,不要管它是否有发展前景,能否为你带来丰厚的收入,当你通过自己的努力,进入了这门技能的大门以后,根据你对于技术本身的理解,你自然就会知道哪个发展方向适合你,哪个技术具有好的发展前景了。还有一点,任何技术发展到了今天,既然已经有很多人在用,既然它能够让你知道它的名字,那么技术本身自然有它存在的必然条件,问题的关键在于你究竟掌握得怎么样。有句俗话叫做365行,行行出状元。只要你掌握的好,竹竿子也能成为你得力的武器的。

 

在这里,我给想要学习某项技术的人提几点建议:
     1.在这个世界上,并没有什么高深的技术,只要你肯钻研,你就会学得很好。
     2.在你真正了解这门技术以前,不要盲目的听别人说这门技术怎么怎么样,因为他说的未必是对的。
举个例子,在我刚开始接触WEB技术的时候,有一天走在路上,听到身边两个人在谈论这个,一个人问另一个人,“我想学做网页,你觉得怎么学比较好呢?”另一个人回答说“学习做网页,需要学会3种东西,Dreamweaver、HTML、JAVA”,说完这个他又解释说“Dreameaver是一种网页得高级编程技术,HTML是网页的一种编程语言,JAVA是用来做一些网页特效的,比较高深,这三种技术都不好学,非常难”。我当时听了,对那个人崇拜的五体投地,同时“很难学”也对我有了很大的打击,可当我慢慢的走进了这扇门以后,回想当时那个人说的话,真的挺想笑的,他说的根本就不对,或者说是不全对。
     3.不管你学习什么,既然决定学了,就要塌下心来,一步一个脚印的学,不要一山望着一山高,没学两天就觉得别的东西更有意思,马上转学别的,这样的话注定哪样东西都学不好,最后一事无成。
     4.在你没有入门以前,对你来说任何技术都是枯燥无味的,你会觉得很艰难,但是请你不要放弃,一旦过了这一关,你就会觉得豁然开朗,开始真正的体会到技术本身的乐趣。
     5.当你入门以后,换句话来说,当你尝到了技术本身的乐趣以后,并不代表你已经学得很好了,这仅仅是一个开始而已,如果你觉得自己学某项东西已经学得很好的时候,那只能说明你还处于初学,刚刚入门阶段,任何东西当你学得越深,你越会觉得自己了解的少。

这些是我这些年学习过程中积累下来的东西,拿出来和大家分享,希望这个能够让初学者少走一些弯路,更快的实现自己想要实现的目标。

可能有人还是很疑惑,究竟学习什么比较好呢,呵呵,那就要看自己兴趣了,看你对于自己有多了解,自己是自己最好的伯乐,要善于发现自己的过人之处,给自己寻找一个最好的出路。

最后,还有一点要说。呵呵,还是用例子说明一切吧,相信我们每个人都读过不少书,上学的时候可能每个人都曾经抱怨过,“学这破玩艺有什么用啊,以后我又不干这个”,老实说,我也曾经这么想过,可现在一路走过来,再回头想想,其实我们上学学的知识只是一个方面,更重要的一点,是我们在学习的过程中培养了自己的思维能力和探索学习新事物的能力。今天你学了一门技能,你不光学到了技术本身的东西,还培养了自己的学习能力,就算哪天这门技术即将被淘汰了,那么好,我很快就能学会新的,这才是真正的让自己在激烈的竞争中立于不败之地的才能了。

The end.

 

BY 呆瓜



FROM:http://www.cnblogs.com/f_pig/archive/2008/08/01/1257800.html
posted @ 2008-08-01 09:41 CowNew开源团队 阅读(320) | 评论 (1)编辑 收藏

我不是阴谋论者,也不是为了吸引大家眼球。此时此刻,当我写下这个标题,我眼前不禁浮起2008年四月份我在吉林大学的场景:当我问起“你们在座各位同学有多少人一毕业就要面临失业的痛苦”,台下是那可怕的安静。那么我请问大家为什么大学生就业难?你们相不相信你们在媒体看到的解释原因基本上都是错的?其实这也不是媒体的错,只是大家不了解全球产业链阴谋而已。

我希望我们的新一代,希望我们未来的领袖们都能具备逆向思维的能力。而对于媒体上以及很多专家学者提出的中国是个制造业大国这个命题本身,能多一些辩证思考。

中国是制造业大国吗?

首先我想问问大家,你认为今天的中国是制造业大国么?我在这里清楚地告诉各位我的研究结论:中国根本不是制造业大国,真正的制造业大国是美国!大家可能觉得我这个结论很荒谬,因为很明显一方面珠三角地区、长三角地区和环渤海经济圈在制造业的各个层次上表现好像很是欣欣向荣,另一方面在诸多产品产量方面中国在世界市场上都是首屈一指。

那么我怎么说我们不是制造业大国呢?我要跟各位谈的就是一个新观点,也是我个人的研究心得。我要清楚地告诉各位:今天的国际竞争已经不是企业的竞争,已经不是产品的竞争,而是进入到了一个前所未有的,一个全新的产业链的战争市场。

什么叫做产业链战争?我就以芭比娃娃为例,芭比娃娃也是中国出口玩具中的一种,而众所周知去年中国和美国之间产生了比较严重的玩具贸易摩擦。美国政府以及美泰等美国玩具进口和零售商对我国的玩具出口产品百般挑剔,比如提出含铅量超标等等的问题。可是当我听到这个新闻的时候,我就想为什么会含铅量超标呢?又有多少退货是产品设计的问题呢?

而大家知不知道,以芭比娃娃为例,我们制造的过程当中,破坏我们的环境,浪费我们的资源,剥削我们的劳动,可是真正的结果是什么呢?我们制造出价值一美金的芭比娃娃,但是最后在美国沃尔玛的零售价格是9.99美金将近10美金。我请大家仔细想想,从一块美金升值到10块美金的的过程当中,10减一,这9块美金的价值是从哪里来的?

产业链6+1

我们的制造业工厂,对外拖欠原料和组件货款,对内延长劳动时间等等,真可谓不择手段,不停压榨,然而放在全球产业链的视角下,只不过是只针对一美金这部分做文章,在最不赚钱的领域不停压榨!这种死拼完全忽视了产业链战争的特点。实际上,任何行业的产业链,除了加工制造,还有六大环节:产品设计,原料采购,物流运输,订单处理,批发经营,终端零售。正是这六大环节创造出了九美金的价值,而他们这六大环节就是整条产业链里面最有价值能够创造出最多盈余的一环。不过在现在的全球竞争格局下,这些环节中最关键最赚钱的环节,几乎都不是我们中国企业所控制的;少数中国企业意识到了,继而取得了巨大的成功,但是可悲的是,大多数中国企业和中国企业家还没有觉醒!

那些没有觉醒的大多数在国际分工之下,被分派到哪一环节了呢?事实上,都被分到附加值最低的,浪费资源的,破坏环境的,不得不剥削劳动的——制造环节。而其他有价值的环节基本上全部掌控在欧美各国的手中。也就是说,当我们破坏环境、浪费资源、剥削劳动创造出一块钱血淋淋的产品之后,我们同时就替美国创造出九倍的价值。当我们创造出一万美元的价值之后,我们就同时替美国创造出九万美元的价值。因此中国越制造,美国越富裕。

中央党校周天勇所收集的数据证实了我的观点,从这些数据来看,这种制造业对中国资源的浪费,环境的破坏和劳工的剥削是不可想象的。

以资源浪费为例,中国百分之八十的江河湖泊断流枯竭,三分之二的草原沙化,绝大部分森林消失,近乎百分之百的土壤板结。而且这10年来中国出口日本的方便筷子总计约2243亿双,而为生产这些筷子而毁灭的山林面积占中国的国土面积的 20%以上。

以环境破坏为例,中国三分之一的国土已被酸雨污染,主要水系的五分之二已成为劣五类水,3亿多农村人口喝不到安全的水,4亿多城市居民呼吸着严重污染的空气,1500万人因此得上支气管炎和呼吸道癌症,世界银行报告列举的世界污染最严重的20个城市中,中国占了 16个。

以剥削劳工为例,根据志愿者曾飞扬的调查,珠江三角洲每年仅冲床工人发生的断指事故至少就有3万宗,被机器切断的手指头超过4万个。而其它绝大部分机器设备造成的工伤事故有多少,目前没有统计。而此前对深圳800万民工的调查显示,每五个人中就有一人受过工伤或患过职业病,为了防止伤残工人打官司影响经济效益和社会稳定,珠江三角洲一些地区把外来民工正常的诉讼时间拉长达到三年以上,迫使伤残民工因耗费不起钱财而放弃上诉回到农村。

从产业链分工看大学生就业困难

那么,这个国际产业链的战争和大学生就业有什么关系?我想大多数人应该答不上来。那我告诉所有读者,为什么大学生就业难。我们在大学扩招合并造出这么多大学生的时候,当初是个什么思维?因为当初我们国家大学生的比例严重低于欧美平均,所以我们就误以为我们培养更多的大学生之后我们经济会更有质量,会更高速的发展。我们哪里知道,这个想法前提就是个问题:美国为什么需要这么多大学生,而中国培育出这么多优秀大学生为什么失业?难道是我们学生程度不够?难道是我们同学不够用功?难道是我们同学专业不对口?

我刚才讲的几句话应该是媒体里面所谈论的现状,实际上这些解释都是错误的:事实上,既不是我们中国学生不用功,也不是因为我们专业不对口。首先,我想谈一谈专业不对口,我觉得这个问题本身就特别可笑,而且可笑得一塌糊涂!我在美国教过不少顶尖的大学,也在世界其他地方教过不少课。可是我教了这么多的学校,我就从来没看过那里哪个学校是专业对口的。那既然美国的大学生专业不对口,我们中国的大学生专业不对口有什么错呢?

再想想,本科教育的目的是什么,本科教育的目的就是专业不对口。为什么呢,因为是通才教育而不是专科教育。什么叫通才教育?也就是说美国大学生和我们大学生一样,要学心理学、经济学,社会学、文学、哲学,那么这些学问跟就业关系不大,这就是通才教育的本质。

那么请读者做反向思维------产业链跟我们大学生就业难有什么关系。关系太重要了,而且是唯一的。在整条产业链六加一的环节里面一是什么,一是制造,就是这种血淋淋的制造业,还有六,六就是从产品设计开始到零售这六大软环节,六加一的环节里面,真正需要大学生的是六而不是一。举个例子来讲,就说工厂,从董事长到门口的保安,可能没有一个大学生,为什么?因为它的本质是不需要大学生。那么真正需要大学生的是什么呢?那就是产业链里面六大软环节需要大学生包括产品设计、仓储运输、原料采购、订单处理、批发经营、以及终端零售。

那么,今天的中国是一个什么样的产业结构,是一个以一为主而不是一个以六为主的产业结构。这个产业结构本身,构成了大学生失业问题的源头。我国的产业现状不足以支持这么样的大学生比例,这就是大学生找工作难的原因。那么为什么美国需要这么多的大学生呢?因为美国所掌握的就是产业链里面最有价值的六部分。它要通过大学生的通才教育创造出更多的价值。但是有一点是我们一直忽略的,那就是我们甚至不理解国际产业的分工当中我们国家是处于何种的劣势地位。

所谓劣势,就是以制造业为主的中国,它产生了诸多的后遗症,读者应该已经完全感受到了。就比如我们很多的大学生,毕业之后不得不考研究生,研究生考过了又失业了。再考博士生,但是博士生要做本科生的事,你不觉得是很大的人才浪费么?

产业链定位悲剧

赤裸裸的事实是我们已经失败了,因为我们被定位在价值最差的制造业环节,而这个制造业环节的特征就是浪费资源、破坏环境、剥削劳动力。而六大软环节,既不剥削劳动,又不浪费资源,更不破坏环境,却能创造出九倍的价值。大学生在这六大环节当中才能有学有所用,才能替国家创造出更多的财富。

以我国制造业而言,2006年,还有可能达到百分之五的净利润回报。2007年呢?百分之二左右吧。2008年今年呢?可能是负的吧。那么我们制造业的困难不是我们不勤劳,不是我们不努力,而是一开始就定位在整条产业链结构中最没有价值的一部分。

你认为我们中国还有廉价劳动力优势么?过去,你可以这么想,但是今天你一旦读完这篇文章,就不能这么想。因为劳动力的优势对个别工厂而言可能有优势,但是,在整条产业链的竞争下,我们毫无优势。我再以芭比娃娃为例,整条芭比娃娃的产业链的十美金,而制造业的劳动成本,只占着一块美金的百分之二十五,也就是说,整条产业链是十美金,而劳动成本只占两毛五分。这么少,因此想透过中国廉价劳动力走出国门的企业都必将失败。

比如说我们最熟悉的两个企业一个是TCL,一个是明基(BenQ),TCL和明基都提出来要利用中国的廉价劳动力以及和国外的品牌、技术要走出去。

我的观点就是——“你一定会失败”。而且大家知道我讲话比较绝对,类似“你有可能会成功”这种模棱两可的话我从来不讲。具体来说,像TCL李东生合作、收购了阿卡特尔以及法国的汤普森,明基收购了西门子的移动业务。阿卡特尔也好,汤普森也好,西门子也好,不都是国际名牌么?不都有着全世界最先进的技术么?既有品牌又有技术,再配合上中国的廉价劳动力,哪有失败的可能,当然应该成功了。

但是,今天大家读完我对产业链的分析之后就不应该这么想,读者应该和我一样同时直面批评他们一定会失败。为什么?因为劳动优势只是一块钱的百分之二十五,而在十块钱里只占了两毛五分钱的劳动成本优势根本没用。一两年之后,两家公司的合资业务轰然倒塌,根本走不出去。我可以很清楚的跟大家说,今天中国企业所面临的问题,已经不是国企和民企哪个更有效率的问题,而是在这种国际产业链分工之下,如果国企和民企不能急起直追的话,有可能双双被淘汰,事情就是如此之严峻!

产业链阴谋与二元经济的成形

产业链阴谋下的中国企业的本质就是在夹缝中苦苦挣扎。但是另外一方面,中国经济发展速度却极快,每一年以10%以上的速度高速增长,这又是怎么回事呢?这是因为我国这十余年来的经济发展的思维就是扭曲畸形的。也就是说地方政府以推动GDP的方式(也就是我所批评的以GDP为纲的理念)拉动了中国经济增长。我以GDP的组成为例,欧美日本的GDP当中70%是消费,也就是社会需要什么物品,就生产什么物品,因此是正常的经济成长。我国GDP当中消费只有35%,是欧美日本的一半,这种消费不足的现象主要还是我国的社会保障体系不健全所导致,老百姓必须存钱上学,住房和看病,因此不敢消费。那么我国GDP其余部分是怎么构成的呢---------也就是超过一半的GDP都是固定资产投资,而欧美日本的固定资产投资只有我们的一半。什么是固定资产投资?也就是读者到处可以看到的高架,桥梁,地铁,地产等等。这些过度的投资带动了经济的成长。所以我国经济就是一个畸形扭曲的“二元经济”,一方面是由于产业链定位错误苦苦挣扎的制造业,另外一方面是极其火爆以拉动GDP为主导的建设工程包括了钢铁,水泥,政绩工程,形象工程,大型国企,替他们融资的银行等等。前者占了经济总量的七成,而后者占了三成。这种二元经济就是中国的特色,但是最近几年由于政府政策的错误,使得二元经济现象更加严峻。

第一个错误就是以拉动GDP为主导的经济发展政策,无疑的造成投资过多,而消费过少的局面-----------我们工厂生产出这么多的产品由于国内消费不足,只有出口卖给外国人消费,因而必定造成所谓“出口创汇”的现实情况,我国出口减掉进口的贸易顺差几乎是日本的两倍,而达到9%的高水平,因此外汇迅速积累。截至2008年七月为止,我国外汇存底已高达1.8万亿。这么多的外汇给了欧美各国极好的借口压迫人民币升值,而人民币的不断升值使得二元经济当中产业链定位错误的制造业更加雪上加霜,使得制造业部门变冷,而火爆的建设部门相对的持续发热。

第二个错误就是劳动合同法的不当推出,这里我要做一个表态,劳动合同法本身它的意义是重大的,我相信全国老百姓包括企业家以及劳动者,对于劳动合同法的本质意义都会赞同。问题是这么重大的法案,竟然没有经过反复的讨论论证,更严重的是,没有经过任何的试点就全面的推出。仓促推动之下,进一步打击了过冷部门制造业的投资营商环境,而使得过冷部门更冷,而过热部门相对持续发热。

第三个错误就是宏观调控的错误,政府看到了股市和地产的过热就持续加强了宏观调控的力度。具体举例而言,2007年年初到年中阶段,深圳的房地产市场非常的火爆,那时候媒体都报道说,老百姓对我们经济发展更有信心了,深圳地区经济发展更成功了,所以深圳房地产才会火爆。大家还记得我当时的解读吗?我说内地专家学者的这种看法错了,本质上,深圳地区房地产之所以火爆是因为深圳的经济发展更衰退了!实际上,是因为企业家更不想继续经营实业了,因此那些本应该投资在企业的钱,他们决定不投资了,而拿出来炒楼,所以,换言之,房价上涨的原因是经济更坏了,而不是更好了!这甚至可以解释成“回光返照”的现象。我这个看法当时有很多人反对,当然也有不少人甚至完全没有听懂!而到2008年一月份和第一季度公布的统计数据完全证明了我们的观点:深圳地区倒闭的企业几乎居名列前茅。

同样,2008年的上半年,我分析认为深圳市中心楼盘价格依然坚挺,而附近中低价房会跌价。因为这些企业或企业家把本应继续投资实业的资金转作投资,用来买高价房,从而全面拉动中低盘房价,形成泡沫现象,再因为宏调和消费力不足的造成中低价楼盘全面跌价。那么高价楼盘还会坚挺多久呢?他就要看企业家资金的动向,而不是看经济的动向。只要企业家抽出资金就会给高价楼盘带来降价压力。

那么整个中国经济究竟有多复杂呢?我们可以从一个很简单的问题开始:你们认为,今天的中国企业是过热吗?如果中国企业过热,企业家的日子怎么这么难过呢?!如果你现在从事的恰好是制造业的话,那么你此刻所感受到的是不折不扣的萧条而不是过热。如果你因为不切身从事而还没感觉到,那么请你去看看飞跃等出口型企业现在的困境吧!

可是,为什么政府说是过热,甚至动用这么大力道控制通货膨胀呢?2008年6月,越南发生了严重的金融危机,而且导火线就来自于这个国家通货膨胀失控,通货膨胀高达25%,一般老百姓看到了越南货币不断的贬值,他们就换美元,换欧元,换其他国家的货币,甚至是换黄金。到最后发现,换美元非常的艰难,不让你换了,怎么办呢?就开始大量的囤积抢购物资,希望能保值。越南本地银行都不愿意做房地产购屋贷款,不想用越南货币做,怕贬值。这种现象的冲击使得我们的政府更有决心进行宏观调控。因为,我们的政府认为,今天中国的问题是流动性过剩。

你们可能会问我,什么是流动性过剩。简单的讲,流动性过剩就是我们手上的钱太多了!我们手上钱多了以后,买楼房就造成楼市泡沫,买股票就造成股市泡沫,买产品就造成了通货膨胀。因此用流动性过剩这个理由可以解释2007年所看到的一切现象,包括楼市泡沫、股市泡沫,以及通货膨胀,所以我们的宏观调控是延续了过去四年来的紧缩政策一直到今天为止。在07年你可以糊涂,因为楼市泡沫,股市泡沫,通货膨胀你可以用简单的钱太多来解释,可是2008年,你看不到楼市泡沫了,你反而担心,楼市要下跌,股市更不用讲了。股市大跌的程度几乎全球名列前茅。那是流动性过剩吗?!通货膨胀确实是有,说不定更严重了?目前的经济现象已经让流动性过剩理论破产了!

如果把目标搞错了,在二元经济环境之下推动这种控制流动性过剩的宏调是什么结果,可以通过三个管道彻底的打击了二元经济的制造业部门。

第一个管道, 银行从过冷的民营企业部门大量的收回流动性,打给过热的地方政府继续从事地方基础建设,这就是为什么四年宏调下来,我国广义货币的增长率依然在18%的高水平,这么多货币供给为什么企业家享受不到实惠呢?因为这些钱通过银行体系从民营制造企业手上收回更多的钱,给地方部门从事地方建设了,这样让二元经济当中过冷的部门更冷,过热的部门更热。

第二个管道,就是处在过冷部门的民营企业家面临宏调所带来利率和银行存款准备金率不断上升的压力、再加上第一个错误造成的汇率的不断上升和第二个错误劳动合同法不当推出等因素,让这些过冷部门的制造业企业家再也干不上去了,所以就把很多应该投资的钱不投资了,从过冷的部门抽出来,打入过热部门去炒楼炒股了,这就是06年开始的股价上涨,也是06年开始房价上涨的主因,那是因为在二元经济环境下,过冷部门的资金大量转入过热部门所导致的,根本不是流动性过剩。

第三个管道,我称之为海尔现象,海尔筹集150万资金自己去干房地产,很多媒体说那是海尔战略重新出发,我说不对,那是海尔在过冷部门的家电制造业干不下去了,就从过冷的制造业部门抽出大量资金,打入过热部门,干开发商了!这种现象也使得资金从过冷获得部门转移到过热的部门。

这三个管道无疑的使得资金从过冷的部门逆流转到过热的部门,使得过冷部门更冷,制造业逐渐萧条,而过热部门更热,这就解释了为什么四年的宏调会失败。

二元经济和股价的关系-----同样的,我们也可以利用这个二元经济的理念来解释股价的走势。2006年股价上升的原因就是因为上面第二个原因使得资金逆流转到股票市场,而造成股价大涨,根本不是因为中国的经济环境更好了。 2007年5月30日政府调升印花税的举措使得股价大跌,但是从五月底到11月的股价大涨却是由大盘股所拉动。当时的大盘股都是那些股票呢?就是地产,钢铁,水泥,政绩工程,形象工程,大型国企,替他们融资的银行,当然还有证券公司。请各位读者回忆一下,这些部门是不是就是我前面讲的二元经济中过热的部门呢?换句话说,当时股市所谓的二八或三七现象拉动了股指,其中的二或者三就是二元经济中过热的部门。到了11月我已经开始呼吁股民注意股市可能的向下波动,听了我的话的股民都逃过了一劫。我当时为什么不看好股市呢?原因很简单-------因为大盘股涨幅太快,一定会回调,而其他股票都是过冷部门的股票,没有涨的可能,因此二元经济中的过热部门股票一定会回调,而过冷部门的股票没有理由涨,其结果就是大盘一直跌到今天。

二元经济和金融超限战引发的通货膨胀

二元经济引发通货膨胀------------读者一定很好奇,这种恶化二元经济的宏观调控政策能够控制通货膨胀吗?当前的治理思路就是简单认为我们当前的国民经济体系中流动性过剩了,所以买什么东西,什么东西就涨价,换言之,宏调的目的就是靠提高利率和准备金率收回一定量的流动性,就可以克制通货膨胀了!是吗?如果真是这么简单的话,我们就太幸运了!我最近和媒体朋友吃饭,媒体记者看到我第一句话就是郎教授你瘦了。我说对的,他说为什么。我说猪肉贵了,我就趁机减肥。

你们认为猪肉价格上涨,粮油的价格上涨,是因为你手上的钱太多吗?!如果真懂经济学的话,就不用讲经济学的理论,用一个老百姓能听得懂的话讲出来就对了。猪肉价格上涨了,是因为钱太多了吗,各位读者想想,如果你钱多了,你会去抢购猪肉吗?!甚至有人认为大米价格上涨也是流动性过剩,难道读者有钱的话要吃五碗饭吗?!你用膝盖去想想,你就会知道流动性过剩是胡说八道。读者哪有可能因为手上有钱可能就多吃大米呢?!也不可能多买猪肉啊!我们食品价格上涨多少,按照官方的公布22%,猪肉76%,实际上比这个高。食品价格上涨这么快,你可以找任何理由,千万不要讲是因为大家手上钱太多,根本不可能,有钱的人不会去多吃几碗饭,但他可能去买奢侈品,买LV包包有可能,食品价格这么高而且远超过其它货品就充分证明流动性过剩是错的。那为什么涨这么多呢?!就要从二元经济开始讲了。

在二元经济里面,过热部门是膨胀的部门,所以价格就上升了,这可以理解。那么,你认为,过冷的部门的价格会下跌吗?不会。过冷的部门价格也会上升,无论是过冷过热部门的价格都是涨的。例如猪肉就是过冷部门的产物。猪肉价格怎么上涨了,原因很简单,那就是二元经济现象。养猪肉的民营企业家跟其它行业企业家是一样的,他们所面临的投资营商环境也是急速恶化。什么原因呢?就是进口饲料价格大涨,还有猪瘟。按照我的二元经济理论他们会怎么做,他们就不养猪了,而把应该投资买小猪的钱不买了,而去炒楼炒股了。所以今天猪肉价格上涨的原因就是农村养猪户从过去的猪肉供应者,变成了今天的猪肉消费者,就这么简单。也就是说,当把你猪宰了以后,你发现后继无猪。政府为了鼓励农民养猪,而提供了各种优惠措施,如果农民不小心把猪养死了,政府还会补贴五百元的丧葬费,但是为什么大家还是不养呢?因为这些补贴弥补不来营商环境恶化带来的损失。

金融超限战(超过传统战争限制的新战争)引发通货膨胀-----------最近石油期货价格涨到130多美元一桶,大米价格飞涨,按照经济学理论似乎很难解释!很多经济学家是只认死道理,不知道怎么一回事!我给读者一个数据大家就懂了,每日石油供需基本维持在8700多万桶,而且有时候市小幅度的供过于求。此外,2008/2009年度的全球农产品供应量大约是21.6亿吨,而需求量接近21.5亿吨,年底库存接近3.4亿吨,这是小幅度的供过于求,两个市场没有出现大幅度的供不应求现象。那么为什么石油价格和粮食价格大幅上涨呢?显然不是供求的问题所造成。原因就是我们进入了一个前所未有的金融战时代-------产品定价权不再由供需决定,而是由国际金融炒家所决定,我们已经进入了一个前所未有的金融超限战争的年代。

为什么金融炒家进入大宗物资的期货市场呢?请读者想一想,炒期货的成败,有一个必备的原则,那就是经济基本面一定要配合你的炒作方向,比如我今天赌这个股票会涨,你就要肯定未来一定有人会买这个股票,比如说你认为大米会涨,你就一定要确认一定有一个国家去大买大米。你一定要掌控基本面才能炒期货,否则容易失败。

我们来看看国际金融炒家是怎么想问题的。他们一下子就看到了中国,各位读者知道中国的影响有多大吗?我们石油价格才涨了13%左右,全世界期货市场的石油价格当天一下子大跌,因为中国人买什么东西,什么东西价格上涨,因为中国人太多了。就以国际金融炒家的立场来看问题,中国人买什么东西,什么东西就大涨,这不就是基本面吗?因此在中国人买什么东西之前先买,比如从一百块炒到三百块,再卖给中国人,国际炒家就赚两百块。生产者没赚到好处,我们大亏,这就是国际金融炒家的阴谋。

金融超限战的原则就是取得定价权----------国际金融炒家为了取得产品定价权就开始选品种,首先他挑到了大米。为什么是大米?而不选小麦,这就是水平呀!因为喜欢吃大米的国家相对吃小麦国家而言,一般而言都是比较贫穷的。这些贫穷国家的老百姓吃大米,如果买不到大米怎么办?就饿死了,但是不是简单的饿死就算了,这会造成政局的动荡!所以,把大米价格一炒高以后,这些吃大米国家的政府立刻面临倒台的危机,因为买不起大米。而且大米价格一上升,稻米出口国就配合国际炒家,像越南一样,不让大米出口,为什么呢?首先保证本国人民不被饿死,因为一饿死政府就倒台,亚洲这些产稻米的国家不让稻米出口了,读者想一想如果不让稻米出口是什么结果呀?价格更涨。那些穷国,比如说菲律宾就更买不起大米了。国际炒家就这么厉害,大米价格一炒高,各国政府为了保全政权的稳定就不出口大米,越不出口,价格越高,穷的国家更买不到大米。其必然结果就是这些大米进口国一定会有人饿死,一旦走到这么一天,这些穷国一定会尽自己的最大力量,砸锅卖铁,求爷爷,告奶奶,到处借钱,他们什么都顾不上,而只能去国际市场上用高价格买大米,以防止自己本国的老百姓饿死。如果所有的国家都是这个逻辑,怕老百姓饿死,连带的使政府倒台,在所有国家都不出口稻米的情况下,不得不接受国际炒家最高定价,只要有一个政府去买,这个价格就是市场价格。就像炒股一样,如果有人在13块交易,市场价格就是13块,12块交易,市场价就是12块。因此,这些穷国家的政府在求爷爷,告奶奶,砸锅卖铁的情况下,筹出这么一点点钱在国际市场上只要一买稻米,这个最高的天价就是稻米的市场价。在这个时刻读者知道不知道发生了什么事?那就是稻米的定价权由过去的供需双方决定,改成了国际金融炒家的定价,也就是国际金融炒家取得了最终定价权。

由于是国际炒家取得了最终定价权,所以供需不重要,世界大米供过于求,石油供过于求,价格却不跌反涨,因为2008年的大宗物资价格是由国际金融炒家决定的,他们说几块金钱就是几块钱。他们找代理人来放话,例如在中国游走的罗杰斯就是其中的重要成员,例如他曾经说过粮食价格上涨将会饿死人,这不就是国际炒家透过饿死人来达到控制定价权的目的,而透过这些代理人发话吗。

这种国际通货膨胀怎么影响我国的物价呢?我以东北大豆为例。中国东北黄金大豆原来是中国最好的,现在美国的大豆进来了,美国大豆比中国的大豆好,因为出油量高达23%,而且价格比我们东北大豆便宜12%。刚开始的时候,因为美国大豆便宜了,所以大豆油也便宜了,因此拉低了其他品种食用油的价格。但从此以后我们的大豆失去了定价权,而由国际炒家取得了定价权。最近国际粮价大涨,所以逼得我们食用油价格不得不上涨,造成进口通货膨胀!举例而言,我国今年全年农产品供应量10,000亿斤,而需求高达10,350亿斤,其中供不应求的350亿斤要靠进口,各位读者猜一下是什么?对了,基本是大豆。

我讲出来读者觉得很简单,都听懂了。如果我不讲,读者可能怎么也想不到,这就是国际炒家的厉害,我把他的逻辑分析给读者讲的清清楚楚。比如说罗杰斯在半年前呼吁大家要买农产品衍生产品,为什么?完全因这个阴谋铺路,他讲什么,什么就要涨。这就是国际金融炒家的厉害。读者读到这里一定觉得很悲哀,你们肯定会说我们不能坐以待毙,我们要联合其他国家,我们要彻底打败国际金融炒家。读者们是不是要问这个问题,想不想要要打败国际金融炒家啊?我们意气风发地联合几个国家一起来围剿国际金融炒家好不好?

但是读者应该知道会有什么结果,那就是我们可能一起被打败,因为国际金融炒家很少失败,而且今天的战争是我们从未经历过的“金融超限战”。而要在这一场战斗中取胜,只有两个重要原则,第一你必须有最充沛的国际资本;第二必须有世界顶级金融操作高手。我把这两个前提丢给各位读者,你觉得我们具备吗?是的,我们只具备第一项充沛的国际资本,第二项具备吗?很遗憾的,中国13亿人口,包括我本人在内,都不具备。因为我只知道理论,我没有亲自操刀过。更可悲的是我们连试试的机会几乎都没有,因为一试就失败!90年代日本经济崩溃谁造成?1997年亚洲金融危机谁造成的?2008年越南经济危机谁造成的?------都是国际炒家。很无奈但又不得不面对的事实就是,国际炒家可以动用几千亿资金轻轻松松打败了各国政府。我想举个让我们痛心的例子,2007年底,美国银行(Bank of America)宣布次债危机该行遭到巨大损失,但是他们透过我国建行的上市赚取了1300亿元,也就是每一位读者都付了100元给美国银行。他们为什么能赚这么多钱呢?因为国际金融炒家取得了建行上市的“定价权”,从而压低定价图利自己。对比而言,我国主权基金购买了黑石基金遭到了巨大损失。以美国银行和我国主权基金的水平相比,证实了我国确实缺乏世界顶级金融操作高手。

总的来说,今天的通货膨胀就是一个二元经济环境和国际进口通货膨胀两个扭曲的力量勾结在一起,我请问一下,这是流动性过剩吗?!只要读懂了我这篇文章,读者就完全理解了为什么食用油、大米价格上涨,猪肉价格上涨,那就是二元经济配合上进口通货膨胀造成的。

那么怎么办呢?难道就只能坐以待毙,束手就擒了吗?我想给读者讲一个小故事。韩国总统李明博要进口美国牛肉,读者知道不知道韩国民众为什么这么激动要冲击韩国政府呢?!读者以为韩国人只是好斗吗?我告诉各位读者,韩国人比我们聪明的多得多,他们从亚洲金融危机学来太多经验那就是韩国一旦成功了进口美国牛肉以后,美国牛肉特别的便宜,他将席卷全韩国牛肉户,把全韩国养牛户淘汰,到最后,韩国牛肉价格将被国际金融炒家掌控!所以我个人认为,韩国老百姓反对政府进口牛肉是有原因,因为只有自己生产,才不会被别人所控制,就这么简单!

我们今天大米价格为什么这么低,而国际价格是我们国内价格的四倍,因为是我们自己生产的。石油价格为什么还可以扛一下,因为我们自己产油。但我们扛不久,因为造成大量的浪费,很多人因为石油便宜就胡乱开车,甚至香港的货车统统到深圳加油,这就是一个负担。我今天通过这么长的文章,把大家过去认为流动性过剩的理念彻底的打掉,流动性过剩确实是存在的,但不是股市泡沫,楼市泡沫和通货膨胀的原因。我们发现楼价上涨、股价上涨也是因为二元经济造成的,是因为投资营商环境恶化,企业家不干了,去炒楼炒股造成的,通货膨胀也是二元经济环境所造成的,过热部门的有膨胀,过冷部门生产不足也有膨胀,以大豆油为例,不但有二元经济结构的问题,还有进口通货膨胀的问题。这就是今天所处的投资营商环境。

产业链阴谋与两只秃鹰的金融超限战

前面谈到二元经济下我国制造业逐渐萧条的现实情况,我想请读者想一想,我们应该怎么办。我想换种方式玩一个游戏好不好。咱们玩什么游戏呢,大家想一想如果你是个外国人,你会怎么对付中国?假设我所讲的这一切外国人都知道,他们会怎么做?

事实上,今天的天空翱翔着两只秃鹰。这两只秃鹰看着我们中国的企业,慢慢流血而死的尸体,即将飞扑下来,把我们的尸骨啃得精光。它们在天空边翱翔,边飞边流口水。大家想一想,这两只秃鹰是谁?我给大家举个例子,你们有多少人以为青岛啤酒还是国有企业。在2008年的年中,它还是国企,青岛国资局控股百分之三十。请各位上网查一下,第二大股东是谁,它是美国安海斯布希,占百分之二十七。它只要多买百分之四的H股,就可以达到百分之三十一的控股权,突然之间,青岛啤酒就会变为外资企业。安海斯-布希公司当初是怎么进入青啤的?青岛啤酒在2001年的时候由于前任的首席执行官政策执行不当的结果,使得公司业绩大幅下滑经营面临极大困难,负债率高达89%,在这种难以为继的情况下,青岛啤酒发行了14亿元的可换股债券,卖给了安海斯-布希公司,安海斯-布希公司将可换股债券转换成27%的股份,基本上而言,安海斯-布希公司就是趁人之危进入了青啤。

安海斯-布希公司就是头上翱翔的第一只秃鹰,他叫做产业资本。产业资本对中国企业的掠夺,其可怕程度大家必须要清醒知道,而对这一点,我预警大家应该及早的注意情况的发展。

那么二只秃鹰是谁?讲讲徐工,徐工是重工业领域,美国的凯雷基金想收购徐工,当时包括我在内的许多人,提出坚决反对,我的反对理由非常坚决,那就是国有企业的好坏,不能以净资产做评估标准,一个企业的价值,不取决于净资产,而取决于这个企业的永续经营能力,因此我反对徐工出让给凯雷。而且更值得我们关切的是假设徐工以100块的价格被卖掉,凯雷基金将可能会以十倍的价格,将它分拆转卖掉,到时候他就会赚大头。或者凯雷将徐工整合进入整条产业链而获取整合的巨大收益。凯雷基金是谁,凯雷基金就是天上翱翔的第二只秃鹰,它叫做金融资本。最近凯雷基金再次说服了徐工,而正式的控股了徐工,我为之叹息。我相信凯雷给的条件非常优惠,因为无可置疑的,凯雷将从这次收购中获取巨大利益.

欧美国家通过头上两只秃鹰,进入中国,看着我们的企业逐渐流血而死的尸体,伺机飞扑下来,啃食我们的尸体。很多人可能就会有个疑问:我们企业家这么努力的工作都不能赚钱,老外凭什么能赚钱?我坦白地告诉大家,你们这句话问错了!我们不赚钱,老外也不一定能赚钱,但是我想要告诉各位读者的是:这一块钱制造业赚不赚钱不重要,你这一块钱的制造业最多赔多少钱,最多赔一块钱吧,但是整条产业链创造出十美金价值,因此制造业赔多少钱都无所谓,因为可以从6+1的6把1的亏损全部赚回来。因此对于两只秃鹰而言,它们并不是看制造业能不能创造利润,而是看能不能把制造业融入到产业链当中,这就是头上的两只秃鹰的产业链战略,而我们对此一无所知。我们还在搞招商引资,欢迎他们进来洗劫我们的企业。当头上的两只秃鹰把我们的制造业融入到整个产业链当中之后,读者们相不相信,这些制造业虽然变成了两只秃鹰的产业,但是秃鹰仍然会把制造业继续放在中国,为什么呢?因为他们要继续浪费我们的资源,破坏我们的环境,剥削我们的劳动,这就是所谓的“国际分工”。目前外资对我国企业的收购就像井喷一样,我国利用外资占GDP的比重已超过40%,外资企业占全国进出口总值的 55.48%,外资企业占高科技产品出口的87%。

法治化游戏规则的缺乏助长金融战

在这种格局之下,有一种话题也是各位读者想问我的话题:郎教授,工厂都在中国,难道你反对我们中国国际化吗?难道你反对外资进入中国吗?我当然不会反对,我是最赞成国际化的,但是我想提醒读者,我们曾经经历过的极左思维给我们国人带来了巨大灾难,但是目前内地专家学者的极右思维依然给中国带来的极大灾难。我们不要极左,也不要极右,我们需要中间路线,而达到中间路线的法则,就是透过精英政府以严刑峻法建立一套法治化游戏规则来规范政府,企业和老百姓。当然很多人对政府是否有能力做这件事提出质疑,我只能说我期望我们政府能做到。

资本主义的本质从来都是掠夺,从来没有改变过,从150年前大清王朝到今天都没有改变过,只是150年前它是以东印度公司为前导,炮舰为后盾,而今天却是以国际化为前导,金融为后盾,其掠夺的本质是不会变的。但是读者们都会提问,产业基金也好,金融资本也好,难道我们不让他们进来吗?

我们当然是有条件的欢迎他进来!不过为了讲清这个问题,我举个农民种地的例子来做解释,大家可以想象农民如何做灌溉呢。灌溉其实很简单,你把这个水闸打开之前必须得先挖沟渠,沟渠挖好之后再把水闸打开,让水顺着沟渠流到需要水的农田。可是如果你忘了挖沟渠怎么办呢?水闸一开,洪水不就漫流大地把良田都淹了吗!

哦,农民同志都知道的事我们会不知道吗?什么是洪水泛滥?那就是大欺小强欺弱,我们今天的国际化包括头上的两只秃鹰,就是打开水闸之后,忘了挖沟渠了,洪水漫流大地,把我们内资企业的良田美地都淹没了。这就是我所反对的国际化!

那么大家想一想什么是沟渠?我们绝对欢迎国际化,我们绝对欢迎产业资本,金融资本大举进入中国但是也要挖沟渠,大家知道什么是沟渠吗?那就是你一定要指定一个严刑峻法的法治化游戏规则,这个规则是要控制这个国家的所有个体包括政府包括国有企业包括百姓。如果缺乏一个严刑峻法的法治化游戏规则,而盲目的引进外资,你陡然放两只秃鹰在天空翱翔,这两只秃鹰将会像洪水一样席卷大地,把良田都淹没,因此未来的格局一定是大欺小,强欺弱。

产业资本和金融资本在这种无沟渠的环境下,他们对我们企业的掠夺简直让我们国内工厂欲哭无泪。两者相比,产业资本更可怕,他们一旦看上了我们的企业,简直可以说我们不卖都不行。举例而言,德国施奈德想要收购正泰,而正泰不想卖,结果施奈德到处控告正泰抄袭仿冒,到处打官司,我相信把正泰搞烦了,他说不定就卖了。为什么这些产业资本这么嚣张呢?因为他们所处的环境就是一个没有挖过沟渠的中国,因此可以用这种不正当的手段大欺小强欺弱。

产业链阴谋下中国企业的危机

表面上,经过20多年的高速发展,今天的中国享受着“世界工厂”的美誉。“中国制造”凭借物美价廉的优势,在世界每个角落几乎随处可见,成为当地人的生活必需品。可以说,“中国制造”已经行销全球。比如说根据研究,在工业制成品中,中国已有超过130种产品的产量位居世界第一。但实际上,中国只不过是国际产业链的分工里利润最薄的一环。事实上,在国际产业链中,中国企业做实际制造那部分如果赚到一块钱(10%)的话,那么对于外商,做这种产品设计与研发以及采购、仓储、订单处理、批发、零售这部分能赚到九块钱(90%)。换句话说,我们就是用这不到10%的价值,积累了1.8万亿美元的外汇储备,意味着我们同时为国外贡献了18万亿美元,这几乎是全国80年的工资总额!

那么什么叫做国际产业链分工呢?我们不妨以玩具业为例来看,一个芭比娃娃的前期产品设计、市场调研等均在美国完成,中国工厂只不过进行“来料加工”或“来样加工”,而后期的仓储、物流、批发、零售也是由外商来做。换言之,就是在国际产业链中真正做制造的是一块钱,我们称之为“硬一元”,而做这种采购、仓储、订单处理、批发、零售这部分的产业链叫做“软九元”。国际产业链分工背后是怎么回事呢?本质是通过“软九元”将劳动密集型的同时也是最不赚钱的部分外包给中国工厂,外商凭借其主导的产业链,靠其在订单上的优势,实际上支付给中国工厂的价钱可以远远比其自己制造还便宜。“硬一元”不是不赚钱,但问题是“硬一元”里最核心的产品设计能力外商从来不会与中国合资企业分享;与此相反,外商或者透过立体营销,全面挤压中国品牌,如果强攻不下,就透过合资、合作、收购等方式,悄悄地消灭中国的这些具备一定“硬一元”核心能力的企业和品牌。而我们地方政府非但完全不晓得这一点,反而不分好坏欢迎一切外商投资。

以玩具业为例,一个芭比娃娃我们的出厂价一块美金,在美国的沃尔玛零售价格是9.99元美金,那一块美金,原料占了0.65%,生产价0.35%,那么你晓不晓得我们能赚多少钱?几美分了不起了吧!我们不停地剥削我们的劳动者,浪费我们的资源,破坏我们的环境,却用这么贱的一块钱的价格卖到美国去,而外商最后以9.99元的价格卖给消费者,席卷了所有的利润。而在国际产业链分工下,中国代工厂事实上没法改变自己的命运。为什么呢?因为中国代工厂既不具备“硬一元”的核心能力,也不懂得掌控“软九元”。这样外商就有机会可以有意识地操控中国代工厂,挑起中国企业之间的价格战,这样让中国企业没有多余的资金积累,进而无力进行核心能力的积累和开发!这样恶性循环的结果就是中国企业永无出头之日!

换句话说,外商透过掌控全球产业链,可以轻而易举地挑起中国厂商的价格战,进而让中国制造走向恶性循环。如何挑起价格战呢?举例而言,还说玩具业,美国前三大进口商透过历史上不断的并购如今基本上垄断了市场的全部订单。假设说其中最大的美泰手中有一亿张单,那么美泰怎么主导价格战呢?第一年美泰给A厂五千万订单,给B三千万,给C两千万,给大家很好的利润,鼓励大家好好干,来年会加订单。到第二年,美泰给B四千万订单,给C三千万,只留给A三千万;这时候A肯定不敢有什么怨言,而且甚至会表示愿意压低报价,要不然还有两千万产能吃不饱呀!为什么A愿意报低价?因为代工业有个严重的问题,就是扩产容易,但扩产都是一次性固定投入,扩产之后的维护成本会逼着代工厂不敢减产,因为签单的时候外商只给一个边际的毛利率,根本不考虑你有多高的固定成本。而实际上,真正的好戏还要等到第三年,按照我们代工厂的惯性思维,B会扩产到四千万产能,C扩产到三千万,而A因为我前面指出的代工业的固有问题,还会维持五千万的产能。现在美泰可以跟三家摊牌:现在你们现在的产能总共一亿两千万,而我手中只有一亿的订单,我只需要你们中任意两家就足够了,有一家今年很可能要出局。然后引入网上同时报价的办法(这正是现在的做法),让三家在短时间内同时独立报价。结果一目了然,很有可能B和C开出的价格仅有成本价,而A甚至报出一个低于另外两家成本的价格,因为不开工就只能亏钱,而开工还能少亏一点。而且在这种分工格局下,中国代工厂只能忍气吞声,任打任骂。在这种背景下,大家就不难理解,为什么美泰将责任推向中国代工厂时,中国老板只有自杀以明志了。

更为可悲的是,在中国最擅长的制造环节,也就是产业链定位错误的环节,也正面临越来越多的问题,宏观调控的压力,汇率的上升,劳动合同法的不适当推出以及通货膨胀的压力。此外,频繁因产品质量问题引起的国际贸易纠纷,印度、越南等更低成本国家的替代竞争压力。这些问题正逐步演变成中国制造日见微薄的利润率,揭示出隐藏在中国制造产品畅销背后的实质上的全面崩盘现象。目前广东企业在这种压力之下,停工和半停工的企业几乎达到30%,而江浙两省停工和半停工的企业也达到20%。这种现象是暂时的经济周期性问题吗?如果不是的话,按照这种趋势走下去,到了年底停工和半停工的企业可能达到了50%?这会释放出超过几千万人的失业人口,再加上依靠他们生活的大约上亿人的亲属,也就是说有接近上亿人口的生活问题立刻显现出来。这些后续性的危机问题值得我们思考。

产业链阴谋下中国企业的战略出路------产业链高效整合

面对重重危机,中国企业的出路在哪里呢?我想透过一个简单例子------世界知名的服装品牌西班牙的飒拉(Zara),系统地解答这一问题。飒拉的成功简单的讲就在于整条产业链6+1的高效整合。而我国服装制造业有没有6+1的部门呢?基本上都有,但大多数分属于不同的企业,更重要的是缺乏“高效”的整合。什么叫做高效整合,简单的讲,我国服装业者走完整条6+1的流程需要180天,而飒拉走完整个流程只需要12天,也就是他们整条产业链的整合速度是我国服装业者的15倍。

这种高效整合的意义重大,因为这是节省成本最有效管道,举例而言,一件衣服库存12天的成本比库存180天的成本起码节省了90%以上的成本。而飒拉85%的生产都在欧洲,当然,由于飒拉大部分的销售都在欧洲,因此在欧洲生产可以提高速度。但是读者可能会问我,他们在欧洲生产劳动成本不是很高吗?如果读者还记得我前面谈的TCL和明基想利用中国廉价劳动力和国外品牌走出去的失败战略吗?由于劳动成本只占了整条产业链的2.5%,而这正是飒拉选择在欧洲生产的原因,因为劳动成本在整条产业链中不重要。而真正能节省成本的方式就在于产业链的高效整合,这是我所提出现代意义的成本控制新思维。

飒拉怎么做产业链的高效整合呢?我想简单谈一谈6+1的几个环节,包括仓储运输,终端零售和产品设计。首先谈谈仓储运输。飒拉为了加快运输的速度,他们在物流基地挖了200公里的地下隧道,用高压空气运输,速度奇快无比。此外,为了加快运输速度,他们用飞机而不是轮船从西班牙将成品运送到上海或香港,虽然飞机运费很高,但是高效整合更重要,成本会更低。

再谈一下终端零售。飒拉有意的减少需求量最大的中号衣服,故意弄成供不应求。因为他们发现当妇女同胞想买中号衣服而买不到的时候,他们心中那种极度的挫败感让他们下礼拜又来了。这样不但加快了周转率,同时吸引了更多的顾客。

此外,飒拉的产品设计的思维也是一绝。他们首先放弃了自主创新的思维,而代之以“市场的快速反应”。我对这点特别推崇,因为要想到放弃大家都认同的自主创新思维,就是一个最创新的思维。那么他们怎么做市场的快速反应者呢?我举个例子,为什么妇女同胞总认为衣橱里少了一件衣服,肯定是她们不知道自己到底需要什么类型的衣服,如果她们知道的话,他们就会去买了,因此衣橱就不会缺少一件衣服了。如果消费者自己都不知道自己需要什么衣服,企业搞自主创新的产品能讨好这些消费者吗?显然不行。因此,什么才是最好的策略呢?那就是做市场的快速反应者,怎么做呢?首先想一想,能卖掉的衣服肯定是消费者喜欢的衣服,假设100件衣服前天卖了12件,昨天卖了6件,今天卖了7件,他们就根据这三天卖掉衣服的共性设计衣服,根据趋势变化稍作修改,而不要创新。这样不但大幅缩减了产品设计的速度,而且可以在市场需求还没变化之前迅速推回市场抓住市场脉动。他们几天可以推回市场呢?12天,这么短的时间当然可以抓住市场脉动。但是12天的速度就是产业链高效整合的结果,如果我们的速度是180天的话就根本不可能当市场的快速反应者。

我想总结一下我的观点,飒拉透过产业链的高效整合大幅压缩成本,而同时透过高效整合作市场的快速反应者,因此他们的衣服总是最新潮,最受市场喜爱,虽然品质不一定很好,但是这年头谁还穿一辈子同样的衣服呢?因此品质没那么重要了。飒拉的产业链高效整合思维应该对我们的企业非常有启发,因为这才是我们企业的未来战略出路。

政府产业政策的思维转换

由于我们已经进入了前所未有的产业链战争的新时代,因此政府推动的产业政策就格外的重要。过去我们犯了很多错误,例如市场换技术,结果市场丢了,技术也没换来。这两年很多地方政府呼吁企业搞产业升级和品牌战略,我认为这又是一个误区。所谓的产业升级,不应该仍然在6+1的1上面搞升级,而应该从1升级到6的环节。此外,以飒拉为例,品牌的建立是产业链高效整合后的必然结果而不是企业成功的原因,因此我们不能倒果为因。政策的转变必然牵扯到思维转变的先行,我期望政府,企业,都能发挥思维的创新,进一步的理解这篇文章的观点,才能真正地走出低谷。

结语

最后,我很痛心地告诉读者,2007年我写的“中国经济的八大危机”文章刚刚发表的时候,全国正洋溢着股市楼市的欢乐气氛,甚至有人认为我唱衰中国经济,而对于那些粉饰太平的专家学者反而给与了更多地关注。这个时刻我想起了屈原所著“离骚”的一段话--------“黄钟毁弃,瓦釜雷鸣”,夫复何言啊。2008年年初南方人物周刊对我做了这个评论“如果郎咸平是对的,其他人都错,那中央从紧的货币政策,非但是下错了药,还是个雪上加霜,落井下石的毒药”。但是今天我对于众人皆醉我独醒的胜利没有丝毫的喜悦,因为我们老百姓并没有因为我的八大危机文章而改善了生活,反而陷入更艰难的生计。我这次发表的文章希望能够在八大危机的基础上,唤醒政府,企业和百姓的共识,共同为着中国的未来,走一条正确的路。最后,我想沉重的提醒这个社会,专家学者粉饰太平的言论虽然能够取悦政府,但今年却让政府和全社会付出沉重的代价。(郎咸平)

 

posted @ 2008-07-30 23:44 CowNew开源团队 阅读(317) | 评论 (0)编辑 收藏

赚钱才是硬道理

据内部人士透露,金山软件(3888.HK,下称“金山”)计划把WPS、词霸等非营利业务从上市公司中剥离出去,单独成立新公司,目前该计划已基本敲定,有望在年底宣布.
据内部可靠消息称,金山内部讨论把非盈利业务剥离的想法由来已久,思路已定,相关工作在今年年底能完成.其此番调整的基本思路是:把词霸、 WPS这些不盈利的业务剥离出去,单独成立新公司,与网游、毒霸这些主营业务分开.相关人士称,这样做的目的不是为了剥离不良资产,而是公司核心战略调整的一环.

根据金山的布局,网游是一块“赚现钱”的业务,软件主要是投资未来的业务.所以,公司管理层希望把需要长期投资且不盈利的业务剥离开,一来有利于长期布局,二者也能给上市公司减轻负担.

  根据公开数据显示,网游业务占金山总收入约70%,毒霸业务约25%,其他业务收入总和仅5%.据了解,这部分业务虽也投入很多资源和人力,但发展效果并不明显.

  金山由求伯君于1988年创办,并于2007年10月9日在香港主板上市.该公司以办公软件业务起家,目前主要涉及软件和网游两大核心业务,旗下还拥有英语学习社区爱词霸网以及大型在线游戏交流社区逍遥网.其中,软件业务主要包括WPS软件、词霸、毒霸等主要产品线.

  另据《第一财经日报》于2007年12月刊载的报道,金山当时进行了一次架构调整,拟将毒霸和网游作为未来发展的重点业务,以提升公司整体赢利水平,并策略性地弱化WPS及词霸等几乎不赢利的通用软件业务.

  显然,金山此次剥离非盈利业务并成立新公司的计划酝酿已久.不过,目前金山新公司的名字并未曝光.昨日下午,金山软件业务相关负责人表示不予评论.

posted @ 2008-07-30 09:42 CowNew开源团队 阅读(283) | 评论 (0)编辑 收藏

计算机专业学习交流问题专用帖
提问请回帖
posted @ 2008-07-29 23:49 CowNew开源团队 阅读(478) | 评论 (3)编辑 收藏

刚看到netbeans成了2008年计算机等级考试java上机考试的IDE,看来SUN没少运作,从娃娃抓起呀 。
C语言的IDE由TC终于升级到VC6了,微软偷偷笑“就是让这帮孩子认为C就是微软家的,C就是VC”,呵呵。
看来这就是传说中的商业化运作。
posted @ 2008-07-28 22:58 CowNew开源团队 阅读(292) | 评论 (0)编辑 收藏

自1999年以来,我国高校开始大规模地扩招。作为热门专业之一的计算机专业,更是走在各专业学生数量扩张规模的前列。

       大多数中国高校计算机专业目前的培养体系,大都于二十世纪八十年代建立并完善起来的,面对着21世纪计算机技术日新月异的进步和中国经济和社会状况的变化,这一教学体系面临着巨大的冲击,弊端开始显露。
       引发问题的关键之处在于:教学主体(指在校学生)整体状况的变化。

一、我国高校计算机本科教育的现状分析
      
       目前在校的计算机本科生中,其主体是被称为“80后”的年轻一代,独生子女占绝对多数。这一代的大学生,伴随着中国经济的快速发展而成长,家庭经济条件的改善使他们比以前的大学生拥有更好的学习环境,从小接触到更多的信息,受到更多的正规教育,而且思想活跃,接受与学习能力强。

       然而,这一代的大学生也有自己的问题。由于许多学生从小在比较富足的环境中成长,又是独生子女,从小受到父母长辈过度的呵护,生活一帆风顺,走的都是父母和老师事先安排好的道路,加上社会风气的影响,带来了一些问题,比如依赖性强、自制力弱、缺乏吃苦耐劳的精神……。

       学生主体状况的改变,会直接影响教学方法与方式的选择。

       根据北京理工大学计算机学院2006年对2004级本科生所作的不计名问卷调查结果,发现许多学生都出现了对计算机专业缺乏兴趣的状况,有的学生打算毕业时转行,有的表达出对未来的迷茫与对激烈就业竞争的忧虑。有不少学生抱怨:我都到了计算机专业3年级了,还不会写程序……

       事实上,据笔者了解的情况,不止北京理工大学,其他高校计算机专业的学生情况也大致相同,这种状况具有相当的普遍性。

       我国高校采用的是通过全国统一进行的高考选拔学生的体制,为了让孩子能考上一所理想的大学,家长为此是“不惜花费一切代价”也要让孩子的成绩好。在这种需求的强劲推动下,中国普遍形成了从小学到高中的应试教育,将对学生其他素质的培养放到了次要的地位。学生在这种强制性的潮流面前,没有任何的自主权,只能被“押着”上了高考的“战车”,其心中的反抗心理是不难想象的。

       从小学到高中,家长和老师几乎为学生“包办”一切,甚至包括为他们选择所读的专业。笔者是2004级学生的班主任,在新生入学时做过调查,全班28个学生,只有不到三分之一的学生回答他们选择计算机专业是出于“喜欢计算机”。事实上,说喜欢计算机的学生中,大部分只是喜欢互联网,喜欢游戏,觉得计算机“好玩”,是个热门专业,就业后收入高,……,真正了解计算机专业内涵的学生是少之又少。可以这样说,大多数学生的专业选择是盲目的,许多学生在入校时对计算机专业的认识是“一张白纸”。这就为日后出现的问题打下了伏笔。

       我国许多高校计算机系课程教学体系是在扩招之前形成的,近年来虽有所调整,但总体框架并未变化。从各门专业课程的设置来看,大都要求对学生要有扎实的理论基础,强调培养学生自主学习与探索的能力,这是一种以培养计算机科学的研究者为目标的“精英教育”。应该说,在扩招之前,这种体制的确培养出了许多人才。

       然而扩招之后各方面情况都发生了变化。最明显的就是由于学生规模的迅速扩大,师资力量严重不足,原来可以比较密切的师生交流现在难以为继,出现了动辄上百人的大课,使教学效果大打折扣。

       为了快速地补充师资,各高校大量将计算机专业硕士和博士毕业生直接补充到教师队伍中来,教师的平均学历指数虽然上升了,但总体平均的水平并未随之有相应的提高。反过来则有下降的趋势。新进的教师中大多从学校到学校,很少或没有业界经验,因而在教学中也只能从“理论”到“理论”,难于做到理论与实践相结合。学生是一张白纸,教师是“纸上谈兵”,其结果是计算机专业开设的理论课打掉了多数学生的兴趣。

       计算机科学与数学等传统的学科不太一样,其实践性非常强,许多重大的计算机理论与技术创新都有一定的应用背景,是由实践推动发展的。

       目前的计算机专业教学过于偏重理论基础的培养,在培养学生实践能力上显得比较弱,结果实践能力的匮乏严重打击学生的自信心,当他们想到毕业后所面临激烈的就业竞争时,其忧虑甚至恐惧的心理是可以想见的。由于大多数学生过去的生活一帆风顺,缺乏足够的人生经历,挫折承受能力不强,面对挑战,有些学生就采取了逃避的态度,于是高校中“网络游戏”成为不可治的顽症,毁掉了许多学生的学业。

       人类已进入信息时代,IT业是发展最迅猛的行业之一,快速发展的整个行业对人才提出了迫切的要求,几乎所有的IT企业都“求才若渴”,在招聘上投入巨大的人力和财力,却痛感要找到一个合乎企业要求的人才是如此地困难。另一方面,每年又有大批的毕业生找不到合适的工作,据报道,2006年全国有124万大学毕业生无法当期就业,在大学生占总人口比例仍非常低的中国,在经济快速成长制造出大量就业机会的时代,在发展迅速对人才需求量很大的IT业,计算机专业大学生就业难居然成为了一个问题。

       大学应服务于社会,应为国家富强与社会进步提供巨大的推动作用,然而,现状表明:我国各高校计算机及相关专业作为当前最大的为IT业提供人才储备的大本营,其教育成效并不能满足社会对人才可渴求。

二、高校计算机本科教育改革的突破口

       我国高校计算机本科教育面临的一个带有全局性的问题是:大学计算机教育是要培养计算机行业高级技术管理人才和科学研究者,还是要培养出大批合格的软件工程师?

       这本质上是大学教育的本质性问题:大学教育是精英教育还是大众教育?

       在高等教育发达的美国,象耶鲁等世界一流名校,其策略是非常明确的:四年本科阶段给本科生提供大量的选修课,培养其基本素质,增加其对社会的适应力,以培养通才为主要目的,到硕士阶段进入才进入与特定行业密切相关的职业训练阶段,博士阶段的培养目标是科学研究者。

       耶鲁这样的大学,很明显是一种“精英”教育。但美国数千所高校中,除了哈佛、耶鲁等名校之外,还有大量的社区大学,在数量上占绝对多数,它们完成的却是“大众教育”的工作。

       美国高等教育的成功经验,对我们有很大的借鉴作用。但中美之间有着巨大的历史、文化和社会背景差异,不能简单地将美国的体制全盘照搬到中国。

       笔者认为,目前我国大学计算机本科教育的主体是—大批入学时对计算机专业知之甚少的学生,因此应实事求是,走“大众教育”这条路,以培养业界合格的工程师为主要目标,满足业界对人才的迫切需求。在此基础之上,给少数优秀的学生以较大的自由发展空间。

       根据我们的调查,经过两年左右的大学学习,真正喜欢上计算机不足学生总数的10%,大多数学生的状况都是“不能说讨厌,但也不是喜欢”,居于一种茫然的状态。笔者与许多成绩不理想学生进行沟通,发现他们之所以不喜欢计算机,多由于所学理论课程枯燥无味、脱离实际而导致。在现有教育体制之下,这些学生几乎不可能有机会转换专业,他既不喜欢所学的课程,但又不得不学习,教学效果差就可想而知了。

       那么这些认为不喜欢计算机专业的学生中的相当部分,是不是真的无法成为一名合格甚至优秀的软件工程师?

       解决问题的关键在于我们的教学体系能否帮助学生培养出对计算机专业的兴趣。

       根据教育心理学的相关理论,兴趣是最好的老师,有了强烈的兴趣,学生就会主动地去学习,在兴趣面前,各种枯燥的理论也都呈现出另一种面貌。

       培养学生兴趣就是实践。事实证明,学生通过实践对计算机技术产生兴趣是非常普遍的现象。

       目前,大学生中沉迷于网络游戏的现象日益引起教育界的重视,仔细分析一下游戏设计者的思路,可以对我们大学计算机教育如何引发学生的兴趣有着很大的借鉴作用。

       我们来分析一下网络游戏的一些特点。

      (1)游戏通常有许多关卡,开头的关卡很简单,过关很容易,以后每一关都比前一关难,每一关都比前一关更有挑战性,正是这种由于游戏的这种持续性与挑战性,玩家在整个玩游戏的过程中其潜在的争强好胜的天性被激发,他们通过不断完成日益困难的任务,获得了很大的成就感,这正是许多学生沉迷游戏的原因之一。
      
     (2)另一方面,人是需要朋友的,而许多网络游戏就提供了这样的一个场景:同玩一个游戏的玩家在一个虚拟的环境中相互合作,满足了人的情感需求。
     
     网络游戏的设计方法,给我们设计计算机专业的实践环节提供了很好的思路:
   
     注重持续性,由浅入深,组建团队协作的学习与实践环境。

      在整个实践环节中,教师起着一个关键的引导作用。
     1940年代,清华大学校长梅贻琦在《大学一解》一文中提出了“大鱼带小鱼”的教学理念:

    古者学子从师受业,谓之从游。孟子曰:“游于圣人之门者难为言”,间尝思之,游之时义大矣哉。学校犹水也,师生犹鱼也,其行动犹游泳也,大鱼前导,小鱼尾随,是从游也,从游既久,其濡染观摩之效,自不求而至,不为而成。

       学校是江河湖海,老师是大鱼,学生是小鱼,小鱼跟着大鱼游,小鱼在游的过程中也成了大鱼。
      
       在计算机教育而言,游就是实践。实践包括科研实践与开发实践。对于计算机本科生教育而言,应以开发实践为主。

       这里面有一个问题,那就是理论课学习与开发实践的关系问题,处理得不好,会顾此失彼。

       笔者认为:理论与实践是相辅相成的,对于绝大多数学生而言,只有在实践中才能真正地理解与掌握理论。

       比如比较抽象的《数据结构》课程,许多学生学完了之后并不知道里面介绍的树、图、堆栈等概念有什么作用,而让学生去亲自设计并开发一个真实的四则运算器程序之后,学生不仅巩固了原先学过的C++、Java等编程语言,也熟悉了业界流行的开发工具如Visual Studio和Eclipse等的使用方法,还弄明白了数据结构到底有什么用……,一举数得,这就是“实践促进理论学习”的例子。

       笔者将计算机本科教育中的理论与实践的关系总结为“珍珠与项链”关系:

    可以把计算机专业开设的《编译原理》、《操作系统》等理论课比喻为一颗颗的珍珠,而实践就是那根将珍珠串成项链的丝线。一串项链的价值,大于单个珍珠价值总和。

       因此,高校计算机本科教育改革的突破口就是实践。

三、高校计算机教育实践环节的实施建议

       一个重要的改革方向是压缩必修课的数量。现在的普遍情况是大学二三年级安排的必修课太多,而且许多课程在教学方式上并未摆脱高中教学那种满堂灌的方式,加上大量的闭卷考试,这实际上是鼓励学生为追求高分而死记硬背,无利于学生培养出真正的能力,应减少专业课的闭卷考试,而采用课程设计、上机考试、撰写论文、课堂讨论等多种方式,增大开放式课程考核的比重。然而,采用开放式课程考核方式也有一些问题,比如抄袭问题在目前的学生规模之下难以避免,另一个出现的问题是评分主观性强,尺度难于把握。一般来说,对于实际开发能力比较出色的学生,他们是欢迎采用开放的考核方式的,其余的学生则更希望采用传统的考试方式。为此,可以尝试采取一种“一课两制”的教学方案,即一部分学生采用传统的卷面考试方式,而另一部分学生则采用开放式的课程设计方式,由学生自由选择。

       另一方面,计算机科学涉及相当广阔的领域,每个学生的情况千差万别,在课程安排上不能软件硬件课程一起上,眉毛胡子一把抓,这不仅会加重学生的负担,而且在短时间内安排多门难度较高、抽象复杂的专业课(比如三年级学生一个学期要学七八门计算机专业课程,绝大部分采用闭卷考试),学生很难在这么短的时间内理解并掌握大量的知识,其结果是学生没有足够的时间通过实践去逐步地消化这些知识,将这些课程煮成了“夹生饭”。笔者认为应根据计算机学科的内在发展规律提供大量的选修课供学生自主选择,学校和教师为学生选课提供足够的指导与帮助。在这点上,国内许多大学都先后实施了本科生的全面选课制,为本科教育改革走出了重要的一步。

       人们在长期的教育实践中发现,学生对于具体的知识易于掌握,而要掌握抽象程度较高的知识必须付出更多的努力。因此,在教学内容安排上就遵循从简单具体再到抽象复杂的认知规律。

       那么,应如何安排实践环节,让实践渗透到计算机专业四年本科的教学体系中?

       这是一个复杂的问题,需要许多教师与教育专家的共同探索。

       就笔者看来,可以采用以下的模式:

       在计算机专业的一年级,学生处于从高中到大学的过渡阶段,实践的内容主要是“用”,即让学生使用现成的各种软件工具培养兴趣,并和他们正在学习的理论课程结合起来。比如计算机专业一年级学生通常都需学数学(高等数学、线性代数等),这时可以同步开展学用数学工具软件(比如MathLab)的教学实践。又比如,C语言是许多学生第一门学习的高级语言,这时可以同步安排LINUX操作系统的实践活动,让学生试着在LINUX这种C语言最适合的“原生环境”中编程,直接拉近学生与现代软件开发技术前沿的距离,并为以后学习《操作系统》等专业课程打下良好基础。

       笔者认为,应该在计算机专业低年级(大一或大二),让每个学生都掌握一个主流的开发工具和语言,在目前而言,Java和C#是两个很好的选择。通过在低年级开设Java/Eclipse或C#/Visual Studio等选修课,可以让学生直接接触到当前主流的软件开发(或硬件设计)技术,不让其与当今计算机技术的发展脱节,同时更重要的,是让学生培养出基本的开发能力,为他们在高年级(大三大四)接触到更抽象复杂的课程(比如《数据结构》、《编译原理》、《软件工程》、《面向对象分析与设计》、《数据库原理》等)时,让给理论有一个落脚点,就不会出现“纸上谈兵”,“空对空导弹”的问题。

       除了在课程安排上要注重突出实践,另一个也很有效的教学环节就是促进团体学习环境的形成,可以尝试组建学生科技活动中心、创新基地、各种专业兴趣小组等,一旦形成了一个良好的学习与实践氛围,于正常的课程教学之外,这些组织对学生能力的增长帮助尤大。

       在创建团队学习与实践环境的过程中,要特别注意发挥教师的引导作用。可以采用从我国古代历史悠久的书院体制,形成密切的师生关系,以“师傅带徒弟”的方式培养精英人才,非常有效。

       总之,在当前我国经济快速增长,各方面都在发生巨大变化的时代,高等学校的计算机专业教育必须进行必要的变革,不进行这种变革,就无法满足社会对人才的渴求,不管对国家还是对学生个体,都是一种巨大的人力资源浪费。而在这一变革中,大力加强实践环节在整个计算机教学体系中的地位,将是一个重要的手段。

from:http://www.5xue.com/modules/bbs/viewthread.php?tid=114897&extra=page%3D30
posted @ 2008-07-28 22:45 CowNew开源团队 阅读(237) | 评论 (0)编辑 收藏

欢迎加入高校计算机专业学习指导交流QQ群,业界资深IT工程师提供指导,在这里你可以聊自己的学习、工作、生活、就业等话题,也可以向专家提出问题,更可以与优秀的计算机专业同学交流。
现在计算机专业就业情况如何?
您不知道如何安排自己大学四年的学习生活吗?
大学里这么多专业课程有用吗?应该怎么学?
找工作的时候应该注意哪些问题?
学习专业课程的时候遇到的问题应该找谁请教?
………………
加入我们的群吧,这些问题都能够帮您解决!
本群偏向于软件开发方向;本群原则上只限于计算机专业在校大学生加入,对计算机有强烈兴趣其他专业学生也可以加入,谢绝已经参加工作的人员(本群特邀专家除外)。加入时请写明自己的大学、专业以及入学年份,比如“清华大学计算机2006”,进入群后修改自己的群备注为自己的个人介绍(包括但不限于“大学、专业以及入学年份”)
QQ群号:29449019
posted @ 2008-07-26 23:04 CowNew开源团队 阅读(1206) | 评论 (2)编辑 收藏

http://211.99.196.18:6666/cownewdemo

posted @ 2008-07-20 20:18 CowNew开源团队 阅读(360) | 评论 (0)编辑 收藏

有同事竟然找LOWORD、HIWORD在C#中的替代函数搞了一个上午 。看来真是被拿来主义给惯坏了,自己写一分钟就能写出来
        /// <summary>
        /// 取低位
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public static int LOWORD(int i)
        {
            return i & 0xFFFF;
        }

        /// <summary>
        /// 取高位
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public static int HIWORD(int i)
        {
            return i >> 16;
        }

posted @ 2008-07-03 14:22 CowNew开源团队 阅读(543) | 评论 (0)编辑 收藏

历经半年时间,《antlr 2.7.5 中文文档》正式版终于发布!

感谢欧进利、周晓、曲金龙、west2snow、阿乐、杨中科等队友卓有成效的工作。特别是欧进利挤出个人时间为文档的最后的合稿与校对做了大量的工作。
未经Antlr.orgCowNew开源团队许可,请勿将此文档用做商业用途!

点击下载:
http://www.blogjava.net/Files/huanzhugege/antlr_2_7_5_中文文档.rar
posted @ 2008-06-30 22:11 CowNew开源团队 阅读(2857) | 评论 (11)编辑 收藏

SWT中调用Automation的方式 这篇文章中我们介绍了SWT中通过Automation访问IE的方式,但是只是简单的URL导航,没有自动填表单、自动提交等功能。我们对其进行了升级,采用了新的操作方式,充分利用了SWT对OLE的支持,裁减掉大量代码。现在可以实现自动填表单、自动提交等功能。不过暂时还无法响应IE的事件。
核心代码如下:

package test;

import org.eclipse.swt.SWTException;
import org.eclipse.swt.internal.ole.win32.COM;
import org.eclipse.swt.internal.ole.win32.GUID;
import org.eclipse.swt.internal.ole.win32.IUnknown;
import org.eclipse.swt.ole.win32.OLE;
import org.eclipse.swt.ole.win32.OleClientSite;
import org.eclipse.swt.widgets.Composite;

/**
 *
 * @author 杨中科
 *
 */
public class AutomationClientSite extends OleClientSite
{
 public AutomationClientSite(Composite parent, int style, String progId)
 {
  super(parent, style);
  try
  {
   appClsid = getClassID(progId);
   if (appClsid == null)
    OLE.error(OLE.ERROR_INVALID_CLASSID);

   //使用CoCreateInstance创建一个进程外Automation服务器
   int[] address = new int[1];
   int result = COM.CoCreateInstance(getClassID(progId), 0,
     COM.CLSCTX_INPROC_SERVER | COM.CLSCTX_LOCAL_SERVER,
     COM.IIDIUnknown, address);
   if (result != COM.S_OK)
    OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);

   objIUnknown = new IUnknown(address[0]);

  } catch (SWTException e)
  {
   dispose();
   disposeCOMInterfaces();
   throw e;
  }
 }

 protected GUID getClassID(String progId)
 {
  GUID guid = new GUID();
  // create a null terminated array of char
  char[] buffer = null;
  if (progId != null)
  {
   int count = progId.length();
   buffer = new char[count + 1];
   progId.getChars(0, count, buffer, 0);
  }
  if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK)
  {
   int result = COM.CLSIDFromString(buffer, guid);
   if (result != COM.S_OK)
    OLE.error(result);
  }
  return guid;
 }

}
public class OleUtils
{
 public static int getIdOfName(OleAutomation auto, String name)
 {
  int[] ret = auto.getIDsOfNames(new String[]{name});
  return ret[0];
 }
 
 public static void setProperty(OleAutomation auto, String name,Variant value)
 {
  int id = getIdOfName(auto, name);
  auto.setProperty(id, new Variant[]{value});
 }
 
 public static Variant getProperty(OleAutomation auto, String name)
 {
  int id = getIdOfName(auto, name);
  return auto.getProperty(id);
 }
 
 public static Variant invoke(OleAutomation auto, String name)
 {
  return invoke(auto,name,new Variant[0]);
 }
 
 public static Variant invoke(OleAutomation auto, String name,Variant... params)
 {
  int id = getIdOfName(auto, name);
  return auto.invoke(id,params);
 }
}



package test;

import org.eclipse.swt.ole.win32.OleAutomation;
import org.eclipse.swt.ole.win32.Variant;

/**
 *
 * @author 杨中科
 *
 */
public class HtmlElement
{
 private OleAutomation auto;

 public HtmlElement(OleAutomation auto)
 {
  this.auto = auto;
 }

 protected OleAutomation getOleAutomation()
 {
  return auto;
 }

 public void setProperty(String name, Variant value)
 {
  OleUtils.setProperty(auto, name, value);
 }

 public Variant getPropertyAsVariant(String name)
 {
  Variant value = OleUtils.getProperty(auto, name);
  return value;
 }

 public void setProperty(String name, int value)
 {
  OleUtils.setProperty(auto, name, new Variant(value));
 }

 public int getPropertyAsInt(String name)
 {
  Variant value = OleUtils.getProperty(auto, name);
  return value.getInt();
 }

 public void setProperty(String name, boolean value)
 {
  OleUtils.setProperty(auto, name, new Variant(value));
 }

 public boolean getPropertyAsBool(String name)
 {
  Variant value = OleUtils.getProperty(auto, name);
  return value.getBoolean();
 }

 public void setProperty(String name, String value)
 {
  OleUtils.setProperty(auto, name, new Variant(value));
 }

 public String getPropertyAsString(String name)
 {
  Variant value = OleUtils.getProperty(auto, name);
  return value.getString();
 }

 public HtmlElement getPropertyAsHtmlElement(String name)
 {
  Variant value = OleUtils.getProperty(auto, name);
  return new HtmlElement(value.getAutomation());
 }

 public Variant invoke(String name,Variant... params)
 {
  return OleUtils.invoke(auto, name,params);
 }

 public int invoke_Int(String name,Variant... params)
 {
  return invoke(name,params).getInt();
 }

 public boolean invoke_Bool(String name,Variant... params)
 {
  return invoke(name,params).getBoolean();
 }

 public String invoke_String(String name,Variant... params)
 {
  return invoke(name,params).getString();
 }

 public HtmlElement invoke_HtmlElement(String name,Variant... params)
 {
  return new HtmlElement(invoke(name,params).getAutomation());
 }
}




package test;

import org.eclipse.swt.ole.win32.OleAutomation;
import org.eclipse.swt.ole.win32.OleClientSite;
import org.eclipse.swt.ole.win32.Variant;

/**
 * 更多方法参考MSDN“InternetExplorer Object”文档
 *
 * @author 杨中科
 *
 */
public class IEAutomation extends HtmlElement
{

 public IEAutomation(OleClientSite clientSite)
 {
  super(new OleAutomation(clientSite));
 }

 public void setVisible(boolean value)
 {
  setProperty("Visible", value);
 }

 public boolean isVisible()
 {
  return getPropertyAsBool("Visible");
 }

 public void setMenuBar(boolean value)
 {
  setProperty("MenuBar", value);
 }

 public boolean isMenuBar()
 {
  return getPropertyAsBool("MenuBar");
 }

 public void setStatusBar(boolean value)
 {
  setProperty("StatusBar", value);
 }

 public boolean isStatusBar()
 {
  return getPropertyAsBool("StatusBar");
 }
 
 public void setToolBar(boolean value)
 {
  setProperty("ToolBar", value);
 }

 public boolean isToolBar()
 {
  return getPropertyAsBool("ToolBar");
 }
 
 public int getHWND()
 {
  return getPropertyAsInt("HWND");
 }
 
 public String getReadyState()
 {
  return getPropertyAsString("ReadyState");
 }
 
 public String getLocationURL()
 {
  return getPropertyAsString("LocationURL");
 }
 
 public boolean getBusy()
 {
  return getPropertyAsBool("Busy");
 }

 public void navigate(String url)
 {
  invoke("Navigate", new Variant(url));
 }

 public HtmlElement getDocument()
 {
  return getPropertyAsHtmlElement("Document");
 }

 public String getInnerHtml()
 {
  HtmlElement document = getPropertyAsHtmlElement("Document");
  HtmlElement body = document.getPropertyAsHtmlElement("body");
  return body.getPropertyAsString("innerHtml");
 }

 public HtmlElement getElementById(String id)
 {
  HtmlElement document = getDocument();
  return document.invoke_HtmlElement("getElementById", new Variant(id));
 }

 public void quit()
 {
  invoke("Quit");
 }
}




使用范例:

 protected void 自动填表()
 {
  //"kw"为关键字输入框
  HtmlElement txtKW = ie.getElementById("kw");
  //自动填表
  txtKW.setProperty("value", "杨中科");
  HtmlElement btnSB = ie.getElementById("sb");
  //自动点击【百度一下】按钮自动提交查询
  btnSB.invoke("click");
 }
 private void automation() throws Exception
 {
  OleFrame frame = new OleFrame(composite, SWT.NONE);
  AutomationClientSite client =
   new AutomationClientSite(frame,SWT.NONE,"InternetExplorer.Application");   
 
  ie = new IEAutomation(client);
  ie.setVisible(true);
  ie.setMenuBar(false);
  ie.setToolBar(false);
  ie.setStatusBar(false);
  
  int hwnd = ie.getHWND();
  OS.SetParent(hwnd, composite.handle);
  // 窗口最大化
  OS.SendMessage(hwnd, OS.WM_SYSCOMMAND, OS.SC_MAXIMIZE, 0);
  OS.SendMessage(hwnd, OS.WM_ACTIVATE, 0, 0);
  
  ie.navigate("http://www.baidu.com");
  //等待加载完毕,正确的方式应该是在网页onComplete的时候继续执行,但是没弄明白OLE 的EventSink机制怎么搞到SWT中来
  //所以先凑合着Sleep循环检测getBusy()的值,当不busy的时候再进行后续处理
  while(ie.getBusy())
  {
   Thread.sleep(10);
  }
  msgBox(ie.getInnerHtml());
  //"sb"为【百度一下】这个按钮的id
  HtmlElement btnSB = ie.getElementById("sb");
  //取value属性
  String txt = btnSB.getPropertyAsString("value");
  msgBox("按钮上的文字:"+txt);
  msgBox("网址:"+ie.getLocationURL());
  
  composite.addDisposeListener(new DisposeListener() {
   public void widgetDisposed(DisposeEvent e)
   {
    //必须手动指定退出,否则会报异常
    ie.quit();
   }
  });
 }

posted @ 2008-06-30 21:08 CowNew开源团队 阅读(1406) | 评论 (2)编辑 收藏

时间:2008年7月5日下午13:30到17:30
  活动地点:北京清华大学(清华东门Fit楼)
  特邀咨询师: EasyJF开源团队 大峡

  活动参加对象:vifir.com的vip用户;
  参加费用:VIP免费;

  主办单:开源人网站(www.vifir.com)
  承办单位:成都蓝源信息技术有限公司 EasyJF开源团队 Cownew开源团队
  
  活动内容:
  采用开展专题讲座、问题答疑等形式,在网下开展面对面的关于前沿富客户端技术的应用及经验交流活动,主要以Ext技术的学习及应用经验交流为主。还将会根据vifir推出的一些ext应用示例,进行比较深入的分析及探讨。

  活动联系人:静水 (QQ: 970426526) 联系电话:028-86272612
  电子邮箱:970426526 at qq.com

posted @ 2008-06-30 21:01 CowNew开源团队 阅读(268) | 评论 (0)编辑 收藏

     摘要: 在SWT中提供了访问OLE的方式,不过相关的例子都是进程内OLE的例子,比如嵌入浏览器、引用ActiveX控件什么的。由于客户的需求,我们需要在程序中通过进程外Automation服务的方式访问IE浏览器。经过网上搜寻,找到一个朋友写的CComObject类可以访问Automation服务。不过经过使用发现一些错误,因此对其进行了修改,为了方便访问IE,我又封装了一个IEAutomation类,这...  阅读全文
posted @ 2008-06-23 17:04 CowNew开源团队 阅读(2258) | 评论 (1)编辑 收藏

     摘要: 《专家手记AJAX开发实战》电子版下载地址:http://www.blogjava.net/Files/huanzhugege/《专家手记AJAX开发实战》电子版.rar
  阅读全文
posted @ 2008-06-22 18:19 CowNew开源团队 阅读(2358) | 评论 (5)编辑 收藏

    在开发系统的时候经常需要嵌入外部的程序,比如将企业原有的系统集成到我们的系统中,而且要求看起来像和我们的程序一样嵌入到我们的系统中,这时就要借助于Win32了。在以前使用VC、Delphi、C#开发的使用的时候可以直接调用Win32的API来操作,好在SWT中提供了Win32API的封装,而且封装的比较好,大部分都在org.eclipse.swt.internal.win32.OS这个类中。核心原理就是调用SetParent这个API将我们的程序中的某个控件设置为被嵌套程序的父窗口。具体原理可以参考我以前写的《WPF中嵌入普通Win32程序的方法 》(http://www.blogjava.net/huanzhugege/archive/2008/04/24/195516.html)。
主要代码如下:
 private void executeProg(String fileName) throws Exception
 {
  int hHeap = OS.GetProcessHeap ();
  TCHAR buffer = new TCHAR (0, fileName, true);
  int byteCount = buffer.length () * TCHAR.sizeof;
  int lpFile = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
  OS.MoveMemory (lpFile, buffer, byteCount);
  SHELLEXECUTEINFO info = new SHELLEXECUTEINFO ();
  info.cbSize = SHELLEXECUTEINFO.sizeof;
  info.lpFile = lpFile;
  //隐藏启动
  info.nShow = OS.SW_HIDE;
  boolean result = OS.ShellExecuteEx (info);
  if (lpFile != 0) OS.HeapFree (hHeap, 0, lpFile);
  if(result==false)
   throw new Exception("启动失败!");
 }
 
 protected void startNotePad() throws Exception {
  //"notepad.exe"为待启动的程序名
  executeProg("notepad.exe");
  
  //等待NotePad.exe启动并且初始化完毕,需要根据实际情况调整sleep的时间
  Thread.sleep(1000);  
  
  //"Notepad"为被嵌套程序窗口的ClassName(Win32级别),可以使用Spy++等工具查看
  int notepadHwnd = OS.FindWindow(new TCHAR(0,"Notepad",true),null);
  
  //&~WS_BORDER去掉内嵌程序边框,这样看起来更像一个内嵌的程序。如果需要显示边框,则将这两行代码删除
  int oldStyle = OS.GetWindowLong(notepadHwnd, OS.GWL_STYLE);       
        OS.SetWindowLong(notepadHwnd, OS.GWL_STYLE, oldStyle&~OS.WS_BORDER);
       
        //composite为承载被启动程序的控件
  OS.SetParent(notepadHwnd, composite.handle);  
  //窗口最大化
  OS.SendMessage(notepadHwnd, OS.WM_SYSCOMMAND, OS.SC_MAXIMIZE, 0);
 }

全部代码在此下载:http://www.blogjava.net/Files/huanzhugege/swtwin32.zip
posted @ 2008-06-05 10:49 CowNew开源团队 阅读(3748) | 评论 (2)编辑 收藏

由CowNew开源团队的侯志松(网名:芽孢)编写的《Hibernate完全手册》已经由机械工业出版社出版。
        本书从应用程序开发的角度出发,在介绍关系数据库系统知识和面向对象方法的基础上,全面介绍对象关系映射领域的工业标准――Hibernate的基本功能、体系架构、使用方法及高级特性。全书以对象关系映射为主线,分成3个模块:第1~6章介绍对象持久化的基础以及Hibernate的基本配置和使用方法;第7~11章详细介绍如何使用Hibernate实现对象关系的映射,并讨论了使用面向对象方式查询数据的方法和技巧;第12~16章分析了Hibernate中事务、并发、缓存等高级特性,并讨论了如何整合Hibernate和成熟技术,构建企业级应用程序开发框架的技术实践。
posted @ 2008-06-04 10:16 CowNew开源团队 阅读(445) | 评论 (0)编辑 收藏

随着Web开发的不断进步,AJAX以一种新的面貌出现在了我们面前,并且迅速席卷全球,成为一种炙手可热的技术。越来越多的开发人员想快速的掌握这门技术,并把它快速应用到自己的项目中。

虽然构成AJAX的技术已经非常成熟了,但是都是以CSS、JavaScript、XML等单一形式出现的,所以相关的技术书籍都仅仅停留在孤立的介绍这些技术方面,读者无法将这些技术有机的整合起来,更无从谈起将AJAX应用到项目中。本书将尝试着打破这种局面,在书中我们对AJAX的基础知识做有重点的介绍,而且本书中将穿插各种小的案例,让读者能够在实践中快速学习到AJAX技术,并且在最后我们安排了一个实用性非常强的WebOS应用,让读者能够学了就能懂、懂了立即用。

在AJAX领域已经有一些非常好的图书出版,不过这些图书大都是用PHP、.Net等语言描述的,以Java实现的并不是很多,即使有也是浅尝辄止。不过《专家手记AJAX开发实战 》的出现改变了这一面貌。

这本书不仅用了大量篇幅介绍了流行的AJAX框架,更加可贵的是,书中用了三个章节以一个实用的WebOS为案例讲解了基于AJAX技术的Web系统的开发开发出了模拟Windows桌面、网络相册、爱墙、在线Office、网络硬盘等经典的Web2.0应用,充分展示了AJAX技术的强大。WebOS是AJAX技术登峰造极制作,跟着作者实打实的学到了一个WebOS的制作,你就是AJAX高手!!!

值得一提的是《专家手记AJAX开发实战 》这本书的代码质量非常高,看了作者的代码不仅能使您学到高手的代码编写习惯,更能使您掌握AJAX的高级开发技能。
    此书是CowNew开源团队第一本团队合作形式出版的图书!
    稍后会提供试读电子版给各位。

       由CowNew开源团队的侯志松(网名:芽孢)编写的《Hibernate完全手册》也已经由机械工业出版社出版。本书从应用程序开发的角度出发,在介绍关系数据库系统知识和面向对象方法的基础上,全面介绍对象关系映射领域的工业标准――Hibernate的基本功能、体系架构、使用方法及高级特性。全书以对象关系映射为主线,分成3个模块:第1~6章介绍对象持久化的基础以及Hibernate的基本配置和使用方法;第7~11章详细介绍如何使用Hibernate实现对象关系的映射,并讨论了使用面向对象方式查询数据的方法和技巧;第12~16章分析了Hibernate中事务、并发、缓存等高级特性,并讨论了如何整合Hibernate和成熟技术,构建企业级应用程序开发框架的技术实践。
posted @ 2008-06-03 16:59 CowNew开源团队 阅读(1996) | 评论 (5)编辑 收藏

向四川汶川大地震遇难同胞表示深切哀悼! 

  举国哀悼,也许,我们会泪流满面,也许,我们会放声痛哭,但任何困难都难不倒中国人民,我们终会擦干泪水,挺起脊梁,继续前进。

posted @ 2008-05-19 21:05 CowNew开源团队 阅读(234) | 评论 (0)编辑 收藏

        今天终于把《鲁宾逊历险记》第一部看完了,看到其中说到“既然上帝都能饶恕他,我们有什么权利剥夺他的生命呢?”,我这才明白为什么电影里边基督徒要杀一个人的时候要说“我以上帝的名义,杀了你”,既然能够有权剥夺你生命的人只有上帝,那么我要杀了你就必须“以上帝的名义”了,也就是说这是上帝他老人家的意思。这也就是说,做一件事情必须有“名分”。看以前很多革命电影中,我们的革命战士要枪毙叛徒的时候要说“我代表人民代表D枪毙了你”,应该这是一个意思吧。
        朱棣要当BOSS就要打着“清君侧”的旗号、洪秀全要造反就必须说自己是上帝的次子、小鬼子要发动七七事变就要找理由攻占宛平城、老美要弄死萨达姆就必须以找核武器为理由……看来无论是国内还是国外、无论是做好事还是做坏事名分都是很重要的,必须找个名分才能行动,如果哪天一个人做事不讲“名分”的话估计也就是流氓透顶了吧。
posted @ 2008-05-03 23:24 CowNew开源团队 阅读(406) | 评论 (5)编辑 收藏

ssy(*^__^*) 16:57:16
不知你做过js的语法分析没有,我正在用antlr做js的语法分析,遇到两个难题,想向您请教:
1.正则和除法的区分
2.js匿名类和组合语句的区分
杨中科 17:08:22
sorry,没做过js的语法分析  
ssy(*^__^*) 17:10:37
哦,谢谢你
杨中科 17:11:39
为什么不用mozilla的js包呢?它那里边好像提供了解析js的类,直接能拿到AST  
ssy(*^__^*) 17:12:30
好的,谢谢您提醒,我去试一下mozilla的js包
杨中科 17:13:04
你们解析JS做什么用途?  
ssy(*^__^*) 17:13:46
做安全代码分析,就是找出js代码可能存在的安全隐患
杨中科 17:14:14
哦。JS包中的Parser类可以干这个  
ssy(*^__^*) 17:14:55
嗯,我去找一下这方面的资料,还没用过js包呢,呵呵,谢谢你提示
posted @ 2008-04-25 21:13 CowNew开源团队 阅读(890) | 评论 (2)编辑 收藏

     摘要: 公司现在在研发基于.Net中WPF技术的产品,由于要兼容旧有产品,比如一些旧有的Win32程序、第三方的Win32程序等等,还要实现自动登录这些外部Win32程序,因此必须能够将这些程序整合到我们的系统中来,让使用者看起来它们好像是一个程序。 在MSDN中有专门的章节提到了在WPF中嵌入Win32控件的办法,那就是使用 HwndHost ,只要把 Win32控件的句柄传递给 HwndHost ...  阅读全文
posted @ 2008-04-24 12:48 CowNew开源团队 阅读(6159) | 评论 (0)编辑 收藏

CowNew开源产品汇总,点击即可下载:
《自己动手写开发工具》随书源码:UIDesigner.rar

《自己动手写开发工具》随书光盘下载地址:http://www.namipan.com/d/b8879fd74ea3e2b2fd092bb3c7550352f5c6f49765b57b00
JDBC监控:JDBMonitor.rar
Hibernate建模工具CowNewStudio源码:CowNewStudio-src.rar
多数据库翻译器,源码CowNewSQL-src.rar,二进制包cownewsql-2.1.zip
antlr中文文档预览版.rar

CowNewToolKit: http://www.blogjava.net/Files/huanzhugege/CownewToolKit.rar

CowNewSQL在线演示:http://211.99.196.18:6666/cownewdemo
《程序员的SQL金典》随书源码: http://www.blogjava.net/Files/huanzhugege/《程序员的SQL金典》随书源码.rar
posted @ 2008-04-17 21:50 CowNew开源团队 阅读(2726) | 评论 (16)编辑 收藏

经过CowNew开源团队成员的不懈努力,《Antlr参考手册》的中文化工作第一阶段已经完成绝大部分工作,现在发布预览版供有兴趣的朋友参考,也请提出宝贵建议。下载地址:http://www.blogjava.net/Files/huanzhugege/antlr中文文档预览版.rar

感谢欧进利、周晓、曲金龙、west2snow、阿乐、杨中科等队友卓有成效的工作。
由于力量有限,Antlr的中文化工作还需要更多朋友的加入,有兴趣的朋友可以和我们联系:about521 at 163.com
未经Antlr.orgCowNew开源团队许可,请勿将此文档用做商业用途!
posted @ 2008-04-15 23:28 CowNew开源团队 阅读(2647) | 评论 (10)编辑 收藏

from:
http://chenxing.blog.51cto.com/240526/44949

随着科技的进步,计算机技术的应用已经延伸到所有能到达的行业,随之而来的计算机软件开发人才的短缺,已经成为IT业迫切急需解决的问题。
       虽然现在全国很多高校都开设了与计算机相关的专业,但由于教学质量不高,计算机教材陈旧,师资力量差,教师本身缺少开发经验,只会理论知识,至使学生毕业后根本就不会做与软件开发有关的工作。为了解决这个问题,社会上出现了各种各样的软件开发培训机构,所有的教材都与社会同步,与世界接轨,全国有名的IT培训机构有北大青鸟、清华等等,在这些IT培训机构学习的学员,在毕业后都能获得软件工程师的认证和其它相关的IT认证,为自己的求职增加了一份筹码。但通过系统学习,在获得软件工程师认证后的学员,其软件开发的水平到底有多高呢?是不是就真的达到了软件工程师的水平呢?经过多家软件企业公布的数据表明,有70%以上的人只能达到或还达不到初级程序员的水平,获得软件工程师认证的人又找不到工作,软件企业招不到合适的开发人员,至使软件企业不惜重金相互挖墙角,但收效甚微,企业内部培养成本又太高,即使培训成才后也免不了替别人做嫁衣。
       那么问题是出在企业用人制度上还是出在软件开发培训机构上呢?经过市场调查,40%是企业用人制度上的问题,60%是IT培训机构培训方法上的问题。下面我们分别从这两个方面对其产生问题的根本进行分析:
      一、企业用人制度太过于机械化
     由于软件企业承接的软件开发项目越来越多,企业原有的开发力量已经无法满足自身的需求,各企业出于对生产效率的提升和技术保密,将本公司所有高端人才集中在一起,共同开发出一套二次开发平台,将一套软件项目的所有相关的部分进行类模块封装处理,所有的软件工人只能在这个平台上进行工作,企业虽然提高了开发效率,但由于二次开发平台的原代码只掌握在及少数人手里,软件工人只能按其规定好的流程进行工作,日复一日,年复一年,时间久了,软件工人成了机器,没有了自己的思想,更别提创新了,出于对自身的发展考虑,很多软件工人都选择了跳槽,但天下乌鸦一般黑,其它软件企业也是一样,至使越来越多的软件工人离开IT业,去从事其它行业。随着人才的流失,企业原有的开发力量就显得力不从心,为了招到合格的人才,软件企业在招聘上花了很大的成本,人是招来了,但经过试用期后发现,高薪招来的人才都是一些纸上谈兵的勇士,工作激情很高,但工作技能太差,根本无法进入角色。有的软件企业已经认识到了这一点,开始寻求解决的办法,例如与一些IT培训机构签署用人需求,将企业的一些项目和IT培训机构的教材相容合,使IT培训机构培养出来的学员到了企业后能很快进入角色,但这只有个别理念先进的企业能够意识到,大部分软件企业还是处于自闭壮态,企业竞争力一天不如一天,最后被市场淘汰出局。
      二、IT培训机构太过于市场化
     现在越来越多的IT培训机构成立了,招生简章可谓五花八门,招生宣传都很到位,服务态度也是一流,培训费用也是其它行业无法比的,一般都在6000-30000元之间,高投入带来高产出,很多大学生和其它行业的在职人员都开始进入IT培训机构进行学习,希望学成之后可以改变人生,梦想是美好的,可学完之后却让他们很失望,原因是他们所学的都是理论知识,只学会了软件开发工具的使用,对软件的实际开发流程一无所知,根本就无法找到合适的工作。一边是IT培训机构的大量扩招,一边是毕业学员无法适应社会的需求。IT培训机构到底哪里出了问题了呢?经过市场分析得出以下几个结论:
    1、教材基本能够和社会同步,但教学模式基本没有发生改变,和大学里面的差不多,一门课一门课的学,并且每门课都严格规定了课时,学员刚学员一门马上就开始学习下一门课,根本没有时间练习。各门课之间没有进行混合教学,等学员学到二期的课程时,要用到一期所学的内容,由于时间过去了很久,平时又不用,早忘没了,回过头再去复习一期的课程,二期的课程又学完了,至使每门课学的都不精。
    2、师资力量不够,很多IT培训机构里面的讲师,有的受过专业的讲师培训,但缺少实践软件开发经验,有的是从社会上临时招来的,他们一般都有很好的软件开发经验,但缺少教学经验和构通能力,无法和学员构通,使教学水平大打折扣。
    3、IT培训机构管理不到位,只注重招生不注重学员的培训管理,不能正确引导和培养学员树立正确的人生观和价值观,使很多学员都错误的理解了软件工程师就是高收入的职业,学完之后就可以得到高薪水的职位,整天在幻想中度过,不好好学习,最后毕业后根本无法就业。
    4、IT培训机构和软件企业缺少构通,无法将软件企业中的实际项目引进来,只有极少数的软件企业愿意与IT培训机构进行合作,达到互利双赢,大部分软件企业出于对技术保密的原因根本就不合作,学员无法在学习期间接触到实际软件项目,到最后只是得到一个经过某某权威认证机构颁发的证书,对自己的未来一片迷茫。
    通过上面两个方面的分析,我们找到了问题产生的原因,如何使软件企业与IT培训机构开展合作,是一个社会问题,而要双方共同努力解决。希望软件企业和IT培训机构的管理者能够认识到这一点,双方之间相互构通,互利合作,共同发展,培训出更多的对企业对社会有用的人才。
posted @ 2008-03-28 22:36 CowNew开源团队 阅读(658) | 评论 (3)编辑 收藏

反编译工具JodeEclipse已经更新,可以正确的支持Eclipse3.2 和 Eclipse3.3。支持视图与反编译代码之间的同步等代码导航功能。
这个版本是CowNew开源团队接手JodeEclipse以来第一次发布正式版。
下载地址:https://sourceforge.net/projects/jodeeclipse/
posted @ 2008-03-18 10:39 CowNew开源团队 阅读(2578) | 评论 (11)编辑 收藏

昨天刚发现一个很好的工具FileHamster,写文档、写小软件等的时候可以进行非常实用的版本控制,因为个人用没必要什么协同控制之类的,只要能实现版本控制就可以,所以VSS、CVS、SVN之类的都太麻烦了。是免费软件,英文版的,运行需要.net framework 2.0的支持。老外做的东西挺实用,:)
这是它软件自己的介绍:
该软件允许你定义需要监测的文件和/或者文件夹并且每当被监视的文件发生改变的时候自动地创建一个拷贝,为你提供一个向改变的文件添加一个注释的选项。如果需要的话,你可以简单地恢复到原先的版本并且可以取消改变或者跟踪问题所在。你可以配置保存版本的数量,限制监视指定类型的文件还可以下载用于扩展功能的额外插件。FileHamster 非常简单易用不需要任何专业技术,只需要点击你想要监视/备份的文件即可,其余的事情都由该软件完成.
posted @ 2008-03-03 09:35 CowNew开源团队 阅读(2004) | 评论 (1)编辑 收藏

         最近公司要开发Windows平台上的产品(由于涉及到商业机密,所以目前无法对这个产品做详细介绍),采用.Net技术进行开发,我负责的是基于Visual Studio插件机制的行业开发工具的开发。从开始接触.Net到现在已经有近三个月了,而且也开发出了第一个版本,对.Net已经有了一些认识,由于以前主要用Java、Python等语言进行开发,因此有意无意的就对这些语言进行了比较。和Java比起来,.Net的优势还是很多的,比如快速开发能力、基于Windows特性进行开发的能力、内置的丰富类库、一些高级语法、组件的多版本管理等。优点是不用过多夸耀的,缺点我则要好好的“批评”一番的,因为“谦虚使人进步,骄傲使人落后”嘛,呵呵。开发场景为:使用Visual Studio2005进行C#的开发、使用Eclipse进行Java开发。 
 
1、HotSwap:在Java中HotSwap技术给程序的调试带来非常大的方便,比如可以让程序一边调试一边修改代码,代码修改以后在程序中立即就可以看到修改后的效果,不用每次修改以后都要重新启动程序;在.Net中几乎不允许这样做,只有在非常苛刻的几个情况下才可以实现在调试状态下修改代码,而且一旦代码段被执行过了就肯定不允许再修改了,这就导致每次修改代码都要频繁启动程序,非常繁琐。
 2、基于.Net的东西和Windows结合过于紧密,而且和Windows平台下一些旧有技术有太多千丝万缕的联系,导致用起来非常麻烦。比如每个对外部系统暴露的接口传来传去最后看到的类型是_ComObject,要想得知其真正的接口类型就必须通过COM技术来取得,非常麻烦;开发的很多组件都需要到注册表中注册,增加了部署的难度。

3、Visual Studio中代码的即时查错能力非常弱,很多的要到编译时才能知道代码是否有错;而在Eclipse中在编写代码的时候对于有错误的代码和有警告的代码(比如一些Private成员没有被引用)可以立即清晰的提示出来,开发人员可以立即修改有错误的代码。

4、Java中默认的方法都是可以override的除非标注为final,而在C#中必须是明确声明virtual的才可以override。在Delphi中也是类似的问题,这应该是Delphi和C#共同的老爹Anders Hejlsberg对于OO的一种理念吧,也许人家大师的想法是正确的:一个方法是否是虚方法必须要明确指定。不过对于习惯了Java中这种实现方式的人来说,C#的这种实现方式还是让人感觉一时难以适应的。

5、Visual Studio的编译速度太慢,点击【调试】/【运行】按钮以后要编译好长一段时间才能启动(不过和Visual Studio6比起来现在的Visual Studio编译速度已经快多了了,已经接近于Delphi的编译速度了);由于Eclipse使用的自己的高性能编译器Eclipse Compiler,而且代码的编译是在编写代码的时候即时进行的,所以在Eclipse中根本感觉不到编译的时间,点击【调试】/【运行】按钮以后程序就运行起来的。

6、.Net类库中一些类设计的不灵活,比如TreeView的节点的显示的值是通过Text属性赋值上去的;而在Java中的Swing、SWT等图形库中,可以在一个树节点中挂任何类型的值,然后通过为这个节点定义个性化的Render(渲染器)来决定这些树节点显示什么。

7、Visual Studio的插件体系过于死板,开发起来不像开发Eclipse插件那样灵活简便,这可能和Visual Studio插件体系的历史渊源有关系。举例如下:
(1)比如要在代码编辑器上增加新特性,在Eclipse中可以通过代码编辑器中提供的大量扩展点来实现,而在Visual Studio中的代码编辑器中则只提供了很可怜的几个可扩展性。这一点是Visual Studio插件体系最大的硬伤,大大限制了基于Visual Stuio的插件的功能,相信随着MS对Visual Studio插件体系的逐渐重视,这一点会慢慢跟上来的。
(2)Visual Studio的插件体系和.Net结合过于紧密,在Eclipse中可以为Python、Ruby、C#、C、ASM等很多语言开发IDE(提供代码编辑、代码辅助、调试、编译等功能),这些语言不必与Java有任何关系,而在Visual Studio中虽然也可以为一种语言编写IDE,比如IronPython、J#,但是这些语言是和.Net集合紧密的,比如要为这种语言提供调试功能,则必须将代码编译成MSIL代码,这对于很多语言来讲是不可能的;
(3)Eclipse中的插件只要在自己的plugin.xml文件中配置好就可以了,把那个插件的jar包放到Eclipse中就可以运行,而Visual Studio中的插件则必须首先注册到注册表,调试和部署起来非常麻烦;
(4)Eclipse运行时的配置是保存在Workspace中的.metedata目录下的,因此在开发插件的时候会把插件的配置信息自动写到Host起来的那个Eclipse的Workspace中,被调试模式启动的Eclipse所做的一些修改不会影响主Eclipse,而在Visual Studio中虽然可以使用Experimental Hive方式进行插件开发,但是由于这些配置是保存在注册表中的,所以被Host启动的Visual Studio实例会污染到主Visual Studio,每次重启IDE都需要运行“Reset the Microsoft Visual Studio 2008 Experimental hive”来进行环境的重置,且重置耗时非常长,浪费了大量时间;
(5)VS2008中,如果插件中抛出异常,而又没有捕获的话,轻则VS2008会显示一个错误消息框,重则VS2008会宕掉;而在Eclipse中会将插件中未捕获异常显示出来并且输出到日志文件中,方便插件开发者排查插件的Bug。
(6)Eclipse中工程相关的特性是以Nature的方式提供的,一个Nature通常可以挂接到几乎所有的工程类型中去,包括用户自定义类型;而在Visual Studio中工程相关的特性则是以SubProject的形式提供的,往往只能挂到Visual Studio内置的少数几个工程类型中去(比如CSharpProject、VBProject),这样可扩展性大大降低了。
(7)Eclipse中可以使用JET来开发非常复杂的代码生成器,而Visual Studio中的代码生成则只能用非常简单的代码模板机制,复杂的逻辑就必须通过字符串拼接来完成;

        毕竟接触.Net时间还是非常短,所以有的地方说的可能有错误,还请园子里的兄弟多指教。最后祝.Net和Java能在相互竞争中快速成长,从而让我们开发人员能够轻松、快乐、快速的开发出产品来,:)

posted @ 2008-02-19 11:29 CowNew开源团队 阅读(18816) | 评论 (72)编辑 收藏

送给未满30和已满30的创业者和奋斗者们 
 放 弃 
把握的反面就是放弃,选择了一个机会,就等于放弃了其他所有的可能。当新的机会摆在面前的时候,敢于放弃已经获得的一切,这不是功亏一篑,这不是半途而废,这是为了谋求更大的发展空间;或者什么都不为,只因为喜欢这样做,因为,年轻就是最大的机会。人,只有在三十岁之前才会有这个胆量,有这个资本,有这个资格。

失 恋 
不是不在乎,是在乎不起。三十岁前最怕失去的不是已经拥有的东西,而是梦想。爱情如果只是一个过程,那么正是这个年龄应当经历的,如果要承担结果,三十岁以后,可能会更有能力,更有资格。其实,三十岁之前我们要做的事情很多,稍纵即逝,过久地沉溺在已经干涸的爱河的河床中,与这个年龄的生命节奏不合。 

漂 泊 
漂泊不是一种不幸,而是一种资格。趁着没有家室拖累,趁着身体健康,此时不飘何时飘?当然,漂泊的不一定是身体,也许只是幻想和梦境。新世纪的时尚领袖是飘一代,渴望漂泊的人唯一不飘的是那颗心。

不适应 
在一首摇滚里有这么一句:"这个城市改变了我,这个城市不需要我。"不要盲目地适应你生存的环境,因为很可能这环境自身已经不适应这个社会的发展了。

失 败
我的老师曾经跟我说,一个人起码要在感情上失恋一次,在事业上失败一次,在选择上失误一次,才能长大。不要说失败是成功之母那样的老话,失败来得越早越好,要是三十岁,四十岁之后再经历失败,有些事,很可能就来不及了。 

稳 定 
三十岁之前就在乎稳定的生活,那只有两种可能,要么就是中了彩票,要么就是未老先衰。 

房 子 
除非你买房子是为了升值,要么就是你结婚了。我有个同学,家在外地,大学毕业之后,单位没有宿舍,家里就给他买了一套房子。他曾经有过去北京工作的机会,但是他觉得刚买了房子就离开这座城市说不过去,就放弃了。到现在他工作稳定,但一事无成。唯一的成就就是结婚了,并且有了孩子,因为他觉得该让这房子永远空着,所以房子变成了家。房子是都市生活的寓言,这个寓言不应该过早的和我们相关。

posted @ 2008-02-09 17:38 CowNew开源团队 阅读(647) | 评论 (2)编辑 收藏

CowNew开源团队2007年工作报告

 

    回首2007年,CowNew开源团队取得了突飞猛进的发展,2008年新年的钟声即将敲响,在此让我们回顾CowNew开源团队在2007年取得的成就、总结经验教训,并且对2008年的工作进行展望。

一、2007年工作回顾

1、开源产品日渐成熟

    在KingChou、杨中科等队友的努力工作下,CowNewSQL经历了五次版本升级,目前已经发展到2.1版本;现在的CowNewSQL能够支持主流的DDL、DML语句,并且支持MYSQL、MSSQLServer、Oracle、DB2四种主流数据库系统;创建了CowNewSQL的JDBC驱动(支持JDBC3.0),这样无需修改系统代码就可以直接使用CowNewSQL;增加了对JDK1.4的支持;创建了CowNewSQL演示站点,使得开发人员可以更方便的试用CowNewSQL。

    CowNewStudio可以支持插件式扩展,可以很容易的支持其他ORM产品;修正了用户反应的若干Bug,产品更加稳定;增加了对JDK1.4的支持。

2、技术图书出版成果丰厚

    CowNew开源团队和清华大学出版社、电子工业出版社以及言实文化传播有限公司等图书出版机构建立了紧密的合作关系,为国内读者带来了多部优质图书,并且进一步扩大了CowNew在国内的影响。

    7月份《J2EE开发全程实录》上市,11月份《自己动手写开发工具》上市,这两本书蝉联技术类图书销售排行榜,取得了非常好的销售成绩和市场反响;侯志松编写的《Hibernate技术手册》(暂定名)以及曲金龙、杨中科合著的《Java下的AJAX开发揭秘》(暂定名)已经交稿,正在出版运作过程中;另外一本数据库技术方面的图书也在编写过程中。

3、Antlr文档中文化第一期工作完成

    在曲金龙、周晓、欧近利、阿乐、west2snow、杨中科等队友的努力工作下,Antlr核心文档的中文化初稿已经完成,目前正在内部校对过程中。

4、和国内外开源团队建立了稳定的合作关系

    自创始之初,CowNew就与EasyJF开源(http://www.easyjf.com)保持着紧密的合作关系,无论是在技术方面还是在开源团队的建设与发展方面都进行了非常深入的交流。12月份CowNew与EasyJF合作的开源项目BlueFin正式启动,这标志着CowNew与EasyJF的合作进入了一个新的阶段。

    与国外的开源组织Antlr建立了稳定的合作关系,CowNew将负责Antlr在中国的本地化与推广工作,与国外开源组织的合作将会扩大国内开源运动在国际上的影响力,并且能够在与国外开源组织的合作过程中学到国外相对较成熟的开源项目运作经验。

5、开源聚会

    4月份我们组织了北京地区成员的聚会,这也是团队成立以来第一次聚会,聚会在轻松愉快的氛围中进行,进行了深入的交流。

6、团队大规模扩充

    2007年,随着团队在业界影响力的不断扩大,CowNew开源团队的成员大规模扩充,特别是欧进利、周晓、曲金龙等核心成员的加入使得CowNew开源的实力得到了极大的增强。

二、2007年工作不足与经验教训

1、产品的市场调研和推广不够

    团队产品在立项的时候没有进行足够的市场调研,导致有的产品的市场定位不明确,不仅浪费了精力,而且使得项目后劲不足,直接影响了成员的积极性;团队产品的推广力度不够,团队产品的知名度仍有待提高;由于推广力度的问题,导致团队产品在实际项目中应用不足,没有形成成功案例,制约了产品的后续发展。

2、团队内部组织建设有待加强

在团队建设初期,由于成员和子项目都非常少,所以采用集中制管理非常适合。但是随着成员的增加以及子项目的丰富,这种集中制管理模式的劣势已经突显:

  • 成员都不是专职从事开源工作,这样当管理人员工作繁忙的时候,所有子项目都会进展缓慢甚至停滞。
  • 所有子项目都由一个管理人员负责,这样项目的成败就完全取决于这个管理人员的水平,如果管理是出现失误,会造成所有项目的失败。
  • 没有让有能力的核心成员参与管理工作,不仅无法全面展示核心成员的优势,而且降低了核心成员的参与积极性。

3、"帮助队友成功"的执行不够彻底

    "帮助队友成功"是我们团队内部建设的一个宗旨,目的是保证让成员开源做的贡献能够实现回报最大化。不过由于种种原因,"帮助队友成功"执行的还不是非常到位,核心成员得到的各方面回报里期望还是有一定差距的。

4、团队内部建设不足

    团队成员资格审核工作不到位,一些不符合基本要求的成员的加入增大了内部管理的难度,使得团队内部管理混乱;信息不够透明,团队的一些最新消息无法及时准确的传递到每个队友;没有完善的成员管理制度,对成员的信息没有一个科学的管理,不仅会造成成员的流失,也使得对团队的人力资源掌握不足,无法充分发挥没有成员的潜力;团队聚会前期准备不足,没有达到理想效果;对核心成员的关怀不足。

5、团队网站重视程度不够

    团队网站做为一个宣传窗口目前还过于简陋,让访问者感觉不够专业,进而使得访问者对CowNew的实力产生了怀疑;团队网站信息不足并且更新不及时,访问者无法得到想了解的信息,甚至有的访问者认为CowNew已经是不活跃的开源组织了;网站上对团队产品以及核心成员的介绍非常缺失。

目前团队网站放在一个普通虚拟主机上,采用的是电信的线路、网站空间只有150M、只支持ASP网页、能够使用的CPU资源和带宽资源都非常有限,所以导致大多数访问者感觉访问速度慢,能够支持的同时访问人数非常有限;同时由于ASP技术的天生缺陷,导致网站经常遭到无聊的Cracker的攻击;由于网站不支持Java、.Net等程序的运行,导致无法提供团队产品的在线演示。

6、团队关注的技术过于狭窄

    CowNew开源项目的产品的技术起点较高,不容易被普通开发人员了解与学习,但是在文档和宣传方面却没有很好的进行技术普及,普通开发人员不能很好的试用与使用我们的产品。

对其他语言和技术关注度不够,.Net、Python、C/C++等语言以及Linux/Unix平台下也有大量的市场需求以及开源组织,特别是Linux平台下的开源项目的影响力更大,但是目前团队的产品几乎都是使用Java语言实现的,以至于很多人认为CowNew只是一个Java开源组织,限制了CowNew在国内的影响力与发展。

三、2008年工作计划

1、CowNewSQL升级以及推广。

CowNewSQL将提供.Net、C/C++等语言的移植版本(开发dll、so共享库,然后提供其他语言的包装);支持存储过程的翻译;支持方言到方言的翻译(比如MySQL到Oracle的翻译);将CowNewSQL的SQL分析引擎提取成单独的产品,进而提供基于它的SQL优化、SQL分析等工具;加大CowNewSQL的推广应用力度,打造典型应用案例,有必要的话可以用产品定制化的方式促进CowNewSQL的发展。

2、继续和国内外的开源组织保持合作

    和EasyJF合作的BlueFin保持迭代性的版本发布,力争在2008年将BlueFin打造成有一定实用性的辅助开发工具;将CowNewStudio功能合并到BlueFin中,然后关闭CowNewStudio子项目,减少产品的重复开发。

    和Antlr官方组织合作推出Antlr中文文档正式版;完成Antlr其他文档的中文化;启动Antlr案例项目,做为Antlr典型案例进行推广,提高编译技术的普及;基于Antlr进行编译技术的知识推广工作。

    扩大与其他活跃开源组织的合作关系。

3、保持技术图书出版的发展势头

完成已经交稿的两本技术图书的出版,并且进行相关市场推广工作;数据库技术图书的完成与出版推广;工作流、编译技术等图书的策划与撰写。

4、其他语言和平台下开源项目的启动

    论证.Net、Python、C/C++等语言以及Linux/Unix平台下开源项目的可行性研究,然后进行项目的启动以及成员招聘工作。

5、加大宣传力度

    加大开源团队、开源产品以及核心成员的宣传工作,扩大与主流媒体的合作。具体包括在主要的技术站点创建团队Blog、团队圈子,和主流媒体合作推出产品以及核心成员的采访专题。

6、加强团队内部建设

    确定子项目负责人,实行项目的负责人制;继续进行成员的招聘,扩充团队规模;加强对团队成员的审核机制,建立标准的笔试题库;定时清理长期不活跃成员;完善内部通讯录制度;针对团队的核心成员和普通活跃成员给予不同的任务并提出不同的要求,进行定期或不定期的工作汇报,并进行审核,指出不足;建立良好的沟通途径(maillist、团队Blog等形式),使得团队的最新消息能够及时传达到每个成员,让团队成员互相了解、集思广益。

7、完善团队网站

    升级团队网站,完善团队栏目和内容,保证信息的及时更新;选择合适的网站Hosting方式,提高网站安全性以及访问速度;实行团队网站站长负责制。团队网站仍然定位为团队的对外宣传窗口。

8、其他工作

    开展在高校的活动,包括开源校园行、技术讲座等;进行计算机学科基础知识的普及,包括网上视频、现场讲座、文章或者图书的撰写等。

 

附录 CowNew开源团队简介

    CowNew开源团队(http://www.cownew.com)是目前国内较活跃的开源团队之一,创立于2006年,我们致力于基础平台的开发以及知识推广,目前已经有数个成熟的基础产品问世,并与国内数家网站、出版社建立了紧密的合作关系。

一、团队产品介绍

1、CowNewSQL

    由于种种原因,各个数据库系统的SQL语句语法以及支持的函数都不尽相同,这造成了如下两个问题:(1)系统在多个不同数据库之间移植变得非常困难,特别是需要维护多个数据库版本的时候;(2)开发人员必须对各种数据库的语法差异非常了解,这加大了开发难度。

    目前解决这种差异的最常用的技术就是SQL语句翻译,使用SQL翻译器可以将SQL语句翻译为在不同的数据库中支持的特定平台的SQL语句。CowNewSQL就是这样一款产品。

    CowNewSQL简化了跨数据库产品的开发,比如取当前日期在MSSQL中是"SELECT GETDATE()",在MYSQL中是"SELECT NOW()",在Oracle中是"SELECT SYSDATE FROM DUAL",使用CowNewSQL以后您只要使用"SELECT NOW()",那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句;取数据库前10条记录,在MSSQL中是"Select top 10 from T_1"、在MYSQL中是"SELECT LIMIT 0, 10 "、在Oracle中是"SELECT FROM DUAL WHERE ROWNUM <= 10",使用CowNewSQL以后您只要使用"Select top 10 from T_1",那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句。

    CowNewSQL支持如下几种类型的SQL语句:CreateTable/AlterTable/DropTable/CreateIndex/DropIndex/Select/Insert/Delete/Update/ShowTable/ShowTables;支持子查询、Join、Union等高级的SQL特性;支持日期(包括取当前日期、从日期中提取任意部分、计算日期差异、日期前后推算等)、数学(包括取绝对值、取PI值、四舍五入、对数计算、随机数等)、字符串(包括取子字符串、取字符串长度、字符串截断、大小写转换等)、基本数据处理(包括数字字符串互转、日期转字符串、非空判断等)等函数。

    CowNewSQL支持MYSQL、MSSQLServer、Oracle、DB2四种主流数据库系统;能够以JDBC驱动的方式使用,这样无需修改系统代码就可以直接使用CowNewSQL;支持JDK1.4以及以上版本。

    CowNewSQL后续工作计划:CowNewSQL将提供.Net、C/C++等语言的移植版本(开发dll、so共享库,然后提供其他语言的包装);支持存储过程的翻译;支持方言到方言的翻译(比如MySQL到Oracle的翻译);将CowNewSQL的SQL分析引擎提取成单独的产品,进而提供基于它的SQL优化、SQL分析等工具;加大CowNewSQL的推广应用力度,打造典型应用案例,有必要的话可以用产品定制化的方式促进CowNewSQL的发展。

2、技术图书

    CowNew开源团队和清华大学出版社、电子工业出版社以及言实文化传播有限公司等图书出版机构建立了紧密的合作关系,为国内读者带来了多部优质图书,并且进一步扩大了CowNew在国内的影响。

    2007年7月份《J2EE开发全程实录》上市,11月份《自己动手写开发工具》上市,这两本书蝉联技术类图书销售排行榜,取得了非常好的销售成绩和市场反响;侯志松编写的《Hibernate技术手册》(暂定名)以及曲金龙、杨中科合著的《Java下的AJAX开发揭秘》(暂定名)已经交稿,正在出版运作过程中;另外一本数据库技术方面的图书也在编写过程中。

3、Antlr的本地化推广

    我们和Antlr合作进行Antlr的本地化(包括文档中文化以及案例中文化)、案例推广以及知识推广工作。目前Antlr文档中文化第一期工作已经完成。

Antlr项目后续工作计划:完成Antlr其他文档的中文化;启动Antlr案例项目,做为Antlr典型案例进行推广,提高编译技术的普及;基于Antlr进行编译技术的知识推广工作。

4、BlueFin

    自创始之初,CowNew就与EasyJF开源(http://www.easyjf.com)保持着紧密的合作关系,无论是在技术方面还是在开源团队的建设与发展方面都进行了非常深入的交流。2007年12月份CowNew与EasyJF合作的开源项目BlueFin正式启动,这标志着CowNew与EasyJF的合作进入了一个新的阶段。BlueFin定位为打造一个用于快速开发JavaEE应用程序的实用开发工具及平台,主要涉及到Eclipse插件开发、常用Java框架(如Spring、JPA、EasyJWeb)支持,辅助领域模型分析及设计,代码生成引擎等领域的技术。

    此项目刚刚启动,需要熟悉Eclipse插件开发、熟悉Java常用开源框架使用的成员的加入。

5、多媒体教程

    CowNew开源推出了《Eclipse实战系列视频教程》等优秀的开发视频教程,在业界引起强烈反响。未来CowNew会推出更多视频教程,包括开发技术类以及计算机学科基础知识等高端视频教程。

    此项目需要对计算机学科基础知识(数据结构与算法、操作系统、编译技术、模式识别等)有深入领悟、并且有一定的实战经验的成员加入。

二、核心成员简介

    优秀的团队离不开优秀的团队成员,自从CowNew开源团队创立以来涌现出一大批技术好、乐于奉献的队友,下面列出的是这些优秀队友中的典型代表。

  1. 周君

网名KingChou,本科毕业于西安交通大学电子商务系。现为北京大学软件与微电子学院在读硕士研究生。目前在IBM中国研究院参与SAAS、SCA相关项目的研发工作。主要的研究领域有SOA、J2EE、P2P等。CowNew开源团队创始人之一,在CowNew开源社区中参与了CowNewSQL中Sql语法词法解析器的开发工作,目前为BlueFin项目负责人。

个人邮箱:kingchou.pro at gmail.com

  1. 杨中科

    毕业于山东大学物流工程专业,曾就职于金蝶软件(中国)有限公司,目前在北京赞同科技发展有限公司从事银行基础开发平台的开发工作。主要研究领域有编译技术、IDE设计与开发、Java企业级应用等。著有《J2EE开发全程实录》、《自己动手写开发工具》等畅销图书。CowNew开源团队创始人之一,参与了CowNewSQL、CowNewStudio等的开发工作。

    个人邮箱:about521 at 163.com

    个人QQ:57077490

  1. 宋传芳

网名:坏男孩,毕业于山东科技大学,资深软件工程师,从事工业控制软件、交通行业业务系统软件开发。关注的技术有J2EE、门户Portal、JAVA框架、Linux操作系统以及数据库运维技术。CowNew开源团队创始人之一,致力于CowNew团队建设以及产品研究与推广。

个人邮箱:badboyryan at gmail.com

blog:http://badboyryan.blogjava.net/

个人QQ: 147863130

  1. 侯志松

    网名芽孢,毕业于武汉理工大学计算机学院,硕士,现任职于河南科技学院,曾任职大型汽车制造集团,主要关注网络数据库和工作流管理技术,参与多个大型项目架构和开发。作者在企业级应用开发方面和工作流管理方面颇有见解,曾发表多篇学术文章。编写的《Hibernate技术手册》(暂定名)即将出版。

blog:http://blog.matrix.org.cn/houor

个人邮箱: forhouor at gmail.com

  1. 曲金龙

    毕业于西安电子科技大学,主要从事 J2EE 方面的工作,有大量 J2EE应用的设计与开发经验。热衷于数据结构、算法以及编译原理等计算机基础学科的研究与学习。酷爱英语,翻译过一些国外的优秀技术文章,并创办"每日英语"网站(www.beanwoo.com)。在CowNew开源团队中参与了Antlr文档的中文化工作,曲金龙等编著的《Java下的AJAX开发揭秘》(暂定名)即将出版

  1. 欧进利

    浙江大学在读硕士,主要研究方向为嵌入式系统开发,对Linux系统有深入的研究。精通C/C++,熟悉VC、QT等编程环境下应用程序的开发。在Antlr文档本地化中做了大量优秀的工作,目前为Antlr本地化项目负责人。

个人邮箱:oujinli1985 at gmail.com

  1. 周晓

2005年毕业于华东理工大学化学工程与工艺专业,目前从事基于Java、.Net技术的商业软件开发。在Antlr文档本地化中做了大量优秀的工作。

个人邮箱:Zhouxiaozxr at 163.com

三、合作伙伴

 

四、加入CowNew

    CowNew开源团队目前处于高速成长期,急需有志之士加盟共同为中国的开源事业奋斗。您可以申请加入任意一个项目组(目前有CowNewSQL、Antlr中文化、BlueFin、图书写作小组、计算机学科基础知识推广小组);也可以提出您自己的想法,我们将会组织对您的想法感兴趣的队友形成新的项目小组。

如果你申请加入CowNewSQL项目组或者Antlr中文化项目组,请回答下面的测试题:

1、请翻译下面的段落:

A lexer (often called a scanner) breaks up an input stream of characters into vocabulary symbols for a parser, which applies a grammatical structure to that symbol stream. Because ANTLR employs the same recognition mechanism for lexing, parsing, and tree parsing, ANTLR-generated lexers are much stronger than DFA-based lexers such as those generated by DLG (from PCCTS 1.33) and lex.

2、编译器的六个阶段:_____、_____、语义分析、中间代码生成、代码优化和代码生成。

3、(1+2)*3的抽象语法树是什么样的?

4、每周能有多少时间投入到开源项目的开发过程中?

5、你为什么要参与开源项目的开发?对你个人有哪些好处?

    如果您申请加入BlueFin项目组,请回答下面的测试题:

1、谈一谈Eclipse的插件体系的亮点。

2、如果你从头开发一个Java开发环境的话,你会规划出哪些功能,预期会遇到哪些问题?

3、请翻译下面的文章:

Eclipse is a platform that has been designed from the ground up for building integrated web and application development tooling. By design, the platform does not provide a great deal of end user functionality by itself. The value of the platform is what it encourages: rapid development of integrated features based on a plug-in model.

4、每周能有多少时间投入到开源项目的开发过程中?

5、你为什么要参与开源项目的开发?对你个人有哪些好处?

6、如果在开发程序的过程中程序报出如下的异常:

21:26:28,171 WARN [JMSContainerInvoker] Could not find the topic destination-jndi-name=my_test_topic javax.naming.NameNotFoundException: my_test_topic not bound

而你又不知道如何处理此问题。那么你会怎么办?

如果您想加入图书写作小组或者计算机学科基础知识推广小组,请简要介绍你的选题。

申请加入的队友请将个人资料、测试题答案(或者选题说明)等资料通过Email发送给相应项目的负责人(联系方式详见下面的"联系我们")。

注意:我们的团队目前只是一个非盈利性、非实体组织,目前仍然在发展的探索中,我们无法在短时间之类让您看到经济回报,团队成员也全部是利用业余时间从事这项工作的,所以如果您需要的一个能立即给您带来经济回报的全职工作,那么我们的团队并不适合您。

五、联系我们

参与BlueFin:kingchou.pro at gmail.com

参与Antlr中文化:oujinli1985 at gmail.com

参与其他项目组:cownew@hotmail.com

合作及其他事宜:cownew@hotmail.com

团队网站:http://www.cownew.com

 

posted @ 2007-12-28 09:44 CowNew开源团队 阅读(1901) | 评论 (18)编辑 收藏

 

  •   作为国内两个比较活跃的开源团队,EasyJF及CowNew都在各自所专注的领域里为开源社区作了不少的贡献。EasyJF开源的EasyJWeb已经推出了1.0m1正式版本,并通过在国内多个大中型项目中的成功应用,充分证明了EasyJWeb是一个优秀并适合快速开发JavaWeb应用的框架;CowNnew开源团队编著的《J2EE开发全程实录》、《自己动手写开发工具》等图书的上市更是得到了业界的好评,多数据库翻译引擎CowNewSQL也成为跨平台系统开发的最佳组件,正在火热进行中的Antlr本地化项目也将引领国内编译技术研究的新高潮。
      两个团队从创立以来一直保持着比较友好的合作,但这些合作都只是仅仅在一些技术交流、开源团队建设经验等方面。在经过近一个多月的筹备及沟通,EasyJF与CowNew决定把两个团队的合作更进一步深入,将通过项目组的形式来从事开源工作。

      JavaEE强大,但对于大多数程序员来说,门槛仍然较高,其实一个因素与工具的缺少也存在关系。关于Java的各种实用工具非常多,有开源的、有商业,有大型的也有轻量级的,但是由于JavaEE开发涉及到的问题比较多,一个工具不可能解决开发中遇到的全部问题,因此打造一个自己的开发工具一直是很多程序以及软件公司的梦想。因此,本次两个团队合作的目标打造一个名为BlueFin的开发工具项目,该项目定位为打造一个用于快速开发JavaEE应用程序的实用开发工具及平台,主要涉及到Eclipse插件开发、常用Java框架如Spring、JPA、EasyJWeb支持,辅助域模型分析及设计,代码生成引擎等领域的技术。
           BlueFin在英文中代表金枪鱼,它是比陆地上跑得最快的动物还要快的鱼类,一生中它不停地持续高速游泳,金枪鱼的旅行范围可以远达数千公里,能作跨洋环游,被称为“没有国界的鱼类”。我们的开源运动爱好者也是这样一群高速运转的精英,我们永远致力于引领开发技术的最前沿,我们目光长远,我们放眼全球技术的发展。这就是我们的金枪鱼,这就是我们的BlueFin。使用BlueFin进行开发您将勇往直前,攻克一道道难关,以最快的速度通向成功的彼岸。

      本次合作将由两个团队各抽取几名核心成员组成项目组,由CowNew杨中科(变更为KingChou。2007年12月12日)任组长及技术总构架,EasyJF站长程强负责需求设计及开发平台搭建等相关工作,CowNew的FoxKnit、Kingchou,EasyJF的大峡、netgod等各自抽取50%的人力资源参与开发。同时我们也欢迎国内广大的开源爱好者参与到该项目的建设中。

      该项目是一个开源项目,任何热爱开源的技术同行都可以参与到项目中,参与方式包括代码编写、Bug及建议提交、文档编写、资料提供等多种方式。该项目svn地址: http://svn.easyjf.com/repository/easyjf/bluefin/trunk,该项目Jira地址, http://jira.easyjf.com/,项目wiki地址, http://wiki.easyjf.com,项目源码http下载地址。(备注:BlueFin的svn在项目开发前期只为项目组成员开放,在项目出beta版的时候再对外开放。)

    附:加入该项目组的测试题
      为了保证能够使得参与项目成员的能力得到最好的发挥,所以请您回答如下的几个测试题:
      1、谈一谈Eclipse的插件体系的亮点。
      2、如果你从头开发一个Java开发环境的话,你会规划出哪些功能,预期会遇到哪些问题?
      3、请翻译下面的文章:
      Eclipse is a platform that has been designed from the ground up for building integrated web and application development tooling. By design, the platform does not provide a great deal of end user functionality by itself. The value of the platform is what it encourages: rapid development of integrated features based on a plug-in model.
      4、每周能有多少时间投入到开源项目的开发过程中?
      5、你为什么要参与开源项目的开发?对你个人有哪些好处?
      6、如果在开发程序的过程中程序报出如下的异常:
    21:26:28,171 Error [JMSContainerInvoker] Could not find the topic destination-jndi-name=my_test_topic javax.naming.NameNotFoundException: my_test_topic not bound   
    而你又不知道如何处理此问题。那么你会怎么办?

           请将问题的答案以及个人简介发送到254400283 at qq.com邮箱。

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

    BlueFin项目CowNew这一方的工作由KingChou全权负责。

    KingChou简介:
    周君。北京大学软件与微电子学院在读二年级硕士研究生。
    在Cownew开源社区中参与了CownewSQL中Sql语法词法解析器的开发工作。
    目前于IBM中国研究院参与SAAS、SCA相关项目的研发工作。
    主要的研究领域有SOA、J2EE、P2P等。

  • posted @ 2007-12-12 22:38 CowNew开源团队 阅读(394) | 评论 (0)编辑 收藏

    在与COM对象交互的时候有的时候我们得到一个对象,我们想知道它的类型,可以使用Object.GetType()方法得到的类型却是System.__ComObject,因为System.__ComObject是代表所有COM对象的,但是它对我们来说是没有任何意义的。如果想得到System.__ComObject的真正类型只要使用Microsoft.VisualBasic.Information.TypeName(objWindow.Object)就可以了,如果是非VB.net工程需要引用Microsoft.VisualBasic.dll 才能保证编译通过。
    12月6日添加说明:
    经过反编译TypeName方法,发现其核心实现为:
        UnsafeNativeMethods.ITypeInfo pTypeInfo = null;
        string pBstrName = null;
        string pBstrDocString = null;
        string pBstrHelpFile = null;
        UnsafeNativeMethods.IDispatch dispatch = VarName as UnsafeNativeMethods.IDispatch;
        if (((dispatch != null) && (dispatch.GetTypeInfo(0, 0x409, out pTypeInfo) >= 0)) && (pTypeInfo.GetDocumentation(-1, out pBstrName, out pBstrDocString, out num, out pBstrHelpFile) >= 0))
        {
            str5 = pBstrName;
        }

    和猜想的一致,它确实是通过IDispatch接口来完成的(呵呵,貌似也只有这一种方式)
    posted @ 2007-12-05 13:01 CowNew开源团队 阅读(5690) | 评论 (0)编辑 收藏

            刚才客户打电话过来说系统有问题,分析他发过来的日志后发现原来程序中用Integer.parserInt的方法把字符串形式的金额解析为整形,以前金额较小没有发现问题,今天发了一笔大额交易,总金额是2150220201,正好比Integer在32位平台上的最大值2147483647大一点点,所以发生了转换异常。
    经验再次提醒我们:
            为了防止精度、大金额溢出等问题,禁止在涉及到金额的地方使用integer、double、float等原始类型,统一使用BigDecimal、BigInteger。在python中也有对应的类型decimal类型用来进行不限精度的。
    posted @ 2007-12-04 14:52 CowNew开源团队 阅读(424) | 评论 (0)编辑 收藏

    去掉一个字符串中的$符号以及大括号中的字符(包括大括号)。
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    public class Main
    {
     public static void main(String[] args)
     {
      Pattern p = Pattern.compile("(\\$)|(\\{.+?\\})");
      Matcher m = p.matcher("abc$ggg{12dgd3}");
      System.out.println(m.replaceAll(""));
     }
    }

    posted @ 2007-11-26 14:46 CowNew开源团队 阅读(3018) | 评论 (1)编辑 收藏

    本章翻译人 CowNew开源团队 周晓

    记号词表

    每一个文法都指定了带有规则(子结构)和词表语言结构。这些符号在运行时被转换成整型的"记号类型"从而可以有效的比较。定义从符号到记号类型的映射的文件对ANTLR和ANTLR生成的分析器来说是基础。 这份文档描述了ANTLR使用和生成的这类文件,还介绍了用于控制词表的选项。

    导言

    在分析时,一个语法分析器文法通过符号在它的词表里引用记号要符合由词法分析器或其他几号流生成的Token对象。记号类型储存在记号对象中,每种符号的值是唯一的,分析器比较这些整数来判断记号类型。如果分析器期望下一个记号类型是23,但发现第一个超前扫描记号类型,LT(1).getType(),不是23,这时分析器抛出MismatchedTokenException异常。

    一个文法可能有一个导入词表,经常也会有一个导出词表,用于被其他文法引用。导入的词表从未被修改,通过它可以知道词表的"初始条件"。不要和导入词汇混淆了。

    下面列出了最常见的问题:

    ANTLR如何决定哪一个词法符号是什么记号类型?

    每个文法有一个记号管理器来管理文法的导出词表。从文法的importVocab选项,记号管理器以 符号/记号类型 的形式被预载。这个选项强制ANTLR寻找有如下映射关系的文件:

    PLUS=44

    没有importVocab选项,文法的记号管理器是空的(稍后会看见一个警告)。

    你的文法中的任意记号没有预设值,它们被按照遇到的顺序赋值。例如,在下面的文法中,记号A和B分别是4和5:

    class P extends Parser;
    a : A B ;

    词法文件以如下形式命名: NameTokenTypes.txt.

    为什么记号类型从4开始?

    因为ANTLR在分析过程中需要一些特殊的记号类型,用户定义的记号类型必须在3后开始。

    ANTLR生成什么样的词表文件?

    ANTLR为词表V生成VTokenTypes.txtVTokenTypes.javaV是文法的名字或者是exportVocab选项指定的名字。文本文件有点像一个简化的记号管理器,保存着ANTLR需要的一些信息,供定义在其他文件中的文法查看其词表信息等等。Java文件是是一个包含了记号类型常量定义的接口。ANTLR生成的分析器实现了其中的一个接口,获得所需要的记号类型定义。

    ANTLR怎样同步符号类型在相同文件和不同文件间文法的映射?

    一个文法的导出词表必须是另一个文法的导入词表或者2个文法必须共享一个公共的导入词表。

    设想p.g中有一个语法分析器P:

    // yields PTokenTypes.txt
    class P extends Parser;
    // options {exportVocab=P;} ---> default!
    decl : "int" ID ;

    l.g中有一个词法分析器L

    class L extends Lexer;
    options {
    importVocab=P; // reads PTokenTypes.txt
    }
    ID : ('a'..'z')+ ;

    即使L主要是P的词表中的值,但ANTLR生成的是LTokenTypes.txt和LTokenTypes。

    不同文件中的文法必须共享同样的记号类型空间,使用importVocab选项去预载同样的词表。

    如果这些文法在同一个文件中,ANTLR会用同样的方法处理它。然而,你可以通过设置它们的导出词表到同一个文件来使这2个文法共享同一个词表。例如,如果P和L在一个文件中,你可以这样做:

    // yields PTokenTypes.txt
    class P extends Parser;
    // options {exportVocab=P;} ---> default!
    decl : "int" ID ;
    class L extends Lexer;
    options {
    exportVocab=P; // shares vocab P
    }
    ID : ('a'..'z')+ ;

    如果你没有为L指定词表,它将会选择共享文件中导出的第一个词表;在这里,它将共享P的词表。

    // yields PTokenTypes.txt
    class P extends Parser;
    decl : "int" ID ;
    // shares P's vocab
    class L extends Lexer;
    ID : ('a'..'z')+ ;

    记号类型映射文件像这样:

    P    // exported token vocab name
    LITERAL_int="int"=4
    ID=5

    文法继承和词表

    文法继承父文法的规则,动作和选项,但是子文法使用什么词表和记号词表呢?ANTLR对子文法的处理就好像你复制粘贴父文法的所有非重载规则到子文法。因此,子文法记号的集合就是父文法和子文法的交集。所有的文法都导出词表所以子文法导出并使用一个和父文法不同的词表文件。除非你使用importVocab选项重载,否则子文法导入父文法的词表。

    文法Q继承P,会预先设置好P的词表,就好像Q使用了importVocab=P选项。例如,下面的文法有2个记号符号。

    class P extends Parser;
    a : A Z ;

    子文法Q,最初和父文法有相同的词表,但随后会增加一些符号。

    class Q extends P;
    f : B ;

    在上面的情况,Q定义了几个符号,B使得Q的词表为{A,B,C}.

    一个子文法的词表一般是父文法词表的父集。注意重载规则不影响最初的词表。

    如果你的子文法需要父文法未使用过的新词法结构,你或许需要子语法分析器使用一个子词法分析器。使用importVocab选项指定子词法分析器的词表来重载它初始的词表。例如,假设语法分析器P使用词法分析器PL。不用importVocab重载,Q的词表将使用P的词表,即PL的词表。如果你想让Q使用另一个词法分析器的记号类型,比如说使用QL,那么做下面的事情:

    class Q extends P;
    options {
    importVocab=QL;
    }
    f : B ;

    Q的词表现在和QL的词表相同或者是QL词表的父集。

    识别器生成次序

    如果你所有的文法在一个文件中,你就不用担心ANTLR将会最先处理哪一个文法文件,不过你仍要担心ANTLR处理文件中文法的次序。如果你尝试去导入一个会被另一个文法导出的词表,ANTLR将提示它不能读取这个文件。下面的文法文件会造成ANTLR出错:

    class P extends Parser;
    options {
    importVocab=L;
    }
    a : "int" ID;
    class L extends Lexer;
    ID : 'a';

    ANTLR在文法文件中还没有发现文法L,所以它将提示不能发现LTokenTypes.txt。另一方面,如果LTokenTypes.txt存在(比如说在文法文件中还没有P文法的时候ANTLR运行生成的),ANTLR将为P读取这个文件,然后在处理L文法的时候覆盖掉它。ANTLR不知道它要处理的文法恰好在一个文件中,所以它假设是要读取从另一个文件生成的词表。

    一般的,如果你想让文法B使用文法A的记号类型(无论什么文法类型),你必须首先对A运行ANTLR。例如,一个树文法用到了分析器文法的词表,应该在ANTLR生成了分析器之后再去处理树文法。

    例如,当你想让一个词法分析器和一个语法分析器共享同一个词表空间的时候,你要做的就是去把它们放到同一个文件中,设置它们的导出词表到同一个空间。如果它们在分开的文件中,把语法分析器的导入词表选项设置为词法分析器的导出词表,除非记号都定义在语法分析器中,这时,换一下导入/导出的关系让词法分析器使用语法分析器的导出词表。

    词表的一些使用技巧

    如果你的文法在不同的文件中,你仍想让它们共享全部或部分记号空间,该怎么办。有2种解决方案:(1) 让文法导入同样的词表 (2) 让文法继承同一个父文法,该父文法含有记号空间。

    第一个方案在下面情况使用,你有2个词法分析器和2个语法分析器,语法分析器必须要处理从根本上就不同的输入部分。ANTLR 2.6.0发行版examples/java/multiLexer中的例子就属于这种情况。javadoc注释和Java代码部分的词法分析和语法分析过程都不一样。javadoc词法分析器有必要识别"*/"中止注释的词法结构,但它一般让Java语法分析器用打开/关闭的记号引用来嵌套运行javadoc语法分析器:

    javadoc
    : JAVADOC_OPEN
    {
    DemoJavaDocParser jdocparser =
    new DemoJavaDocParser(getInputState());
    jdocparser.content();
    }
    JAVADOC_CLOSE
    ;

    问题在于:javadoc词法分析器定义了JAVADOC_CLOSE,即也定义了它的记号类型。不幸的是Java语法分析器的词表基于Java词法分析器而不是javadoc词法分析器。 要让javadoc词法分析器和java词法分析器都可以看到JAVADOC_CLOSE (并且有同样的记号类型),2个词法分析器都要导入含有这种记号类型定义的词表。这里有DemoJavaLexer和DemoJavaDocLexer的头部:

    class DemoJavaLexer extends Lexer;
    options {
    importVocab = Common;
    }
    ...
    class DemoJavaDocLexer extends Lexer;
    options {
    importVocab = Common;
    }
    ...

    CommonTokenTypes.txt有:

    Common // name of the vocab
    JAVADOC_CLOSE=4

    共享词表的第二种方案在下面情况使用,你有1个语法分析器和3个不同的词法分析器(比如说为不同类型的C)。如果你只想语法分析器空间利用率高,语法分析器必须可以访问3个词法分析器的词表,去掉文法不用的结构(大概可以用语义断言)。给出CLexer,GCCLexer和MSCLexer,CLexer作为父文法定义出所有记号的集合。例如,如果MSCLexer需要"_int32",那么在CLexer中定义一个所有词法分析器可见的记号类型:

    tokens {
    INT32;
    }

    在MSCLexer中,你可以给它实际意义的字符。

    tokens {
    INT32="_int32"
    }

    用这种方法,3个词法分析器共享同一个记号空间,允许你用一个语法分析器识别多种C的输入。

    Version: $Id: //depot/code/org.antlr/release/antlr-2.7.6/doc/vocab.html#1 $
    posted @ 2007-11-24 17:40 CowNew开源团队 阅读(2203) | 评论 (0)编辑 收藏

    原文:http://blog.csdn.net/nileel/archive/2007/04/17/1567656.aspx

    Java和C#都提供了对网络的不同抽象层,编程人员可以使用不同的网络接口完成对网络的操作。

    Java C#
    应答/请求:
    java.net.URL和java.net.URLConnection。
    System.Net.WebRequest。

    协议:
    TCP/IP协议使用java.net.Socket和java.net.ServerSocket;
    UDP协议使用java.net.DatagramSocket和java.net.MulticastSocket。
    CP/IP协议使用System.Net.Sockets.TCPListener和System.Net.Sockets.TCPClient;
    UDP协议使用TSystem.Net.Sockets.UDPClient

    原始套接字层:
    没有。
    System.Net.Sockets.Socket


      应答/请求层可以用于HTTP类的请求,其中的一端开始启动一个连接,发送一些字节的数据,然后停止,等待对方作为应答发回的一些字节。对于象流这样更灵活的操作,协议层的用处更大。对于大多数的Java编程人员来说,除非需要完成性能非常高的网络操作,不需要对套接字进行直接控制。如果需要。C#仍然提供了对原始的Berkeley套接字进行控制的能力。


    应答/请求层:

      这个层次抽象掉了所有网络层的细节,提供了一个可以双向传输数据的象流那样的接口。Java可以接受HTTP URL,并通过下面的命令完成GET命令:

    URL url= new URL( "http://to.post.to.com" );
    URLConnection urlConnection url.openConnection();
    InputStream input urlConnection.getInputStream();
    ... read stuff from input ...
    input.close();

      C#通过System.Net.WebRequest对象完成同样的功能:

     WebRequest request= WebRequestFactory.Create(
      "http://to.post.to.com" );
     Stream input request.GetResponse().GetResponseStream();
     ... read stuff from input ...
     input.Close();

      二种语言都隐藏了底层的套接字创建HTTP协议要求,而是提供了编程人员可以用来发送和接收数据的流。与C#中的Stream类一样,WebRequest类有可以异步地获得流进行写或从中读数据的流的方法,或者可以从中读取数据的WebResponse对象。

      协议层:

      对于熟悉java.net.Socket的Java编程人员对于System.Net.Sockets.TCPClient应该非常熟悉,因为二者是非常相似的。由于编程人员无须处理套接字的实现,而只须返回一个可供使用的流,因此二者的API和功能都非常相似。

      在Java中可以使用下面的命令实现一个非常简单的telnet客户端:

    Socket telnet= new Socket( "telnet.host.com", 23 );
    OutputStream output= telnet.getOutputStream();
    InputStream input= telnet.getInputStream();

      二个流都可用于与telnet同telnet.host.com的连接中。同样功能的程序可以以相同的风格在C#中用下面的方式实现:

    TCPClient telnet= new TCPClient( "telnet.host.com", 23 );
    Stream telnetStream= telnet.GetStream();
    StreamWriter output =new StreamWriter( telnetStream );
    StreamReader input =new StreamReader( telnetStream );


      接收TCP/IP连接在二种语言中几乎是相同的。在Java中,可以用下面的命令建立、并接收TCP/IP连接:

    ServerSocket server= new ServerSocket( 23 );
    Socket accept =server.accept();


      在C#中的实现方式如下:

    TCPListener server= new TCPListener( 23 );
    server.Start();
    Socket accept= server.Accept();


      在二种语言中,每个接收的套接字都需要单独处理。在Java中,比较好的方法(直到Java 1.4)是为每个接收的套接字产生一个线程。在C#中也可以作同样的处理,Socket类提供了使用带有select方法的事件驱动的接口。(在事件驱动方式下对套接字编程已经超出了本文的范围。)

      原始套接字层:

      这一部分的内容对于大多数Java程序员来说都是陌生的。由于被java.net.Socket和 java.net.DatagramSocket二个类进行了抽象,只使用Java编程语言的编程人员几乎无需了解Berkeley套接字的实现。通过对Berkeley Socket类进行操作,同样可以实现Java中的流功能。
    至此,我们已经用C#中的命令实现了大多数在Java中被抽象的功能━━对I/O和网络的操作。
    posted @ 2007-11-23 00:02 CowNew开源团队 阅读(607) | 评论 (0)编辑 收藏

    一篇介绍写自定义浏览器的很好的文章:
    from:http://www.codeproject.com/csharp/ExtendedWebBrowser.asp

    Sample Image

    Contents

    1. Introduction
    2. The goals, challenges, and solutions
    3. Creating the extended WebBrowser component
    4. Using the component
    5. Conclusion

    1: Introduction

    .NET 2.0 has a new WebBrowser control in the System.Windows.Forms namespace. This control itself is very useful, but doesn't supply some events that might be needed in certain situations. This article explains how to extend the WebBrowser control and add functionality for things like pop-up blocking, script error handling, and handling new windows in a tabbed browser environment.

    For extending the WebBrowser control, some features are not documented in the Help files of the .NET Framework. Not letting us be stopped by the "This method supports the .NET Framework infrastructure and is not intended to be used directly from your code." message, it is possible to create an object that implements IWebBrowser2 and use all the functionality of the underlying browser. Besides this, DWebBrowserEvents2 can be implemented for adding events to the control.

    This article assumes that you have already some knowledge of the browser interfaces IWebBrowser2 and DWebBrowserEvents2. Some knowledge about COM Interop and interfaces is also required.

    2: The goals, challenges, and solutions

    The goals of this component are:

    • Handling script errors in a neat way
    • Blocking unwanted pop-ups
    • Enabling functionality for tabbed browsing or MDI browsing
    • Making sure that a window is closed when it is closed by script

    This section explains the problems associated with the goals and their solutions, in a short form. The next section goes more into the coding details.

    Handling Script Errors

    The WebBrowser control has a ScriptErrorsSuppressed property... Setting this property to true does actually a bit more than it is supposed to. It not only disables the script error dialog, but also the dialog for logging on to a secure website with user certificates... What if we still want that functionality, or we would like to be notified when a script error has taken place, or we would like to know all the details about the script error?

    The script error can be caught by the HtmlWindow.Error event. This event fires whenever a script error occurs, with all the details. The challenge is that HtmlWindow is to be accesed with the HtmlDocument object, which is not always available. HtmlDocument comes available as soon as the Navigated event is fired. But what if the user refreshes the browser with F5? Sorry, the Navigated event doesn't fire. After some testing, I found that the only reliable way was to use the DownloadComplete event, which is not part of the default WebBrowser control.

    Solution:

    1. Implement DWebBrowserEvents2
    2. Create a DownloadComplete event
    3. When DownloadComplete fires, subscribe to the HtmlWindow.Error event
    4. Use the error event for obtaining the script error information
    5. Set the Handled property to true to suppress the script error

    Blocking unwanted pop-ups

    Pop-ups are most of the time not very welcome, or could be inappropriate. To block these things, some additional information is needed. NewWindow3 gives this information when the user uses Windows XP SP2, or Windows 2003 SP1 or better. If this event is not fired, NewWindow2 takes its place. When NewWindow3 is fired, you can check:

    • If the user initiated the action that leads to the new window
    • If the user holds the override key (the Ctrl Key)
    • If it is a pop-up displayed because of a window that is closing
    • The URL that is going to be opened
    • And more...

    Using NewWindow3 clearly is very interesting for this purpose. To use this event, DWebBrowserEvents2 needs to be implemented.

    Solution:

    1. Implement DWebBrowserEvents2
    2. Create a new event and a new event arguments class
    3. Launch this event with the appropriate information
    4. After the event is fired, see if the navigation needs to be canceled

    Enabling functionality for tabbed browsing or MDI browsing

    Tabbed browsing seems to gain popularity these days. For Internet Explorer 7, this is one of the new features. The challenge in tabbed browsing is that you need to create a window when this is needed by scripts or links. Besides this, window name resolution should work over multiple windows or tabs. (For example: <A href="http://SomeSite" target="SomeWindowName"/>) To achieve this, the automation object (called ppDisp in the NewWindowX event, and Application in the IWebBrowser2 interface) should be passed from the new browser back to the event. To get access to the Application property, it is needed to get a reference to the underlying IWebBrowser2 interface.

    Solution:

    1. Override AttachInterfaces and DetachInterfaces
    2. Store a reference to the IWebBrowser2 interface object
    3. Create a property called Application that exposes the Application property of the interface
    4. Implement the DWebBrowserEvents2 interface
    5. Listen for NewWindow2 and/or NewWindow3 events
    6. Whenever an event is raised, create a new instance of the browser control
    7. Assign the event parameter ppDisp to the Application property of the new instance

    Making sure that a window is closed when it is closed by script

    When you invoke window.close() in JScript, it looks like the WebBrowser control hangs. Somehow, it can't be used for navigation, nor can it be used for anything else. It would be nice if we know when this happens. There are several events that fire when this happens, but none of the events gives us actually the information needed. Overriding WndProc and seeing if the parent is notified that the browser is destroyed, is the only reliable solution. (If someone knows how to get WindowClosing to work, it would be nice here!)

    Solution:

    1. Override WndProc
    2. Check for the message WM_PARENTNOTIFY
    3. Check for the parameter WM_DESTROY
    4. If this is the case, fire a new event (this event is called Quit, in the example)

    3: Creating the extended WebBrowser component

    From the last section, we have seen that all of this basically comes down to two things:

    1. Implement an object of type IWebBrowser2, for obtaining the Application property of the browser
    2. Implement DWebBrowserEvents2 for firing events

    Implementing IWebBrowser2

    The WebBrowser control has two methods that are undocumented: AttachInterfaces() and DetachInterfaces(). These methods need to be used when you want to obtain a reference to the IWebBrowser2 interface.

    Collapse
      /// <summary>
    /// An extended version of the <see cref="WebBrowser"/> control.
    /// </summary>
    public class ExtendedWebBrowser : System.Windows.Forms.WebBrowser
    {
    private UnsafeNativeMethods.IWebBrowser2 axIWebBrowser2;
    /// <summary>
    /// This method supports the .NET Framework
    /// infrastructure and is not intended
    /// to be used directly from your code. 
    /// Called by the control when the underlying
    /// ActiveX control is created. 
    /// </summary>
    /// <param name="nativeActiveXObject"></param>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void
    AttachInterfaces(object nativeActiveXObject)
    {
    this.axIWebBrowser2 =
    (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
    base.AttachInterfaces(nativeActiveXObject);
    }
    /// <summary>
    /// This method supports the .NET Framework infrastructure
    /// and is not intended to be used directly from your code. 
    /// Called by the control when the underlying
    /// ActiveX control is discarded. 
    /// </summary>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void DetachInterfaces()
    {
    this.axIWebBrowser2 = null;
    base.DetachInterfaces();
    }
    ...
    }

    Next, we can add the Application property.

    /// <summary>
    /// Returns the automation object for the web browser
    /// </summary>
    public object Application
    {
    get { return axIWebBrowser2.Application; }
    }

    This property can be used for creating a new window, and redirecting the browser to this new window, when a new window event is fired.

    Implementing DWebBrowserEvents2

    The following events are implemented in this sample:

    • NewWindow2 and NewWindow3 (for blocking pop-ups and creating new windows)
    • DownloadBegin and DownloadComplete (for handling script errors)
    • BeforeNavigate2 (if you want to see where you're going before even starting to get there)

    To neatly implement DWebBrowserEvents2, it is best to create a privately nested class in the component. This way, all the events that are needed are on one place and easy to find. When we instantiate this class, we provide a reference to the caller, whose methods can be invoked for raising the events we need.

    Events are not attached at component construction, but a bit later. There are two methods here that provide this and can be overridden. These are CreateSink() and DetachSink(). When adding this all up, we get something like this (note that some code has been cut for readability):

    Collapse
      /// <summary>
    /// An extended version of the <see cref="WebBrowser"/> control.
    /// </summary>
    public class ExtendedWebBrowser : System.Windows.Forms.WebBrowser
    {
    // ... (More code here)
    System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
    WebBrowserExtendedEvents events;
    /// <summary>
    /// This method will be called to give
    /// you a chance to create your own event sink
    /// </summary>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void CreateSink()
    {
    // Make sure to call the base class or the normal events won't fire
    base.CreateSink();
    events = new WebBrowserExtendedEvents(this);
    cookie = new AxHost.ConnectionPointCookie(this.ActiveXInstance,
    events, typeof(UnsafeNativeMethods.DWebBrowserEvents2));
    }
    /// <summary>
    /// Detaches the event sink
    /// </summary>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void DetachSink()
    {
    if (null != cookie)
    {
    cookie.Disconnect();
    cookie = null;
    }
    }
    /// <summary>
    /// Fires when downloading of a document begins
    /// </summary>
    public event EventHandler Downloading;
    /// <summary>
    /// Raises the <see cref="Downloading"/> event
    /// </summary>
    /// <param name="e">Empty <see cref="EventArgs"/></param>
    /// <remarks>
    /// You could start an animation
    /// or a notification that downloading is starting
    /// </remarks>
    protected void OnDownloading(EventArgs e)
    {
    if (Downloading != null)
    Downloading(this, e);
    }
    // ... (More code here)
        #region The Implementation of DWebBrowserEvents2 for firing extra events
    //This class will capture events from the WebBrowser
    class WebBrowserExtendedEvents :
    UnsafeNativeMethods.DWebBrowserEvents2
    {
    public WebBrowserExtendedEvents() { }
    ExtendedWebBrowser _Browser;
    public WebBrowserExtendedEvents(ExtendedWebBrowser
    browser) { _Browser = browser; }
          #region DWebBrowserEvents2 Members
    // ... (More code here)
    public void DownloadBegin()
    {
    _Browser.OnDownloading(EventArgs.Empty);
    }
    public void DownloadComplete()
    {
    _Browser.OnDownloadComplete(EventArgs.Empty);
    }
    // ... (More code here)
          #endregion
    }
        #endregion
    }

    4: Using the component

    In the last section, we created a new component. Now, it's time to use the new events and get the maximum functionality out of the browser. For each of the goals, the details are explained here.

    Handling the script errors

    In the sample application, there is a tool window that simply shows a list of errors that occured, with their details. A single-instance class holds the script errors' information and notifies the subscribers when this information has been changed. For handling these script errors, the BrowserControl first attaches to the DownloadComplete event, and next subscribes to the HtmlWindow.Error event. When this event is fired, we register the script error and set the Handled property to true.

    Collapse
      public partial class BrowserControl : UserControl
    {
    public BrowserControl()
    {
    InitializeComponent();
    _browser = new ExtendedWebBrowser();
    _browser.Dock = DockStyle.Fill;
    // Here's the new DownloadComplete event
    _browser.DownloadComplete +=
    new EventHandler(_browser_DownloadComplete);
    // Some more code here...
    this.containerPanel.Controls.Add(_browser);
    // Some more code here...
    }
    void _browser_DownloadComplete(object sender, EventArgs e)
    {
    // Check wheter the document is available (it should be)
    if (this.WebBrowser.Document != null)
    // Subscribe to the Error event
    this.WebBrowser.Document.Window.Error +=
    new HtmlElementErrorEventHandler(Window_Error);
    }
    void Window_Error(object sender, HtmlElementErrorEventArgs e)
    {
    // We got a script error, record it
    ScriptErrorManager.Instance.RegisterScriptError(e.Url,
    e.Description, e.LineNumber);
    // Let the browser know we handled this error.
    e.Handled = true;
    }
    // Some more code here
    }

    Blocking unwanted pop-ups, and enabling functionality for tabbed browsing or MDI browsing

    Handling pop-ups should be user configurable. For the purpose of demonstration, I've implemented four levels, ranging from blocking nothing to blocking every new window. This code is part of the BrowserControl, and shows how to do this. After the new window is allowed, the example shows how to let the new browser participate in the window name resolution.

    Collapse
    void _browser_StartNewWindow(object sender,
    BrowserExtendedNavigatingEventArgs e)
    {
    // Here we do the pop-up blocker work
    // Note that in Windows 2000 or lower this event will fire, but the
    // event arguments will not contain any useful information
    // for blocking pop-ups.
    // There are 4 filter levels.
    // None: Allow all pop-ups
    // Low: Allow pop-ups from secure sites
    // Medium: Block most pop-ups
    // High: Block all pop-ups (Use Ctrl to override)
    // We need the instance of the main form,
    // because this holds the instance
    // to the WindowManager.
    MainForm mf = GetMainFormFromControl(sender as Control);
    if (mf == null)
    return;
    // Allow a popup when there is no information
    // available or when the Ctrl key is pressed
    bool allowPopup = (e.NavigationContext == UrlContext.None)
    || ((e.NavigationContext &
    UrlContext.OverrideKey) == UrlContext.OverrideKey);
    if (!allowPopup)
    {
    // Give None, Low & Medium still a chance.
    switch (SettingsHelper.Current.FilterLevel)
    {
    case PopupBlockerFilterLevel.None:
    allowPopup = true;
    break;
    case PopupBlockerFilterLevel.Low:
    // See if this is a secure site
    if (this.WebBrowser.EncryptionLevel !=
    WebBrowserEncryptionLevel.Insecure)
    allowPopup = true;
    else
    // Not a secure site, handle this like the medium filter
    goto case PopupBlockerFilterLevel.Medium;
    break;
    case PopupBlockerFilterLevel.Medium:
    // This is the most dificult one.
    // Only when the user first inited
    // and the new window is user inited
    if ((e.NavigationContext & UrlContext.UserFirstInited)
    == UrlContext.UserFirstInited &&
    (e.NavigationContext & UrlContext.UserInited)
    == UrlContext.UserInited)
    allowPopup = true;
    break;
    }
    }
    if (allowPopup)
    {
    // Check wheter it's a HTML dialog box.
    // If so, allow the popup but do not open a new tab
    if (!((e.NavigationContext &
    UrlContext.HtmlDialog) == UrlContext.HtmlDialog))
    {
    ExtendedWebBrowser ewb = mf.WindowManager.New(false);
    // The (in)famous application object
    e.AutomationObject = ewb.Application;
    }
    }
    else
    // Here you could notify the user that the pop-up was blocked
    e.Cancel = true;
    }

    The reason the event is called StartNewWindow is that the code design guidelines do not allow an event to begin with "Before" or "After". "NewWindowing" doesn't have the same kind of ring to it :)

    Using the Quit event

    When the Quit event is fired, it's simply a matter of finding the right window or tab to close, and Dispose the instance.

    5: Conclusion

    The WebBrowser control is a good control for enabling web content in Windows applications. The additions in this article can be used to overcome the obstacles that developers face when they have no control over what web pages or other content the user might visit with their application. Hopefully, the next version of the .NET Framework will give us a little extra.

    The sample application and source

    The sample application is not a flashy UI, but it does demonstrate everything about this article. The code is commented, and hopefully gives enough information for helping you put your own solution together.

    Acknowledgements

    I would like to thank the following persons that made part of this article possible:

    • The technique for DWebBrowserEvents2 was in the bug list of Microsoft .NET 2.0. This has been used with modification.
    • The technique for WndProc was told by someone called "JoeBlow" on the MSDN forums, who had it derived from the MSKB article #253219.

    This is my first article on The Code Project. Please excuse me for my English. Thanks for reading! If you can add anything or have suggestions or tips, please post a message below.

    License

    This code is copyrighted by The Wheel Automatisering in The Netherlands. Some rights are reserved.

    The code in this license may be used for any purpose, just let your users know where it came from, and share derived code under the same license as this one. Don't blame me if something goes wrong. More information can be found here.

    If you wish to use and/or publish this in commercial closed-source applications, you have my consent. You may use this code under your own license when you do so.

    History

    • 27th of March 2006: First post of this article.

    About Jeroen Landheer


    I am
    - born in The Netherlands
    - living in Chile together with my wife.
    - a Microsoft Certified Professional Developer on all 3 areas (Windows, Web and Enterprise)
    - an MCITP on Microsoft SQL Server 2005 (Database Administrator)
    - an active programmer for about 14 years.
    - a business owner, of a Dutch company called "The Wheel Automatisering" (http://www.thewheel.nl)
    - a coder in C#, VB.Net and Managed C++.
    - someone who likes to share knowledge

    For fun I like to go out with my dogs, enjoy the sun or write some articles that I share with the community.

    Click here to view Jeroen Landheer's online profile.

    posted @ 2007-11-20 13:27 CowNew开源团队 阅读(1758) | 评论 (0)编辑 收藏

    from ftplib import FTP
    import time,os,sys

    print "按回车开始备份"
    raw_input()

    ftp=FTP()
    ftp.set_debuglevel(2)
    ftp.connect('服务器IP', '21')
    ftp.login("用户名","密码")
    ftp.cwd('/wwwroot/bbs/DataBase')
    now = time.localtime()
    blocksize = 1024
    poststr = str(now.tm_year)+"-"+str(now.tm_mon)+"-"+str(now.tm_mday)
    filename=r'e:\网站备份\bbs\database\Dbbs7'+poststr+'.asp'
    if(os.path.isfile(filename)):
        print "文件已经存在"
        raw_input()
        sys.exit()
    file_handler = open(filename,'w').write
    ftp.retrbinary("RETR Dbbs7.asp", file_handler, blocksize)
    ftp.quit()
    print "下载完毕"
    raw_input()

     

    posted @ 2007-11-20 10:51 CowNew开源团队 阅读(469) | 评论 (0)编辑 收藏

    实现了一个简单的请假审批功能,展示了一个常用JBPM API的使用,工程下载地址:

    http://www.blogjava.net/Files/huanzhugege/myjbpm002.zip
    posted @ 2007-11-19 20:17 CowNew开源团队 阅读(578) | 评论 (0)编辑 收藏

     

    已经可以比较好的运行JBPM了,但是如果能以图形化的方式显示工作流,并且把当前节点高亮显示,这样可用性就更好了,用户可以很轻松的看到当前流程到哪个节点了。

           我发现JBPMstarters-kit的例子中就有类似的效果,所以决定分析一下它是怎么实现的。

           打开网页,浏览到有显示当前工作流节点的页面,查看到此页面的地址为task.jsp,发现其中的核心代码如下:

    <jbpm:processimage task="${taskBean.taskInstanceId}"/>

           这里使用了JBPM提供的jbpm:processimage标签,此标签定义在jbpm.tld中,这个Tag的类为org.jbpm.webapp.tag.ProcessImageTag。所以只要使用这个标签我们就可以很轻松的在Web页面中显示图形化的工作流了。

           那么如果是在SwingSWT等非Web界面中也想显示这种效果怎么办呢?那么让我们来分析一下ProcessImageTag类。

     private void retrieveByteArrays() {

        try {

          FileDefinition fileDefinition = processDefinition.getFileDefinition();

          gpdBytes = fileDefinition.getBytes("gpd.xml");

          imageBytes = fileDefinition.getBytes("processimage.jpg");

        } catch (Exception e) {

          e.printStackTrace();

        }

     }

           gpd.xml中记录的是节点的位置关系,processimage.jpg是图形化的图片(只是基图,没有高亮显示当前节点),这两个文件是JBPMEclipse插件自动生成的。

           得到流程实例当前节点的方法:

     private void initialize() {

        JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();

        if (this.taskInstanceId > 0) {

               TaskInstance taskInstance = jbpmContext.getTaskMgmtSession().loadTaskInstance(taskInstanceId);

               currentToken = taskInstance.getToken();

        }

        else

        {

               if (this.tokenInstanceId > 0)

                      currentToken = jbpmContext.getGraphSession().loadToken(this.tokenInstanceId);

        }

        processDefinition = currentToken.getProcessInstance().getProcessDefinition();

     }

           currentToken中可以得到当前节点在显示的时候的长度、宽度、横纵坐标等值。得到的方式如下:

     private int[] extractBoxConstraint(Element root) {

        int[] result = new int[4];

        String nodeName = currentToken.getNode().getName();

        XPath xPath = new DefaultXPath("//node[@name='" + nodeName + "']");

        Element node = (Element) xPath.selectSingleNode(root);

        result[0] = Integer.valueOf(node.attribute("x").getValue()).intValue();

        result[1] = Integer.valueOf(node.attribute("y").getValue()).intValue();

        result[2] = Integer.valueOf(node.attribute("width").getValue()).intValue();

        result[3] = Integer.valueOf(node.attribute("height").getValue()).intValue();

        return result;

     }

           这样用<div/>标签就可以将当前节点框上一个红色的框框了:

               jspOut.println("<div style='position:relative; background-image:url(" + imageLink + "); width: " + imageDimension[0] + "px; height: " + imageDimension[1] + "px;'>");

           //详细代码参考:writeTable方法

    原来高亮显示是在原有的图片上叠加一个高亮的框框实现的。所以如果要显示在SwingSWT中的话也只要参考这个思路,在当前节点位置显示一个高亮的框框就可以了!

    posted @ 2007-11-19 17:44 CowNew开源团队 阅读(6048) | 评论 (8)编辑 收藏

    本版主要新增特性:
      1、对Show语句的支持

           自从CowNewSQL2.1开始,我们提供了对Show语句的支持,主要用来查看系统中的表定义、字段定义、支持的函数等。由于各个数据库中取得这些元信息的方式各有不同,经常需要关联查询很多系统表才能搬到,为了简化用户的使用,我们创新性的设计了Show系列语句,这样您至少使用非常短的语句就可以实现以前需要编写很复杂的语句才能实现的功能。

           Show语句语法列表:

    1show  tables:显示系统中默认Schema下的所有表的表名。

    2show  tables Schema名:显示指定Schema下的所有表的表名。例子:show tables DEMO

    3show  functions:显示系统支持的函数的列表。

    4show  functioncolumns:显示系统支持的函数参数以及返回值的详细说明。

    5show  tablecolumns 表名:显示指定表的数据列信息。例子:show  tablecolumns table_1。
    2、提供了JDBC驱动的使用方式 

           自从CowNewSQL2.1开始,我们提供了以JDBC驱动方式使用的支持(支持最新的JDBC4.0标准)。通过这种方式用户无需修改系统的任何代码,只要修改原有的JDBC连接字符串就可以轻松的将CowNewSQL融入系统,使用CowNewSQLJDBC驱动后系统中所有的SQL语句在送到数据库系统中执行前都将会自动进行翻译。

           CowNewSQLJDBC驱动类为:com.cownew.cownewsql.imsql.jdbc.DBDriver;连接字符串格式为:jdbc:cownewsql:目标数据库类型:目标数据库JDBC驱动类:JDBC连接字符串。

    使用方式举例:

           原有程序连接到Oracle数据库,使用的Oracle驱动类为oracle.jdbc.driver.OracleDriverJDBC连接字符串为:jdbc:oracle:thin:@192.168.88.128:1521:XE

           我们只要将CowNewSQLJar包(包括cownewsql***.jarantlr.jarcommons-lang**.jarretrotranslator-runtime**.jar等)加入程序的ClassPath,然后修改使用的数据库驱动为:com.cownew.cownewsql.imsql.jdbc.DBDriver,然后修改JDBC连接字符串为:jdbc:cownewsql:oracle:oracle.jdbc.driver.OracleDriver:jdbc:oracle:thin:@192.168.88.128:1521:XE

           这样我们无需修改任何代码就将CowNewSQL翻译器轻松的植入了原有系统。
    3、增加了对Alter Table语句的支持;修正了Convert函数在各个数据库中取值范围不一致的Bug;改进了方言管理器的实现机制;修复了若干Bug。

    下载地址1:http://www.blogjava.net/Files/huanzhugege/cownewsql-2.1.zip
    下载地址2:http://www.cownew.com/Soft/UploadSoft/cownewsql-2.1.zip


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

           由于种种原因,各个数据库系统的SQL语句语法以及支持的函数都不尽相同,这造成了如下两个问题:(1)系统在多个不同数据库之间移植变得非常困难,特别是需要维护多个数据库版本的时候;(2)开发人员必须对各种数据库的语法差异非常了解,这加大了开发难度。

           虽然Hibernate通过HQL等技术部分的解决了跨数据库移植的问题,但是在对性能要求比较高的场合还是需要直接使用SQL语句访问数据库的,在这种情况下如何编写能被不同数据库支持的SQL语句就成了。目前解决这种差异的最常用的技术就是SQL语句翻译,使用SQL翻译器可以将SQL语句翻译为在不同的数据库中支持的特定平台的SQL语句。CowNewSQL就是这样一款产品。

           CowNewSQL简化了跨数据库产品的开发,比如取当前日期在MSSQL中是“SELECT GETDATE()”,在MYSQL中是“SELECT NOW()”,在Oracle中是“SELECT SYSDATE FROM DUAL”,使用CowNewSQL以后您只要使用“SELECT NOW()”,那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句,而且CowNewSQL的兼容性也非常好,比如“SELECT NOW()”写成“SELECT GETDATE()”同样可以被正确的翻译;取数据库前10条记录,在MSSQL中是“Select top 10 from T_1”、在MYSQL中是“SELECT  LIMIT 0, 10 ”、在Oracle中是“SELECT  FROM DUAL WHERE ROWNUM <= 10”,使用CowNewSQL以后您只要使用“Select top 10 from T_1”,那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句。

           CowNewSQL还通过变通的方式对目标数据库不直接支持的语法进行了支持。比如MYSQL是不支持“select * from t1 where fid in(select fid from t2 limit 0,5)”这样在子查询中的Limit语句的,CowNewSQL通过将子查询进行二次结果集包装的方式巧妙的对其进行了支持,“delete from T_SaleInvoice where FId in(select top 5 FParentId from T_SaleInvoiceDetails)”通过CowNewSQL的翻译以后就成了“DELETE FROM T_SaleInvoice WHERE FId IN (select * from(SELECT FParentId FROM T_SaleInvoiceDetails LIMIT 0, 5 ) t_temp_sub)”这样被MYSQL支持的语法了;MYSQL中没有提供计算两个日期之间月份差异的函数,CowNewSQL通过组合其他日期函数的方式模拟了这个函数,这样使用者只要使用MONTHS_BETWEEN函数即可了,无需关心内部的差异。

           CowNewSQL支持如下几种类型的SQL语句:CreateTable/AlterTable/DropTable/CreateIndex/DropIndex/Select/Insert/Delete/Update/Show;支持子查询、JoinUnion等高级的SQL特性;支持日期(包括取当前日期、从日期中提取任意部分、计算日期差异、日期前后推算等)、数学(包括取绝对值、取PI值、四舍五入、对数计算、随机数等)、字符串(包括取子字符串、取字符串长度、字符串截断、大小写转换等)、基本数据处理(包括数字字符串互转、日期转字符串、非空判断等)等函数。

    posted @ 2007-11-17 15:27 CowNew开源团队 阅读(2922) | 评论 (10)编辑 收藏

    定义一个ActionHandler:

    package com.test;

    import org.jbpm.graph.def.ActionHandler;
    import org.jbpm.graph.exe.ExecutionContext;

    public class MyAction implements ActionHandler
    {

     private static final long serialVersionUID = 1L;

     private String message;

     public String getMessage()
     {
      return message;
     }

     public void setMessage(String message)
     {
      this.message = message;
     }

     public void execute(ExecutionContext executionContext) throws Exception
     {
      System.out.println(message);
     }

    }


    定义一个流程文件:

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

    <process-definition
      xmlns="urn:jbpm.org:jpdl-3.1"
      name="simple">
       <start-state name="start">
          <transition name="to_state" to="first">
             <action name="action" class="com.test.MyAction">
                <message>Going to the first state!</message>
             </action>
          </transition>
       </start-state>
       <state name="first">
          <transition name="to_end" to="end">
             <action name="action" class="com.test.MyAction">
                <message>About to finish!</message>
             </action>
          </transition>
       </state>
       <end-state name="end"></end-state>
    </process-definition>

    定义流程驱动类:

    package com.test;

    import java.io.IOException;
    import java.io.InputStream;

    import org.jbpm.graph.def.ProcessDefinition;
    import org.jbpm.graph.exe.ProcessInstance;

    public class Main
    {
     public static void main(String[] args) throws IOException
     {
      InputStream stream = Main.class.getResourceAsStream("processdefinition.xml");
      ProcessDefinition processDefinition = ProcessDefinition
        .parseXmlInputStream(stream);
      stream.close();
      ProcessInstance instance = new ProcessInstance(processDefinition);
      while (!instance.hasEnded())
      {
       instance.signal();
      }
     }
    }


    将jbpm***.jar、commons-logging**.jar和dom4j.jar三个包加入classpath就可以了。
    执行结果:
    Going to the first state!
    About to finish!
    posted @ 2007-11-16 13:51 CowNew开源团队 阅读(2544) | 评论 (0)编辑 收藏

    package com.sample;

    import org.jbpm.graph.def.ProcessDefinition;
    import org.jbpm.graph.exe.ProcessInstance;

    public class Main
    {
     public static void main(String[] args)
     {
      ProcessDefinition processDefinition = ProcessDefinition
        .parseXmlResource("simple/processdefinition.xml");
      ProcessInstance instance = new ProcessInstance(processDefinition);
      while (!instance.hasEnded())
      {
       instance.signal();
      }
     }
    }



    不需要人工参与,不需要持久化状态,流程一次性短时间内运行完成,其实这是把JBPM当成普通的流程图运行引擎来用了,呵呵,大材小用了,:),不过省的自己写流程运行引擎了。
    posted @ 2007-11-15 15:29 CowNew开源团队 阅读(507) | 评论 (0)编辑 收藏

    本章翻译人 CowNew开源团队 周晓

    记号流

    长久以来, 词法分析器和语法分析器是紧紧耦合在一起的; 也就是说, 你不可以在他们中间做任何事情,也不能修改记号流。但是,用记号流来处理词法分析器和语法分析器之间的连接的话,会给代码识别和翻译带来极大的帮助。这个想法类似于Java的输入输出流,利用输入输出流你可以用管道的方式处理多个深加工的数据流。

    介绍

    ANTLR识别任何满足TokenStream接口的记号流对象(2.6以前的版本, 这个接口叫做Tokenizer);也就是说记号流对象要实现以下的方法。

    Token nextToken();

    如图, 在分析过程中的某一时刻,从词法分析器(生产者)到语法分析器(消费者)的一般记号流会像是下面的样子。

    lexer.to.parser.tokens.gif (3585 bytes)

    最普通的记号流是一个词法分析器,但是想象一下,在词法分析器和语法分析器中间有一个流的实体,都能做哪些有趣的事情呢。比如说,你可以:

    • 过滤掉不想要的记号
    • 插入一些辅助的记号,帮助语法分析过程识别一些复杂的结构
    • 把一个流分成多个流,把某些感兴趣的记号送到不同的流中
    • 把多个记号流合并成一个流,从而“模拟”PCCTS,lex等词法分析工具的状态。

    记号流概念的优雅在于它对词法分析器和语法分析器没有影响--它们只不过是流的生产者和消费者。流对象是消费者用来生产,处理,合并或者分离记号流的过滤器。可以使已有的词法分析器和语法分析器在不修改的情况下合并成一种新的工具。

    这份文档正式提出了记号流的概念,详细描述了一些非常有用的流过滤器。

    让记号通过的记号流

    一个记号流是任何满足下面接口的对象。

    public interface TokenStream {
    public Token nextToken()
        throws java.io.IOException;
    }

    例如, 一个"没有操作"或者说仅仅是让记号通过这里的过滤器是这样工作的:

    import antlr.*;
    import java.io.IOException;
    class TokenStreamPassThrough
        implements TokenStream {
    protected TokenStream input;
    /** Stream to read tokens from */
      public TokenStreamPassThrough(TokenStream in) {
    input = in;
    }
    /** This makes us a stream */
      public Token nextToken() throws IOException {
    return input.nextToken(); // "short circuit"
    }
    }

    在下面的main()程序中,你使用这个简单的流对象从词法分析器中获得记号,然后语法分析器从流对象中获得记号。

    public static void main(String[] args) {
      MyLexer lexer =
    new MyLexer(new DataInputStream(System.in));
    TokenStreamPassThrough filter =
        new TokenStreamPassThrough(lexer);
    MyParser parser = new MyParser(filter);
      parser.startRule();
    }

    记号流过滤

    多数情况下,你希望词法分析器忽略掉空白符和注释,然而,你还希望在语法分析器必须使用注释的情况下重用词法分析器。这时,你只要为需要注释和空白符连同普通记号的情况设计一个词法分析器。然后,当你想忽略空白符的时候,只要在词法分析器和语法分析器中间加入一个过滤器,过滤掉空白符。

    针对这种情况,ANTLR提供了TokenStreamBasicFilter。你可以在不修改词法分析器的情况下让它过过滤掉任何类型的记号。下面TokenStreamBasicFilter的用法的例子中过滤掉了注释和空白符。

    public static void main(String[] args) {
      MyLexer lexer =
    new MyLexer(new DataInputStream(System.in));
    TokenStreamPassThrough filter =
        new TokenStreamPassThrough(lexer);
    filter.discard(MyParser.WS);
    filter.discard(MyParser.COMMENT);
      MyParser parser = new MyParser(filter);
      parser.startRule();
    }

    可以看到,它比修改词法分析器的词法结构要来的有效,你也会这么做的吧,因为这样你不用去构建一个记号对象。另一方面,采用这种过滤流的方法使词法分析器的设计更加灵活。

    记号流分离

    有时,在识别阶段,你想让翻译器忽略但不是丢弃输入的部分记号。比如说,你想在语法分析时忽略注释,但在翻译时又需要注释。解决办法是将注释发送到一个隐藏的记号流中,所谓隐藏,就是语法分析器没有对它进行监听。在识别期间,通过动作来检查这些隐藏的流,收集注释等等。流分离过滤器有点像棱镜把白光分离成彩虹。

    下面的图中示出了把一个记号流分成三个的情况。

    stream.splitter.gif (5527 bytes)

    让语法分析器从最上面的流中获得记号。

    用流分离器可以实现很多功能。比如,"Y-分离器"像有线电视Y连接器一样,复制符号流。如果过滤器是线程安全的而且有缓冲器缓冲,过滤器就可以同时为多个语法分析器提供记号。

    这一节描述了ANTLR提供的一个叫做TokenStreamHiddenTokenFilter的流过滤器,它工作的时候有点像给一堆硬币分类,把一分一分的放到一个箱子里,把一角一角的放到另一个箱子里,等等。这个过滤器把输入流分离成两个流,一个包含主要记号,另一个被缓冲以便以后可以访问。因为这种实现方式,无论怎么做,你都无法让语法分析器直接访问隐藏流。下面你将会看到,过滤器实际上把隐藏记号交织在主记号中。

    例子

    考虑以下的简单文法,该文法用来声明整型变量.

    decls: (decl)+
    ;
    decl : begin:INT ID end:SEMI
    ; 

    比如说有以下输入:

    int n; // list length
    /** doc */
    int f;

    假定词法分析器忽略空白符,你用过滤器把注释分离到一个隐藏流。那么现在如果语法分析器从主记号流中获得记号,它只会看到"INT ID SEMI FLOAT ID SEMI",注释在隐藏流中。实现了语法分析器可以忽略注释,而你的语义动作可以从过滤器中查询隐藏流中的记号。

    第一次识别出文法规则decl,begin记号前后没有对隐藏记号的引用,但

    filter.getHiddenAfter(end)

    返回一个对下面记号的引用

    // list length

    接下来就会访问到

    /** doc */

    第二次识别出decl

    filter.getHiddenBefore(begin)

    指向

    /** doc */

    的引用

    过滤器实现

    下图示出记号对象是如何组织记号来模拟两个不同的流。

    hidden.stream.gif (3667 bytes)

     

    因为记号是假定的,TokenStreamHiddenTokenFilter对象通过链表来连接隐藏记号和主记号。过滤器只提供了一个物理上的记号流,通过交织指针维护和管理记号次序。

    因为这个额外的指针需要把记号连接到一起,你必须要用一个叫CommonHiddenStreamToken的特殊记号对象(普通记号对象叫做CommonToken)。前面曾说过,你可以用以下的方法去指定词法分析器为特定的类制造记号。

    lexer.setTokenObjectClass("classname");

    技术上,如果不请求特殊记号对象,也可以实现同样功能的过滤器,但这样实现非常有效率而且它很容易告诉词法分析器去生成什么种类的记号。进一步说,这样实现使得它很容易去自动完成包含隐藏流信息的树结点的创建。

    这个过滤器影响ANTLR的懒惰消费。在识别每一个主记号之后, TokenStreamHiddenTokenFilter必须获取下一个记号看它是不是一个隐藏记号。因此,这个过滤器在交互程序(比如命令行)下工作的不是很好。

    怎样使用这个过滤器

    要使用TokenStreamHiddenTokenFilter,仅仅要做的是:

    • 创建词法分析器,让它创建链接隐藏记号的记号对象。
    MyLexer lexer = new MyLexer(some-input-stream);
    lexer.setTokenObjectClass(
      "antlr.CommonHiddenStreamToken"
    );
    • 创建一个TokenStreamHiddenTokenFilter对象,该对象从上面的词法分析器中获得记号。
    TokenStreamHiddenTokenFilter filter =
      new TokenStreamHiddenTokenFilter(lexer);
    • 设置TokenStreamHiddenTokenFilter要隐藏哪些记号,要丢弃哪些记号。例如,
    filter.discard(MyParser.WS);
    filter.hide(MyParser.SL_COMMENT);
    • 创建一个语法分析器,从TokenStreamHiddenTokenFilter而不是从词法分析器中获得记号。
    MyParser parser = new MyParser(filter);
    try {
    parser.startRule(); // parse as usual
    }
    catch (Exception e) {
    System.err.println(e.getMessage());
    }

    查看ANTLR指南,在preserving whitespace处有一个完整的例子。

    树的构建

    最后,在翻译阶段,如果需要这些隐藏的流记号,在遍历树的时候,则可以按正常的方式使用。怎么做才能在不打乱树文法的情况下把隐藏流的信息送给翻译器呢?很简单: 用AST结点储存这些隐藏流记号。ANTLR定义了CommonASTWithHiddenTokens来自动连接隐藏流记号到树结点; 联合一个树结点,适用于树结点的方法在这里也适用于访问这些隐藏记号。你只需要告诉语法分析器去创建这种类型的结点而不是默认的CommonAST类型的结点。

    parser.setASTNodeClass("antlr.CommonASTWithHiddenTokens");

    树结点作为记号对象的功能被创建。当ASTFactory创建树结点的时候,树结点的initialize()方法被调用。从记号创建的树结点包含隐藏记号,不管在前还是在后,都有着同样的对隐藏记号的引用。你不需要用这个结点定义,但它工作在很多翻译任务中:

    package antlr;
    /** CommonAST在初始化时把从记号中获得
    *  的隐藏记号的信息复制,用来创建结点
    */
    public class CommonASTWithHiddenTokens
    extends CommonAST {
    // 指向隐藏记号
    protected Token hiddenBefore, hiddenAfter;
    public CommonHiddenStreamToken getHiddenAfter() {
        return hiddenAfter;
      }
    public CommonHiddenStreamToken getHiddenBefore() {
        return hiddenBefore;
      }
    public void initialize(Token tok) {
    CommonHiddenStreamToken t =
          (CommonHiddenStreamToken)tok;
    super.initialize(t);
    hiddenBefore = t.getHiddenBefore();
    hiddenAfter  = t.getHiddenAfter();
    }
    }

    注意到这个结点定义假设你用了CommonHiddenStreamToken对象。如果你没有让词法分析器创建CommonHiddenStreamToken对象,就会出现运行时类下行异常。

    垃圾回收问题

    利用对主流记号的引用分隔输入流,保存隐藏流记号时,GC允许在记号流上工作。在上面的整数声明的例子中,当没有更多的对第一个SEMI记号以及第二个INT记号的引用时,comment记号将会作为垃圾回收的候选人。如果所有的记号是连在一起的,一个单独的对任意记号的引用会阻止任何记号被回收。这在ANTLR实现不是问题。

    提示

    翻译时,过滤器在保存空白符和注释方面做得很好,但在处理输出和输入相差很远的情况下,用过滤器不是一个最好的办法。例如,有3个注释散布在一个输入声明语句中,你想在翻译阶段合并到输出声明语句的头部。比起察看注释周围的每一个分析的记号,更好的办法是有一个真正实际上分开的流来保存注释以及一个方法去联系分析好的记号的组和注释流记号的组。你或许想支持像"给我在注释流上从开始分析到结束分析时最初出现的的所有记号."

    这个过滤器实现了同JavaCC中special记号及其相似的功能。Sriram Sankar (JavaCC之父) 关于特殊记号有一个非常好的想法,在1997的Dr. T's Traveling Parsing Revival and Beer Tasting Festival,出席者认同了泛化记号流的概念。现在JavaCC特殊记号功能仅仅是另一个ANTLR流过滤器,好处是你不用去为指定哪些记号是特殊的而修改词法分析器。

    记号流多路技术 (又叫 "词法分析器多状态")

    现在,考虑一下相反的问题,你想合并多个流而不是把一个流分成多个。当你的输入包含根本上不同的片段,比如说Java和JavaDoc注释,你会发现仅用一个词法分析器去识别所有的输入片段是很难的。这主要是因为合并各种部分的记号定义会造成二义性词法语言或者识别出一些错误的记号。例如,"final"在某些部分里是一个关键字,但在另一个部分里它可能会是一个标示符。同样,"@author"是一个合法的javadoc注释里的标记,但在Java代码中,它是不合法的。

    大部分人为了解决这个问题,为词法分析器设定了很多状态,在不同的部分里切换到不同的状态来工作(例如,在"读取Java模式"和"读取JavaDoc模式"中间切换)。词法分析器开始是以Java模式工作的,然后在遇到"/**"后切换到JavaDoc模式; "*/"强制切换回Java模式。

    多词法分析器

    让一个词法分析器在多个状态下工作可以解决上述的问题,但有一个更好的解决问题的办法,让多个词法分析器协同工作,生成一个记号流。为什么说这种办法更好呢?因为分开的词法分析器更利于重用(不是剪贴粘贴,而仅仅是告诉流的多元管理器去切换不同的词法分析器,就得到了一个新的词法分析器)。例如,JavaDoc词法分析器可以在解决任何有JavaDoc注释的语言问题时得到重用。

    ANTLR预设了一个记号流叫做TokenStreamSelector,可以用它在多个词法分析器间进行切换。不同词法分析器中定义的动作控制这个选择器切换输入流。考虑下面的Java代码片段。

    /** Test.
    *  @author Terence
    */
    int n;

    给出2个词法分析器,JavaLexer和JavaDocLexer,2个词法分析器的动作序列可能看起来是下面的样子:

    JavaLexer: 匹配JAVADOC_OPEN, 切换到JavaDocLexer
    JavaDocLexer: 匹配AUTHOR
    JavaDocLexer: 匹配ID
    JavaDocLexer: 匹配JAVADOC_CLOSE, 切换回JavaLexer
    JavaLexer: 匹配INT
    JavaLexer: 匹配ID
    JavaLexer: 匹配SEMI

    在Java词法分析器的文法中,你需要定义一个规则去切换到JavaDoc词法分析器(把需要切换的词法分析器记录在栈中):

    JAVADOC_OPEN
    :    "/**" {selector.push("doclexer");}
    ;

    同样地,在JavaDoc词法分析器中定义一个规则切换回去:

    JAVADOC_CLOSE
    :    "*/" {selector.pop();}
    ;

    选择器中有一个栈,所以JavaDoc词法分析器不用知道谁调用了它。

    入图,选择器和并2个词法分析器流,为下游的语法分析器提供单独的一个记号流。

    stream.selector.gif (5976 bytes)

    选择器可以为你维护流列表,所以你可以通过名字或者实际对象的引用来切换到另一个输入流。

    public class TokenStreamSelector implements TokenStream {
    public TokenStreamSelector() {...}
    public void addInputStream(TokenStream stream,
        String key) {...}
    public void pop() {...}
    public void push(TokenStream stream) {...}
    public void push(String sname) {...}
    /** Set the stream without pushing old stream */
    public void select(TokenStream stream) {...}
    public void select(String sname)
        throws IllegalArgumentException {...}
    }

    用选择器很简单:

    • 创建一个选择器。
    TokenStreamSelector selector =
    new TokenStreamSelector();
    • 为流命名(不是一定要命名--在切换的时候你可以用流对象的引用来避免使用哈希表查找)。
    selector.addInputStream(mainLexer, "main");
    selector.addInputStream(doclexer, "doclexer");
    • 选择哪一个词法分析器先从字符流中读数据。
    // start with main java lexer
    selector.select("main");
    • 语法分析器可以像用词法分析器一样使用选择器。
    JavaParser parser = new JavaParser(selector);

    词法分析器共享同一字符流

    在介绍语法分析器如何使用选择器之前,注意一下这2个词法分析器都要从同一个输入流中读取字符。以前的ANTLR2.6.0版本,每一个词法分析器都有它自己的记录行号的变量,输入字符流变量等等。为了共享同样的输入状态,ANTLR2.6.0代理词法分析器来处理字符输入到对象中,LexerSharedInputState可以被n个词法分析器共享(单线程)。为了让多个词法分析器共享状态,你创建第一个词法分析器,获得它的输入状态对象,然后在构建其它词法分析器并且需要共享输入状态的时候使用它:

    // 创建Java词法分析器
    JavaLexer mainLexer = new JavaLexer(input);
    // 创建javadoc词法分析器; 使用
    // java词法分析器的共享输入状态
    JavaDocLexer doclexer =
      new JavaDocLexer(mainLexer.getInputState());

    分析多元记号流

    就像一个词法分析器在从不同的输入片段中生产一个单独的流会遇到很多麻烦,一个单独的语法分析器在处理多记号流的时候也会遇到一些麻烦。又是同样的问题,一个记号在一个词法分析器中可能是一个关键字,在另一个词法分析器中可能会是一个标示符。把语法分析器分解成子分析器,为每一个输入片段单独处理它们的单词表,这样做同时也利于语法分析器的重用。

    下面的语法分析器文法用主词法记号的词表(用importVocab指定),在遇到JAVADOC_OPEN的时候,它创建并且调用一个JavaDoc分析器去处理接下来在注释中的记号流。

    class JavaParser extends Parser;
    options {
    importVocab=Java;
    }
    input
    :   ( (javadoc)? INT ID SEMI )+
    ;
    javadoc
    :   JAVADOC_OPEN
    {
            // 创建一个分析器去处理javadoc注释
    JavaDocParser jdocparser =
              new JavaDocParser(getInputState());
    jdocparser.content(); // 用jdocparser继续分析
    }
            JAVADOC_CLOSE
    ;

    你会发现从2.6.0版本起,ANTLR语法分析器也共享记号输入流状态。当创建"子分析器"时, JavaParser告诉它从同一输入状态对象中获取记号。

    JavaDoc分析器匹配一串标签:

    class JavaDocParser extends Parser;
    options {
    importVocab=JavaDoc;
    }
    content
    :   (   PARAM // includes ID as part of PARAM
    |   EXCEPTION
            |   AUTHOR
    )*
    ;

    当子分析器规则content结束后,控制权自然地返回给它的调用方,也就是Java分析器中的javadoc

    多记号流超前扫描的作用

    如果语法分析器需要去查看JavaDOc注释起始位置后的2个记号,那会发生什么呢?换句话说,以主分析器来看,JAVADOC_OPEN之后的记号是什么呢? 自然是记号 JAVADOC_CLOSE! 主分析器把任何JavaDoc注释都看作是一个实体,不管这个注释有多复杂; 它不用去了解注释记号流内部情况,它也不需要这么做--子分析器会去处理这件事情。

    在子分析器中,content规则后是什么记号呢?是"End of file"记号。子分析器的分析过程不能确定你的代码中将会调用怎样的方法。但这不是一个问题,因为一般情况会有一个单独的记号标示子分析过程的结束。即使因为某种原因EOF被载入到分析过程,EOF也不会出现在记号流中。

    多词法分析器vs调用另一条词法规则

    多词法分析器状态也经常被用来处理那些非常复杂的单个记号,比如说嵌入转义字符的字符串,输入"\t"应该被识别为一个字符串。针对这种情况,典型的做法是在第一个引号之后,切换词法分析器到"字符串状态"然后在识别完字符串之后切换回"普通状态"。

    所以把这种代码依靠模式做事情的方式叫做"模态"编程,这通常是一个比较差的方式。在这种复杂记号的情况下,最好是用多个规则直接指定复杂的记号。这里有一个什么时候该用多记号流和什么时候不该用的黄金规则:

    复杂的单个记号应该通过调用另一个(protected)词法规则来匹配,对一段输入片段来说应该用多个词法分析器处理此输入流并提供给分析器。

    例如,词法分析器字符串的定义应该仅仅是调用另一个规则来处理转义字符的情况:

    STRING_LITERAL
    :    '"' (ESC|~('"'|'\\'))* '"'
    ;
    protected // 不是一个记号; 仅仅被另一个规则调用
    ESC
    :    '\\'
    (    'n'
    |    'r'
    |    't'
    |    'b'
    |    'f'
    |    '"'
    |    '\''
    |    '\\'
    |    ('u')+
                 HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ...
    )
        ;

    TokenStreamRewriteEngine 简单的语法制导翻译

    在很多情况下,你希望在原代码基础上修改或者增加一段程序或数据文件。ANTLR 2.7.3 介绍了一个(只有Java/C#版本)非常简单但非常强大的类TokenStream处理以下问题:
    1. 输出语言和输入语言相似
    2. 语言元素的相对次序不改变
    参见antlr网站上的
    Syntax Directed TokenStream Rewriting

    将来

    ANTLR 2.6版本为使用记号流提供了基本结构,一旦我们有经验使用它们,今后的版本将会更加强大。

    现在的"隐藏记号"流过滤器解决"忽略但保存空白符"的问题解决的很好,但它在很多情况下不能很好的处理注释。例如,在真正的翻译过程中,你想在各种单独的树结点上收集注释(像DECL或者METHOD)而不是把它们分布在树的各个地方。你迫切需要一个流分离器缓冲注释到一个隔离的流中,这时你就可以说"给我在识别这个规则上所用掉的所有注释"或者 "给我这2个记号之间的所有注释." 这几乎是你在注释翻译时所需要的所有功能。

    记号流会带来很多便利。大部分人不经常思考关于记号流的事,使得很难去想象可以在其他一些什么地方可以变的更好。让思想更奔放一些。怎样处理嵌入语言的输入片段,就像你所能看到的Java中嵌入SQL(每一个输入的部分被分开并通过不同的流)。怎么样分析含有和不含有调试信息的Java .class文件?如果你有一个可以分析不含调试信息的.class文件分析器,你想用这个来分析含有调试信息的.class文件,不要去管这个分析器,为你的词法分析器新增关于调试信息的结构。然后用一个过滤器分离调试信息记号到另一个流,这样,对两种类型的.class文件,原来的分析器都可以正常工作了。

    稍后,我想加一个"视图",这是真正的另一个查看过滤器的方法。想象一下从一个词法分析器(根视图)中发射出一个未加工的记号流。对它,我可以非常轻松的构建一棵视图树。例如,给出一个嵌有SQL的Java程序,你可能想为分析或翻译在输入流上建立视图,会是下面的样子:

    stream.perspectives.gif (2679 bytes)

    你可以把SQL流或者去掉注释的Java流交给你的语法分析器处理,分析器中的动作也可以去访问注释流。

    将来,我还会增加分析器的另一个功能,去生成记号流(或文本)作为输出,就像建立了树一样。用这样方式,多传递分析变得十分自然和简单,因为语法分析器也变成了流的生产者。一个语法分析器的输出可以是另一个语法分析器的输入。

    Version: $Id: //depot/code/org.antlr/release/antlr-2.7.6/doc/streams.html#1 $

    posted @ 2007-11-13 21:25 CowNew开源团队 阅读(2012) | 评论 (5)编辑 收藏

        看到CSDN上有很多人在讨论汉语言编程,有人把“汉编”骂的狗血喷头,有人在苦苦支撑自己的“民族特色”。我感觉骂 “汉编”的人们是过于西化了,而苦苦维护“汉编”的人们又过于保守了,那么我就发表一下我中庸而又和谐的想法:在目前这种结构化的编程语言中,“汉编”是没有什么意义的,理由我就不说了,很多人已经慷慨陈词了;我认为“汉编”的希望在明天,等到自然语言理论发展起来的时候,“汉编”将会有自己的用武之地。想一下也许下面的代码对于中文或者英文来说没有区别:

    if you.tired then you.sleep();

    如果 你.累了 那么 你.睡觉

        可是下面的自然语言化的代码就有意义了:

    if you're tired ,please fall aleep

    累了的话就睡吧/累了就睡呗/如果累了就睡

        想想如果能够实现用自然语言控制计算机的话,汉语言编程还没有意义吗?如果再结合语音识别,那么做为一个纯种中国老爷们儿,你是愿意假装归国华侨似的对着电脑说“Please format disk c if you receive command 'ok'!”,还是愿意用纯种国语说“收到'ok'就把c盘给它格式化喽”呢???
    好好发展汉语言的自然语言理论吧。

    posted @ 2007-11-12 09:51 CowNew开源团队 阅读(748) | 评论 (9)编辑 收藏

        上午第一个Session:突出重围,使用软件工厂和MSF成功打造优质的企业应用。因为昨天听的一个关于“微软软件工厂”的讲座,所以来听这个Session也是为了加深对“微软软件工厂”的认识的,来了一个才知道这个Session更多讲的是MSF。MSF是微软提出的一个软件开发方法学,我是第一次听说MSF,通过这个Session我感觉MSF是敏捷开发与CMMI的一个结合体。由于采用“微软软件工厂”以后系统就分为核心模块开发和外围Features的开发。采用MSF以后核心模块做不断的持续集成,而外围Features则在核心平台的每一个版本出来以后再做周期性集成。针对目前很多国内项目人数比较少的现状,他提出了进行角色合并的方式来组成一个小团队,比如测试人员和产品经理可以合并,但是开发人员就不能和测试人员合并。
        国内软件企业面临的问题:
    (1)、整体软件业在快速增长,但主要在外包领域
    (2)、受到国外ISV强烈挑战,没有掌握标准和话语权。大部分是在做系统集成工作。
    (3)、平台产品难以外化,成功外化的盗版横行。自己的平台自己用,一旦开放就会被盗版。比如WPS就无法维持金山的生存。
    (4)、不重视规避法律问题。很多商业项目中大量使用GPL协议的开源产品。
    (5)、项目管理和开发流程不规范,失败率高盈利率低
    (6)、时间紧任务急,客户需求多变
    (7)、人员素质参差不齐,缺乏优秀团队模型和技术交流
    (8)、没有驾驭优质企业应用的经验,上线后问题众多。比如奥运订票网站的当级就是一个最生动的例子。
        通过这个Session,我也终于纠正了我昨天的一个错误“微软软件工厂就是代码生成”,现在我的认识是“微软软件工厂就是基于某些方法论和架构的代码生成”,并且生成的代码也是无法用其他手法消除掉的boring代码。
        上午第二个Session:SilverLight开发的极速体验。讲师是微软的美女郭晓颖(偶也系广大色狼中的一份子),讲座风格很有女孩子的特点,不知道是不是她做讲座的经验不多,感觉语气过于平淡,有点令人boring。SilverLight非常容易开发、调试和部署,可以很容易的自定义控件,并且可以很容易与服务器交互,比如在SilverLight中只要调用被标记为WebMethod的方法就可以很容易的与服务器交互;还可以在SilverLight中调用脚本或者Dom。
        讲座结束以后我提问了我最关心的两个问题:是否可以把自定义的ActiveX控件加入SilverLight(应用场景就是用SilverLight做网银客户端);SilverLight是否可以操作本地硬件(应用场景就是用SilverLight做银行柜员终端显示技术)。这两个问题得到的回答都是“NO”,很失望,看来SilverLight是不能用来做银行相关的这些东西了,也许微软只是把它定位为一个多媒体的东西吧。
        下午第一个Session:SilverLight1.1CLR内核架构。讲师是andrew pardoe和美女郭晓颖。这也是我唯一听的一个英文课程。可能考虑到了在场的大部分是国人,所以andrew的英文发音挺标准、听起来不算费劲,而且他还不时的蹦出几个中国字“你好,我是from。。。来的,不是牛”,呵呵。他主要讲了SilverLight的底层CoreCLR的实现内幕,不熟悉的读者可以把CoreCLR想像成运行SilverLight的虚拟机。CoreCLR和代码实用的是和CLR一样的代码,所以GC(垃圾收集)、JIT(实时编译,呵呵,从JavaHotSpot中学去的技术)都依然是存在的。不过为了减少无用的功能以减小CoreCLR的尺寸以及为了使用沙箱机制来保证应用的安全性,因此移除了正则表达式的编译、本地代码调用等功能,并且对于文件系统的访问也进行了受限处理(这让我想起了J2ME以及Applet)。由于CoreCLR就是SilverLight的虚拟机,所以客户端机器无需安装.Net Framework也能Run SilverLight的应用,这也就是为什么MACOS中也能Run SilverLight了,所以如果有耐心,我们也可以让SilverLight Run在Unix以及其他操作系统下。目前SilverLight即将支持Linux,不过SilverLight是只能运行在SUSE下的,不能运行在其他的Linux下,看来这也是和Novell合作的结果,刚才查了一下SUSE下是使用MONO实现的CoreCLR。
        这个Session中让我感到的一个亮点是我们可以用Python(IronPython)以及Ruby(IronRuby)来写SilverLight(任何能生成CLR的语言都可以用来写SilverLight),也就是完全可以在运行时动态运行SilverLight。andrew用的演示Demo就是IronPython写的一个在线Python命令行界面,在这个界面中敲入Python指令就可以使得SilverLight中的图形发生变化,真的是太棒了。
        讲座完了以后我同样问了andrew一个问题:从Tech-Ed的一开始到现在,我们看到的都是用SilverLight写游戏、写媒体播放器,那么我们是否可以用SilverLight来写企业级应用。也许是andrew只是做CoreCLR底层技术的,所以对这种商业性的问题也并不是很清楚,所以他的回答是:微软是一家大公司,而且我们有很多的合作ISV,所以没有做不到的事情,他还说百度不是用SilverLight做出来企业级应用吗(我注:貌似百度的那个视频播放频道不是我指的那种企业级应用)?他的回答比较失望,再次验证了我的结论:SilverLight只是用来做Game、Player等多媒体应用的东西,微软没有打算让我们用它来做企业级应用的表现层。   

        下午第二个Session:SoftGrid应用程序虚拟化。这个专题也是我最期待的。本以为SoftGrid是开幕式上鲍尔默演示的那个虚拟Office,听了以后才明白鲍尔默演示的是升级版的Windows Terminal,只是进行了输入输出的重定向。而SoftGrid则是另外一种程序的部署方式。程序以文件的形式保存在SoftGrid服务器中,当用户要运行程序的时候,只需要下载程序运行所需的最小组件集合(dll等),然后就可以运行了。程序是运行在客户机的SoftGrid提供的一个虚拟环境中,这个虚拟环境模拟了COM、注册表、字体等关键位置的调用,这样应用程序所做的任何修改都只会影响到这个虚拟环境,不过对客户机产生任何修改,这样就可以轻松运行相冲突的软件了(比如Office2003是不能和Office97同时安装的,但是通过使用SoftGrid,我们就可以在一台机器中同时运行他们)。由于SoftGridClient只是模拟了COM、注册表、字体等,并不像VMWare、VPC那样完全模拟以计算机,所以其运行效率非常高。由于它不像Windows Terminal那样是运行在远程终端服务器中的,所以可以减小服务器的压力、提高客户端的响应,而且不像Windows Terminal那样受服务器版本的限制大,同时当服务器Down掉或者处于脱机环境中的时候程序仍然可以运行(再次提醒,程序是Run在客户端的,而不是运行在服务器端的)。讲师给出的一个性能数据是:一台服务器上可以Run 1000个客户端。
        SoftGrid不是Windows Terminal的终结者,它和Windows Terminal之间是一个互补的解决方案,在某些应用场景下可以发挥各自的优势来实现组合应用。
        不过SoftGrid进行组件的依赖性判断不可能是完全准确的(比如有可能是动态的组件调用或者运行的程序是Java程序),所以如果第一次不是100%下载,那么运行时有可能出错,而如果第一次是100%下载,则就会大大减慢程序的部署速度。不过SoftGrid只是微软的一个刚刚起步的技术,希望它未来的发展不会让我们失望。也许银行的图形前端技术也能用它来实现呢!

        下午第三个Session:通过微软Office Communications Server2007召开企业级的音频视频和在线会议。这是今年Tech-Ed的最后一节课,大部分人已经提前离开九华山庄了,所以参加课程的人非常少,主讲用非常幽默的方式把大家全部集中到了会议室的前边。由于是第一次接触OCS(因为错过了前边了解OCS的Session,所以我把握住了最后这个机会来了解它)。由于听课的人中有相当大一部分(听课的一共才二三十个人,呵呵)不了解OCS,所以主讲首先介绍了OCS,正好满足了我的愿望。OCS是一个非常优秀的企业级的办公系统,可以非常方便的使得员工能够通过语音、邮件、视频等各种方式进行交流,而且可以借助于会议预定、预约等功能轻松的进行时间管理。这个Session主要讲的就是使用OCS来组建公司内网视频会议系统,优点多多,无奈我是门外汉,只是概念上有了了解,这里就不献丑了。最后的一节课我回答对了问题,得到了我的唯一一个奖品:《Exchange Server2007安装部署指南》,正好送给我们公司做信息管理的同事:)。
        三天的Tech-Ed就此结束,离开的时候还有点恋恋不舍。我这三天的“报道”也到此结束了,当然我对Tech-Ed的学习还没有到此结束,不仅因为很多我感兴趣的Session由于与我选的其他Session时间冲突造成没法去学习,而且也因为这三天我接触了很多好东西,需要进一步了解,这样我就需要对照着那三大本讲义继续研究微软产品好的一些东西。以后我也很可能会把我学习的经验教训继续与大家分享,不过这可不是我的promise呀,我尽力吧!好啦,午夜了,也该休息了,这三天睡眠明显不足(听课也比工作更累人,今天早晨都用咖啡来提神了),正好好好利用周六补个觉喽,明天睡到太阳下山,哈哈,晚安!

    posted @ 2007-11-10 00:19 CowNew开源团队 阅读(1383) | 评论 (5)编辑 收藏

        上午第一个Session:微软IT Exchange Server2007的架构和设计。本来是想去了解一下Exchange的基本应用的,去了以后才知道是讲微软是怎么搭建他们的全球邮件系统的,由于以前没有用过Exchange,所以听得云里雾里的。主要的思想就是怎么进行网络拓扑设计和防火墙、防垃圾邮件服务器的组合。
        上午第二个Session:SharePoint企业应用集锦。讲了SharePoint的三个典型案例:服务型政府门户、面向知识的文档管理和IT支持管理,没感觉有啥特别的。
        中午在“合作伙伴展区”中看到了博客园的宣传广告,呵呵,祝咱们的dudu越来越好,也希望dudu多来关心俺们blogjava的兄弟呀,别把我们忘了,什么.Net开发者、Java开发者的,大家都是搞技术的,那些区别只是对厂商而言的,咱们都是“开发人员”,不要分那么多小类别,不要搞内斗,呵呵。
        下午第一个Session:深入剖析S+S应用。Saas应用的必备的几个特性:Try before buy(也就是用户在购买之前可以体验);pay what I use(用户只需要购买他需要的服务,减少资源浪费,降低投资);要支持离线应用,并且支持富客户端的前端表现;SIMT(单实例多租用,无需为单个的客户进行个性化开发,所有的客户应用都run在同一个平台下,只是利用其可配置性进行个性化配置)。
        微软这次大会一直在推荐他们收购的FaceBook,也多次提到Saas的基础理论--长尾理论,也就是不像以前的那样只赚富人的钱了,“从1000个穷人那里赚来的钱会和一个富人的钱一样多,但是也许所有从穷人那里赚来钱的总和也许会比从富人那里赚来的钱的总和还多”,也就是降低软件使用的价格,使得更多人能买软件(或者服务)。Saas的生态系统中有两个特色的角色:ISV和Saas hoster,ISV在Saas hoster提供的平台进行应用的开发为最终用户服务,而Saas hoster提供平台、计费交易、监控监管等服务,这样两者双赢共生,想必微软是想成为一个Saas hoster,从而把众多的ISV继续团结到它周围,它继续做第四代软件革命的领导者。微软的Saas让我想起了动易CMS和众多的动易模板提供商之间的关系。
        课中讲了微软给的一个Saas的案例性应用:LitwareHR,这是一个提供人员招聘的服务,企业可以个性化的进行招聘页面的定制。实现可配置性的时候使用了元数据技术。讲师提到了实现可配置性有两种实现技术:预留字段和元数据。预留字段是最传统也是最土的技术,其可扩展性是受限的,不过效率也许会稍微高一点;采用元数据技术(可以在数据库中通过基于DB的扩展键值来实现元数据,也可以使用SQLServer2005提供的XML数据类型来实现)可以实现不受限的可扩展性。
        实现SIMT可以有三种实现技术:Separated DB,每个用户一个数据库,这样数据的安全性最好,实现简单,但是对软硬件的投资需要非常高;Separated Schema,每个用户一个表,这样软硬件投资会少一些;Shared Schema,用户共享一个表,通过一个类似于UserId的字段来分辨当前记录属于哪个用户。
        讲师还演示了微软的“软件工厂”。其实就是代码生成技术,开发人员只要简单配置就可以生成以前需要手工编写的代码。个人感觉这东西没什么,而且我认为“代码生成器”是最土的一种“复用性”技术,只有万不得已的时候采用。不过如果“软件工厂”能发展起来的话,也许能养活一批专门制造各种不同“软件工厂模板”的厂商,也许这又是微软说的“生态系统”吧。
        下午第二个Session:面向Web.netxt的兵器谱。主要讲了SilverLight的优势。SilverLight可以运行在很多主流浏览器上,用户端的操作系统可以是非Windows,而且服务器端也可以支持非Windows操作系统。SilverLight的内容是XML格式,可以很容易被搜索引擎收录到,而Flash则是二进制格式,很难被搜索引擎支持。SilverLight支持DRM(数字版权管理),这样就不用担心像Flash那样被别人盗用了。SilverLight能够支持JavaScript、C#、VB.NET、J#等多种语言编写,容易上手而Flash则支持ActionScript。最重要的,美工人员可以用Expression来进行美工设计,然后生成的工程可以被开发人员在VS.Net Studio以一个工程的形式被打开以进行程序设计,这样美工人员和程序开发人员就可以很好的协作了,不像Flash那样要求开发人员既要懂美工又要懂Development。
        下午第三个Session:基于BizTalk RFID快速构建RFID应用。因为我上大学时候是学物流的,对RFID接触比较多,所以就来“温习”一下自己对RFID的知识了。使用BizTalk RFID我们能容易开发出RFID应用,降低了开发难度。由于RFID涉及到很多非纯软件技术的东西,所以这里就不介绍了,有兴趣可以去搜索“RFID”、“射频”、“条形码”等关键字:)。看起来BizTalk RFID是微软新推出的技术,目前还在需要能进行推广的合作伙伴。
        下午第四个Session:Office Business Application实战:SharePoint在企业SOA环境中的应用。演示了一个真实的基于SharePoint的应用,讲师也是来自微软的一个合作伙伴。看了以后感觉微软的SharePoint、InfoPath、Office之类的系统结合还是非常密切的,用好了的话能轻松解决很多问题,门槛非常低。比如业务人员可以直接使用Excel录入数据,然后可以直接把数据发布到SharePoint中,而SharePoint则会定时把这些数据提交到后台系统。而且我们可以在Excel中嵌入自己用WinForm编写的界面,完全把Excel做成了一个业务系统的前台界面的开发平台了,这样业务人员只要会用Excel就可以了,不仅可以实现各个企业的个性化要求,而且可以直接使用Excel的高级功能进行功能扩展,“会用Excel就会操作所有业务系统”,这一点让我想起了一个叫“Excel服务器”的产品。在普通程序开发中,我们复用的是程序代码;而在SOA中,我们复用的是服务,并且业务人员就可以将这些服务拼装起来从而满足自己的要求。
        晚上是“UC之夜”晚宴,来了美女跳热舞,呵呵。明天是最后一天,期望明天能学到更多东西:)
    posted @ 2007-11-09 00:08 CowNew开源团队 阅读(1369) | 评论 (5)编辑 收藏

        微软的技术也许不是最好的,但是确实是把技术与商业化结合最好的公司之一,也是比较具有市场前瞻性的公司;抛弃那些商业色彩过浓的东西,完全站在技术的视角,微软也确实是一个值得去仔细研究的公司。正好公司有一个去参加微软2007技术大会(Tech-Ed)的机会,因此就参加了今年的Tech-Ed。
        早晨6点起床、刷牙、洗脸,6:30打的去首都大酒店,7:20到达首都大酒店,领了人民大会堂的请柬,然后坐班车去人民大会堂,8:10会开始安检、入场。
        9:10分大会开始。微软CEO 鲍尔默(据说是比张飞脾气还大,直接和盖茨拍桌子的主儿)致开幕词,主题是《Dynamic IT》,核心思想就是:目前的IT系统发展已经进入了一个新阶段了,大部分力量投入在旧系统的维护和整合上,因此我们必须去适应这种形势,用Dynamic的技术去建设Dynamic的和谐IT。
        鲍尔默演讲中还穿插的以百度的一个新版音乐网站演示了SilverLight技术,微软把SilverLight放到这么重要的位置来推荐,可以看到微软对SilverLight的推广决心,看来Flash要被小小的动摇一下了。SilverLight这种Smart Client技术确实是不错的技术,希望能帮助我们更容易开发、部署出功能更强的系统。看来这是合久必分呀,C/S发展到B/S,然后又回归到了以Smart Client为基础的C/S,终于令人恶心的Web开发技术早晚淘汰了!
        老鲍讲完了以后,微软大中华区的首席技术官做主题演讲,他主要讲了微软现在主推的三项技术:基于Office套件的办公一体化;Open XML;虚拟化。基于Office套件的办公一体化还是那一套综合利用Live Meeting、Outlook什么的实现无纸化、更高效的办公;Open XML就没啥新鲜的了,还美其名曰“咱们的文档几百年后的后人也能阅读”;虚拟化大部分也很老套,不过令我感觉震撼的是新的远程应用程序部署模式:程序可以将Office之类的应用程序直接在服务器端“推送”到客户端,并且只是放一个几十KB的文件而已,根本不用在客户端安装程序,所有程序都运行在远程服务器中,但是如果单独是这一点并不新奇,因为Citrix metaframe早就实现类似技术了,它的亮点是用户可以直接打开和保存客户端上的文件,而不像metaframe那样只能打开和保存在服务器上的文件。
        11点大会结束,坐车去九华山庄,12点到达九华山庄(离著名的小汤山很近)分会场,1点就餐完毕。因为下午2点课程才开始,所以就在会场里边转悠,在本次大会的赞助合作伙伴的展台前看一下,重点看了一下K2和Bussiness Objects。以前没有听说过K2,它是一家美国公司,专业做工作流开发工具的,开始进军中国市场,看来今后这种专业提供技术解决方案的公司会越来越多的,中国的IT终于该上一个台阶了,不要再继续当世界软件工厂了,要拥有自己的核心技术!也许你没听说过Bussiness Objects,但是不能没听说过水晶报表,是微软把这个小弟亲手扶植起来的,看来OEM的力量强大呀(当时投靠Borland的那些控件厂商跟错了队伍了呀,很多挺好的技术没有得到发扬!)。
        14:00至15:15去听了关于SCVMM的讲座(俺们的盆盆讲的)。主要讲了微软的虚拟化技术,SCVMM(System Center virtual Machine Manangement)是System Center重要的组成部分,应该是由VirtualPc发展起来,不过针对Windows平台进行了更多个性化的定制,这样能够更紧密的和Windows联系(劣势当然就是不再支持Linux之类的系统)。使用虚拟化技术可以减少硬件的投入、提高硬件的资源利用率,更容易的管理。SCVMM还有一个很贴心的功能:自主化服务。使用这个功能,企业的员工完全可以根据自己的需要在服务器上自助化的创建虚拟机,而且用完了可以删除,这样完全不需要公司的硬件运维人员操心了。SCVMM提供的P2V功能可以将一台物理机迁移为一台虚拟机。
        15:30至16:45去听了关于S+S(软件加服务)的讲座。S+S的三剑客:Saas、SOA和Web2.0。用主讲的话说:微软“豪赌”S+S。计算机发展的第一个阶段是提供单独软件;第二阶段是提供IT托管;第三个阶段将是提供服务的阶段。微软收购FaceBook也是基于发展S+S的策略,未来的Office将提供单机版和在线Office两种版本,使用在线Office我们只需要在用的时候按月付费就可以,不用了就不用交钱。而且基于S+S还将形成新的软件生态系统,每个人都可以轻松发布服务和利用其他人提供的服务。像CRM、OA之类的应用完全可以做到以服务的形式购买,只要满足个性化定制的可扩展性就可以,这样也可以养活一些专业做个性化定制的厂商。用主讲的话说:可以把眼光放在S+S,未来的一流IT企业一定会有S+S的公司。讲座中还演示了一个未来IT生活的片段,家庭中一切设备都能互联互通,看电视的时候能在屏幕中看到自己有新邮件,可以直接把在电脑上看的东西切换到车载设备中,片段中还出现了被微软曾经主推但是不温不火的平板电脑。
        17:00至18:15听了关于LINQ的讲座。这是一个纯编程技术的讲座。听了这个讲座使我不再认为LINQ只是一个内嵌的ORM。LINQ分为三个部分:LINQ TO SQL、LINQ TO Entity和LINQ TO XML。LINQ TO SQL是一个内嵌的ORM,在语言级别支持类似于SQL语句的东西;LINQ TO Entity是一个很有意思的技术,感觉和Java中的Quaere和joSQL类似,也就是我们可以用SQL语句的形式对数据进行过滤,比如我们要查找一个类中所有方法名长度大于10的方法,那么只要写类似于下面的语句就可以:select m.name from MyClass.getMethods() as m where m.name.length>10(注意这个代码只是示例性的,LINQ语法不是这样的),不知道这个东西是不是从Java的joSQL借鉴过去的;LINQ TO XML也是可以以更加直观的方式操作XML,并且可以和LINQ TO SQL、LINQ TO Entity很好的结合。偶对LINQ没感觉有啥新奇,因为这些东西在Python中用lambda早就可以实现了,不过还是很佩服微软的学习与融会贯通精神,LINQ确实能提高基于.Net的傻瓜化开发效率。比较奇怪的是主讲竟然对C#3.0中新增的lambda和匿名类(都是为LINQ而生的)感到特别振奋,天哪,这两个技术已经在Java、Python等语言中出现三百多年了。:)。这里没有别的意思,只是感叹一下,希望微软的拥趸们不要拍砖。
        未来还有两天的会程,希望能吸收到更多有用的东西。
    posted @ 2007-11-07 23:14 CowNew开源团队 阅读(1626) | 评论 (7)编辑 收藏

    《自己动手写开发工具》系统地介绍了SWT、Draw2D、GEF、JET等与Eclipse插件开发相关的基础知识,并且以实际的开发案例来演示这些知识的实战性应用,通过对这些实际开发案例的学习,读者可以非常轻松地掌握Eclipse插件开发的技能,从而开发出满足个性化需求的插件。
    本书以一个简单而实用的枚举生成器作为入门案例,通过该案例读者能学习到扩展点、SWT、JET等Eclipse插件开发的基本技能;接着对Eclipse插件开发中的基础知识进行了介绍,并且对属性视图的使用做了重点介绍;最后以两个具有一定复杂程度的插件(Hibernate建模工具和界面设计器)为案例介绍了SWT、Draw2D、GEF、JET等技术的综合运用。

    电驴下载地址:http://www.verycd.com/groups/@u2105483/204642.topic

    HTTP下载地址:
    http://www.cownew.com/Soft/ShowSoft.asp?SoftID=16

    http://www.cownew.com/Soft/ShowSoft.asp?SoftID=10
    posted @ 2007-11-04 12:34 CowNew开源团队 阅读(824) | 评论 (0)编辑 收藏

    《自己动手写开发工具--基于Eclipse的工具开发》
    本书系统地介绍了SWT、Draw2D、GEF、JET等与Eclipse插件开发相关的基础知识,并且以实际的开发案例来演示这些知识的实战性应用,通过对这些实际开发案例的学习,读者可以非常轻松地掌握Eclipse插件开发的技能,从而开发出满足个性化需求的插件。.
    本书以一个简单而实用的枚举生成器作为入门案例,通过该案例读者能学习到扩展点、SWT、JET等Eclipse插件开发的基本技能;接着对Eclipse插件开发中的基础知识进行了介绍,并且对属性视图的使用做了重点介绍;最后以两个具有一定复杂程度的插件(Hibernate建模工具和界面设计器)为案例介绍了SWT、Draw2D、GEF、JET等技术的综合运用。..
    本书不仅适合于Eclipse插件开发初学者学习,对于有一定相关开发经验的开发人员也具有很高的参考价值。

    ChinaPub地址:http://www.china-pub.com/computers/common/info.asp?id=36806


    目录:

    第2章  Eclipse插件开发
    2.2  简单的案例插件功能描述
    2.3  插件项目的建立
    2.3.1  建立项目
    2.3.2  调试方式运行插件项目
    2.4  改造EnumGeneratoreNewWizardPage
    2.4.7  取得界面控件值的方法:
    2.5  开发枚举项编辑向导页
    2.5.1  初始化
    2.5.2  相关环境数据的处理
    2.5.3  代码生成
    2.6  编写代码生成器
    2.7  功能演示、打包安装
    第3章  插件开发导航
    3.1  程序界面的基础-SWT/JFace
    3.1.1  SWT的类库结构
    3.1.2  SWT中的资源管理
    3.1.3  非用户线程中访问用户线程的GUI资源
    3.1.4  访问对话框中的值。
    3.1.5  如何知道部件支持哪些style?
    3.2  SWT疑难点
    3.3  异步作业调度
    3.4  对话框
    3.4.8  自定义对话框及配置保存与加载
    3.5  首选项
    3.6  Eclipse资源 API 和文件系统
    3.6.1  资源相关接口的常见方法
    3.6.2  方法中force参数的意义
    3.6.3  资源相关接口的方法使用示例
    3.6.4  Eclipse中没有当前项目
    3.7  Java项目模型
    3.7.1  类结构
    3.7.2  常用工具类
    3.7.3  常用技巧
    3.7.4  设定构建路径实战
    3.7.5  如何研读JDT代码
    3.8  插件开发常见问题
    3.8.1  InvocationTargetException异常的处理
    3.8.2  Adaptable与Extension Object/Interface模式
    3.8.3  千万不要使用internal包
    3.8.4  打开视图
    3.8.5  查找扩展点的实现插件
    3.8.6  项目nature
    3.8.7  透视图开发
    3.8.8  关于工具条路径
    3.8.9  Eclipse的日志
    第4章  属性视图
    4.1  基本使用
    4.1.1  IPropertySource接口说明
    4.1.2  对象实现IPropertySource接口
    4.1.3  对象适配成IPropertySource对象
    4.2  属性视图高级话题
    4.2.1  属性分类
    4.2.2  复合属性
    4.2.3  常用属性编辑器
    4.2.4  自定义属性描述者
    第5章  开发Hibernate插件
    5.3  实体模型文件创建向导
    5.4  模型的定义和模型文件处理
    5.5  实体属性描述者
    5.6  实体编辑器
    5.6.1  字段的编辑
    5.6.2  编辑器基类
    5.6.3  实体编辑器核心配置界面
    5.6.4  多页实体编辑器
    5.7  代码生成
    5.7.1  代码生成器接口
    5.7.2  代码生成器配置文件
    5.7.3  代码生成向导
    5.7.4  公共工具类CommonUtils
    5.8  Hibernate代码生成器
    5.8.1  命名策略
    5.8.2  工具类
    5.8.3  代码生成的JET代码
    第6章  基于GEF的界面设计工具
    6.1  GEF简介
    6.1.1  Draw2D
    6.1.2  请求与编辑策略
    6.1.3  视图与编辑器
    6.1.4  GEF的工作过程
    6.2  系统需求
    6.2.1  界面设计工具的分类
    6.2.2  功能描述
    6.3  构建模型
    6.4  实现控制器
    6.4.1  窗体和组件的控制器
    6.4.2  编辑策略
    6.4.3  命令对象
    6.5  窗体文件创建向导
    6.6  组件加载器
    6.7  编辑器
    6.8  代码生成和构建器
    6.8.1  代码生成
    6.8.2  构建器
    6.8.3  为项目增加构建器
    6.9  实现常用组件
    6.9.1  标签组件
    6.9.2  按钮组件
    6.9.3  复选框
    6.9.4  编辑框
    6.9.5  列表框
    6.10  使用演示
    《自己动手写开发工具》

    posted @ 2007-11-02 17:34 CowNew开源团队 阅读(1518) | 评论 (9)编辑 收藏

        现在大部分软件开发书籍都是讲解某个技术如何用,很少有讲实战的,即使有实战案例的讲解,也是讲解网上购物、聊天室之类已经被人写烂了的系统的开发,最可怕的是书中的实现代码惨不忍睹,使得读者很容易被误导,至于如何进行合理的架构设计就更无从谈起;少数从国外引进的高端技术书籍又大谈特谈各种在天上飞来飞去的理论,“看的时候心潮澎湃,看完之后一脸茫然”,读者不知道如何将这些理论应用到实际的开发过程当中。本书就尝试着打破这种局面,把一个真实的系统搭建从头讲起,不仅包含具体的实现技术,也包含一些架构方面的设计思想。
           这是一本以Java开发语言为载体来讲解企业级信息系统开发的书,其中涉及到了Hibernate、Struts、Spring、JSP、Swing、JDBC等很多技术,而且案例系统的搭建过程中也较合理的使用了面向对象理念进行系统设计,但是书中不可能详细讲解这些技术的使用,读者可以根据需要参考这些技术相关的参考资料。

           序言部分介绍了开发框架等的概念;第1、2、3、4章介绍了正则表达式、AOP、自定义JSP标签等基础知识;第5章给出了案例系统的需求文档;第6章基于Spring技术搭建了案例系统的Remoting部分;第7章构建了一个基于MDA理念的元数据引擎;第8章对案例系统中用到的枚举异常类、工具类等做了介绍;第9、10、11、12章基于Spring、Hibernate等技术搭建了事务、DTO生成器、权限控制、日志记录、多数据库支持等基础模块;第13、14章开发了登录服务、Swing客户端基础模块以及数据选择器等自定义Swing控件;第15章实现了列表界面、编辑界面和编辑界面的基类;第16章搭建了Web客户端的登录界面、主菜单等基础模块,并开发了JSP用的数据选择器等自定义标签;第17章则以前面章节搭建出的基础框架为基础实现了第5章中的需求文档所要求的功能。

       《J2EE开发全程实录》是国内J2EE研究领域里具有里程碑意义的一部作品。作者以通俗易懂的语言将J2EE企业级系统架构设计、开发过程中的看似高深的技术与原理娓娓道来,使得读者在不经意间随着作者的思路一起参透高深的技术理念。阅读完本书我才发现架构设计、设计模式、元数据编程、AOP、分布式开发这些看似高深的理论完全可以很轻松的用来改善系统架构的设计,而Spring 、Hibernate、Struts、Swing、XML这些看似孤立的技术也可以有机的结合起来搭建一个高度灵活的系统架构。相信对于想深入学习基于J2EE技术的企业级系统架构设计与开发技术的读者来说,《J2EE开发全程实录》将是一本不可多得的宝典。

    详细地址:http://www.china-pub.com/computers/common/info.asp?id=35167
    电子版下载地址:http://soft.hackbase.com/page/2007-07-11/01750187507.Html

    posted @ 2007-11-02 17:31 CowNew开源团队 阅读(805) | 评论 (4)编辑 收藏


    ANTLR树分析器
                    本章翻译人 CowNew开源团队 周晓

    曾经的SORCERER

    在ANTLR 2.xx版本中,只要增加一些树操作符,就可以帮助你建立一种中间形式的树结构(抽象语法树) 来重写语法规则和语义动作。ANTLR同样允许你去指定AST树的文法结构,因此,可以通过操作或简单遍历树结点的方式来进行文法翻译。

    以前,树分析器用一个单独的工具SORCERER来生成,但是ANTLR已经取代了它的功能。ANTLR现在可以为字符流,记号流,以及树节点来建立识别器。

    什么是树分析器?

    分析是决定一个记号串是否能由一个文法产生的过程。ANTLR在这方面比大多数工具考虑的都要深,它把一个二维树结构看作是一串节点。这样,在ANTLR中,对记号流分析和树分析的代码生成过程来说,真正仅有的区别就变成了对超前扫描,规则方法定义头部的检测,以及对二维树结构代码生成模板的指定上。

    可以分析什么类型的树?

    ANTLR树分析器可以遍历实现了AST接口的任何树。AST接口是一种基于类似儿子-兄弟结点的树通用结构,有如下重要的制导方法:

    • getFirstChild: 返回第一个子结点的引用.
    • getNextSibling: 返回下一个兄弟结点的引用.

    每一个AST结点有一个子女列表,一些文本和一个"记号类型"。每个树的结点都是一棵树,因此我们说树是自相似的。AST接口的完整定义如下:

    
    /** 最小AST结点接口用于ANTLR的AST成生
    *	和树遍历
    */
    public interface AST {
    /** 添加一个子结点到最右边 */
    public void addChild(AST c);
    public boolean equals(AST t);
    public boolean equalsList(AST t);
    public boolean equalsListPartial(AST t);
    public boolean equalsTree(AST t);
    public boolean equalsTreePartial(AST t);
    public ASTEnumeration findAll(AST tree);
    public ASTEnumeration findAllPartial(AST subtree);
    /** 得到第一个子结点; 如果没有子结点则返回null */
    public AST getFirstChild();
    /** 得到本结点的下一个兄弟结点 */
    public AST getNextSibling();
    /** 得到本结点的记号文本 */
    public String getText();
    /** 得到本结点的记号类型 */
    public int getType();
    /** 得到本结点的子结点总数; 如果是叶子结点, 返回0 */
    public int getNumberOfChildren();
    public void initialize(int t, String txt);
    public void initialize(AST t);
    public void initialize(Token t);
    /** 设置第一个子结点. */
    public void setFirstChild(AST c);
    /** 设置下一个兄弟结点. */
    public void setNextSibling(AST n);
    /** 设置本结点的记号文本 */
    public void setText(String text);
    /** 设置本结点的记号类型 */
    public void setType(int ttype);
    public String toString();
    public String toStringList();
    public String toStringTree();
    }
    

    树的语法规则

    正如PCCTS1.33的SORCERER工具和ANTLR记号语法中所看到的,树语法是一个嵌入语义动作,语义断言和句法断言的EBNF规则的集合。

    
    规则:	可选产生式1
    |	可选产生式2
    ...
    |	可选产生式n
    ;
    

    每一个可选的产生式都是由一个元素列表所组成的,列表中的元素是加入了树模式的ANTLR正规语法中的一个,有如下的形式:

    
    #( 根结点 子结点1 子结点2 ... 子结点n )
    
    

    例如:下列的树模式匹配一个以PLUS为根结点,并有两个INT子结点简单树结构:

    
    #( PLUS INT INT )
    

    树模式的根必须是一个记号引用,但是子结点元素不限于此,它甚至可以是子规则。例如,一种常见结构是if-then-else树结构,其中的else子句声明子树是可选的:

    
    #( IF expr stat (stat)? )
        

    值得一提的是,当指定树模式和树语法后,通常,会进行满足条件的匹配而不是精确的匹配。一旦树满足给定的模式,不管剩下多少没有分析,都会报告一次匹配。例如,#( A B ),对于像#( A #(B C) D)这样有相同结构的树,不管有多长,都会报告一次匹配。

    句法断言

    ANTLR树分析器在工作时仅使用一个单独的超前扫描符号,这在通常情况下不是一个问题,因为这种中间形式被明确设计成利于遍历的结构。然而,偶尔也需要区别出相似的树结构。句法断言就是被用来克服有限确定的超前扫描所带来的限制。例如:在区分一元和二元减号时,可以为每一种类型的减号都创建操作结点,这样的做法可以工作的很好。但对于一个相同的根结点,使用句法断言可以区分以下结构:

    
    expr:   ( #(MINUS expr expr) )=> #( MINUS expr expr )
    |   #( MINUS expr )
    ...
    ;
    

    赋值的次序很重要,因为第二个可选产生式是第一个可选产生式的“子集”.

    语义断言

    语义断言在可选产生式的开始,仅仅同可选的断言表达式合成一体,就像合成一个正规文法。语义断言在产生式的中间,当它断言失败时,也会像正规文法一样抛出异常。

    一个树遍历器的例子

    考虑一下如何去建立一个计算器。一个方法是建立一个分析器,这个分析器识别输入并计算表达式的值。按照这种方法,我们将会建立一个分析器来为输入的表达式创建一棵树,把表达式以这种中间形式表示,然后树分析器遍历这个树,并计算出结果。

    我们的识别器, CalcParser, 通过如下的代码来定义:

    
    class CalcParser extends Parser;
    options {
    buildAST = true;   // // 默认使用 CommonAST
    }
    expr:   mexpr (PLUS^ mexpr)* SEMI!
    ;
    mexpr
    :   atom (STAR^ atom)*
    ;
    atom:   INT
    ;
    

    PLUSSTAR记号是操作符,因此把它们作为子树的根结点,在它们后面注释上字符'^'。SEMI记号后缀有字符'!',这指出了它不应该被加入到树中。

    这个计算器的词法分析定义如下:

    
    class CalcLexer extends Lexer;
    WS	:	(' '
    |	'\t'
    |	'\n'
    |	'\r')
    { _ttype = Token.SKIP; }
    ;
    LPAREN:	'('
    ;
    RPAREN:	')'
    ;
    STAR:	'*'
    ;
    PLUS:	'+'
    ;
    SEMI:	';'
    ;
    INT	:	('0'..'9')+
    ;
        

    识别器生成的树是一棵简单的表达式树。例如,输入"3*4+5"所产生的树的形式为#( + ( * 3 4 ) 5 )。为了给这种形式的树建立树遍历器,你必须要为ANTLR递归的描述树的结构:

    
    class CalcTreeWalker extends TreeParser;
    expr	:	#(PLUS expr expr)
    |	#(STAR expr expr)
    |	INT
    ;
    

    一旦指定结构,就可以自由的嵌入语义动作去计算出结果。一个简单的实现办法就是使expr规则返回一个整型的值,然后使每一条可选产生式计算每个子树的值。下面的树文法和动作达到了我们期望的效果:

    
    class CalcTreeWalker extends TreeParser;
    expr returns [int r]
    {
    int a,b;
    r=0;
    }
    :	#(PLUS a=expr b=expr) {r = a+b;}
    |	#(STAR a=expr b=expr) {r = a*b;}
    |	i:INT		      {r = Integer.parseInt(i.getText());}
    ;
        

    注意到当计算表达式值得时候,没有必要指定优先级,因为它已经隐含在树的结构中了。这也解释了为什么在以中间树形式表示的时候,要比它的输入要多很多。输入的符号确实作为结点储存在树结构中,而且这种结构隐含了结点之间的关系。

    要想执行分析器和树遍历器,还需要以下的代码:

    
    import java.io.*;
    import antlr.CommonAST;
    import antlr.collections.AST;
    class Calc {
    public static void main(String[] args) {
    try {
    CalcLexer lexer =
    new CalcLexer(new DataInputStream(System.in));
    CalcParser parser = new CalcParser(lexer);
    // 分析输入的表达式
    parser.expr();
    CommonAST t = (CommonAST)parser.getAST();
    // 以LISP符号的形式输出树
    System.out.println(t.toStringList());
    CalcTreeWalker walker = new CalcTreeWalker();
    // 遍历由分析器建立的树
    int r = walker.expr(t);
    System.out.println("value is "+r);
    } catch(Exception e) {
    System.err.println("exception: "+e);
    }
    }
    }
        

    翻译

    树分析器对检查树或者从一棵树产生输出来说是很有用的,但必须要为它们添加处理树转换的代码。就像正则分析器一样,ANTLR树分析器支持buildAST选项,这类似于SORCERER的翻译模式。程序员不去修改代码,树分析器自动把输入树拷贝到作为结果的树。每一个规则都隐含(自动定义的)一个结果树。通过getAST 方法,我们可以从树分析器中获得此树的开始符号。如果要一些可选产生式和文法元素不被自动添加到输入的树上,它们后面要注释上"!"。子树可以被部分的或者全部重写。

    嵌入到规则中的语义动作可以根据测试和树结构来对结果树进行设置。参考文法动作翻译章节.

    一个树翻译的例子

    再来看一下上面提到的简单计算器的例子,我们可以执行树翻译来代替计算表达式的值。下面树文法的动作优化了加法的恒等运算(加0)。

    
    class CalcTreeWalker extends TreeParser;
    options{
    buildAST = true;	// "翻译"模式
    }
    expr:!  #(PLUS left:expr right:expr)
    // '!'关闭自动翻译
    {
    // x+0 = x
    if ( #right.getType()==INT &&
    Integer.parseInt(#right.getText())==0 )
    {
    #expr = #left;
    }
    // 0+x = x
    else if ( #left.getType()==INT &&
    Integer.parseInt(#left.getText())==0 )
    {
    #expr = #right;
    }
    // x+y
    else {
    #expr = #(PLUS, left, right);
    }
    }
    |   #(STAR expr expr)  // 使用自动翻译
    |   i:INT
    ;
        

    执行分析器和树翻译器的代码如下:

    
    import java.io.*;
    import antlr.CommonAST;
    import antlr.collections.AST;
    class Calc {
    public static void main(String[] args) {
    try {
    CalcLexer lexer =
    new CalcLexer(new DataInputStream(System.in));
    CalcParser parser = new CalcParser(lexer);
    // 分析输入的表达式
    parser.expr();
    CommonAST t = (CommonAST)parser.getAST();
    // 以LISP符号的形式输出树
    System.out.println(t.toLispString());
    CalcTreeWalker walker = new CalcTreeWalker();
    // 遍历由分析器建立的树
    walker.expr(t);
    // 遍历,并得到结果
    t = (CommonAST)walker.getAST();
    System.out.println(t.toLispString());
    } catch(Exception e) {
    System.err.println("exception: "+e);
    }
    }
    }
    }
    

    检查/调试AST

    当开发树分析器的时候,经常会得到分析错误。不幸的是,你的树通常异乎寻常的大,使得很难去确定AST结构错误到底在哪里。针对这种情况(当创建Java树分析器的时候,我发现它非常有用),,我创建了一个ASTFrame类(一个JFrame),这样,你就可以用Swing树视图来查看你的AST。它没有拷贝这棵树,而是用了一个TreeModel。以应用程序方式运行antlr.debug.misc.ASTFrame去或者看看Java代码Main.java。就像不确定如何去调试一样,我不确定它们在相同的包下,总之,将会在以后的ANTLR版本中给出。这里有一个简单的使用例子:

    public static void main(String args[]) {
    // 创建树结点
    ASTFactory factory = new ASTFactory();
    CommonAST r = (CommonAST)factory.create(0, "ROOT");
    r.addChild((CommonAST)factory.create(0, "C1"));
    r.addChild((CommonAST)factory.create(0, "C2"));
    r.addChild((CommonAST)factory.create(0, "C3"));
    ASTFrame frame = new ASTFrame("AST JTree Example", r);
    frame.setVisible(true);
    }
    Version: $Id: //depot/code/org.antlr/release/antlr-2.7.6/doc/sor.html#1 $
    posted @ 2007-10-29 22:26 CowNew开源团队 阅读(4545) | 评论 (5)编辑 收藏

    写存储过程的时候,发现一有意思的现象:语句大概有1k多行,在编译的时候提示:
    [IBM][CLI Driver][DB2/HP64] SQL0101N  语句太长或者太复杂。  SQLSTATE=54001
    然后就是粗略的优化SQL语句了,什么能不要的全不要,能折行的就折行,但是,效果还是一样。
    最后,就只能用这招了:更改SQL堆的大小!
    把默认的堆值放大一倍后,执行顺利通过!
    -- Start of generated script for NO CONNECTION
    --  Dec-20-2006 at 13:20:35
    #ATTACH NDE4C3D4;
    UPDATE DATABASE CONFIGURATION
      FOR FWMY USING
        stmtheap 50000
      IMMEDIATE;
    DETACH;
    #SYNC 10;
     
    -- End of generated script for NO CONNECTION

    from:http://blog.sina.com.cn/s/blog_55fc875c010007zj.html
    posted @ 2007-10-28 16:56 CowNew开源团队 阅读(457) | 评论 (0)编辑 收藏

            本书系统地介绍了SWT、Draw2D、GEF、JET等与Eclipse插件开发相关的基础知识,并且以实际的开发案例来演示这些知识的实战性应用,通过对这些实际开发案例的学习,读者可以非常轻松地掌握Eclipse插件开发的技能,从而开发出满足个性化需求的插件。.
            本书以一个简单而实用的枚举生成器作为入门案例,通过该案例读者能学习到扩展点、SWT、JET等Eclipse插件开发的基本技能;接着对Eclipse插件开发中的基础知识进行了介绍,并且对属性视图的使用做了重点介绍;最后以两个具有一定复杂程度的插件(Hibernate建模工具和界面设计器)为案例介绍了SWT、Draw2D、GEF、JET等技术的综合运用。..
    本书不仅适合于Eclipse插件开发初学者学习,对于有一定相关开发经验的开发人员也具有很高的参考价值。

    Chinapub购买地址:http://www.china-pub.com/computers/common/info.asp?id=36806

    本书随书光盘下载地址:http://www.namipan.com/d/b8879fd74ea3e2b2fd092bb3c7550352f5c6f49765b57b00
    posted @ 2007-10-24 22:44 CowNew开源团队 阅读(474) | 评论 (3)编辑 收藏

    今天写了一个Maxthon的“进入编辑模式”插件,可以用来破解防复制的网页。插件机制真是爽呀,看来我的《网页复制大师》要彻底退休了,呵呵。
    点此下载:http://www.blogjava.net/Files/huanzhugege/editit.zip

    maxhon已经收录本插件:http://addons.maxthon.com/post/2007/10/23/进入编辑模式
    posted @ 2007-10-24 00:12 CowNew开源团队 阅读(455) | 评论 (0)编辑 收藏

    CowNewSQL多数据库翻译器在线演示已经开发完成,欢迎体验
    http://211.99.196.18:6666/cownewdemo

    由于访问人数众多,如果暂时无法访问,请稍后再试。
    目前已经支持SQLServer、DB2、MySQL、Oracle四种数据库管理系统。
    CowNewSQL源码和二进制包可以从CowNew网站(http://www.cownew.com )下载。
    **********************************************
           由于种种原因,各个数据库系统的SQL语句语法以及支持的函数都不尽相同,这造成了如下两个问题:(1)使得系统在多个不同数据库之间移植变得非常困难,特别是需要维护多个数据库版本的时候;(2)开发人员必须对各种数据库的语法差异非常了解,这加大了开发难度。

           虽然Hibernate通过HQL等技术部分的解决了跨数据库移植的问题,但是在对性能要求比较高的场合还是需要直接使用SQL语句访问数据库的,在这种情况下如何编写能被不同数据库支持的SQL语句就成了。目前解决这种差异的最常用的技术就是SQL语句翻译,使用SQL翻译器可以将SQL语句翻译为在不同的数据库中支持的特定平台的SQL语句。CowNewSQL就是这样一款产品。

           CowNewSQL简化了跨数据库产品的开发,比如取当前日期在MSSQL中是“SELECT GETDATE()”,在MYSQL中是“SELECT NOW()”,在Oracle中是“SELECT SYSDATE FROM DUAL”,使用CowNewSQL以后您只要使用“SELECT NOW()”,那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句,而且CowNewSQL的兼容性也非常好,比如“SELECT NOW()”写成“SELECT GETDATE()”同样可以被正确的翻译;取数据库前10条记录,在MSSQL中是“Select top 10 from T_1”、在MYSQL中是“SELECT  LIMIT 0, 10 ”、在Oracle中是“SELECT  FROM DUAL WHERE ROWNUM <= 10”,使用CowNewSQL以后您只要使用“Select top 10 from T_1”,那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句。

           CowNewSQL还通过变通的方式对目标数据库不直接支持的语法进行了支持。比如MYSQL是不支持“select * from t1 where fid in(select fid from t2 limit 0,5)”这样在子查询中的Limit语句的,CowNewSQL通过将子查询进行二次结果集包装的方式巧妙的对其进行了支持,“delete from T_SaleInvoice where FId in(select top 5 FParentId from T_SaleInvoiceDetails)”通过CowNewSQL的翻译以后就成了“DELETE FROM T_SaleInvoice WHERE FId IN (select * from(SELECT FParentId FROM T_SaleInvoiceDetails LIMIT 0, 5 ) t_temp_sub)”这样被MYSQL支持的语法了;MYSQL中没有提供计算两个日期之间月份差异的函数,CowNewSQL通过组合其他日期函数的方式模拟了这个函数,这样使用者只要使用MONTHS_BETWEEN函数即可了,无需关心内部的差异。

           CowNewSQL支持如下几种类型的SQL语句:CreateTable/DropTable/CreateIndex/DropIndex/Select/Insert/Delete/Update;支持子查询、JoinUnion等高级的SQL特性;支持日期(包括取当前日期、从日期中提取任意部分、计算日期差异、日期前后推算等)、数学(包括取绝对值、取PI值、四舍五入、对数计算、随机数等)、字符串(包括取子字符串、取字符串长度、字符串截断、大小写转换等)、基本数据处理(包括数字字符串互转、日期转字符串、非空判断等)等函数。

    posted @ 2007-10-21 23:39 CowNew开源团队 阅读(1388) | 评论 (10)编辑 收藏

    自从2005年底discuz 4.0宣布开源以来,国内很多程序都陆续宣布开源,个个都把开源当作一把大旗来鼓吹自己,但它们真的是开源了吗?

    dedecms是国内用户最多的CMS,自己搞了个协议。
    discuz最初叫CDB,基于XMB 1.5 Silver开发的,CDB代码中也写了遵循BSD许可协议,但CDB后来名字变为discuz,discuz1.X已经去除了BSD授权说明……
    cmsware也很可笑,减少了加密文件的数量,就宣称自己在“走向开源”。
    上个月PHPCMS宣布开源了,下载了个看看,里面竟然连个license说明文件都没?难道没有任何约束和限制?

    希望这些国内的优秀程序更规范一些,开源不仅仅是让别人看到源代码,也不仅仅是供别人免费使用,这不是开源的精神,开源的真正目的是让更多的人参与进来,让软件更完美。

    from :http://news.csdn.net/n/20071019/109739.html
    posted @ 2007-10-20 10:27 CowNew开源团队 阅读(416) | 评论 (0)编辑 收藏

        今天用通讯前置配置工具连接BICE修改其中的参数,重启BICE以后BICE报错“SAXException:文件过早结束”,用通讯前置配置工具再次连接也连不上了,而行科技处的人用他们的通讯前置配置工具修改则没事。检查配置工具的版本也一样。
        最后琢磨出来的原因:BICE服务器(包括配置服务器)是运行的JDK1.4,我机器上的JDK是1.6.所以用通讯前置配置工具修改以后保存的XML格式文件就是JDK1.6能识别的了(呵呵,貌似和XML的语言无关的理念有冲突呀),这样到JDK1.4中就识别错误了。经过验证也是确实是这个原因。
        我用的是最懒的人的解决方法:把JRE1.4拷贝到通讯前置配置工具的目录下(命名为jre1.4),然后修改通讯前置配置工具的启动脚本run.bat为:
    start ./jre1.4/bin/javaw.exe -cp
    ./lib/commons-httpclient-2.0-beta1.jar;./lib/commons-logging.jar;./lib/jgraph.jar;./lib/PropertyPanel.jar;./lib/Utility.jar;./lib/xalan.jar;./lib/tools.jar;./lib/workflow.jar;./lib/org.mortbay.jetty.jar
    cn.com.icbc.bice.ui.ConfigMainPanel

        一切OK!




    posted @ 2007-10-19 19:01 CowNew开源团队 阅读(549) | 评论 (0)编辑 收藏

     

    VirtualBoxforLinuxHost-Only设定

    类似VMwareHost-only的作法,需要建立虚拟网卡和GuestOS来通讯。

    工具 tunctl 可从 uml-utilities套件中取得。

    建立虚拟网卡:

    # tunctl -t vmnet1(网卡名称可自定) -u atsiv(使用者名称)

    此时用ifconfig -a 查看会多出一个虚拟网卡界面。

    # chmod 666 /dev/net/tun

    为虚拟网卡设定 IP (私有private ip)

    # ifconfig vmnet1 192.168.0.1 netmask 255.255.255.0

    VirtualBox的设定:

    Attached to 选择 Host Interface

    Interface Name 键入 vmnet1(就是上面所设的名称)

    然后在GuestOS中设定同网段的IP,例如 192.168.0.2

    HostOSGuestOSPing看看是否可连通。

    若要让GuestOS也可架站或连上网络,则可在HostOS中用iptables设定DNAT, SNAT即可。

    删除 虚拟网卡

    # tunctl -d vmnet1

    目前用CentOS 4.4 母机养了一只Win2K小机。

    转贴自:http://www.xuniji.com/forum/view.asp?id=7661&p=1&page=1

    杨中科注:如果按照上面方法设置还ping不通的话,请查看是否是防火墙的问题,可以将GuestOSHostOS的防火墙的ping规则放开。由于我是用VirtualBox做没有网络环境时候的数据库服务器用的,不会有网络攻击的问题,所以我干脆直接将两个系统的防火墙都关掉了。对于HostOS来说只要关闭针对于虚拟网卡的防火墙就可以了。

    posted @ 2007-10-17 22:16 CowNew开源团队 阅读(783) | 评论 (0)编辑 收藏

    设定lib包下所有的jar到classpath
    1、windows下的方法:
    首先创建文件setenv.bat,内容如下:
    set CLASSPATH=.\bin\
    for %%f in (".\lib\*.jar") do call cpappend.bat %%f

    然后创建主脚本:
    if "%OS%" == "Windows_NT" setlocal
    call setenv.bat
    java cn.com.agree.isbp.schedule.Startup
    if "%OS%" == "Windows_NT" endlocal
    2、Linux下的方法:
    首先创建文件setenv.sh,内容如下:
    #!/bin/sh
    CP=./bin/
    for i in ./lib/*.jar
    do
        CP="$i:$CP"
    done
    export CP
    然后创建主脚本:
    #!/bin/sh
    source setenv.sh
    java -cp "$CP" cn.com.agree.isbp.schedule.Startup &

    posted @ 2007-10-12 15:57 CowNew开源团队 阅读(896) | 评论 (0)编辑 收藏

    今天需要为产品增加Linux下的启动脚本,编写完成运行以后发现不能正常执行,而是提示:
    'etenv.sh:line 4:syntax error near unexpected token do
    检查脚本没有发现任何语法问题。经过自己研究发现是不同的系统下换行符造成的。我是在Windows下的Eclipse中编写的脚本,然后通过虚拟机的共享目录方式传递到虚拟机中的Linux中的,这样换行符就是Windows格式的了,使用Dos2Unix等工具或者直接使用UE的DOS转Unix功能转换以后就正常了。
    posted @ 2007-10-12 15:43 CowNew开源团队 阅读(1996) | 评论 (0)编辑 收藏


    - 你是否渴望用程序自由的书写思想?
    - 你是否渴望淋漓尽致地培养并施展自己的才能?
    - 你是否渴望加入一支志同道合的团队,共同成就一番事业,并最终推动一个行业的进步?

    请加入我们,把你的渴望变成现实!
    ---- 赞同科技-产品开发部
    ====

    赞同科技产品开发部诚聘软件工程师。公司提供有竞争力的薪资福利,开放和谐的工作环境,广阔的成长空间。

    职位描述:
    负责面向银行软件系统的各类软件研发

    发展方向:
    软件设计,系统架构,方案咨询

    招聘人数:
    北京4人,上海4人。

    职位要求:
    1 对软件技术怀有浓厚兴趣,思维敏捷,视野开阔;
    2 硕士 或 本科 学历,专业不限;
    3 熟练运用Java、C或C#语言进行软件开发;
    4 丰富的软件项目经验;
    5 如果广泛了解各种软件技术,例如Eclipse RCP、.Net WPF、Linux/Unix、Python更佳。

    期待着你的加盟!

    应聘北京职位请发送简历至 pu.yun@agree.com.cn
    应聘上海职位请发送简历至 xu.hb@agree.com.cn

    欢迎随简历一起发送一份你自认为算是个人杰作的介绍,可以是程序的抓图,可以是一篇文章,一个网页链接,也可以是一段代码(字如其人,代码也是).请注意不要涉及版权、保密等敏感信息。

    ====

    赞同公司简介:

    北京赞同科技发展有限公司成立于1993年,是集金融软件开发、销售、服务为一体的高新技术企业。

    客户主要为金融行业客户,主要包括:工商银行,建设银行,交通银行,广东发展银行,北京银行,恒丰银行,各种商业银行及地方农信等。

    作为一家资深金融软件开发公司,目前拥有上海、广州、西安三地直属分部。

    公司主页:http://www.agree.cn/
    ====

    赞同公司 产品开发部简介:

    产品开发部负责公司各系统多条产品线的研发,与北京、上海、广州等地的事业部紧密配合,通过提供优秀的执行平台、开发工具、运维平台,为工行、建行、交行、广发、北京银行等多家银行提供高品质的服务。

    主要产品线包括:
    - 前端系统产品线。主要包括传统的unix字符终端的AHA系统,c/s结构使用IE浏览器的AE系统,b/s结构使用web浏览器的eTeller系统,b/s结构基于插件体系RCP的AB系统等。

    - 中间业务产品线。主要包括中间业务联机处理AFA系统,中间业务批量处理ISBP系统,联机批量报表aReport系统等。

    - 渠道整合产品线。主要包括通讯前置AFE系统,企业渠道整合ECI系统等。

    - 监控运维产品线。CAMA集中监控运行维护管理平台,并结合与前三条产品线多个产品相关的多套适配器,针对不同银行不同系统环境提供可定制产品。

    - 集成开发环境产品线。与前四条产品线多个产品相关的多套IDE产品,基于插件体系,可自由组合定制。

    - 业务系统产品线。在前五条产品线的基础上,提供针对新兴金融服务业务的一揽子解决方案,例如影像工作流、流程再造、小额支付系统、支票截留系统等。

    公司简介请点击此处:http://www.blogjava.net/Files/huanzhugege/03-赞同科技简介.zip

    posted @ 2007-10-08 13:14 CowNew开源团队 阅读(642) | 评论 (0)编辑 收藏

    源码:
    public class Main
    {
     public void main(String[] args)
     {
      int a = (int) 3.14;
      a++;
      a=a+1;
      a=a+2;
      System.out.println(3+4);
      List list = new ArrayList();
      list.add(1);
      
      List<String> list2 = new ArrayList<String>();
      list2.add("333");
     }
    }

    反编译以后:
    public class Main
    {
      public void main (String[] args)
      {
        int a = 3;
        a++;
        a++;
        a += 2;
        System.out.println (7);
        java.util.List list = new ArrayList ();
        list.add (Integer.valueOf (1));
        java.util.List list2 = new ArrayList ();
        list2.add ("333");
      }
    }

    posted @ 2007-09-30 10:46 CowNew开源团队 阅读(1409) | 评论 (7)编辑 收藏

          准备开始翻译Antlr的文档,已经取得了Antlr的作者Terence Parr的授权,将会做为Antlr的中文官方文档发布。
          有兴趣一起翻译的请和我联系,目前Long、阿乐等人已经加入。有意加入的请首先完成下面的几个问题,然后Email给我(about521 at 163.com),并告知您的联系方式等信息:
    1、请翻译下面的段落:
    A lexer (often called a scanner) breaks up an input stream of characters into vocabulary symbols for a parser, which applies a grammatical structure to that symbol stream. Because ANTLR employs the same recognition mechanism for lexing, parsing, and tree parsing, ANTLR-generated lexers are much stronger than DFA-based lexers such as those generated by DLG (from PCCTS 1.33) and lex.
    2、编译器的六个阶段:_____、_____、语义分析、中间代码生成、代码优化和代码生成。
    3、(1+2)*3的抽象语法树是什么样的?
    posted @ 2007-09-28 10:54 CowNew开源团队 阅读(1546) | 评论 (2)编辑 收藏

    CowNewSQL发布新版本了,这个版本的推出标志着CowNewSQL能正式应用于开发实际了。
    本版更新列表:
    1、增加了对Create Table、Drop Table、Create Index和DropIndex的支持。

    2、修改了N多Bug,使用从各方收集到的近百条各种复杂的SQL语句全面测试通过!!!

    3、完善开发文档,语法规则、SQL例子、函数列表、使用方法一应俱全。

    4、支持JDK1.4或更高版本。

    下载地址:http://www.cownew.com/download/

    CowNewSQL简介:

           由于种种原因,各个数据库系统的SQL语句语法以及支持的函数都不尽相同,这造成了如下两个问题:(1)使得系统在多个不同数据库之间移植变得非常困难,特别是需要维护多个数据库版本的时候;(2)开发人员必须对各种数据库的语法差异非常了解,这加大了开发难度。

           虽然Hibernate通过HQL等技术部分的解决了跨数据库移植的问题,但是在对性能要求比较高的场合还是需要直接使用SQL语句访问数据库的,在这种情况下如何编写能被不同数据库支持的SQL语句就成了。目前解决这种差异的最常用的技术就是SQL语句翻译,使用SQL翻译器可以将SQL语句翻译为在不同的数据库中支持的特定平台的SQL语句。CowNewSQL就是这样一款产品。

           CowNewSQL简化了跨数据库产品的开发,比如取当前日期在MSSQL中是“SELECT GETDATE()”,在MYSQL中是“SELECT NOW()”,在Oracle中是“SELECT SYSDATE FROM DUAL”,使用CowNewSQL以后您只要使用“SELECT NOW()”,那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句,而且CowNewSQL的兼容性也非常好,比如“SELECT NOW()”写成“SELECT GETDATE()”同样可以被正确的翻译;取数据库前10条记录,在MSSQL中是“Select top 10 from T_1”、在MYSQL中是“SELECT  LIMIT 0, 10 ”、在Oracle中是“SELECT  FROM DUAL WHERE ROWNUM <= 10”,使用CowNewSQL以后您只要使用“Select top 10 from T_1”,那么CowNewSQL就会为您自动将其翻译为对应数据库平台支持的SQL语句。

        CowNewSQL还通过变通的方式对目标数据库不直接支持的语法进行了支持。比如MYSQL是不支持“select * from t1 where fid in(select fid from t2 limit 0,5)”这样在子查询中的Limit语句的,CowNewSQL通过将子查询进行二次结果集包装的方式巧妙的对其进行了支持,“delete from T_SaleInvoice where FId in(select top 5 FParentId from T_SaleInvoiceDetails)”通过CowNewSQL的翻译以后就成了“DELETE FROM T_SaleInvoice WHERE FId IN (select * from(SELECT FParentId FROM T_SaleInvoiceDetails LIMIT 0, 5 ) t_temp_sub)”这样被MYSQL支持的语法了;MYSQL中没有提供计算两个日期之间月份差异的函数,CowNewSQL通过组合其他日期函数的方式模拟了这个函数,这样使用者只要使用MONTHS_BETWEEN函数即可了,无需关心内部的差异。

    CowNewSQL支持如下几种类型的SQL语句:CreateTable/DropTable/CreateIndex/DropIndex/Select/Insert/Delete/Update;支持子查询、JoinUnion等高级的SQL特性;支持日期(包括取当前日期、从日期中提取任意部分、计算日期差异、日期前后推算等)、数学(包括取绝对值、取PI值、四舍五入、对数计算、随机数等)、字符串(包括取子字符串、取字符串长度、字符串截断、大小写转换等)、基本数据处理(包括数字字符串互转、日期转字符串、非空判断等)等函数。

    下载地址:http://www.cownew.com/download/

    posted @ 2007-09-21 19:39 CowNew开源团队 阅读(2318) | 评论 (11)编辑 收藏

    一直无法开启TurboLinux的Telnet和FTP服务,根据网上提供的方法也不凑效。下面是我的一位同事写的TurboLinux下开启Telnet和FTP服务的方法,版本是TurboLinux 7.1 SP2 DataServer。使用他的方法就能成功开启了:


    =============================
    1、配置telnet服务
    =============================
    (1)检查配置
     # chkconfig telnet on

    (2)修改 /etc/hosts.allow
    加入
     in.telnetd : ALL

    (3)修改 /etc/pam.d/login
    注释掉
     auth required pam_securetty.so

    (4)关闭放火墙
     # /etc/init.d/iptables stop

    (5)修改 /etc/xinetd.conf
    放大并发数到
     instances=600
    因为只是测试用,也不用太大了(可以不改而用系统的默认值)

    (6)重启xinetd服务
    #service xinetd restart


    =============================
    2、开启服务
    =============================

    在图形方式下,可以通过系统的管理工具完成下面的开启及停止工作,也可以用下面的命令操作

    (1)开启ftp
    #service proftpd start

    (2)开启telnet
    编辑/etc/xinetd.d/telnet,把disable=yes修改为disable=no,保存退出(与命令chkconfig telnet on作用相同);
    #service xinetd restart

    (3)编辑/etc/hosts.deny
    在ALL : ALL 前面加#注释这一行。
    最好修改 /etc/hosts.allow文件,系统默认拒绝不在该文件中列出的所有服务请求,即/etc/hosts.allow文件记录对外开发的服务,
    否则修改/etc/hosts.deny文件,把所有的服务对外开放可能引来系统安全性问题。

     

    posted @ 2007-09-13 09:52 CowNew开源团队 阅读(1417) | 评论 (2)编辑 收藏

    第三次沈阳徒步开始,上午11点30出发,下午7点30返回,总行程约28公里。路线如下:
    天光小区—市府广场—市府大街—北一东路—北一中路—北一西路—重工北街—建设西路—建设中路—建设东路—南五马路—青年大街—大西路—天光社区
    posted @ 2007-09-01 22:12 CowNew开源团队 阅读(328) | 评论 (0)编辑 收藏

    本周第二次沈阳徒步开始,上午11点出发,下午7点返回,总行程约25公里,由于手机忘了充电了,所以没拍照。路线如下:
    天光小区-市府广场-北京街-昭陵-新乐遗址-航空学院-医学院-沈阳外环路-沈阳农科院-辽宁大学-西塔-太原街-南京街-和平大街-大西路-天光小区
    posted @ 2007-08-25 23:17 CowNew开源团队 阅读(347) | 评论 (0)编辑 收藏

    1
    top 看当前运行的进程
    kill -9 pid 终止某进程(树)
    cd 返回根目录
    pwd 显示当前目录
    3 less more查看文本文件指令 在less中打入v键就会启动vi编辑当前文件
    4 mkdir、rm mv 改变文件名和目录名的命令
    cp 复制文件和目录命令
    man 命令使用方法参考工具,很有用
    nano是一个小巧自由,并且友好的编辑器
    5
    vi有两种模式,一种是命令模式,一种是编辑模式。进入vi以后,默认处于命令模式。

    现在我们执行vi LoveLetter。进入以后,按一下键盘上的Insert功能键或者i键可以进入编辑状态,可以插入字符,再按一下Insert变成复盖模式,这两种模式的区别很容易体现,大家尝试一下就可以了。上下左右四个方向键可以移动光标。基本的编辑命令和Windows里面没有区别。是不是很容易呢?当你把需要的内容输入完成以后,我们要保存,这时候按一下ESC键从编辑模式回到命令模式,首先输入一个冒号“:”,也就是按住SHIFT键不放再按分号“;”这样首先输入一个“:”,然后,输入w,回车,就可以保存我们编辑的内容到LoveLetter文件。现在我们按一下Insert就可以继续编辑。再按ESC,输入“:”,再按w又可以保存。可是现在我们不需要保存,我们想要不保存就退出,怎么做呢?当我们输入w的时候是write的意思,保存,那么我们输入q就是quit退出的意思。好,输入q,回车,vi提示我们刚才进行的修改还没有保存,所以记住!一旦需要放弃我们的修改,不能直接用q命令退出,而需要用“q!”命令。输入q!,好了,退出了。
    我们想看看我们刚才编辑的LoveLetter是不是真的保存好了,再vi LoveLetter,ok,看到了吧?现在我们想要直接退出,就可以只输入“:q”就可以了,不用输入那个“!”因为我们没有修改文件内容。如果我们修改一下这篇文章,我们在退出的时候可以输入“ESC : wq”就可以了。不需要把w和q分成两次输入。
    6 linux中可以用amount命令将iso文件挂接为目录:mount -t iso9660 -o loop /home/kris/somewhat.iso /mnt/cdrom
    7 file 检查文件的类型
    8 wall write mesg
    9 reset 重置终端,当屏幕发生问题的时候用此方法
    10 env 显示环境变量
    11 改变系统语言的方式:运行 export   LC_ALL="en_US"   LANG=en_US 就可以改成英文。要想一直输出E文.可以到 /etc/sysconfig/i18n里修改LANG="en_US. Utf-8"
    12 查看本机ip:ifconfig -a
    13 mount光盘:mount/dev/cdrom /mnt/cdrom,然后就可以在/mnt/cdrom中看到光盘内容了 。用umount /mnt/cdromo 可以卸载光盘。只有卸载光盘以后才能将光盘弹出。
    14 在linux的提示符下输入文件名等的时候,可以输入部分文件名然后按Tab键即可智能补全。
    15 redhat中安装rpm包的方法:rpm -i "包路径";要升级包可以rpm -U packagename。包的删除比较容易,使用:# rpm -e packagename就能够删除自己想要删除的包,不需要知道版本和路径
    16 启动即运行vsftp方法,运行ntsysv,选中列表中的vsftpd即可。
    17 查看文件内容:cat 文件名
    18 find / -name "*network*" -print 查找根目录下所有包含network的文件
    find / -iname "*network*" -print 查找根目录下所有包含network的文件,忽略大小写
    19 useradd user1 建立一个用户,不过在为用户设定密码之前这个用户是不能使用的,设定密码的命令为passwd user1
    20 ls的时候文件名旁边如果有“*”号,表示它是可执行文件,只要运行“*/文件名”即可运行。
    21 重启网络service network restart
    22 字符界面进入图形界面:startx,图形界面返回字符界面:注销即可。
    23 安装VMWare,然后虚拟机网络类型选NAT即可实现主机和虚拟机之间的通信,要远程登录linux还需要安装telnet服务,root默认不能通过telnet登录
    24 删除非空目录:rm -rf 目录名
    25 解压cpio的方法:cpio -idmv < ***.cpio
    26 UE中编辑的shell脚本到unix中运行提示“h^M: is not an identifier”,解决方法:dtox a.txt >b.txt 转换为unix格式,或者使用UE中的“文件”“转换”“DOS转Unix”功能。第二种更方便
    27 find /usr -name httpd
    28 解压some.tgz的方法:首先gunzip some.tgz,生成some.tar,然后tar -xvf some.tar解压
    29 将gcc加入路径的方法:
    PATH=$PATH:/usr/gnu/bin/
    export PATH
    30 sh脚本的变量的赋值等号两边不能有空格
    31 sh脚本中命令行之间不能有空行,if语句后的条件前后要有空格
    32 判断当前终端类型echo $TERM
    33 重新获取ip的方式:/etc/init.d/network   restart  
    34 Linux中录入ESC转义符的方法:首先按下Ctrl+V,然后按下ESC键
    35 以后台方式运行一个程序,也就是脚本退出、shell退出都不会导致程序退出:命令后加“&”
    36 登录自启动的脚本放在“/etc/profile”文件中,比如配置Java的环境变量就必须在这个文件中加入:
    pathmunge /usr/java/j2re1.4.2_14/bin/ after
    JAVA_HOME="/usr/java/j2re1.4.2_14/"

    注意JAVA_HOME中的等号两边不能有空格,否则JAVA_HOME会被当成命令处理!!!!!!!!!!!!!!!!!!!1
    37 如果系统出现乱码修改LANG环境变量即可。以前批量系统就出现过此问题
    39 windows下的trace对应Linux的"traceroute ip地址"
    40 Linux下使用U盘的方法,插入U盘,在mnt下创建目录usb;然后运行“fdisk -l”,这样会显示所有的设备,因为一般的U盘都是Fat格式的,所以找到格式为FAT的硬盘的标识符,比如sdb1,然后运行mount -t vfat /dev/sdb1 /mnt/usb;这样就U盘就挂接到/mnt/usb下了;卸载的时候umount /mnt/usb

     

    posted @ 2007-08-23 20:06 CowNew开源团队 阅读(1066) | 评论 (0)编辑 收藏

        上次换工作,给自己说了一万遍“打死也不做应用系统开发”,稀里糊涂的又来做应用开发了,项目又要上线了,SB客户整天催,什么这帐户、那扣税的,一听就烦。客户竟然还敢骂本尊,靠!!!真想暴揍他一顿,你个SB客户算个算狗屁!!!好在我强压心中怒火,没爆发。。。不知道还能憋几天。。。
        好想做纯技术开发,再也不用管那些恶心的“业务流程”,一心写代码,老天呀,给条明路吧!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    posted @ 2007-08-16 20:53 CowNew开源团队 阅读(769) | 评论 (14)编辑 收藏

      为了减肥,为了锻炼,我决定以后每周至少一次全天徒步锻炼。这天是第一次,上午10:30出发,下午6点返回,总行程约18公里,路线:天光小区——故宫——顺着大东路走——顺着长安路走——顺着东滨河街走——下木厂——滨河路——文萃路——青年大街————达到浑河大桥以后顺着青年大街返回天光小区。

    下面是用低分辨率的手机拍摄下来的沿途风景:

     

    沈阳的造币厂

     

    沈矿集团

     

    开始进入郊区

     

    郊区某路口

    看到运河了

     

    东塔1

    东塔2

    运河上的桥

     

    运河好直

     

    运河好美

     

    运河畔,动物园前

     

     

    尊重科学家

     

    家乐福

     

    夏宫前的迎奥运标志

     

    浑河

     

    浑河畔的垂钓者

     

    此次到达的最南端——浑河大桥

    posted @ 2007-08-15 23:59 CowNew开源团队 阅读(818) | 评论 (8)编辑 收藏

    1、map的声明方法:
     m={"1"=>"3","2"=>"aa"}
    2、if count>10
         ....
       elsif c<3
       else
        ...
       end
    3、while c<3
       ...
       end
    4、正则表示式方法:
    /d3/
    有match等方法
    判断字符串的匹配:
    if line=~/Perl|Python/
       ...
    替换:
    line.sub(/Perl/,'Ruby')将第一个Perl替换成Ruby
    line.gsub(/Perl/,'Ruby')将所有Perl替换成Ruby
    5、block的使用:
     as = ["2","66"]
    as.each{|a|print a}
    6、变量的作用域:@成员变量,@@类变量,$全局变量
    7、
    class Person
      def initialize(name,age)
        @name = name
        @age = age
      end
      def say()
        print "我叫"+@name
        print "#@age"
      end
    end

    p = Person.new("tom",20)
    p.say()
    print p.inspect#反射显示对象的内容
    8、类方法与类变量:
    class Person
      @@count = 0
      def Person.doIt
      end
    end
    9、数组的子数组:
    a=[1,2,3,5]
    a[1..3]→[2,3,5]
    切片
    a=[1,2,3,5]
    a[0..2]=[4]
    a→[4,5]
    10、for语句:
    for i in 0..100
       print i
    end
    11、block:
    def a
      for i in 0..100
        yield i
      end
    end

    a{|f|puts f}
    带返回值的block:
    def a
      for i in 1..100
        if yield i
          puts "接受"+i.to_s
        end
      end
    end

    a{|v|v>90}

    应用强大的block:
    m={}
    (1..100).each{|a| m[a]=a**a}
    m.each{|a|puts a}
    12、block与变长参数:
    class FileProcess
      def FileProcess.process(*args)
        f = File.open(*args)
        yield f
        f.close()
      end
    end

    FileProcess.process("c:/boot.ini","r"){
      |file|
      while line=file.gets
        puts line
      end
    }
    另一种用法:
    FileProcess.process("c:/boot.ini","r") do |file|
      while line=file.gets
        puts line
      end
    end
    13、闭包:
    class MyClass
      def initialize(&action)
        @action = action
      end
      def begin()
        for i in 1..100
          if i>90
            @action.call(self)
          end
        end
      end
    end

    a = MyClass.new(){puts "超限"}
    a.begin()

    lambda:
    a = lambda{|n| puts n}
    a.call(3)
    14 数字:
    6.times{|i|puts i}
    1.upto(5){|i| puts i}
    50.step(100,10){|i| puts i}
    15 转化
    a="33"
    b="55"
    puts Integer(a)+Integer(b)
    puts a.to_i+b.to_i
    puts a*3
    16 字符串中内嵌ruby表达式
    puts "He#{'l'*100}o"
    puts "1+1=#{1+1}"

    city = "peking"
    y=2008
    puts "#{city}-#{y}"
    注意只有用双引号括起来的才支持内嵌表达式
    17 puts "2005|03|08".split(/\|/)
    18 Range
    ('a'..'f').each{|c| puts c}
    Range转化为数组:puts ('a1'..'a9').to_a
    19 返回bool的方法通常以?结尾,修改对象状态的方法以!结尾
    20 自定义复数:
    class FuNum
      def initialize(shi,xu)
        @shi=shi
        @xu=xu
      end
     
      def xu
        @xu
      end
      def shi
        @shi
      end
      public :shi,:xu
     
      def +(other)
        newshi = @shi+other.shi
        newxu = @xu+other.xu
        return FuNum.new(newshi,newxu)
      end 
     
      def to_s()
        return "#{@shi}+#{@xu}i"
      end
    end

    i = FuNum.new(1,2)
    j = FuNum.new(2,9)
    puts i+j
    21 交换两个变量(并行赋值):
    a=20
    b=30
    c=40
    a,b,c=c,b,a

    print a,b,c
    python也支持
    22 Case语句:
    a=1
    salary=case a
          when 0..100 then 3000
          when 101 then 333
          else 888
          end
         
    puts salary
    Case语句的When部分还支持正则表达式
    case line
    when /title=(. )/
    puts"Titleis#$1"
    when/track=(. )/
    puts"Trackis#$1"
    when/artist=(. )/
    puts"Artistis#$1"
    end
    23 异常处理
    begin
      raise "33333333"
    rescue RuntimeError
      #$!表示异常信息
      print $!
      #再次抛出
      raise
    end

    begin
      raise "33333333"
    rescue RuntimeError
      #$!表示异常信息
      print $!
      #再次抛出
    ensure
      print "无论如何都被打印"
    end

    还可以在rescue中调用retry来重新执行程序块
    24 模块
    CowNew.rb模块文件
    module CowNew
      PI = 3.14
      def CowNew.calc(r)
        return 2*PI*r
      end 
    end

    调用者Main.rb
    require "CowNew"
    puts CowNew.calc(3)
    从文件加载模块:
    load "E:/greeninst/eclipse3.2.2/eclipse/workspace/r/CowNew.rb"
    25 文件处理:
    f = "E:/greeninst/eclipse3.2.2/eclipse/workspace/r/CowNew.rb"
    puts IO.read(f)
    puts IO.readlines(f)

    逐行处理:
    f = "E:/greeninst/eclipse3.2.2/eclipse/workspace/r/CowNew.rb"
    i=IO.foreach(f){|line| puts line}

    f = "E:/greeninst/eclipse3.2.2/eclipse/workspace/r/CowNew.rb"
    i=0
    IO.foreach(f) do |line|
      i=i+1
      print i,"  ",line
    end
    26 流:STDOUT<<33<<"adfa"
    27 Ruby专用Http服务器,支持eruby,免得使用Apache,调试方便:
    require "webrick"
    include WEBrick
    server = HTTPServer.new(:DocumentRoot=>"E:/俺的文档/个人资料/网站安全/cownew空间/")
    server.start()

    在目录web下创建rhtml文件,增加服务器:
    require "webrick"
    include WEBrick
    server = HTTPServer.new(:DocumentRoot=>File.join(Dir.pwd,"web"))
    server.start()
    自定义Servlet:
    require "webrick"
    include WEBrick

    class HelloServlet<HTTPServlet::AbstractServlet
       def do_GET(req,res)
         res["Content-Type"] = "text/html"
         res.body="aaaaaaaaa"
       end
    end
    server = HTTPServer.new(:DocumentRoot=>File.join(Dir.pwd,"web"))
    server.mount("/hello",HelloServlet)
    server.start()

     

    posted @ 2007-08-02 20:09 CowNew开源团队 阅读(417) | 评论 (0)编辑 收藏

    Commons-Lang

    一、org.apache.commons.lang

    1CharRange用来判断一个Char是否位于某个范围内;

    2CharSet判断一个或者多个字符是否位于一个字符集合中;

    3CharSetUtils用来替换字符串、计算一个字符串中某个字符的出现次数等;

    4ObjectUtilsdefaultIfNullequalstoString(当null时可以为空格或者默认值)。

    5SerializationUtils序列化用cloneserialize(序列化到流中或者序列化为二进制字符串)、deserialize

    6StringUtils:判断是否是数字,截取某个分隔符前后的字符串,交换大小写,将多个Object类型的join为一个字符串,一个字符串重复n次,反转字符串,将某个字符串居中//右对齐。

    7SystemUtils:读系统变量

    8ClassUtils进行反射调用,比如得到一个类的包名、类名、所有接口、所有父类

    9StringEscapeUtils将字符串格式化为符合HTMLSQLJavaScript等能否使用的字符串

    二、org.apache.commons.builder

           方便构建equalscompareTohashCode方法。

    三、org.apache.commons.exception

           ExceptionUtils用来为Nest异常脱皮,将异常转换为异常字符串(调用堆栈)或者将异常字符串转换为异常堆栈。NestableRuntimeException嵌套运行时异常。

    四、org.apache.commons.time

    1DateFormatUtils:格式化日期

    2StopWatch跑表

    五、其他

    ArrayUtils,字符串操作。toString方法用来返回数组的字符串形式(比如new int[]{3,5,7,2,3,4}转换为{3,5,7,2,3,4});hashCode方法得到数组的hashcodeclone得到数组的拷贝;toPrimitivetoObject等用来在Wrapped数组和原生数组之间转换;

    commons-configuration

        用来提供配置文件保存和加载,能以xml这样的层级格式保存。

    commons-IO

    一、CopyUtils

        提供将对象拷贝到流中,将输出流拷贝到输入流中,

    二、FileUtils

        byteCountToDisplaySize:得到字节大小的通俗表示,比如3MB

        copyFileToDirectory:将文件拷贝到某目录;

        deleteDirectory:删除目录

        cleanDirectory:清理目录

           readFileToString:将文本文件读取到字符串中

           writeStringToFile:将字符串写到文本文件中

    三、HexDump

           以类似于UE的方式显示二进制数据,例子:

                  byte[] datas = SerializationUtils.serialize(Boolean.TRUE);

                  ByteArrayOutputStream bos = new ByteArrayOutputStream();

                  HexDump.dump(datas, 0, bos, 0);

                  System.out.println(bos.toString());

                  IOUtils.closeQuietly(bos);

    四、IOUtils

           closeQuietly:关闭各种资源

           toString:得到InputStream的字符串形式

           toByteArray:得到InputStream的二进制形式

           contentEquals:两个InputStream是否相等

     

    posted @ 2007-07-17 22:51 CowNew开源团队 阅读(594) | 评论 (0)编辑 收藏

        《J2EE开发全程实录》的随书光盘中的案例配置比较麻烦,如果要运行起来需要修改很多配置,而且要求用户必须使用WTP、Tomcat、MSSQLServer。为了方便读者学习,作者对其进行了优化,与书中的代码比起来有如下变化:
    1、将演示数据库由MYSQLServer修改为HSQL
    2、由Tomcat改为使用内嵌Jetty部署和开发
    3、修正了配置文件中对Windows操作系统的依赖(比如使用C盘,使用\分割路径等),能够真正跨平台
    4、数据源配置方式由从应用服务器JNDI方式改为通过Commons-DBCP,增加可移植性
        您无需对系统进行任何配置、无需安装数据库、无需部署Web服务器,只要您的系统中安装了JDK或者JRE,那么点击几下鼠标即可轻松运行本系统,真正做到“下载之后立即运行”,打造绿色的Java软件。
        源码下载地址:http://www.onlinedown.net/soft/59588.htm 
        《J2EE开发全程实录》读者专区:http://www.cownew.com/bbs/

    posted @ 2007-07-17 21:24 CowNew开源团队 阅读(976) | 评论 (2)编辑 收藏

        经过几天发布版的准备,CowNewPIS终于公开发布了。CowNewPIS是一款基于MDA理念研发的新一代技术平台。它采用开放的J2EE 技术,跨平台、跨数据库,系统具有非常高的可扩展性,可以基于CowNewPIS快速搭建出复杂的企业级应用。从技术角度来讲,CowNewPIS有机的融合了Spring、Hibernate、Struts、Swing等主流的J2EE技术,并且创造性的提出了Spring分布式开发解决方案、DTOGenerator(OSIV的杀手)、基于AOP的权限框架实现、Swing控件库、Web控件库等技术。系统搭建过程中合理的使用了面向对象的开发思想,并且将主流的设计模式融合起来,无论是对于想学习J2EE开发技术,还是想深入了解企业级系统建模的人员,CowNewPIS都是非常好的实际案例。源码包中还包含了关于CowNewPIS的设计开发文档(《J2EE开发全程实录》的部分章节),源码和文档结合起来的话将能帮助你更加快速和有效的学习到你想学习到的知识。
        此版本与以前内部发布版本比起来有如下几个优点:
    1、将演示数据库由MYSQLServer修改为HSQL
    2、由Tomcat改为使用内嵌Jetty部署和开发
    3、修正了配置文件中对Windows操作系统的依赖(比如使用C盘,使用\分割路径等),能够真正跨平台
    4、数据源配置方式由从应用服务器JNDI方式改为通过Commons-DBCP,增加可移植性
        您无需对系统进行任何配置、无需安装数据库、无需部署Web服务器,只要您的系统中安装了JDK或者JRE,那么点击几下鼠标即可轻松运行本系统,真正做到“下载之后立即运行”,打造绿色的Java软件。
        源码及开发文档下载地址:http://www.onlinedown.net/soft/59588.htm
        CowNew开源团队:http://www.cownew.com
    posted @ 2007-07-17 21:13 CowNew开源团队 阅读(1409) | 评论 (5)编辑 收藏

    北京赞同科技发展有限公司是一家金融软件行业的专业公司,目前公司已经形成包括前端(柜台)系统、大前置(中间业务)系统、通讯前置(通讯中间件)系统、业务集中监控管理系统等多条产品线,公司客户主要有中国工商银行、中国建设银行、交通银行、广东发展银行、北京银行、恒丰银行、烟台商业银行、石家庄商业银行及一批农信社,公司与Intel、HP等主流硬件厂商也有密切的合作。

    产品开发部是公司的产品研发部门,主要负责公司核心产品的开发、维护,随着公司业务规模的扩大及产品研发任务的不断提出,长期需要以下两类人才:


    1、高级软件工程师及系统架构师

    职位描述:
    (1)参与或主导公司核心产品的研发
    (2)为产品推广提供技术支持

    基本要求:
    (1)扎实的计算机软件基础,精通JAVA或C/C++,熟悉常见操作系统及数据库系统
    (2)对计算机软件技术有强烈的兴趣,爱好钻研新技术
    (3)英语6级以上



    2、产品经理

    职位描述:
    (1)负责公司现有产品的推广及后续发展
    (2)为产品应用实施人员提供技术支持

    基本要求:
    (1)扎实的计算机软件基础,精通JAVA或C/C++,熟悉常见操作系统及数据库系统
    (2)丰富的应用实施及产品维护经验
    (3)良好的沟通能力
    (4)英语4级以上



    欢迎广大爱好计算机软件、有长期事业规划的有志青年加入我们的队伍。有兴趣请通过电子邮件投递简历,简历至少包含以下内容:
    (1)教育经历
    (2)工作、实习经历,包括项目经验
    (3)特长及爱好

    我的邮箱: chen.xm@agree.com.cn

    posted @ 2007-07-16 00:14 CowNew开源团队 阅读(565) | 评论 (1)编辑 收藏

    本版解决问题:

    1、可以在eclipse3.1、eclipse3.2下正确运行

    2、支持JDK1.4、JDK1.5

    下载地址:
    http://www.cownew.com/download/com.cownew.studio_1.1.0.jar
     

    J2EE开发全程实录》试读地址:http://book.csdn.net/bookfiles/427/
    posted @ 2007-07-15 18:38 CowNew开源团队 阅读(1232) | 评论 (4)编辑 收藏

    刚入职要谦虚谨慎。多交朋友,多认老师。刚毕业一定要非常谦虚 。记住在企业里和学校不一样。没人能耐心去教你,你必须要学会自己去找资源学习,加强自学能力。
    不要把入职导师当成老师,他只是“导师”,“指导你学习”。
    不要什么问题都问,要学会掂量问题的分量,注意提问的时间(别人忙的时候不能打扰),注意提问的技巧。
    同事不是同学,他们都有自己的事情,不要招人烦,同样是注意提问的技巧,不要什么都问,也不要什么都不问。不要什么都问,也不要什么都不问 。思考后再问,问的时候说一下自己的看法,不要问“这个问什么运行不起来”。而要“我这个运行不起来,因为我进行了如下操作。。。。,我分析问题的原因是。。。,我是这么解决的。。。,但是还是不行” 。不要把自己定位的太死。不要把自己定位为“做Java的Web开发的程序员”,而是“不管什么类型的项目、什么语言都能灵活应对的软件工程师” 。

    J2EE开发全程实录》试读地址:http://book.csdn.net/bookfiles/427/
    posted @ 2007-07-14 18:52 CowNew开源团队 阅读(707) | 评论 (4)编辑 收藏

    靠,气死了!!!!!!!!
    chinapub上的人怎么这样,张嘴闭嘴就骂人!!!!!!!!
    vtmas是群里哪位兄弟,谢谢帮我鸣冤,兄弟在这跪谢了!!!以后不去chinapub看书评了!!!!!!!
    我容易吗!!!!!!
    书好你就看,不好拉倒!!
    真想回帖骂他们一顿!!!!!!!!!!!!!!!!!!!
    书还没上市就惹一肚子气!!!!!!!!!!!!
    什么素质呀!!!
    posted @ 2007-07-08 20:54 CowNew开源团队 阅读(502) | 评论 (4)编辑 收藏

       

          现在大部分软件开发书籍都是讲解某个技术如何用,很少有讲实战的,即使有实战案例的讲解,也是讲解网上购物、聊天室之类已经被人写烂了的系统的开发,最可怕的是书中的实现代码惨不忍睹,使得读者很容易被误导,至于如何进行合理的架构设计就更无从谈起;少数从国外引进的高端技术书籍又大谈特谈各种在天上飞来飞去的理论,“看的时候心潮澎湃,看完之后一脸茫然”,读者不知道如何将这些理论应用到实际的开发过程当中。本书就尝试着打破这种局面,把一个真实的系统搭建从头讲起,不仅包含具体的实现技术,也包含一些架构方面的设计思想。

           这是一本以Java开发语言为载体来讲解企业级信息系统开发的书,其中涉及到了HibernateStrutsSpringJSPSwingJDBC等很多技术,而且案例系统的搭建过程中也较合理的使用了面向对象理念进行系统设计,但是书中不可能详细讲解这些技术的使用,读者可以根据需要参考这些技术相关的参考资料。

           序言部分介绍了开发框架等的概念;第1234章介绍了正则表达式、AOP、自定义JSP标签等基础知识;第5章给出了案例系统的需求文档;第6章基于Spring技术搭建了案例系统的Remoting部分;第7章构建了一个基于MDA理念的元数据引擎;第8章对案例系统中用到的枚举异常类、工具类等做了介绍;第9101112章基于SpringHibernate等技术搭建了事务、DTO生成器、权限控制、日志记录、多数据库支持等基础模块;第1314章开发了登录服务、Swing客户端基础模块以及数据选择器等自定义Swing控件;第15章实现了列表界面、编辑界面和编辑界面的基类;第16章搭建了Web客户端的登录界面、主菜单等基础模块,并开发了JSP用的数据选择器等自定义标签;第17章则以前面章节搭建出的基础框架为基础实现了第5章中的需求文档所要求的功能。

       《J2EE开发全程实录》是国内J2EE研究领域里具有里程碑意义的一部作品。作者以通俗易懂的语言将J2EE企业级系统架构设计、开发过程中的看似高深的技术与原理娓娓道来,使得读者在不经意间随着作者的思路一起参透高深的技术理念。阅读完本书我才发现架构设计、设计模式、元数据编程、AOP、分布式开发这些看似高深的理论完全可以很轻松的用来改善系统架构的设计,而Spring HibernateStrutsSwingXML这些看似孤立的技术也可以有机的结合起来搭建一个高度灵活的系统架构。相信对于想深入学习基于J2EE技术的企业级系统架构设计与开发技术的读者来说,《J2EE开发全程实录》将是一本不可多得的宝典。

    预订地址:http://www.china-pub.com/computers/common/info.asp?id=35167
    posted @ 2007-07-06 19:23 CowNew开源团队 阅读(610) | 评论 (4)编辑 收藏

          刚才买了一瓶“妮唯雅”的洗面奶,还有一个“多润”洗发水。给“妮维雅”厂家打电话人家说没有这个牌子,是假冒的,给汕头工商局打电话,他们说“多润”的厂家都不存在。闻了闻都是香精的味道,妈的,刚才去退货了,也懒得闹事,退了就拉倒了。以后买东西一定要注意,以后再也不去那个小店买东西了,上次买的一个三无的沐浴露,用起来跟肥皂水似的。  
          难道沈阳假货真的这么多?还是只有这一家是??? 一天的好心情全给破坏了! 在那个店里根本容不得你自己挑选,售货员随便拿个产品就逼着你去收银台,靠,跟打劫的似的。 气煞我也,最可恶的是不让你挑选,买东西的时候都感觉害怕,我都怕如果我不买他推荐的东西他会拿刀子捅我,我Sun!
    posted @ 2007-06-16 13:25 CowNew开源团队 阅读(482) | 评论 (5)编辑 收藏

    爪哇国家里福洲有个农民汤木,听说联邦政府在东南部的佛落里洲建设特别区,需要大批劳力。吃不上饭的汤先生就打算去那里混饭吃了。
    到了佛落里洲之后,才知道这里竟然在洲政府序列里有个绑架局。绑架局是干什么的呢?
    首先,向汤木一类的来自外洲的人收取费用,颁发《免绑架证》,费用高昂,有效期一年。但是,有了《免绑架证》后,还不能免于被绑架,还必须在敲诈局办理《免绑架证承认证》、在勒索局办理《免绑架证生效证》及在无事生非局办理《免绑架证防伪卡》,简称“三证一卡”,此外,女性还必须在性别歧视局办理《女性免绑架证附加证》等许多证件,并且保证说,有了这么多证后,在大街上就不会被政府绑架,还威胁到,没有这么多证的话,或者虽然有却没有带的话,以“无证卡人”的理由予以绑架勒赎。而且,去赎人的人如果没有这么多证,也可能被绑架。至于是否有联邦政府颁发的《公民资格证》倒不重要。
    汤木吓坏了,为了在这里混下去,卖血办了这么多证,并且随身带在身上,以为就不会被绑架了。
    可是汤木想错了。
    这一天,汤木走在大街上,不幸遇到了查《免绑架证》的人员。前面已经有许多人因为没有《免绑架证》或者没有《免绑架证承认证》、《免绑架证生效证》及《免绑架证防伪卡》和《女性免绑架证附加证》等被绑架了!汤木正想着,我的证件齐了,不会被绑架了,所以没有害怕,依然向前走。
    戴着绿色帽子的绑架官粗鲁地问汤木:“北佬,有《免绑架证》吗?”
    汤木不敢跟他计较礼貌,赶紧说:“我有。”
    绑架官继续问:“三证一卡呢?”“都有。”
    “拿出来看看。”
    汤木赶快拿出来了。
    想不到绑架官拿过去看也不看,撕成碎片一扔。然后扬长而去。
    这时另一个绑架官问汤木:“你有《免绑架证》吗?”
    汤木说:“被他撕了。”
    “不要狡辩!来人,这个北佬没有《免绑架证》,马上绑了!”
    汤木浑身是嘴也说不清了。到了天边,也可以说那天汤木根本没有带《免绑架证》,所以,绑架汤木是完全正确的。
    posted @ 2007-06-16 11:16 CowNew开源团队 阅读(338) | 评论 (0)编辑 收藏

       今天我通过为JVM增加“-Dorg.apache.tapestry.disable-caching=true -Dorg.apache.tapestry.enable-reset-service=true”启动参数的方式启用了tapestry的非缓存模式以提高开发时的效率,但是在运行的时候发现以前正常工作的页面出现了错误,跟踪调试以后发现所有的页面成员变量都为null了。经过分析才发现自己以前对tapestry的一个超大误解,也避免了程序投入使用以后造成更大的问题。
    因为有一些属性是只有运行期意义的,对用户没有意义,所以我的程序中原有的java的set/get方法没有与页面中的组件绑定,因为我误认为tapestry会替我在请求之间保存这些变量值,我也曾为此怀疑tapestry是否会因此而造成内存占用过大的问题。
       tapestry的页面java文件默认是会被缓存的,当这个页面对象服务完一个请求以后会被放回池中供下一个请求使用。由于一开始的开发的时候我没有启动非缓存模式,这样当我再次对页面进行操作而造成页面刷新后,tapestry把上次为我服务的页面对象又拿给我了,这样在我看来那些页面中的变量好像是被保存了一样。当我打开非缓存模式以后,每次请求完成后,tapestry都会把变量值清空,这样就会造成上面的问题了,这样也就暴露问题了。
       因此在使用tapestry的时候一定要将需要在页面之间保存的变量放到session中或者保存在页面的hidden字段中,否则很容易出现bug。为了提早发现bug,建议在detach方法中将所有的变量赋值为null。
    posted @ 2007-06-06 23:46 CowNew开源团队 阅读(835) | 评论 (0)编辑 收藏

       在开发程序的时候热加载是非常有帮助的,这能大大简化我们开发调试的速度。在使用tapestry开发的时候,只要是启动了调试模式,那么代码的热替换是自动被JVM支持的,也就是只要我们的tapestry运行在调试模式下,就可以实现java代码的即时修改即时生效。但是tapestry的页面文件(.page和.html模板)默认是无法实现热加载的,每次修改页面都必须重启服务器,大大降低了开发速度。其实解决这个问题只要增加虚拟机参数就可以了,只要在虚拟机参数(注意不是应用参数)中加入:-Dorg.apache.tapestry.enable-reset-service=true -Dorg.apache.tapestry.disable-caching=true即可。这样每次修改的时候tapestry就不会去缓存中取了,其中org.apache.tapestry.enable-reset-service的意思是:If not specified as "true", then the reset service will be non-functional. The reset service is used to force the running Tapestry application to discard all cached data (including templates, specifications, pooled objects and more). This must be explicitly enabled, and should only be used in development (in production, it is too easily exploited as a denial of service attack).

    Unlike most other configuration values, this must be specified as a JVM system property.

    posted @ 2007-06-05 19:13 CowNew开源团队 阅读(427) | 评论 (0)编辑 收藏

     批量系统原有的页面定时刷新的实现是不太合理的,以RealtimeBatchRunningOfCountwf为例:
     首先在RealtimeBatchRunningOfCountwf.page中定义了属性refreshUrl:<property-specification name="refreshUrl" type="java.lang.String"/>,RealtimeBatchRunningOfCountwf.html中将refreshUrl插入head部分。实现的重点在RealtimeBatchRunningOfCountwf.java中,getRefreshUrl方法返回httpmeta头,在这个头信息中定义了刷新时间和要刷新到的页面的url:
     public String getRefreshUrl() {
      String t_intervalTime = getIntervalTime();
      if (t_intervalTime == null) {
       t_intervalTime = getRequestCycle().getRequestContext()
       .getParameter("intervalTime");
      }
      if (t_intervalTime == null || t_intervalTime.equals("")) {
       return "";
      }
      String url = "";
      
      try{
       url = "<meta http-equiv=\"Refresh\" content=\""
        + t_intervalTime
        + "; URL="
        + getRequestCycle().getRequestContext().getAbsoluteURL(
        "batch-server/app?service=page/RealtimeBatchCountwf")
        + "&gappid=" + getGappid() + "&gfuncid=" + getGfuncid() + "&intervalTime=" + t_intervalTime
        + "&agentzoneno=" + getAgentzoneno()
        + "\"/>";
      } catch(Exception e){
       setMessage(e.getMessage());
       return "";
      }
      return url;
     }
     可以看到getRefreshUrl的实现是非常复杂的,由于TapeStry的页面模型是比较复杂的,其中的变量都是通过页面模型来储存的,如果只是简单的刷新页面,会造成这些页面变量错误,因此在getRefreshUrl方法中将所有的变量拼接到url中,这样在页面的getGappid、getAgentzoneno等方法中首先判断页面请求(getRequestContext)中是否有此页面变量,如果有则取页面请求中的,否则再去取本对象中的变量值。这样看起来getGappid、getAgentzoneno、getRefreshUrl等方法都非常复杂,一旦页面中增加新的属性就需要去修改getRefreshUrl方法,而且这样造成视图(View)的逻辑混杂到了模型(Model)中,违反了MVC的隔离原则,最重要的是这样做违背了Tapestry页面模型设计的原意。因此我做了一个新的实现方法,可以参考BatchTaskContrlwf:
     首先仍然是在BatchTaskContrlwf.java中定义getIntervalTime方法:
     public String getIntervalTime()
     {
      if (intervalTime == null)
      {
       intervalTime = "60";
      }
      setMessage("数据每 " + intervalTime + " 秒更新一次,更新的速度可以在左上角更改");
      return intervalTime;
     }
     getIntervalTime比以前的实现简单了。BatchTaskContrlwf.java中也没有了getRefreshUrl方法,这样保持了视图与模型的独立性。
     在BatchTaskContrlwf.html中body的开头增加如下的javascript:
    <script>
     //intervalTime表示秒,但是在setTimeout中的单位是毫秒,所以在后边加三个零
     window.setTimeout("RefreshPage()",<span jwcid="@InsertText" value="ognl:intervalTime"></span>000);
     function RefreshPage()
     {  
      document.getElementById("imgRefresh").click();
     }
    </script>
     这里调用定时器实现每隔intervalTime秒就调用一次RefreshPage方法,在RefreshPage方法中则去模拟点击imgRefresh控件,这样就可以达到刷新页面的目的了。imgRefresh是为“刷新”这个图形按钮增加的id属性,因为图形按钮默认是只有name属性的,而且name属性生成的也是随机的,所以为“刷新”按钮增加id属性:
    <img jwcid="@ImageSubmit" id="imgRefresh" hspace="20" align="middle" image="ognl:assets.refreshImage" listener="ognl:listeners.refreshAction"/>
     这样就可以在RefreshPage方法中轻松的取得此控件了。
     在RefreshPage方法中也使用getElementById这个技巧,因为Tapestry生成的html中的表单的名称也是不可测的,目前的名称是“$Form0”,但是这个名称是不保障的,如果我们在RefreshPage方法中使用document.$Form0.$ImageSubmit.click()方式刷新页面的话,很有可能在Tapestr实现机制改变或者在页面中加入了新的表单元素后造成代码错误。而getElementById则可以直接根据控件id来定位控件,大大提高了代码的灵活性。
    注:上边的文章是我对公司原有产品进行重构的时候发的一篇文章,涉及到了公司的一些私有概念,非公司的人可能读部分章节起来有点费劲,请谅解。如果以后有时间我会整理成通用的文档的。
    posted @ 2007-06-05 18:40 CowNew开源团队 阅读(1268) | 评论 (0)编辑 收藏

    1、开发工作进行到比较后期时,会进入一个“视觉冻结”阶段,也就是界面固定不动,这样做的目的是让使用手册等文件能够定稿。
    2、电子邮件让我们工作时不被电话打扰,开发人员彼此之间的讨论主要通过电子邮件,只有必要时才开会。
    3、领导者的任务是努力消除程序员工作上的一切障碍,让程序员能全力专注于产品开发,而非写报告、开会。
    4、如果你要准备向上级报告项目概况,非得要所有的程序员停下手边的工作,为每个程序写一份摘要吗?这是leader的工作。有太多的Leader

    在不该授权的时候授权,让组员为了与产品无关的事情疲于奔命,导致进度停滞不前。
    5、我写文章的时候,从不使用电脑,而是使用纸笔来写作,然后再录入计算机。因为使用计算机的时候,每写完一句就忍不住要编辑以前写稿

    的东西,这样造成进度过慢,太分心于修改上,忘记了写作内容才是本旨。
    6、微软曾经有几位主管,每次遇到项目进度不顺利,就把组员叫出来骂。这种责骂只会激起组员心中的愤怒。
    7、用看程序的方式找错,是无效率的方法,用debugger来找bug才是最快最方便的,观察各变量在程序执行过程中的变化,是非常有效的方法

    ,绝对不要用猜或者用看的办法来找错。
    8、这样做对产品有没有帮助?对于目标的完成有没有策略上的价值?这样做是否会使我忽略了更重要的事情?
    9、不要把会议时间定在上午10点或者下午3点,这样会把上午或者下午的时间切割的太零碎,最好排在一清早或者快下班之前。
    10、不要让程序员的学习停滞不前,要让他们有机会磨练不同领域的技术,培养复合型人才。
    11、不要舍不得放您最优秀的程序员到别的项目去。如果他在您的项目中已经没有新的东西科学,为了公司和他个人的前途,您应该把他推荐

    到别的项目,让他的成长永不间断。
    12、加班本身就是一个危险的讯号,明确告诉你一定有什么地方出现了问题。

    posted @ 2007-06-03 12:14 CowNew开源团队 阅读(477) | 评论 (2)编辑 收藏

    此版本更新了在Eclipse3.1下无法使用的问题,目前已经能够在Eclipse3.2、Eclipse3.1下运行。
    下载地址:http://www.cownew.com/download/

    posted @ 2007-06-02 23:45 CowNew开源团队 阅读(313) | 评论 (0)编辑 收藏

    from http://blogs.huihoo.com
    1. 确保固定的发布周期,短一些。最好每月一个 milestone版,半年一个final版。人手不够?步子可以迈小一点;变化?把部分feature推迟到下一版……无论如何,版本发布的频率节奏一定要稳定,周期要短。这是很多成功的开源项目的经验,也是Agile最重要的原则之一。
    2. 建立一个子项目,专门用于集成实用的示范应用,演示JFox推荐的体系结构、设计模式用法。这些示范应用必须是实际的完整的解决方案,而不是Hello World式的Demo。用户可以在此基础上修改扩充,形成自己的系统。Pragmatic的开发框架对推广很重要。

    posted @ 2007-06-02 21:09 CowNew开源团队 阅读(345) | 评论 (0)编辑 收藏

    首先自我介绍:我是郑重,南京人,Java程序员,现在巴黎一个小IT公司任职,做J2EE编程,主要做servlet/JSP,CMS和portal。应龙辉之邀加入huihoo社区。
    言归正传。我算是关注huihoo的一员。所谓关注,首先要知道的一个问题就是,huihoo是什么。网站上说huihoo是Open Enterprise Foundation,它自己也有一些项目,比如JFox,这样看来,huihoo很象一个类似Apache或者Codehaus的一个组织。 Huihoo还拥有一个技术论坛,这样又有点象The Server Side。龙辉还有建立自己的forge的打算,如果forge真的建立起来了,huihoo又有了点sourceforge或者objectweb的模样。但其实,Apache,The Server Side和sourceforge是完全不同的三个东东,那么huihoo到底是什么?
    我个人倾向于把huihoo看成是一个Open Source Foundation。原因如下:
    先说技术论坛。我觉得国内没有必要再存在一个Java技术论坛。最权威的Java技术论坛,堪称Sun的Java Forum,The Server Side和Java World。国内也有一些有知名度的论坛,比如CSDN,比如China Java World,比如java-cn,所以我觉得技术论坛已经够多了。而且技术论坛的灵魂是人气,不是技术本身。国内那些论坛,统统好像菜场,到处充斥着关于 CLASSPATH如何设置之类的问题,这些问题虽然低级,但却正是一个技术论坛所需要的:不停的有人问问题,有人回答问题,论坛的人气就起来了,至于问题本身是什么,却不那么重要。你要去国内那些论坛问castor怎么用,问xmlbeans怎么用,肯定问津者鲜。我想,一个这样的技术论坛,应该不是 huihoo所需要的。Huihoo不是一个Java初学者俱乐部。
    然后说forge。一个forge,本质上是一个服务提供者,所以最重要的是提供的服务是否可靠,是否稳定。Huihoo不是财大气粗的地主,弄个服务器来为别人提供CVS和问题跟踪系统,这样的负荷huihoo肯定受不了。而且,即使能弄来一个这样的服务器,为什么别人不选择sourceforge而选择huihoo?再而且,我觉得项目不贵多而贵精。我三天一个想法,如果用huihoo做forge,一个月我就能注册10个项目,可这10个项目,我能坚持到底的能有一个就不错了。成千上万个半途而废的项目也比不上一个好项目。烂尾的项目太多,反而坏了名声。
    最后是开放原代码基金会。做好一个基金会,关键是有一个或者n个有技术有激情并能坚持不懈的团队,和一个或者n个优秀的项目,这也很象目前huihoo的发展模式。如果huihoo意在成为一个这样的组织,那么我觉得forum也好,forge也好,都好比阑尾,有了是个累赘,迟早要卸载掉,所以干脆不用。看看apache和codehaus,都没有自己的forum和forge。为什么没有?因为没有必要。
    在上面所说的基础上,再谈谈huihoo的项目。我看了看huihoo网站上列出的一些项目,一个普遍的问题是,似乎坚持下去的不多。很多的项目,最后更新时间都是去年,而今年都快结束了。Java技术日新月异,如果一个Java项目停滞一年没有进展,基本就可以进回收站了。所以,我觉得huihoo应该把它的成员组织好,把它的项目精简一下,然后好好进行开发。
    开始一个项目,首先要问的一个问题是,为什么需要做这样的项目。Unix下的 bash,全称是but another shell。为什么大家不用原来的shell,却要用这个bash,but这个单词,很有讲究。因为bash提供了shell所不具有的新特性,所以需要这样的but another。做任何一个项目,都一样。
    不客套了,直接拿JFox开刀。J2EE服务器,市场上已经有很多了,比如 JBoss,比如JONAS,比如Apache的Geronimo。为什么还需要JFox?这个问题,我没有和列位JFox团队的成员探讨过,JFox的主页上也没有找到,所以并不清楚。Apache的Geronimo,开始的时间不久,但主页上明确说明了为什么在大家有JBoss和JONAS可以选择的时候启动Geronimo:因为license的问题,Apache希望创建一个在Apache License 2.0之下的开源J2EE服务器。那么,JFox的理由是什么?
    做开放源代码的项目,关键是有人愿意使用。开放源代码,让程序员不能从中获得物质上的所得,那么开发的动力来自哪里?我个人认为,一部分来自于理想,一部分来自于别人的认可,两者缺一不可。一个没有人使用的项目,就得不到别人的认可,就难以为继,即使各位是多么的理想主义。而且,优秀的项目,不是闭门造车的成果,而是无数次的反馈和回应反馈的迭代。没有人使用,就没有反馈,就创造不出优秀的项目,这恐怕也是对理想的一个打击。
    我看到JoyAOP,看到Willow,都有同样的疑问:我为什么要选择huihoo 的项目,而不是Spring AOP或者aspectJ,不是ObjectWeb的Enhydra?Huihoo需要有自己的项目,每个项目都应该有自己存在的理由。没有存在理由的项目,为什么要存在?
    先说这么多。我想,每一个关注huihoo的人,或多或少都会有类似我的想法。要把huihoo建设好,需要直面这些问题。虽然我心存疑问,但我对huihoo是有希望的,因为huihoo有灵魂,那就是它的成员。措辞直接,不够委婉,还望见谅。
    from http://blogs.huihoo.com

    posted @ 2007-06-02 20:58 CowNew开源团队 阅读(482) | 评论 (1)编辑 收藏

    朋友银狐999写得一篇blog,他说出了 Huihoo 目前的一些现状,贴出来与大家分享,希望对大家能有所启发。
    Allen,huihoo的创始人之一,这几年一直用自己的热情和努力,来支撑着huihoo的发展。
    huihoo,国内著名的开源社团,创造了诸如JFox Server,JFoxAOP,JFoxSOAF,JFoxMX,JFoxMQ等不错的一些开源组件。
    这几天Allen来到了北京,趁着今天周六,晚上大家聚了聚:Allen(龙辉),Peter(程勇),Orbat(杨永),梁震宇,以及我(胡长城,银狐999)。
    Allen依然对开源充满信心,也依然在为创造一个开源神话而努力:他希望基于开源为大家提供产品和服务,利用服务来创造盈利。—— Allen很执着,也坚定着这个方向。
    我们很理解Allen的梦想,但是也不得不承认现实就是现实。
    huihoo是国内最值得推崇的开源团体,也创造了诸如JFox Server,JFoxAOP,JFoxSOAF,JFoxMX,JFoxMQ等不错的一些开源组件。然而,曾经的热血小伙子们,如今正在为“房子”,为 “自主创业”等等事情所困扰,JFox的研发越来越缓慢了。
    huihoo的网站上,google的广告越来越多了,没有办法,Allen只能依靠这有限的广告收入来维护huihoo网站的运营,甚至这两年多来,Allen利用提供咨询和培训的收入来维持huihoo的网站。
    在Allen眼中,国内开源的市场,应该能够托起huihoo这艘大船。然而这艘船越来越沉,船上的水手也越来越疲惫。这艘大船航行在一望无际的海洋 上,充满热情和激情的Allen,面对着一张可能有宝藏的图纸,却苦于没有一个指南针:风帆依然在扬起,帆布却逐渐在被撕碎······
    我们很佩服Allen的执着,但是我们也实在不忍心说一些打击Allen的话,但是我们心里都明白,Allen这个梦想,也许真的仅仅只是一个梦。这个 梦还要沉睡多久,我们谁也说不清,但是我们都希望,某一天,这个梦醒来,一切晴空万里,面对着远方,我们这些水手,可以高喊:瞧,就在那里。
    谢谢 银狐999 对 Huihoo 和我的鼓励与支持,我们会坚定不移地继续走下去。
    from http://blogs.huihoo.com

    posted @ 2007-06-02 20:55 CowNew开源团队 阅读(390) | 评论 (1)编辑 收藏

    由于工作需要,今天看了看Groovy,下面是学习过程的学习笔记:
    基本原则:Java完全可以调用Groovy写好的类;Groovy完全可以调用Java写好的类;即使不使用Groovy的特有的语法,可以使用Java中的绝大部分传统写法。
    1 如果使用 groovy.lang.*,grooby.util.*,java.lang.*,java.util.*,java.net.*中的类的时候无需import。
    2、支持assert,比如assert 1==1,assert(true)
    更高级的用法:assert('text'.3<<'hello').size==4*3+5
    3、groovy支持弱类型声明def x=1
    4、GroovyBean
    class Book
    {
       String title;//声明的是属性,而非字段
    }
    def g = new Book()
    print g.title
    print g.getTitle()
    5 groovy中的==表示等于(equality),而非同一(identity),这与java不同。
    6 def nick = 'Gina'
    def book = 'Groovy'
    assert '$nick is $book' = 'Gina is Groovy'
    7 使用正则判断字符串匹配:assert '12345'=~/\d+/
    8 groovy中可以直接对Integer类型使用四则运算,可以对int类型调用toString方法。
    9 使用list:
    def r =['a','b','c']
    assert r[0]='a'
    assert r.size()==9
    使用map:
    def http=[100:"cont",200:'ok']
    assert http[200]=='ok'
    http[800]='what?'
    使用ranges:
    def x=1..10
    assert x.contains(5)
    10 闭包:
    (1)[1,2,3].each{entry->println entry}
    (2)累加计算:其中upto表示从1遍历到10
    def  counter=0
    1.upto(10)
    {
       number->
       counter = counter+number
    }
    println counter
    11 动态执行:evaluate('1+2') 会打印出3
    12 groovy中类型可以弱类型声明,也可以强类型声明,并且声明的时候会自动进行boxing,比如def a=1是可以的,int a=1也是可以的,而且第二种用法中声明的a是Integer类型的。
    13 Groovy支持运算符重载,其实现方式和python类似,也就是类只要实现某个方法即可实现运算符重载,下面是运算符和对应方法:+ plus;- minus;* multiply;/ div;% mod;++ next;-- previous;** power;| or;& and;^ xor;~ negate;a[b] a.getAt(b);a[b] = c a.putAt(b,c);a<<b a.leftShift(b);a>>b a.rightShift(b);a>>>b a rightShiftUnsigned(b);
    switch(a){case b:} b.isCase(a);a==b a.equals(b);
    a<=>b a.compareTo(b);
    a>b a.compareTo(b)>0;
    a>=b a.compareTo(b)>=0;
    a<b a.compareTo(b)<0;
    a<=b a.compareTo(b)<=0;
    a as type a.asType(typeClass)
    14 字符串操作:
    g="Hello Grooby!"
    assert g[6..11] == 'Groovy'
    assert g.count('0')==3
    assert 'x'.padLeft(3)=='  x'
    assert 'x'.padRight(3,'_')=='x__'
    assert 'x'.center(3)==' x '
    assert 'x'*3=='xxx'
    15 字符串的LeftShift和切片的应用
    g='Hello'
    g<<' Groovy'
    assert g instanceof java.lang.StringBuffer
    g<<'!'
    assert g.toString()=='Hello Groovy!'
    g[1..4] = 'i'//替换ello为i,切片的典型应用
    assert g.toString()=='Hi Grooby!'
    list等collection类型同样支持切片
    16 数字的方法:
    def s = ''
    10.times{s+='x'}
    10.downto(0){x+='d'}
    s=''
    0.step(0.5,0.1){number->
    s+=number+' '
    }
    assert s=='0 0.1 0.2 0.3 0.4'
    17 List的常见操作
    assert [1,[2,3]].flattern()==[1,2,3]//扁平化
    assert [1,2,3].intersect([4,3,1])==[3,1]//交集
    assert [1,2,3].disjoint([4.5,6])
    list = [1,2,3]
    assert list.pop()==3//像使用堆栈一样
    assert [3,1,2].sort()==[1,2,3]
    assert [1]==[1,1,1].unique()//去掉重复元素

    def list=[1,2,3]
    assert list.count(2)==1
    assert list.max()==3
    assert list.min()==1
    def even = list.find{item->
     item%2==0
    }
    assert even ==2
    assert list.every{item->
     item<5
    }//所有的都小于5
    assert list.any{item->
     item<2
    }//任何一个小于5
    list.reverseEach{item->
     store+=item
    }//反向遍历

    assert [1,2,3].join('-')=='1-2-3'
    for(i in [1,2,3])
    {
       println i
    }
    18 文件处理:
    new File('a.txt').eachLine{println it}
    19 groovy中xml处理非常简单,可以参考blogjava上的一篇名为“Groovy高效编程——生成XML文件”的文章。
    20 Groovy中使用Swing构建界面:
    import grooby.swing.SwingBuilder

    swing = new SwingBuilder()
    frame = swing.frame(titile:'Demo'){
      menuBar{
        menu('File'){
            menuItem 'New'
            menuItem 'Open'
        }
      }
      panle{
        label 'Label my'
        slider()
        comboBox(items:['1','2','3'])
      }
    }
    frame.pack()
    frame.show()
    21 groovy中简化了jdbc访问数据库的方法,提供了execute、eachRow等方法,无需开发人员关心关闭连接等问题。
    22 java中运行grooby脚本的方法:
    GroovyShell shell = new GroovyShell()
    Object result = shell.evaluate("12+23")
    23 Groovy解析引擎的类为GroovyScriptEngine
    def engine = new GroovyScriptEngine(".")
    def value = engine.run("test/MyScript.grooby",new Binding())

     

    posted @ 2007-05-31 20:17 CowNew开源团队 阅读(2896) | 评论 (0)编辑 收藏

         摘要: 下面的例子中第一个进度条是一个“确定模式”的滚动条,进度中显示了当前的工作完成百分比,第二个进度条可以通过按钮切换“不确定模式”与“确定模式”: package com.cownew.Char19; import java.awt.Rectangle; import javax.swing.JButton; impor...  阅读全文
    posted @ 2007-05-30 20:18 CowNew开源团队 阅读(2839) | 评论 (3)编辑 收藏

        王开源的事情已经过去一段时间了,看过太多对这件事情的评论,这些评论或者是口出污言秽语的谩骂或者是狂热的非理性的力挺(在这件事的初期属于后者)。很多人对开源的评论也使得我这个投身于开源一年多的新人感到过迷茫。这件事过去好久,我一直在思索一个问题:开源在目前中国的意义究竟是什么,开源在中国这种大环境下究竟应该如何发展。
        开源在国外现在是火的一塌糊涂,Linux、Eclipse、Hibernate、Spring、Python、Ruby、MySQL等等或大或小的开源产品的发展大大推动了软件开发这个行业的高速发展,apache、sourceforge等开源社区中也是百花齐放,开源产品的开发者、推动者、推广者也得到了各自想得到的回报,更不用说使用这些开源产品进行开发的用户得到的开发效率的提升。反观国内开源的发展则相对滞后很多:违背Linux开源协议进行商业化Linux开发的厂家被开源社区骂的狗血喷头;屈指可数的几个开源爱好者组织的开源团队在个人的意志与信念的坚守下苦苦支撑着,很多因为种种原因中途夭折;商业公司对开源社区的几次推广行动也胎死腹中,比如CSDN的开源社区、Apusic的Operamasks;更有甚者打着开源的旗号却从事着根本与开源不搭边的事情。国内大部分人对开源更是有着很深的误解:“你凭什么叫人家开源,不就是想看看Windows的代码吗?”、“人家商业公司做出来的产品是你们几个技术疯子做出来的东西能比的吗?”、“把别人写好的东西拿来抄一抄改一改我的任务就完成了,钱就到手了,开源真好”、“我做的项目用了很多开源的东西,很牛吧!”。
        我认为开源对于整个软件行业有如下几个作用:使用开源产品搭建出的产品有更好的安全性和可控性;开源的产品能得到开发社区的广泛支持,从而使得产品能够成熟的更快;使用开源产品搭建出的产品有更好的安全性和可控性;开发、学习开源产品能够提升开发人员的技术水平。
        对于第一个作用这里不做过多解释,相信大部分人都能理解。
        开源产品是在全世界所有技术牛人的手下开发出来的,并且有千万双眼睛盯着它,众多的使用者可以完善它,这使得开源产品的成熟速度也十分惊人,Linux、Eclipse的成熟就是最典型的证明。各种开源产品层出不穷,相似功能的产品就有几十种甚至上百种,一个开源产品如果想要在这些产品中脱颖而出,不仅需要强大的技术做支撑,更需要非常强的商业化推广,否则做出来的产品只能成为少数技术人员把玩的玩物。如果没有IBM对Eclipse的巨额投入,Eclipse会发展成现在的规模吗?这些开源项目的后面通常都是有一个非常强大的开源基金会在做支撑。遗憾的是,目前国内还没有一家公司能够进行对开源社区如此大的投入,因此国内大部分的开源团队都是在自己开发着自己的开源产品,放到网站上供他人下载,然后梦想着自己的开源产品能够有一天会像Hibernate、Struts一样成为风靡全球的产品,但是如果没有强大的商业推广的话这肯定是一场白日梦。
        鉴于此,我认为目前国内的开源产品商业化的可能性是非常小的,因此开源的对于广大开发人员的意义更多的在于使用和学习,而且我们使用开源产品快速的搭建出满足需求的产品,这本身也是对开源的学习过程。这里提到的“学习”包含下面几个含义:学习开源产品的使用;学习开源产品的实现原理;学习模仿开源产品;学习开源社区的运营。
        (1)学习开源产品的使用:成熟的开源产品是非常优秀的,如果能够学会它们的使用,这对于开源人员来说就是一种很大的收获,因为通过使用这些产品就能认识到这些产品的功能、特性以及优缺点。
        (2)学习开源产品的实现原理:开源产品的代码都是开放的,我们可以深入产品的内部学习其实现原理,从而提高自身的开发水平。不得不承认的是国内开发人员的技术水平还是非常低的,通过学习开源产品的代码,就可以提高整体的技术水平,从这个层面来讲哪怕是非开源的源代码开放产品(比如Borland的VCL)对我们也是同样有帮助的。值得高兴的是,国内很多开发人员已经开始尝试着深入开源产品的内部去探寻这些产品的实现原理,并把它们的学习成果与更多人分享。开源对开发人员的提升也是显而易见的,最明显的就是微软开发社区中开发人员的普遍技术水平是低于Java等开源社区中开发人员的普遍技术水平的(注意,这里说的是“普遍技术水平”,请微软社区中的高人不要动怒)。中国计算机业的发展必须依靠核心技术,而提高技术水平是拥有核心技术的大前提!
        (3)学习模仿开源产品:弄懂了开源产品的实现原理以后就可以尝试模仿它们开发自己的产品,这和“重复造轮子”是没有关系的,模仿是学习他人技术的最佳途径。因此大家应该多多的“造轮子”,越多越好,哪怕造完就扔掉也是可以的。
        (4)学习开源社区的运营:国外很多开源人员都有在开源社区中开发的经验,因此他们对于开源这种协同开发方式就有更多的经验,因此我们可以加入他们的开发团队,可以帮他们做文档、界面的本地化,更可以参与产品功能的完善,从而学习他们的协作方式,更可以和他们做朋友,了解更多“外面的世界”。国内很多朋友都参与了开源产品的文档中文化、产品的推广等工作,这都是有深远意义的。我们CowNew开源团队参与JodeEclipse、DWPL等国外项目就是基于这一点考虑的。
         相信经过一段时间学习之后,我们的开发人员将有能力开发出世界级的产品,如果我们的民族企业能够得到长远的发展,并且在商业上帮助国产开源真正走向强大,从而使得中国的开源社区也能跻身“世界开源之林”!
        上边是我一点愚蠢的看法,仅供各位看管参考。希望开源能够在中国发展、壮大,希望中国早日成为软件强国!
       
    posted @ 2007-05-20 18:08 CowNew开源团队 阅读(2108) | 评论 (11)编辑 收藏

    今天要使用mysql做一个功能的实验,但是发现写进去的中文变成了乱码,可是数据库的编码都改成gbk了,而且jdbc连接字符串和my.ini的default-character-set配置项也改成了gbk,但是连接的时候还是乱码,通过mysql的原生客户端连接则不会出现这种情况。最终的解决方法是将所有的字符集都改成utf-8。
    用gbk、gb2312 之类的时候都可能会出现问题,而utf-8作为一个标准的多语言字符集则解决乱码的终极方案。所以推荐大家在其他遇到中文的情况下也使用utf-8。
    posted @ 2007-05-19 11:59 CowNew开源团队 阅读(599) | 评论 (0)编辑 收藏

    Eclipse的插件机制是个非常好的东西,架构也非常灵活。我们开发的插件有时候需要提供一些扩展机制,允许他人扩展,但是如果是提供的标准的Eclipse扩展点的话无疑加大了开发扩展功能的难度,开发人员必须熟悉Eclipse插件开发才可以。在最近做的几个IDE中,为了避免这个问题,我都采用了最原始的插件扩展方式,也就是扩展功能的开发人员把扩展插件的jar包或者.class文件放到某个目录下即可,这些扩展功能也只需实现某个接口即可,由我的插件来进行加载。这样在扩展功能开发人员看来,写扩展功能就是写一个实现了某个接口的Java类,无需了解Eclipse插件开发的知识了,当然这带来的缺点就是灵活性降低了。
    posted @ 2007-05-19 00:32 CowNew开源团队 阅读(526) | 评论 (0)编辑 收藏

       做系统设计的时候有时会碰到一些无法在父类(或者接口)中抽取通用行为的特性,遇到这种情况就可以采用StringConfigure模式,这个模式我取的名字,不知道是否已经有先人做了总结,如果哪位朋友知道这种模式的正确名称,希望不吝赐教。
       以JDBC中取得数据库连接为例,我们可以抽象出数据库的一些公共行为,比如连接数据库都要求提供用户名和密码,因此在JDBC中提供设定连接的用户名和密码的方法。但是另外的一些行为则不一定是所有数据库都具备的,比如对于网络型数据库才需要指定网络地址,而文件型数据库则不需要,再比如在MySQL中需要指定字符集,而其他数据库则不一定需要。如果为了照顾这些特性,为JDBC提供setHostIP、setDBFilePath、setCharSet等方法的话无疑会使得接口变得复杂,会出现很多用不到的方法,并且这些方法也无法覆盖所有未来可能出现的情况,比如某个数据库又增加了允许用户定制连接超时的方法,那么JDBC也要为他提供相应的setTimeOut方法。为了解决这个问题,JDBC提出了连接字符串的概念,这样各个数据库的JDBC驱动只要规定好连接字符串的格式即可,用户把所有的配置信息写到连接字符串中,如果用户修改为其他数据库的话只需修改连接字符串即可,不用修改其他的调用。
       使用StringConfigure模式的好处是使得系统中的个性化配置在一个参数中完成,这样保证系统的不同模块的行为的一致性,缺点是配置字符串的格式要由各个实现模块来规定,各个不同实现模块的格式不一致,造成了一定的学习成本,而且无法在开发期发现配置字符串的问题。
       这里再来讲一个StringConfigure模式的应用的例子。现在我们要开发一套对IC卡读写器的类库,应用开发人员只要调用不同的IC卡读写子类即可实现操作不同的IC卡读写器。各种不同的IC卡读写器有两个共同的抽象行为:读卡和写卡,即readCard和writeCard,但是各个不同的读卡器还有自己的特性,比如有的读卡器需要指定采用ISO格式还是IBM格式来读写磁卡,有的读卡器需要指定读写操作的分隔符,这些特性不是各个读写器共有的,因此我们采用StringConfigure模式进行设计,开发如下的接口:
    interface IICCarder
    {
      public void writeCard(String data);
      public String readCard();
      public void configure(String configStr);
    }

       比如需要指定读写格式的读写器就可以如下实现:
    class SomeCarder implements IICarder
    {
        private FormatEnum format;
        public void writeCard(String data)
        {
           if(format==FormatEnum.IBM)
           {
                 .........
           }
           else...........
        }
        public String readCard()
        {.............
        }
        public void configure(String configStr)
        {
            if(configStr.equls("IBM"))
            {
               format=FormatEnum.IBM
            }
            else if(configStr.equls("ISO"))
            {
               format=FormatEnum.ISO
            }
        }
    }

    开发人员使用的时候只要如下调用
    IICarder c = new SomeCarder();
    c.configure("IBM");
    print c.readCard();
    如果采用配置文件的话更可以把配置参数写到配置文件中,这样就可以避免修改代码。

    posted @ 2007-05-19 00:22 CowNew开源团队 阅读(1134) | 评论 (2)编辑 收藏

    CowNew 成为JodeEclipse的管理员,今后JodeEclipse以后将会由CowNew来进行维护,对于JodeEclipse有哪些需求,可以在这里提出。预计近期为jode eclipse增加调试和批量反编译的功能。有兴趣的朋友也可以加入开发队伍。

    JodeEclipse的网站:http://sourceforge.net/projects/jodeeclipse
    posted @ 2007-05-17 19:16 CowNew开源团队 阅读(375) | 评论 (2)编辑 收藏

    最近在和technoetic的Steve Bate接触,已经达成初步的合作意向,technoetic将会接收jode eclipse的管理权,以后将会由CowNew来进行jode eclipse的bug修复和新功能添加,预计近期为jode eclipse增加调试和批量反编译的功能。此外计划为cownewstudio增加生成DDL的功能。有兴趣的队友可以来领任务。
    posted @ 2007-05-14 22:26 CowNew开源团队 阅读(318) | 评论 (1)编辑 收藏

    Jodeclipse 是Jode的Eclipse插件,是一个非常好的反编译插件,不过Jodeclipse 在eclipse3.2上有bug,每次反编译的时候都会报一个错误,虽然不影响反编译结果,但是非常影响使用。因此我从Jodeclipse 的CVS上CheckOut出了代码,做了修复,编译以后的二进制包从此处下载:
    http://www.blogjava.net/Files/huanzhugege/net.sourceforge.jode_1.0.5.rar

    安装方法:
    直接解压到eclipse的plugins目录下。

    已经将修改后的代码提交给jodeclipse的管理员。
    开源万岁!!!
    posted @ 2007-05-13 17:05 CowNew开源团队 阅读(8692) | 评论 (16)编辑 收藏

     

    下面的代码就演示了为JTextArea、JList增加滚动条的代码:

    package com.cownew.Char19;

    import javax.swing.SwingUtilities;

    import java.awt.BorderLayout;

    import javax.swing.DefaultListModel;

    import javax.swing.JPanel;

    import javax.swing.JFrame;

    import javax.swing.JTextArea;

    import javax.swing.ListModel;

    import java.awt.Rectangle;

    import javax.swing.JList;

    import javax.swing.JScrollPane;

    public class ScrollPaneTest1 extends JFrame

    {

    private JPanel jContentPane = null;

    private JTextArea jTextArea = null;

    private JList jList = null;

    private JScrollPane jScrollPane = null;

    private JScrollPane jScrollPane1 = null;

    private JList jList1 = null;

    private JTextArea jTextArea1 = null;

    private JTextArea getJTextArea()

    {

    if (jTextArea == null)

    {

    jTextArea = new JTextArea();

    jTextArea.setBounds(new Rectangle(12, 7, 95, 71));

    }

    return jTextArea;

    }

    private JList getJList()

    {

    if (jList == null)

    {

    jList = new JList();

    jList.setBounds(new Rectangle(8, 92, 106, 71));

    DefaultListModel listModel = new DefaultListModel();

    listModel.addElement("22222");

    listModel.addElement("33333333");

    listModel.addElement("55555555555555");

    listModel.addElement("8888888888");

    listModel.addElement("88888888");

    listModel.addElement("999999999");

    jList.setModel(listModel);

    }

    return jList;

    }

    private JScrollPane getJScrollPane()

    {

    if (jScrollPane == null)

    {

    jScrollPane = new JScrollPane();

    jScrollPane.setBounds(new Rectangle(143, 7, 122, 75));

    jScrollPane.setViewportView(getJTextArea1());

    }

    return jScrollPane;

    }

    private JScrollPane getJScrollPane1()

    {

    if (jScrollPane1 == null)

    {

    jScrollPane1 = new JScrollPane();

    jScrollPane1.setBounds(new Rectangle(142, 96, 128, 68));

    jScrollPane1.setViewportView(getJList1());

    }

    return jScrollPane1;

    }

    private JList getJList1()

    {

    if (jList1 == null)

    {

    jList1 = new JList();

    DefaultListModel listModel = new DefaultListModel();

    listModel.addElement("22222");

    listModel.addElement("33333333");

    listModel.addElement("8888888888888888888888888888");

    listModel.addElement("8888888888");

    listModel.addElement("88888888");

    listModel.addElement("999999999");

    jList1.setModel(listModel);

    }

    return jList1;

    }

    private JTextArea getJTextArea1()

    {

    if (jTextArea1 == null)

    {

    jTextArea1 = new JTextArea();

    }

    return jTextArea1;

    }

    public static void main(String[] args)

    {

    SwingUtilities.invokeLater(new Runnable() {

    public void run()

    {

    ScrollPaneTest1 thisClass = new ScrollPaneTest1();

    thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    thisClass.setVisible(true);

    }

    });

    }

    public ScrollPaneTest1()

    {

    super();

    initialize();

    }

    private void initialize()

    {

    this.setSize(300, 200);

    this.setContentPane(getJContentPane());

    this.setTitle("JFrame");

    }

    private JPanel getJContentPane()

    {

    if (jContentPane == null)

    {

    jContentPane = new JPanel();

    jContentPane.setLayout(null);

    jContentPane.add(getJTextArea(), null);

    jContentPane.add(getJList(), null);

    jContentPane.add(getJScrollPane(), null);

    jContentPane.add(getJScrollPane1(), null);

    }

    return jContentPane;

    }

    }

    运行效果图:

    图 17.9

    JScrollPane还能为组合界面增加滚动条:

    package com.cownew.Char19;

    import java.awt.Dimension;

    import java.awt.Rectangle;

    import javax.swing.JButton;

    import javax.swing.JCheckBox;

    import javax.swing.JFrame;

    import javax.swing.JPanel;

    import javax.swing.JScrollPane;

    import javax.swing.JSlider;

    import javax.swing.JTextField;

    import javax.swing.SwingUtilities;

    public class ScrollPaneTest2 extends JFrame

    {

    private JPanel jContentPane = null;

    private JScrollPane jScrollPane = null;

    private JPanel jPanel = null;

    private JButton jButton = null;

    private JButton jButton1 = null;

    private JCheckBox jCheckBox = null;

    private JTextField jTextField = null;

    private JSlider jSlider = null;

    private JScrollPane getJScrollPane()

    {

    if (jScrollPane == null)

    {

    jScrollPane = new JScrollPane();

    jScrollPane.setBounds(new Rectangle(28, 17, 142, 114));

    jScrollPane.setViewportView(getJPanel());

    }

    return jScrollPane;

    }

    private JPanel getJPanel()

    {

    if (jPanel == null)

    {

    jPanel = new JPanel();

    jPanel.setLayout(null);

    jPanel.add(getJButton(), null);

    jPanel.add(getJButton1(), null);

    jPanel.add(getJCheckBox(), null);

    jPanel.add(getJTextField(), null);

    jPanel.add(getJSlider(), null);

    jPanel.setPreferredSize(new Dimension(300,200));

    }

    return jPanel;

    }

    private JButton getJButton()

    {

    if (jButton == null)

    {

    jButton = new JButton();

    jButton.setBounds(new Rectangle(6, 10, 74, 28));

    }

    return jButton;

    }

    private JButton getJButton1()

    {

    if (jButton1 == null)

    {

    jButton1 = new JButton();

    jButton1.setBounds(new Rectangle(102, 9, 82, 30));

    }

    return jButton1;

    }

    private JCheckBox getJCheckBox()

    {

    if (jCheckBox == null)

    {

    jCheckBox = new JCheckBox();

    jCheckBox.setBounds(new Rectangle(17, 56, 93, 21));

    jCheckBox.setText("aaaaabbb");

    }

    return jCheckBox;

    }

    private JTextField getJTextField()

    {

    if (jTextField == null)

    {

    jTextField = new JTextField();

    jTextField.setBounds(new Rectangle(126, 57, 99, 22));

    }

    return jTextField;

    }

    private JSlider getJSlider()

    {

    if (jSlider == null)

    {

    jSlider = new JSlider();

    jSlider.setBounds(new Rectangle(20, 111, 205, 25));

    }

    return jSlider;

    }

    public static void main(String[] args)

    {

    SwingUtilities.invokeLater(new Runnable() {

    public void run()

    {

    ScrollPaneTest2 thisClass = new ScrollPaneTest2();

    thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    thisClass.setVisible(true);

    }

    });

    }

    public ScrollPaneTest2()

    {

    super();

    initialize();

    }

    private void initialize()

    {

    this.setSize(221, 177);

    this.setContentPane(getJContentPane());

    this.setTitle("JFrame");

    }

    private JPanel getJContentPane()

    {

    if (jContentPane == null)

    {

    jContentPane = new JPanel();

    jContentPane.setLayout(null);

    jContentPane.add(getJScrollPane(), null);

    }

    return jContentPane;

    }

    }

    运行效果图:

    图 17.10

    对于这种组合界面必须为界面设定一个最佳尺寸(PreferredSize),这样JScrollPane才知道如何显示滚动条:jPanel.setPreferredSize(new Dimension(300,200))。

    JScrollPane中的ViewPort是一种特殊的对象,通过它就可以查看基层组件,滚动条其实就是沿着组件移动“视点”,这样就可以查看隐藏的部分。

    posted @ 2007-04-29 12:32 CowNew开源团队 阅读(5914) | 评论 (0)编辑 收藏

     

    首先演示一个NumberFormatter的例子,在这个例子中要求用户输入一个数字,单击按钮后将用户输入的数字乘2以后重新赋值给输入框。用户输入的数字必须大于0,小于100。

    package com.cownew.Char19;

    import java.awt.Font;

    import java.awt.Rectangle;

    import java.math.BigDecimal;

    import javax.swing.JButton;

    import javax.swing.JDialog;

    import javax.swing.JFormattedTextField;

    import javax.swing.JOptionPane;

    import javax.swing.JPanel;

    import javax.swing.text.NumberFormatter;

    import javax.swing.JTextField;

    public class NumberFormaterDialog1 extends JDialog

    {

    private JPanel jContentPane = null;

    private JFormattedTextField numTxtField = null;

    private JButton jButton = null;

    private JTextField jTextField = null;

    private JFormattedTextField getNumTxtField()

    {

    if (numTxtField == null)

    {

    NumberFormatter numFormater = new NumberFormatter();

    numFormater.setMaximum(new BigDecimal(100));

    numFormater.setMinimum(new BigDecimal(0));

    numTxtField = new JFormattedTextField(numFormater);

    numTxtField.setBounds(new Rectangle(56, 38, 154, 24));

    }

    return numTxtField;

    }

    private JButton getJButton()

    {

    if (jButton == null)

    {

    jButton = new JButton();

    jButton.setBounds(new Rectangle(78, 80, 81, 36));

    jButton.setFont(new Font("Dialog", Font.PLAIN, 18));

    jButton.setText("计算");

    jButton.addActionListener(new java.awt.event.ActionListener() {

    public void actionPerformed(java.awt.event.ActionEvent e)

    {

    BigDecimal oldValue = (BigDecimal) getNumTxtField()

    .getValue();

    if (oldValue != null)

    {

    getNumTxtField().setValue(

    oldValue.multiply(new BigDecimal(2)));

    }

    else

    {

    JOptionPane.showMessageDialog(

    NumberFormaterDialog1.this,"值非法");

    }

    }

    });

    }

    return jButton;

    }

    private JTextField getJTextField()

    {

    if (jTextField == null)

    {

    jTextField = new JTextField();

    jTextField.setBounds(new Rectangle(176, 83, 76, 22));

    }

    return jTextField;

    }

    public static void main(String[] args)

    {

    NumberFormaterDialog1 dlg = new NumberFormaterDialog1();

    dlg.show();

    }

    public NumberFormaterDialog1()

    {

    super();

    initialize();

    }

    private void initialize()

    {

    this.setSize(300, 200);

    this.setContentPane(getJContentPane());

    this.setTitle("JFrame");

    }

    private JPanel getJContentPane()

    {

    if (jContentPane == null)

    {

    jContentPane = new JPanel();

    jContentPane.setLayout(null);

    jContentPane.add(getNumTxtField(), null);

    jContentPane.add(getJButton(), null);

    jContentPane.add(getJTextField(), null);

    }

    return jContentPane;

    }

    }

    当我们输入-3这个无效值的时候是允许输入的,但是当鼠标焦点移动到另外的控件的时候,“-3”就会消失。这个行为可以通过NumberFormatter 的setAllowsInvalid方法来改变:

    图 17.5

    图 17.6

    如果输入“10”这个合法的数字,单击“计算”按钮即可算出正确的值:

    图 17.7

    图 17.8

    案例系统中的com.cownew.ctk.ui.swing.JNumberTextField就是为了方便使用而从JFormattedTextField派生的一个数字输入控件。

    DateFormatter的使用也是类似的,也允许设置最大最小值,实际上只要从InternationalFormatter派生的类,并且数据类型实现了Comparable接口都可以设置极值。

    MaskFormatter允许开发人员使用掩码指定更加复杂的校验规则。掩码是一串特殊的字符串,每个字符的含义如下表所示:

    字符

    说明

    #

    匹配任何数字字符

    '

    转义符,用来将格式字符当成普通字符用

    U

    任意大写字母

    L

    任意小写字母

    A

    任意数字或者字母

    ?

    任何字母

    *

    任何字符

    H

    任何十六进制字符 (0-9, a-f or A-F).

    实例化时指定其掩码即可:

    MaskFormatter formatter = new MaskFormatter("0x***");

    formatter.setValidCharacters("0123456789abcdefABCDEF");

    还允许为掩码设定占位符,这样可用性更好:

    MaskFormatter formatter = new MaskFormatter("###-####");

    formatter.setPlaceholderCharacter('_');

    formatter.getDisplayValue(tf, "123");

    posted @ 2007-04-26 09:29 CowNew开源团队 阅读(1600) | 评论 (0)编辑 收藏

    盖茨北大演讲被闹场2007年4月20日

    from腾讯网。
    4月20日,比尔盖茨在北大演讲,在他为一行人颁奖时,一位男子手拿海报并大声用英语叫喊反对微软垄断。

    男子海报上写着“Free software”“Open resource”,抗议微软垄断,呼吁开源,事后该男子被警方带走进行调查。

    据熟知内情的人士透露,此男子系CSDN的前市场总监,是个衷情于开源软件的业内人士。据传,此人甚至将名字改为带有“开源”的字样。

    组图:盖茨北大演讲遭遇反垄断抗议
    高举手书海报

    组图:盖茨北大演讲遭遇反垄断抗议
    现场被控制

    组图:盖茨北大演讲遭遇反垄断抗议 

    来自CSDN的信息显示,该名男子是LPI中国首席代表王洋,自号王开源,是开源软件的积极分子。

    2005年王开源先生任即时科研集团总裁助理;2006年加入CSDN,参与创建OSDN开源社区,并与北京点击查看北京及更多城市天气预报大学、中国开源软件联盟合作,首次把“国际软件自由日”引进中国。离开CSDN后加入LPI(Linux Professional Institute)。




    CowNew开源团队声援王开源大哥!!!
    希望政府不要再被盖茨这个大资本家迷惑!!!
    国家采购首选开源!!!
    发展国内开源事业,做民族的脊梁!!!
    from:http://blog.csdn.net/arthur5933/archive/2007/04/20/1571507.aspx

           《愿歌》



    未名湖畔嚣声涩 ,
    帝国列强作秀狼;
    博雅先贤清风泪,
    男儿七尺当自强!


           开源
    2007年4月20日晨


    posted @ 2007-04-20 15:16 CowNew开源团队 阅读(1807) | 评论 (20)编辑 收藏

    以前写书的时候写的一个案例,如果应用于实际的项目还需要改进,应一个网友的要求贴上来,仅供参考
    <?xml version="1.0" encoding="GB2312" ?>
    <project name="dailybuild" default="main">
    <!--tomcat的路径-->
    <property name="tomcathome.dir"
        value="C:\Program Files\Apache Software Foundation\Tomcat 5.0\"/>
    <!--tomcat管理控制台路径-->
    <property name="tomcathome.mgr.dir" value="http://127.0.0.1:8080/manager/"/>   
    <!--tomcat管理控制台用户名-->
    <property name="tomcat.username" value="admin"/>   
    <!--tomcat管理控制台密码-->
    <property name="tomcat.password"  value=""/>
    <!--tomcat中-->
    <property name="cownewwebpath" value="/CownewPISWeb"/>
    <!--Web应用的路径-->   
    <property name="cownewwebhome.dir"
        value="${tomcathome.dir}webapps\CownewPISWeb\"/> 
    <!--Web应用的源码路径(主要供稍后的编译用)-->     
    <property name="cownewwebhome.java.dir"
        value="${cownewwebhome.dir}WEB-INF\java\"/>
    <!--Web应用输出的class路径-->       
    <property name="cownewwebhome.classes.dir"
        value="${cownewwebhome.dir}WEB-INF\classes\"/> 
    <!--CVS根路径-->    
    <property name="cvsRoot" value=":pserver:杨中科:123456@192.168.1.6:/cvsrep"/>    
    <!--代码检出的路径-->
    <property name="cvs.outtemp.dir" value="${cownewwebhome.dir}cvsout/"/>
    <!--BVT测试(冒烟测试)的测试结果输出的路径-->
    <property name="bvt.output.dir" value="c:/bvtreport/"/>

    <taskdef name="stopTomcat" classname="org.apache.catalina.ant.StopTask">       
      <classpath>           
        <path location="${tomcathome.dir}/server/lib/catalina-ant.jar"/>       
      </classpath>   
    </taskdef>
    <taskdef name="startTomcat" classname="org.apache.catalina.ant.StartTask">       
      <classpath>           
        <path location="${tomcathome.dir}/server/lib/catalina-ant.jar"/>       
      </classpath>   
    </taskdef>
    <taskdef
    name="sendBuildEmail" classname="com.cownew.dailybuild.taskdefs.DailyBuildMailTask">       
      <classpath>           
        <path location="../lib/ant-dailybuild.jar"/>       
      </classpath>   
    </taskdef>
    <target name="main">
    <echo>停止Tomcat</echo>
    <stopTomcat url="${tomcathome.mgr.dir}" username="${tomcat.username}"
        password="${tomcat.password}" path="${cownewwebpath}"/>
    <echo>清除原有构建文件</echo>
    <delete dir="${cownewwebhome.dir}"/>
    <echo>开始从CVS下拉代码</echo>
    <mkdir dir="${cvs.outtemp.dir}"/>
    <cvs cvsRoot="${cvsRoot}" package="CownewPISWeb" dest="${cvs.outtemp.dir}"/>
    <mkdir dir="${cownewwebhome.dir}"/>
    <copy todir="${cownewwebhome.dir}">
      <fileset dir="${cvs.outtemp.dir}CownewPISWeb/WebContent/"/>
    </copy>

    <mkdir dir="${cownewwebhome.java.dir}"/>
    <copy todir="${cownewwebhome.java.dir}">
      <fileset dir="${cvs.outtemp.dir}CownewPISWeb/src/"/>
    </copy>
    <delete dir="${cvs.outtemp.dir}"/>
    <echo>开始编译源代码</echo>
    <mkdir dir="${cownewwebhome.classes.dir}"/>
    <javac srcdir="${cownewwebhome.java.dir}" destdir="${cownewwebhome.classes.dir}" >
       <classpath>
          <pathelement location="E:\保留文档\java\常用包\junit-3.8.1.jar" />
          <pathelement location="E:\保留文档\java\常用包\struts.jar" />
          <pathelement location="E:\保留文档\java\常用包\log4j.jar" />
          <pathelement location="E:\保留文档\java\常用包\dom4j.jar" />
       </classpath>
    </javac>
    <delete dir="${cownewwebhome.java.dir}"/>
    <echo>启动Tomcat</echo>
    <startTomcat url="${tomcathome.mgr.dir}" username="${tomcat.username}"
        password="${tomcat.password}" path="${cownewwebpath}"/>
    <echo>开始冒烟测试</echo>
    <delete>
      <fileset dir="${bvt.output.dir}"
               includes="*.*"
               defaultexcludes="false"/>
    </delete>
    <junit>
        <classpath>
           <pathelement location="E:\保留文档\java\常用包\junit-3.8.1.jar"/> 
           <pathelement location="${cownewwebhome.classes.dir}"/>         
        </classpath>
        <formatter type="brief" usefile="true"/>
        <batchtest todir="${bvt.output.dir}">
          <fileset dir="${cownewwebhome.classes.dir}">
              <include name="**/bvt/*.class" />
           </fileset>
        </batchtest>   
    </junit>

    <echo>开始发送构建结果邮件</echo>

    <sendBuildEmail smtpHost="smtp.mycompany.com" smtpUserId="scmheader" smtpPassword="123456"
      senderEmail="scmheader@mycompany.com" title="日构建已经完成"
      jdbcClass="net.sourceforge.jtds.jdbc.Driver"
      dbUrl="jdbc:jtds:sqlserver://127.0.0.1/dailybuild;user=sa">
      日构建已经完成,请到此处查看构建日志:\\192.168.1.15\dailybuild\result.log
      点击此处查看冒烟测试结果: \\192.168.1.15\bvtreport\
    </sendBuildEmail>
    </target>
    </project>

    posted @ 2007-04-20 09:10 CowNew开源团队 阅读(1186) | 评论 (1)编辑 收藏

     

    与VCL、AWT等框架中的图形界面框架不同,Swing创造性的采用了MVC(Model View Controller) 模式。MVC 把控件(Component)划分成三个部分:模型( Model):管理这个模块中所用到的数据和值,如某个数据的最大值、最小值、当前值等数据;视图( View):管理如何将模型显示给用户;控制器(Controller) 决定如何处理用户和该模块交互时产生的事件,如用户单击一个按钮等。Sun 出于对视图和控制器之间的依赖关系的考虑, 在 Swing 设计中将 MVC体系简化为分离模型体系 ( Separable Model Architecture) , 将其中的控制器和视图结合成 UI 代理。

    界面中的每个控件都包含三种特征:

    它的状态:比如一个按钮的状态

    它的外观:颜色、尺寸等

    它的行为:对事件作出的反应

    以一个按钮为例,它有可用、不可用状态,在不同的LookAndFeel中有不同的外观显示,在鼠标按下、鼠标右击等事件中有自己独特的响应方式。如果管理按钮状态、绘制按钮外观,响应时间等任务都由按钮负责的话就违背了面向对象设计中的“单一责任原则”。Swing开发人员采用MVC模式解决了此问题,将控件的LookAndFeel同一个对象关联到一起,同时将其内容保存到另一个对象中。控制器负责控制用户输入事件。比如鼠标单击、按键操作等,它会决定将这些事件转换成模型中的改变.还是视图中的改变。例如,假定用户在文本框中按下某个键,控制器就会调用模型的“插入字符”命令。随后,模型会通知视图更新来显示新的模型。视图不用关心什么时候进行文字改变,只要模型通知它更新它就会更新。这样控制器只用与用户交互并把交互结果反映到模型中去;模型负责维护状态,当状态变化时通知视图更新显示;视图不负责用户交互的状态维护,它只是根据模型中的状态绘制不同的界面。

    Swing中的大多数控件的模型是由一个名字以Model结尾的接口实现的。比如按钮对应的模型接口就是 ButtonModel,JDK中定义了ButtonModel的默认实现类DefaultButtonModel。下面是ButtonModel各个方法的说明:

    boolean isArmed():如果按钮被按下,且鼠标指针仍停留在按钮上则返回true

    boolean isSelected():如果按钮处于选择状态则返回true

    boolean isEnabled():如果按钮可用则返回true

    boolean isPressed():如果按钮被按下,但鼠标没有松开,则返回true

    boolean isRollover():如果鼠标指针在按钮之上则返回true

    public int getMnemonic():返回按钮的助记键

    public String getActionCommand():返回命令字符串

    此外还有对应的设置状态方法:public void setArmed(boolean b)、public void setSelected(boolean b)、public void setEnabled(boolean b)、public void setPressed(boolean b)、public void setRollover(boolean b)、public void setMnemonic(int key)、public void setActionCommand(String s)等。

    每一个JButton都保存着一个ButtonModel对象,我们可以通过JButton的getModel方法来取得该模型对象:

    JButton btn = new JButton(“test”);

    ButtonModel btnModel = btn.getModel();

    通过这个模型对象我们就可以得到按钮的是否可用等状态,不过这个模型是给控件开发者使用的,对于普通使用者来说无需直接调用它,JButton提供了方法来间接的取得这些属性,这一点可以从AbstractButton类的isSelected方法中看出来:

    public boolean isSelected()

    {

    return model.isSelected();

    }

    Swing中大部分控件都由自己的模型,比如JList控件的ListModel、JTable的TableModel、JSpinner的SpinnerModel、JComboBox的SpinnerModel(SpinnerModel是从ListModel派生出来的),这些模型也由默认的实现,名称通常为模型名前加Default。

    Swing中的大多数控件的视图是由一个名字以UI结尾的类实现的,比如按钮对应的模型接口就是 ButtonUI。由于视图在不同的LookAndFeel中有不同的展现形式,所以控件的视图对每一种LookAndFeel都提供了不同的实现。以JLabel为例,它就有MetalLabelUI、MotifLabelUI、WindowsLabelUI等对应不同LookAndFeel的实现。所有的视图都要直接或者间接的从ComponentUI抽象类派生,ComponentUI类中的方法都是供Model回调使用的,下面是ComponentUI主要方法的说明:

    public void installUI(JComponent c):这个方法在ComponentUI 实例被安装到UI代理的时候被触发,用来根据LookAndFeel配置控件。它需要完成如下工作:为Color、Font、Border、Icon等类型的属性设定默认值;根据需要设置布局管理器;创建子控件;初始化监听器;为控件设置PropertyChangeListener 监听器以检测控件属性变化事件;初始化快捷键、Tab键顺序等;初始化数据;

    public void uninstallUI(JComponent c):这个方法在ComponentUI 实例被从UI代理移除的时候触发。需要在此方法中撤销任何在installUI中进行的配置,要保证JComponent实例变为洁净状态(也就是没有监听器,没有LookAndFeel专有属性等)。它需要完成如下工作:从控件中移除border;从控件中移除布局管理器;从控件中移除子控件;从控件中移除事件、属性监听器、从控件中移除快捷键、Tab键顺序等;将数据标记为可以垃圾回收。

    public void paint(Graphics g, JComponent c):为本视图的LookAndFeel绘制控件。

    public void update(Graphics g, JComponent c):通知UI代理绘制指定控件。当特定的控件被绘制的时候此方法会被触发。这个方法的默认实现是用背景色填充控件,并且立即调用paint方法。

    public Dimension getPreferredSize(JComponent c):返回当前LookAndFeel下控件的最佳尺寸。默认实现是返回null;

    public Dimension getMinimumSize(JComponent c):返回当前LookAndFeel下控件的最小尺寸。默认实现是返回getPreferredSize的值;

    public Dimension getMaximumSize(JComponent c):返回当前LookAndFeel下控件的最大尺寸。默认实现是返回getPreferredSize的值;

    public boolean contains(JComponent c, int x, int y):判断指定的x、y坐标是否存在于当前LookAndFeel下的控件中。

    public static ComponentUI createUI(JComponent c):为指定的控件返回UI代理实例。如果UI代理子类是无状态的,它也可以返回多控件共享的实例。如果UI代理子类是有状态的,则它必须为某个控件返回一个新的实例。

    public int getAccessibleChildrenCount(JComponent c):返回所有可访问子控件的数量。

    public Accessible getAccessibleChild(JComponent c, int i):返回指定的子控件

    posted @ 2007-04-19 19:37 CowNew开源团队 阅读(3872) | 评论 (3)编辑 收藏

          目前Hibernate的辅助开发工具有很多,商业的有MyEclipse,自由工具则有HibernateTool、HibernateSynch、Middlegen等,这些工具提供了现有数据库表来生成代码和配置文件等功能,大大简化了开发。这些工具的缺陷也是非常明显的,其指导思想不明确,仅仅是一个代码生成器而已。比如HibernateTool暗示开发人员要先建立数据库表,这其实是一种数据驱动的开发模式,使得开发人员先要去思考数据是如何存储的、有哪些字段,而不是先思考系统对象之间的关系是怎么样的。
          基于此,我们开发了一个正向建模的Hibernate辅助工具,使用这个工具可以通过图形界面建立模型,然后可以由模型生成持久类、映射文件和数据库表。这样开发人员只要在工具中定义对象的模型即可,工具可以自动完成其他的工作。并且工具要保留设计的模型,这样开发人员可以迭代的修改模型,这就可以保证前期的工作成果尽可能多的被利用了。
          此版修复的Bug主要有界面布局的刷新、生成代码的正确性等,此版本在Eclipse3.2.0下测试通过,下载包包含二进制文件和源码。
          CowNew开源团队 http://www.cownew.com   

                   
    文档PDF格式

    文档Word格式

    二进制文件和源码下载>>>

    posted @ 2007-04-17 18:50 CowNew开源团队 阅读(1634) | 评论 (4)编辑 收藏

    2007年4月14日,CowNew开源团队组织了团队第一次北京地区聚会。本次聚会参会成员:散仙、Problem、星、Kingchou、红孔雀、曲金龙、杨中科。此外我们还邀请到了言实文化传播有限公司的执行董事屈辰晨先生、北京科技大学物流研究所的潘洪波先生和北京华美汉盛软件公司的张成先生及其同事。

     

     

     

     

    posted @ 2007-04-16 15:27 CowNew开源团队 阅读(296) | 评论 (1)编辑 收藏

     

    经常可以从开发人员口中听到“面向对象”这个词:

    场景1、

    A:我今天开始用面向对象的方法设计程序了!

    B:你怎么做的?

    A:我把保存文件、加载文件封装成了一个类,以后只要调用这个类就可以实现文件操作了。

    场景2、

    A:我开始学习Java了,面向对象的语言,你不要再学VB了,好土呀!

    B:VB怎么了?

    A:VB是面向过程的,已经过时了,Java中都是类,很时髦!

    B:VB中也有类呀!

    A:(无语)

    场景3、

    A:面向对象思想就是好呀,我真的离不开Java了!

    B:你又用什么高超技术了?

    A:我今天从一个操纵数据库的类继承了一个子类,然后重写了它的保存到数据库的方法,然后把数据通过Socket发送到了远程客户端了,而调用者根本不知道,哈哈!

    场景4、

    A:我推荐你用的Java不错吧?

    B:真是不错,面向对象就是好,JDK里边也有好多好多的类可以用,不用像在VB里边那样要去查API文档了。

    A:但是我听说现在又出了个面向方面编程,咱们看来又落伍了呀,看来做编程真的不是长久之计。

    写几个类就是面向对象了吗?继承父类就是为了重用父类的代码吗?覆盖父类的方法就可以瞒天过海了吗?VB中也有类,它是面向对象吗?

    1.1

    类与对象

    “类”和“对象”是面向对象编程中最基本的概念,从语言的角度来讲,“类”是用户自定义的具有一定行为的数据类型,“对象”则是“类”这种数据类型的变量。通俗的讲,“类”是具有相同或相似行为的事物的抽象,“对象”是“类”的实例,是是一组具有相关性的代码和数据的组合体,是有一定责任的实体。

    类本身还可以进一步抽象为类型,类型是一种更高层次上的抽象,它只用来描述接口,比如抽象类和接口就是一种类型。当一个类型的接口包含另外一个类型的接口时,我们就可以说它是此类型的子类型。类型是用来标识特定接口的,如果一个对象接受某个接口定义的所有行为,那么我们就可以说该对象具有该类型。一个对象同时拥有多种类型。

    面向对象编程的特性

    面向对象编程有三个特性:封装,继承,多态。这三个特性从低级到高级描述了面向对象的特征。一种语言只有同时具备这三种特性才能被称为面向对象的语言。VB中也有类,它的类也支持封装和简单的继承,但是它不支持所有的继承语义和多态,因此VB只能被称为基于对象的语言。

    封装是所有抽象数据类型(ADT)的特性,很多刚刚接触面向对象的人认为封装就是就是面向对象。将程序按照一定的逻辑分成多个互相协作的部分,并将对外界有用的稳定的部分暴露出来,而将会发生的改变隐藏起来,外界只能通过暴露的部分向这个对象发送操作请求从而享受对象提供的服务,而不必管对象内部是如何运行的,这就是封装。理解封装是理解面向对象的第一个步骤,40%的程序员对面向对象的理解仅停留在封装这个层次。

    继承也称为派生,继承关系中,被继承的称为基类,从基类继承而得的被称为派生类或者子类。继承是保持对象差异性的同时共享对象相似性的复用。能够被继承的类总是含有并只含有它所抽象的那一类事务的共同特点。继承提供了实现复用,只要从一个类继承,我们就拥有了这个类的所有行为。理解继承是理解面向对象的第二个步骤,50%的程序员对面向对象的理解仅停留在继承这个层次。语义上的“继承”表示“是一种(is-a)”的关系。很多人体会到了继承在代码重用方面的优点,而忽视了继承的语义特征。于是很多滥用继承的情况就发生了,关于这一点我们将会在后边介绍。

    多态是“允许用户将父对象设置成为一个或更多的它的子对象相等的技术,赋值后,基类对象就可以根据当前赋值给它的派生类对象的特性以不同的方式运作”(Charlie Calvert)。多态扩大了对象的适应性,改变了对象单一继承的关系。多态是行为的抽象,它使得同名方法可以有不同的响应方式,我们可以通过名字调用某一方法而无需知道哪种实现将被执行,甚至无需知道执行这个实现的对象类型。多态是面向对象编程的核心概念,只有理解了多态,才能明白什么是真正的面向对象,才能真正发挥面向对象的最大能力。不过可惜的是,只有极少数程序员能真正理解多态。

    对象之间的关系

    对象之间有两种最基本的关系:继承关系,组合关系。

    继承关系

    继承关系可以分为两种:一种是类对接口的继承,被称为接口继承;另一种是类对类的继承,被称为实现继承。继承关系是一种“泛化/特化”关系,基类代表一般,而派生类代表特殊。

    组合关系。

    组合是由已有的对象组合而成新对象的行为,组合只是重复运用既有程序的功能,而非重用其形式。组合与继承的不同点在于它表示了整体和部分的关系。比如电脑是由CPU、内存、显示器、硬盘等组成的,这些部件使得电脑有了计算、存储、显示图形的能力,但是不能说电脑是由CPU继承而来的。

    1.2

    对象之间有两种最基本的关系:继承关系,组合关系。通过这两种关系的不断迭代组合最终组成了可用的程序。但是需要注意的就是要合理使用这两种关系。

    派生类是基类的一个特殊种类,而不是基类的一个角色。语义上的“继承”表示“is-a”(是一种)的关系,派生类“is-a”基类,这是使用继承关系的最基本前提。如果类A是类B的基类,那么类B应该可以在任何A出现的地方取代A,这就是“Liskov代换法则(LSP)”。如果类B不能在类A出现的地方取代类A的话,就不要把类B设计为类A的派生类。

    举例来说,“苹果”是“水果”的派生类,所以“水果是植物的果实”这句话中的“水果”可以用“苹果”来代替:“苹果是植物的果实”;而“苹果”不是“香蕉”的派生类,因为“香蕉是一种种子退化的了的植物果实”不能被“苹果”替换为“苹果是一种种子退化的了的植物果实”。

    举这个例子好像有点多余,不过现实的开发中却经常发生“苹果”从“香蕉”继承的事情。

    某企业中有一套信息系统,其中有一个“客户(Customer)”基础资料,里边记录了客户的名称、地址、email等信息。后来系统要进行升级,增加一个“供应商(Supplier)”基础资料,开发人员发现“供应商”中有“客户”中的所有属性,只是多了一个“银行帐号”属性,所以就把“供应商”设置成“客户”客户的子类。

    图 2.1

    到了年终,老板要求给所有的客户通过Email发送新年祝福,由于“供应商”是一种(is-a)“客户”,所以系统就给“供应商”和“客户”都发送了新年祝福。第二天很多供应商都感动流涕的给老板打电话“谢谢老板呀,我们供应商每次都是求着贵公司买我们的东西,到了年终你们还忘不了我们,真是太感谢了!”。老板很茫然,找来开发人员,开发人员这才意识到问题,于是在发送Email的程序里做了判断“如果是供应商则不发送,否则发送”,一切ok了。到了年初,老板要求给所有很长时间没有购买他们产品的“客户”,打电话进行问候和意见征集。由于“供应商”是一种(is-a)“客户”,所以第二天电话里不断出现这样的回答:“你们搞错了吧,我们是你们的供应商呀!”。老板大发雷霆,开发人员这才意识到问题的严重性,所以在系统的所有涉及到客户的地方都加了判断“如果是供应商则……”,一共修改了60多处,当然由于疏忽遗漏了两处,所以后来又出了一次类似的事故。

    我们可以看到错误使用继承的害处了。其实更好的解决方案应该是,从“客户”和“供应商”中抽取一个共同的基类“外部公司”出来:

    图 2.2

    这样就将“客户”和“供应商”之间的继承关系去除了。

    派生类不应大量覆盖基类的行为。派生类具有扩展基类的责任,而不是具有覆盖(override)基类的责任。如果派生类需要大量的覆盖或者替换掉基类的行为,那么就不应该在两个类之间建立继承关系。

    让我们再来看一个案例:

    一个开发人员要设计一个入库单、一张出库单和一张盘点单,并且这三张单都有登帐的功能,通过阅读客户需求,开发人员发现三张单的登帐逻辑都相同:遍历单据中的所有物品记录,然后逐笔登到台帐上去。所以他就设计出了如下的程序:

    图 2.3

    把登帐逻辑都写到了“库存业务单据”这个抽象类中,三张单据从这个类继承即可。过了三个月,用户提出了新的需求:盘点单在盘点过程中,如果发现某个货物的盘亏量大于50则停止登帐,并向操作人员报警。所以开发人员在盘点单中重写了“库存业务单据”的“登帐”方法,实现了客户要求的逻辑。又过了半个月,客户要求出库登帐的时候不仅要进行原先的登帐,还要以便登帐一边计算出库成本。所以开发人员在出库单中重写了“库存业务单据”的“登帐”方法,实现了客户要求的逻辑。到了现在“库存业务单据”的“登帐”方法的逻辑只是对“入库单”有用了,因为其他两张单据都“另立门户”了。

    这时候就是该我们重新梳理系统设计的时候了,我们把“库存业务单据”的“登帐”方法设置成抽象方法,具体的实现代码由具体子类自己决定:

    图 2.4

    注意此处的“库存业务单据”中的“登帐”方法是斜体,在UML中表示此方法是一个抽象方法。这个不难理解,每张单据都肯定有登帐行为,但是每张单据的登帐行为都有差异,因此在抽象类中定义类的“登帐”方法为抽象方法以延迟到子类中去实现。

    继承具有如下优点:实现新的类非常容易,因为基类的大部分功能都可以通过继承关系自动赋予派生类;修改或者扩展继承来的实现非常容易;只要修改父类,派生的类的行为就同时被修改了。

    初学面向对象编程的人会认为继承真是一个好东西,是实现复用的最好手段。但是随着应用的深入就会发现继承有很多缺点:继承破坏封装性。基类的很多内部细节都是对派生类可见的,因此这种复用是“白箱复用”;如果基类的实现发生改变,那么派生类的实现也将随之改变。这样就导致了子类行为的不可预知性;从基类继承来的实现是无法在运行期动态改变的,因此降低了应用的灵活性。

    继承关系有很多缺点,如果合理使用组合则可以有效的避免这些缺点,使用组合关系将系统对变化的适应力从静态提升到动态,而且由于组合将已有对象组合到了新对象中,因此新对象可以调用已有对象的功能。由于组合关系中各个各个对象的内部实现是隐藏的,我们只能通过接口调用,因此我们完全可以在运行期用实现了同样接口的另外一个对象来代替原对象,从而灵活实现运行期的行为控制。而且使用合成关系有助于保持每个类的职责的单一性,这样类的层次体系以及类的规模都不太可能增长为不可控制的庞然大物。因此我们优先使用组合而不是继承。

    当然这并不是说继承是不好的,我们可用的类总是不够丰富,而使用继承复用来创建一些实用的类将会不组合来的更快,因此在系统中合理的搭配使用继承和组合将会使你的系统强大而又牢固。

    1.3

    接口的概念

    接口是一种类型,它定义了能被其他类实现的方法,接口不能被实例化,也不能自己实现其中的方法,只能被支持该接口的其他类来提供实现。接口只是一个标识,标识了对象能做什么,至于怎么做则不在其控制之内,它更像一个契约。

    任何一个类都可以实现一个接口,这样这个类的实例就可以在任何需要这个接口的地方起作用,这样系统的灵活性就大大增强了。

    接口编程的实例

    SQL语句在各个不同的数据库之间移植最大的麻烦就是各个数据库支持的语法不尽相同,比如取出表的前10行数据在不同数据库中就有不同的实现。

    MSSQLServer:Select top 10 * from T_Table

    MySQL:select * from T_Table limit 0,10

    Oracle:select * from T_Table where ROWNUM <=10

    我们先来看一下最朴素的做法是怎样的:

    首先定义一个SQL语句翻译器类:

    public class Test1SQLTranslator

    {

    private int dbType;

    public Test1SQLTranslator(int dbType)

    {

    super();

    this.dbType = dbType;

    }

    public String translateSelectTop(String tableName, int count)

    {

    switch (dbType) {

    case 0:

    return "select top " + count + " * from " + tableName;

    case 1:

    return "select * from " + tableName + " limit 0," + count;

    case 2:

    return "select * from " + tableName + " where ROWNUM<=" + count;

    default:

    return null;

    }

    }

    }

    然后如下调用

    public static void main(String[] args)

    {

    String tableName = "T_Table";

    int count = 10;

    int dbType = 0;

    Test1SQLTranslator translator = new Test1SQLTranslator(dbType);

    String sql = translator.translateSelectTop(tableName,count);

    System.out.println(sql);

    }

    如果要增加对新的数据库的支持,比如DB2,那么就必须修改Test1SQLTranslator类,增加一个对DB2的case语句,这种增加只能是在编辑源码的时候进行添加,无法在运行时动态添加。再来看一下如果用基于接口的编程方式是如何实现的。

    首先,定义接口ISQLTranslator,这个接口定义了所有SQL翻译器的方法,目前只有一个翻译Select top的方法:

    public interface ISQLTranslator

    {

    public String translateSelectTop(String tableName, int count);

    }

    接着我们为各个数据库写不同的翻译器类,这些翻译器类都实现了ISQLTranslator接口:

    public class MSSQLServerTranslator implements ISQLTranslator

    {

    public String translateSelectTop(String tableName, int count)

    {

    return "select top " + count + " * from " + tableName;

    }

    }

    public class MySQLTranslator implements ISQLTranslator

    {

    public String translateSelectTop(String tableName, int count)

    {

    return "select * from " + tableName +" limit 0,"+count;

    }

    }

    public class OracleSQLTranslator implements ISQLTranslator

    {

    public String translateSelectTop(String tableName, int count)

    {

    return "select * from " + tableName+" where ROWNUM<="+count;

    }

    }

    如下调用:

    public static void main(String[] args)

    {

    String tableName = "T_Table";

    int count = 10;

    ISQLTranslator translator = new MSSQLServerTranslator();

    String sql = translator.translateSelectTop(tableName, count);

    System.out.println(sql);

    }

    运行以后,打印出了:

    select top 10 from T_Table

    可以看到,不同的数据库翻译实现由不同的类来承担,这样最大的好处就是可扩展性极强,比如也许某一天出现了了支持中文语法的数据库,我要为它做翻译器只需再增加一个类:

    public class SinoServerTranslator implements ISQLTranslator

    {

    public String translateSelectTop(String tableName, int count)

    {

    return "读取表"+tableName+"的前"+count+"行";

    }

    }

    修改调用代码:

    public static void main(String[] args)

    {

    String tableName = "T_Table";

    int count = 10;

    ISQLTranslator translator = new SinoServerTranslator();

    String sql = translator.translateSelectTop(tableName, count);

    System.out.println(sql);

    }

    运行后控制台打印出:

    读取表T_Table的前10行

    这里的translator 可以随意实例化,只要实例化的类实现了ISQLTranslator 就可以了,这个类也可以通过配置文件读取,甚至是其他类传递过来的,这都无所谓,只要是实现了ISQLTranslator 接口它就能正常工作。

    如果要给SQL语句加上验证功能,也就是翻译的时候首先验证一下翻译的结果是否能在数据库中执行,我们就可以采用偷天换日的方式来进行。

    首先创建一个VerifyTranslator类:

    public class VerifyTranslator implements ISQLTranslator

    {

    private ISQLTranslator translator;

    private Connection connection;

    public VerifyTranslator(ISQLTranslator translator, Connection connection)

    {

    super();

    this.translator = translator;

    this.connection = connection;

    }

    public String translateSelectTop(String tableName, int count)

    {

    String sql = translator.translateSelectTop(tableName, count);

    PreparedStatement ps = null;

    try

    {

    ps = connection.prepareStatement(sql);

    ps.execute();

    } catch (SQLException e)

    {

    DbUtils.close(ps);

    return "wrong sql";

    }

    return sql;

    }

    }

    这个类接受一个实现了ISQLTranslator 接口的变量和数据库连接做为构造参数,最重要的是这个类本身也实现了ISQLTranslator 接口,这样它就完全能“伪装”成SQL翻译器来行使翻译的责任了,不过它没有真正执行翻译,它把翻译的任务转发给了通过构造函数传递来的那个翻译器变量:

    String sql = translator.translateSelectTop(tableName, count);

    它自己的真正任务则是进行SQL语句的验证:

    ps = connection.prepareStatement(sql);

    再次修改调用代码:

    public static void main(String[] args)

    {

    String tableName = "T_Table";

    int count = 10;

    ISQLTranslator translator = new VerifyTranslator(

    new SinoServerTranslator(), getConnection());

    String sql = translator.translateSelectTop(tableName, count);

    System.out.println(sql);

    }

    运行后控制台打印出:

    wrong sql

    下面这段代码看上去是不是很眼熟呢?

    ISQLTranslator translator = new VerifyTranslator(new SinoServerTranslator(), getConnection());

    这段代码和我们经常写的流操作非常类似:

    InputStream is = new DataInputStream(new FileInputStream(new File(“c:/boot.ini”)));

    这就是设计模式中经常提到的“装饰者模式”。

    针对接口编程

    从上面的例子我们可以看出,当代码写到:

    String sql = translator.translateSelectTop(tableName, count);

    的时候,代码编写者根本不关心translator这个变量到底是哪个类的实例,它只知道它调用了接口约定支持的translateSelectTop方法。

    当一个对象需要与其他对象协作完成一项任务时,它就需要知道那个对象,这样才能调用那个对象的方法来获得服务,这种对象对另一个协作对象的依赖就叫做关联。如果一个关联不是针对具体类,而是针对接口的时候,任何实现这个接口的类都可以满足要求,因为调用者仅仅关心被依赖的对象是不是实现了特定接口。

    当发送的请求和具体的请求响应者之间的关系在运行的时候才能确定的时候,我们就称之为动态绑定。动态绑定允许在运行期用具有相同接口的对象进行替换,从而实现多态。多态使得对象间彼此独立,所有的交互操作都通过接口进行,并可以在运行时改变它们之间的依赖关系。

    针对接口编程,而不是针对实现编程是面向对象开发中的一个非常重要的原则,也是设计模式的精髓!

    针对接口编程有数不清的例子,比如在Hibernate中,集合属性必须声明为Set、Map、List等接口类型,而不能声明为HashSet、HashMap、ArrayList等具体的类型,这是因为Hibernate在为了实现LazyLoad,自己开发了能实现LazyLoad功能的实现了Set、Map、List等接口的类,因为我们的属性的类型只声明为这些属性为这些接口的类型,因此Hibernate才敢放心大胆的返回这些特定的实现类。

    现实的开发过程中有如下一些违反针对接口编程原则的陋习:

    陋习1

    ArrayList list = new ArrayList();

    for(int i=0;i<10;i++)

    {

    list.add(……);

    }

    这里使用的是ArrayList的add方法,而add方法是定义在List接口中的,因此没有必要声明list变量为ArrayList类型,修改如下:

    List list = new ArrayList();

    for(int i=0;i<10;i++)

    {

    list.add(……);

    }

    陋习2

    public void fooBar(HashMap map)

    {

    Object obj = map.get(“something”);

    ……

    }

    在这个方法中只是调用Map接口的get方法来取数据,所以就不能要求调用者一定要传递一个HashMap类型的变量进来。修改如下:

    public void fooBar(Map map)

    {

    Object obj = map.get(“something”);

    ……

    }

    这样修改以后用户为了防止传递给fooBar方法的Map被修改,用户就可以这样调用了:

    Map unModMap = Collections.unmodifiableMap(map);

    obj.fooBar(unModMap);

    Collections.unmodifiableMap是JDK提供的一个工具类,可以返回一个对map的包装,返回的map是不可修改的,这也是装饰者模式的典型应用。

    试想如果我们把接口声明为public void fooBar(HashMap map)用户还能这么调用吗?

    1.4 抽象类

    抽象类的主要作用就是为它的派生类定义公共接口,抽象类把它的部分操作的实现延迟到派生类中来,派生类也能覆盖抽象基类的方法,这样可以很容易的定义新类。抽象类提供了一个继承的出发点,我们经常定义一个顶层的抽象类,然后将某些位置的实现定义为抽象的,也就是我们仅仅定义了实现的接口,而没有定义实现的细节。

    一个抽象类应该尽可能多的拥有共同的代码,但是不能把只有特定子类才需要的方法移动到抽象类中。Eclipse的某些实现方式在这一点上就做的不是很好,Eclipse的一些界面类中提供了诸如CreateEmailField之类的方法来创建界面对象,这些方法并不是所有子类都用得到的,应该把它们抽取到一个工具类中更好。同样的错误在我们的案例的JCownewDialog中也是存在的,这个类中就提供了CreateOKBtn、CreateCanceBtn两个方法用来创建确定、取消按钮。

    在设计模式中,最能体现抽象类优点的就是模版方法模式。模版方法模式定义了一个算法的骨架,而具体的实现步骤则由具体的子类类来实现。JDK中的InputStream类是模版方法的典型代表,它对skip等方法给出了实现,而将read等方法定义为抽象方法等待子类去实现。后边案例中的PISAbstractAction等类也是模版方法的一个应用。

    在实际开发中接口和抽象类从两个方向对系统的复用做出了贡献,接口定义了系统的服务契约,而抽象类则为这些服务定义了公共的实现,子类完全可以从这些抽象类继承,这样就不用自己实现自己所不关心的方法,如果抽象类提供的服务实现不满足自己的要求,那么就可以自己从头实现接口的服务契约。

    posted @ 2007-04-10 15:14 CowNew开源团队 阅读(1608) | 评论 (8)编辑 收藏

        CowNew开源团队是目前国内较活跃的开源团队之一,我们致力于基础平台的开发以及知识推广,目前已经有数个成熟的基础产品问世,并与国内数家网站、出版社建立了知识推广的合作关系。目前团队处于成长的转型期,急需有志之士加盟共同为中国的开源事业奋斗。
        我们需要如下几类队友:
        (1)基础平台开发工程师
         要求:对软件开发有很强的兴趣;有较多的时间能够投入到开源开发中来;有较强的计算机学科基础(编译原理、数据结构、操作系统等)或者熟悉Eclipse、NetBeans等平台的插件开发;能够胜任基础平台的开发;
         职责:SQL翻译器、SQL调优器、数据库监控、开发工具等基础平台的开发;
        (2)技术类图书作者
        要求:对软件开发有很强的兴趣;有较强的计算机学科基础(编译原理、数据结构、操作系统等);有实际的开发经验;有较好的书面表达能力;有较多的时间能够投入到书籍编写中来;
        职责:计算机学科基础类图书的编写;
        (3)外联人员
        要求:有较强的沟通能力和组织协调能力;有校园活动的组织经验;有较多的时间能够投入到团队的宣传工作中来;
        职责:团队校园活动的组织以及团队的对外宣传;
     
        注意:我们的团队目前只是一个非盈利性、非实体组织,目前仍然在发展的探索中,我们无法在短时间之类让您看到经济回报,团队成员也全部是利用业余时间从事这项工作的,所以如果您需要的一个能立即给您带来经济回报的全职工作,那么我们的团队并不适合您。CowNew开源团队的明天是美好的,如果您有创业精神,如果您有充足的时间和热情投入到这份具有前途的事业中的话,那么我们欢迎您的加入。
        团队在4月14日将会举办一次北京地区的聚会活动,希望新加入的队友能够参加我们的活动。
        有意加入团队的朋友请将您要加入的职位和您的基本情况通过Email发送给我们,我们的Email是:about521@163.com
        http://www.cownew.com
         thanks to dudu and other administrators.
      
    posted @ 2007-04-10 14:33 CowNew开源团队 阅读(1099) | 评论 (0)编辑 收藏

          最近要做一个Python的基于Eclipse的界面设计器,因此我对各种GUI设计工具做了一下分析,发现GUI设计工具也有一个门派。
          在那个懵懂的年代,一切界面代码都是要开发人员手工书写,这无疑增加了开发难度,Delphi、VB等工具的出现扭转了这个局面,使用这些工具开发人员只要在控件面板上拖拖拽拽就可以完成界面的设计,做到了“所见即所得”的开发方式。仔细分析,GUI设计工具有如下几个门派:基于界面文件的纯代码生成、代码生成与界面文件结合、无界面文件方式。

          基于界面文件的纯代码生成:NetBeans是这类工具的典型代表(如果我没记错的话JBuilder也是这样实现的),NetBeans中与界面设计有关的有两个文件:.java文件和.form文件。.form文件中是以XML格式描述界面布局和控件的属性等信息;.java文件则是通过解析.form文件生成的代码,生成的界面代码主要位于initComponents方法中,这个方法在NetBeans IDE中是无法手工编辑的。在用户拖拉控件的时候,NetBeans就将拖拉的控件描述增加到.form文件中,并且即时将新的代码生成到.java文件中。这样实现的好处有如下几点:IDE实现容易,IDE的开发人员只要关注于如何将界面信息转化为.form文件和如何将.form文件解析生成.java代码即可,无需关心用户修改.java代码造成的反向解析问题;.java文件可以脱离.form而存在,也就是.form文件只是在设计期有意义,而在运行期是无用的。缺点是:用户无法手工修改生成的代码。
         代码生成与界面文件结合:Delphi和VB是这类工具的典型代表。以Delphi为例,在Delphi中新建以后界面以后将会存在两个文件:.dfm和.pas,.dfm描述了界面布局和控件的属性等信息,.pas则定义了控件的变量和事件处理函数。在编译的时候.dfm被编译到可执行文件中,运行的时候动态解析.dfm文件来构建界面。与NetBeans不同的就是.dfm文件是有运行期的意义的,如果没有.dfm文件文件,程序将无法编译运行。这样的方式通常只适用于Delphi、VB这样代码和IDE结合过于紧密的语言,很难将生成的代码进行手工修改。
      无界面文件方式:Eclipse的Visual Editor是最经典的例子。使用Visual Editor进行GUI绘制的时候,只存在一个.java文件,Visual Editor将用户绘制的界面直接解析为.java代码,如果用户修改了.java代码,Visual Editor会运行一个虚拟机,在虚拟机中运行用户修改后的文件,得到运行时的程序界面,然后将这个界面绘制到窗口设计器中。这样做可以将所有的界面信息都集成到一个文件中,并且支持用户手工修改生成的代码;由于设计器中的界面是通过另外一个虚拟机运行而得到的,在界面设计器中看到的界面就是运行时的界面,这样保证了真正的“所见即所得”。这样做的坏处也是明显的,由于需要重新启动一个虚拟机,导致了速度很慢,资源占用比较高,使用Visual Editor的时候经常造成Eclipse内存不足退出。   
     
          我在开发界面设计器的早期采用的基于界面文件的纯代码生成方式,系统中有一个.aui文件和对应生成的.py源代码文件,后来由于系统需求(主要是要求允许开发人员修改生成的代码),我就准备改用无界面文件方式。如果采用Visual Editor的无界面文件方式难度是比较大的,而且会导致资源占用太大,因此我采用了另外一种思路,也就是在内存中为每个界面维护一个对象模型(树状结构),在用户绘制界面的时候去修改这个对象模型,在用户保存界面的时候去解析这个对象模型生成.py源代码;在由.py源代码加载绘制设计器中的界面的时候,首先通过解析.py 源代码生成源代码的抽象语法树(AST),然后解析这个AST生成界面的对象模型,这样就可以很轻松的绘制界面了。这样做不仅有Visual Editor的优点,而且占用资源比较小;不过由于手工修改代码的千差万别,如果开发人员修改的代码采用了比较生僻的语法,有可能造成用户修改的代码无法正确的解析为对象模型,造成.py源代码加载绘制设计器中的界面的时候发生异常,解决这个问题的唯一一个办法就是建议开发人员尽量采用常用的代码来修改生成的界面代码。
          由于HTML代码本身就是一个树状模型,无需进行代码和模型间的转换,所以网页设计器就不存在上边说的这些帮派了。

     http://www.cownew.com CowNew开源团队 
     杨中科 email:about521爱特163.com
    posted @ 2007-04-08 17:24 CowNew开源团队 阅读(3253) | 评论 (4)编辑 收藏

       IWorkbenchPage page = Activator.getActivePage();

       IAdapterManager mgr = Platform.getAdapterManager();
       String propPageName = IPropertySheetPage.class.getName();
       PropertySheetPage proppage = (PropertySheetPage) mgr.loadAdapter(
         page, propPageName);
       if (proppage != null)
       {
           proppage.refresh();
       }

    posted @ 2007-03-28 15:22 CowNew开源团队 阅读(708) | 评论 (0)编辑 收藏

          可能大家常常会有这样的疑问,为什么我发的帖子始终没有人回复呢?这种感觉一定很让人沮丧吧?实际上,并不是没有人愿意伸出自己的手,但是这前提是,你要掌握提问的智慧,必须激起看你帖人的回答欲望。

          在提出技术问题前,检查你有没有做到:
    1. 通读帮助文档,试着自己找答案。
    2. 通过搜索引擎搜索。
    3. 自己尝试进行问题解决。

          当你提出问题的时候,首先要说明在此之前你干了些什么,这将有助于树立你 的形象:你不是一个妄图不劳而获的乞讨者,不愿浪费别人的时间。一个问题如果提的好那么即使大家不知道怎么解决,也会帮你出谋划策,和你一起解决;如果一个问题提得不好,那么即使再简单,也没人搭理你!

          周全的思考,准备好你的问题,草率的发问只能得到草率的回答,或者根本得 不到任何答案。越表现出在寻求帮助前为解决问题付出的努力,你越能得到实 质性的帮助。

          决不要自以为够资格得到答案,你没这种资格。毕竟你没有为这种服务支付任何报酬。你要自己去“挣”回一个答案,靠提出一个有内涵的,有趣的,有思维激励作用的问题--一个对社区的经验有潜在贡献的问题,而不仅仅是被动的从他人处索要知识--去挣到这个答案。

          这是对自己的尊重,也是对别人的尊重。

    posted @ 2007-03-28 10:59 CowNew开源团队 阅读(257) | 评论 (0)编辑 收藏

         摘要: XML 技术是随着 Java 的发展而发展起来的。在 XML 出现之前对于简单的数据格式通常是存储在 ini 配置文件等文本文件中,复杂的格式则采用自定义的文件格式,因此对于每种文件格式都要有专门的解析程序。 XML 出现以后解决了这个问题,程序面对的是有固定格式的 XML 文件,只要通过...  阅读全文
    posted @ 2007-03-26 13:14 CowNew开源团队 阅读(3400) | 评论 (5)编辑 收藏

         摘要: 是否选择了合适的数据结构进行数据处理对系统的性能有着极大的影响, JDK 中提供了常用的数据结构的实现类,比如链表、堆栈、哈希表,很多第三方开源库也进行了有益的扩展。关于这些类的原理以及使用可以参考相关的手册,在本节中重点讲解一些使用中需要注意的问题 。 1.1.1.       增量内存分配 ...  阅读全文
    posted @ 2007-03-16 12:37 CowNew开源团队 阅读(1764) | 评论 (5)编辑 收藏

    这是刚才和一个朋友的聊天记录,希望对大家有帮助:
    佘士东 08:41:47
    我设计一个接口,其中有些方法很类似,比如取得某个工作对象,有可能需要获得多个,也有可能获得其中一个,参数为工作对象的名字、名字列表。
    我是用窄接口还是宽接口好,是用一个最大功能的方法还是多个重载方法好?
    比如:
    IService
    public Worker  getWorker(String name);
    public Vector<Worker> getWorkers(final Vector<String> names);
    我是在接口约束这两个方法还是只约束最大的那个,使所有的方法都适配为后面这个最大方法,而在接口中去掉第一个方法
    杨中科 08:51:57
    我认为还是多个重载方法好,主要是考虑方便别人使用
     
    杨中科 08:52:31
    顺便说一句:为什么参数和返回值要用Vector?用List接口不更好吗?
     
    佘士东 08:53:55
    如果适用者很有限,大概只有5个左右,实际上使用者也是提供适配功能,比如使用cs结构,web方式,wap方式,sms方式获得接口服务的适配模块
    佘士东 08:55:04
    我的想法是使用Vector它是异步安全的,服务可能是多线程实现的,所以使用Vector返回,不知道有没有这个必要,有没有这个作用
    杨中科 08:55:12
    你说的是什么意思,不太明白。你说getworker方法不是所有实现类都能实现?
     
    佘士东 08:56:35
    其实这个接口是夹在实现和使用这中间的,使用者实现不同类型服务的适配,实现根据项目不同所要求的业务实现不一样,实际上这个接口是约束实现要多
    佘士东 08:58:08
    如果接口方法太多,我怕如果变更会不会陷入变更里面,因为重载多了,其中很多有重复,比如参数列表,如果需要加上用户验证,那就都要加,这样所有实现都要改动一批
    杨中科 08:59:41
    “我的想法是使用Vector它是异步安全的,服务可能是多线程实现的,所以使用Vector返回,不知道有没有这个必要,有没有这个作用 ”,你可以将传进来的List参数用Collections类中的syn****List方法将List搞成异步安全的,返回的时候你也可以返回Vector类型的,但是返回值要生命成List类型
     
    杨中科 09:00:14
    要考虑二次开发人员的易用性,大部分人还是倾向于使用List、ArrayList这样的东西的
     
    杨中科 09:01:50
    “如果接口方法太多,我怕如果变更会不会陷入变更里面,因为重载多了,其中很多有重复,比如参数列表,如果需要加上用户验证,那就都要加,这样所有实现都要改动一批 ”,还是那句话,不要陷入实现的漩涡中,你的接口是声明服务用的,不要管实现,怎么实现是实现类的事情,站在二次开发人员的角度来看你必须同时提供getworker和getworkers两个方法
     
    佘士东 09:01:49
    原来如此,就是说实际上还是Vector,只不过返回值使用List接口,但是如果他直接转换成ArrayList使用会不会丢掉原来异步安全特性?因为返回值毕竟只是一个引用,可能其它地方也在用同一个引用
    杨中科 09:02:30
    不可能转换为ArrayList的,否则运行的时候会抛ClassCastException
     
    佘士东 09:02:46
    但是,二次开发实际上是开发实现类,而不是服务调用类
    杨中科 09:03:24
    哦,也就是二次开发实际上是写一个实现了你定义的接口的插件???
     
    佘士东 09:03:47
    对,就是这个意思
    杨中科 09:04:57
    那也最好提供这两个接口,这样你使用这些插件的时候也方便,你可以写一个抽象类来实现默认的getworker方法,在getworker中调用getworkers方法,这样二次开发人员一般只要实现getworkers方法就可以了
     
    佘士东 09:04:57
    但是这个插件是惟一的,使用一个Factory获得实现
    佘士东 09:05:57
    哈哈,豁然开朗,宽接口,加上适配抽象父类,就搞定了
    杨中科 09:06:26
    接口方法是越多用起来越方便
     
    佘士东 09:07:10
    我只是怕在产生变更的时候,对应的实现也要改动很多,毕竟框架才是初期
    杨中科 09:08:29
    “对应的实现也要改动很多”,那就看你抽象类的实现水平的,定义接口的时候不要去想实现,只要想接口定义那些方法才够用就可以,实现和接口不能混
     
    杨中科 09:09:00
    你可以用各种设计模式来保证不会发生“产生变更的时候,对应的实现也要改动很多”
     
    杨中科 09:09:11
    但是接口就是接口

    posted @ 2007-03-13 09:18 CowNew开源团队 阅读(1964) | 评论 (10)编辑 收藏

    Python 的模块一旦加载就会常驻内存,直到程序结束。再碰到 import 语句式只是修改名字空间,而不需要重新加载。这种机制是出于运行时的效率考虑,每遇到 import 的时候重新加载显然很低效。它也不会检查源文件的修改时间以确定是否重新加载,Python 有那么多的模块,每次调用时都检查一遍时间也是不行的。

    这种机制下,开发长时间运行的守护程序就会很麻烦,修改源代码后要重新启动程序才能让新的代码生效。比如用 mod_python 做 web 开发,Apache 会启动多个守护进程来应答客户请求,里面有 python 的解释引擎和加载的模块,若要让修改后的代码生效只能重起 apache,这会影响到其它服务的正常运行,非常不方便。mod_python 有一个PythonAutoReload 参数,它只是针对 PythonHandler 而言的,能够对设定的 PythonHandler 实现自动重新加载,而该 Handler 中所用到的模块却不能自动 reload。

    这种修改源代码然后重起 apache 的调试方式实在让我无法忍受了,决定实现一种自动重新加载机制。基本的思路就是每个用户请求到来时,检查我所关心的那些模块源文件的修改时间,如果比加载时的修改时间新,则重新加载。

    编写一个检测时间和重新加载的函数,让它在每个请求到来时执行:

    1. def  autoreload():   
    2.   mod_names = ['Entry','Index','SideBar']   
    3.    for  mod_name  in  mod_names:   
    4.      try :   
    5.       module =  sys .modules[ mod_name ]   
    6.      except :   
    7.        continue   
    8.     mtime =  os .path.getmtime( module.__file__ )   
    9.      try :   
    10.        if  mtime > module.loadtime:   
    11.          reload ( module )   
    12.      except :   
    13.      pass   
    14.     module.loadtime = mtime   

    这段代码不长,但是改了好多个版本,最开始用 has_key() 的方式来检测是否存在某个模块,检测该模块是否有 loadtime 属性( 用 module.__dict__ ),现在这种方式应该效率高一些,曾经在一个 blog 上看到过对比测试数据。起初还在每个关心的模块里面加上一句loadtime = os.path.getmtime( __file__ ),这是不必要的,因为 Python 用的是动态类型,可以在运行时追加属性,第一次检测时设置初始状态即可。

    有了这段代码,开发 BlogXP 方便多了,改了源码之后立马就能生效,而且它在正常运行时的消耗也很小。另外,由于mod_python 能够实现指定的 Handler 的自动重新加载,将这段代码放在该 Handler 中,可以方便地改变所关心的模块列表,也不需重起 apache。

    欢迎批评指正:-)
    from: http://blog.daviesliu.net/article/entry20050610-235635

    posted @ 2007-03-12 14:57 CowNew开源团队 阅读(1736) | 评论 (2)编辑 收藏

    thanks to hengheng123456789:
    首席执行官『ceo.icxo.com』专家指点:30岁前让你成为“富翁”的四大秘诀

     内修工夫+外营人脉

        所谓,只能靠钱赚钱?尽管市面上理财书籍教的致富方法,大多是以投资工具为媒介,但积累资产的方法不只一种,有人懂得善用投资工具,大赚机会财;有人则专营人脉圈,年轻时愿意多付点交际费当学费,先蹲后跳,随之而来的是职位、薪水的提升以及见识的增广,已经不是可以用报酬率这类数字来衡量的了。

        外营:深耕职场关系

        上世纪九十年代初就开始投资的李雨,对于理财工具的知识比一般人还要强,却没有用于自己的资产规划,“我没有很刻意存钱或寻求投资,我认为投资自己最重要!”他说:李雨对自我的投资,包含了进修与人脉两项。他曾在上海一家最高级的休闲俱乐部待了7年,做到市场总监,举办过数十场的大型休闲运动赛事,招待过阿加西、张德培等世界运动名将。

      有些俱乐部是达官贵人的汇聚之所,在那里可以接触到很多优秀的人。李雨从一个小专员开始,只有一千多元的薪水,他却舍得请客吃饭、多结交朋友,而非存起来。“你知道吗?光听他们讲话就觉得收获颇丰!”他觉得这交际费花得太值了。他的专业是市场营销,深耕人脉的作用很快便“发酵”般扩散,各方人士大力赞助并参与他所举办的活动。不过三年,他便跻身年薪百万一族了。

        李雨实行的就是“人脉理财法”:藉由结识比自己更优秀的人才,协助事业或眼界的拓展。理财专家也认为:投资在理财的时间愈长就表示投资在自己身上的时间愈短,而增加自己这个“人力资本”,如增加学历、才能、提升工作技能与人际关系,比投资所得的利息更多。这个建议特别适合初入社会三五年的青年,正逢职涯起步,最重要的是积累专业知识与建立职场关系,与其算计一些蝇头小利,倒不如将时间成本花在经营本业,工作表现好,升官加薪也不远了。

        内修:打响自我口碑

        人脉理财,需要真才实学相辅相成,指的是专业知识与敬业态度。在工作上肯下苦工是第一步,博得客户、上司、同事的信任,先有工作表现为基础,人脉的加分效果才明显。

        27岁的杨庆,前一份工作是精品公关公司的专员,如今,则是国内某知名钟表代理公司的公关经理。当初尚未正式上班,公司就送来一支市价20万的名表当作员工福利。不少人欣羡她能得到这个好职位,杨庆则说获得职涯攀升的机会连自己都觉得意外,因为是老板主动找上她的。

        原来现在的老板曾经是她的客户,认同杨庆的办事能力;当底下有缺,便将她列为候选人之一。而之所以被公司选中,“后来我才知道,老板曾问过几位媒体记者的意见,最后选了我。”由于她与媒体接洽时,会针对不同属性的媒体提供多元的新闻角度,这份努力让记者肯定其专业,若有人问起杨庆的工作能力,想必多是美言。往往就是因为共事的好印象,就算没有刻意经营关系,无形之中也帮你牵起好人脉,因此实力与人脉的养成不能偏废。

     真诚付出,心薪相印

        “人脉理财法”并不适合急欲一步登天的人,关系是一种长期投资,要细火慢炖,谁也算不准它在何时才开花结果,甚至要有心理准备,不一定有职位、薪资等实质回馈。

        人脉的回馈是以各种形式展现在你的生涯中。结识优秀的人就像李雨所说,听他们讲话都有收获!当你面对人生关卡、遭遇困境之际,往往能从好的人脉那儿得到指引和帮助,他们或许无法在事业上给予直接帮助(通常若你值得信任,他们必会拔刀相助),但有时一句话就让你受益无穷。

        而最会经营人脉者都不约而同地透露:与人结交,真心为贵。美国知名企业家与激发潜能大师博恩崔西(Brain Tracy)指导学员销售成功术时,最常挂在嘴边的就是“真诚地关怀你的顾客”。他说:“你越关怀你的顾客,他们就越有兴趣跟你做生意,一旦客户认定你是真心关怀他的处境,不论销售的细节或竞争者如何,他都会向你购买。”做成生意只是结果,崔西教导的重点是以真诚赢得人心。

    posted @ 2007-03-09 16:58 CowNew开源团队 阅读(377) | 评论 (0)编辑 收藏

    这是今天早晨我和一个网友关于eclipse调试原理的聊天记录,希望对大家有帮助:
    小鱼 说:
    你说了解JAVA的编译机制和熟练使用调试,最好的方法是不是去阅读eclipse的源代码啊
    杨中科 说:
    编译机制?要了解编译机制的话最先肯定要把编译原理搞清楚呀,eclipse本身是不负责编译java代码的,它是委托给JDK去编译的,因此要了解java的编译机制肯定要去阅读jdk的源码的
    杨中科 说:
    不过jdk的编译器部分的源码好像没有开放
    杨中科 说:
    使用调试也不用去看源码,功能很简单的
    小鱼 说:
    是啊,我觉得eclipse的调试很有用啊,尤其是你以前讲过的那个jsp的调试,学问很深啊
    杨中科 说:
    原理上并不难,因为eclipse是把调试请求通过jpda协议发给jdk来完成的,eclipse本身不提供java代码的编译和调试机制
    小鱼 说:
    这就是实时监测虚拟机的运行状态吧
    杨中科 说:
    不过读懂了eclipse的java调试部分的代码你就也可以写出一个java的调试器出来
    小鱼 说:
    断点就是给程序一个中断是吧?
    小鱼 说:
    是的
    杨中科 说:
    不是实时检测,是一个请求、应答的模式
    杨中科 说:
    比如我们在java的编译器的第五行放了一个断点,那么代码调试起来以后,eclipse就告诉运行环境“请在第五行停下来”,那么运行环境就会在第五行停下来。然后你想看看i这个变量的值,eclipse就会向运行环境请求“请告诉我i等于多少”,然后运行环境就将i的值告诉eclipse,eclipse就将这个值显示给你。原理非常简单
    小鱼 说:
    也就是程序挂起吧?
    杨中科 说:
    eclipse只是充当了一个介绍人的角色
    杨中科 说:
    不明白程序挂起具体指的什么,不过应该就是你理解的意思
    小鱼 说:
    也是,一个和用户直接打交道的UI

    杨中科 说:

    http://www.blogjava.net/huanzhugege/

     

    posted @ 2007-03-07 09:13 CowNew开源团队 阅读(2521) | 评论 (1)编辑 收藏

       在开发过程中我发现终端屏幕频繁的刷新,看上去闪的厉害。使用截包工具(我用的是EtherDetect Packet Sniffer,在Sniffer单机端口数据的时候比Sniffer Pro易用)分析发现,每次更新一个子窗口的时候竟然整个屏幕都被刷新了,数据量非常大。为了发现问题,我编写了下面的测试程序:
    from ACursesEX import *
    import curses

    def main():
        mainwin = curses.newwin(15,50,0,0)
        mainwin.box()
       
        mainwin.addstr(0,0,"主窗口")
        mainwin.refresh()
       
        cwin = curses.newwin(5,20,2,2)
        cwin.addstr(1,1,"子窗口")
        cwin.box()
        cwin.refresh()
        while(True):
            ch = cwin.getch()
            cwin.clear()
            cwin.addch(2,1,ch)
            cwin.touchwin()
            cwin.refresh()
           
      
    try:
        initapp()
        try:       
            main()
        except:       
            traceback.print_exc()
    finally:
        endapp()

    经测试每一次按键的时候屏幕的数据都刷新一次,经过尝试发现把cwin.clear()改成cwin.erase()就不会出现这种问题了。查看curses的API说明才发现自己犯了一个大错误:
    clear( ) :
    Like erase(), but also causes the whole window to be repainted upon next call to refresh().

       也就是说erase只会使子窗口刷新,而clear会导致整个窗口刷新。
    看来还是自己太粗心了!

     

    posted @ 2007-03-06 16:32 CowNew开源团队 阅读(327) | 评论 (0)编辑 收藏

     分页在任何系统中都是非常头疼的事情,有的数据库在语法上支持分页,而有的数据库则需要使用可滚动游标来实现,并且在不支持可滚动游标的系统上只能使用单向游标逐步接近要取得的数据。
     Hibernate提供了一个支持跨系统的分页机制,这样无论底层是什么样的数据库都能用统一的接口进行分页操作。比如下面的代码就是从第500条开始取出100条记录:
    Query q = session.createQuery("from FooBar as f");
    q.setFirstResult(500);
    q.setMaxResults(100);
    List l = q.list();
    那么Hibernate底层如何实现分页的呢?Hibernate根据Query拼装SQL语句的地方是在org.hibernate.loader.Loader类的prepareQueryStatement方法中,对分页支持的代码在这一段中可以发现:
    if (useLimit)
    {
    sql = dialect.getLimitString(
         sql.trim(), //use of trim() here is ugly?
         useOffset ? getFirstRow(selection) : 0,
         getMaxOrLimit(selection, dialect)
        );
     }
     此处调用Dialect的getLimitString方法来得到不同平台的分页语句。
    在MySQLDialect中是如下实现getLimitString方法的:
    public String getLimitString(String sql, boolean hasOffset)
    {
    return new StringBuffer( sql.length()+20 )
    .append(sql)
    .append( hasOffset ? " limit ?, ?" : " limit ?")
    .toString();
    }
     这是MySQL的专用分页语句,再来看Oracle9Dialect:
     public String getLimitString(String sql, boolean hasOffset) {
      
      sql = sql.trim();
      boolean isForUpdate = false;
      if ( sql.toLowerCase().endsWith(" for update") ) {
       sql = sql.substring( 0, sql.length()-11 );
       isForUpdate = true;
      }
      
      StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
      if (hasOffset) {
       pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
      }
      else {
       pagingSelect.append("select * from ( ");
      }
      pagingSelect.append(sql);
      if (hasOffset) {
       pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
      }
      else {
       pagingSelect.append(" ) where rownum <= ?");
      }

      if ( isForUpdate ) {
       pagingSelect.append( " for update" );
      }
      
      return pagingSelect.toString();
     } 
    Oracle采用嵌套3层的查询语句结合rownum来实现分页,这在Oracle上是最好的方式,因为如果只是一层或者两层的查询语句的rownum不能支持order by。
    此外Interbase,PostgreSQL,HSQL等也在语法级别上支持分页,具体实现可以查看相应的Dialect实现。如果数据库不支持分页的SQL语句,那么如果数据库支持可滚动游标,那么Hibernate就会采使用ResultSet的absolute方法直接移到查询起点;否则使用循环语句,通过rs.next一步步移动到要查询的数据处:
    final int firstRow = getFirstRow( selection );
    if ( firstRow != 0 )
    {
    if ( getFactory().getSettings().isScrollableResultSetsEnabled() )
    {
    // we can go straight to the first required row
    rs.absolute( firstRow );
    }
    else
    {
    // we need to step through the rows one row at a time (slow)
    for ( int m = 0; m < firstRow; m++ ) rs.next();
    }
    }

    可见使用Hibernate,在进行查询分页的操作上,是具有非常大的灵活性,Hibernate会首先尝试用特定数据库的分页sql,如果没用,再尝试Scrollable,如果不支持Scrollable再采用rset.next()移动的办法。这样既兼顾了查询分页的性能,同时又保证了代码在不同的数据库之间的可移植性。

    posted @ 2007-03-06 09:22 CowNew开源团队 阅读(673) | 评论 (0)编辑 收藏

          当使用多个资源合作解决一个问题的时候,必须使这些资源在一个事务中进行合作。为了实现这一目的,将事务分为两个阶段进行:
          第一阶段开始时,向此事务涉及到的全部资源发送提交前信息。此时,事务涉及到的资源还有最后一次机会来回滚事务。如果任意一个资源决定回滚事务,那么整个事务将被取消。否则,事务会被提交。
    第二阶段只是在第一阶段没有回滚时才会发生。在这个阶段,所有的能被定位和单独控制的资源都将真正的更新。
          事务被分割成两个阶段来完成,这被称为两阶段提交协议。如果程序在同一个操作中需要访问多种资源,您就要使用两阶段提交事务。例如,如果从 JMS 队列中删除一个消息,并且随后更新数据库中基于这条消息的纪录,这时,要保证这两个操作的原子性。不应该出现一条消息已经从队列中被删除,而系统没有更新与此消息相关的数据库中的纪录的情况。可以通过应用程序的代码在数据库更新失败的时候 "撤销"对队列的操作。但是这样做并不还,因为当程序在执行“撤销”操作的过程中服务器突然崩溃的话就会导致数据出现不一致。作为替代的方式,应该使用两阶段提交事务。
    posted @ 2007-03-06 09:20 CowNew开源团队 阅读(360) | 评论 (0)编辑 收藏

    out of the box:“The following apply to SCO 3 only; Python builds out of the box on SCO 5。”(源自:http://svn.python.org/projects/python/trunk/README
    解释:
    out-of-the-box具有“创造性的,独特性,思维不合常规”的意思,但在计算机术语里又可以指“从盒子里拿出来直接可以使用的,也就是即开即用”的意思。

    因此上边那句的翻译是:下面所说的只适用于SCO3;在SCO 5中Python已经构建好了。

    posted @ 2007-03-02 16:47 CowNew开源团队 阅读(288) | 评论 (0)编辑 收藏

    作者:Phillip J. Eby.
    翻译:ShiningRay @ NirvanaStudio
    原文地址:[[http://dirtsimple.org/2004/12/python-is-not-java.html][1]][1]

    我最近正在看一个基于wxPython的GUI应用程序,大概45.5KLOC的样子,但我没有计算它用到的库的大小(如Twisted)。代码是由那些对Python相对生疏的Java的开发者写的,所以程序有很严重的性能问题(如三十秒的启动时间)。我在检查代码的时候发现他们写了很多对Java有意义但是对Python却很恐怖的东西。并不是因为“Python比Java慢”,而是因为在Python中有更方便的方法去完成同样的目标,甚至在Java中不可能的事情。

    所以,可悲的事就是这些可怜人事倍功半,产生了很多很多不需要写的代码,从而比相应合乎Python习惯的写法慢得多得多。我们来看一些例子:

    * 在Java中一个静态的方法(static)不能翻译成一个Python的类方法(classmethod)。哦,当然,多多少少他最终产生类似的效果,但类方法的目的实际上是做了一些通常在Java中不可能的事(如继承一个非默认的构造函数)。Java静态方法的习惯翻译通常是一个模块级函数,而不是一个类方法或静态方法(staticmetho)。(同时静态封闭(final)字段应该翻译成模块级常量。)

    这并不是一个性能上的问题,但是一个Python程序员要用像这些类似Java习惯的代码的话,可能就会被在该输入Foo.someFunction时却要输入Foo.Foo.someMethod这种情况给惹毛了。但是请注意:调用一个类方法将会比调用一个静态方法和函数要多一部分额外的内存。

    啊,那些Foo.Bar.Baz也不是省油的。在Java中,这些点分割的名称是由编译器去查找的,所以运行时根本无所谓你有多少点。在Python中,每次运行时都要查找,所以每个点都要计算在内。(Python中一定要记住这点,“平铺比嵌套好”,尽管比起性能,他和“可读性”和“简单就是美”更靠近。)

    * 要用switch语句?Python翻译将是一个哈希表,不是一堆if-then语句。用一堆if-then在Java中也不是switch语句,如果有字符串参与了呢?他其实是一个哈希表。CPython字典实现用了性能最佳??在我们宇宙中目前所知道的?的哈希表的实现之一。你自己所写的代码也不会比这个再好了,除非你是Guido、Tim Peters和Raymond Hettinger的关门弟子。

    * XML不是答案。它也不是一个问题。要在正则表达式上解释Jamie Zawinski,“一些人,当遇到一个问题的时候,就想‘我知道,我要用XML’那这个时候,他们就有两个问题了。”

    和Java比这个一个不同的情况,因为比起Java代码,XML是轻巧而且有弹性的。但比起Python的代码来,XML就是一个船锚,一个绊脚石。在Python中,XML是用来做交换,而不是你的核心功能,因为你不需要这么做。在Java中,XML可能是你的大救星因为他让你实现了特定领域的语言并“不通过编码”提高了你的应用程序的适应性。在Java中,避免编码是一个很大的优势,因为编码意味着重新编译。但在Python中,更常见的是,写代码比写XML更方便简单。同时Python处理代码要远远比处理XML快。(不仅仅是这个,你必须书XML处理代码,同时Python自身就已经为你准备好了。)

    如果你是一个Java程序员,对于你是否要在你的Python核心应用中使用XML作为一部分,不要相信你的本能。如果你不是因为信息交互的原因去实现一个已经存在的XML标准或是建立某种导入、导出格式或者建立某种XML编辑器或处理工具,那么就不要这么做。一次也别。甚至连想都不要想。现在,扔掉那个XML模式把你的手解放吧!如果你的应用程序或者平台要被Python开发者使用,他们只会感谢你不要在他们的工作量中添加使用XML的负担。

    (这里唯一的例外是如果你的受众的的确确,确确实实需要XML,出于某种奇怪的理由。像,他们拒绝学习Python并只对你使用了XML而付钱给你,或者你打算给他们一个编辑XML的GUI,同时这个写XML的GUI呢是另一个人写的,同时你得到免费使用的权利。还有一些很少见的架构上的原因需要用到XML。相信我,他们不会出现在你的程序中。如果有疑问,对一个资深的Python开发员解释你的用例。或者,如果你脸皮厚的话,试试向一个Lisp程序解释你的程序为什么要用XML!)

    * Getter和Setter是坏蛋!坏蛋!魔鬼! Python对象不是Java Bean。不要写什么getter和setter,然后还把它们包装在“属性”里面。它直到你能证明你需要比一个简单访问复杂一点的功能时才有意义,否则,不要写getter和setter。它们是CPU时间的浪费,更要紧的是,它们还是程序员宝贵时间的极大浪费。不仅仅对于写代码和测试的人,对于那些要阅读和理解它们的人也是。

    在Java中,你必须使用getter和setter因为公共字段不允许你以后改变想法再去使用getter和setter。在Python中,这样做很傻,因为你可以以一个普通特性开始并可以在任何时间改变你的想法,而不用影响到这个类的任何客户。所以不要写getter和setter。

    * 代码重复在Java中常常是一个不得不要的魔鬼,你必须经常一遍一遍写同一个方法而只有一点点的变化(通常是因为静态类型约束)。在Python中这样做是没有必要的也是不值得的(除了极少数一些特定的场合需要内联一些要求性能的函数)。如果你发现自己一遍一遍在写同样的代码而且变化很少,你就需要去学一下闭包。他们并不是真的很可怕。

    这就是你要做的。你写了一个包含了函数的函数。这里内部的函数就是你要一遍遍写的函数的模版,但是在里面加入了针对不同情况的函数要使用变量。外部的函数需要刚刚提高的那种变量作为参数,并且将内部的函数作为结果返回。然后,每次你要写另一种略微不同的函数的时候,你只要调用这个外部的函数,并且把返回值赋给你要让“重复”函数出现的名字。现在,如果你需要改变这个工作方式,你只要改变一个地方:这个模版。

    在我所看过的应用程序/平台中,只有一个很微不足道的程序使用了这个技术之后可以去掉数百行重复代码。事实上,自从开发者使用了特别的样板文件来为这平台开发插件,这会节省很多很多第三方开发人员的代码,同时也使那些程序员要学习的东西简化了。

    这只是Java->Python思维方式转变的冰山一角而已,现在我可以让他转变成正确的而不用钻研这个程序的细节。本质上,如果你曾经用过一段时间Java,而且对Python比较陌生,不要太相信自己的本能。你的本能已经为Java调节,而不是Python。向后退一步,最重要的,不要写这么多代码了。

    要这样做,让自己觉得更加需要Python。假装好像Python是可以做任何你想做的魔棒,却让你无须动一个手指。问一下,“Python是怎样解决我的问题的?”还有“Python语言的哪个特点和我的问题最相似?”你绝对会惊讶于你需要的东西其实已经有了某种固定形式。事实上,这种现象实在是太普遍了,甚至在很有经验的Python程序员中也会出现,以至于Python社区中给这种现象起了个名字。我们称之为“GUIDO的时间机器”(GUIDO是美语中太空飞行工程师的意思),因为有时候看上去得到我们所需要的东西好像只有他知道的一种方法,但当我们自己知道了就不一样了。

    所以,如果你不能感到你在使用Python时至少比用Java要多出10倍的生产力,!(同时如果你还怀念你的Java IDE,考虑一下这种可能性:因为你写的Python程序比他所需要的要复杂得多)


    附录:(翻译自此篇文章的评论)

    确实,哈希表==字典。举个最简单的例子,从Python标准库中检出“pickle”和“copy”模块,这两个模块会从字典中查找类型并调用相应的函数。另一个有些诡异的例子是范型函数,我已经在最近的Blog中写了一下。

    关于闭包的例子,我这里给出一个很笨的资历。假设你要写很多这样的函数:

    def addOne(x): return x+1
    def addTwo(x): return x+2

    然后你可以这样写:

    def makeAdder(addend):
    ... def add_it(x): return x+addend
    ... return add_it

    并且这样使用:

    addOne = makeAdder(1)
    addTwo = makeAdder(2)

    这样就可以等同于原来的定义了。

    [1]: [http://dirtsimple.org/2004/12/python-is-not-java.html][2]
    [1]: http://dirtsimple.org/2004/12/python-is-not-java.html][1]
    [2]: http://dirtsimple.org/2004/12/python-is-not-java.html

    posted @ 2007-03-02 12:29 CowNew开源团队 阅读(369) | 评论 (0)编辑 收藏

    来到美国已经有一段时间了。我极其后悔当初的选择。一直都被西方媒体所蒙蔽欺骗,让我错误地以为美国是一个科技发达,工业成熟的现代化国家。怀着学习美国先进科技报效祖国的豪情,我翻山越岭来到了这个“强大”的国度。可是结果让我大失所望!我才发现我居然一直被蒙在鼓里这么多年!
      
      ------美国真的是个还未经开发的大农村!
      
       在中学时,老师们就教过工业越发展,环境就会遭到破坏。比如咱们的工业城市沈阳,到处都是大烟囱,到处都是大工厂。街道灰尘比较多。这都是工业化的象征啊!中国产品已经占领了美国市场。在美国到处都可见“中国制造”,就连厕所里放用过的厕纸的盒子都是来自中国的,这让我非常骄傲!可是美国呢?极少见到烟囱,偶尔见到小小的几个,还是别墅装饰用的,到处都是清澈见底的河流和湖泊,河边也没有造纸厂啊,炼钢厂啊什么的。简直没有一点工业化的影子!
      
       除了几个少数的大城市外,根本没有什么高楼大厦。我刚到美国时,飞机快降落,我看到纽约边上大片大片小平房,错以为到了柬埔寨。
      
      美国人的思想也比较单纯,完全是没有开化的表现。美国的高速公路四通八达,可是完全没有收费站!这么好的巨大商机居然白白浪费!我恨不得马上用水泥在这些路上筑几收费站,不出一个月,肯定可以在西海岸或者迈阿密买带花园的的海景别墅。还有,公路边随处可见宁静,还未开发的湖泊,go-vern-ment宁愿让水鸟随便栖息拉屎,也不会开发个湖景花园来大赚一笔。可见美国人毫无经济头脑。曾经有一个著名的美国经济学家曾经说过:“中国的经济学家里,真正可以称得上经济学家人,不会超过五个。”我简直要笑掉大牙了,连这么简单的赚钱机会都看不到的美国人,居然说中国没有经济学家?我看美国经济才是停留在原始社会。
      
      说到水泥和混凝土,我简直不敢相信美国几乎没有混凝土的建筑,他们的房子大部分都是木头和一些奇怪的材料建成的。用原始的木头做房子,看来洋人们的建筑水平还只停留在中国清朝以前啊!
      
      洋人们简直就是单纯无知到了极点,根本不惧怕和陌生说话,替陌生人做事。我刚到纽约的时候,在肯尼迪机场一个行李车要3美圆。我没有零钱,一个美国人看见我行李很多,就替我出了三美圆并把车推到我面前,我想起小学时老师说过人贩子一般都是用小恩小惠引诱并拐卖孩子和妇女的,我白了他一眼,拖着我的行李艰难的往相反的方向走了……后来我才发现这是美国人幼稚的表现,他们会随便把书包啊,电脑啊什么的放在图书馆门口,大树底下,完全不怕小偷,真是一点警惕感都没有;他们还随时会给你开门,随时会把车停下要“give me a ride”,随时会问需不需要帮助……我才不会上洋人的当呢,因为我知道“不能和陌生人说话。
      美国人开车的方式也很奇怪,马路上很多车,却听不见喇叭声。街道安静得不像街道,一点省会城市的热闹和人气都没有。最可怕的是,有一天晚上我和同学开车去另一个城市,忽然从路中间跑出几只马鹿来,同学眼疾手快刹了车才免了一场“马鹿的自杀性撞车事件”,据说这样的事经常发生,有时候一头鹿就可以毁了一辆车。美国go-vern-ment也不知道管管,连马鹿都管不好,还要整天张罗着要打伊朗,真不知道布什吃饱了在想什么。还不只马鹿呢,据说树林里还有熊和狐狸,野鸟和松鼠随时光顾厨房就更不用说了。美国人整天就和这些动物住在一起,根本就是原始社会。
      
      学校里的教授一点都架子都没有,完全没有学者尊贵的风范。D教授据说是美国著名的心理学家,可是课间休息的时候居然和学生在教室里大吃饼干,大侃《24》和《越狱》。一点学术的威严都没有,我简直失望死了。还有,刚上两星期课就要测验,第三个星期要交book review,要求读10多本书,一学期要两个paper。我说您都整到教授了还一天到晚这么认真负责干吗?也不知道去当个引进教授不干白拿钱。
      
      还有,美国人看点小病都要给自己制造麻烦。先得跟医生预约,看完病,医生给开药方。有些人还得咨询药师。买药得自己去超市买,不像咱们那块儿,看完病拿着医生龙飞凤舞的处方在医院直接买药就行了。可见美国医院又不会赚钱了,干吗告诉病人药名啊?在医院直接买,把药价翻个8倍10倍的,多好的生意不会做,可见资本主义市场经济真的不活啊,唉。
      
      美国人人人都开车,可是却连小摩托车都没见过,可见见识之少。学校里有一个非洲学生,为了方便和便宜就不知从哪里搞来一个女式小摩托车,在校园里开的时候,美国人都觉得他很“alien”,真是少见多怪。美国人要来到咱们国家,特别是南宁海口什么的,那还不被那汹涌的小摩托车大潮吓死。
      
      有时候对美国人的无知和愚蠢我完全失去了耐心。比如当他们知道中国有电视台和报社的时候,居然无知的问我:“中国有报纸啊?!”简直太岂有此理了,咱们中国不但有中文报纸,而且我们的报纸都是精心加工制作的,才不像美国报纸乱七八糟的舆论,把人头都搞晕了。
      
      还有我最受不了的就是,大部分美国人吃饭前都要做什么祷告,星期天都去什么礼拜,美圆上都印什么“In God We Trust”,美国人还天真的说:“上帝保佑美国”,完全是胡说八道嘛,上帝保佑美国,怎么还让美国如此落后,如此原始,还让美国人民如此单纯幼稚啊。所以我还是相信毛主席的“人定胜天”,我的祖国靠着类似的一些伟大观点,为这个地球创造了多少让人惊叹的奇迹啊!
      
      在美国的每一天,我都会深深的想起我的故乡和那些勤劳勇敢的中国人民。
    posted @ 2007-03-02 12:28 CowNew开源团队 阅读(899) | 评论 (3)编辑 收藏

    经常可以在论坛上可以看到这样的帖子:“小弟要学 Java 了,可是听说 Ruby 现在如日中天,要取代 Java 了,到底如何选择?”、“ Borland 要卖掉 Delphi 了,学 Delphi 还有没有前途?”、“学 Java 应该用 JBuilder 呢还是 Eclipse 呢?”……这样的帖子经常可以成为论坛中点击率回帖量最多的帖子。我曾经警告过自己不要去点击这种帖子,以表明自己有多么的“拽”,以示自己的“清高”,可是经常仍然忍不住诱惑而点进去。春秋时期的群儒论战在这里又得到了重现,每个人都以自己的亲身经历讲述到底那个语言更有前途,讲述为什么 C# 程序员没有 Java 程序员公司高,偶尔也有回帖曰:“语言不重要,思想才重要”,可是立即就被后边回帖的人反驳:“你说思想重要,那么要求你一个月时间用你不熟悉的一个语言开发一个系统出来,你还思想不思想?”,遂唾沫横飞……

    如果说语言之争是赤裸裸的话,那么框架之争就显得隐蔽多了:“ EJB3.0 要出来了, Hibernate 还有没有前途”、“做 Struts 的工资高还是做 WebWorks 的工资高”、“ Spring 万岁, EJB 去死!”。

    上面这些问题的答案是什么?我也不知道。

    我只知道——

    有个人由于工作的需要,学了一周的 C#, 然后就用 C# 开发出一个 ORMMaping 框架来;

    有一个 PB 用了八年的老手因为公司转用 Java 而失业 ;

    有人只学了一个月的 Java 就在应聘中击败了有多年开发 Java 开发经验的老手;

    一位有多个大型项目经验的人被问之什么是多态的时候,他回答“是化学里边的词汇吧”;

    有个人用了两个月的时间搭建出了一个企业开发平台,这个平台后来发展成为一个核心企业开发平台;

    有个用 Websphere Studio 开发过多个大型项目的高手在转用 JSP 的时候写出来的代码被人笑掉大牙;


    http://www.blogjava.net/huanzhugege/ 

    我还知道——

    任何语言都是由循环、顺序、分支结构组成的;

    Eclipse 是很多由 C++ 转过来的人员开发的,虽然 Eclipse 代码中还有很多 C++ 的影子,但是没有人说 Eclipse 写的不好;

    Java 中的 CachedRowSet C# 中叫脱机 DataSet ,在 Delphi 中叫 ClientDataSet

    JSF 是向 C# WebForm 学习的,而 IntraWeb 早在 WebForm 之前就实现了拖放式 Web 开发;

    EJB 中的声明式事务在 DCOM 中就有了;
    ...

    posted @ 2007-03-01 09:28 CowNew开源团队 阅读(1370) | 评论 (5)编辑 收藏

    现在有很多屏幕录制的工具,比如“屏幕录像专家”等,这些工具都是收费的,而且用起来很麻烦,所以我向大家推荐camstudio,这是一款免费的屏幕录制工具,大小才1M多,但是功能却非常的全,真是佩服他的作者了。
    网站地址:http://www.camstudio.org/
    下载地址:http://www.camstudio.org/CamStudio20.exe
    posted @ 2007-02-28 09:22 CowNew开源团队 阅读(1539) | 评论 (1)编辑 收藏

    Eclipse 使用系统内置的“ Text Editor ”做为文本编辑器,这个文本编辑器有一个长期存在的问题,那就是文本无法换行。虽然这个问题长期存在,而且解决起来并不困难,但是这却给人们带来不少麻烦。

    终于有人忍不住开发了一个扩展插件 WordWrap ,这个插件非常小,但是安装这个插件以后就可以轻松实现文本编辑器的换行功能了。

    【本文来自 Cownew 开源团队: http://www.cownew.com http://www.blogjava.net/huanzhuege

     

    安装方法:使用 Eclipse 的自动升级功能(【 Help 】→【 Sofeware updates 】→【 Find and Install 】→【 search for new features to install 】,点击【 New Remote Site 】按钮),在“ Name ”中填入“ wordwrap ”,“ URL ”中填入“ http://ahtik.com/eclipse-update/ ”,

    ew1.JPG
    然后点击【
    Finish 】安装即可。

    ew2.JPG
    安装完毕后在文本编辑器的右键菜单中就可以看到“
    Virtual Word Wrap ”了。

     ew3.JPG

    posted @ 2007-02-25 16:29 CowNew开源团队 阅读(4351) | 评论 (5)编辑 收藏

    对于“人脉”两个字,不少人有许多迷思,在你还没厘清人脉到底是什么之前,怎么谈得上去找到你的“人脉入口”?

    所以建议你,先仔细对照一下这张Check list,将你对人脉的迷思勾选出来,看看你到底是属于“铁齿型”、“软脚型”、“唬烂型”、“全灭型”中哪一类型的人,根据这4种不同类型,参考《Cheers》杂志采访到的8位业界精英说法,他们不但分享自己经营人脉的 方法及过程,还提供私房建议,让你走对方向,找到你的人脉入口。

    1、人脉好=攀关系,我才不做这种事。

    2、凡事不求人,我靠自己哪需要人脉?

    3、工作都忙不完了,哪有时间建立人脉?

    4、现在努力加强专业就好,建立人脉是以后的事。

    *以上归类为 铁齿型 *

    5、我脸皮薄怕被人拒绝,建立人脉太难。

    6、别人讲话我只有听的份,怎么建立人脉?

    7、生活=办公室+我家,去哪里建立人脉?

    8、周末只想睡大觉,别说人脉、连出门都懒!

    *以上归类为 软脚型 *

    9、有人脉=好办事,我做事最吃得开!

    10、有人脉,升迁就像坐电梯,没人脉,升迁就像爬楼梯!

    11、人脉要过滤,没利用价值的人,不用浪费时间!

    12、我认识许多大老板,人脉好得不得了!

    *以上归类为 唬烂型 *

    13、朋友有难,两肋插刀,我用血泪换人脉。

    14、别人都躲着我,人脉出现大危机。

    15、每次提出要求都石沉大海,人脉实在不可靠!

    *以上归类为 全灭型 *

    看看你是属于「铁齿型」、「软脚型」、「唬烂型」、「全灭型」中哪一类型的人
    铁齿型的你很有工作实力,做事有自己的一套,但是别忘了,现在是一个讲究团队工作的时代,单打独斗既不能拓展格局又不能持久,所以,适时地分享你的经验,或是帮助其它人,会对你事业上的提升有很大帮助

    软脚型的你比较内向、不善交际,但经营人脉并不是要你当花蝴蝶,其实你可以从当一个好的倾听者开始,建立别人对你的信赖感,而工作之外的时间,也可以参加跟自己嗜好有关的社团活动,例如登山社、旅行团、美术馆义工等等,增加认识朋友的机会,这将对你今后的发展起到重要作用。

    属于唬烂型的你,最好放下身段、脚踏实地经营自己的专业实力比较能走得远走得稳,不要整天计算周遭人的利用价值,这种功利心态真的很让人讨厌!不要忘了,你利用别人一次,人家不但会永远记得还会告诉别人,就算你认识的人再多,别人提到你的名字都嗤之以鼻,这样恶质的人脉不如没有。

    属于全灭型的你基本上人脉已经亮起红灯,你用错误的观念去经营人脉,不但危及自己的工作、信用扫地,甚至可能有触犯公司规定或犯法的可能,劝你及时煞车,重新检视自己对于人脉的定义。

    posted @ 2007-02-25 12:42 CowNew开源团队 阅读(255) | 评论 (0)编辑 收藏

    ISA环境,foxmail能收,但不能发邮件;而Outlook Express和Outlook都没有任何问题。

    首先我要确定是服务器的问题还是我这边客户端的问题,于是又试了其它几个邮箱,也是不能发送,而且出错问题是一样的,基本可以确定是我的机器的问题了。为了进一步明确我的判断,我又用telnet命令分别连接了实验室邮箱的25和110端口,发现25端口不能连接,其它邮箱也是如此。

         然后看看我的foxmail设置是否有问题,我到foxmail官方论坛去查阅了相关资料,发现最可能出错的地方就是在"属性"设置中没有选择"服务器验证",但我的情况是选择与否都还是不能发送。总之,按照资料基本把foxmail设置的问题排除了。

         由于我的系统是没有安装防火墙的,所以我没有怎么考虑防火墙的问题。接着查看机器的25端口(smtp协议所用端口),发现tcp 25端口没有打开,于是又想办法试图打开这个端口,但很快我发现自己的想法是错的,因为服务器使用25端口,而客户端却是在1024以上随机选择端口的,使用的根本不是25端口。

         那是什么原因呢?以"foxmail不能发送邮件"关键词在google上搜索,在众多资料中发现一篇提到安装"MacFee Antivirus"之后会把可能被蠕虫病毒利用传播的25端口关闭,而自己用的正是"MacFee Antivirus"的企业版,而解决的办法有两个:要么将上述功能选项关闭,要么将编辑这个选项,将foxmail.exe排除在关闭端口的程序之外。我两者都试了一下,均能发送邮件了。

    系统装有McAfee Desktop Firewall 8.0、McAfee VirusScan Enterprise +Anti-spyware Module 8.0、ewido anti-spyware 4.0。

    问题不在防火墙MDW和防御木马、间谍程序的ewido上,而是在防病毒的VirusScan。

    在Mcafee的VirusScan控制台中有一个“访问保护”,其中有一项“禁止大量发送邮件的蠕虫病毒发送邮件”,默认的是开启的,把这项功能取消就可以了。 

    如果不想取消这个功能,则编辑这个功能,在已排除的进程中添加foxmail.exe就行了。

    以前一直用Outlook Express收发邮件,而VirusScan默认排除了OE的进程,后来重装系统,换了foxmail,一直没有机会发邮件,所以也就一直没有发现问题症结之所在。

    posted @ 2007-02-25 10:07 CowNew开源团队 阅读(32072) | 评论 (22)编辑 收藏

      方案一:利用工作资源建立人脉关系
      这是上班族的一个特点,也是上班族的一个优势,学会充分利用在工作中积累的资源和建立的人脉关系进行创业,可以大大减少创业风险。《科学投资》采访过一位朋友,原来在北京一家大的电脑图像制作公司工作,在工作中与很多小的电脑图像公司、报社、杂志社、电视台、电视节目制作公司建立了关系,积累了人脉。时机成熟后,这位朋友辞去了原来的工作,自己成立了一个电脑图像工作室。因为相当于原来工作的延续,无缝衔接,这位朋友几乎没有冒任何风险,便踏上了成功之路。现在这位朋友的工作室生意很红火。但是在这方面要注意的是,不能将个人生意与单位生意搞混淆,将工作秩序搞颠倒,甚至只要是有利可图的生意就归自己,而无利可图或者亏本的生意就归单位,这样做不仅要冒道德上的风险,而且很有可能会受到法律的制裁。另外,要区分清楚主业、副业,不能因为自己的创业活动影响单位的工作。
      方案二:选择合适的合伙人进行创业
      有些上班族没有时间自己进行创业,但可以提供一定的资金,或者拥有一定的业务经验和业务渠道,这时候就可以寻找合作伙伴一起进行创业。与合作伙伴一起进行创业需要注意的事项是:责、权、利一定要分清楚,最好形成书面文字,有双方签字,有见证人,以免到时候空口无凭。更不能等到赚钱了再说。我们看到无数合作创业的伙伴,在公司没有赢利之前,双方都能够和谐相处、和和气气,一旦公司赚了钱,矛盾便开始出现,有时一发而不可收拾。这就是大多数合伙企业,开始热热闹闹,中间打打闹闹,最后一败涂地的原因。
      方案三:找准好的项目
      一位朋友在上海的一家台资企业工作,妻子在一家大型电器公司当推销员。这位朋友手头有一定积蓄,又不愿放在银行里吃息,因为银行利息太低(眼下已是负息)。从去年6月起,他瞅准时机,在上海吴淞码头开了一家拉面馆,后来连开了4家。现在这4家拉面馆每月能为他带来2万多元的收入,远超过其打工的薪水。这位朋友说,其实很简单,他看准了地方,出钱盘下店面,请了几个人来开店,设了一个店长,工资要高些,其他人按市场行情走,每月几百元外带吃住。他只要每个星期到店里走一趟,盘盘账。因为店小,账目很简单,无非是进货、出货。进货,就是这个星期买了多少钱的面粉、买了多少钱的牛肉、蔬菜;出货,就是这个星期消耗了多少面粉,消耗了多少钱的牛肉、蔬菜;卖了多少钱,将中间差价一算,刨除房租、水电、税费及人员工资,就是他赚的钱。既省心省力,又不花时间。类似这样的项目,非常适合想创业的上班族。关键是你要开动脑筋,时刻留心,四处留心。另外,就是该下手时就下手,不能犹犹豫豫。大家都在找机会,机会来了你不下手,一眨眼机会可能就被别人逮跑了。
      前不久,有台湾机构调查上班族最热衷的创业项目,一共有10个,分别是:摆地摊卖服装饰品,占20.81%;炸鸡排、咸酥鸡等小吃摊,占18.78%;咖啡店占16.63%;网络上开设店铺,占15.54%;便利商店,占15.32%;饮料冰品店,占14.15%;连锁加盟餐饮,占13.11%;语言补习班,占11.96%;升学补习班,占11.62%;瘦身美容用品或服务,占11.22%。这10个项目都有一个共同的特点,就是投资较少,另一个特点是管理相对简单,不需要创业者长年累月、耗时费力地盯在那里。
    posted @ 2007-02-20 14:37 CowNew开源团队 阅读(316) | 评论 (0)编辑 收藏

      有钱你可以请漂亮的女孩子一起去吃饭,唱歌跳舞

      有钱你可以开车带着女朋友去兜风,旅游
      有钱,你可以过上很体面的日子
      作为男人,你要是没钱,你还是个男人吗?
      男人们,努力挣钱吧,就是为了老婆,你也要做个有钱人.
     终于明白,为什么这么多小姑娘,哭着喊着要嫁给有钱人了,有钱是好呀!
           有钱你出门好打车,走出家门轻轻一摆手就成;没钱,呵呵,那您就做好准备挤公车吧,那出门可就不能想穿啥就穿啥,尤其记得不要穿白皮鞋哦,否则下了车也成黑的。
       有钱你出门看到喜欢的就能买下来,营业员乐得嘴都笑到耳朵根了,帮您包的漂漂亮亮,还来句“谢谢光临,下次我们有什么新品,我电话通知您”呵呵,全程享受VIP待遇。
        你没钱??呵,那可就对不起您喽,进店没人理你是小意思,搞的不好,在一件物品那里待久了,营业员还白你两眼。
        有钱,饿了随便找个餐厅就把吃饭的问题解决了,吃好了连碗碟都不用洗,桌子也不用擦,拍拍屁股走人!
       没有钱,为了要尽量省钱必须在家吃,呵呵,到菜场买菜,搞的一身鱼腥味。跑到家还要烧,又添不少油烟味,最后还要洗盘子啊,碟子啊,碗筷啊,呵呵,好好一双手就费了,用再多美家净也没有用!好了,这下就什么希望啊,前途啊,未来啊都没了!
        呵呵,有钱没钱就是不一样啊
    posted @ 2007-02-20 14:32 CowNew开源团队 阅读(231) | 评论 (0)编辑 收藏

    下面是 AOP 的一些基本概念

    aspect (方面):实现了 cross-cutting 功能,是针对方面的模块,是为题的不同关注点,我们可以将这些方面通过某种方式加入到核心关注点中。

    jointpoint (连接点):连接点是方面插入应用程序的地方,该点能被方法调用。

    advice (通知): advice 是我们关注点功能的实现,它通知程序新的行为。如在权限处理中, permission advice 包括权限控制的实现代码。

    pointcut (切入点): pointcut 可以指定把哪些 advice 应用到 jointpoint 上去、如何应用上去以及应用的位置。

    AOP 包括三个开发步骤:

    关注点分解:分解需求提取出横切关注点和一般关注点。把核心模块级关注点和系统级的横切关注点分离开来。就前面所提到的网上购物系统来说,可以分解出四个关注点:核心的订单处理、权限、日志和事务。

    关注点实现:各自独立的实现这些关注点。

    关注点的重新组合:在这一步里,通过创建一个模块单元来指定关注点重组的规则。重组过程被称为织入( Weaving )。以前边的网上购物系统来说,可以通过某种方式指定每个操作结束后需要记录日志、操作开始前要验证是否有权限、操作失败要事务回滚。

     

     

    下面是 AspectJ 实现日志记录的一个例子:

    public aspect AutoLog

    { 

    pointcut publicMethods() :

    execution(public * org.apache.cactus..*(..));

    pointcut logObjectCalls() :

    execution(* Logger.*(..));

    pointcut loggableCalls() :

    publicMethods() && ! logObjectCalls();

    before() : loggableCalls()

    {

    Logger.entry(thisJoinPoint.getSignature().toString());

    }

    after() : loggableCalls()

    {

    Logger.exit(thisJoinPoint.getSignature().toString());

    }

    }

    可以看到,这里边有很多 Java 中没有的关键字,比如 aspect pointcut 等。这些关键字都是 AspectJ 提供的,使用这些扩展我们可以用 AspectJ Java 类增加字段及方法,甚至使 Java 支持多继承。

     

     

    Spring 没有自己进行 AOP 技术的实现 , 它的主要实现技术来自于 AOP 联盟( AOPAlliance )。

    Spring AOP 中的术语不像 AspectJ 那样多,因而也更容易理解和学习。只要理解三个概念就可以, advice pointcut advisor

    advice 是要向别的模块内部不同的地方注入的代码

    pointcut 定义了需要注入 advice 的位置,通常是某个特定的类的一个 public 方法

    advisor pointcut advice 的装配器,是将 advice 注入主程序中预定义位置的代码

    posted @ 2007-02-20 00:50 CowNew开源团队 阅读(202) | 评论 (0)编辑 收藏

    为了巩固 CGLib 的知识,下面我们实现一个稍微复杂一点的例子。

    例、请实现一个拦截器,使其能够检测一个 JavaBean 的哪些字段改变了。

    1 )首先定义一个 JavaBean

    public class PersonInfo

    {

         private String name;

     

         private String email;

     

         private int age;

     

         private String address;

     

         public String getEmail()

         {

             return email;

         }

     

         public void setEmail(String email)

         {

             this.email = email;

         }

     

         public String getName()

         {

             return name;

         }

     

         public void setName(String name)

         {

             this.name = name;

         }

     

         public String getAddress()

         {

             return address;

         }

     

         public void setAddress(String address)

         {

             this.address = address;

         }

     

         public int getAge()

         {

             return age;

         }

     

         public void setAge(int age)

         {

             this.age = age;

         }

    }

    2 )定义一个 MethodInterceptor ,这一步是最关键的

    import java.lang.reflect.Method;

    import java.util.Collections;

    import java.util.HashSet;

    import java.util.Set;

     

    import net.sf.cglib.proxy.MethodInterceptor;

    import net.sf.cglib.proxy.MethodProxy;

     

    public class JavaBeanDataChangeInterceptor implements MethodInterceptor

    {

         private static final String SET = "set";

     

         private Set changedPropSet;

     

         public JavaBeanDataChangeInterceptor()

         {

             changedPropSet = new HashSet();

         }

     

         public Object intercept(Object obj, Method method, Object[] args,

                  MethodProxy proxy) throws Throwable

         {

             String name = method.getName();

             if (name.startsWith(SET))

             {

                  String s = name.substring(SET.length());

                  changedPropSet.add(s);

             }

             return proxy.invokeSuper(obj, args);

         }

     

         public Set getChangedPropSet()

         {

             return Collections.unmodifiableSet(changedPropSet);

         }

     

         public void reset()

         {

             changedPropSet.clear();

         }

    }

    定义一个集合 changedPropSet 用来存放修改了的字段名,增加了一个方法 reset 用来清空此集合,增加了一个 getChangedPropSet 方法用来供外界得到修改了的字段,为了防止调用者对 changedPropSet 做修改,因此我们采用 Collections.unmodifiableSet 对返回的集合进行不可修改的修饰。

    intercept 方法中,我们判断如果被调用的方法以 set 开头,则把此字段名放入 changedPropSet 集合中。

    3 )定义剖析用工具类。

    import net.sf.cglib.proxy.Callback;

    import net.sf.cglib.proxy.Factory;

     

    public class JavaBeanInterceptorUtils

    {

         public static JavaBeanDataChangeInterceptor getInterceptor(

                  Object obj)

         {

             if (!(obj instanceof Factory))

             {

                  return null;

             }

             Factory f = (Factory) obj;

             Callback[] callBacks = f.getCallbacks();

             for (int i = 0, n = callBacks.length; i < n; i++)

             {

                  Callback callBack = callBacks[i];

                  if (callBack instanceof JavaBeanDataChangeInterceptor)

                  {

                       return (JavaBeanDataChangeInterceptor) callBack;

                  }

             }

             return null;

         }

    }

    这个 JavaBeanInterceptorUtils 只有一个方法 getInterceptor ,这个方法用于从一个被 CGLib 代理的 JavaBean 中取出拦截器 JavaBeanDataChangeInterceptor

    前边提到了, CGLib 实现拦截的方式就是生成被拦截类的子类,这个子类实现了 net.sf.cglib.proxy.Factory 接口,这个接口中有一个非常重要的方法 getCallbacks() ,通过这个方法我们可以得到所有的拦截器

    4 主程序

    public class MainApp

    {

         public static void main(String[] args)

         {

             Enhancer enhancer = new Enhancer();

             enhancer.setSuperclass(PersonInfo.class);

             enhancer.setCallback(new JavaBeanDataChangeInterceptor());

     

             PersonInfo info = (PersonInfo) enhancer.create();

             // 对生成的 JavaBean 做一些初始化

             info.setAddress(" 地址 1");

             info.setAge(21);

             info.setName("tom");

     

             // 得到拦截器

             JavaBeanDataChangeInterceptor interceptor = JavaBeanInterceptorUtils

                       .getInterceptor(info);

             // 复位修改字段记录集合

             interceptor.reset();

     

             // JavaBean 做一些修改

             editPersonInf(info);

     

             // 得到修改了的字段

             Iterator it = interceptor.getChangedPropSet().iterator();

             while (it.hasNext())

             {

                  System.out.println(it.next());

             }

         }

     

         private static void editPersonInf(PersonInfo info)

         {

             info.setName("Jim");

             info.setAddress("N.Y Street");

         }

    }   

    运行结果:

    Address

    Name

     

    这个“变化字段拦截器”是有一定实际意义的,比如可以用来实现“只保存修改了的字段以提高效率”等功能

     

    很多资料中都说如果要使用 JDK Proxy ,被代理的对象的类必须要实现接口,这种说法是不严谨的。从上边的例子我们可以看出,正确的说法应该是:如果要使用 JDK Proxy ,那么我们要通过代理调用的方法必须定义在一个接口中。“面向接口编程而不是面向实现编程”是 OOP 开发中的一条基本原则,因此这种限制并不会对我们的开发造成障碍。

    posted @ 2007-02-20 00:50 CowNew开源团队 阅读(346) | 评论 (0)编辑 收藏

         摘要: 服务器通过配置文件将符合特定格式的 URL 同 Servlet 建立对应关系,当一个客户端请求到达服务器的时候,服务器就会分析其 URL 格式并派发给合适的 Servlet 处理,然后将 Servlet 处理完成的结果返回给客户。 与 ASP 、 ...  阅读全文
    posted @ 2007-02-19 21:45 CowNew开源团队 阅读(785) | 评论 (0)编辑 收藏

    公司安排偶做终端字符界面库,这是我半个月做出来的东西,呵呵,挺有意思,与大家分享。
    p3.JPG

    这是用这些控件搭建出来的程序界面,供大家把玩
    p1.JPGp2.JPG
    posted @ 2007-02-13 17:37 CowNew开源团队 阅读(541) | 评论 (2)编辑 收藏

    对象图
    XStream支持对象图,也就是“反序列化”一个对象的时候将会保持原来的对象引用关系,这其中包括循环引用关系。 我们可以指定XStream是使用XPath还是IDs来实现对象引用的这种处理方式,指定的方式就是调用XStream的setMode方法,此方法有XStream.XPATH_REFERENCES、XStream.ID_REFERENCES、XStream.NO_REFERENCES三个选项。其意义分别如下:
    XStream.XPATH_REFERENCES:这是默认值。这个选项指定XStream使用XPath引用方式处理重复引用。
    XStream.ID_REFERENCES:这个选项指定XStream使用ID引用方式处理重复引用。当使用手写XML的时候,这种方式可能更好用一些。 
    XStream.NO_REFERENCES:这个选项指定XStream不支持图引用,将对象结构当做树状处理。重复的引用将会被认为是两个独立的对象,而循环引用将会导致一个异常。这种方式速度会更快一些,并且相对于前两者来说占用更少的内存。
    自定义转换器
    XStream对String, Date, int, boolean等基本类型以及Map, List, Set, Properties等集合类型提供了转换器,因此这些类型可以轻松的实现序列化和反序列化。如果您使用的数据类型不被XStream支持,那么就需要自定义数据转换器。自定义转换器要实现com.thoughtworks.xstream.converters.Converter接口,这个接口定义了如下三个方法:
    boolean canConvert(Class type);
    void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context);
    Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context);
    这三个方法分别表示:type这个类型的数据此转换器是否有能力转换;将对象进行编组(marshal)为XML格式;将XML格式反编组(unmarshal)为对象。
    我们通常无需直接实现该接口,而是继承com.thoughtworks.xstream.converters.MarshallingContext.AbstractBasicConverter抽象类,然后覆盖:
    protected String toString(Object obj)
    protected Object fromString(String str);
    两个方法即可。可以参考com.thoughtworks.xstream.converters.extended.SqlTimestampConverter的实现代码。
    转换器开发完毕以后调用XStream类的public void registerConverter(Converter converter)方法注册转换器。
    posted @ 2007-02-13 09:38 CowNew开源团队 阅读(819) | 评论 (0)编辑 收藏

    为什么使用数据源
    在帐套配置项中,我们使用数据源来表示对应的数据库连接。使用数据源有两个好处:对开发人员屏蔽数据库细节,只要通过JNDI取得数据源就可以了,无需关心数据库连接是如何建立的;数据源通常都提供了数据库连接池的功能。
    数据库连接是一种关键的有限的昂贵的资源,而且数据库连接的建立和关闭也是很耗费系统资源的。在传统的两层C/S架构中,一个客户端对应一个数据库连接,在用户活动期间就独占此连接;而在分布式系统中,数据库连接的建立与关闭是异常频繁的,因此数据库连接的对系统的性能影响更是明显。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
    数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
    JDBC3.0规范中规定了如下的接口和类来实现数据库连接池:
    javax.sql.ConnectionEvent:连接事件
    javax.sql.ConnectionPoolDataSource:连接池数据源
    javax.sql.PooledConnection:被池化的连接
    javax.sql.ConnectionEventListener:连接事件监听接口
    上边这些接口和类是对数据库连接池内部实现的规定,对于使用者来说是透明的。数据库连接池的使用者一般只和DataSource接口直接打交道,通过这个接口获得数据库连接,其主要方法为:
    Connection getConnection():得到一个数据库连接
    Connection getConnection(String userName,String password):得到一个数据库连接
    java.io.PrintWriter getLogWriter():获得Log Writer的对象
    void setLogWriter(java.io.PrintWriter out):设置Log Writer
    void setLoginTimeout(int seconds):设置数据源尝试连接数据库的最大时间
    int getLoginTimeout():获得数据源尝试连接数据库的最大时间
    开源社区中有很多数据库连接池的实现,比如PoolMan等,使用这些数据库连接池包可以保证跨应用服务器的移植。不过在本案例系统中,我们使用应用服务器的数据源功能提供的数据库连接池。数据源在不同的服务器中有不同的配置方式,下面介绍Tomcat中数据源的配置。
    打开%TOMCAT_HOME%\conf\server.xml,在</Context>和</host>前添加如下配置文件项:
    <Context docBase="CowNewPIS" path="/CowNewPIS"      reloadable="true">
    <Resource type="javax.sql.DataSource"
          auth="Container" name="jdbc/PISMSSQL_Dev" />
    <ResourceParams name="jdbc/PISMSSQL_Dev">
    <parameter>
    <name>maxWait</name>
    <value>5000</value>
    </parameter>
    <parameter>
    <name>maxActive</name>
    <value>4</value>
    </parameter>
    <parameter>
    <name>password</name>
    <value></value>
    </parameter>
    <parameter>
    <name>url</name>
    <value>
    jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106
    </value>
    </parameter>
    <parameter>
    <name>driverClassName</name>
    <value>
    com.microsoft.jdbc.sqlserver.SQLServerDriver
        </value>
    </parameter>
    <parameter>
    <name>maxIdle</name>
    <value>2</value>
    </parameter>
    <parameter>
    <name>username</name>
    <value>sa</value>
    </parameter>
    </ResourceParams>
    </Context>
     
    在配置的时候,要指定数据库的JDBC驱动、数据库连接URL等。数据源配置完毕,重启服务器。编写一个测试客户端:
    Context ctx=null;
    Connection conn=null;
    try
    {
    ctx=new InitialContext();
    DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/PISMSSQL_Dev");
    conn=ds.getConnection();
    }
    finally
    {
    if(conn!=null)
    conn.close();
    if(ctx!=null)
    ctx.close();
    }

    Tomcat启动的时候会将Server.xml中的数据源配置绑定到JNDI中,我们可以在应用服务器启动的时候用代码来代替Tomcat完成绑定:
    BasicDataSource bdds = new BasicDataSource();
    //设置数据库驱动
    bdds.setDriverClassName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
    //设置JDBC的URL
    bdds.setUrl("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106");
    bdds.setUsername("sa");
    //设置连接池初始大小
    bdds.setInitialSize(2);     
    //JNDI配置
    Map env = new Hashtable();
    env.put("java.naming.factory.initial",
    "org.apache.naming.java.javaURLContextFactory");
    InitialContext ctx=new InitialContext(env);     
    //数据源绑定到JNDI
    ctx.bind("jdbc/PISMSSQL_Dev",bdds);

    这样我们可以把数据源的配置文件移到ServerConfig.xml中,增加类似如下的配置:
    <DataSources>
    <DataSource
    name=”jdbc/PISMSSQL_Dev” driverClassName=”com.microsoft.jdbc.sqlserver.SQLServerDriver”
    url=”jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106”
    userName=”sa”
    >
    </DataSource>
    </DataSources>
    在应用服务器启动的时候,到ServerConfig.xml中读取数据源配置完成绑定。这种方式一是减少了实施人员配置文件的工作量,服务端的任何配置都可以在这个配置文件中完成;二是使得系统在不同服务器之间移植变得更加容易。

    posted @ 2007-02-13 09:37 CowNew开源团队 阅读(344) | 评论 (0)编辑 收藏

    BeanUtils
    BeanUtils是Apache-Commons项目提供的另一个非常方便的类库,通过这个类库能够更方便的使用反射。最常用的类是BeanUtils(org.apache.commons.beanutils包中),使用这个类能通过名字访问一个Bean中的某个属性。
    通过BeanUtils.getProperty(person,”age”)能得到person的age属性。此方法还支持内嵌对象,比如BeanUtils.getProperty(person,”manager.name”)就能得到person的manager属性的name属性。还支持List和Map类型的属性,如下面的语法即可取得Order的顾客列表中第一个顾客的名字BeanUtils.getProperty(orderBean, "customers[1].name")。 使用BeanUtils.setProperty方法则可以设置javaBean的属性值。
    ConstructorUtils提供了调用构造函数的方法,使用public static Object invokeConstructor(Class klass, Object arg)可以直接调用某个类的构造函数。
    MethodUtils提供了调用bean方法的方法,使用MethodUtils.invokeMethod(bean, methodName, parameter);可以直接调用某个类的某个方法。
    PropertyUtils提供了更详细的属性访问方法,使用public static Class getPropertyType(Object bean, String name)获取属性的Class类型。
    UserInfo userInfo = (UserInfo) ConstructorUtils.invokeConstructor(
        UserInfo.class, new Object[] {});
    PersonInfo personInfo = (PersonInfo) ConstructorUtils
        .invokeConstructor(PersonInfo.class, new Object[] {});
    BeanUtils.setProperty(personInfo, "age", new Integer(20));
    BeanUtils.setProperty(personInfo, "name", "Tom");
    BeanUtils.setProperty(userInfo, "number", "admin");
      BeanUtils.setProperty(userInfo, "person", personInfo);
    System.out.println(BeanUtils.getProperty(userInfo, "person.name"));
    BeanUtils.setProperty(userInfo, "person.name","xdx");
    System.out.println(BeanUtils.getProperty(userInfo, "person.name"));
    System.out.println(PropertyUtils.getPropertyType(userInfo,"person"));
    运行结果:
    Tom
    xdx
    class com.cownew.PIS.basedata.common.PersonInfo
    posted @ 2007-02-05 12:49 CowNew开源团队 阅读(764) | 评论 (1)编辑 收藏

         摘要: LDBC 支持的语法 ( 1 ) Insert 语句 插入单行数据: INSERT INTO tableName [ (columnName [,...] ) ...  阅读全文
    posted @ 2007-02-05 12:44 CowNew开源团队 阅读(570) | 评论 (0)编辑 收藏

    虽然使用正则表达式能很好的进行字符串的解析、提取、替换,但是对于一些简单的应用,使用 String 类提供的一些方法就可以很好的完成,最突出的就是 split 方法。

    split 方法能够很方便的将字符串按照一定的规则拆分开。

    比如对于下面的字符串:

    Tom,Jane,Tony,Elva,Gigi

    只要调用如下的代码就可以将各个名字提取出来:

    String value = "Tom,Jane,Tony,Elva,Gigi";

    String[] names = value.split(",");

    for(int i=0,n=names.length;i<n;i++)

    {

         System.out.println(names[i]);

    }

    运行结果:

    Tom

    Jane

    Tony

    Elva

    Gigi

     

    看到这个运行结果,很多人都认为 split 方法就是按照给定的字符串对字符串进行拆分,知道碰到了下面的问题。

    有一个字符串:中国 . 北京 . 海淀 . 学院路。请解析此字符串,并打印输出“中国 北京 海淀 学院路 ”。

    于是写代码如下:

    String value = " 中国 . 北京 . 海淀 . 学院路 ";

    String[] names = value.split(".");

    for(int i=0,n=names.length;i<n;i++)

    {

         System.out.print(names[i]+" ");

    }

    运行结果:

     

    对,没看错!没有任何输出!

    让我们来看看 split 方法的方法签名吧:

    public String[] split(String regex)

    这里的参数的名称是 regex ,也就是 Regular Expression (正则表达式)。这个参数并不是一个简单的分割用的字符,而是一个正则表达式,看了 split 方法的实现代码就更坚定了我们的信心:

    public String[] split(String regex, int limit) {

         return Pattern.compile(regex).split(this, limit);

    }

    split 的实现直接调用的 Matcher 类的 split 的方法。读者已经知道,“ . ”在正则表达式中有特殊的含义,因此我们使用的时候必须进行转义。

    修改代码如下:

    private static void split2()

    {

         String value = " 中国 . 北京 . 海淀 . 学院路 ";

         String[] names = value.split("\\.");

         for(int i=0,n=names.length;i<n;i++)

         {

             System.out.print(names[i]+" ");

         }

    }

    运行结果

    中国 北京 海淀 学院路

    posted @ 2007-01-20 23:38 CowNew开源团队 阅读(2831) | 评论 (9)编辑 收藏

    CowNewSQL的扩展:
    要编写对新的数据库的支持必须首先开发翻译器,翻译器必须实现IMethodTranslator接口,不过一般只要从BaseMethodTranslator派生即可,BaseMethodTranslator类已经提供了标准的SQL的翻译。因为方法的翻译在BaseMethodTranslator中实现时是独立到一个方法翻译器中的,所以派生类要通过getMethodTranslator方法提供方法翻译器,方法翻译器要实现IMethodTranslator接口,一般从BaseMethodTranslator派生即可。翻译器开发完毕,调用DialectManager类的registerTranslator方法将翻译器注册到系统中。
    CowNewSQL的编译
    CowNewSQL使用JDK1.5语法编写的,因此如果要在JDK1.4的平台上运行必须使用RetroTranslator将二进制代码编织成在JDK1.4下能运行的二进制代码。RetroTranslator的使用非常简单,在命令行敲入如下指令即可完成代码编织:
    java -jar retrotranslator-transformer-1.0.7.jar -srcjar F:\资料\写书\ZDisk\lib\common\cownewSQLjdk5.jar -destjar F:\资料\写书\ZDisk\lib\common\cownewSQLjdk4.jar
    RetroTranslator对JDK1.5中枚举等类型的支持是通过RetroTranslator的运行时包来实现的,因此运行时还需要将RetroTranslator的运行时包retrotranslator-runtime-***.jar加入到类路径中。
    posted @ 2007-01-20 23:36 CowNew开源团队 阅读(2104) | 评论 (0)编辑 收藏

    原文:
    http://community.csdn.net/Expert/topic/5294/5294255.xml?temp=.9256861

    汇总我的观点:
    1、大家应该理性的看待这个问题,尽管从短期来看,这种行为会使大家在短期内受害,但是我想为这家公司喝彩,中国的知识产权保护观念太淡薄了,也间接导致了国内IT环境的乌烟瘴气,利润越来越低。随着中国入世的脚步,国人的版权观念会逐渐加强的。到那个时候国内才会有一个良性循环的环境。
    2、大家还记得当年的打假英雄王海吗?尽管他是在借着打假赚钱,也被很多人骂,很多人对他的做法也是嗤之以鼻,可是理性的思考一下,他的行为是不是有积极的意义呢?假如北京美好景象这样的公司再多一点,或者我们每个公司都像北京美好景象这样,那么还有人敢盗用别人的东西吗,还敢随便用网上下载的图片吗,还敢随便用网上下载来的软件包吗,还敢随便用盗版软件搞低价竞争吗?这样我们产品的成本提高了,软件开发的门槛提高了,市场规范了,那么IT业规范化、良性化、规模化发展的格局也就离我们不远了。
    如果我见了北京美好景象的老总,我会对他说:你真他妈的无耻,不过我支持你!
    3、“我们是要强调版权,但问题是有的图片你从baidu获取的,你知不知道这个图片是不是有版权?”,你连一点的知识产权的观念都没有,悲哀!做商业开发所用的任何东西,除非是明确表示能被免费用于商业用途,否则你都不能未经授权使用。如果你还不理解的话,希望你想想你去黑市买偷来的车是合法的吗?
    4、“不过他是应该在图片上写明什么东西的,你这样不写,如果你在用别人的东西的时候,不是也会 被陷害 吗”。严格来说,你用别人的东西的时候必须要他证明这个东西是他合法占有的,并要他书面授权你使用。这听起来有点变态,不过这正是一个高度发达的法制社会的最终目标。如果你听过罗永浩的“小心地滑”、“毒药请勿吞服”那几段语录的话,就明白米国的法治社会是什么样的了,我不是崇洋媚外,但是不得不承认的是在很多事情上我们和很多国家还有很大差距。

    总之,支持无耻的“北京美好景象图片有限公司”。
    posted @ 2007-01-16 01:06 CowNew开源团队 阅读(1192) | 评论 (7)编辑 收藏

    由于系统遭受恶意攻击,CowNew开源论坛2006年12月30日至2007年1月13日的数据丢失,给各位朋友带来的不便表示歉意。
    在此警告恶意攻击者:你们这些用别人写的工具攻击别人发现的漏洞,并且在自己都不知道原理的情况下对系统进行攻击,你们只是恶意攻击者,是一群小孩子。靠牛开源是致力于开源技术推广的网站,需要更多的精力投入到开源系统的开发中,没有时间去修复动网BBS中那些漏洞。请那些有恶意攻击企图的小朋友们好好学习去吧,不要如此无聊。对于对CowNew开源网站进行恶意攻击的人我只想说:日你老母!
    posted @ 2007-01-14 00:14 CowNew开源团队 阅读(476) | 评论 (3)编辑 收藏

    今天收到一封邮件,哈哈,我发财了!
    Mr. Richard Khoza.
    Director of Projects
    Department of Minerals & Energy
    Pretoria South Africa.

    Fax: +27- 86 516 9900
    Fax: +27- 86 516 9351


    Attention: President/CEO


    I write, asking for your indulgence in re-profiling funds to tune of Fifty
    Million, Eight Hundred Thousand United States Dollars (US$52.8M) which we
    want kept safely overseas under your supervision.

    In other words, we would like you to receive the said funds on our behalf.
    The Funds were derived over time from a project awarded to a foreign firm
    by my Department, and presently the actual contract cost have been paid to
    the original project executors, leaving the balance in the tune of the
    said amount which we have in principle obtained approval to remit
    overseas.

    Kindly pardon the use of a medium as informal as this for reaching out to
    you to make a request of great importance to us.

    Currently, I work as a Director of Projects at the Department of Minerals
    & Energy here in Pretoria South Africa. I have the authority and approval
    of my partners involved in this transaction to negotiate a suitable
    compensation for your participation and I propose 32.2 percent for you,
    while we also propose that we receive 56.6 percent and 11.2 percent are
    earmarked for purposes of taxation and other expenses.

    This endeavor has a minimal risk factor on your part provided you treat it
    with the utmost discretion. You are advised to reach me through my private
    fax for more information.

    I am available via fax to discuss further with you. I kindly wait to hear
    from you.

    Yours Sincerely,
    Mr. Richard Khoza.

    NOTE: Please dont reply to this email address for security reasons.
    Contact me via my private Fax +27 86 516 9900 or +27 86 516 9351


    __________________________________________
    DISCLAIMER:
    The information contained in this e-mail may be confidential, proprietary,
    and/or legally privileged. It is intended only for the person or entity to
    which it is addressed. If you are not the intended recipient, you are not
    allowed to distribute, copy, review, retransmit, disseminate or use this
    e-mail or any part of it in any form whatsoever for any purpose. If you
    have received this e-mail in error, please immediately notify the sender
    and delete the original message. Please be aware that the contents of this
    e-mail may not be secure and should not be seen as forming a legally
    binding contract unless otherwise stated.

    posted @ 2007-01-13 11:26 CowNew开源团队 阅读(704) | 评论 (0)编辑 收藏

    Rhino 中使用 Java 对象

    与网页中所使用的 JavaScript 不同的是, Rhino 中的脚本可以使用 Java 中的对象。要在脚本中使用 Java 类必须将 Java 类引入脚本。

    使用 cx.initStandardObjects 创建出来的 Scriptable 类型实例,不支持在脚本中使用 import 语句,此时需要使用如下的代码来创建一个 ImporterTopLevel 类的实例,它是 Scriptable 一个实现,这样就支持在脚本中使用 importPackage 语句:

    Context cx = Context.enter();

    Scriptable iptScope = new ImporterTopLevel(cx);

    在脚本中如下引入包名:

    importPackage(Packages.javax.swing);

    如果不使用 importPackage 语句,也可以采用直接包名来使用类:

    Packages.javax.swing.JFrame frame = new JFrame(“myWindow”);

     

    下面的代码演示在脚本中创建一个窗口,并在窗口上显示一个按钮。

    import org.mozilla.javascript.Context;

    import org.mozilla.javascript.ImporterTopLevel;

    import org.mozilla.javascript.Scriptable;

     

    public class JSTest3

    {

         public static void main(String[] args)

         {

             StringBuffer script = new StringBuffer();

             script.append("importPackage(java.awt);\n");

             script.append("frame = new Frame(\"JavaScript\");\n");

             script.append("frame.show();\n");

             script.append("frame.setSize(new Dimension(200,100));\n");

             script.append("button = new Button(\" 按钮 \");\n");

             script.append("frame.add(button);\n");

             script.append("frame.show();\n");

     

             Context ctx = Context.enter();

             Scriptable scope = new ImporterTopLevel(ctx);

             try

             {

                  ctx.evaluateString(scope, script.toString(), null, 1, null);

             } finally

             {

                  Context.exit();

             }

         }

    }

    运行以后就会显示下面的窗口:

    ri1.JPG

    posted @ 2007-01-03 21:17 CowNew开源团队 阅读(892) | 评论 (0)编辑 收藏

    Spring 事务管理创造性的解决了很多以前要用重量级的应用服务器才能解决的事务问题,那么其实现原理一定很深奥吧?可是如果读者仔细研究了Spring事务管理的代码以后就会发现,事务管理其实也是如此简单的事情。这也印证了在本书开头的一句话“重剑无锋、大巧不工”,Spring并没有使用什么特殊的API,它运行的原理就是事务的原理。下面是DataSourceTransactionManager的启动事务用的代码(经简化):
    protected void doBegin(Object transaction, TransactionDefinition definition)
    {
     DataSourceTransactionObject txObject =
    (DataSourceTransactionObject) transaction;
     Connection con = null;
     try
     {
      if (txObject.getConnectionHolder() == null)
      {
       Connection newCon = this.dataSource.getConnection();
       txObject.setConnectionHolder(
    new ConnectionHolder(newCon), true);
      }
      txObject.getConnectionHolder()
    .setSynchronizedWithTransaction(true);
      con = txObject.getConnectionHolder().getConnection();

      Integer previousIsolationLevel = DataSourceUtils
         .prepareConnectionForTransaction(con, definition);
      txObject.setPreviousIsolationLevel(previousIsolationLevel);
      if (con.getAutoCommit())
      {
       txObject.setMustRestoreAutoCommit(true);
       con.setAutoCommit(false);
      }
      txObject.getConnectionHolder().setTransactionActive(true);
      // Bind the session holder to the thread.
      if (txObject.isNewConnectionHolder())
      {
       TransactionSynchronizationManager.bindResource(
    getDataSource(),txObject.getConnectionHolder());
      }
     }
     catch (SQLException ex)
     {
      DataSourceUtils.releaseConnection(con, this.dataSource);
      throw new CannotCreateTransactionException(
         "Could not open JDBC Connection for transaction", ex);
     }
    }
    本文出自:http://www.cownew.com
    在调用一个需要事务的组件的时候,管理器首先判断当前调用(即当前线程)有没有一个事务,如果没有事务则启动一个事务,并把事务与当前线程绑定。Spring使用TransactionSynchronizationManager的bindResource方法将当前线程与一个事务绑定,采用的方式就是ThreadLocal,这可以从TransactionSynchronizationManager类的代码看出。
    public abstract class TransactionSynchronizationManager
    {
     ……
     private static final ThreadLocal currentTransactionName = new ThreadLocal();
     private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();
     private static final ThreadLocal actualTransactionActive = new ThreadLocal(); ……
    }
    从doBegin的代码中可以看到在启动事务的时候,如果Connection是的自动提交的(也就是getAutoCommit()方法返回true)则事务管理就会失效,所以首先要调用setAutoCommit(false)方法将其改为非自动提交的。setAutoCommit(false)这个动作在有的JDBC驱动中会非常耗时,所以最好在配置数据源的时候就将“autoCommit”属性配置为true。

    posted @ 2007-01-02 23:33 CowNew开源团队 阅读(3228) | 评论 (0)编辑 收藏

    书稿终于发给出版社了,随书光盘也发给出版社了,两个月的“闭门造书”总算有了一点结果。现在就祈祷这本书能顺利出版了。
    写书的过程中有一些“下脚料”,扔了怪可惜,就在blog中陆续共享出来吧。“下脚料”并不代表写的差,大部分是因为和书的结构有偏离,所以被cut下来了。所以的下脚料文章都以“xjl:”开头,以免得以后我发的文章也被当成下脚料了。:)

    posted @ 2007-01-02 23:31 CowNew开源团队 阅读(325) | 评论 (1)编辑 收藏

    procedure TMainForm.CopyFileByFolder(Ahandle: THandle; fromDir,
      toDir: String);
    var
      SHFileOpStruct: TSHFileOpStruct;
      pFromDir, pToDir: PAnsiChar;
    begin
      GetMem(pFromDir, Length(fromDir)+2);
      try
        GetMem(pToDir, Length(toDir)+2);
        try

          FillChar(pFromDir^, Length(fromDir)+2, 0);
          FillChar(pToDir^, Length(toDir)+2, 0);

          StrCopy(pFromDir, PChar(fromDir));
          StrCopy(pToDir, PChar(toDir));

          with SHFileOpStruct do
          begin
            Wnd    := AHandle;   // Assign the window handle
            wFunc  := FO_COPY;  // Specify a file copy
            pFrom  := pFromDir;
            pTo    := pToDir;
            fFlags := FOF_NOCONFIRMATION or FOF_SILENT;
            fAnyOperationsAborted := True;
            hNameMappings := nil;
            lpszProgressTitle := nil;
            if SHFileOperation(SHFileOpStruct) <> 0 then
              RaiseLastWin32Error;
          end;
        finally
          FreeMem(pToDir, Length(ToDir)+2);
        end;
      finally
        FreeMem(pFromDir, Length(FromDir)+2);
      end;
    end;

    posted @ 2006-12-31 00:18 CowNew开源团队 阅读(2007) | 评论 (0)编辑 收藏

    经过40多天的“闭门造书”,终于被释放了,终于可以上网了,做个记号,以后博客又可以更新了,团队网站又可以维护了!
    讲个刚看到的故事吧:
    联合利华引进了一条香皂包装生产线,结果发现这条生产线有个缺陷:常常会有盒子里没装入香皂。总不能把空盒子卖给顾客啊,他们只好请了一个学自动化的博士后设计一个方案来分拣空的香皂盒。博士后拉起了一个十几人的科研攻关小组,综合采用了机械、微电子、自动化、X射线探测等技术,花了几十万,成功解决了问题。每当生产线上有空香皂盒通过,两旁的探测器会检测到,并且驱动一只机械手把空皂盒推走。 中国南方有个乡镇企业也买了同样的生产线,老板发现这个问题后大为光火,找了个小工来说你他妈给我把这个搞定。小工果然想出了办法:他在生产线旁边放了台风扇猛吹,空皂盒自然会被吹走。
    posted @ 2006-12-15 00:25 CowNew开源团队 阅读(366) | 评论 (1)编辑 收藏

    public class DTODataChangeInterceptor implements MethodInterceptor, Serializable
    {
     private static final String SET = "set";
     private Set changedPropSet;
     
     public DTODataChangeInterceptor()
     {
      changedPropSet = new HashSet();
     }

     public Object intercept(Object obj, Method method, Object[] args,
       MethodProxy proxy) throws Throwable
     {
      String name = method.getName();

      if (name.startsWith(SET))
      {
       String s = name.substring(SET.length() - 1);
       String propName = StringUtils.firstLowerCase(s);
       changedPropSet.add(propName);
      }

      return proxy.invokeSuper(obj, args);
     }
     
     public Set getChangedPropSet()
     {
      return Collections.unmodifiableSet(changedPropSet);
     }
     
     public void reset()
     {
      changedPropSet.clear();
     }
    }

    然后如下调用来初始化javaBean

      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(destClass);
      enhancer.setCallback(new DTODataChangeInterceptor());
      
      IValueObject newBean = (IValueObject) enhancer.create();

    ........初始化newBean

      DTODataChangeInterceptor interceptor = InterceptorUtils
    //    .getDTODataChangeInterceptor(newBean);
      interceptor.reset();

    然后就可以将newBean传递给其他层进行操作,操作完毕,调用:
     public static DTODataChangeInterceptor getDTODataChangeInterceptor(Object obj)
     {
      if(!(obj instanceof Factory))
      {
       return null;
      }
      Factory f = (Factory)obj;
      Callback[] callBacks = f.getCallbacks();
      for(int i=0,n=callBacks.length;i<n;i++)
      {
       Callback callBack = callBacks[i];
       if(callBack instanceof DTODataChangeInterceptor)
       {
        return (DTODataChangeInterceptor)callBack;
       }
      }
      return null;
     }
    既可以得到哪些字段变化了。

     

    posted @ 2006-10-19 01:53 CowNew开源团队 阅读(954) | 评论 (0)编辑 收藏

      Button btnBrowsePackage = new Button(container, SWT.NONE);
      btnBrowsePackage.setText("...");
      btnBrowsePackage.addSelectionListener(new SelectionListenerAdapter(){
       public void widgetSelected(SelectionEvent e)
       {
        super.widgetSelected(e);
        IJavaProject javaProject = JavaCore.create(getCurrentProject());
        SelectionDialog dialog = null;
        try
        {
         dialog = JavaUI.createPackageDialog(getSite().getShell(),
           javaProject,IJavaElementSearchConstants.CONSIDER_REQUIRED_PROJECTS);
        } catch (JavaModelException e1)
        {
         ExceptionHandler.handleExceptionAndAbort(e1);
        }
        if (dialog.open() != Window.OK)
        {
         return;
        }
        IPackageFragment pck = (IPackageFragment) dialog.getResult()[0];
        if (pck != null)
        {
         txtPackageName.setText(pck.getElementName());
        }

       }
       
      }); 

    posted @ 2006-10-08 23:08 CowNew开源团队 阅读(893) | 评论 (0)编辑 收藏

    我正在写一个小东西,用hibernate做数据层,用hessian提供的remoting做业务层,表现层通过http的方式取得业务层的服务,有的地方需要把PO传递到表现层(有人不同意把PO和VO重用,但是我的观点是:大部分实体对象只要vo、po重用就可以了,只有vo、po差距较大的地方才分开,这样就做到了简洁性和可扩展性的良好折中)。
    但是在我将一个PO传递到表现层的时候出现了下面的问题:
    java.lang.InstantiationException: org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer
     at java.lang.Class.newInstance0(Unknown Source)
     at java.lang.Class.newInstance(Unknown Source)
     at com.caucho.hessian.io.JavaDeserializer.instantiate(JavaDeserializer.java:104)
     at com.caucho.hessian.io.JavaDeserializer.readMap(JavaDeserializer.java:54)
     at com.caucho.hessian.io.SerializerFactory.readMap(SerializerFactory.java:147)
     at com.caucho.hessian.io.HessianInput.readObject(HessianInput.java:781)
     at com.caucho.hessian.io.MapDeserializer.readMap(MapDeserializer.java:88)
     at com.caucho.hessian.io.SerializerFactory.readMap(SerializerFactory.java:149)
     at com.caucho.hessian.io.HessianInput.readObject(HessianInput.java:781)
     at com.caucho.hessian.io.JavaDeserializer.readMap(JavaDeserializer.java:69)
     at com.caucho.hessian.io.JavaDeserializer.readMap(JavaDeserializer.java:55)
     at com.caucho.hessian.io.HessianInput.readObject(HessianInput.java:658)
     at com.caucho.hessian.io.HessianInput.readReply(HessianInput.java:241)
     at com.caucho.hessian.client.HessianProxy.invoke(HessianProxy.java:179)
     at $Proxy2.loadByPK(Unknown Source)
     at com.cownew.PIS.demo.client.HelloTest.testDAO(HelloTest.java:85)
     at com.cownew.PIS.demo.client.HelloTest.main(HelloTest.java:94)
    java.lang.reflect.UndeclaredThrowableException
     at $Proxy2.loadByPK(Unknown Source)
     at com.cownew.PIS.demo.client.HelloTest.testDAO(HelloTest.java:85)
     at com.cownew.PIS.demo.client.HelloTest.main(HelloTest.java:94)
    Caused by: java.io.IOException: java.lang.InstantiationException: org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer
     at com.caucho.hessian.io.JavaDeserializer.readMap(JavaDeserializer.java:60)
     at com.caucho.hessian.io.SerializerFactory.readMap(SerializerFactory.java:147)
     at com.caucho.hessian.io.HessianInput.readObject(HessianInput.java:781)
     at com.caucho.hessian.io.MapDeserializer.readMap(MapDeserializer.java:88)
     at com.caucho.hessian.io.SerializerFactory.readMap(SerializerFactory.java:149)
     at com.caucho.hessian.io.HessianInput.readObject(HessianInput.java:781)
     at com.caucho.hessian.io.JavaDeserializer.readMap(JavaDeserializer.java:69)
     at com.caucho.hessian.io.JavaDeserializer.readMap(JavaDeserializer.java:55)
     at com.caucho.hessian.io.HessianInput.readObject(HessianInput.java:658)
     at com.caucho.hessian.io.HessianInput.readReply(HessianInput.java:241)
     at com.caucho.hessian.client.HessianProxy.invoke(HessianProxy.java:179)
     ... 3 more

    我的这个对象是如下定义的:
    package com.cownew.PIS.demo.common;
    import com.cownew.PIS.framework.common.BaseObjectValue;

    public class MaterialInfo extends BaseObjectValue
    {  
       private String Id;     
       private String Number;     
       private PersonInfo Manager;  
      
       public void setId(String value)
       {
         this.Id=value;
       }
      
      
       public void setNumber(String value)
       {
         this.Number=value;
       }
      
      
       public void setManager(PersonInfo value)
       {
         this.Manager=value;
       }
      
      
       public String getId()
       {
         return Id;
       }
      
      
       public String getNumber()
       {
         return Number;
       }
      
      
       public PersonInfo getManager()
       {
         return Manager;
       }
         
    }
    经跟踪发现原来是在反序列化getManager的返回值的时候出错的。hibernate使用CGLIB实现的惰性加载,这样getManager的返回值的类型其实是PersonInfo 的一个子类,其中有一个CGLIBLazyInitializer类型的字段,这个CGLIBLazyInitializer是没有默认构造函数的,这样就造成了反序列化失败。
    我的解决方式是写一个DTOAssembler来将PO手动转换成VO,这个VO的类型和PO一样,但是对于关联属性进行了针对CGLIB的特别处理。然后把转换后的VO传递到表现层。
    请各位多指教。谢谢。

     

    posted @ 2006-10-06 00:58 CowNew开源团队 阅读(2054) | 评论 (3)编辑 收藏

    1.经常自我反省,检视一下,在管辖范围内的人、时、地、物、有没有浪费资源,或无效运用的状况。

    2.不要在下属面前抱怨工作,数落上司及公司的不对。

    3.接受上司交待任务时,在没有尝试执行之前,绝不说“不可能”、“办不到”。

    4.每天找出一件需要突破,创新的事物,并动脑筋想一想,有无改善创新的方法。

    5.当工作未能顺利完成时,对上司要能一肩承担所有责任,不在上司面前数落部属的不是。

    6.做任何事物以前,先花些时间思考一下目标与方向是否正确。

    7.找出在个人管理范畴内,有哪些原理与原则是不可违背的。

    组织管理的原则

    8.除非特殊状况,交待事项只对下一级的直属部属,而不跨级指挥。

    9.除非事先已协调有共识或遇紧急状况,否则不指挥其它平行单位的员工。

    10.接受上级跨级指挥时,必定要及时回报直属上司,让其了解状况。

    11.交办员工工作或任务分配时,能多花点时间沟通,了解他对工作的想法同时让他了解工作的重要性与意义,想办法唤起他内心执行的愿意。

    12.交待部属工作时,尽量思考如何给予他更多的空间发挥。

    13.下达指示时,着重要求目标的完成,对过程不需要太多的限制。

    计划与执行

    14.做事以前,一定要先想一想,做好应有的计划,绝不冒然行事。

    15.在计划阶段,要多参考别人的意见,借用别人的经验与智慧,做好必要的协调工作,绝不可以闭门造车。

    16.工作之前,一定要先明确的订定或确认目标,把握正确的方向。

    17.做计划时,要从人、事、时、物、地各方面来收集相关事实、信息、详细分析研判,作为计划的参考。

    18.不单凭直觉判断事情,凡事要以科学的精神实事求是。

    19.要尽力让部属了解状况,与大家信息共享,不要存在“反正叫你去做就对了”的观念。

    控制与问题掌握

    20.在工作计划阶段,就要先想好可能的状况,事先拟订对应措施。

    21.当提出问题时,一定要能明确指出它的“目标”、“现状”以及差距所带来的影响。

    22.解决问题时,一定要客观的找出原因,不可凭主观的直觉来判断。

    23.每天发现一项需要改善的事项,并思考应该如何做会更好。

    24.在部属进行工作的时候,从旁予以观察,当有偏差时给予必要的指导纠正。

    25.鼓励员工培养观察力,提出问题,并引导出具体的建设性意见。

    部属培育与教导

    26.所属员工接受Off.J.T(off job time)训练时,要能够全力支持,协助他排除时间与工作的障碍,使他专心接受训练。

    27.要充分了解部门内各项职位应具备的知识,技巧与态度条件,并设置《岗位说明书》。

    28.新员工报到前一定要做好他的《新员工训练计划表》。

    29.一般性的工作,当部属做得没有我好时,先不要急着自己去做,仍能让他有一定的学习机会。

    30.当员工提出问题时,不要急着回答他,可先听听他的看法,让他先思考。

    31.掌握时机,随时随地对部属进行工作教导,例如:开会时,部属报告时,部属犯错时,交付工作时……等等。

    沟通与协调

    32.要主动的找部属聊天谈心,不要只是被动的等部属来找我说话。

    33.当听到其它人有和我不同意见的时候,能够先心平气和的听他把话说完,要克制自己自我防卫式的冲动。

    34.当遇见别人始终未能明白自己的意思时,能先反省是否自己的沟通方式有问题,而不先责备对方。

    35.开会或上课等正式场合上,最好将手机关机,塑造一个良好的沟通环境。

    36.和他人沟通时,能够专注的看着对方,听对方的话也要用心理解,而不左顾右盼,心有旁骛。

    37.和别人协调沟通时,避免对他人有先入为主的负面想法。

    38.与其它部门或同事协调时,能保持客观理解的态度,遣词用句多用正面的话。

    掌握人性的管理

    39.不要只是期望公司透过制度来激励员工士气,随时想想有哪些我可以自己来做的部分。

    40.对每一位员工都要能够多加了解,确实掌握他的背景、个性、习惯、需求、态度、优缺点。

    41.养成每天说几句好话的习惯,如“辛苦了”、“谢谢”、“做得不错”等。

    42.不只是赞赏员工,遇到员工有错的时候,能给予必要的责备。

    43.员工本人生病时,能拔通电话给予关心,如果员工家中有婚丧喜庆,尽可能去参加。

    44.要求员工的事,自己也要能做到,凡事从自己做起。

    领导力的发挥

    45.要强化自己的人文素养,培养一些除了工作以外的正当兴趣及嗜好。

    46.不要只是靠权势(力)要求部属,而要展现自己的管理及专业上的才能,让员工能够心服口服。

    47.在组织内所做的一切,不能只是为了自己私人的利益,而应以团队为出发点。

    48.对不同的员工,要运用不同的领导方式来带领,而不是一味追求齐头式的平等。

    49.不论通过何种方式(如:看书、上网、娱乐活动等),每年都要让自己感受到吸收了新的信息,有明显的成长。

    50.要将以上所学内容运用到今后的工作中。
    from:http://cailinaaa.spaces.live.com/

    posted @ 2006-09-19 23:30 CowNew开源团队 阅读(320) | 评论 (0)编辑 收藏

    刚才写了一个日构建脚本,还没有写完,还差界面冒烟测试、把构建结果通知相关开发人员这个功能没有实现,太晚了,明天再搞:
    <?xml version="1.0" encoding="GB2312" ?>

    <project name="dailybuild" default="main">

    <!--tomcat的路径-->
    <property name="tomcathome.dir"
        value="C:\Program Files\Apache Software Foundation\Tomcat 5.0\"/>

    <property name="tomcathome.mgr.dir"
        value="http://127.0.0.1:8080/manager/"/>
    <property name="tomcat.username"
        value="admin"/>
    <property name="tomcat.password"
        value=""/>

    <property name="cownewwebpath"
        value="/CownewPISWeb"/>
    <!--Web应用的路径-->   
    <property name="cownewwebhome.dir"
        value="${tomcathome.dir}webapps\CownewPISWeb\"/>
     
    <!--Web应用的源码路径(主要供稍后的编译用)-->     
    <property name="cownewwebhome.java.dir"
        value="${cownewwebhome.dir}WEB-INF\java\"/>
     
    <!--Web应用输出的class路径-->       
    <property name="cownewwebhome.classes.dir"
        value="${cownewwebhome.dir}WEB-INF\classes\"/>
     
    <!--CVS根路径-->    
    <property name="cvsRoot"
        value=":pserver:杨中科:123456@192.168.1.6:/cvsrep"/>
       
    <property name="cvs.outtemp.dir"
        value="${cownewwebhome.dir}cvsout/"/>

    <taskdef name="stopTomcat" classname="org.apache.catalina.ant.StopTask">       
      <classpath>           
        <path location="${tomcathome.dir}/server/lib/catalina-ant.jar"/>       
      </classpath>   
    </taskdef>

    <taskdef name="startTomcat" classname="org.apache.catalina.ant.StartTask">       
      <classpath>           
        <path location="${tomcathome.dir}/server/lib/catalina-ant.jar"/>       
      </classpath>   
    </taskdef>

    <target name="main">

    <echo>停止Tomcat</echo>

    <stopTomcat url="${tomcathome.mgr.dir}" username="${tomcat.username}"
        password="${tomcat.password}" path="${cownewwebpath}"/>

    <echo>清除原有构建文件</echo>

    <delete dir="${cownewwebhome.dir}"/>

    <echo>开始从CVS下拉代码</echo>

    <mkdir dir="${cvs.outtemp.dir}"/>
    <cvs cvsRoot="${cvsRoot}" package="CownewPISWeb" dest="${cvs.outtemp.dir}"/>
    <mkdir dir="${cownewwebhome.dir}"/>
    <copy todir="${cownewwebhome.dir}">
      <fileset dir="${cvs.outtemp.dir}CownewPISWeb/WebContent/"/>
    </copy>

    <mkdir dir="${cownewwebhome.java.dir}"/>
    <copy todir="${cownewwebhome.java.dir}">
      <fileset dir="${cvs.outtemp.dir}CownewPISWeb/src/"/>
    </copy>
    <delete dir="${cvs.outtemp.dir}"/>

    <echo>开始编译源代码</echo>
    <mkdir dir="${cownewwebhome.classes.dir}"/>
    <javac srcdir="${cownewwebhome.java.dir}" destdir="${cownewwebhome.classes.dir}" >
       <classpath>
          <pathelement location="E:\保留文档\java\常用包\junit-3.8.1.jar" />
       </classpath>

    </javac>
    <delete dir="${cownewwebhome.java.dir}"/>

    <echo>启动Tomcat</echo>

    <startTomcat url="${tomcathome.mgr.dir}" username="${tomcat.username}"
        password="${tomcat.password}" path="${cownewwebpath}"/>


    <echo>开始冒烟测试</echo>
     <junit printsummary="yes" fork="yes" haltonfailure="no">
        <classpath>
           <pathelement location="E:\保留文档\java\常用包\junit-3.8.1.jar"/> 
           <pathelement location="${cownewwebhome.classes.dir}"/>         
        </classpath>
        <batchtest fork="yes" todir="${cownewwebhome.classes.dir}" haltonfailure="no">
          <fileset dir="${cownewwebhome.classes.dir}">
              <include name="**/bvt/*.class" />
           </fileset>
        </batchtest>
     </junit>
    <echo>todo:</echo>

    </target>


    </project>

    posted @ 2006-09-18 01:54 CowNew开源团队 阅读(755) | 评论 (1)编辑 收藏

    apusicjsf.JPG
    上边这个图是macos系统吗?非也,你打开:http://www.operamasks.org/OnlineExample.jsp
    看看吧!
    为Apusic JSF开源喝彩!我已经申请加入了!我想把它移植到其它服务器上去。我本来不喜欢做Web前台界面,可是看了这个以后我决定一定要好好研究一下!!!!
    http://www.operamasks.org/
    posted @ 2006-09-11 22:28 CowNew开源团队 阅读(1371) | 评论 (4)编辑 收藏

    from:http://www.blogcn.com/u2/18/33/zzjdblog/index.html

    1.先进先出法,是以先入库的存货先发出为假设前提,对发出存货计算成本的一种方法。
    例如:
      假设库存为零,1日购入A产品100个 单价2元;3日购入A产品50个 单价3元;
      5日销售发出A产品50个,则发出单价为2元,成本为100元。
    2.后进先出法和他相反,是以后收进的存货先发出为假设前提。
    3.加权平均法:
     单位存货成本=(月初成本+本月收入成本)/(月初结存数量+本月收入数量)
       发货成本=发货数量X单位存货成本
    4.移动加权平均:(
     一批收货后单位存货成本=(原有库存成本+本次收货成本)/(原有数量+本次收入数量)
    发货成本=发货数量X一批收货后单位存货成本
    5.个别计价法:是假设存货的成本流转与实物流转一致,按每一存货的购入成本来确定发出成本
    6.计划成本法:存货的收入、发出、结存都以计划成本计价,同时通过“材料成本差异”,登记实际成本与计划成本的差异。具体内容好多了,可以看看会计方面的书。

    移动加权平均法,库存每发生一次变化,就会做一次计算并更新结果。因此移动加权平均法的开销较大,一般的企业在应用时都使用的先进先出法或者加权平均法。


    存货计价方法的筹划是采取合适的计价方法将材料费用计入产品成本。在选用先进先出法、个别计价法、后进先出法等计价方式应与批次管理结合起来才能便于管理系统进行价格进行实时核算与分析。物料的物理的先进行出、后进先出、分别认定与存货计价方式可以分开处理,比如物料的进出库存采用,先进先出但它的计价方法可以选先进先出法、加权平均法、移动平均法、个别计价法、后进先出法。
    不同的计价方法,会使结转当期销售成本的数额有所不同。期末存货的大小与销售成本的高低成反比,从而会影响到当期纳税利润数额。期末存货如果计价过低,当期的利润可能因此减少;期末存货计价过高,当期利润可能增加;期初存货如果计价过低,当期的利润会增加,期初存货过高,当期利润会减少。在物价上升情况下,企业耗用原材料的成本较高,当期利润减少,可采用后进先出法;如果原材料价格下跌,就应用先进先出法;如果价格比较平稳,就用加权平均法;如果材料价格涨落幅度大,宜用移动平均法。

    通常采用全月加权平均


    加权平均是手工核算方式下应用较为普遍的一种方式,在实际工作中,有下面两种计算方式,但不论哪种方式,首先计算单位存货成本,计算公式一般如白菜所写,也有下面这种写法
      单位存货成本=(月初结存成本+本月采购成本+本月其他增加金额-本月其他减少金额)/(月初结存数量+本月采购数量+本月其他增加数量-本月其他减少数量)
      上式中,其他增加是指除采购外的增加库存的情况,如转入、盘盈等,但不包括借入,其他减少是指除销售外的减少库存的情况,如转出、损耗等,但不包括借出
    1、先算库存
      月末结存成本=月末结存数量*单位存货成本
      销售成本=月初结存成本+本月采购成本+本月其他增加金额-本月其他减少金额-月末结存成本
    2、先算销售成本
      销售成本=销售数量*单位存货成本
      月末结存成本=月初结存成本+本月采购成本+本月其他增加金额-本月其他减少金额-销售成本
    posted @ 2006-09-03 17:04 CowNew开源团队 阅读(1636) | 评论 (0)编辑 收藏

    随着我们伟大祖国建设的飞速发展,能源问题日益突出,要发展,我们就要开发新的能量来源,在此,我郑重提出:向太阳进军!向太阳要能源!在太阳上挖煤!

      本报告分三个部分:

      第一部分:论太阳上有没有煤

      一些资产阶级学者认为,组成太阳的主要元素是氢和氦,这简直是不明物理,乱说一通。我们随便找来一个充满氢气的气球,用火点燃它,气球确实会剧烈燃烧,但它持续的时间非常短暂,如果太阳是由氢和氦组成,氦气不会燃烧,而氢气在太阳上即使贮量再多,太阳燃烧的时间也决不会很长。

      太阳也不会是由液体燃料组成。如果是液体,众所周知,液体具有流动性,那么这些组成太阳的液体会流满整个天空,我们看到的就不会是太阳这个火球燃烧,而是整个天空都在燃烧了。

      所以组成太阳的既不会是气体,也不会是液体,而只能是固体。固体能燃烧的,有木柴和煤,然而前者燃烧时会发烟,但我们谁曾看见太阳冒着浓烟从天空掠过呢?所以组成太阳的主要物质只能是煤,而且是优质的无烟煤。

      第二部分:论能不能挖太阳上的煤

      资产阶级学者还鼓吹:“没有太阳,地球上就不会有风雪雨露,也不会有草木鸟兽。”甚至还说:“没有太阳,就没有我们这个美丽可爱的世界。”太阳的作用真的这样重要吗?太阳就真的如老虎屁股,一点儿也不能动吗?实践是检验真理的唯一标准!生活常识告诉我们:太阳,它只是在充满温暖和光明的白天发光,而在寒冷、黑暗、最需要光和热的时候,太阳,却不知躲到哪里去了!从这个意义上讲,太阳的作用甚至远远不及在黑夜里发微光的月亮。这些资产阶级的所谓学者抛出这种耸人听闻的太阳至上的论调其实别有用心,其目的在于阻挠别人对太阳上能源的开发利用。但他们忘记了任何伪科学的东西都是经不起推敲的,唯心的反动鼓吹其结果只能是在真理的厚墙上撞得头破血流。

      第三部分:论如何在太阳上挖煤

      我们都知道,太阳无时无刻不在燃烧,那么怎样才能在太阳上挖煤呢?要回答这个问题,笔者想先讲一讲自己年轻时的经历。那时笔者身在东北,三月植树节时响应号召植树造林。三月的北疆,土地尚未化冻,一镐抡下去,只能砸出一个白点。但困难吓不倒我们,我们砍倒大树生起了一堆堆篝火,让火把土地烤暖后移开它再挖。就这样边烧边挖,边挖边烧,终于胜利完成了光荣而艰巨的植树任务。

      今天我们要在太阳上挖煤,就可以用到这个在激情燃烧的岁月中积累的宝贵经验。太阳上虽然燃烧着熊熊大火,但火不是可以用水来灭的么?难能可贵的是离太阳最近的一颗行星就是水星,水星水星,顾名思义,就是一颗充满了水的行星,那上面烟波浩淼,水资源可谓取之不尽,用之不竭。我们完全可以取水星之水局部地灭太阳之火,然后在已灭火的太阳局部表面上迅速地挖煤。就这样边挖煤边灭火,边灭火边挖煤。

      虽然水星上水资源丰富,但本着节约的原则,我建议最好是利用早晨和黄昏这两个时间段搞生产。因为在这两个时间段里,太阳的温度不是很高,火势不是很猛,这时生产作业不但可以节约水资源,而且还提高了安全系数。并且在这两个时间段里,太阳离地表最近,也便于煤的运输,如果在正午生产,大大增加了水资源的消耗和提高了运输成本不说,如果煤块从高空跌落,还容易造成劳动人民生命财产的损失。

      结语:不怕做不到,只怕想不到,只要我们解放思想,开动脑筋,一切东西都可以拿来为社会主义建设服务。正所谓:中华儿女多奇志,敢叫太阳变煤田![/
    posted @ 2006-09-02 15:18 CowNew开源团队 阅读(615) | 评论 (5)编辑 收藏

    CowNew 开源团队网站 www.cownew.com

    论坛 http://www.cownew.com/newpeng/ 

    转载请保留此信息

    有一些插件会自动将需要的jar包自动设置到构建路径上,比如使用WTP的新建向导新建web项目的时候就会把web开发需要的jar包自动放入项目的构建路径,使用PDE的“将项目转换为插件项目”功能后项目的构建路径中就增加了插件依赖项的库。我这里来演示一下其实现:
    在这个例子中,我们想要做一个“为项目添加lucene支持”的功能,用户在项目上点击右键,选择菜单中的“为项目添加lucene支持”以后,插件把lucene的jar包和源码包拷贝到项目的lib目录下,并且将jar包加入构建路径。如下图:
    这是增加lucene支持前的项目结构:

    CowNew开源团队网站www.cownew.com 
     
    用户在项目上点击右键,选择菜单中的“为项目添加lucene支持”后的项目结构
     
    这是工程构建路径
     
    ①新建一个插件工程,并将JDT相关的依赖项加入。
    ②添加一个“org.eclipse.ui.popupMenus”的扩展点,如果不熟悉怎么添加,可以使用插件向导中的“弹出菜单”向导。
    需要注意contribution的配置,
    此插件只针对Java项目才起作用,因此“objectClass”中填入“org.eclipse.jdt.core.IJavaProject”;
    adaptable选择“true”(后边讲解为什么);
    如果是用向导生成的那么请记得清空“nameFilter”。
    ③下面是核心类ActionAddLucene 的实现代码
    public class ActionAddLucene implements IObjectActionDelegate
    {
     private static final String FILESEPARATOR = System.getProperty("file.separator","/");
     private static final String LUCENESRCJAR = "lucene-1.4.3-src.jar";
     private static final String LUCENEJAR = "lucene-1.4.3.jar";
     private static final String LIB = "lib";
     private static final String RESOUCELIB = "resoucelib";
     private IStructuredSelection structSelection;

     public ActionAddLucene()
     {
      super();
     }

     public void setActivePart(IAction action, IWorkbenchPart targetPart)
     {
     }

     public void run(IAction action)
     {
      Object selectObj = structSelection.getFirstElement();
      if (selectObj instanceof IProject)
      {
       IProject project = (IProject) selectObj;
       IJavaProject javaProject = JavaCore.create(project);
       IClasspathEntry[] oldPaths = javaProject.readRawClasspath();
       IClasspathEntry luceneLibEntry = JavaCore.newLibraryEntry(project
         .getFile(LIB + FILESEPARATOR + LUCENEJAR).getFullPath(), project
         .getFile(LIB + FILESEPARATOR + LUCENESRCJAR).getFullPath(), null,
         false);  
       
       if(classPathExists(oldPaths,luceneLibEntry))
       {
        return;
       }

       URL luceneLib = Activator.getDefault().getBundle().getEntry(
         RESOUCELIB + FILESEPARATOR + LUCENEJAR);
       URL luceneSrc = Activator.getDefault().getBundle().getEntry(
         RESOUCELIB + FILESEPARATOR + LUCENESRCJAR);
       IClasspathEntry[] newPaths = new IClasspathEntry[oldPaths.length + 1];
       System.arraycopy(oldPaths, 0, newPaths, 0, oldPaths.length);

       IFolder libFolder = project.getFolder(LIB);
       if (!libFolder.exists())
       {
        try
        {
         libFolder.create(true, true, null);
        } catch (CoreException e)
        {
         handleException(e);
        }
       }

       copyURLToFile(luceneLib, project, LIB + FILESEPARATOR + LUCENEJAR);
       copyURLToFile(luceneSrc, project, LIB + FILESEPARATOR + LUCENESRCJAR);
       
       newPaths[oldPaths.length] = luceneLibEntry;
       try
       {
        javaProject.setRawClasspath(newPaths, null);
       } catch (JavaModelException e)
       {
        handleException(e);
       }
      }
     }

     private static boolean  classPathExists(IClasspathEntry[] entrys,IClasspathEntry entry)
     {
      for(int i=0,n=entrys.length;i<n;i++)
      {
       if(entrys[i].getPath().equals(entry.getPath()))
       {
        return true;
       }
      }
      return false;
     }
     private static void handleException(Exception e)
     {
      Activator.getDefault().getLog().log(
        new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, e
          .getMessage(), e));
     }

     private static void copyURLToFile(URL url, IProject project,
       String destFileName)
     {
      InputStream inStream = null;
      try
      {
       inStream = url.openStream();
       IFile file = project.getFile(destFileName);
       if (!file.exists())
       {
        file.create(inStream, true, null);
       }

      } catch (IOException e)
      {
       handleException(e);
      } catch (CoreException e)
      {
       handleException(e);
      } finally
      {
       try
       {
        if (inStream != null)
         inStream.close();
       } catch (IOException e)
       {
        handleException(e);
       }
      }

     }

     public void selectionChanged(IAction action, ISelection selection)
     {
      structSelection = (IStructuredSelection) selection;
     }
    }
    下面解释一下代码中的重点部分:
    ①IClasspathEntry[] oldPaths = javaProject.readRawClasspath();
    读取项目原有的构建路径条目。
    ②      
    IClasspathEntry luceneLibEntry = JavaCore.newLibraryEntry(project
         .getFile(LIB + FILESEPARATOR + LUCENEJAR).getFullPath(), project
         .getFile(LIB + FILESEPARATOR + LUCENESRCJAR).getFullPath(),null,
         false);  
    这一句构建lucene的jar包。
    第一个参数是二进制jar包的位置,我们的二进制jar包的位置为项目路径下的lib/lucene-1.4.3-src.jar;
    第二个参数是jar包对应的源码包的位置;
    第三个参数为源码包的根路径,lucene的源码包的源码根路径就是jar包的根路径,因此我们置此参数为null;
    第四个参数表示是否导出,我们置为false;
    ③URL luceneLib = Activator.getDefault().getBundle().getEntry(RESOUCELIB + FILESEPARATOR + LUCENEJAR);
    我们把“lucene-1.4.3.jar”、“lucene-1.4.3-src.jar”放到我们插件的“resoucelib”目录下,当用户点击“为项目添加lucene支持”的时候我们要把这两个文件拷贝到项目的lib目录下,因此我们需要首先读取插件路径“resoucelib”目录下的这两个jar包。
    读取插件路径下的文件我们使用插件Activator类提供的方法即可,比如:
    Activator.getDefault().getBundle().getEntry(“config/my.xml”)
    就可以读取到插件根目录下的文件“config/my.xml”,返回类型是java.net.URL。
    ④copyURLToFile(luceneLib, project, LIB + FILESEPARATOR + LUCENEJAR);
    Activator.getDefault().getBundle().getEntry读取到的文件位置是URL类型的,我们需要把这个URL对应的文件拷贝到项目的"lib"下。下面看一下copyURLToFile的主干代码:
     inStream = url.openStream();
     IFile file = project.getFile(destFileName);
     if (!file.exists())
     {
      file.create(inStream, true, null);
     }
    URL类有一个openStream可以打开文件的输入流,IFile也有一个接受输入流的create方法用来创建文件,因此我们只需要把url的输入流输出给IFile的create方法即可。
    这里我们也可以由url得到其对应的磁盘上的路径,也可以得到IFile对应的磁盘上的路径,然后使用Java IO来进行文件复制操作。但是这样做不仅代码数量变多了,而且由于不是使用的Eclipse的资源管理API,会带来无法自动刷新等问题,因此建议读者尽量使用Eclipse提供的API来完成功能。

    posted @ 2006-09-01 21:46 CowNew开源团队 阅读(1458) | 评论 (1)编辑 收藏

    十岁以前,就不说了,无非是淘气和不懂事。

    十三、四岁的时候,开始对女孩有好感,但是那时候他离女孩远远的,并且以讨厌女孩自居,生怕被同伴嘲笑。

    十五岁的时候,听到大人们说某某男人好花,把女朋友甩了,女孩自杀了。 他觉得这人真狠毒,自己将来一定要做个痴情的男人,一定要一生只爱一个人。

    十六岁的时候,他喜欢上了一个女孩,但是他不敢和她说。仍然和往常一样,脏兮兮的在灰土飞扬的操场上踢球.只在女孩走出校门的时候,躲在二层的窗户上看她的背影,他觉得她一定是个天使。

    十七岁的时候,有个女孩喜欢上了他,但是他离她很远,他心里面只有自己那个女孩, 他觉得看别的女孩都是对她的不忠。

    十八岁的时候,看了一个MTV,感动得想哭,他想,如果自己的女孩失去了双眼,他一定会像男主角那样毫不犹豫的把自己的眼睛给她,让她能看到光明。

    十九岁的时候,高考了。终于和自己暗恋的女孩分别,坐火车去学校的时候,感觉自己离她越来越远,心像被掏空了一样。还在想自己一定不会忘记她,等到自己成功以后一定要去找她。

    二十岁的时候,听到有人讲黄色笑话,觉得这人真可耻。

    二十一岁的时候,她的回信中告诉他,自己有了男朋友。偷偷的哭了一个晚上。

    二十二岁的时候,他向一个女孩表白,女孩说你是个好人,可是我还小。他想,我的确是个好人,他说没关系,我可以等你。心想,我不会像那些花心的人一样,三年五年我也能等。

    二十三岁的时候,说自己还小的女孩和一个帅哥恋爱了。他很纳闷,长大原来可以这快。

    二十四岁的时候,他又向一个女孩表白,女孩说你是个好人,可是我并不适合你。他纳闷很久,我是好人你怎么还不适合我呢?

    二十五岁的时候,他又追求一个女孩,女孩接受了他。他开始很幸福的为未来拼搏,他想,一时的开心只是暂时的,只有努力拼搏,他和她才能有快乐的未来,但是,半年以后,女孩和他分手了。只是因为另外一个男孩会说让她开心的话。女孩说你是个好人 ,是我对不起你。他似乎明白了问题所在,他是个好人。

    二十六岁的时候,他开始堕落,交网友。打扮得时尚而酷,而且渐渐的学习着讨好女孩的话。不久,他有了个女朋友,虽然他对她也很好,可是,他心里知道,自己并不爱她。

    二十七岁的时候,他和女孩分手了。他对女孩说你是个好女孩,是我对不起你。

    二十八岁的时候,他尝试了一夜情,发现别人能做的,自己也一样。

    二十九岁的时候,他学会了讲黄色笑话,并且以看旁边的女孩子脸红为乐趣。

    三十岁的时候,他忽然发现自己变得很有能力追求到女孩,但是却没有了爱的能力。于是他在自己QQ上写下了如下的话:

    其实每个男孩,本来都是想做一个感情专一的好男人的。

    其实每个男孩,本来看女孩子都是看脸而不是胸部的。

    其实每个男孩,本来都是不会讲黄色笑话的。

    其实每个男孩,本来都是渴望爱一个人直到永远的。

    只是,没有任何女孩爱这样的男孩,她们觉得这样的男孩太幼稚,太古板,没有情趣。

    于是男孩开始改变,变成女孩喜欢的那种 嘴角挂着坏坏的笑,玩世不恭或者幽默,开始学会说甜言蜜语而不是心里想说的话,开始学会假装关心,学会给女孩送小饰物讨好她,学会如何追求,如何把握爱情。 或者看破红尘,游戏情场,成为女人恨恨的那种男人。

    他们可以很容易俘获女孩子的心 但是他们也会在黑的夜里叼着烟流泪,心里有爱的时候,没有女孩.有了女孩,却永远没有了爱的感觉 在听到女人抱怨世上没有一个好男人时候他们不会再去努力做个好男人,只是微笑着擦肩而过……

    posted @ 2006-08-25 20:05 CowNew开源团队 阅读(339) | 评论 (0)编辑 收藏

    一切可计算的问题都能计算,这样的虚拟机或者编程语言就叫图灵完备的。
    posted @ 2006-08-25 20:00 CowNew开源团队 阅读(1423) | 评论 (0)编辑 收藏

    CowNew 开源团队网站 www.cownew.com

    论坛 http://www.cownew.com/newpeng/ 

    转载请保留此信息

    今天一个CownewStudio的使用者通过QQ问我他的Eclipse安装CownewStudio以后在eclipse中可以看到studio,但是运行的时候提示类加载错误。因为CownewStudio目前的版本只支持JDK5,所以我询问他Eclipse使用的是不是1.4的JRE,但是他确认它用的就是1.5的。
    后来经过实验,我确认还是JRE版本的问题,他就把他的Eclipse截图发给了我,以证明他用的是JDK1.5,但是我发现他发过来的图片工程编译器配置对话框的。哈哈,我终于明白了,让他把Eclipse的配置详细信息(“帮助”=》“关于Eclipse”=》“配置详细信息”)发过来,果然:
    -vm
    c:\programe\jdk1.4.2\jre\bin\javaw.exe

    原来他装了多个版本的JDK。我要他把JDK1.5目录下的JRE目录拷贝到eclipse安装目录下,然后重启Eclipse,一切工作正常了。
    其实这是很多刚刚接触Eclipse、甚至用了好长时间Eclipse的开发人员经常犯的错,也就是把Eclipse运行时的JRE与工作空间中项目所用的JRE版本弄混乱。
    Eclipse也是一个普通的Java程序,因此必须有一个JRE做为运行环境。如果你的机器上没有安装任何JRE(或者JDK,本文不做二者的区分),那么点击eclipse.exe就会报错说找不到JRE。此时可以安装一个JRE、或者直接把JRE目录拷贝到eclipse安装目录下。
    在Eclipse的每个项目中可以为项目指定不同的JRE版本,比如A项目使用JDK1.4编译,B项目使用JDK1.5编译。这个JDK版本是和Eclipse运行JRE没有直接关系的。
    项目的JDK版本是很容易修改的,那么任何指定Eclipse启动所用的JRE呢?
    Eclipse启动的时候找JRE的顺序是:如果eclipse.ini中配置了-vm参数,那么则使用这个参数指定的JRE;否则就去查看eclipse安装目录下是否有JRE文件夹,如果有的话就使用这个JRE;否则的话就去系统中查找安装的JRE,如果还找不到的话就报错。
    所以如果不想卸载掉其他的JDK的话,可以有两种方式:(1)直接把要使用的JRE文件夹拷贝到Eclipse目录下,这是懒人常用的方法(2)修改eclipse.ini文件,添加-vm参数,指定要运行的虚拟机的地址,使用 -vm 命令行自变量例子:-vm c:\jre\bin\javaw.exe

    posted @ 2006-08-19 00:45 CowNew开源团队 阅读(3464) | 评论 (0)编辑 收藏

    今天无意中发现一个很有意思的终端界面GUI开源项目charva。
    这个框架让你可以用开发Java Swing/AWT的方式来开发在字符终端下使用的"GUI"。可以利用像JBuilder这样的IDE设计出UI,然后把标准的"java.awt"和"javax.swing"包声明换成"charva.awt"和"charvax.swing"就能够实现转换。
    http://www.pitman.co.za/projects/charva/
    项目的名字也很有意思,char-字符,va应该就是java的后半边了吧。
    以前在搞Delphi的时候有个DWPL开源项目是把Delphi程序转换成DOS程序,我还把它的文档翻译了一遍呢,呵呵,不要说我崇洋媚外,老外真的很牛。


    这个是转换之后的

    说实话,这种东西并没有什么技术含量,只要有耐心谁都可以做出来,人家有耐心,所以人家就成了牛人了。

    posted @ 2006-08-17 22:59 CowNew开源团队 阅读(1587) | 评论 (2)编辑 收藏

    类名、字段、方法以及对象的首字母的大小写;
    对于自己创建的每一个类,都考虑置入一个main();
    使类尽可能短小精悍; 让一切东西都尽可能地"私有";
    考虑采用内部类;
    尽可能细致地加上注释;
    需要时应创建一个常数;
    创建大小固定的对象集合时,使用数组;
    尽量使用interfaces,然后才是abstract类;
    在现成类的基础上创建新类时,请首先选择"新建"或"创作",然后才是继承;
    警惕"过早优化",首先让它运行起来,再考虑变得更快;
    阅读代码的时间比写代码的时间多得多。

     

     1) 类名首字母应该大写。字段、方法以及对象(句柄)的首字母应小写。对于所有标识符,其中包含的所有单词都应紧靠在一起,而且大写中间单词的首字母。 例如: ThisIsAClassName thisIsMethodOrFieldName 若在定义中出现了常数初始化字符,则大写static final基本类型标识符中的所有字母。这样便可标 志出它们属于编译期的常数。 Java包(Package)属于一种特殊情况:它们全都是小写字母,即便中间的单词亦是如此。对于域名扩展名称,如com,org,net或者edu等,全部都应小写(这也是Java 1.1和Java 1.2的区别之一)。

     (2) 为了常规用途而创建一个类时,请采取"经典形式",并包含对下述元素的定义: equals() hashCode() toString() clone()(implement Cloneable) implement Serializable

     (3) 对于自己创建的每一个类,都考虑置入一个main(),其中包含了用于测试那个类的代码。为使用一个项目中的类,我们没必要删除测试代码。若进行了任何形式的改动,可方便地返回测试。这些代码也可作为如何使用类的一个示例使用。

     (4) 应将方法设计成简要的、功能性单元,用它描述和实现一个不连续的类接口部分。理想情况下,方法应简明扼要。若长度很大,可考虑通过某种方式将其分割成较短的几个方法。这样做也便于类内代码的重复使用(有些时候,方法必须非常大,但它们仍应只做同样的一件事情)。

    (5) 设计一个类时,请设身处地为客户程序员考虑一下(类的使用方法应该是非常明确的)。然后,再设身处地为管理代码的人考虑一下(预计有可能进行哪些形式的修改,想想用什么方法可把它们变得更简单)。

     (6) 使类尽可能短小精悍,而且只解决一个特定的问题。下面是对类设计的一些建议: ●一个复杂的开关语句:考虑采用"多形"机制 ●数量众多的方法涉及到类型差别极大的操作:考虑用几个类来分别实现 ●许多成员变量在特征上有很大的差别:考虑使用几个类

     (7) 让一切东西都尽可能地"私有"--private。可使库的某一部分"公共化"(一个方法、类或者一个字段等等),就永远不能把它拿出。若强行拿出,就可能破坏其他人现有的代码,使他们不得不重新编写和设计。若只公布自己必须公布的,就可放心大胆地改变其他任何东西。在多线程环境中,隐私是特别重要的一个因素--只有private字段才能在非同步使用的情况下受到保护。

     (8) 谨惕"巨大对象综合症"。对一些习惯于顺序编程思维、且初涉OOP领域的新手,往往喜欢先写一个顺序执行的程序,再把它嵌入一个或两个巨大的对象里。根据编程原理,对象表达的应该是应用程序的概念,而非应用程序本身。

     (9) 若不得已进行一些不太雅观的编程,至少应该把那些代码置于一个类的内部。

     (10) 任何时候只要发现类与类之间结合得非常紧密,就需要考虑是否采用内部类,从而改善编码及维护工作(参见第14章14.1.2小节的"用内部类改进代码")。

     (11) 尽可能细致地加上注释,并用javadoc注释文档语法生成自己的程序文档。

     (12) 避免使用"魔术数字",这些数字很难与代码很好地配合。如以后需要修改它,无疑会成为一场噩梦,因为根本不知道"100"到底是指"数组大小"还是"其他全然不同的东西"。所以,我们应创建一个常数,并为其使用具有说服力的描述性名称,并在整个程序中都采用常数标识符。这样可使程序更易理解以及更易维护。

     (13) 涉及构建器和异常的时候,通常希望重新丢弃在构建器中捕获的任何异常--如果它造成了那个对象的创建失败。这样一来,调用者就不会以为那个对象已正确地创建,从而盲目地继续。

    (14) 当客户程序员用完对象以后,若你的类要求进行任何清除工作,可考虑将清除代码置于一个良好定义的方法里,采用类似于cleanup()这样的名字,明确表明自己的用途。除此以外,可在类内放置一个boolean(布尔)标记,指出对象是否已被清除。在类的finalize()方法里,请确定对象已被清除,并已丢弃了从RuntimeException继承的一个类(如果还没有的话),从而指出一个编程错误。在采取象这样的方案之前,请确定finalize()能够在自己的系统中工作(可能需要调用System.runFinalizersOnExit(true),从而确保这一行为)。

     (15) 在一个特定的作用域内,若一个对象必须清除(非由垃圾收集机制处理),请采用下述方法:初始化对象;若成功,则立即进入一个含有finally从句的try块,开始清除工作。

     (16) 若在初始化过程中需要覆盖(取消)finalize(),请记住调用super.finalize()(若Object属于我们的直接超类,则无此必要)。在对finalize()进行覆盖的过程中,对super.finalize()的调用应属于最后一个行动,而不应是第一个行动,这样可确保在需要基础类组件的时候它们依然有效。

     (17) 创建大小固定的对象集合时,请将它们传输至一个数组(若准备从一个方法里返回这个集合,更应如此操作)。这样一来,我们就可享受到数组在编译期进行类型检查的好处。此外,为使用它们,数组的接收者也许并不需要将对象"造型"到数组里。

     (18) 尽量使用interfaces,不要使用abstract类。若已知某样东西准备成为一个基础类,那么第一个选择应是将其变成一个interface(接口)。只有在不得不使用方法定义或者成员变量的时候,才需要将其变成一个abstract(抽象)类。接口主要描述了客户希望做什么事情,而一个类则致力于(或允许)具体的实施细节。

     (19) 在构建器内部,只进行那些将对象设为正确状态所需的工作。尽可能地避免调用其他方法,因为那些方法可能被其他人覆盖或取消,从而在构建过程中产生不可预知的结果(参见第7章的详细说明)。

     (20) 对象不应只是简单地容纳一些数据;它们的行为也应得到良好的定义。

     (21) 在现成类的基础上创建新类时,请首先选择"新建"或"创作"。只有自己的设计要求必须继承时,才应考虑这方面的问题。若在本来允许新建的场合使用了继承,则整个设计会变得没有必要地复杂。

    (22) 用继承及方法覆盖来表示行为间的差异,而用字段表示状态间的区别。一个非常极端的例子是通过对不同类的继承来表示颜色,这是绝对应该避免的:应直接使用一个"颜色"字段。

    (23) 为避免编程时遇到麻烦,请保证在自己类路径指到的任何地方,每个名字都仅对应一个类。否则,编译器可能先找到同名的另一个类,并报告出错消息。若怀疑自己碰到了类路径问题,请试试在类路径的每一个起点,搜索一下同名的.class文件。

     (24) 在Java 1.1 AWT中使用事件"适配器"时,特别容易碰到一个陷阱。若覆盖了某个适配器方法,同时拼写方法没有特别讲究,最后的结果就是新添加一个方法,而不是覆盖现成方法。然而,由于这样做是完全合法的,所以不会从编译器或运行期系统获得任何出错提示--只不过代码的工作就变得不正常了。

    (25) 用合理的设计方案消除"伪功能"。也就是说,假若只需要创建类的一个对象,就不要提前限制自己使用应用程序,并加上一条"只生成其中一个"注释。请考虑将其封装成一个"独生子"的形式。若在主程序里有大量散乱的代码,用于创建自己的对象,请考虑采纳一种创造性的方案,将些代码封装起来。

     (26) 警惕"分析瘫痪"。请记住,无论如何都要提前了解整个项目的状况,再去考察其中的细节。由于把握了全局,可快速认识自己未知的一些因素,防止在考察细节的时候陷入"死逻辑"中。

     27) 警惕"过早优化"。首先让它运行起来,再考虑变得更快--但只有在自己必须这样做、而且经证实在某部分代码中的确存在一个性能瓶颈的时候,才应进行优化。除非用专门的工具分析瓶颈,否则很有可能是在浪费自己的时间。性能提升的隐含代价是自己的代码变得难于理解,而且难于维护。

     (28) 请记住,阅读代码的时间比写代码的时间多得多。思路清晰的设计可获得易于理解的程序,但注释、细致的解释以及一些示例往往具有不可估量的价值。无论对你自己,还是对后来的人,它们都是相当重要的。如对此仍有怀疑,那么请试想自己试图从联机Java文档里找出有用信息时碰到的挫折,这样或许能将你说服。

    (29) 如认为自己已进行了良好的分析、设计或者实施,那么请稍微更换一下思维角度。试试邀请一些外来人士--并不一定是专家,但可以是来自本公司其他部门的人。请他们用完全新鲜的眼光考察你的工作,看看是否能找出你一度熟视无睹的问题。采取这种方式,往往能在最适合修改的阶段找出一些关键性的问题,避免产品发行后再解决问题而造成的金钱及精力方面的损失。

    (30) 良好的设计能带来最大的回报。简言之,对于一个特定的问题,通常会花较长的时间才能找到一种最恰当的解决方案。但一旦找到了正确的方法,以后的工作就轻松多了,再也不用经历数小时、数天或者数月的痛苦挣扎。我们的努力工作会带来最大的回报(甚至无可估量)。而且由于自己倾注了大量心血,最终获得一个出色的设计方案,成功的快感也是令人心动的。坚持抵制草草完工的诱惑--那样做往往得不偿失。

    posted @ 2006-08-13 10:24 CowNew开源团队 阅读(271) | 评论 (0)编辑 收藏

    今天无意中看到一个人写的blog,其中有一段。
    "ChartDirecto:非常棒的东东,做出的图形很漂亮。不过需要$。
      可能有些人会破解,哎,人家辛辛苦苦做出的东西,又不是很富有。破解它,忍心吗?这种人有点龌龊哦。我就不会做这样的事

    我会用破解好的,哈哈哈哈。。。。(周星星的笑声响起)"
    多么没有廉耻,悲哀!!!!!!!!!!!

    from http://bloodwolf1979.spaces.live.com/

    posted @ 2006-08-10 21:26 CowNew开源团队 阅读(1960) | 评论 (21)编辑 收藏

    由于好长时间没有搞界面开发了,所以很多人问我一些web开发的细节问题的时候我只能对它十分客套的说上一句“对不起,我好长时间没有做web开发了,一些细节忘了,抱歉”,弄得自己很尴尬。
    而且最近要写东西,里边有一小部分涉及到web开发的文章,所以就打算把web开发的东西再拾起来。
    首先安装tomcat,然后在配置应用path的时候出现问题了,上网一查才知道新版本tomcat已经不建议在server.xml中配置应用path了。现在只要在Tomcat 5.0\conf\Catalina\localhost中增加一个xml配置文件就可以了,内容类似于:

    <Context path="/balancer" docBase="balancer" debug="0" privileged="true">

    </Context>
    看来真是老了,几年不见一切都变了,呵呵。

    posted @ 2006-08-09 23:55 CowNew开源团队 阅读(741) | 评论 (1)编辑 收藏

     最近做一些文档的时候要在软件屏幕截图上做标注,用的是word的绘图标注功能,在使用过程中发现当重新排版的时候这些标注就会跑版(印刷专用术语,哈哈)。上网查资料得知必须把标注和被标注的图片进行组合才可以,这样这两者之间就相对位置固定了。按照网上说“按住shift键依次点击要组合的对象,然后点击右键选择‘组合’”,但是我尝试以后发现按shift根本无法选择多个图形对象。又经过一阵子误打误撞发现了问题所在,原来我是Alt+PrintScreen之后直接把图片粘贴到word中了,这样插入的标注和图片并不在一个画布上,所以无法组合。正确的做法是:
    1、单击文档中要创建绘图的位置。
    2、在“插入”菜单上,指向“图片”,再单击“绘制新图形”。绘图画布就插入到文档中了。
    3、使用“绘图”工具栏 添加所需的图片或标注。
    然后就可以进行组合了。
    看来office的易用性还有待改进呀。
    posted @ 2006-08-08 21:04 CowNew开源团队 阅读(1310) | 评论 (0)编辑 收藏

    还记得这些图吗?
    xxj1.JPGxxj2.JPGxxj3.JPGxxj4.JPGxxj5.JPG
    想当年小霸王可是高档“电脑”呀,我买的那个100元的杂牌学习机和400多的小霸王不在一个档次上,没想到现在。。。。真是感慨万千。

    上边有一个GBasic,俺的第一行代码就是在这个上边敲出来的,别小看它,符合基本的Basic语法,在上边还能直接写汇编指令,当时买了一本叫“学习机原理与FBASIC”,是一个叫“李春”的人写的,当时感觉巨崇拜,听说这个人现在已经是电子工业部的离退休职工了.

    NES模拟器+小霸王学习机ROM下载地址:

    http://www.ode.cn/ch/download.asp?x=1&keyno=141

    想玩的自取。:)

    posted @ 2006-08-08 21:03 CowNew开源团队 阅读(1245) | 评论 (4)编辑 收藏

    cownewstudio视频教程已经更新到硅谷动力,列表界面:
    http://www.enet.com.cn/article/2006/0704/A20060704124810.shtml
    直接访问:
     点击此处学习第九节 ↓↓

    应广大网友的要求,本周讲推出至少一讲设计模式课程,敬请关注:
    第一讲 教案:
    1、多态,
       重载,向下转型。动物:猫,狗叫的例子。
    2、接口与抽象类
    3、通过调用者ICaller与执行者IExecutor的例子更深刻理解
    4、例子实例最简单使用的模式应用

    posted @ 2006-08-07 23:32 CowNew开源团队 阅读(429) | 评论 (0)编辑 收藏

    在此下载:

    CownewStudio for eclipse 3.1

    CownewStudio for eclipse 3.2

    演示视频

    一、安装

    1 在eclipse的安装目录的plugins目录下新建一个CownewStudio_1.0.0文件夹,将压缩包的内容解压到
    CownewStudio_1.0.0下,解压以后plugin.xml、lib、icons等文件应该在CownewStudio_1.0.0的根下,即
    目录结构如下:
    eclpse
    +plugins
    +CownewStudio_1.0.0
    +lib
    +com
    +icons
    +META-INF
    plugins.xml

    readme1.jpg

    2 在eclipse的命令行参数上增加-clean参数启动eclipse。

    提示:您运行的eclipse的JRE必须是1.5以上版本,但是生成的hibernate代码则适用于任何JDK版本。

    二、建模
    1、新建一个java工程
    2、建立源文件夹,并根据自己需要建立包
    3、建立实体:在资源视图中点击右键,选择“new”->“other”->"Cownew Studio"-"Entity Model 
    File creation wizard",选择“下一步”,在目录树中选择实体文件要存放的路径,在下边的“File 
    name”中输入实体文件的名字,注意文件扩展名必须是emf。点“finish”


    4、eclipse会自动打开实体文件编辑器

    readme2.jpg

    5 Name代表实体对象的名字(此项必录)

    Alias中可以填入对这个实体的描述

    PackageName则填入源文件夹的包名,代码生成的时候生成的POJO的包名将和此处一致。支持手工录入,也可以点击右边的按钮选择一个包。(此项必录)

    DBTableName:对应的数据库实体表名。

    PrimaryKey:主键。因为目前我们的CowNewStudio只支持字符串类型的主键,因此此处只能选择在下边“FieldList”中定义的字符串类型的简单属性。

    FieldList:所有的字段,可以通过“add”、“Remove”按钮增删字段,字段的其他属性显示在eclipse的标准“properties”视图中(也就是属性视图),要修改字段的属性请打开“properties”视图,也可以通过“open properties views”按钮快捷打开。

    readme3.jpg

    6 字段属性视图。

    在属性视图中可以对字段进行灵活的定制,比如可以在FieldType中设定字段的类型等。

    当isLinkProperty属性为false的时候是简单字段,当为true的时候就可以设定字段为关联字段(目前支持one-one,one-many,many-one):

    readme4.jpg

    点击LinkedEntity可以选择关联的实体,linkType设定关联的类型,等等。

    三、代码生成:

    1、在要发布生成代码的实体文件上点击右键(支持多选,如果选择的是文件夹则会发布此文件夹下所有的实体文件),选择“CowNewStudio”-》“Generate Code from Model File”。

    readme5.gif

    跳出如下画面:

    readme6.jpg

    SourceFolder处配置生成的代码和配置文件保存到的源文件夹

    Target ORM处选择生成的ORM工具的版本,目前支持Hibernate2和Hibernate3.

    generate config file:是否生成配置文件

    generate srouce code:是否生成POJO代码。

    override existing file:如果生成代码的时候发现文件已经存在的时候是否覆盖。

    2、点击“finish”就可以看到已经生成的代码和配置文件了:

    readme7.jpg

    测试版本还有很多bug,欢迎大家到我们论坛上反馈。

    CowNew 开源团队网站 http://www.cownew.com

    邮箱 about521  at 163 dot com

    论坛 http://www.cownew.com/newpeng/

    转载请注明此版权信息

    posted @ 2006-08-05 16:12 CowNew开源团队 阅读(4879) | 评论 (33)编辑 收藏

    CowNew 开源团队网站 http://www.cownew.com

    作者 杨中科 CowNew 开源团队发起人之一,邮箱 about521  at 163 dot com

    论坛 http://www.cownew.com/newpeng/

    转载请注明此版权信息

    您没有看错,就是从eclipse3.2向3.1移植。我们开源团队的cownewstudio是基于eclipse3.2开发的,但是考虑到现在很多开发人员还在使用3.1进行开发,因此我们把cownewstudio工程在3.1中重新打包发布了一次,这样就可以输出3.1可用的包了,在移植中有如下几个小经验:
    1、3.2中Assert类有好几个包下的都可以用,但是3.1中只有
    org.eclipse.jface.util.Assert下的,因此把工程中用到其他Assert的地方都改成org.eclipse.jface.util.Assert。
    2、属性页相关的类,比如PropertyDescriptor等,在3.2中的依赖项是org.eclipse.ui.views.properties.tabbed,而在3.1中是org.eclipse.ui.views,因此要去掉org.eclipse.ui.views.properties.tabbed改成org.eclipse.ui.views
    3、eclipse3.2向导生成的Manifest.mf文件中没有了在3.1中本来有的Eclipse-AutoStart: true,可能是3.2中默认就是eclipse启动时激活插件,但是3.1则不是,因此运行的时候调用Activator的时候会报空指针的错误,因此要手动把Eclipse-AutoStart: true加到Manifest.mf中去。
    cownewstudio公测版本周末发布。

    posted @ 2006-08-03 01:07 CowNew开源团队 阅读(739) | 评论 (0)编辑 收藏

    CowNew 开源团队网站 http://www.cownew.com

    作者 杨中科 CowNew 开源团队发起人之一,邮箱 about521  at 163 dot com

    论坛 http://www.cownew.com/newpeng/

    转载请注明此版权信息


    最近准备把进销存项目激活,这样一方面可以让更多的人有机会参与到开源开发中来,另一方面也把
    SQL 翻译器、 SQL 优化器、 JDBMonitor 应用到这个项目中,这样这三个基础模块就可以在实际项目应用中得到验证和增强。我准备用 hibernate 实现持久层,在网上找了很久都没找到一个免费的实体建模然后生成 ORM 相关代码和文件的工具,因此自己就写了一个。

    经过近十天的开发,基于 eclipse CownewStudio (这个名字是个暂定的名字,以后很可能会改一个更好的名字,因为这个名字太大、太俗,呵呵)已经完成了基本的功能。已经可以进行较复杂的建模,并可以生成 hibernate2.0 POJO hbm 配置文件。

       建模界面:

    cnstudio001.JPG
    代码生成配置界面:

    cnstudio002.JPG
    生成的
    POJO

    cnstudio003.JPG
    生成的
    hbm 配置文件:

    cnstudio004.JPG
      现在的版本还有很多问题,比如容错性、模型文件校验、稳定性,生成的
    POJO hbm 的正确性也有待校验(细心的朋友也许已经发现上边生成的 hbm 文件中的错误,呵呵)。

    后续要添加的新功能有如下几点:能生成 hibernate3.0 及其他主流 ORM 的代码;增加 Remoting 建模和代码生成功能。

    公开测试版(简称公厕版,呵呵)预计将会在下周发布。

    我本人对 hibernate 不是很熟悉,希望有对此感兴趣并对 hibernate 比较熟悉的朋友加入我们开发。还需要一位对 XML DTD 比较熟悉的人,和我们一起编写模型文件的 DTD 。我的 email about521 at 163.com

    posted @ 2006-07-31 00:34 CowNew开源团队 阅读(1485) | 评论 (6)编辑 收藏

    zt from:http://cache.tianya.cn/publicforum/Content/free/1/715536.shtml
    以前中国向日本出口花生进口三合板。日本的轮船来了,并没见卸下三合板,而是推了一个机器,现场把壳花生倒进去,出来了三合板和花生米。三合板给你留下,花生米拿走了。
    发展核心竞争力,不管ZF怎么样,最终国家是咱们自己的,要奋斗!
    posted @ 2006-07-22 23:37 CowNew开源团队 阅读(182) | 评论 (0)编辑 收藏

    1、从TextEditor继承,调用setSourceViewerConfiguration,并传进去一个从SourceViewerConfiguration 继承的配置类,就可以实现各种代码editor。
    2、swt尽量使用GridLayout布局(不是java.awt中的GridLayout,而是swt中的)和GridData域。文章:http://coolbear.yculblog.com/post.89429.html

    3、得到文件的编辑器的方法:
        public static IEditorPart findEditor(IFile file){
            IEditorReference[] editors = getActivePage().getEditorReferences();;
            for (int i = 0; i < editors.length; i++) {
                IEditorPart part = (IEditorPart)editors[i].getPart(false);
                if (part != null ){
                    IEditorInput input = part.getEditorInput();
                    if(input instanceof FileEditorInput && ((FileEditorInput)input).getFile().equals(file))
                        return part;
                }               
            }
            return null;
        }

    4、得到工作区中所有工程的方法:
            IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
                    .getProjects();
    这在开发自己的工程向导的时候很有用处。
    5、工程特有文件判断方法
    project.getFile("cownew.prj").exists();
    project.getDescription().hasNature();
    给工程增加Nature的方法:
     IProjectDescription desc = project.getDescription();
    String[] oldNatureIds = desc.getNatureIds();
                    String[] newNatureIds  = new String[oldNatureIds.length +1];
                    System.arraycopy(oldNatureIds, 0, newNatureIds, 0, oldNatureIds.length);
                    newNatureIds[oldNatureIds.length] = "CowNewNature";
                    desc.setNatureIds(newNatureIds);
                    project.setDescription(desc, monitor);
    6、创建文件夹的方法:
    IFolder folder = project.getFolder("myfold");
    if (folder!=null && !folder.exists())
      folder.create(false, true, null);

    7、弹出包选择对话框的方法:
    ElementListSelectionDialog dialog = new ElementListSelectionDialog(
                        getShell(), new LabelProvider());
                dialog.setIgnoreCase(false);
    dialog.setElements(getAllPackages().toArray());
                String path = currentPackage();
     dialog.setInitialSelections(new Object[] { path });
    dialog.open();
    fPKName.setText((String) dialog.getFirstResult());

    public List getAllPackages() {
            List list = new ArrayList();
            IResource res = getFirstSelection();
            IProject project = res.getProject();
            File file = project.getFolder("src").getLocation().toFile();
            File[] fs = file.listFiles();
            for (int i = 0; i < fs.length; i++) {
                if (fs[i].isDirectory())
                    iterator("", fs[i], list);
            }
            Collections.sort(list);
            return list;
        }
    8 objectClass="org.eclipse.core.resources.IFile"代表菜单应用到文件
    9 透视图的的实现很简单,就是在构造函数里边打开一些视图,使一些action(这样菜单和按钮也就都可用)可以用,比如:
    String editorArea = layout.getEditorArea();
            IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT,
                    0.30f, editorArea);
            left.addView(PACKAGE_VIEW_ID);
     layout.setEditorAreaVisible(true);
     layout.addShowViewShortcut(IDESystem.BUSINESSVIEW_ID);

    posted @ 2006-07-21 00:33 CowNew开源团队 阅读(1274) | 评论 (1)编辑 收藏

    为了帮助更多的朋友掌握eclipse的使用,我们团队做了一个eclipse视频教程,全部都是开发过程的屏幕录像,并且伴有语音讲解。一共八讲,今天全部上传完毕。希望我们的努力帮助更多的朋友。
    观看方式:
    1、登录硅谷动力在线观看:http://www.enet.com.cn/article/2006/0704/A20060704124810.shtml
    2、通过cownew团队网站中的超链接访问:
    http://www.cownew.com/kc/

    感谢大家的支持。
    附前四讲课件:
              第一讲  eclipse的基本使用
    1、eclipse工程的建立
    2、源文件夹等概念
    3、基本代码的编写
                 第二讲  eclipse基本操作(1)
    1、建立包、建立接口 及其他  
    2、工程的高级配置   
    3、工程的构建
    3、代码的自动完成、自动修正功能
       黄色的、红色的标识
       (1)方法的自动生成
       (2)导入import
       (3)清除无用的import
       (4)自动清除无用的方法、变量
       (5)自动实现接口的、抽象类的方法,自动重载父类方法
             第三讲   eclipse基本操作(2)
    1、Java的调试
        (1) 断点、条件断点、异常断点
       (2)断点中变量的查看,语句的执行
    2、智能纠错、自动完成:
       (1)自动生成try...catch,自动列出异常列表,自动转型...在红色提示上点击鼠标,常常可以得到惊喜
       (2)自动生成set、get方法
       (3)自动生成构造函数, 
       (4)javadoc的自动生成

    第四讲 eclipse高级操作(1) 重构
    一、概述
    1、好的程序应该是不断重构出来的。消除bad smell,提高代码可读性、可维护性和可扩展性。《重构-改善既有代码的设计》(英文名《Refactoring: Improving the Design of Existing Code 》)
    2、Eclipse的自动重构功能能够很好地支持各种程序元素的重命名,并自动更新相关的引用。Eclipse能够支持方法、字段在类之间移动,并自动更新引用。Eclipse较好地支持内联字段、函数的更新替换。Eclipse较好地支持抽取方法、变量等程序元素。
    3、Eclipse的重构支持撤销和重做,并且能够预览重构结果,会对有可能导致错误的重构结果进行提示。所以使用Eclipse进行重构是非常安全的。
    二、重构不高深-实战重构
    1、方法抽取 Extract Mehod:
    将caclCost中参数校验部分抽取成方法verify。
    2、重命名 Rename
      (1)重命名类名Test1为CostCalculator。
      (2)重命名User为UserInfo
    3、内联 Inlining
       内联方法add
    4、常量抽取 Extract Constant:
       将"normal"、"vip"抽取成常量
    5、抽取局部变量 Extract Local Variable
       将user.userType抽取成变量
    6、包装字段 Encapsulate Field
       重构User类,用set get包装
    7、Extract Interface 抽取接口
       CostCalculator中抽取ICostCalculator接口
    posted @ 2006-07-19 23:55 CowNew开源团队 阅读(1791) | 评论 (3)编辑 收藏

    类型转化

    Java是一种强类型语言,每个实例都必须有指定的类型。实际上,Java类型有两种声明类型运行时类型 (也可以相应的说是静态类型动态类型 ). 像Python这样的弱类型语言通常称为无类型,但是这样说并不严谨,因为每个实例都有它的运行时类型。你只是不用事先声明一个实例的类型而已。

    要想调用一个对象中的方法,这个方法需要在声明类型中存在。也就是说,你只能调用定义在父类中的方法,即使该实例是一个确定的子类型:

    List list = new ArrayList();
    list.add("data");       // 在这里没问题
    list.ensureCapacity(4); // 这里就不行了ensureCapacity() 只在ArrayList中才有。
    

    如果我们要调用实际类型中的方法,我们首先要将它转为正确的类型。在本例中,我们可以把 ArrayList 转为List,因为ArrayList实现了List 接口. 也可以在运行时动态的检验,使用 list instanceof ArrayList.

    可扩展的接口

    糟糕的是,一个类不能总是实现你所需要实现的接口。可能是因为这只对少数几种情况才有效,或者它是一个没有被关联的库中的类型,或者这个接口在后期又被改变了。

    这种情况就可以使用IAdaptable。 你可以把 IAdaptable 动态的进行类型转化。使用如下方法避免直接的类型转化:

    Object o = new ArrayList();
    List list = (List)o;
    

    我们可以这样做:

    IAdaptable adaptable = new ArrayList();
    List list = (List)adaptable.getAdapter(java.util.List.class);
    

    你可认为它是一种类型动态转化; 我们把adaptable转为List实例。

    为什么不直接转化,而要用额外的getAdapter() 呢?这种机制可以使我们将目标类转化为没有实现的接口。例如, 我们可能想使用HashMap 作为一个 List, 尽管他们并不兼容。

    IAdaptable adaptable = new HashMap();
    List list = (List)adaptable.getAdapter(java.util.List.class);
    

    实现IAdaptable

    大多数IAdaptable的实现看起来就想是为支持类型构造多个if表达式的叠加。如果要为HashMap实现getAdapter() 可以这样:

    public class HashMap implements IAdaptable {
      public Object getAdapter(Class clazz) {
        if (clazz == java.util.List.class) {
          List list = new ArrayList(this.size());
          list.addAll(this.values());
          return list;
        }
        return null;
      }
      // ...
    }
    

    返回的是一个对自身的代理,而不是直接转化类型。如果请求的是不支持的类型,可以直接返回null表明失败,这样比抛出异常要好。

    PlatformObject

    当你想添加新的要扩展的类型时,只是简单的修改一下就可以了。在任何情况下,如果已经得到了类型,为什么不修改接口?不修改类(如果使用接口,不容易保证向后兼容)或者改变它的类型(HashMap不是 List,但是可以转化)是有原因的。要解决这个问题,在Eclipse中,使用了一个抽象类 HashMap is not a List, but can be conveted into one).

    To solve this problem, there's an abstract class that is used by most parts of Eclipse called -->PlatformObject。它为你实现了 IAdaptable接口,你就可以不用再操心了。

    PlatformObject 代理所有的它对getAdapter()的请求到 IAdapterManager. IAdapterManager是平台默认提供的,通过 Platform.getAdapterManager()来访问。你可以将它想象为一个巨大的 Map ,它负责关联类和适当的适配器。PlatformObjectgetAdapter() 方法可以访问到这个Map.

    适配已存在的类

    这样的好处是可以为每一个PlatformObject对象动态的关联新的适配器,而不用重新编译。在Eclipse中的很多地方都是这样来支持扩展的。

    这里希望将装有StringList转为XML节点。 XML节点显示为:

    <List>
      <Entry>First String</Entry>
      <Entry>Second String</Entry>
      <Entry>Third String</Entry>
    </List>
    

    因为ListtoString方法可能有别的用途,所以不能使用。 可以为List添加一个工厂,当有转为XML节点的请求时,一个Node对象就会自动返回。

    这里需要3个步骤:

    1. 从List中生成Node

    使用IAdapterFactory 来封装转换机制:

    import nu.xom.*;
    public class NodeListFactory implements IAdapterFactory {
      /** The supported types that we can adapt to */
      private static final Class[] types = {
        Node.class,
      };
      public Class[] getAdapterList() {
        return types;
      }
      /** The actual conversion to a Node */
      public Object getAdapter(Object list, Class clazz) {
        if (clazz == Node.class && list instanceof List) {
          Element root = new Element("List");
          Iterator it = list.iterator();
          while(it.hasNext()) {
            Element item = new Element("Entry");
            item.appendChild(it.next().toString());
            root.appendChild(item);
          }
          return root;
        } else {
          return null;
        }
      }
    }
    

    2. 注册工厂到PlatformAdapterManager

    我们需要注册工厂到适配器工厂,当我们向 List实例请求Node时, 它就会知道是使用我们注册的工厂。 Platform为我们管理IAdapterManager ,而且注册过程相当简单:

    Platform.getAdapterManager().registerAdapters(
      new NodeListFactory(), List.class
    );
    

    上面的代码要求平台管理者关联NodeListFactoryList。但我们要求List实例的适配器,它会调用这个工厂。根据我们对工厂的定义,会获得一个Node对象。在Eclispe中,这一步必须在插件启动的时候显式的执行,要隐式执行可以通过 org.eclipse.core.runtime.adapters 扩展点。

    3. 向List要求Node

    这里是要求适配器返回一个 Node 对象:

    Node getNodeFrom(IAdaptable list) {
      Object adaptable = list.getAdapter(Node.class);
      if (adaptable != null) {
        Node node = (Node)adaptable;
        return node;
      }
      return null;
    }
    

    总结

    如果你要在运行时为已存在的类添加功能,只要定义一个能完成转换功能的工厂,然后注册工程到 PlatformAdapterManager就可以了. 这项功能可以用来为一个非UI组件注册一个指定的UI组件,同时保持两部分的完全分离。就像在org.rcpapps.rcpnews.uiorg.rcpapps.rcpnews 插件中的使用。在这些例子中, IPropertySource 在UI插件中,它需要与非UI插件的数据相关联。当UI插件初始化时,它注册IPropertySourcePlatform, 当数据对象在浏览器中被选中时,属性视图中就会显示相应的属性。

    很明显, java.util.List不能扩展PlatformObject, 所以你不能指望例子中的代码能够编译通过,你可以重新构造 List的子类来实现目的.继承PlatformObject 也不是必须的:

    public class AdaptableList implements IAdaptable, List {
      public Object getAdapter(Class adapter) {
         return Platform.getAdapterManager().getAdapter(this, adapter);
      }
      private List delegate = new ArrayList();
      public int size() {
        return delegate.size();
      }
      // ...
    }
    

    本例中使用了XOM 来生成XML。

    from:
    http://www.javathink.org/bbs/read.php?tid-1469-page-e.html

    posted @ 2006-07-19 21:49 CowNew开源团队 阅读(354) | 评论 (0)编辑 收藏


    CowNew开源团队网站 http://www.cownew.com
    作者 杨中科 是CowNew开源团队发起人之一,邮箱about521  at 163 dot com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息


       最近准备把进销存项目激活,这样一方面可以让更多的人有机会参与到开源开发中来,另一方面也把SQL翻译器、SQL优化器、JDBMonitor应用到这个项目中,这样这三个基础模块就可以在实际项目应用中得到验证和增强。
        我准备用hibernate实现持久层,于是到hibernate的网站上把hibernate3下载下来,看了看有个hibernatetools,是个hibernate在eclipse下的辅助工具,也down了下来,用了用感觉不错。可以直接从数据库表生成POJO和hbm.xml(其实我不是很喜欢这种开发方式,我更喜欢我用建模工具来写POJO,然后用工具生成hbm.xml和DDL,不过好像hibernate3现在还没有这种工具,如果哪位朋友知道有这种工具,希望赐教)。
    美中不足的是它生成的javabean的字段名是完全和数据库字段名一致、生成的javabean的类名是完全和数据库表名一致。出于清晰以及可移植的考虑(也是公司的开发规范养成的习惯),我设计的表名全部以"T_"开头,中间再加上子系统名,最后才是表意的表名,比如用“T_PS_BOM”表示生产管理系统中的物料清单表;字段名全部以“F”开头,比如FId,FName。
    这样就导致生成了如下的javabean:

    public class TPSBOM
    {
       .......
       public String getFID()
       ...
       public String getFNumber()
    }


        看起来很不直观。我刚刚想放弃这个工具,想了想,“拿来就用,不好用就换”可不是做开源人该有的精神呀。钻研一下。
    看看了Hibernate Code Generation页签中有一个“reveng Strategy”,什么意思?“反向工程策略”??好像有门儿,点击“Browse”弹出一个类选择对话框,竟然看到了它默认显示的“DefaultReverseEngineeringStrategy”类了,我在hibernatetools的安装目录找来找去,终于在plugins\org.hibernate.eclipse_3.2.0.beta6\lib\tools下的hibernate-tools.jar中找到了这个类的影子,用反编译工具反编译一下(懒得去网上下源码了,呵呵)。一个个方法名展现在我面前:
    tableToClassName
    columnToPropertyName
    columnToHibernateTypeName
    。。。
        这不就是在把数据库相应的项映射成java相应的项吗?
        开工!
        新建一个类CowNewReverseEngineeringStrategy,继承自DefaultReverseEngineeringStrategy,override  tableToClassName、
    columnToPropertyName这两个方法,在这两个方法中写入自己的转换逻辑。
    然后打包成jar包,放到plugins\org.hibernate.eclipse_3.2.0.beta6\lib\tools下,然后在plugins\org.hibernate.eclipse_3.2.0.beta6\lib\tools\MANIFEST.MF中把这个新增包的内容加上,关闭eclipse,加个-clean参数启动eclipse,然后点击“Hibernate Code Generation”,把“reveng Strategy”填成“com.cownew.DevTools.hibtools.RevEng.CowNewReverseEngineeringStrategy”,“Run”!!!
    晕倒,竟然报错“com.cownew.DevTools.hibtools.RevEng.CowNewReverseEngineeringStrategy
    Exception while generating code
    Reason   org.hibernate.console.HibernateConsoleRunTimeException:Could not create or find com.   with one argument deleate constructor”

    看来是反射调用的时候出了问题,重新打开hibernate-tools.jar,仔细观察,竟然发现了一个DelegatingReverseEngineeringStrategy,它多    了一个参数为“ReverseEngineeringStrategy delegate”的构造函数,而其他调用都是转发给ReverseEngineeringStrategy了,晕倒,搞不懂它在做什么,也没时间研究了,给CowNewReverseEngineeringStrategy也曾街一个参数为“ReverseEngineeringStrategy delegate”的构造函数,重新打包,重新启动eclipse,哈哈,一切搞定,终于生成我可爱的,
    public class PersonInfo

      public String getNumber()。。。
      public String getId()。。。

    了。
        附全部代码:

    package com.cownew.DevTools.hibtools.RevEng;

    import java.beans.Introspector;

    import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy;
    import org.hibernate.cfg.reveng.ReverseEngineeringSettings;
    import org.hibernate.cfg.reveng.ReverseEngineeringStrategy;
    import org.hibernate.cfg.reveng.ReverseEngineeringStrategyUtil;
    import org.hibernate.cfg.reveng.TableIdentifier;
    import org.hibernate.util.StringHelper;

    public class CowNewReverseEngineeringStrategy extends
    DefaultReverseEngineeringStrategy
    {

     public CowNewReverseEngineeringStrategy(ReverseEngineeringStrategy delegate)
     {  
      super();
     }

     private ReverseEngineeringSettings settings = new ReverseEngineeringSettings();

     public String tableToClassName(TableIdentifier table)
     {
      String tableName = table.getName();
      if (tableName != null && tableName.toUpperCase().startsWith("T_"))
      {
       String pkgName = settings.getDefaultPackageName();
       int lastIndex = tableName.lastIndexOf('_');
       tableName = tableName.substring(lastIndex + 1, tableName.length())
         + "Info";

       String className = toUpperCamelCase(tableName);

       if (pkgName.length() > 0)
        return StringHelper.qualify(pkgName, className);
       return className;

      } else
      {
       return super.tableToClassName(table);
      }
     };

     public String columnToPropertyName(TableIdentifier table, String column)
     {
      if (column != null && column.toUpperCase().startsWith("F"))
      {
       String cownewColName = column.substring(1, column.length());
       
       String decapitalize = Introspector
         .decapitalize(toUpperCamelCase(cownewColName));
       return keywordCheck(decapitalize);
      } else
      {
       return super.columnToPropertyName(table, column);
      }
     }

     private String keywordCheck(String possibleKeyword)
     {
      if (ReverseEngineeringStrategyUtil
        .isReservedJavaKeyword(possibleKeyword))
       possibleKeyword += "_";
      return possibleKeyword;
     }

     public void setSettings(ReverseEngineeringSettings settings)
     {
      super.setSettings(settings);
      this.settings = settings;
     }

     public static void main(String[] args)
     {
      TableIdentifier table = new TableIdentifier("T_BD_Person");
      //TableIdentifier table = new TableIdentifier("T_Person");
      //TableIdentifier table = new TableIdentifier("Person");
      CowNewReverseEngineeringStrategy revEng = new CowNewReverseEngineeringStrategy(null);
      String className = revEng.tableToClassName(table);
      System.out.println(className);
      System.out.println(revEng.columnToPropertyName(table, "FId"));
      System.out.println(revEng.columnToPropertyName(table, "Id"));
     }
    }


     

    posted @ 2006-07-16 22:27 CowNew开源团队 阅读(1517) | 评论 (4)编辑 收藏

    CowNew开源团队网站 http://www.cownew.com
    作者是CowNew开源团队发起人之一,邮箱about521  at 163 dot com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息


    java做的系统给人的印象是什么?占内存!说道这句话就会有N多人站出来为java辩护,并举出一堆的性能测试报告来证明这一点。其实从理论上来讲java做的系统并不比其他语言开发出来的系统更占用内存,那么为什么却有这么N多理由来证明它确实占内存呢???两个字,陋习。
    (1)别用new Boolean()。
    在很多场景中Boolean类型是必须的,比如JDBC中boolean类型的set与get都是通过Boolean封装传递的,大部分ORM也是用Boolean来封装boolean类型的,比如:
    ps.setBoolean("isClosed",new Boolean(true));
    ps.setBoolean("isClosed",new Boolean(isClosed));
    ps.setBoolean("isClosed",new Boolean(i==3));

    通常这些系统中构造的Boolean实例的个数是相当多的,所以系统中充满了大量Boolean实例小对象,这是相当消耗内存的。
    Boolean类实际上只要两个实例就够了,一个true的实例,一个false的实例。
    Boolean类提供两了个静态变量:
    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);
    需要的时候只要取这两个变量就可以了,
    比如:
    ps.setBoolean("isClosed",Boolean.TRUE);

    那么象2、3句那样要根据一个boolean变量来创建一个Boolean怎么办呢?可以使用Boolean提供的静态方法:   Boolean.valueOf()
    比如:
     
    ps.setBoolean("isClosed",Boolean.valueOf(isClosed));
    ps.setBoolean("isClosed",Boolean.valueOf(i==3));
    因为valueOf的内部实现是:
    return (b ? TRUE : FALSE);
    所以可以节省大量内存。

    相信如果Java规范直接把Boolean的构造函数规定成private,就再也不会出现这种情况了。
    (2)别用new Integer。
    和Boolean类似,java开发中使用Integer封装int的场合也非常多,并且通常用int表示的数值通常都非常小。
    SUN SDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这256个状态的Integer,如果使用Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例。
    这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用。如果您的系统要在不同的SDK(比如IBM SDK)中使用的话,那么可以自己做了工具类封装一下,比如IntegerUtils.valueOf(),这样就可以在任何SDK中都可以使用这种特性。

    (3)用StringBuffer代替字符串相加。这个我就不多讲了,因为已经被人讲过N次了。我只想将一个不是笑话的笑话,我在看国内某“著名”java开发的WEB系统的源码中,竟然发现其中大量的使用字符串相加,一个拼装SQL语句的方法中竟然最多构造了将近100个string实例。无语中!
    (4)过滥使用哈希表,有一定开发经验的开发人员经常会使用hash表(hash表在JDK中的一个实现就是HashMap)来缓存一些数据,从而提高系统的运行速度。比如使用HashMap缓存一些物料信息、人员信息等基础资料,这在提高系统速度的同时也加大了系统的内存占用,特别是当缓存的资料比较多的时候。其实我们可以使用操作系统中的缓存的概念来解决这个问题,也就是给被缓存的分配一个一定大小的缓存容器,按照一定的算法淘汰不需要继续缓存的对象,这样一方面会因为进行了对象缓存而提高了系统的运行效率,同时由于缓存容器不是无限制扩大,从而也减少了系统的内存占用。现在有很多开源的缓存实现项目,比如ehcache、oscache等,这些项目都实现了FIFO、MRU等常见的缓存算法。
    (5)避免过深的类层次结构和过深的方法调用。因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户)。

    (6)变量只有在用到它的时候才定义和实例化。
    (7)尽量避免使用static变量,类内私有常量可以用final来代替。

    posted @ 2006-07-14 23:50 CowNew开源团队 阅读(1275) | 评论 (3)编辑 收藏

            很多关心CowNew的朋友纷纷给我发email或者qq留言,说看到最近CowNew开源项目没有动静了,问我是不是虎头蛇尾死掉了。谢谢大家的关心,CowNew没有停止进步的步伐,最近一段时间没有动静是因为我们在闷头做产品的开发。经过一个多月的努力,在kingchou、紫龙等队友的团结奋斗下,SQL解析引擎和JDBMonitor都已经取得了阶段性的成果。
            SQL解析引擎已经可以生成完整的异构SQLAST,除有少数小bug之外已经基本达到了预期的目标。另外在SQL解析引擎基础上开发的CowNewSQL翻译器也可以实现了基本的功能。可以翻译大部分主流的sql语句,比如:
    (1)可以将符合CowNewSQL语法的select now()翻译成对应如下的特定平台sql:
    mssql:Select GETDATE()
    mysql:Select NOW()
    oracle8i:Select SYSDATE FROM DUAL
    oracle9i:Select SYSDATE FROM DUAL
    (2)可以将符合CowNewSQL语法的
    update T2 set fid=t1.fid from (select * from t2
    left join t3 on t3.fid=t2.fid union select * from t5)
    翻译成对应如下的特定平台sql:
    mssql:UPDATE T2 SET fid = t1.fid
    FROM(
    Select *
    From t2 left join t3 on t3.fid = t2.fid
    union Select *
    From t5
    )
    mysql:UPDATE T2 SET fid = t1.fid
    FROM(
    Select *
    From t2 left join t3 on t3.fid = t2.fid
    union Select *
    From t5
    )
    oracle8i:UPDATE T2 SET fid = t1.fid
    FROM(
    Select *
    From t2,t3 WHERE t3.fid = t2.fid(+)
    union Select *
    From t5
    )
    oracle9i:UPDATE T2 SET fid = t1.fid
    FROM(
    Select *
    From t2 left join t3 on t3.fid = t2.fid
    union Select *
    From t5
    )

    (2)可以将符合CowNewSQL语法的
    select top 20 ABS(-1),lcase(trim(name)),tochar(now()), ADD_SECONDS(now(),22),t2.name,DateAdd(Year,now(),3) from T_Table
    ,(select * from T_MD where FID=2222222222) as tmd
    left join T_T4 on tmd.id>T_Table.id
    left join T_T2 as t2 on T_T2.id=T_Table.id
    right join T_T3 as t3 on t2.id=t3.id
    翻译成对应如下的特定平台sql:
    mssql:Select  top 20
     ABS(-1) , LOWER(LTRIM(RTRIM(name)) ,CONVERT(VARCHAR, GETDATE()),DATEADD(second,GETDATE(),22),t2.name,DATEADD(Year, GETDATE(), 3)
    From T_Table,
    Select *
    From T_MD
    Where FID = 2222222222 as tmd
     left join T_T4 on tmd.id > T_Table.id left join T_T2 as t2 on T_T2.id = T_Table.id right join T_T3 as t3 on t2.id = t3.id
    mysql:Select  ABS(-1) , LOWER(LTRIM(RTRIM(name)) ,CONCAT('', NOW()),DATE_ADD(NOW(), INTERVAL 22 SECOND),t2.name,DATE_ADD(3, INTERVAL NOW() YEAR)
    From T_Table,
    Select *
    From T_MD
    Where FID = 2222222222 as tmd
     left join T_T4 on tmd.id > T_Table.id left join T_T2 as t2 on T_T2.id = T_Table.id right join T_T3 as t3 on t2.id = t3.id limit 0, 20

    oracle8i:Select  ABS(-1) , LOWER(LTRIM(RTRIM(name)) , TO_CHAR(SYSDATE) ,(SYSDATE + 22/86400),t2.name,add_months(3, TRUNC(SYSDATE) * 12)
    From T_Table,
    Select *
    From T_MD
    Where FID = 2222222222 as tmd
    ,T_T4,T_T2 as t2,T_T3 as t3 WHERE ROWNUM <= 20
     AND tmd.id > T_Table.id(+) AND T_T2.id = T_Table.id(+) AND t2.id(+) = t3.id
    oracle9i:Select  ABS(-1) , LOWER(LTRIM(RTRIM(name)) , TO_CHAR(SYSDATE) ,(SYSDATE + 22/86400),t2.name,add_months(3, TRUNC(SYSDATE) * 12)
    From T_Table,
    Select *
    From T_MD
    Where FID = 2222222222 as tmd
     left join T_T4 on tmd.id > T_Table.id left join T_T2 as t2 on T_T2.id = T_Table.id right join T_T3 as t3 on t2.id = t3.id WHERE ROWNUM <= 20

            但是这些sql翻译只是按照语法手册进行的翻译,还没有经过正式数据库环境的测试,还需要进一步的测试。
            目前仅支持MSSQLSERVER,MYSQL,Oracle8i,Oracle9i,我们计划进一步支持DB2UDB,FireBird、ACCESS等数据库。而且SQL解析引擎是用JDK5开发的,我们将是用Retrotranslator将其转换个以保证可以在JDK1.4上运行。

            JDBMonitor的需求已经基本完成,但是新增的功能目前只能运行在MSSQLSERVER上,我们准备等COWNEWSQL翻译器开发完毕后,将JDBMonitor涉及到数据库操作的地方是用COWNEWSQL翻译器来完成多数据库支持,所以我们将会推迟JDBMonitor的原计划的发版日期。
            目前我们的项目还是很缺乏高手,比如CowNewSQL这块就缺乏对各种数据库比较熟悉的朋友,还有能对CowNewSQL进行全面测试的朋友,希望对这方面开发比较感兴趣的能加入到我们的开发中来,共同打造优秀的开源产品。可以直接给我发送邮件about521 at 163.com

    posted @ 2006-07-03 00:35 CowNew开源团队 阅读(2716) | 评论 (0)编辑 收藏

    以下内容转自韩寒的“太变态了!”
    "
     
    ... ...
    今年的超级女声开始了,
    加油好男儿也开始了,
    但是我发现,
    就我看的这些选手里,
    明显有点问题,
    仿佛两个节目弄反了,
    男的全是能挤出奶来的,
    还经常对着镜头耶耶耶耶的,
    耶他大爷..
    女的全是弄成男人样还压低嗓子说话的.
    总之就是,
    让异性看着都一点性欲没有.
    太变态了.
    太变态了.
    我相信超级女声里很多是赶时髦,
    可能性格并不如此,
    但那些男的,
    我真恨不得冲上去对着他们的裤裆就是一脚... ..."
    posted @ 2006-06-23 18:40 CowNew开源团队 阅读(343) | 评论 (1)编辑 收藏

    CowNew开源团队网站 http://www.cownew.com
    作者 杨中科 是CowNew开源团队JDBMonitor开发组的开发人员,邮箱about521  at 163 dot com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息
    以前我一直是用使用数据源的系统测试JDBMonitor,昨天我准备把JDBMonitor嵌入到一个小的jsp留言板中,这个留言板写的非常简单,数据库操作也是connection随取随用、用完了就关这种最简单的形式,这倒是帮助我发现了一个超级大bug。
    在记事本运行中常常不规律的DataBaseDBListener的logSQL方法报空指针错误,是在logStatement.setString(1, randomGUID.toString());这一句抛出的,我跟踪到mysql驱动的内部(我使用的是mysql数据库做DataBaseDBListener的输出数据库),发现在setString的实现中会去调用connection的方法,而此时connection已经是null了,所以会报空指针错误。
    从其不规律的特点我判断出应该是多线程导致的问题。我跟踪发现,有的时候是先调用DataBaseDBListener的close后logSql才被调用。经过分析找出了问题所在,问题就在DBLogger中内部类LogConsumer的startConsumer方法,这个是修改以前的代码:
    for (;;)
     {
      SQLInfo info = (SQLInfo) channel.take();    

      if(info==null)
      {
       ontinue;
      }
      for (int i = 0, n = dbListeners.length; i < n; i++)
      {
       dbListeners[i].logSql(info);
      }

     }


    在调用channel.take()以后,这个SQLInfo就从channel中去除了。这时如果DBLogger的方法被调用,那么即使dbListeners[i].logSql(info)仍然在运行,但是DBLogger会认为channel已经空了,所有的dbListeners都可以被close了,而在DataBaseDBListener的close方法中会把输出目标数据库connection关掉,那么此时如果DataBaseDBListener的logSql方法还在调用的话,那么一旦使用这个connection,那么就会出现错误了。
    我是如下修改的:
    修改BlockedChannel类,去掉其take方法,增加一个peek方法和一个remove方法,peek方法是从channel中查出一个对象,但是不把它从channel中移走,只有调用remove方法后才会被移走。
    修改DBLogger中内部类LogConsumer的startConsumer方法为如下:
    for (;;)
     {
      SQLInfo info = (SQLInfo) channel.peek();
      if(info==null)
      {
       continue;
      }
      for (int i = 0, n = dbListeners.length; i < n; i++)
      {
       dbListeners[i].logSql(info);
      }
      channel.remove(info);
     }

    也就是只有SQLInfo被处理完了,才会从channel中移走。
    看来JDBMonitor还是要多多测试多多验证,我近期准备对JDBMonitor进行性能测试,看看有没有并发问题有没有性能问题,不要再急着加新功能了,把这些基础的功能做好再说,否则别人用着用着就出现中断性错误了,那将会是比缺少功能更可怕的事情。一位同事曾经说过一句话:“做的越多错的越多。不要你做的多好,只要把已经做完的东西做的更好就可以了。”,看来确实有一定道理呀。把基本的东西做好再说,否则被人骂不专业就惨了。

    posted @ 2006-06-15 22:52 CowNew开源团队 阅读(830) | 评论 (0)编辑 收藏

    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息

    今天做的事情比较杂,所以感想也比较杂:
    1、java程序的远程调试。
    “JPDA是sun jdk自带的远程调试机制。它提供了一套标准的调试接口,可以从虚拟机一级允许外界用特定协议探测虚拟机内部的运作细节。只要你装了jdk 1.2以上的sun jdk,就已经有了jpda支持。 只要是用标准JDK中java.exe运行的应用,就可以用jpda进行远程调试。以web应用的开发为例,servlet和ejb的调试一直不是一件太容易的事情。虽然jbuilder、eclipse等有一些常见的应用服务器,如tomcat, weblogic 6.x,的调试插件,但是用法各不相同,而且很容易由于版本问题导致出现各种问题,而且对于有的服务器则没有相应的IDE插件。
    JPDA就不一样。由于它是java平台的标准功能之一,所以我们其实可以调试任何用jdk运行的程序。只需要做两件事:
    (1)、 在被调试的应用上,增加几个java虚拟机启动参数,让它启动后进入调试服务器模式;
    (2) 在本机或网络中另一台机器上用某种jpda客户端程序,attach到被调试的应用程序(可以通过socket或共享内存两种方式)。jpda本身只是一个接口,调试工具的好用与否就要看其对jpda的应用如何。jdb是sun jdk自带的命令行jpda调试客户程序,你可以用命令行设置断点,查看变量值,等等。但不是很直观。而jbuilder、eclipse的jpda调试器就做到了将jpda图形化,可以直观的设置断点,跟踪程序,查看量值,等等。 ”---本段改编自“http://www.cjsdn.com/post/print?bid=7&id=1376”

    以elipse+tomcat为例:
    (1)打开Tomcat 5.0\bin下的catalina.bat,在“set JPDA= ”下加入如下两行:
    set JPDA_TRANSPORT=dt_socket
    set JPDA_ADDRESS=8787
    (2)启动tomcat
    (3)在eclipse的debug中新建一个“Remote Java Application”,工程选择被调试的远程程序的源码工程,host填127.0.0.1,port为8787
    (4)运行调试。
    这样我们就可以在eclipse中下断点调试tomcat中运行的程序了。让那些乱七八糟的插件哪凉快去哪呆着吧。
    注意一定要保证eclipse工程中的源码和tomcat中运行的程序一致。

    2、调用对象的wait方法的时候有可能会抛出InterruptedException异常,以前我是把这个异常再次抛出,今天运行发现当这个异常抛出的时候,线程就死掉了。因此不能简单的将此异常re-throw,必须处理它,比如JDBMonitor中的BlockedChannel的take方法就要如下改写:
    public synchronized Object take()
     {
      if (container.isEmpty())
      {
       try
       {
        wait();
       } catch (InterruptedException e)
       {
        return null;
       }
      }
      Object obj = container.pop();
      return obj;
     }

    3、windows下运行linux的最好的工具
    最近一直想验证JDBMonitor在linux底下是否有bug,但是听人说过,linux安装不当很容易发生数据丢失,因此一直不敢装。而用virtual PC,VMWare之类的软件又太消耗内存,而且需要虚拟机安装完成再安装linux。今天无意中搜索到一个windows下的linux虚拟机:MetroPipe VPM 。
    下载地址:
    http://www.metropipe.net/ProductsPVPMDownload.shtml
    解压后直接运行其中的qemu-win.bat就能启动Linux。不用安装,启动关闭都非常快,而且占用内存相对来说比较小。
    唯一一个缺点就是默认就进入图形模式,抽时间看看怎么配置让它启动以后进入字符模式。
    详细可以参考:http://www.highand.com/viewthread.php?tid=545

     

    posted @ 2006-06-13 01:06 CowNew开源团队 阅读(962) | 评论 (0)编辑 收藏

    对于一个新手来说,安装Linux势必会带来很大的风险。胆子小的最后决定继续享受Windows,胆子大的有一些不幸地丢失了硬盘中的所有数据。现在你不必提心吊胆了!在Windows下你可以轻易运行Linux,无需安装,你只要下载一个MetroPipe VPM(以下简称VPM),解压后运行一下就OK了。

    QUOTE:

    MetroPipe VPM 小档案

    软件版本:不详 软件大小:83MB
    软件性质:免费 适用平台:Windows/Linux
    下载地址:http://www.metropipe.net/ProductsPVPMDownload.shtml
    软件备注:在下载页面中包含了多种下载方式,建议使用“Download.zip file via HTTP”右侧的Download按钮下载。


    VPM其实是一个多平台的小型虚拟机软件,这个压缩包中包含了一个完整的Linux版本。解压后直接运行其中的qemu-win.bat就能启动Linux(如果硬盘配置较低,启动时间会比较长),根据弹出窗口的提示回车登录Linux,出现桌面后就能和普通Linux一样cao作了。磁盘目录结构、命令等都和普通的Linux完全相同,如果想练手的话非常合适。


    *为什么鼠标逃不出Linux窗口了

    进入Linux之后,你会发现鼠标无法脱离Linux窗口了,要再次回到Windows,可以使用组合键“Ctrl+Shift”。


    *能否全屏显示

    使用组合键“Ctrl+Shift+F"(要回到窗口模式只需再按一次)就能全屏cao作Linux,但是全屏之后 屏闪比较严重,还是窗口模式比较对得起自己的眼睛。

    *在这个Linux中能否上网

    运行后直接映射Windows中当前存在的网络连接,无需手动配置。可以用Linux中自带的FireFox看网页、Thunderbird收邮件、axFTP上传文件,但可惜只支持英语

    *小提示
    要关闭时可以直接关闭窗口,也可以右键点击桌面空白处选择“Power Down→Shutdown”。


    摘自《电脑爱好者》2006年第5期 Page 40

    posted @ 2006-06-12 23:59 CowNew开源团队 阅读(1606) | 评论 (0)编辑 收藏

    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息

    我准备给JDBMonitor增加一个性能监测报表的功能。用户在“报表条件”中填写要统计的起始时间、结束时间和单位时间后,点击查询。程序从DataBaseDBListener记录的表T_LOG_SQLLog中进行统计并显示报表。例如:用户在起始时间中输入”2006-5-30 18:00:00”,结束时间输入”2006-6-1 12:00:00”,时间单位选择“5分钟”,点击“查询”。程序将把T_LOG_SQLLog中FbeginTime大于等于”2006-5-30 18:00:00”,小于等于”2006-6-1 12:00:00”的记录过滤出来。然后统计每5分钟记录的条数(也就是数据库执行的次数),以时间序列图的形式显示成报表。
    比如:
    fid       ftime
    1 2006-05-05 10:00:00.000
    2 2006-05-05 10:00:01.000
    3 2006-05-05 10:00:10.000
    4 2006-05-05 10:01:10.000
    5 2006-05-05 10:01:20.000

    这样的数据属于离散的数据,因为数据库的执行时间是不确定的,要把它们按统计它们的出现次数常常需要使用数据挖掘的东西。数据挖掘通常都是不同的数据库有不同的实现的,JDBMonitor是跨数据库的,因此肯定不能使用这些数据库特有的东西。现在也有一些开源的跨数据库的数据挖掘引擎,但是其尺寸巨大无比,都要50M以上。JDBMonitor是一个小的工具,为了方便部署和使用,JDBMontior的一个基本原则就是尽量避免使用JDK之外的类,所以肯定不能使用它们。我经过仔细思考,发现可以通过如下技巧来解决:

    select count(sub.f) as exeCount,min(sub.FBeginTime) as FTime from(
    select cast(DateDiff(ss,?,FBeginTime)/? as int) as f,FBeginTime from T_LOG_SQLLog
    )as sub
    where 1=1
    and FBeginTime>=?
    and FBeginTime<=?
    group by sub.f
    order by sub.f ASC


    其中第一、三个参数传递用户选择的时间段的起始时间,第二个参数是用户选择的计时间隔(以秒为单位),参数四是用户选择的时间段的结束时间。
    我采用的是整除的技巧来实现的这个效果。
    其中FBeginTime是SQL语句执行的开始时间(在这里我们就把它看作SQL语句的执行时间),cast(DateDiff(ss,?,FBeginTime)/? as int) as f的意思就是计算SQL语句的执行时间到选择的时间段的起始时间之间的秒间隔数,然后再整除用户选择的计时间隔(以秒为单位)。经过整除以后同一个时间段内的数据就相同了,然后我们一个groupby,然后一个count(sub.f),这样各个时间段sql的执行次数就出来了。
    以上边的数据为例,假如我输入的起始时间是2006-05-05 10:00:00.000,结束时间是2006-05-05 10:02:00.000。
    那么select cast(DateDiff(ss,?,FBeginTime)/? as int) as f,FBeginTime from T_LOG_SQLLog的结果集就是:
    f  FBeginTime
    0 2006-05-05 10:00:00.000 
    0 2006-05-05 10:00:01.000 
    0 2006-05-05 10:00:10.000
    1 2006-05-05 10:01:00.000
    1 2006-05-05 10:01:00.000 
    然后,以f为分组条件进行汇总,并统计f的count,这样各个时间段sql的执行次数就出来了:
    3 2006-05-05 10:00:00.000 
    2 2006-05-05 10:01:00.000 
    当然不同的数据库的计算日期时间差和截取整数的方式是略有差异的,我这里用的是mssqlserver的语法。

    posted @ 2006-06-12 01:30 CowNew开源团队 阅读(1079) | 评论 (0)编辑 收藏

    我上上个月申请java.net的开源服务,没想到前两天才收到抄送给我的邮件,收件人是java.net的另外一个工作人员,发件人要收件人,批准我的请求:
    发件人:"Eric Renaud"
    收件人:leads@javatools.dev.java.net
    抄送:cownew@dev.java.net
    主题:New Java.net Request to JavaTools - jdbmonitor

    To: JavaTools Community Leaders -

    https://jdbmonitor.dev.java.net/

    This project has been moved to your inbox for review.
    Please approve or disapprove ASAP.
    ......
    工作效率太慢了,我回邮件道:

    The working efficiency too lowered!
    My request to sourceforge already approved last month,I don't need your webhosting service anymore,thanks  all the same!
    没想到今天竟然收到一封中文邮件:

    对不起,你要主办项目jdbmonitor的请求你被否决。你再也不能为项目jdbmonitor访问任何资源。
    以下是否决的理由:
    Project
    owner moved to sourceforge, so, he does not want to host it at java.net
    anymore.
    关于更多信息,请联系fabiane (@dev.java.net)”
    呵呵,原来不光中国人办事效率低呀。
    posted @ 2006-06-10 22:47 CowNew开源团队 阅读(262) | 评论 (0)编辑 收藏

    CowNew开源团队网站 http://www.cownew.com
    论坛    http://www.cownew.com/newpeng/
    转载请注明此版权信息。

    ORM在整个java社区使用越来越广泛,但是随着更多的项目使用ORM,很多人也感到了它的不足:慢,甚至慢的让人无法忍受!可是让我们从ORM的原理仔细思考一下,就会发现,使用ORM并不会明显降低运行速度。因为无论什么ORM工具都是根据对象去动态构造SQL语句,执行的,相信无论构造SQL的速度多么慢,那和数据库操作比起来,几乎是可以忽略不计的。但是为什么确实又那么慢呢?归根结底,是对ORM的使用不当造成的。
    1、陋习:过渡依赖ORM的Update和delete。比如,将某个人的年龄加3,很多人就会如下写:
    PersonInfo p = orm.getPerson(...);
    p.setAge(p.getAge);
    orm.update(p);
    看看,这一来一回就要两个sql语句,先取数据:select age,id,.... from T_Person,然后再update,update T_Person set age=23....。
    相信没有ORM,谁也不会去这么写。直接写sql:update T_Person set age=age+3 where...这不很好吗?速度不会快多了吗?
    又如:删除年龄为15的人,有的人就敢这么写:
    PersonInfo persons[] = orm.getPersons("age=15");
    for(int i=0,n=persons.length;i<n;i++)
    {
       orm.delete(persons[i]);
    }

    我真的要疯了,它真的不懂delete from T_person where age=15吗??
    根据我个人的经验如果要发挥ORM的最大作用,同时最大程度的避免其副作用,我建议最好只使用orm的addNew(增加数据)和get***Info(从数据库中取数据)的功能,而对update,delete则直接写sql,这样最好。
    ORM+JDBC,优美和效率的最佳结合点。
    2、认为ORM万能。在写一些报表的时候甚至也有人用orm取出数据,然后通过代码来出报表。相信稍微复杂一点的报表就能把人搞死。所以报表,千万不能用ORM,直接写SQL是最好的事情。

    posted @ 2006-06-09 01:33 CowNew开源团队 阅读(852) | 评论 (0)编辑 收藏

    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息
           
            昨天发现JDBMonitor在多数据源的情况下会有问题,这个问题就是对单例模式理解不深造成的。为了减少系统中的对象数目,我用单例模式设计DBLogger,也就是提供一个getLogger方法返回一个日志处理器,getLogger则返回的是一个缓存了的DBLogger实例。昨天我用一个大型的信息系统测试了一下,发现当有多个数据源存在的时候,所有的日志都记录到了第一个启动的JDBMonitor的配置文件指定的监听器中了。经过分析得知,虽然多个数据源启动了多个JDBMonitor,但是由于这些JDBMonitor实例是运行在同一个JVM中的,而一个类变量在同一个JVM是唯一的,所以这些实例调用getLogger的时候得到的都是第一个JDBMonitor中配置的了。
            我采用如下方式解决:为getLogger增加一个connectionId参数,将原先的单例去掉,改成一个hash表的静态变量instanceMap。在调用getLogger的时候,先以connectionId为key到instanceMap中找是不是已经有一个实例了,如果有则直接返回这个实例,否则构造一个DBLogger,将此DBLogger以connectionId为key保存到instanceMap中,然后返回实例。
            根据JDBMonitor的功能特点配置文件的路径就可以做为这个connectionId了,也就是如果是多个数据源指向一个配置文件,那么这几个数据源其实还是共用一个DBLogger,这个也是合理的,而且也可以节省很多资源。
            从这个例子我们可以看出,单例模式并不一定是只创建一个实例这么简单。Log4j的getLogger就是很好的证明。
            但是多个数据源共用一个DBLogger又引来了另一个问题,就是当有一个数据源的Connection被close掉以后,DBLogger也会随之close掉,其他数据源再访问的时候就会报错。我采用类似GC、COM等的引用机制解决此问题。在DBLogger内部维护一个计数器refCounter,初始值是0,当调用getLogger访问到此实例的时候,就refCounter自动加1,当调用DBLogger的close的时候就自动减1,当refCounter降到0的时候就说明没有对象引用到它了,这个时候再释放DBLogger中的各种资源。当然addRef、releaseRef、close等方法都要标识成synchronized的。
            同理,以前的这些channel、dbListeners类变量也要改成实例变量。consumerthread也要改成实例变量,在close中再关闭这个线程。这样就保证了每一个JDBMonitor都有自己的消费者线程。
            为了使语意更加明确,我将getLogger重命名为createLogger。
            代码已经提交到CVS,今天晚些时候将打包放到团队网站上。
            向大家汇报,SQL解析引擎已经有阶段成果,强类型AST节点都已定义完毕,也已经可以生成最简单的CommonAST。

     

    posted @ 2006-06-06 20:55 CowNew开源团队 阅读(900) | 评论 (0)编辑 收藏

        为了测试我的一个业务系统在不同数据库上的表现,我的tomcat上配置了多个数据源,这样我可以轻松的切换系统到不同的数据源上。为了监测每个数据源的运行状况,随时观测执行的sql语句,我为每个数据源都配置了JDBMonitor,并且这些数据源的JDBMonitor的配置文件共用一个config.xml文件。

        但是在我运行的时候却发现系统报错“java.net.bindexception:  address  in  use:  jvm_bind”,根据我三十多年的从医经验判断,俺认为是端口冲突。。。。。。唉,别扔臭鸡蛋呀,呵呵。原来是我在config.xml中配置了SocketDBListener,端口为默认的9527,这样当第一个数据源使用以后,这个数据源将启动一个SocketDBListener,所以9527端口就被占用了,以后其他的数据源被时候以后在启动SocketDBListener的时候,也尝试去监听9527端口,这样就出现了如上面的错误。解决问题很简单:为每个数据源都指定一个不同的配置文件(比如config1.xml,config2.xml),并且在每个配置文件中都配置不同的端口(比如9527、9528、3721、9981等等,只要不互相重复,并且不与系统中其他软件占用的端口冲突即可)。
      
       JDBMonitor今天修改了一个在一个JVM中启动多个JDBMonitor的bug。已经提交到CVS,并更新网站下载。
    posted @ 2006-06-06 01:49 CowNew开源团队 阅读(511) | 评论 (0)编辑 收藏

    作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息

    我们经常需要将我们的程序运行中的一些信息(比如在选项对话框中的设置)记录下来,以做便再次运行的时候不用再重写填写这些数据。这对改善软件的人机可用性方面是很有用的。但是让人失望的是,现在很多Java开源软件在这一点做的很不好,每次运行都要用户去填写那些配置文件。做为最好用的数据库监控、日志工具,JDBMonitor在这方面做的是非常好的,以它的Swing界面监视器和数据库日志记录查询窗口中所有的配置信息(例如远程服务器地址、端口、数据库名称、JDBC驱动等等)都是被保存的,当再次运行的时候程序会自动加载这些配置信息,所以使用起来相当方便。
    我们接下来就来分析一下JDBMonitor是如何实现的。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
    保存加载配置文件有多种方式,比如xml文件、properties文件等,采用这些保存方式的一个问题就是如果程序是以jar,war 包等方式发布的那么这些配置文件就不能放在包中,因为包中的文件是不能在运行时改动的,只能放在磁盘的文件中,但是放在磁盘的文件中又很容易出现因为操作系统的差异、权限等问题造成程序的问题。JDBMonitor采用的则是JDK中的Preferences类来避免这些问题。
    JDK1.4中提供了Preferences类,在java.util.prefs包里面。Preferences类在不同的平台中有不同的实现方式。比如在Windows平台中,Preferences是将数据保存在注册表中的。

    为了区分不同的应用程序的参数项,在建立Preferences时要指定一个节点路径。
    Preferences是一个抽象类,提供了一系列静态方法和抽象方法来操作参数项:
     Preferences userData = Preferences.userNodeForPackage(this); //得到用户配置节点
     Preferences sysData = Preferences.systemNodeForPackage(this); //得到系统配置节点。
    比如在windows中Preferences.userNodeForPackage代表得到 HKEY_CURRENT_USER\Software\JavaSoft\Prefs下的相对路径
    Preferences.systemNodeForPackage代表得到  HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs下的相对路径

    Preferences的读取、存储是非常容易的,存储只要调用put***方法就可以,读取调用get***即可,不同的put,get方法分别用于存取不同的数据类型,详细信息可以参考JavaDoc。
    以JDBMonitor的Swing界面监视器的连接对话框为例为大家分析,打开com.cownew.JDBMonitor.listenerImpl.sckListenerClient.ConnectConfigDialog,saveConfig()和loadConfig()分别就是保存和读取参数用了,这两个方法会在超类中被调用。可以看到代码实现非常简单:
    protected void saveConfig()
     {
      Preferences prefer = Preferences.userNodeForPackage(getClass());
      prefer.put(HOST_NAME,getHostName());
      prefer.putInt(PORT,getPort());
     }
     
     protected void loadConfig()
     {
      Preferences prefer = Preferences.userNodeForPackage(getClass());
      setHostName(prefer.get(HOST_NAME,""));
      setPort(prefer.getInt(PORT,9527));
     }

    posted @ 2006-06-02 23:48 CowNew开源团队 阅读(961) | 评论 (0)编辑 收藏

    作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息

    数据库监控、日志工具JDBMonitor在介绍文档中说到“JDBMonitor另起一个线程来记录SQL,所以它不会对程序运行速度有任何影响。”,那么它是如何做到的呢?
    JDBMonitor采用“生产者-消费者模型”完成此功能。学过操作系统原理的朋友对“生产者-消费者模型”一定不陌生,它是和“哲学家进餐问题”等相提并论的经典模型。
    JDBMonitor的主线程做为“生产者”,产生“日志信息”这个产品,另起一个线程做为消费者,这个消费者负责“消费”日志信息,并把日志信息派发给所有的监听者,这样日志的产生和消费是独立的,所以无论日志的派发有多慢,都没有关系,都不会影响到主线程的运行速度。下面让我们深入研究一下:
    (注:JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。)
    打开com.cownew.JDBMonitor.common.DBLogger。JDBMonitor每次截获到一条sql语句,都会调用logSQL方法,并把sql语句的信息对象传过来,这样我们就可以把logSQL方法当成生产者,logsql把消息放到channel中。LogConsumer是一个实现了Runnable接口的类,它就是日志的消费者,并且是运行于另一个线程的,它负责实时检测channel,只要channel中有东西,他就从channel取出日志对象,然后发送给各个监听器。
    startConsumer中
    for (;;)
    {
      SQLInfo info = (SQLInfo) channel.take();
      for (int i = 0, n = dbListeners.length; i < n; i++)
      {
        dbListeners[i].logSql(info);
      }
    }
    就是在实时检测channel中的产品。
    channel是一个阻塞通道BlockedChannel的实例,这个阻塞通道主要提供两个方法offer,take,offer方法向通道中放入产品,take从通道中取产品,当通道中没有产品的时候,take方法将会阻塞,直到有产品为止。BlockedChannel是靠java的wait-notify机制实现的,原理非常简单,有兴趣的朋友看一下其实现代码就可以。
    值得注意的是,LogConsumer是一个后台线程,因为如果LogConsumer不是后台线程,那么由于LogConsumer一直在无限循环里执行,所以程序就不能正常终止。而设置为后台线程后,在其他工作线程停止后,此线程就会自动终止。关于“后台线程”的知识,可以查看相关资料。
    但是采用后台线程以后,又有另一个问题出现了,在主线程停止后,有可能产品通道channel中还有没有发送完的日志信息,这样就会造成漏记日志信息。
    Runtime 类有一个addShutDownHook方法,可以调用此方法向JVM注册一个监听器,这个监听器必须实现Thread接口,在JVM停止之前,这个监听器将会被运行,这样我们就可以在JVM停止之前做一些事情了。
    JDBMonitor就是用addShutDownHook解决此问题的。见DBLogger的静态初始化块:

    Runtime.getRuntime().addShutdownHook(new Thread(){
      public void run()
      {
        //once JVM will shutDown,this hook will pause the shutingdown
        //until all the SQLInfo be dispatched
        while (!channel.isEmpty())
        {
          try
          {
            Thread.sleep(SHUTDOWNSLEEPMSECOND);
          } catch (Exception e)
          {
            throw CommonUtils.toRuntimeException(e);
          }
        }
        ...
       }
    }); 

    在JVM停止之前会首先检测产品通道中有没有产品,如果还有,则会一直等到产品被消费完后再终止。

     while (!channel.isEmpty())
        {
          try
          {
            Thread.sleep(SHUTDOWNSLEEPMSECOND);
          } catch (Exception e)
          {
            throw CommonUtils.toRuntimeException(e);
          }
        }

    posted @ 2006-06-02 23:46 CowNew开源团队 阅读(940) | 评论 (0)编辑 收藏

    作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息

      有一定开发经验的朋友在处理异常的时候都不会直接写个e.printstacktrace()来“捕获”异常,但是在有些情况下是“无法抛出”异常的,比如一些重载基类的一些方法,但是这些方法是没有声明异常抛出的,或者在类的static初始化块的时候也是“无法抛出”异常的。其实“无法抛出异常”的地方还是能抛出运行时异常的。
    最好用的数据库监控、日志工具JDBMonitor就是通过这种方式解决此问题的。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
    JDBMonitor在CommonUtils总定义了一个toRuntimeException方法,用来把异常转换成运行时异常:
    public static RuntimeException toRuntimeException(Throwable e)
    {
     RuntimeException re = new RuntimeException(e);
     re.setStackTrace(e.getStackTrace());
     return re;
    }
    让我们首先打开com.cownew.JDBMonitor.jdbc.DBDriver,然后定位到代码的最后
    static
    {
        try
        {
     DriverManager.registerDriver(new DBDriver());
        } catch (Exception e)
        {
     throw CommonUtils.toRuntimeException(e);
        }
    }
    这是在类的初始化块中向DriverManager注册JDBC驱动,在初始化块中是不能声明抛出异常的,因此JDBMonitor将异常转化为RuntimeException异常抛出。这样就做到了不放过任何一个异常。

    再打开:
    com.cownew.JDBMonitor.listenerImpl.sckListenerClient.ListenerClient.java中的SocketListener类,其中的run方法是实现的Runnable接口中的方法,而Runnable接口中的Run方法是没有声明异常的,因此JDBMonitor也是采用的转换成RuntimeException的方式进行的异常处理:
    public void run()
    {
      try
      {
     ...
      } catch (IOException e)
      {
        throw CommonUtils.toRuntimeException(e);
      } catch (ClassNotFoundException e)
      {
        throw CommonUtils.toRuntimeException(e);
      }
    }

    posted @ 2006-06-02 23:46 CowNew开源团队 阅读(813) | 评论 (0)编辑 收藏

    作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息

    正则表达式是一个非常强大的工具,有了这个工具,在进行字符串的解析、修改等不会再麻烦,比写一堆if else语句更清晰易懂。
    关于正则表达式的基础知识我这里不再多讲,大家可以到网上查找相关的资料。本文假定您已经熟悉正则表达式的基本使用。
    让我们以最好用的数据库监控、日志工具JDBMonitor为例来讲解。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
    DataBaseDBListener要读取形如"dburl=jdbc:odbc:MQIS;user=sa;password=sa;logtable=T_Log_Log"的配置字符串,然后从中解析数据库连接配置、表名等信息,并且user=sa;password和logtable部分也是可以忽略的(这是当然的,因为有的数据库不需要用户名密码,而且logtable也有默认值)。
    打开com.cownew.JDBMonitor.listenerImpl.DataBaseDBListener,init就是进行参数arg的解析的:
    1、Pattern patAll = Pattern.compile("dburl=(.+?);?(user=.*;password=.*;)?(logtable=.+)?");
    这句是从arg中提取三个部分,分别是dburl部分,用户名密码部分,logtable部分。因为用户名密码部分,logtable部分是可以忽略的,因此采用"?"来标识这个两个分组“(user=.*;password=.*;)?”、“(logtable=.+)?”。而一旦dburl部分,用户名密码部分忽略,那么dburl=...后的;也是可以忽略的,因此";?"。
    值得我们注意的是“dburl=(.+?)”,为什么不是"dburl=(.+)"呢?怎么多了个?。你可以尝试去掉“?”后,再次运行。你会看到dburl=后所有的字符,包括用户名密码部分,logtable部分都被看成dburl=的值了,也就是后边的字符都被吃掉了。为什么呢?
    这就要提到正则表达式的贪婪性和懒惰性,关于贪婪性和懒惰性可以查看网上一篇文章《深入浅出之正则表达式》(http://dragon.cnblogs.com/archive/2006/05/08/394078.html)。
    象《深入浅出之正则表达式》描述的那样:“+”是贪婪的。也就是说,“+”会导致正则表达式引擎试图尽可能的重复前导字符。只有当这种重复会引起整个正则表达式匹配失败的情况下,引擎会进行回溯。也就是说,它会放弃最后一次的“重复”,然后处理正则表达式余下的部分。一个用于修正以上问题的可能方案是用“+”的惰性代替贪婪性。你可以在“+”后面紧跟一个问号“?”来达到这一点。“*”,“{}”和“?”表示的重复也可以用这个方案。
    因此JDBMonitor就采用了dburl=(.+?)来解决这个贪婪性问题。
    2、Pattern patUserPwd = Pattern.compile("user=(.*);password=(.*);");
    在第一步中把“user=sa;password=sa;”当成一个整体来提取,那么我们接下来还要从这个提取中的串中提取用户名user、密码password信息。因此采用这种方式来提取。这种分步提取的方式比写复杂的正则表达式一次性提取看起来更清晰,更加易维护。

    posted @ 2006-06-02 23:43 CowNew开源团队 阅读(909) | 评论 (0)编辑 收藏

    作者杨中科是CowNew开源团队JDBMonitor项目组的开发人员。
    CowNew开源团队网站 http://www.cownew.com
    论坛 http://www.cownew.com/newpeng/
    转载请注明此版权信息

    我个人是极力反对不必要的downcasting的,但是在使用java的集合类的时候确是不可避免的,因为JDK5之前的集合中只能存储Object类型,所以看到一个List的时候,你也不知道里边放的是什么数据类型,只能胆战心惊的来下转型:Integer i = (Integer)list.get(i)。
    好在JDK5可以使用泛型了,这个问题也就迎刃而解了。这样就再也不会去去问其他开发人员“你List里放的是什么类型的对象?”,再也不会望着一大堆以“老祖先”形式表现的object了发呆了,终于可以看到容器中存的这些对象的类型了。
    但是在有的情况下我们还是不能使用JDK5的,比如你的正在开发的系统是基于JDK1.4的,那么迁移到JDK5是有一定风险的,或者你开发的模块要被JDK5一下的程序使用的,那么就暂时放弃JDK5的这个新特性了。
    那么没有泛型我们就没法解决这个问题了吗?非也!鸟枪!呵呵。
    一种方式是自己包装一下List写一个自己的专有数据类型的List,比如
    class IntegerList()
    {
       private List list;
       ......
       public void add(Integer i)
       {
         list.add(i);
       }
       public Integer get(int i)
       {
          return (Integer)list.get(i);
       }
    }
    这样做的缺点就是对每个数据类型都要生成一个集合类,无疑加大了代码量。
    另一种方式就是使用数组解决此问题,因为数组中的数据类型是清晰的,比如Integer[] ia = new Integer[5];,一眼就可以看出其中存储的是什么类型。
    最好用的数据库监控、日志工具JDBMonitor就是通过这种方式解决此问题的。JDBMonitor的二进制jar包和源代码都可以从 http://www.cownew.com 下载得到。
    打开com.cownew.JDBMonitor.jdbc.connect
    定位到:
    List lisList = configInfo.getListenerInfoList();
    DBListenerInfo[] dbListenerInfos = new DBListenerInfo[lisList.size()];
    for(int i=0,n=lisList.size();i<n;i++)
    {
        DBListenerInfo lisInfo = (DBListenerInfo) lisList.get(i);
        dbListenerInfos[i] = lisInfo;
    }    
    return new DBConnection(cn,dbListenerInfos);  
    程序把多个监听器对象信息DBListenerInfo拼转成DBListenerInfo数组,然后传递给DBConnection。
    DBConnection接收到dbListenerInfos会把它转发给DBLogger做为其构造函数的参数:
    private DBLogger(DBListenerInfo[] dbListenerInfos)
    这样在DBLogger内部就可以很清晰的知道dbListenerInfos中的数据类型了:
    for(int i=0,n=dbListenerInfos.length;i<n;i++)
    {
       ...
       DBListenerInfo info = dbListenerInfos[i];
       ...
    }

    在系统的接口边界处传递的数据类型非常明确,不会因为传递一个光秃秃的List而不知道其类型,然后胆战心惊的进行类型转换了。
    因此我认为在一个方法或者类的内部可以采用List等进行数据的处理,但是当需要与外部(相对于类来说就是其他类,相对于方法来说就是其他方法)交换多个同构对象的时候,最好转换成数组传递,这样就清晰多了。

    posted @ 2006-06-02 23:41 CowNew开源团队 阅读(744) | 评论 (0)编辑 收藏

    作者杨中科

    CowNew 开源团队网站 http://www.cownew.com

    论坛 http://www.cownew.com/newpeng/ 

    转载请保留此信息

    一、HQL代码的构建。
    (1)首先将hibernate中的src目录下的代码解压。
    (2)安装配置好antlr。
    (3)把grammar目录下的三个.g文件(hql.g,hql-sql.g,sql-gen.g)解压到一个目录,然后从命令行进入此目录,依次运行"java antlr.Tool hql.g","java antlr.Tool hql-sql.g","java antlr.Tool sql-gen.g",将生成的java代码拷贝到源代码的org.hibernate.hql.antlr下。
    二、让我们从QueryTranslatorImpl开始分析,当调用session.find('...')的时候将会调用QueryTranslatorImpl的compile方法来解析hql语句为sql语句。compile则主要是调用的doCompile方法。
    // PHASE 1 : Parse the HQL into an AST.
    HqlParser parser = parse( true );

    // PHASE 2 : Analyze the HQL AST, and produce an SQL AST.
    HqlSqlWalker w = analyze( parser, collectionRole );
    sqlAst = ( Statement ) w.getAST();
    generate( ( QueryNode ) sqlAst );
    queryLoader = new QueryLoader( this, factory, w.getSelectClause() );

    parse的主要代码:
    private HqlParser parse(boolean filter)
     HqlParser parser = HqlParser.getInstance( hql );
     parser.statement();
     AST hqlAst = parser.getAST();
      return parser;
    }
    analyze的主要代码:
    private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException {
     HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole );
     AST hqlAst = parser.getAST();
     w.statement( hqlAst );
     return w;
    }
    generate的主要代码:
    private void generate(AST sqlAst) throws QueryException, RecognitionException {
     SqlGenerator gen = new SqlGenerator(factory);
     gen.statement( sqlAst );
     sql = gen.getSQL();
    }

    可以看到主要是三步:调用parse方法将hql解析成AST,调用analyze根据上一步生成的AST生成SQLAST,调用generate根据上一步生成的SQL AST生成sql语句, 调用w.getSelectClause()就得到sql语句了。
    “用parser把ast抽取出来,再用treeparser进行动作的double pass builder模式,解耦了parser和generation,再配合template,是antlr推荐的最佳模式。”-《看Hibernate3如何解释HQL语言》
    1、三个语法文件的作用:

    hibernate的hql grammar文件一共有三个,在/grammar目录下:
       1.hql.g   定义token类和parser类,将hql解释成hql的抽象语法树(ast)
       2.hql-sql.g  定义tree walker ,将hql ast转化为sql ast,将生成模块与hibernate解耦。
       3.sql-gen.g 定义tree walker,从sql ast生成sql
    ”-《看Hibernate3如何解释HQL语言》
    2、
    逐步分析:
    (1)parse方法:
    HqlParser是从hql.g生成的HqlBaseParser继承来的,主要实现了HqlBaseParser定义的几个模版方法,传入的是hql语句,传出的是HQL AST。
    (2)analyze:
    HqlSqlWalker是从hql-sql.g生成的HqlSqlBaseWalker继承来的,HqlSqlBaseWalker又是从TreeParser继承的,主要实现了HqlSqlBaseWalker定义的几个模版方法,传入的是HQL AST,传出的是SQL AST。
    hql-sql.g比hql.g简单许多了,因为hql-sql.g已经为我们生成了HQL AST了,hql-sql.g需要做的就是把HQL AST组装成强类型的SQL AST,此处大量引用了hql.g中定义的Vocabulary。
    比如:
    query!
     : #( QUERY { beforeStatement( "select", SELECT ); }
       // The first phase places the FROM first to make processing the SELECT simpler.
       #(SELECT_FROM
        f:fromClause
        (s:selectClause)?
       )
       (w:whereClause)?
       (g:groupClause)?
       (o:orderClause)?
      ) {
      // Antlr note: #x_in refers to the input AST, #x refers to the output AST
      #query = #([SELECT,"SELECT"], #s, #f, #w, #g, #o);
      beforeStatementCompletion( "select" );
      processQuery( #s, #query );
      afterStatementCompletion( "select" );
     }
     ;
    这里主要就是在调用模版方法拼状强类型的SQL AST(异构AST)。所有的节点都定义在org.hibernate.hql.ast.tree中。
    与第一部的HqlParser用户几乎不用写任何代码相反,我们需要完成我们从HqlSqlBaseWalker继承来的HqlSqlWalker的那些模版方法。
    (3)generate方法:
    遍历SQL AST,输出sql语句。SqlGenerator是从sql-gen.g生成的SqlGeneratorBase继承来的。输入的是SQL AST,输出的是SQL语句。我个人认为这一步也可以通过全部书写代码完成,可能更清晰,更灵活。
    selectExpr
     : e:selectAtom { out(e); }
     | count
     | #(CONSTRUCTOR (DOT | IDENT) ( selectColumn )+ )
     | methodCall
     | aggregate
     | c:constant { out(c); }
     | arithmeticExpr
     | PARAM { out("?"); }
     | sn:SQL_NODE { out(sn); }
     | { out("("); } selectStatement { out(")"); }
    其中的out("(");就是在拼装代码。

    posted @ 2006-06-02 00:56 CowNew开源团队 阅读(4973) | 评论 (2)编辑 收藏