Home 博客

知力企业博客

A short description about your blog

从ASP.NET MVC框架迁移到Ruby on Rails

Posted by: bin in Untagged  on

TekPub是一个面向开发人员的站点,致力于为开发人员提供一系列主题的在线培训,主题范围非常广泛,从微软的O/R Mapping框架Microsoft Entity Framework,到如何使用Ruby on Rails技术编写自己的日志引擎等内容都有涉及。该网站是由前微软员工Rob Conery与Lounge的老板James Avery创立的。

TekPub是个很有趣的学习案例,公司开始时使用ASP.NET MVC框架,之后很快迁移到了Ruby on Rails上。InfoQ与Rob和James探讨了这次迁移之旅。

InfoQ:和我们谈谈TekPub吧,对于哪些不熟悉你们的产品的读者,TekPub意味着什么?

James Avery(简称JA):TekPub为程序员提供了高质量的技术视频演示。我们的目标是帮助一些人在几个小时内学习一项新技术,主要方式就是观看一些牛人的演讲视频。他们对演讲的技术非常了解,演讲内容不仅仅覆盖基础知识,还深入到了这些具体技术在真实项目中的应用。与其等几个月才拿到一本很可能已经过时的书,还不如订阅我们的产品立刻获得新技术的提升。我们已经完成ASP.NET MVC 2的系列视频,但目前还没有与这个主题相关的书籍。

InfoQ: James Avery和Rob Conery有什么来头?

JA:除了TekPub之外,我还搞了几个科技创业公司。我运营了Lounge和Ruby Row广告网络,分别关注.NET和Ruby开发人员。我还帮助运营DotNetKicks公司,一个.NET开发人员的社区网站。我最新的关注点是Adzerk,这是我自己构建的Web服务器,用来有效的运行Lounge和Ruby Row,让其他人来使用。从90年代中期我就开始使用Web,.NET发布后,我开始转移到微软的技术上。最近我一直再用.NET、Ruby on Rails和MongoDB等,还有任何让我感兴趣的技术。

Rob Conery(简称RC):我自1991年以来一直从事软件行业,做一些数据库,CGI和HTML之类的开发。从1997年开始使用ASP,从那之后一直坚持使用微软技术。2006年我开始为微软工作,主要职责是帮助人们学习和使用新的ASP.NET MVC框架。2009年我离开了微软开始做些不同的事情(更多的关注开源平台),之后和James Avery一起创办了Tekpub。

InfoQ:能介绍一下你们刚创业时TekPub的架构吗?

JA:TekPub的第一个版本是基于Ruby on Rails构建的,当时Rob花费了整整一个周末的时间。之后我们仔细的进行了讨论,最终决定放弃这个版本。由于我们都很了解ASP.NET MVC技术,所以决定用ASP.NET MVC来实现TekPub。我相信,当开始一项新业务时是没有时间尝试和学习新技术的。Rob和我过去都写过Rails应用,但真正使用时,我们都觉得ASP.NET MVC比Rails好得多。于是我们放弃了Rails转而使用ASP.NET MVC技术开发网站。后来我们取消该站点并重新构建它,因为它已经变得太复杂。在我们开始进行技术迁移时,TekPub的版本是3,主要技术是ASP.NET MVC,C#和MS SQL Server。

InfoQ:从网站使用者的角度你遇到了什么样的挑战?从网站管理者的角度呢?

RC:最初,或者说网站运营的第一天,我们就遇到了网络带宽的问题。我们在Twitter上宣布网站开张,这直接导致我们的ISP由于带宽的需求被淘汰。他们毫不夸张的让工程师“坐在开关上”来保证网站的正常运行,但最终网站还是停了。之后两小时内我把我们所有免费的内容都放到了亚马逊的S3上,这对我们帮助非常大。

还有,一小部分人不喜欢Silverlight,不愿意安装它。我们在Reddit上投放了广告,人们却简单的认为我们的网站是微软资助的一个什么东西——这是和我们的目标背离的。对我们来说这是个大问题。

JA:ASP.NET MVC运行的很好,Windows架构也不错。事实上我们在这个领域没碰到什么麻烦。主要的挑战来自于我们决定使用Silverlight播放流媒体。很多用户不愿意安装Silverlight,这给我们带来很大的困扰。与Rob确认后,我们不得不迁移到Flash技术。迁移到Flash之后还没有一个人抱怨过。我们希望HTML5很快面世。

InfoQ:架构如何应对用户需求?

RC:我们从来没有遇到底层框架的问题——它处理的很好。这并不是一个负载非常大的网站(在功能方面),所以我们从没真正遇到那方面的问题

InfoQ:既然平台运行的非常好,为什么要做架构的改变呢?

RC:成本。我们加入了微软的BizSpark计划,而且它的确给了我们一个很棒的起点,但是随着项目的发展,我们发现,3年以后,从我们使用的数据库到开发环境,每一件事情都需要付费。而且我们很可能需要为Silverlight(使用流媒体)提供一个分离的服务器,用来播放视频,这样就需要再支付一个使用许可的费用——此外,为了使视频流平滑输出,我们还需要买媒体编码器。

对于大公司来说,这的确不算什么,但当我们坐下来看帐单时——噢,这可是个5位数啊。最终我们发现,根据我们现有的业务规模,是无法承担这笔费用的。

不仅仅如此,James和我都清楚Rails非常好用。我们意识到可以把所有事情都推到云端,只需支付很低的价格就可以获得很好的流媒体和吞吐量。

JA:正如Rob提到的,成本压力是其中一个因素,BizSpark是很好,但却像一个定时炸弹。我觉得比成本更重要的推动因素是每天我们希望使用什么技术。ASP.NET MVC和.NET技术在某些领域是有缺陷的,而这些领域的工作对我们非常重要。在.NET上做测试就并不让人满意,你不得不大费周章才能以正确的方式设计你的应用,处理测试,而且编写测试本身也不像其他语言那么清晰和有用。另一个问题是部署,虽然有很多种方式可以处理,但确实不如Capistrano好用。

InfoQ:那么现在TekPub平台是什么样子的?

RC:我们迁移到Rails 2.3.5,使用了针对MongoDB的MongoMapper技术。我们做了一个报告设置,用MySQL来跟踪反馈使用DataMapper的情况。我们还植入了New Relic RPM,来跟踪我们的站点和健康情况——所有的这些,平均成本仅仅是我们使用BizSpark的1%。

JA:这解决了我们所有与使用许可有关的问题,我们每月需要为Amazon EC2平台上的一个Ubuntu实例支付$80,这是保留实例后的费用。Rob和我都很喜欢这种技术,我们使用Cucumber做了大量测试,用Capistrano部署变得非常简单容易。

InfoQ: 能给我们讲讲你们的技术架构细节吗?

RC:使用Rails 2.3.5及其对应的MongoMapper/MongoDB,使用MySQL 5.2和O/R Mapping工具DataMapper。我们还用了New Relic RPM工具,非常棒。

JA:我们选择使用Rails 2.3.5和Ruby 1.8.7,通过Passenger运行Rails应用。在数据库方面,我们通过使用优秀的MongoMapper gem访问MongoDB 1.3.4。我们还通过DataMapper实现MySQL 5.1的数据访问。我们并不使用很多其他的Gem,只是用Pony发邮件,rpx_now访问RPX做身份验证。同时我俩还都是HAML的爱好者,所有的界面都是基于HAML实现的。

InfoQ:你们的EC2怎么配置的?

JA:所有的内容都是托管在云端,相当于一个比较小的服务器,也就是一个单独的EC2实例(虚拟双核,2个计算单元,7G内存)。在这个实例上运行着Ubuntu 9.1(karmic)和Apache。我希望未来有更多的资源,你知道,运行在EC2上,想增加资源是非常容易的。

InfoQ:为什么选择Ruby on Rails?

RC:James和我都知道,插件的世界是非常吸引人的。例如New Relic,简直是上帝送来的礼物。我不担心服务器挂掉,而且我能看到所有代码的“瓶颈点”。他们还能跟踪最高发生频率的问题,甚至会提出改进意见。

MongoMapper是一个令人难以置信的数据工具,而MongoDB本身的速度比闪电还快。Rails的平台已经成熟到了这样的地步,几乎难以说服自己*不*使用它。

JA:我们遇到的所有问题(使用许可、测试和部署)都得到了很好的解决。我们还能使用一些变通的办法,例如写自己的部署框架等。随之而来的是我们都很享受与Rails工作,我们喜欢Rails社区,还有很多工具和类库可用。经过迁移之后最棒的地方就是,这一切让我们变的非常高兴。

InfoQ:相对很多传统数据库例如MySQL或者PostgreSQL,你们为什么选择MongoDB?

RC:速度和扩展性。使用MongoDB非常简单——不用担心迁移,非常灵活。而且它不可思议的快——这一点对用户带来的感受是巨大的。

JA:事实上我们都用了,我们用MongoDB做那些它最擅长的(灵活存储产品、用户和订单等信息),同样我们也这么使用MySQL,我们用MySQL提供正在发生的持久事务日志。

InfoQ:完成了新的设计和重写应用之后,最直接的好处是什么?

RC: 最直接的——第一件事就是人们发现网站变快了。他们还注意到一个“更严格”的设计,诚实的说,确实有些繁琐,但它让我们能更多的关注服务器端。

不仅仅如此——当出现问题时,我们可以在几秒钟之内消除它。这是由于基于Capistrano的部署是如此简单。问题的修复、推出——仅需几秒。

我们的测试套件使用的非常好——使用Cucumber做一些事情简直是一种享受,但用ASP.NET MVC就会很困难。例如——使用ASP测试PayPal的支付接口时就会很麻烦。

基于Rails/Cucumber/Webrat,在这样的框架下要做的就是填空并提交——然后确认所有事情都是按照计划执行的。我想我们的用户会看到很多功能在按照预期的方式运行——这确实很棒。

最直接的好处是我们想做一些变化时,可以快速完成,并且这种响应速度直接反应到了产品上。在原来基于ASP.NET MVC技术的网站上,我经常会写些SQL脚本来处理一些复杂的支持需求,比如改变某人的OpenID,或合并帐户什么的。但现在我只需花30-60分钟的时间写了几行的Ruby脚本就能完成。

在重写网站过程中另一个重大的改变之一是如何处理用户的文件。过去我们从自己的服务器或运行在EC2上的Wowza媒体服务器上以流的方式处理文件。这两种方案都可以,但是太贵了,而且在其他国家就运行的没那么好了。这次我们开始重新设计亚马逊服务,提供了从云端和云端流来处理私有内容的能力。现在我们的全部内容都是通过云端处理,并使用了安全签名的URL,这就意味着世界上任何地方的用户都可以进行高速下载。这也节省了我们的成本,因为我们只需支付使用带宽的费用,不需要额外的设备或许可费用。

InfoQ: 在你们当前的实现中,TDD测试方法包含哪些内容,引入模拟对象了吗?

JA:我们用Cucumber和Pickle实现测试驱动开发。这方面Rob应该比我更清楚。

RC:没有进行模拟测试,都是BDD(行为驱动开发)。我痛恨那种拖拉的感觉,就像我需要做“代码覆盖率”一样——事实上我们有个商业应用在运行,我更需要确认用户获得良好的体验,这对我来说就是BDD。Cucumber扮演了一个真正的重要角色——就像Pickle和Factory Girl做的那样——它与MongoMapper配合的好极了,对比我在微软框架下做的和我现在能做的事情,这让我高兴的笑了好几次。我几乎完全在考虑业务——甚至没有注意到测试方法这回事。

InfoQ: 你们现在的测试方法和以前在微软使用的方法有什么不同?

RC:100%不同。测试微软的东西是极其痛苦的,当时你很穷,还有三个月钱就花完了,在这种情况下,测试就是变成了一个很难判断的的东西。不可否认——我为我们的第一次修改几乎写了一吨的垃圾。如果你没有客户,那么你的应用系统好不好用就无关紧要,我真正需要确定的是不出现那些不可预期的错误。所以我进行了一些测试,但并没有得到想要的结果。我们对PayPal的东西进行了大量地测试,这是你必须要做的。当开始使用他们的API时,我在他们的沙箱环境中折腾了整整三天,还是会不断的出问题。

另一边呢——感觉是黑夜和白天的对比。现在我们覆盖了所有的行为类型,我想James甚至抽时间写了一些。

JA:对微软产品的测试总是像打一场战争,主要是因为C#和静态语言对测试的支持不是很好。在.NET上测试时你总是需要在各种循环中跳来跳去。话虽这么说,.NET的SpecFlow框架看上去还是很乐观,但我对它能解决.NET的测试方面的所有问题持怀疑态度。

InfoQ: 在微软框架上做测试会有多少困难?为什么会这样?

RC:语言和工具造成的。假如微软对这一点想的多一些,测试可能会更容易一些。使用RSpec进行测试,没有其他语言比Ruby做得更好了——它让测试变得非常容易。微软可以利用DLR实现这些功能……但是他们没有这么做。因为这不符合“.NET Story”,那么好吧,这是他们的商业决策,我们这次的迁移也是一样。

InfoQ: 在这次全面的重新设计中,你们有什么经验教训吗?

RC:没什么——我想James和我都知道,我们到了需要调整和重写的那个点。这是我的第三次创业,对James来说应该是第五次。开始时我们经过很长的时间讨论采用什么技术。我们都同意我们要“跟随你所知道的,并且去实现它”——于是我们就做了。

我们很幸运把握住了这个机会——然后我们进入了这样一个状态:“好吧,让我们开始为之后的3-5年规划,进入可控的增长模式”——这就是我们现在的状态。我们不想做得很大,我们不想引入IT人员或一组开发人员。我们想自己做而且保持小的规模——重点放在了我们的创意上。

对于我们这样的两个家伙来说,Rails超级简单,易于维护。我们有世界上最可靠的支撑(可自动扩展的亚马逊EC2),我们对正在做的事情非常满意,获得了很多乐趣。

JA:我想大部分人看到这个故事,会认为我们应该从开始就使用Rails,事实上我很高兴我们没有那么做。开始创业时我想我们要相信自己的直觉,哪些是当时我们认为最好的,我们应该关心所有的业务问题,而不是使用什么工具。现在业务已经正常运转,在这样一个坚实的基础之上,我们就有了很多美妙的时光,释放内心的渴望做一些好玩的事情。平台移植让我们享受了很多乐趣。

InfoQ: 你们现在的架构有什么缺点吗?如果今天开始重新做一遍的话,有什么改变吗?

RC:从我的观点来看没什么——我爱现在的一切。对我来说这很不可思议——我在很长一段时间内曾是一名微软员工,并被扣上了这样一顶帽子……其实这对我们来说并不意味着什么。我非常喜欢硬件成本的可扩展性——我想在很长时间之内我们不再需要其他的硬件方案了。我们的服务器非常灵活,完全根据需求动态扩展。使用微软技术你就没法做到这些(据我所知),如果你想搞一台独立的机器,那你就需要支付一大笔款项。

JA:针对现有架构,我唯一想做的改变就是把MongoDB从我们的单一服务器上分离出来,同时运行两个MongoDB对我们来说是有意义的,但现在这部分功能被废弃了,对我们来说更有意义的事就是等MongoDB开发新的配对策略。但是考虑到额外的两个虚拟机的成本,以及我们的业务在现有的单一服务器上运行良好,我们暂时还不准备这么做。


社会化网络的B2C电子商务模式

Posted by: bin in Untagged  on

社会化网络营销和电子商务的结合是近年来新型Web 2.0电子商务网站的发展趋势,这种新型的电子商务模式和传统的B2C网站有很大不同,有很多独特的模式,下面我就以Groupon网站为例分析一下基于社会化网络的B2C电子商务的商业模式。

Groupon并不是一个纯粹的电子商务网站,它是电子商务、web2.0、互联网广告以及线下模式的结合体。目前的表现形式是团购,收入模式是依靠收取提成等,据《纽约时报》报道,美国团购网站Groupon恐怕已经成为史上最疯狂的互联网公司。Twitter达到10亿美元估值用了3年时间,Facebook达到10亿美元估值用了2年时间,而Groupon只用了一年半。

Groupon的商业模式特点:

1、电子商务的社会化营销:微博、SNS、电子邮件等社会化网络营销。

2、极低价格的产品:大多是非实物产品,因为实物产品很难有低折扣,一些团购网初期有可能自己贴钱营销。

3、用户习惯培养:每天一次服务,和博客的每天更新非常像,用来提高用户黏度。

4、界面简单:简单就是美,大为简化购物流程,减少用户的购物时间,提高消费者的购买效率。

5、稀缺营销:每天只卖一个产品,购买时间倒计时,购物人数有底线。

5、线上服务:替代街头发小广告的服务

6、用户群体精准:习惯于使用网络购买方式和容易被折扣所吸引的年轻人……

7、吸纳优质商户:通过商务独特的商品或服务吸引用户。

2192_3

Groupon网站的SWOT分析:

优势:

1、成本低廉:有较为低廉的团购程序可购买,网站简单,易维护,运营成本低。

2、盈利快:做为电子商务网站,从一开始就能实现盈利,以保证网站的长期持续发展。

3、政策扶持:某些地方政府,例如深圳,对于互联网电子商务表现出扶持的态度,大多数政府部门也不会有意阻碍电子商务网站的发展。

劣势:

1、竞争激烈:已经存在大量竞争对手,较为知名的如美团网等。

2、运营困难:运营网站对消费类商家可能不熟悉,联系商家确认产品有难度,通常网站可能缺少社会化媒体推荐经验,也缺少个人用户销售经验。

机遇:

1、市场潜力:一些核心一线城市还缺少足够服务,市场潜力大,目前还没有类似社会化电子商务产品的垄断产品存在。

2、风险投资:运营此类业务的网站有获得风险投资的先例。

威胁:

1、发展前景:新型的电子商务模式,前景不明朗,有可能会失败;目前在国内还没有成功案例,未来具有很大的不确定性。

2、运营风险:运营模式可能会带来人力资源成本,线下销售团队规模远超线上团队。

总结:

2192_1

上面说了这么多,用一张图片来总结更清晰一些,上图是我做的一个关于电子商务网站业务分析的图片,不仅仅包括Groupon,还包括Blippy、Alibaba、Intuit等网站,限于篇幅就不再多说。


通过离线工具向Joomla发布文章

Posted by: bin in Untagged  on

在线写博客是不错的选择,可惜的话,如果文章中包含图片的时候,就觉得相当于力不从心,借助向windows live writer这样的工具话,我们很方便在客户端本地就可以发布博客文章,WLW是一个类似word一样的文字编辑工具,如果操作起来非常的方便。下面就给大家介绍一下:

 

客户端设置:

  打开WLW,配置的时候,要选择其他博客,要对应的地址里输入:http://www.cheeli.com.cn/xmlrpc/index.php

 

cheeli_blog

 

再输入博客的帐号和密码,就可能发布了。本篇文章就是通过WLW发布的。


十大建议 改变电脑操作系统的安全等级

Posted by: bin in Untagged  on

无论你现在使用的操作系统是什么,总有一些通用的加强系统安全的建议可以参考。如果你想加固你的系统来阻止未经授权的访问和不幸的灾难的发生,以下预防措施肯定会对你有很大帮助。

  1、使用安全系数高的密码

  提高安全性的最简单有效的方法之一就是使用一个不会轻易被暴力攻击所猜到的密码。

  什么是暴力攻击?攻击者使用一个自动化系统来尽可能快的猜测密码,以希望不久可以发现正确的密码。使用包含特殊字符和空格,同时使用大小写字母,避免使用从字典中能找到的单词,不要使用纯数字密码,这种密码破解起来比你使用母亲的名字或你的生日作为密码要困难的多。

  另外,你要记住,每使你的密码长度增加一位,就会以倍数级别增加由你的密码字符所构成的组合。一半来说,小于8个字符的密码被认为是很容易被破解的。可以用10个、12个字符作为密码,16个当然更好了。在不会因为过长而难于键入的情况下,让你的密码尽可能的更长会更加安全。

  2、做好边界防护

  并不是所有的安全问题都发生在系统桌面上。使用外部防火墙/路由器来帮助保护你的计算机是一个好想法,哪怕你只有一台计算机。

  如果从低端考虑,你可以购买一个宽带路由器设备,例如从网上就可以购买到的路由器等。如果从高端考虑,你可以使用企业级厂商的可网管交换机、路由器和防火墙等安全设备。当然,你也可以使用预先封装的防火墙/路由器安装程序,来自己动手打造自己的防护设备。代理服务器、防病毒网关和垃圾邮件过滤网关也都有助于实现非常强大的边界安全。

  请记住,通常来说,在安全性方面,可网管交换机比集线器强,而具有地址转换的路由器要比交换机强,而硬件防火墙是第一选择。

  3、升级您的软件

  在很多情况下,在安装部署生产性应用软件之前,对系统进行补丁测试工作是至关重要的,最终安全补丁必须安装到你的系统中。如果很长时间没有进行安全升级,可能会导致你使用的计算机非常容易成为不道德黑客的攻击目标。因此,不要把软件安装在长期没有进行安全补丁更新的计算机上。

  同样的情况也适用于任何基于特征码的恶意软件保护工具,诸如防病毒应用程序,如果它不进行及时的更新,从而不能得到当前的恶意软件特征定义,防护效果会大打折扣。

  4、关闭没有使用的服务

  多数情况下,很多计算机用户甚至不知道他们的系统上运行着哪些可以通过网络访问的服务,这是一个非常危险的情况。

  Telnet和FTP是两个常见的问题服务,如果你的计算机不需要运行它们的话,请立即关闭它们。确保你了解每一个运行在你的计算机上的每一个服务究竟是做什么的,并且知道为什么它要运行。

  在某些情况下,这可能要求你了解哪些服务对你是非常重要的,这样你才不会犯下诸如在一个微软Windows计算机上关闭RPC服务这样的错误。不过,关闭你实际不用的服务总是一个正确的想法。

  5、使用数据加密

  对于那些有安全意识的计算机用户或系统管理员来说,有不同级别的数据加密范围可以使用,根据需要选择正确级别的加密通常是根据具体情况来决定的。

  数据加密的范围很广,从使用密码工具来逐一对文件进行加密,到文件系统加密,最后到整个磁盘加密。通常来说,这些加密级别都不会包括对boot 分区进行加密,因为那样需要来自专门硬件的解密帮助,但是如果你的秘密足够重要而值得花费这部分钱的话,也可以实现这种对整个系统的加密。除了boot分区加密之外,还有许多种解决方案可以满足每一个加密级别的需要,这其中既包括商业化的专有系统,也包括可以在每一个主流桌面操作系统上进行整盘加密的开源系统。

  6、通过备份保护你的数据

  备份你的数据,这是你可以保护自己在面对灾难的时候把损失降到最低的重要方法之一。数据冗余策略既可以包括简单、基本的定期拷贝数据到CD上,也包括复杂的定期自动备份到一个服务器上。

  7、加密敏感通信

  用于保护通信免遭窃听的密码系统是非常常见的。针对电子邮件的支持OpenPGP协议的软件,针对即时通信客户端的Off The Record插件,还有使用诸如SSH和SSL等安全协议维持通信的加密通道软件,以及许多其他工具,都可以被用来轻松的确保数据在传输过程中不会被威胁。

  当然,在个人对个人的通信中,有时候很难说服另一方来使用加密软件来保护通信,但是有的时候,这种保护是非常重要的。

  8、不要信任外部网络

  在一个开放的无线网络中,例如在你本地具有无线网络的咖啡店中,这个理念是非常重要的。如果你对安全非常谨慎和足够警惕的话,没有理由说在一个咖啡店或一些其他非信任的外部网络中,你就不能使用这个无线网络。但是,关键是你必须通过自己的系统来确保安全,不要相信外部网络和自己的私有网络一样安全。

  举个例子来说,在一个开放的无线网络中,使用加密措施来保护你的敏感通信是非常必要的,包括在连接到一个网站时,你可能会使用一个登录会话 cookie来自动进行认证,或者输入一个用户名和密码进行认证。还有,确信不要运行那些不是必须的网络服务,因为如果存在未修补的漏洞的话,它们就可以被利用来威胁你的系统。这个原则适用于诸如NFS或微软的CIFS之类的网络文件系统软件、SSH服务器、活动目录服务和其他许多可能的服务。

  从内部和外部两方面入手检查你的系统,判断有什么机会可以被恶意安全破坏者利用来威胁你的计算机的安全,确保这些切入点要尽可能的被关闭。在某些方面,这只是关闭不需要的服务和加密敏感通信这两种安全建议的延伸,在使用外部网络的时候,你需要变得更加谨慎。很多时候,要想在一个外部非信任网络中保护自己,实际上会要求你对系统的安全配置重新设定。

  9、使用不间断电源支持

  如果仅仅是为了在停电的时候不丢失文件,你可能不想去选择购买UPS.实际上之所以推荐你使用UPS,还有更重要的原因,例如功率调节和避免文件系统损坏。由于这种原因,确保使你的操作系统能够提醒你它什么时候将关闭,以免当电源用尽的时候你却不在家中,还要确保确保一个提供功率调节和电池备份的UPS.

  一个简单的浪涌保护器还不足以保护你的系统免遭"脏电"的毁坏。记住,对于保护你的硬件和你的数据,UPS都起着非常关键的作用。

  10、监控系统的安全是否被威胁和侵入

  永远不要认为:因为你已经采取了一系列安全防护措施,你的系统就一定不会遭到安全破坏者的入侵。你应该搭建起一些类型的监控程序来确保可疑事件可以迅速引起你的注意,并能够允许你跟踪判断是安全入侵还是安全威胁。我们不仅要监控本地网络,还要进行完整性审核,以及使用一些其他本地系统安全监视技术。

  根据你使用的操作系统不同,还有很多其他的安全预防措施。有的操作系统因为设计的原因,存在的安全问题要大一些。而有的操作系统可以让有经验的系统管理员来大大提高系统安全性。不过,无论你的使用的是像微软的Windows和苹果的Mac OSX,还是使用的像Linux、FreeBSD等开源操作系统,当你在加固它们的安全的时候,以上建议都是必须牢记心头的。

                                                                              来源:中国IT实验室 作者:佚名


Ruby On Rails发送邮件的配置

Posted by: bin in Untagged  on

ruby on rails 发送邮件配置

一、环境
  ubuntu 9.0.4  ruby 1.8.7 (2008-08-11) [i486-linux]  Rails 2.3

二、目的
   给注册发送激活邮件

三、实现过程
   本想考虑用sendmail,因为RubyOnRails默认情况下就是用sendmail来发送。不过sendmail需要一些复杂的配置,而且人员和系统的用户绑定(也可分开,没有去研究)。
所以,干脆实现用stmp来实现,采用Gmail邮件。
  因为gmail用tls,用先安装插件
  ruby script/plugin install http://svn.xlsuite.org/trunk/vendor/plugins/action_mailer_tls/
  在environment.rb中加入
 config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
   :enable_starttls_auto => true,
:address => "smtp.gmail.com",
:port => 587,
#:domain => "mycompany.com",
:authentication => :plain,
:user_name => "xxx@gmail.com",
:password => "xxx"
}
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
config.action_mailer.default_charset = 'utf-8'

千万要注意这句,:enable_starttls_auto => true, 不然会出现如下错误
530 5.7.0 Must issue a STARTTLS command first. i6s

因为Rails中具体应用Mail,请参考文档
http://guides.rubyonrails.org/action_mailer_basics.html


Erlang知识-变量及数据类型

Posted by: bin in erlang on

公司里有项目要用到Erlang,关于Erlang的介绍,这里先简单交代一下

Erlang是一个丹麦的数学家,他搞出来的一个概率分布Erlan分布,并且用这个分布开创一们学科排队理论,电信上经常用这个分布来测算话务量,因此在电信界比较有名.当年Joe Amstrong把他的语言命名为Erlang也是为了纪念这个为电信领域作出过卓越贡献的人.
   Erlang是Ericsson和Ellemtel Computer ScientceLaboratories为解决电信领域中的并发和分布式问题,设计的语言;从理论应用于实践的角度讲,主要探索的是函数式语言能否应用到通信领域的大型交换机上,从Erlang的实践效果来看,答案是肯定的。
    Erlang的优点:
    (1) Code Loading Primitives允许在系统运行过程中升级代码。
    (2) Erlang的轻量级进程可以支持极高的并发性,而且在高并发的情况下内存使用相当的少。Erlang的并发性并不会受到宿主操作系统并发性的限制。Erlang的原子操
作是一个压栈级别的,而C语言是指令级别的。
   (3)最开始Erlang的设计目标就是实现分布式环境,一个Erlang的虚拟机就是一个Erlang网络上的节点。一个Erlang节点可以在另一个-Erlang节点上创建自己的并发进程,而子进程所在的节点可能是运行其他的操作系统的服务器。不同节点的之间的可以进行极为高效而又精确的通信,就像它们运行-在同一个节点一样。
    (4)Erlang内部建设有多种错误检测原语。我们可以通过这些原语来架设高容错性的系统。例如,一个进程可以监视其他进程的状态和活动,即使那些被监 -控的进程处于其他节点。在分布式状态下,我们可以把系统配置成具有Fail-over功能的分布式系统。当有其他节点出错的时候,系统会把他的运行场景自动快速-的切换备份节点上。
    (5) Erlang是一个"软"实时系统(Soft Real Time),它可以提供毫秒级别的响应。

变量
所有的变量都必须以大写字母开头。
X = 12832.
如果再执行 X=1244.则报错了。
注意:在Erlang中,X不是一个变量,至少不是你在Java或C中的那种变量。
另外,=不是赋值操作符。而模式匹配,变量只能被赋值一次。当我们第一次输入X=12832时,Erlang会问自己,"要怎么做才能让这样语句的值变是true?"(注:erlang的每一个语句都会有值),由于X没有被赋值,因此可以把12832绑定到X上。同时也使得语句有效。


浮点数
1> 5/3.
1.66667
2> 4/2.
2.00000
3> 5 div 3.
1
"/"永远返回浮点数。

原子
用来表示不同的非数字常量值。类似于java/c中的枚举类型。原子是一串以小写字母开头、后跟数字、字母或下划线(_)或邮件符号(@)的字符。而且原子是全局有效的,而且无需使用宏定义或者包含文件。
比如,red、december、a_login_name
使用单引号引起来的字符也是原子,一个原子的值就是原子自身。比如,'a'就等同于a

元组
将一定数量的项目组成单一的实体,那么就可以使用元组(tuple)。将若干个以逗号分割的值用一对花括号括起来,就形成了一个元组。如{ supercode, 1.75}.这个元组就包括了一个原子和一个浮点数。 元组类似于C语言中的结构。

  • 创建元组
    在声明元组时,就自动创建了元组,不需要时,元组也自动销毁。因为erlang有垃圾回收。

2> F = {firstName, joe}.
{firstName,joe}
3> L = {lastName, armstrong}.
{lastName,armstrong}
4> P = {person, F, L}.
{person,{firstName,joe},{lastName,armstrong}}


  • 从元组中提取字段值
    1> Point = {point, 10, 45}.
    {point, 10, 45}.
    2> {point, X, Y} = Point. 
    {point,10,45}
    3> X.
    10
    4> Y.
    45

注意
{my,X,Y}=Point, 将出错,因为my与point不匹配,如果{Mypoint,X,Y}=Point. 那么是正确的.

列表
列表用来存储数目可变的东西,如在商店里买到的商品。将若干个以逗号分割的值用一对方括号括起来,就形成了一个列表。
1> ThingsToBuy = [{apples,10},{pears,6},{milk,3}].
[{apples,10},{pears,6},{milk,3}]

列表之中的各个元素可以有各自不同的类型。
2> [1+7,hello,2-2,{cost, apple, 30-20},3].
[8,hello,0,{cost,apple,10},3]

列表的第一个元素称为列表的头(head),除去头,剩下的东西称为列表的尾。注意,列表的头可以是任意东西,但列表的尾通常还是一个列表。

3> ThingsToBuy1 = [{oranges,4},{newspaper,1}|ThingsToBuy].
[{oranges,4},{newspaper,1},{apples,10},{pears,6},{milk,3}]

4> [Buy1|ThingsToBuy2] = ThingsToBuy1.
[{oranges,4},{newspaper,1},{apples,10},{pears,6},{milk,3}]
绑定结果如下
Buy1 7→ {oranges,4}


字符串
严格地讲,Erlang中并没有字符串,字符串实际上也就是一个整数列表。
1> Name = "Hello".
"Hello"

可以用$符号来表示字符中整数值。
5> I = $s.
115
6> [I-32,$u,$r,$p,$r,$i,$s,$e].
"Surprise"


Nodepad++的美中不足

Posted by: bin in Untagged  on

      一直在用Notepad++,做为一款开源而免费的文本编辑器,它还是不错的,我偶尔用它快速查看一些文件,比如html,php,python,ruby,txt等等.我的机子上装了MyEclipse,VS2008,NetBeans,Aptana,所以开发是不会用Notepad++的,用它主要是快速,不想用这些超重的IDE拖我的笔记本,虽然有3G的内存.不过这两天用NotePad++,发现有个不太如意的地方.当打开多个文件时,注意是同时打开50个文件以上,而且涉及到查找,替换等.偶尔会没有响应,要比较内容太多了.UltraEditb也是如此,查找时窗口刷的厉害,默认的情况,语言的高亮支持没有nodepad++多, 另外,打开这么多的文件,在找文件时,比较麻烦,因为它的选择窗口,连首字母定位的功能都没有,不过这个功能UltraEdit倒是有的. 另外一直看到国外的ruby开发人员一直用TextMate,不过windows上没有这东东.不过有E - TextEditor号称是The power of TextMate on Windows.当然其他的编辑器还有Emacs,Vim,TextPad这些也都非常有名.后面这几款对键盘的掌握度要高些,而如果鼠标做大多数人的选择,面向的对象群体也相对少了,不过掌握后,效率也更高.


ASP.NET Forms验证(自定义、角色提供程序)

Posted by: bin in Untagged  on


一、普通实现方式

这种方式是最简单的,只需要配置一下就可以了。

1、执行aspnet_regsql命令建立数据库

aspnet_regsql命令在C:WINDOWSMicrosoft.NETFrameworkv2.0.50727目录下,按提示运行就可以了

2、新建一个web网站

在Web.Config中加入配置:
<code>
  <connectionStrings>
    <add name="MySqlConnection" connectionString="Data Source=dbserver;Initial Catalog=database;user id=userid;password=****;" />
  </connectionStrings>

  <system.web>
        <authorization>
            <deny users="?"/>
        </authorization>
        <authentication mode="Forms">
            <forms loginUrl="login.aspx" name=".ASPXAUTH"/>
        </authentication>

    <membership defaultProvider="SqlProvider">
      <providers>
        <clear />
        <add connectionStringName="MySqlConnection" applicationName="MyApplication"
          enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true"
          requiresUniqueEmail="true" passwordFormat="Hashed" name="SqlProvider"
          type="System.Web.Security.SqlMembershipProvider" />
      </providers>
    </membership>

  </system.web>
</code>
主要就是指定Forms验证使用的数据库,如果不指定数据库会使用本机默认的aspnetdb 数据库。

deny users="?"表示不允许匿名用户访问,也就是说当匿名用户访问时自动跳转到下面配置的login.aspx页面。
至于authorization和authentication节的其他属性可以参考MSDN,里面有很详细的介绍。

3、在网站里创建Default.aspx和Login.aspx页面

在Login.aspx页面里面放入Login和CreateUserWizard控件(因为我们新建的库中一个用户也没有,CreateUserWizard控件只是用来建立测试用户的,建好用户后可以把这个控件删除)
在Default.aspx页面中随便放入一些内容。

当我们访问Default.aspx时就会自动转入Login.aspx进行验证了。

二、自定义实现方式

采用第一种方式时会要求建立一个数据库,很多表,可能并不符合我们自己的业务要求。可以使用以下的自定义方式

1、利用Login控件的Authenticate事件

这个事件就是用来进行验证的,可以通过指定true值表示验证通过:
    protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
    {
        //判断用户名密码是否正确
        //
        e.Authenticated = true;
    }

2、完全抛开Login等控件,自己写代码

其实Login控件的核心主要也就是往Cookie里面放入一些值,那么我们可以在自己的代码中来进行这个操作:

    protected void Button1_Click(object sender, EventArgs e)
    {
        //判断用户名密码是否正确
        //.
        FormsAuthentication.SetAuthCookie(userName, false);
        if (Context.Request["ReturnUrl"] != null)
        {
            Response.Redirect(Context.Request["ReturnUrl"]);
        }
        else
        {
            Response.Redirect(FormsAuthentication.DefaultUrl);
        }
    }

采用以上两种方式就不用建立默认的数据库了,直接使用我们的逻辑进行验证操作

三、自定义角色提供程序

以上说的都是用户级别的验证,在有的情况下需要根据角色来进行验证,比如指定某个目录或某个aspx文件只能让哪几个角色的用户访问,根据角色来控制的话比较方便灵活。

1、在登录验证的时候把角色信息也保存到Cookie中去:
    protected void Button1_Click(object sender, EventArgs e)
    {
        //判断用户名密码是否正确
        //.

        //得到用户的角色,测试时暂时写死
        string userRoles = "Admins,testst";
        FormsAuthenticationTicket Ticket = new FormsAuthenticationTicket(1, user, DateTime.Now, DateTime.Now.AddMinutes(30), false, userRoles, "/");
        string HashTicket = FormsAuthentication.Encrypt(Ticket);

        //把角色信息保存到Cookie中去
        HttpCookie UserCookie = new HttpCookie(FormsAuthentication.FormsCookieName, HashTicket);
        Response.Cookies.Add(UserCookie);

        if (Context.Request["ReturnUrl"] != null)
        {
            Response.Redirect(Context.Request["ReturnUrl"]);
        }
        else
        {
            Response.Redirect(FormsAuthentication.DefaultUrl);
        }
    }

把角色信息加密成特定的格式保存。

2、自定义角色提供程序

如果要按照角色进行验证的话,肯定要涉及到角色提供程序,在默认情况下也是会去连接默认的数据库的,我们可以自己写一个角色提供程序来实现自己的逻辑。
首先在web.config中加入配置:
<code>
    <roleManager defaultProvider="MyRoleProvider"
      enabled="true"
      cacheRolesInCookie="true"
      cookieName=".ASPROLES"
      cookieTimeout="30"
      cookiePath="/"
      cookieRequireSSL="false"
      cookieSlidingExpiration="true"
      cookieProtection="All" >
      <providers>
        <clear />
        <add name="MyRoleProvider"
          type="MyRoleProvider"
          writeExceptionsToEventLog="false" />
      </providers>
    </roleManager>
</code>
这个就是指定我们的角色提供类MyRoleProvider。

这个类必须从System.Web.Security.RoleProvider继承,只要重载实现一个方法就可以了(其他方法返回异常):
<code>

    public override string[] GetRolesForUser(string username)
    {
        FormsIdentity Id = HttpContext.Current.User.Identity as FormsIdentity;
        if (Id != null)
        {
            return Id.Ticket.UserData.Split(new Char[] { ',' });
        }
        return null;
    }</code>

也就是从我们之前保存到Cookie中的值取得用户角色(FormsAuthentication会自动把保存的cookie转化成User内的值)

之后我们就可以在web.config中配置角色验证规则了:
<code>
  <location path="admin">
    <system.web>
      <authorization>
        <allow roles="Admins"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location></code>

或者也可以在代码中判断:
bool a = User.IsInRole("testt");

判断起来还是很方便的。

四、单点登录

使用Forms的单点登录主要是通过machineKey的配置,machineKey 元素对密钥进行配置,以便将其用于对 Forms 身份验证 Cookie 数据和视图状态数据进行加密和解密,并将其用于对进程外会话状态标识进行验证

使用这种方式的单点登录目前只能实现相同主机或相同子域站点之间的同步登录,比如www.cnblogs.com和firstyi.cnblogs.com可以实现,但是www.cnblogs.com和www.sina.com.cn就不能实现了,对于非同一父域名下的域名间不能跨站登录

主要配置如下:
<code>
  <machineKey validationKey="282487E295028E59B8F411ACB689CCD6F39DDD21E6055A3EE480424315994760ADF21B580D8587DB675FA02F79167413044E25309CCCDB647174D5B3D0DD9141" decryptionKey="8B6697227CBCA902B1A0925D40FAA00B353F2DF4359D2099" validation="SHA1"/>
  <authentication mode="Forms">
      <forms loginUrl="login.aspx" name=".ASPXAUTH1" domain=".cnblogs.com" />
  </authentication>
</code>
要实现单点登录的多个web站点的machineKey必须一样,forms里面的name和domain也必须一样

这样配置好之后,在其中一个站点登录后再调转到另一个站点就不需要再次登录了。

注:如果MOSS网站采用Forms验证方式的话,只要把MOSS站点的对应配置改成和自己的Asp.Net站点一致,那么可以从自己的站点直接进入MOSS站点,也不需要重新登录(MOSS站点和自己的站点要有相同的用户名)

其他:

Forms验证之后可以使用以下方法退出登录:
FormsAuthentication.SignOut();


另外这些登录的后台Module是配置在C:WINDOWSMicrosoft.NETFrameworkv2.0.50727CONFIGweb.config文件中的:
<code>

      <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule"/>
      <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/>
      <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule"/>

</code>
附:
最后的web.config文件
<code>
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
  <system.web>
        <authorization>
            <deny users="?"/>
        </authorization>
        <authentication mode="Forms">
      <forms loginUrl="login.aspx" name=".ASPXAUTH1" domain=".cnblogs.com" />
    </authentication>
    <machineKey validationKey="F9A61F796A204D9945889B64D9DA5086E89CEC5200F0CED4" decryptionKey="D679BCF2A76DEBB04D7FED5E5967F46C92FEF2B31AD5D7C9" validation="SHA1" />
    <compilation debug="true"/>
   
    <roleManager defaultProvider="MyRoleProvider"
      enabled="true"
      cacheRolesInCookie="true"
      cookieName=".ASPROLES"
      cookieTimeout="30"
      cookiePath="/"
      cookieRequireSSL="false"
      cookieSlidingExpiration="true"
      cookieProtection="All" >
      <providers>
        <clear />
        <add name="MyRoleProvider"
          type="MyRoleProvider"
          writeExceptionsToEventLog="false" />
      </providers>
    </roleManager>

  </system.web>
  <location path="admin">
    <system.web>
      <authorization>
        <allow roles="Admins"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
</configuration></code>


关于职业中学班级管理和建设

Posted by: bin in Untagged  on

大力发展职业教育是我国经济社会发展的重要基础和教育工作重点,这就对培养高素质的从业者、加强职业中学的班级管理和建设提出新的要求。当前,职业中学由于生源素质较差,学生文化基础相对薄弱,学生的学习主动性和行为习惯较差、缺乏自律性,导致班级管理和建设难度较大。班级作为学校的一个重要组成部分,其管理和建设状况是学校办学水平的重要标志,同时也影响着培养学生成人成才的教育目标。因而,加强班级管理和建设,创造良好的班级育人环境,形成良好的班风、学风,是培养优秀劳动者的基础前提。
  1.精挑、细选班主任,培养管理和建设者。班主任作为建设、巩固和发展班集体的组织者、教育者和领导者,是学校教学工作和各项教育活动的得力助手,对学生进行全面发展教育具有主导作用,在组织班级教育力量中具有纽带和桥梁作用。要创建积极向上、团结奋进、奋斗目标明确的班集体,就要有高素质的班主任。因此,确定班主任时,应考虑以下几方面:
  ①选择敬业精神强、富有责任感的教师担任班主任,这是当好班主任的必备条件;
  ②选择有爱心的老师担任班主任,爱学生、爱班主任这项工作是当好班主任的原动力;
  ③选择工作主动积极、教育管理实践经验丰富的老师当班主任,这是搞好班级建设和管理的基础;
  ④选择能灵活、适度运用教育规律、原则,因材施教的老师当班主任,是班级建设和管理的基础;
  ⑤具有组织协调各教育力量和活动的能力,是当好班主任的保障;
  ⑥良好的个人修养,高尚的师德、师风是当好班主任的前提;
  ⑦加强班主任的交流与合作,是提高班主任能力的重要途径。
  2.潜心研究职业中学学生特点,全力担任好班主任。到职业中学就读的学生水平参差不齐、情况各异:第一类学生基础较好,但因家庭经济原因,为了早就业而选择职业中学就读,这类学生管理难度不大,重在引导;第二类学生是以学习技能、便于就业为目标;第三类学生则是因为文化基础相对较差、学习主动性不强、学习目标不明确、纪律意识淡薄、行为习惯差等原因,家长为避免其受不良因素影响而送读职业中学找老师看护的。除上述三类学生特点应摸清外,班主任还应细心发现学生动态变化,及时教育引导,总之,班主任应将每位学生的状况和变化情况烂熟于心,在工作中有的放矢,才能起到事半功倍的效果。
  3.做好班级管理和建设应做的工作。
  3.1制定规章制度。对班级的管理和建设最终应落实到学生自己管理自己和约束自己,培养良好的纪律意识和行为习惯。制定班级规章制度时,让每位学生理解明白班级规章制度是班级每位成员的行动准则,是必须遵守的,否则将受到惩处。制定班级规章制度应不违背国家的法律法规、教育各级主管部门的法规和规定,要遵循教育规律,在制定过程中让班级成员充分发表意见和看法,通过讨论达成共识,最后由班主任集中形成条文,并根据班级变化情况适时调整。总之,班级规章应成为全体成员自觉遵守、主动接受违规处理的行为准绳。
  3.2形成积极向上的班级舆论。班集体是学生人生观、世界观和价值观形成的主要场所,一个先进的班集体应具有健康的、积极向上的班级舆论,它影响着学生的价值取向和集体合力的形成。班主任应随时了解班级舆论情况,正确引导,对不良的言行及时纠正,避免消极影响。
  3.3确定班级奋斗目标。没有奋斗目标的班集体不可能成为一个先进班集体,班主任应结合班级实际情况与全体学生一道制定出适合本班的近期、中期、长期具体目标和总体目标,使之成为班主任和全体学生的行为指南。
  3.4注重班级文化建设。班级文化建设包括物质文化、制度文化和精神文化,它对培养学生审美观、高尚的情操和优良的道德品质起着积极、促进作用,能协调班级人与人、人与物、物与物的和谐,能诱导学生形成良好的心态,对班风学风良性发展起到潜移默化的影响。
  3.5开好班会和搞好各项活动。班会是班主任对全体学生进行思想政治工作的主阵地,应做到有准备并有预见的教育,针对实际情况开展教育性、常规性、总结性、知识性、文化性班会。搞好每一次学校或班级组织的活动,充分调动每位学生积极性,让其自觉成为班级主体。
  3.6整合教育力量,使之成为教育的合力。班级的建设和管理需要各方的支持和配合。班主任应经常与家长沟通联系并及时反馈和了解学生情况,在教育学生过程中最有效的得到家长的支持和配合。班主任还应多协调科任教师及其它校内相关人员的教育力量,同时争取最大限度的得到社会各种有效力量的支持。
  3.7加强沟通,尊重、关爱学生。语言是架通心灵的桥梁。班主任应利用一切机会与学生交谈、交流,从而洞察出学生的心理状况,为采用正确的教育方法做有效的准备。尊重、关爱学生是教育效果好坏的先决条件,是学生接纳老师和接受教育的必备条件之一。
  3.8搞好班干部队伍建设领导集体发展。班主任应选择乐于奉献、品行端正、有组织能力、号召力强的学生作为班干部成员,并搞好班干部队伍建设,使之成为班级向心力,同时应爱护班干部,真正做到学生自己管理自己,使班级每位成员都得到发展。
  总之,班级是学校的基本组成单位,一个班集体良好的班风直接影响着学校校风的建设。班主任又是班集体的组织者、教育者和领导者,班主任的基本素质与工作能力直接影响着班风、学风的好坏。搞好学校班级管理和建设,是一个任重而道远的工作。(来源:中国教育发展研究 作者:强朝晖 )

关于Joomla用户注册审批的问题

Posted by: bin in Untagged  on

目标: 用户完成注册后,提示帐号待审核状态,我们会尽快处理,并将处理结果通过注册时的电子邮件通知用户.管理员后台登录后,显示待审核用户,可以通过,也可以驳回.不管哪种,都通过email告诉用户.

解决的思路
1.采用Jom Social来扩展用户自定义的定段.将默认登录的注册连接指向的JomSocial中的注册页面.

2.将系统设计为允许注册用户,并将New User Account Activation=Yes

3.用mod_useract来显示待审批的用户,每条记录的后面都有拒绝和通过的操作.

4. 注册时先不发激活邮件,   这是Jom Social中的模块,因为注册用它,componentscom_communitycontrollersregister.php
   注释掉     $this->_sendMail($user, $password);    

5. 修改用mod_useract发送给用户的语言,默认mod_useract语言放在 administratorlanguageen-GBen-GB.mod_useract.ini
修改文件名为zh-CN.mod_useract.ini,并将其放到
administratorlanguagezh-CN下.

6.修改zh-CN.mod_useract.ini的内容

当然,也可以直接用CB这个组件,但是似乎无缘,所以采用上面的曲折方式,顺便说一直,CB可以扩展字段,但我不确定有审批功能。



友情链接: 上海市企业信息化促进中心 国家工业和信息化部 中国信息安全评测认证中心 中国教育网 多特软件站 天空软件站 华军软件园 上海西楚礼仪