Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15843 articles
Browse latest View live

蹭WiFi 易掉黑客陷阱

$
0
0

蹭WiFi 易掉黑客陷阱
蹭WiFi 易掉黑客陷阱

央视《消费主张》栏目近日曝光了WiFi日常使用中存在的巨大安全隐患:仅需简单设备和软件就能设下的“钓鱼WiFi”陷阱,能在网友毫不知情的情况下盗走个人支付宝密码、网上银行密码等重要信息。

对此,南国都市报记者走访发现,海口公共场所轻易能搜索到免费WiFi,但许多市民并不知道“蹭”WiFi有风险,更不懂得如何规避风险。

南国都市报记者 孙学新

案例

免费WiFi上网结果钱没了

据国内媒体报道,今年3月份,重庆一名男子吃饭时连接了饭店里的免费WiFi,结果中了恶意扣费病毒,400元话费不翼而飞。江苏一名男子使用在公共场所使用WiFi后,网银被盗走6万多元。

接连发生在国内的“蹭WiFi丢钱”事件,给众多“手机控”敲响警钟。央视《消费主张》节目中,央视记者联合金山毒霸安全工程师在多个场景进行“钓鱼WiFi”实验,他们模拟黑客,在北京火车站和王府井(600859,股吧)商业区分别设置了两个免费WiFi热点,很快就有几十个网民连入使用,而网民在网络上的一举一动,甚至其手机型号、打开的应用名称及上网信息,如浏览过的网页、机主QQ号码、微信朋友圈照片、淘宝、微博账号等信息,同时被该WiFi创建者截获。

WiFi名称可随意设置

体验

6月19日下午,记者进入海口火车东站一层的肯德基餐厅进行一次设置WiFi的体验,设备仅为一部手机和一部笔记本电脑。

记者用手机设置了共享的WiFi网络。随后记者使用笔记本电脑搜索,仅十秒钟便搜到所设置的“FREE WiFi”网络并连接使用。

3分钟后,记者将手机名称更改为餐厅英文简称“KFC”,重新打开共享WiFi选项时,笔记本电脑上又立即能搜到名为“KFC”的WiFi信号。该信号设置后15分钟,先后有6人在没有任何验证的情况下连接使用。假如记者是一名黑客,这6人连接后操作的所有信息都将能“了如指掌”。

当场,记者找到使用所设WiFi的林女士,并告知她详情后,她表示“不敢相信”。林女士说:“候车还需要1个多小时,到餐厅消费就搜到这个免费WiFi信号,因为名字和餐厅相符,理所当然觉得这是餐厅提供的免费WiFi,没想到是假的。”

许多市民不知蹭WiFi有风险

走访

记者先后走访海口火车东站、明珠广场、国兴大润发等多处公共场所发现,许多商家为了招揽生意,都设置了WiFi,部分商家设置了使用密码,部分则免费开放。特别在国兴大润发商圈内,随处可见边逛边低头“刷手机”的市民。仅几分钟,记者在国兴大润发使用手机即搜到该区域11个WiFi,其中3个可免费使用。

记者随机询问10名市民是否知道“蹭”WiFi有风险时,只有1人明确表示知道和“使用WiFi前会核实”,其余9人均摇头不知情。

大学生小彭说:“发现免费WiFi就直接连上,哪里还想那么多。就算连接WiFi后,我也是在我的手机上操作,这样信息也会被偷吗?”

接受采访时,商场导购陈女士很惊讶:“手机都是24小时打开"自动连接可用网络"设置,只要搜索到免费WiFi,手机就会自动连接,根本不知道这样做有风险。”

支招

怎样安全用WIFI

怎样使用WIFI才安全?有关专家给出五大建议。

第一,谨慎使用公共场合的WIFI热点。官方机构提供的而且有验证机制的WiFi,可以找工作人员确认后连接使用。其他可以直接连接且不需要验证或密码的公共WiFi风险较高,背后有可能是钓鱼陷阱,尽量不使用。

第二,使用公共场合的WIFI热点时,尽量不要进行网络购物和网银的操作,避免重要的个人敏感信息遭到泄露,甚至被黑客银行转账。

第三,养成良好的WIFI使用习惯。手机会把使用过的WIFI热点都记录下来,如果WiFi开关处于打开状态,手机就会不断向周边进行搜寻,一旦遇到同名的热点就会自动进行连接,存在被钓鱼风险。因此当我们进入公共区域后,尽量不要打开WIFI开关,或者把WiFi调成锁屏后不再自动连接,避免在自己不知道的情况下连接上恶意WIFI。

第四,家里路由器管理后台的登录账户、密码,不要使用默认的admin,可改为字母加数字的高强度密码;设置的WIFI密码选择WPA2加密认证方式,相对复杂的密码可大大提高黑客破解的难度。

第五,不管在手机端还是电脑端都应安装安全软件。对于黑客常用的钓鱼网站等攻击手法,安全软件可以及时拦截提醒。金山毒霸正在内测的“路由管理大师”功能,还能有效防止家用路由器遭到攻击者劫持,防止网民上网裸奔。

(责任编辑:HN666)

您可能也喜欢:

危险的wifi 解密黑客破解家用路由器全过程

简单搭建家庭用wifi方案总结

使用reaver爆破WIFI PIN码 Use reaver blasting WIFI PIN code

FAST MERCIRY路由器telnet另类入侵 读取WIFI密码

极路由教您防范“危险的WiFi”
无觅

The post 蹭WiFi 易掉黑客陷阱 appeared first on 神刀安全网.


在微信朋友圈里:你其实是一个演员

$
0
0
在微信朋友圈里:你其实是一个演员

  美国著名社会学家戈夫曼认为人生就是一出戏,社会是一个大舞台,社会成员作为表演者都渴望自己能够在观众面前塑造能被人接受的形象,所以每一个人都在社会生活的舞台上竭力表演。相较于其他社交媒介个人内容的公开性,微信朋友圈中的大多数沟通发生在“熟人”之间,因此用户在其中建立的“形象”将更直接地影响现实生活中别人对自己的看法。

  剧组与观众:互动中的二元关系

  戈夫曼认为,一个完整的表演过程必须包括表演者、观众两种角色。按照戈夫曼的理论,表演者可以是个人也可以是“剧组”。一般情况下,朋友圈的表演者是单独的个人,但是“剧组”有时也可能在评论栏中出现。除了表演者之外,其他的参与者都是观众,按参与程度的高低,我们可以把观众分为主动观众和被动观众。主动的观众会在自己感兴趣的作品下方留下自己的评论,并可能与内容的作者或其他观众形成互动。这种互动意味着观众渴望根据该文章内容与作者或其他观众达成意见的交流。此外,转发演员的文章也是主动观众配合演员表演的重要形式。

  “赞”的妙用:被动观众的主动化

  在传统的社交网站中,主动观众看到该表演内容后会发出感想,感想的形式就是留言,被动观众只浏览不回复。但是微信“赞”的功能被最大化之后,被动的观众也存在了主动化的倾向。所以当演员发布了一条自己并不太感兴趣的内容时,原本被动的观众可以用“赞”来代替。

  “赞”的妙处在于,你不用与演员进行互动,这样你不用对不感兴趣的内容进行讨论。不点赞也不留言的被动的观众看完表演后不留下任何痕迹,但值得注意的是,这并不代表不回复的被动观众不受该表演的影响。

  “印象管理”:一切表演的出发点

  戈夫曼认为,“在人际互动中,不管个人具体目标是什么,他的兴趣始终是控制他人的行为,特别是控制他人对他的反应。”这就是所谓的“印象管理”。戈夫曼认为表演是被有意或无意地设计出来的,用以给他人制造一个“我们是谁”的印象,这是一个理想化的“自我”。在微信中,演员的表演分为四种模式:

  1、理想化表演。这是最常见的一种表演模式,这种模式的特征就是集中展示自己理想化的形象。在发布内容前,我们会斟酌自己想发布的内容,心里暗暗评估这条内容是否能够获得观众的肯定,是否会被某些人耻笑。内容主体的发布完成并不代表理想化的表演的终结,由于微信的非好友不可见评论的原则,所以除了本人之外没有人知道该消息得到了多大的评论数,所以“点赞的都是什么心态”或者“感谢各位点赞的童鞋”,都是发布者在证明这条微信有很多人点了赞;

  2、误解表演。这种表演的目的是使观众产生错觉,比如为了获得尊重,一个本来脑中空空如也的人在朋友圈中装得很有学问,本来并不富裕的人炫耀自己的奢侈物件或者“高档生活”;

  3、神秘化表演。与互动方保持一定距离,使对方产生一种崇敬心理的表演称之为“神秘化表演”。微信中有的“熟人”更愿意发布让人看不懂的内容或曲高和寡的内容,以将自己与微信中的大多数人区隔开来。这样做就是让观众对演员产生“陌生”的感觉;

  4、补救表演。演员有可能将朋友圈场外产生的尴尬放置到朋友圈中,在微信上主动表露这种尴尬行为,但这种表露是经过修饰的,让人觉得自己“可爱”。

  “尴尬”的出现:假面具被揭开

  戈夫曼认为人们之间的互动就是各人表演“我”,不是表现真实的“我”,而是表现伪装起来的“我”。丢“面子”有两种情况:一种是观众闯入后台;一种是表演被“非目标观众”看到。

  1、观众闯入后台。前台是个人按一种一般性的固定方式进行表演、为观众规定特定的情景的舞台部分;后台是为前台表演做准备、掩饰在前台不能表演的东西的场合。在后台,人们可以放松、休息,但是,一旦前台观众误闯了后台,演员不堪的一面就会被曝光。当演员进行表演的时候,我们发布的内容往往经过修饰、美化甚至歪曲。但是,如果观众中有人看出了这种美化,并且很直爽地指出了这种修饰或歪曲,那么演员将会受到严重的打击。当用户在朋友圈中发布了一条与事实不符的信息,他很有可能在评论中看到了解“后台详情”又个性耿直的好友的批判性留言,此时,尴尬就不可避免。

  2、表演被“非目标观众”看到。微信朋友圈有一个“可见范围”功能,用户在发布内容时可以通过设置使某些好友看不到该信息。但是万一这些信息被他们通过其他的渠道看到,那么“尴尬”的情况就会出现。我的朋友C曾跟我说起她的经历:这个故事中A和B是情侣,C是她们的共同微信好友圈朋友。某一次C无意中向B讲起了某一天A晒在微信朋友圈里泡吧的事,没想到B根本不了解这件事。B意识到自己的男友A对自己设置了内容屏蔽,那天A谎称自己在加班。之后,B和男友之间的一场分手风波由此开始。在这里,A想要在除了女友B之外的所有朋友圈好友中树立自己拥有丰富多彩夜生活的印象,于是将女友排除在观众之外。但他没想到目标观众中有人会将表演内容透露给了非目标观众。

  当丢面子的时候,我们会变得狼狈不堪。所以,当这些“尴尬”发生的时候,我们就得使用新的“面子功夫”(face-work)去维护自己面子的完整性。

   关注 互联网的一些事官方微信,回复ID " 17759 " 即可在微信里阅读本篇内容。

  在查找公众号中搜索:imyixieshi,或者扫描下方二维码快速关注。

   关注互联网的一些事微信

  本文链接: http://www.yixieshi.com/it/17759.html

  ===============关于互联网的一些事===============

   互联网的一些事http://www.yixieshi.com)  ——  专注于互联网产品设计的媒体平台,报道互联网前沿资讯,分享产品设计经验、用户体验心得。为产品策划和产品运营人士提供专业的产品资讯文档,以及产品设计、策划、运营、交互设计、用户体验、电子商务信息、互联网创业信息、移动互联网等专业信息服务。

   官方微博: @互联网的一些事

   官方微信: 互联网的一些事(ID:imyixieshi)

  如果您对互联网产品有独特的想法和见解,欢迎给我们投稿。投稿信箱:tougao#yixieshi.com (自行将“#”修改为“@”)

软件需求获取方法

$
0
0

 

软件需求获取是软件需求开发的关口环节,关口没把守好,后面就会全面溃败。

 

软件需求获取个人认为有以下几个方法:

 

  1. 面谈和问卷调查;
  2. 小组讨论;
  3. 情景串联;
  4. 参与、观察业务流程;
  5. 现有产品和竞争对手的描述文档;
  6. 市场资料

 

面谈和问卷调查:

 

面谈是获取软件需求的最有用的方法之一。面谈需准备的内容:

 

  1. 面谈对象
  2. 面谈的问题

 

面谈对象:与系统相关的涉众,并具有代表性,保证涵盖到每个角色。如何获取涉众:

 

  1. 谁为系统付费,购买系统?
  2. 谁使用系统:
  3. 谁会受到系统结果的影响,谁来监管该系统?
  4. 谁来维护系统?

 

面谈问题:需保证与背景无关,保证获取信息的公正性。问题的设计:

 

  1. 确定访谈对象的背景:姓名、年龄、部门所处的职位、目前的工作范围
  2. 目前碰到哪些问题,这些问题会对工作、生活产生什么影响?
  3. 对象环境的背景:a、计算机水平,b、目前是否有相同的系统在使用,c、使用该系统碰到哪些问题,d、目前如何处理工作?e、对培训等有什么要求?
  4. 问题重复,取得面谈者对问题的认同;
  5. 分析问题:问题产生的原因是?在什么情况下会有该问题?目前的解决方案是什么,效果如何?客户期待的解决方案是?
  6. 解决方案的可行性分析;
  7. 非功能性需求:性能?稳定性方面的要求;
  8. 维护,是否有专门的维护团队?
  9. 对当前的访谈结果的认同,确认后期有问题可继续联系。
  10. 总结出当前优先级最高的三个问题;
  11. 调查问卷无法取代面谈在需求获取阶段的作用,问卷调查的问题和答案具有一定的引导性,在某种程度上会影响结果。

 

小组讨论:

小组讨论是指将与项目某个问题相关的人员聚集在一起开会讨论。优势:容易在内部取得对方案的认同,有利于项目的开展;在讨论会上每个相关人员都可发表自己的意见,保证了获取信息的全面性。缺点:不容易把握。

 

小组讨论的注意事项:

1、 需先确定议题,范围;参会人员;

2、事先将相关资料送达参与人员,让参与人员开会前先了解会议的整体背景,有利于会议的顺利开展;

3、 确定好会议室、开会的时间(需控制开会时间的长度),做好后勤保障;

4、 选一个好的主持人,可把握会议的方向、进度、调整会议的氛围;

5、保证每个人都有5-10分钟的发言时间,不允许他人打断,但也不允许超过限定的发言时长;

6、 会后将会议纪要发送给参会人员,取得对结果的认同。

 

情景窜联

 

由于软件产品的抽象性,大部分涉众在脑海子未有一个清晰的产品轮廓,影响涉众对产品的理解。基于此可考虑编写清晰、完整的情景描述文档。

1、 采用PPT加图片的方式描述情景;

2、 采用原型法(比较推荐这种方法)

 

参与、观察业务流程

 

涉众描述的业务流程可能由于某些原因会遗漏掉重要的信息,需求分析人员可申请参与到他们具体的工作,观察、体验业务操作过程。需求分析员在观察业务操作过程时,可根据实际的情况提问并详细记录,记录业务操作员操作过程,操作过程中碰到的难题,可获取真实的材料和理解整个业务。

 

现有产品和竞争对手文档

 

阅读现有产品文档有利于了解当前系统情况,从中也可以了解业务流程,对操作员反映的系统问题有着更深层次的理解。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Google创建OpenSSL分支,宣布BoringSSL

$
0
0
在OpenBSD创建OpenSSL分支LibreSSL两个月后,Google宣布了它创建的OpenSSL分支BoringSSL。Google安全团队的Adam Langley在个人博客上说,他们使用了超过70个OpenSSL补丁,部分被接受合并到了OpenSSL主库,但大部分没有。随着Android、Chrome和其它项目开始需要这些补丁的子集,事情日益变得复杂,要保证所有补丁在不同代码库正常工作需要太多精力。所以他们决定创建OpenSSL分支。但Google不打算取代OpenSSL,使用BoringSSL的代码不能保证API或ABI的稳定性,他们会继续向 OpenSSL递交bug修正,继续资助Core Infrastructure Initiative和OpenBSD基金会。OpenBSD创始人Theo de Raadt对此表示,有选择总是好的。






hdfs-ha热备原理

$
0
0

下面的总结来自于: http://dongxicheng.org/hadoop-hdfs/hdfs-ha-federation-deploy/ 

 

           Hadoop 2.0中的HDFS增加了两个重大特性,HA和Federaion。HA即为High Availability,用于解决NameNode单点故障问题,该特性通过热备的方式为主NameNode提供一个备用者,一旦主NameNode出现故障,可以迅速切换至备NameNode,从而实现不间断对外提供服务。Federation即为“联邦”,该特性允许一个HDFS集群中存在多个NameNode同时对外提供服务,这些NameNode分管一部分目录(水平切分),彼此之间相互隔离,但共享底层的DataNode存储资源。

 

           在一个典型的HDFSHA场景中,通常由两个NameNode组成,一个处于active状态,另一个处于standby状态。Active NameNode对外提供服务,比如处理来自客户端的RPC请求,而Standby NameNode则不对外提供服务,仅同步active namenode的状态,以便能够在它失败时快速进行切换。

 

           为了能够实时同步Active和Standby两个NameNode的元数据信息(实际上editlog),需提供一个共享存储系统,可以是NFS、QJM(Quorum Journal Manager)或者Bookeeper,Active Namenode将数据写入共享存储系统,而Standby监听该系统,一旦发现有新数据写入,则读取这些数据,并加载到自己内存中,以保证自己内存状态与Active NameNode保持基本一致,如此这般,在紧急情况下standby便可快速切为active namenode。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



【javaScript基础】异常处理

$
0
0

         理解异常在javaScript面向对象编程是非常重要的,异常是一种非常强大的处理错误的方式。


错误处理


         首先我们来看一个有问题的代码:

nonexistant();

在以上这个例子中,访问一个不存在的变量,在这种情况下,程序会怎么处理?很早以前的处理方式就是程序直接崩溃死掉,所以我们不能容忍这种处理方式,需要有办法来处理。

    最简单的处理方式是先检查,像这样:

	if (window.func) {
  		func();
	}

         上面这种处理方式,仍然可能还会出现错误。因为window.func可能不是一个函数,因此我们仍需要这样检查:

if (typeof(func) == 'function') { 
    func();
}

在上面的例子中,typeof确保变量存在并确保是个函数。

         我们满怀希望地做了很多需要的检查来确保执行func是安全的。但是如果func的函数体内有错误呢?我们更想做的是处理错误,而不是让程序死掉。

         我们可以用trycatch结构来处理。


Try catch 结构


         用try…catch来代替我们常用的if语句结构来处理错误,我们用如下代码来改写上面的例子:

	try {
	  func() 
	} catch(e) {
	  alert(e)
	}

         如果在try块中出现错误,这个时候catch块会起作用,参数e被赋值为一个特别的异常对象,该对象包括异常发生时的一些信息。

         变量e是Error对象的一个实例(或者从TypeError,ReferenceError等继承)。

         这个错误的属性在不同浏览器有点不一样,详情参考 Error in MDN 和  Error inMSDN

但是基本属性是相同的:

name:错误类型,对于浏览器产生的error会匹配error构造函数如TypeError, ReferenceError 等。

message: 告诉我们更详细的error信息。

在以下例子中,我们在try块中增加其他声明,name和message会被打印出来。

	try {
	  var a = 5
	  var res = func(a) 
	  if (res > 0) doA()
	  else doB()
	} catch(e) {
	  alert("name:" + e.name + "\nmessage:" + e.message)
	}

很多异常都可以被try..catch捕获,你仅需通过try来检测可能的错误就行了。


获取栈的信息


         Firefox,Chrome, Opera浏览器提供了stack属性,通过stack属性我们可以看到所有导致异常的嵌套的调用信息,例子如下:

	function f(a) { 
	  g(a+1) 
	}
	function g(a) {
	  notexists;
	}
	try { f(1) } catch(e) { alert(e.stack)

         不幸的是在IE中没有这个属性,甚至在IE9中也没有。


Try…catch…finally完整形式


         完整的组成形式是由3部分组成:

	try {
	   .. try statemenets ..
	} catch(exception) {
	   .. catch statements ..
	} finally {
	   .. finally statements ..

执行过程如下:

1. Try中的声明会被执行,如果没有错误发生,catch部分会被忽视。

2. 如果错误发生,exception变量会被赋值为错误对象,并且catch中的声明也会被执行。

3. 在以上两种情况下,在try或者catch中不管有没有执行,finally代码都会被执行。


try…catch…finally…return


在以下例子中,如果try中有return语句并且有finally块时,finally中的执行完后,执行return语句。

    function inc(a) {
	  try {
	    return a+1
	  } catch(e) {
	    // ..
	  } finally {
	    alert('done')
	  }
	}
	alert( inc(1) )
//执行结果:‘done’, 2


Throw声明

所有的错误可以被分成两种:

1. 程序设计错误:一般是由开发人员造成的,如输入错误。

2. 异常流错误:这个错误是程序执行过程中的正常部分。一个常见的错误是表单验证。如果用户输入了一些错误,正常的做法是处理这个错误并且叫用户重复输入。

         用try…catch来处理异常错误,需要通过throw手动抛出错误。

         语法是:throw e,e可以是任何东西。不管你抛出什么,都可以被catch…捕获,但是如果在try块外面抛出程序可能会崩溃。

         下面的例子展示了throw是如何工作的。

	try {
	  throw 5
	} catch(e) {
	  alert("Caught: "+e)
	}


表单验证例子


         例如,我们对年龄进行验证,检查是否合法。

function validateAge(age) { // age is a text to check 
    if (age === '') return; // no age is valid
    age = +age
    if (isNaN(age)) {
        throw { name: 'BadAge', message: 'Invalid age' }
    }
    if (age < 5 || age > 150) {
        throw { name: 'BadAge', message: 'Age out of range' }
    }
}

try {
    var age = prompt("Enter your age please?") 
    validateAge(age)
    alert("The age is accepted!")
} catch(e) {
    alert("Error: "+e.message)
}

经常来说,抛出的异常对象最好是从Error对象继承,提供一种更好的方式来管理error在上面的例子中应该这样实现:throw new BadAgeError("Invalid age")。


验证变化


现在如果需要添加一个验证条件,验证用户所提供的值是必须提供的,并且是有效的年龄。比如我们实现了validateAge和validateRequired。

错误的检测方法

var value = input.value

    // VALIDATE

    var error = validateRequired(value)

    if (!error) {
        error = validateAge(value)
    }

    if (!error) { 
        /* another validator... */
    }
    // FINISHED VALIDATING
    if (error) {
        /* process error */
    } else {
        /* success */
}


Try…catch方法


这种方式就是当检测到错误时手动抛出。

    var value = input.value
	try {
	  validateRequired(value)
	  validateAge(value)
	  // other validators in a row
	  /* success */
	} catch(e) {
	  /* process error */
	}

我们不需要一个一个地来检测,只需要把可能出现错误的验证放到try块中就行了,如果一有错误,在catch中就会捕获到,没有错误自然很顺利地执行,不会进入到catch块中。


比较


用try..catch处理错误有一些优点和缺点:

1. Try…catch方法处理错误更干净、简单可依赖,能够捕获所有错误。

2. 有可能存在一些不能检测的异常,try…catch是唯一能解决的方法。例如检测浏览器的一些特性。

3. Try…catch结构会占据几行代码的位置,看起来代码不太优雅。


异常分析和重新抛出


         有时代码会产生不同的错误,这种情况下,经常用if来选择正确的处理方式。以下是伪代码。

try {
	  // 1. do smth
	} catch(e) {
	  if (e instanceof ValidationError) {
	    // 2.1 process e
	  } else if (e instanceof PermissionError) {
	    // 2.2 process e
	  } else {
	    // 3. we don't know how to deal with e
	    throw e
	  }
	}

1. 在try块中的代码比较复杂,也许会抛出异常,有些异常我们知道怎么处理,比如ValidationError,但是其他一些异常不知道。

2. 在catch块中,我们分析异常并且处理它。

3. 否则,异常重新抛出,假定在外面还有一层try…catch块知道怎么处理该异常。

异常要么被重新抛出,要么被处理,千万不要不管它,除非你完全知道你在做什么。

	try {
	  func()
	} catch(e) {
	  if (e instanceof KnownError) {
	    // ...
	  } 
	}

在上面代码片段中,除了KnownError异常外,其他异常都被忽视了。

坦白地说,在java的世界里有这种不处理异常的情况存在,但是留下不处理的异常总有隐患。

         想象下,如果在func中代码有输入错误,这将会很难调试,因为TypeError 和ReferenceError 异常被忽视了。


总结


1. Try…catch…finally结构允许你在try块中加入几种声明,可以在各自的catch块中进行异常处理。

2.  允许处理所有错误,包括JS自己产生的和手动抛出的。

3.  严格来说javaScript允许throw任何值,但是推荐所有的错误继承Error对象,形成继承层级。在这种情况下,instanceof 工作得很好。例如你可以捕获所有e instanceof ValidationError的异常,ValidationError包括AgeValidationError, RequiredValidationError 等。

作者:u013764803 发表于2014-6-21 23:44:22 原文链接
阅读:155 评论:0 查看评论

学动画应该掌握那些软件?

$
0
0
感谢 @叶比吕同学在评论区的指点!不胜感激!!妈妈,我用了五年的SAI,今天方知可以设置复制图层的快捷键,女儿不孝,蠢出境界了……TVT


在 SAI 和 ZBrush 两个方面有叶同学的指导,我会用引用标注出来。

—————————————————正文分割线————————————————————

额,要说哪种动画呢……算了,都说说好了。

只谈新媒体,因为这是我的专业。

新媒体承载的动画有三种,FLASH 动画,二维动画,三维动画。之所以把 FLASH 动画单拉出来是因为它同时可以做交互,不过这个应该不在题主的研究范围内,不提。

动画软件领域有几个大家:Adobe 家族,Autodesk 家族,Corel 家族,还有异军突起的日本 CELSYS 株式会社家(其实这家的产品只有一样,架不住忒好用所以我们放在这里)。

在接下来的介绍中我会从动画种类而非软件所在公司来安排。

一、FLASH 动画,或曰矢量动画


常用软件 Adobe Flash,它曾经是网络动画制作的翘楚,如今虽然仍有不小的地位,却再无当年风光,甚至于FLASH风格的动画有时候用 Adobe After Effect 做还更省事一点……稍微有点伤感。

但是这货操作简单,入手难度不大,最重要的是它是我朝大学必修,对于动画初学者,算是练手的不错作品,这年头有能耐 Word 都能做动画,软件嘛够用就行。
bilibili.com 的页面

总结:前任老妈子,虽然的确很好,但是稍微有点过时。

此君被广泛运用在欧美动画中,我们能够在迪斯尼式和好莱坞式的矢量动画中见到她的身影(小道消息是,蓝猫淘气也是用的它……这个我真不确定啊),基本上可以用它完成整个动画的制作。

总结:勤劳杂工,儿童电视动画引导者,自从3D横空出世,和前辈FLASH一样活计变少了。

二、二维动画

这个门类底下的要做的事情有点多,所以我们按制作步骤来说。

  • 二维动画首先要做分镜,然后做原画,要完全追求无纸化制作,有几种软件推荐:

首先是大名鼎鼎的 Adobe Photoshop,分镜得,原画亦得,就我个人的制作经验,更加喜欢用它画原画和逐帧,CS4【好像是吧?不太清楚】以后这货还能做动画了,虽然时间轴看上去很简陋,图层分起来也有点麻烦,但是熟悉之后是能够做得很好的,唯一的美中不足,大概是稍微有些吃内存……

总结:全能家政,只要你和她熟,就能什么都做得很好。


然后就是许多插画师很喜欢的 SAI,个人经验在分镜和草稿阶段用它做效果会很好,可恨 Adobe 至今不出抖动修正,Painter 对大多数人来说又太不友好,音清体柔个头小的 SAI 在这种时候就显得格外令人感到亲切……

当然它也有缺点,就是这货的图层操作和调色已经简陋到一个境界了,如果要做动画这种对颜色指定要求高的东西,会显得有些苦手,这里的颜色指定,不是说颜色准确度,而是指颜色协调度,PS里有许多方法可以做到这一点,SAI 连蒙版都没有,唯二滤镜是色相/饱和度和亮度/对比度,无法好好玩耍……图层操作方面,要复制图层本身,需要通过选区来达成,这就造成了复制后的图层还要重新控制着对齐原先的线条这样繁琐的操作,以一拖三为标准,一秒八帧,那手也是会断掉的……据说作者在重新编写程序,期待 SAI2 能更好吧。

@叶比吕同学教导了我们解决复制图层问题的方法,踹掉PS吧!
图层>复制图层——我忘了它原来是不是默认就有快捷键,总之因为我一直把ctrl+r指配给这个命令(随便分配快捷键这个功能超实用哒~其他任何命令也可以分配呀~),所以直接俩键复制图层,今天你就可以拥有!XDDD

总结:呆萌女仆,上手难度几乎没有,抖动修正手感一级棒,但是涉及更加精深的刻画和调整,还得回去找 PS。

  • 分镜和原画做完了,我们接下来要进入二维动画最枯燥的环节:逐帧作画。
诚然如今已经有很多动画方面的技术可以让我们偷懒,但是如果在它们出现之前我们的工作量是100%的话,有了它们之后我们的工作量顶多变成了70%——而且最累的那一环节依然没有得到精简。

除了之前说过的 PS 和 SAI 之外,还可以用:

同样是大名鼎鼎的 RETAS!相当于将有纸动画一比一的搬进了电脑!批量上色简直业界良心!线条整洁,矢量可调整,线稿修理十分方便,你甚至可以把纸上的画扫描进去让它生成矢量线稿,贴心到这个地步!她有四套软件,分别对应扫描描线、无纸作画、上色和后期,四款软件都能调用摄影表,对动画要求不高的人其实只需要这一款软件就可以做得很好了,不愧是制作出鲁邦三世的好软件!

当然问题也有,这货的上色比较局限于色彩比较少的人物,一旦人物身上的颜色超过六种,就比较容易悲剧,如果制作者追求更高的效果,它自带的后期是无法完成任务的,并且还有一点,无法做出效果很好的动背,所以我一般是用它描线和上色块,再导出PNG自己修。

总结:万能保姆,做得是很好啦,想要更好就没有啦。

  • 好了,吐血爆肝画完了,然后我们要面临的是动画背景的制作。
感谢现代科技,3D渲染2D技术已然成熟,具体可以看之前的预告片《我的师父姜子牙》中几段大透视的背景,以及新海诚老师《言叶之庭》中的背景(至少八成,尤其是那个鸟绕着钟楼飞的,开玩笑这个如果要用画的言叶之庭的预算估计会很可怕……),动背是一部动画中面积最大的东西,很大意义上奠定了动画的基调和风格,就给动画加入情感的阶段而言,新海诚之前大家比较侧重于使用镜头和动作刻画来表达氛围,但《秒速五厘米》刷新了我们的三观,或者对于常年关注动画的人来说,从《星之声》起,这三观就被刷新了不少,预算少而机器弱的独立动画制作人,可以通过对动画背景极其细致而感性的刻画,加上些许丁达尔现象的晕光,达到十分惊艳令人感动的画面效果——专业工作室中学这招最快的是京阿尼,从凉宫春日开始,再到 KON,再到冰菓中二病和境界的彼方,这是一个进化的过程,动背也许因为制作时间短的原因会稍有取舍,但是光晕真是越来越过分的——画面就果然很好看了。

稍微有点偏题,言归正传。

首先还是 PS 和 SAI,这俩在这一块尤其给力,SAI 细致的刻画,PS优秀的调色和材质,能够为我们帮上不少忙,如果搭配下者,至少短篇动画应该是够的。



依然大名鼎鼎的 Adobe After Effect,专业人士大概已经知道我想要怎么做了——在 PS 和 SAI 里单独画出背景的前中后景物,单独导出,然后拖进 AE,开3D图层模式,按照前中后排排好,搭好摄像机,调整摄像机参数,设置关键帧,这样我们就能得到一个移动起来有相对变化看起来好像很真实的动画背景——仅平面。当然也可以在AE里用3D图层架构立体物空间啦,这个在很多V家音乐PV里常见,比如neru的《How To 世界征服》里友达募集P就这么干了……那个教室的空间,四面墙就是这样搭的,当然也许人家有更高端的方法……我对AE没有PS那么熟_(:з」∠)_
【鏡音リン・レン】 how to世界征服 【PV付】
这段有点像教程,主要是我个人的经验,我自己在制作过程中觉得她很好用,但其实人家更擅长后期……在动背这里,我们能看到很多其实是干别的的软件来客串,对于动画制作,我们要遵循拿来主义(喂),啥好用就用,管它之前是干什么的……

总结:强力外援,黑喵抓住老鼠就是好喵。



Autodesk 双连杀!下面那个是 MAYA,关于它们俩谁更适合做动画背景这个,真是仁者见仁了,所以我就把它们放一起,其实 3DMAX 本来不是A家的,但奈何 Discreet 家卖掉了喜儿,不对,它是把自己带着喜儿一起嫁给了A百万,所以我们如今看到的,就是3D 软件界被魔王统治的局面——也没啥不好,这俩,尤其是3DMAX,自从跟了A百万,操作界面从“(╯‵□′)╯︵┻━┻你特么啥!”变成了“( ˘•ω•˘ )虽然还是烦,但是好歹没那么烦”,通过他们建好模型贴好图,摄像机运起分镜计划好的镜头,再运用卡通渲染技术把它2D化,省时省力制作精良,把人物动画在 AE 里合成进去,成就感!

总结:强强力外援,白喵抓住老鼠也是好喵。


最后就个人经验的推荐是:草稿分镜用 SAI,当然更好用纸笔,原画用 PS 或者 SAI,逐帧绘画用 PS 、SAI 或 Retas,至于 Painter,它侧重于艺术类电脑绘画,个人不推荐,动背用 PS 、SAI 或者3D转2D,后期合成用 AE。

先介绍到这里,后面还有二维动画的后期制作方面,和三维动画的软件介绍,深夜已至,为我脸上的黑眼圈和我的肝着想,先睡去,明天再更。

————————————————美容觉的分割线———————————————————

看书看过了早饭和午饭,怒啃提子方包。



  • 做完了前期的动画,这个时候基本上已经要吐魂了,更惨的是,画面效果完全不酷炫!如果是色指定非常严格的动画,在这一步之前画面都是灰的!不是所有人都跟新海诚似的有闲到给明暗交界再刷一层纯亮色的啊!绝望了!对这个看起来像是一坨翔的玩意儿绝望了!
————后期拯救你!
关于动画后期,二维动画的后期和三维比简单得多,无非调色、特效、氛围,如果做的是图形运动动画,后期很多时候是声音方面的调整和叠材质,像是《84000·佛典传译》的宣传动画,虽然这项目本身槽点颇多,但动画真是十分优秀啊——看了看工作室是Giant Ant Studio,怪不得……
腾讯视频
后期是一个一开始会让制作者愉快到后来会让制作者纠结细小的参数纠结到崩溃的步骤,因为很多时候你很难界定两个方案之间谁会更美,商业化会建立标准,独立制作就要自己判断,也许你觉得这个效果不错,但是一个不小心可能会影响到全片的氛围和风格,需要强大的目的观和自制力才能下狠手把它改掉——真的很伤心啊!我一般会另存一个表示这参数没准别的片子里可以用……虽然似乎从没用过= =。



首先还是 AE,身为影视后期之王,虽然某些细小的方面比如调色被达芬奇这样的专注调色方案不干别的的软件抢了点生意,但是它的优越地位依然屹立不倒(如果你看到了奇怪的即视感,请联系我),CS4.5之后的操作性得到了一次飞跃,在这之前的一切奇葩界面比如输入时间码居然是点了时间之后跳出小框来设置参数这么麻烦的东西已经完全消失,变成了十分有亲和力长得又漂亮的美人儿,连带的我做动画的心情都好了,AE 的战斗力在于,它完美地继承了 Adobe 家族 【上手不易,深入容易】【人有多大胆,地有多大产】的优良传统,高阶制作者可以用它在视频中玩出花来,这其中有一部分要归功于 AE 的特效插件体系。

所谓特效插件体系,就是 AE 的“效果和预置”模块,自带特效和预置已然可以很好地制作出优秀的作品,但要到专业荧屏级,或者想做更高端的动画,就有些力有不逮,但 AE 发挥了人民群众的力量——外挂插件。

外挂插件有名的有几个,稍微介绍一下:
  1. Twitch,浓缩就是精华,浓缩就是正义,这货只有一个效果,其下六种主特效:模糊、色彩、照明、比例、滑动、时间,搭配相应不同参数设置,又有26种预置,涵盖各个方面,几乎是 Twitch 在手,天下我有,具体怎么用,这个属于你要自己去摸索的方面,AE 特效是不上手玩坏它就不懂它怎么用的东西,所以我只会介绍一些我觉得好用的以供参考。
  2. 蓝宝石,大名鼎鼎也傲娇顶顶,注册码经常抽(叫你不花钱买),特效也经常抽……架不住好用啊,模糊有各种不同的模糊方案,抖动有各种不同抖动的方案,还有颜色啊氛围啊,都有很好的方案,预置也搭配得很好,具体有多好,就不要为难一个英语废了……我一般用搜单词+拖出来试试看的方法来找效果。
  3. 红巨星,粒子极美,主要悲剧在于……嗯……没有中文版TVT,如果说蓝宝石没有中文班我还能瞎猫碰死耗子,这个真不行啊,参数和选项太多了……磨合期长且久,但是真的比CC的粒子好看,所以继续面对着完全不懂的英语,各种胡搞了解参数对应的是什么,还有一个方法就是去看教程,这个好歹有字幕,不在这里多提。
  4. Optical Flares,这是一个我个人很推荐的光晕插件,有了它,太阳光灯泡光反光七彩光再也不是困扰!分分钟闪瞎狗眼!光本身还能有透视!动起来真实度爆表!五星推荐!
以上三种几乎就能满足毕业设计这样的作品了,这都是 AE 的后宫呀,各个环肥燕瘦,想要和她们搞好关系,的确不容易,但是佳人在前,其他的阿猫阿狗已然不能满足了,只好苦心追求,以求鸾凤和鸣,达成人生的大圆满(喂)。

插一句话,AE 方面国内外有教程也有模板分享,善用可以省不少事。

总结:后宫三千的大神,跪拜吧庶民!


二维动画的后期基本上就是 AE 了,包罗万象包君满意,有了一生挚爱为啥要选别家野花儿,考虑到别的比如达芬奇啊 FC 啊都是影视后期制作的东西,不在动画范畴,就不深展开,善用 AE 就好了,别的基本上没啥很全的,因为 Adobe 是魔王嘛,平面媒体基本上就它家了。





三、三维动画

欢迎来到土豪的世界。

这里我就泛泛而谈一下,不单列,主要是因为我自己也用得不多,大华师其穷已然超神,我也就偶尔建个模玩,做动画什么的,看到渲染球就痛不欲生……

3D是个崭新而深邃的世界,其中充满铜臭,却又美丽无比。

在这里有非垃圾桶不可的软件,有软件基础推荐配置随便算算就要2w+的硬件,有就算这样最后渲染还是要拖很久的渲染器,然后我们就会深刻意识到现代艺术是有多依赖金钱——梵高尚可蹲在乡下画油画,要是梵高是个三维动画师,蹲乡下就是个伪命题,乡下网速不高啊!怎么翻素材!全存盘里吗!那盘得多少T?!一块以T为单位的硬盘,还想便宜啊?!

刚才我什么都没说,忘掉忘掉。

三维动画制作界,就平民制作来说,只需要看 Autodesk 大魔王家众多儿女就好了,除了前面的3DMAX 和 MAYA,还有比如 CAD 这样虽然更广泛用于工业设计但是也不妨碍我们拿它做建筑的小能手,好了家财没过百万的同志们可以去查资料了,下面的东西比较烧钱。

就商业大片来说,还有一个必不可少的东西,叫引擎。

游戏爱好者也许会熟悉这个,但是很多人似乎不知道引擎这玩意儿其实用在三维动画的时候更多……狗大户(愤恨状)如迪士尼,自家自己开发引擎,据说梦工厂和福克斯的引擎也是自己开发的,但是显然不如迪士尼的好——这一点在冰雪奇缘中得到了铁一般的证实,雪花的物理属性被完美地呈现出来了,我总是在想,这样的引擎,本身就很美了。

预算也很美,1.5亿刀,换成人民币,高山仰止……

如果你只是想建模之后做短篇动画,前面推荐的A百万系列已经能够完成了,要提醒的一点是,Zbrush 的领域在于3D 艺术创作和人偶模型方面,如果运用到动画中,它生成的面不够工整,而且太多了,放进游戏也许能让人忍受,放进动画这种凝视艺术中就比较不好,当然你想用它来激发灵感是没有问题的,但是同样的这货也没有中文版╮(╯▽╰)╭

在这里, @叶比吕同学也有非常棒的经验,实在太感谢了,干脆您去开个新答案,我把我的删了好了……越看越渣啊TVT!

游戏并不是它最发挥的领域,最发挥的正是在凝视艺术领域中:电影和动画。它是完全可以和maya/max等主流3D软件完全连通使用的。如果不知道中间那些麻烦复杂的pipeline的话确实会觉得“日哟,在这里把模型建出个花儿来有毛用!”——咳咳,要真那样的话它哪儿活得到今天一早被业界抛弃了……能实际用于production的软件才有意义撒。一般都是在ZB里sculpt完了后降低subdivision level(当然不能直接把上千万级别polygon的模型直接转回来,多好的机器也得死),把所雕刻的细节用displacement map和normal map等方式带回maya等主流3D制作软件……甚至贴图也可以直接在里面画好带回来,还可以用投射的方式把找好的参考图片直接刷到模型上(就是不能像C4D一样同一个object分很多层画不太爽)
maya/max里建好粗模(把线排得美美哒),然后再丢进ZB去细雕(因为这样再分面它就会按照你粗模的布线去细分而不用担心布线变得太糟。当然了……我坚信有深度ZB患者是直接在ZB里用Z-sphere从头开始搞粗模的……还是看个人的习惯程度吧,我反正是……不喜欢……)。其实我觉得ZB的重点并不在于是不是非要有解剖基础……你说我要想做一个风格化的角色甚至一非生物模型呢(枪械、头盔、机器人…请自由的~)……并不是非要都做写实它才有用,它的重点(当然也是个人观点)我脚着在于“超级易用的建模手段”,比maya/max这种传统的3D软件要更直观方便——当然前提和其他软件一样:用熟了

评论里有说到MMD和CSA两个引擎,我是觉得这俩只能做宅舞来用……做故事MMD不行,CSA也差得远。当然 @加刘景长说的用它们做场景是完全可以的,我甚至觉得没准会比MAYA和3DMAX更方便……有时间试试看。

三维动画是被主流认可的动画艺术形式,二维挣扎于搬上大屏幕就空空一片的漩涡,三维却是有真正的纵深的,这就注定这种动画不适合独立制作人——离最先进的太远了,如果真的要追求最高的那种效果,只能做出小短片,小短片只能拿去参赛做广告而已。

很好玩的一点是,二维动画在引入三维技术给自己提供纵深,三维动画自己却开始喜欢把自己装成二维动画……这个技术就是所谓的卡通渲染,原理这里有个帖子可作入门: 非真实渲染技术(NPR)-1.卡通渲染
作品的话,隔壁广美家去年毕设做了个《开飞机的鸡》,可以参考一下,他们这个技术很成熟了 毕业季2013@广美 亮点在于美术指导是李安……!!!!!!w(゚Д゚)w吓cry!!!!最后深海那一段,的确很有少年派要把人吓出深海恐惧症的风格……

说引擎不是为了吓答主,只是三维动画的领域普通人的确不好掌握,人物建模这方面,解剖学知识不过关就很容易捏出火柴人,摄像机架构方面,没有一定专业知识也不好做得漂亮,而且真的是太烧钱,纳米核心为啥只有三集?



最后一总览,看起来挺吓人的,要装这么多软件就很吓人了,还要学这么多,还要升级设备。

但是这些都不是问题的,如果你真想要把心中的故事讲出来,什么都不是问题。

—————————————接下来是题外话的扯淡干货到此为止—————————————

很多时候不是不能做,而是不想做。

高端如冰雪奇缘,仍然有大量必须手工修整完成的效果,在这之前它经历了一帧渲染一天的难耐,出来后还要让美工一帧帧修改补充,这是迪士尼对动画的爱意,背后是近百年的品牌信誉,它就愿意去逐帧逐帧修改,愿意精益求精,愿意把动画逼到最好,荧屏艺术发展到现在,我们的梦想越发容易被描绘,科学和艺术从未有如此的亲近过,迪士尼还会讲王子和公主,但是又不单是讲王子和公主,我在它身上看到了电影艺术的前世今生以及未来,世界还有那么多美丽的故事。
【AnimeTaste】Silent

软件不是全部,它甚至不是制作动画的必要条件,它只是让我们能做得更好的途径,不是有了它我们才能做动画的理由,在没有汽车的年代,人们想要去看望隔壁县城的亲友,要跋涉几十里几百里的路去寻找,中间也许没有逆旅,也许会有山贼,也许干粮不够,但是“想要见你,看看你好不好”的心情支持着古人,会让他们最后达成所愿,如今不仅汽车,飞机高铁都有了,甚至视频对话也很方便了,人反而怠惰了。

机会越多,就越不被珍惜。

动画作为一门艺术,它的年纪比起各位前辈堪称幼齿,从翻页小动画开始,再到电影开始前五分钟的小消遣,再到绑定各种公司的长篇广告,再到独立动画,到电视动画,到儿童专属,到一个个角色和故事,到搬上荧屏,到被世界接受,这才两百年不到的历史,和其他艺术形式相比,只是一个蹒跚的孩童,但它有无限的希望,它带给我们新的世界,新的眼光,新的感受,敦煌莫高窟的匠人,如果能够掌握现在的技术,会画出怎样的飞天?志怪小说的作者,来到现代,能写出怎样的剧本?他们没看到这样的好时代,我们作为他们的精神传人,总该试着认真地,向世界讲述属于中国的美丽故事。

天马行空的幻想是动画的源泉,画面中会动的美丽世界,是制作者和观众共同的乐土,在没有这些便利软件的年代,想要达到满意的效果难如登天,在软件便利的年代,动画却又回到了长篇广告的境地,人们在不停地寻找捷径,寻找快速制作的方法,寻找不费事就能做出动画的技术,一帧帧去画去雕琢的精神,在独立动画人身上慢慢消散,视觉快感和激情的贩售变得寻常且不以为耻,方便的软件不止方便了追求梦想的人,也方便了淘金者。

但是并不需要感到悲观,对未来,对现在,都应该乐观,我们是见证动画成长的人,就算是在现在,也依然有优秀的动画作品和那些捞钱的分庭抗礼,大浪淘沙,沙子会被筛走,变成几十年后没人在意的什么东西,而金子会被珍重地留下来,经过锤炼,变成宝物。

写这些的时候,我一直在想之前看过的一个短片,2000年奥斯卡最佳动画短片奖获得者,亚历山大·彼得洛夫的《老人与海》,这是一部定格动画,每一帧都用油画描绘,完美地再现了厄纳斯特·海明威的传世名作《老人与海》,在这之前,亚历山大·彼得洛夫已经用油画这种方法制作动画十五年了,无论是亚历山大·彼得洛夫,还是厄纳斯特·海明威,还是《老人与海》,都与我想说的如出一辙——千里之行,始于足下,道阻且长,且行且稳当。

《老人与海》动画电影 视频

最后,再次感谢评论区包括 @叶比吕同学在内的诸位,互相交流太有助于提升自己了,谢谢大家!

— 完 —
本文作者: 王莫良

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)
延伸阅读:
国产动画片有哪些佳作?
如何解读 EVA 动画?

ORACLE 五种表的优缺点总结

$
0
0

ORACLE 五种表的优缺点总结:
1,普通表(heap table):适合大部分设计场景,有优点也有缺点。
优点:
a,语法简单方便
b,适合大部分场景
缺点:
a,更新日志开销较大
b,Delete无法释放空间(HWM High Water Mark不下降)
c,表记录太大检索太慢
d,索引回表读开销很大
e,即便有序插入,也很难保证有序读出

2,全局临时表:适合接口表设计
优点:
a,高效删除
b,产生很少的日志
c,不同的SESSION独立,不产生锁
缺点:
a,语法特别
b,数据无法得到有效的保护
全局临时表分两类:
一个是基于会话的全局临时表(on commit preserve rows),一个是基于事务的全局临时表(on commit delete rows),下面就是创建的例子:
create global temporary table T_TMP_SESSION on commit preserve rows as select * from dba_objects;
create global temporary table T_TMP_TRANSACTION on commit delete rows as select * from dba_objects;

3,分区表:尤其适合日志表,非常大的表
优点:
a,有效的分区消除 (分区裁剪)
b,高效的记录清理(即可以对某一个分区进行truncate)
c,高效的记录转移(分区交换)
缺点:
a,语法复杂
b,分区过多对系统有一定的影响

4,索引组织表:适合极少更新的表
优点:
a,表就是索引,可以避免回表
缺点:
a,语法复杂
b,更新开销较大

5,蔟表:使用频繁关联查询的多表
优点:
a,可以减少或避免排序
缺点:
a,语法复杂
b,表更新开销大

作者:waterxcfg304 发表于2014-6-21 22:00:24 原文链接
阅读:102 评论:0 查看评论

开源爬虫Labin,Nutch,Neritrix介绍和对比

$
0
0

Larbin
开发语言:C++
http://larbin.sourceforge.net/index-eng.html
larbin是个基于C++的web爬虫工具,拥有易于操作的界面,不过只能跑在LINUX下,在一台普通PC下larbin每天可以爬5百万个页面(当然啦,需要拥有良好的网络)

简介

Larbin是一种开源的网络爬虫/网络蜘蛛,由法国的年轻人 Sébastien Ailleret独立开发。larbin目的是能够跟踪页面的url进行扩展的抓取,最后为搜索引擎提供广泛的数据来源。
Larbin只是一个爬虫,也就是说larbin只抓取网页,至于如何parse的事情则由用户自己完成。另外,如何存储到数据库以及建立索引的事情 larbin也不提供。
Latbin最初的设计也是依据设计简单但是高度可配置性的原则,因此我们可以看到,一个简单的larbin的爬虫可以每天获取500万的网页,非常高效。
      
功能
      1. larbin 获取单个、确定网站的所有联结,甚至可以镜像一个网站。
      2. larbin建立 url 列表群,例如针对所有的网页进行 url retrive后,进行xml的联结的获取。或者是 mp3 。
      3. larbin 定制后可以作为搜索引擎的信息的来源(例如可以将抓取下来的网页每2000一组存放在一系列的目录结构里面)。

问题
Labin的主要问题是,:

仅提供保存网页保存功能,没有进行进一步的网页解析;

不支持分布式系统;

功能相对简单,提供的配置项也不够多;

不支持网页自动重访,更新功能;

从2003年底以后,Labin已经放弃更新,目前处于荒芜长草的状态

 

 

**********

Nutch
开发语言:Java
http://lucene.apache.org/nutch/

 

简介:

Apache的子项目之一,属于Lucene项目下的子项目。

Nutch是一个基于Lucene,类似Google的完整网络搜索引擎解决方案,基于Hadoop的分布式处理模型保证了系统的性能,类似Eclipse的插件机制保证了系统的可客户化,而且很容易集成到自己的应用之中。 
 总体上Nutch可以分为2个部分:抓取部分和搜索部分。抓取程序抓取页面并把抓取回来的数据做成反向索引,搜索程序则对反向索引搜索回答用户的请求。抓取程序和搜索程序的接口是索引,两者都使用索引中的字段。抓取程序和搜索程序可以分别位于不同的机器上。下面详细介绍一下抓取部分。

抓取部分:
  抓取程序是被Nutch的抓取工具驱动的。这是一组工具,用来建立和维护几个不同的数据结构: web database, a set of segments, and the index。下面逐个解释这三个不同的数据结构:
    1、The web database, 或者WebDB。这是一个特殊存储数据结构,用来映像被抓取网站数据的结构和属性的集合。WebDB 用来存储从抓取开始(包括重新抓取)的所有网站结构数据和属性。WebDB 只是被 抓取程序使用,搜索程序并不使用它。WebDB 存储2种实体:页面 和 链接。页面 表示 网络上的一个网页,这个网页的Url作为标示被索引,同时建立一个对网页内容的MD5 哈希签名。跟网页相关的其它内容也被存储,包括:页面中的链接数量(外链接),页面抓取信息(在页面被重复抓取的情况下),还有表示页面级别的分数 score 。链接 表示从一个网页的链接到其它网页的链接。因此 WebDB 可以说是一个网络图,节点是页面,链接是边。
    2、Segment 。这是网页的集合,并且它被索引。Segment的Fetchlist 是抓取程序使用的url列表,它是从 WebDB中生成的。Fetcher 的输出数据是从 fetchlist 中抓取的网页。Fetcher的输出数据先被反向索引,然后索引后的结果被存储在segment 中。 Segment的生命周期是有限制的,当下一轮抓取开始后它就没有用了。默认的 重新抓取间隔是30天。因此删除超过这个时间期限的segment是可以的。而且也可以节省不少磁盘空间。Segment 的命名是日期加时间,因此很直观的可以看出他们的存活周期。
    3、The index。索引库是反向索引所有系统中被抓取的页面,它并不直接从页面反向索引产生,而是合并很多小的segment的索引产生的。Nutch 使用 Lucene 来建立索引,因此所有Lucene相关的工具 API 都用来建立索引库。需要说明的是Lucene的segment 的概念和Nutch的segment概念是完全不同的,不要混淆。简单来说 Lucene 的 segment 是 Lucene 索引库的一部分,而Nutch 的Segment是WebDB中被抓取和索引的一部分。
抓取过程详解:

      抓取是一个循环的过程:抓取工具从WebDB中生成了一个 fetchlist 集合;抽取工具根据fetchlist从网络上下载网页内容;工具程序根据抽取工具发现的新链接更新WebDB;然后再生成新的fetchlist;周而复始。这个抓取循环在nutch中经常指: generate/fetch/update 循环。
    一般来说同一域名下的 url 链接会被合成到同一个 fetchlist。这样做的考虑是:当同时使用多个工具抓取的时候,不会产生重复抓取的现象。Nutch 遵循 Robots Exclusion Protocol, 可以用robots.txt 定义保护私有网页数据不被抓去。
    上面这个抓取工具的组合是Nutch的最外层的,也可以直接使用更底层的工具,自己组合这些底层工具的执行顺序达到同样的结果。这是Nutch吸引人的地方。下面把上述过程分别详述一下,括号内就是底层工具的名字:
    1、创建一个新的WebDB (admin db -create)。
    2、把开始抓取的跟Url 放入WebDb (inject)。
    3、从WebDb的新 segment 中生成 fetchlist (generate)。
    4、根据 fetchlist 列表抓取网页的内容 (fetch)。
    5、根据抓取回来的网页链接url更新 WebDB (updatedb)。
    6、重复上面3-5个步骤直到到达指定的抓取层数。
    7、用计算出来的网页url权重 scores 更新 segments (updatesegs)。
    8、对抓取回来的网页建立索引(index)。
    9、在索引中消除重复的内容和重复的url (dedup)。
    10、合并多个索引到一个大索引,为搜索提供索引库(merge)。

 

*****************

Heritrix
开发语言:Java
http://crawler.archive.org/
Heritrix是一个开源,可扩展的web爬虫项目。Heritrix设计成严格按照robots.txt文件的排除指示和META robots标签。


简介

Heritrix与Nutch对比

和 Nutch。二者均为Java开源框架,Heritrix 是 SourceForge上的开源产品,Nutch为Apache的一个子项目,它们都称作网络爬虫/蜘蛛( Web Crawler),它们实现的原理基本一致:深度遍历网站的资源,将这些资源抓取到本地,使用的方法都是分析网站每一个有效的URI,并提交Http请求,从而获得相应结果,生成本地文件及相应的日志信息等。

Heritrix 是个 "archival crawler" -- 用来获取完整的、精确的、站点内容的深度复制。包括获取图像以及其他非文本内容。抓取并存储相关的内容。对内容来者不拒,不对页面进行内容上的修改。重新爬行对相同的URL不针对先前的进行替换。爬虫通过Web用户界面启动、监控、调整,允许弹性的定义要获取的URL。

 

Nutch和Heritrix的差异:

Nutch 只获取并保存可索引的内容。Heritrix则是照单全收。力求保存页面原貌

Nutch 可以修剪内容,或者对内容格式进行转换。

Nutch 保存内容为数据库优化格式便于以后索引;刷新替换旧的内容。而Heritrix 是添加(追加)新的内容。

Nutch 从命令行运行、控制。Heritrix 有 Web 控制管理界面。

Nutch 的定制能力不够强,不过现在已经有了一定改进。Heritrix 可控制的参数更多。

Heritrix提供的功能没有nutch多,有点整站下载的味道。既没有索引又没有解析,甚至对于重复爬取URL都处理不是很好。

Heritrix的功能强大 但是配置起来却有点麻烦。

 

 

*********************

 

三者的比较
一、从功能方面来说,Heritrix与Larbin的功能类似。都是一个纯粹的网络爬虫,提供网站的镜像下载。而Nutch是一个网络搜索引擎框架,爬取网页只是其功能的一部分。

二、从分布式处理来说,Nutch支持分布式处理,而另外两个好像尚且还没有支持。

三、从爬取的网页存储方式来说,Heritrix和 Larbin都是将爬取下来的内容保存为原始类型的内容。而Nutch是将内容保存到其特定格式的segment中去。

四,对于爬取下来的内容的处理来说,Heritrix和 Larbin都是将爬取下来的内容不经处理直接保存为原始内容。而Nutch对文本进行了包括链接分析、正文提取、建立索引(Lucene索引)等处理。

五,从爬取的效率来说,Larbin效率较高,因为其是使用c++实现的并且功能单一。

 

 

 

crawler

开发

语言

功能

单一

支持分布式

爬取

效率

镜像

保存

Nutch

Java

×

×

Larbin

C++

×

Heritrix

Java

×


-----------------------------------------------------------

 

其它一些开源爬虫汇总:


WebSPHINX 
WebSPHINX是一个Java类包和Web爬虫的交互式开发环境。Web爬虫(也叫作机器人或蜘蛛)是可以自动浏览与处理Web页面的程序。WebSPHINX由两部分组成:爬虫工作平台和WebSPHINX类包。
http://www.cs.cmu.edu/~rcm/websphinx/

WebLech 
WebLech是一个功能强大的Web站点下载与镜像工具。它支持按功能需求来下载web站点并能够尽可能模仿标准Web浏览器的行为。WebLech有一个功能控制台并采用多线程操作。
http://weblech.sourceforge.net/
Arale 
Arale主要为个人使用而设计,而没有像其它爬虫一样是关注于页面索引。Arale能够下载整个web站点或来自web站点的某些资源。Arale还能够把动态页面映射成静态页面。
http://web.tiscali.it/_flat/arale.jsp.html

J-Spider 
J-Spider:是一个完全可配置和定制的Web Spider引擎.你可以利用它来检查网站的错误(内在的服务器错误等),网站内外部链接检查,分析网站的结构(可创建一个网站地图),下载整个Web站点,你还可以写一个JSpider插件来扩展你所需要的功能。
http://j-spider.sourceforge.net/

spindle 
spindle 是一个构建在Lucene工具包之上的Web索引/搜索工具.它包括一个用于创建索引的HTTP spider和一个用于搜索这些索引的搜索类。spindle项目提供了一组JSP标签库使得那些基于JSP的站点不需要开发任何Java类就能够增加搜索功能。
http://www.bitmechanic.com/projects/spindle/

Arachnid 
Arachnid: 是一个基于Java的web spider框架.它包含一个简单的HTML剖析器能够分析包含HTML内容的输入流.通过实现Arachnid的子类就能够开发一个简单的Web spiders并能够在Web站上的每个页面被解析之后增加几行代码调用。 Arachnid的下载包中包含两个spider应用程序例子用于演示如何使用该框架。
http://arachnid.sourceforge.net/

LARM 
LARM能够为Jakarta Lucene搜索引擎框架的用户提供一个纯Java的搜索解决方案。它包含能够为文件,数据库表格建立索引的方法和为Web站点建索引的爬虫。
http://larm.sourceforge.net/

JoBo 
JoBo 是一个用于下载整个Web站点的简单工具。它本质是一个Web Spider。与其它下载工具相比较它的主要优势是能够自动填充form(如:自动登录)和使用cookies来处理session。JoBo还有灵活的下载规则(如:通过网页的URL,大小,MIME类型等)来限制下载。
http://www.matuschek.net/software/jobo/index.html

snoics-reptile 
snoics -reptile是用纯Java开发的,用来进行网站镜像抓取的工具,可以使用配制文件中提供的URL入口,把这个网站所有的能用浏览器通过GET的方式获取到的资源全部抓取到本地,包括网页和各种类型的文件,如:图片、flash、mp3、zip、rar、exe等文件。可以将整个网站完整地下传至硬盘内,并能保持原有的网站结构精确不变。只需要把抓取下来的网站放到web服务器(如:Apache)中,就可以实现完整的网站镜像。
http://www.blogjava.net/snoics

Web-Harvest 
Web-Harvest是一个Java开源Web数据抽取工具。它能够收集指定的Web页面并从这些页面中提取有用的数据。Web-Harvest主要是运用了像XSLT,XQuery,正则表达式等这些技术来实现对text/xml的操作。
http://web-harvest.sourceforge.net

spiderpy
spiderpy是一个基于Python编码的一个开源web爬虫工具,允许用户收集文件和搜索网站,并有一个可配置的界面。
http://pyspider.sourceforge.net/

The Spider Web Network Xoops Mod Team 
pider Web Network Xoops Mod是一个Xoops下的模块,完全由PHP语言实现。
http://www.tswn.com/



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



一个简单的Java集合范围过滤的多个方式对比

$
0
0
在一个项目里面有这么一个技术需求:
1.集合中元素个数,10M
2.根据上限和下限从一个Set中过滤出满足要求的元素集合.

实际这个是个很典型的技术要求, 之前的项目也遇见过,但是因为当时的类库不多, 都是直接手写实现的. 方式基本等同于第一个方式.

在这个过程中, 我写了四个方式, 基本记录到下面.
第一个方式:对Set进行迭代器遍历, 判断每个元素是否都在上限和下限范围中.如果满足则添加到结果集合中, 最后返回结果集合.
            测试效果:集合大小100K, 运算时间 3000ms+
过滤部分的逻辑如下:
 1     void filerSet(Set<BigDecimal> targetSet, String lower, String higher) {
 2         BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
 3         BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
 4 
 5         Set<BigDecimal> returnSet = new HashSet<BigDecimal>();
 6         for (BigDecimal object : targetSet) {
 7             if (isInRange(object, bdLower, bdHigher)) {
 8                 returnSet.add(object);
 9             }
10         }
11     }
12 
13     private boolean isInRange(BigDecimal object, BigDecimal bdLower,
14             BigDecimal bdHigher) {
15         return object.compareTo(bdLower) >= 0
16                 && object.compareTo(bdHigher) <= 0;
17     }
第二个方式: 借助TreeSet, 原始集合进行排序, 然后直接subset.
            测试效果: 集合大小10M, 运算时间: 12000ms+(获得TreeSet) , 200ms(获得结果)
过滤部分的逻辑如下(非常繁琐):
  1     Set<BigDecimal> getSubSet(TreeSet<BigDecimal> targetSet, String lower,
  2             String higher) {
  3 
  4         BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
  5         BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
  6 
  7         if ((bdHigher.compareTo(targetSet.first()) == -1)
  8                 || (bdLower.compareTo(targetSet.last()) == 1)) {
  9             return null;
 10         }
 11 
 12         boolean hasLower = targetSet.contains(bdLower);
 13         boolean hasHigher = targetSet.contains(bdHigher);
 14         if (hasLower) {
 15             if (hasHigher) {
 16                 System.out.println("get start:" + bdLower);
 17                 System.out.println("get end:" + bdHigher);
 18                 return targetSet.subSet(bdLower, true, bdHigher, true);
 19             } else {
 20                 BigDecimal newEnd = null;
 21                 System.out.println("get start:" + bdLower);
 22                 SortedSet<BigDecimal> returnSet = null;
 23                 if (bdHigher.compareTo(targetSet.last()) != -1) {
 24                     newEnd = targetSet.last();
 25                 } else {
 26                     SortedSet<BigDecimal> newTargetSet = targetSet
 27                             .tailSet(bdLower);
 28                     for (BigDecimal object : newTargetSet) {
 29                         if (object.compareTo(bdHigher) == 1) {
 30                             newEnd = object;
 31                             break;
 32                         } else if (object.compareTo(bdHigher) == 0) {
 33                             newEnd = object;
 34                             break;
 35                         }
 36                     }
 37                 }
 38                 returnSet = targetSet.subSet(bdLower, true, newEnd, true);
 39                 if (newEnd.compareTo(bdHigher) == 1) {
 40                     returnSet.remove(newEnd);
 41                 }
 42                 return returnSet;
 43             }
 44 
 45         } else {
 46             if (hasHigher) {
 47                 System.out.println("get end:" + bdHigher);
 48                 TreeSet<BigDecimal> newTargetSet = (TreeSet<BigDecimal>) targetSet
 49                         .headSet(bdHigher, true);
 50                 BigDecimal newStart = null;
 51                 SortedSet<BigDecimal> returnSet = null;
 52 
 53                 if (bdLower.compareTo(targetSet.first()) == -1) {
 54                     newStart = targetSet.first();
 55                 } else {
 56                     for (BigDecimal object : newTargetSet) {
 57                         if (object.compareTo(bdLower) != -1) {
 58                             newStart = object;
 59                             break;
 60                         }
 61                     }
 62                 }
 63                 returnSet = targetSet.subSet(newStart, true, bdHigher, true);
 64 
 65                 return returnSet;
 66             } else {
 67                 System.out.println("Not get start:" + bdLower);
 68                 System.out.println("Not get end:" + bdHigher);
 69                 BigDecimal newStart = null;
 70                 BigDecimal newEnd = null;
 71                 if (bdHigher.compareTo(targetSet.last()) != -1) {
 72                     newEnd = targetSet.last();
 73                 }
 74                 if (bdLower.compareTo(targetSet.first()) == -1) {
 75                     newStart = targetSet.first();
 76                 }
 77                 for (BigDecimal object : targetSet) {
 78                     if (newStart == null) {
 79                         if (object.compareTo(bdLower) != -1) {
 80                             newStart = object;
 81                             if (newEnd != null) {
 82                                 break;
 83                             }
 84                         }
 85                     }
 86 
 87                     if (newEnd == null) {
 88                         if (object.compareTo(bdHigher) != -1) {
 89                             newEnd = object;
 90                             if (newStart != null) {
 91                                 break;
 92                             }
 93                         }
 94                     }
 95                 }
 96 
 97                 if (newStart == null) {
 98                     if (newEnd == null) {
 99                         if ((bdHigher.compareTo(targetSet.first()) == -1)
100                                 || (bdLower.compareTo(targetSet.last()) == 1)) {
101                             return null;
102                         }
103                         return targetSet;
104                     } else {
105                         SortedSet<BigDecimal> newTargetSet = targetSet.headSet(
106                                 newEnd, true);
107                         if (newEnd.compareTo(bdHigher) == 1) {
108                             newTargetSet.remove(newEnd);
109                         }
110                         return newTargetSet;
111                     }
112                 } else {
113                     if (newEnd == null) {
114                         SortedSet<BigDecimal> newTargetSet = targetSet.tailSet(
115                                 newStart, true);
116                         return newTargetSet;
117                     } else {
118                         SortedSet<BigDecimal> newTargetSet = targetSet.subSet(
119                                 newStart, true, newEnd, true);
120                         if (newEnd.compareTo(bdHigher) == 1) {
121                             newTargetSet.remove(newEnd);
122                         }
123                         return newTargetSet;
124                     }
125                 }
126             }
127         }
128     }
第三种方式: 使用Apache Commons Collections, 直接对于原始Set进行filter.
            测试效果:集合大小10M,过滤结果1M, 运算时间: 1000ms+
过滤部分的代码如下:
 1 //过滤的主体逻辑
 2     void filterSet(Set<BigDecimal> targetSet, String lower, String higher) {
 3         final BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
 4         final BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
 5 
 6         Predicate predicate = new Predicate() {
 7             public boolean evaluate(Object object) {
 8                 BigDecimal bDObject = (BigDecimal) object;
 9                 return bDObject.compareTo(bdLower) >= 0
10                         && bDObject.compareTo(bdHigher) <= 0;
11             }
12         };
13 
14         CollectionUtils.filter(targetSet, predicate);
15     }

第四种方式:使用Guava(google Collections), 直接对于原始Set进行Filter
            测试效果:集合大小10M,过滤结果1M, 运算时间: 100ms-
过滤部分的代码如下:
 1 //guava filter
 2 
 3     Set<BigDecimal> filterSet(Set<BigDecimal> targetSet, String lower,
 4             String higher) {
 5         final BigDecimal bdLower = new BigDecimal(Double.parseDouble(lower));
 6         final BigDecimal bdHigher = new BigDecimal(Double.parseDouble(higher));
 7 
 8         Set<BigDecimal> filterCollection = Sets.filter(targetSet,
 9                 new Predicate<BigDecimal>() {
10                     @Override
11                     public boolean apply(BigDecimal input) {
12                         BigDecimal bDObject = (BigDecimal) input;
13                         return bDObject.compareTo(bdLower) >= 0
14                                 && bDObject.compareTo(bdHigher) <= 0;
15                     }
16                 });
17 
18         return filterCollection;
19     }


四种方式对比如下:
第一种方式:  仅依赖于JAVA原生类库 遍历时间最慢, 代码量很小
第二种方式:  仅依赖于JAVA原生类库 遍历时间比较慢(主要慢在生成有序Set), 代码量最多
第三种方式:  依赖于Apache Commons Collections, 遍历时间比较快, 代码量很少
第四种方式:  依赖于Guava, 遍历时间最快, 代码量很少

基于目前个人的技术水平和视野, 第四种方式可能是最佳选择.

记录一下, 以后可能还会有更好的方案.






混沌中立 2014-06-21 23:33 发表评论

web app开发技巧总结 (share)

$
0
0

web app开发技巧总结 (share)

  (转自http://hi.baidu.com/kuntakinte/item/ca92d6e5edae9fc0bbf37d08)

自Iphone和Android这两个牛逼的手机操作系统发布以来,在互联网界从此就多了一个新的名词-WebApp(意为基于WEB形式的应用程序,运行在高端的移动终端设备)。

开发者们都知道在高端智能手机系统中有两种应用程序:一种是基于本地(操作系统)运行的APP;一种是基于高端机的浏览器运行的WebApp,本文将主要讲解后者。

WebApp与Native App有何区别呢?

Native App:

1、开发成本非常大。
一般使用的开发语言为JAVA、C++、Objective-C。

2、更新体验较差、同时也比较麻烦
每一次发布新的版本,都需要做版本打包,且需要用户手动更新(有些应用程序即使不需要用户手动更新,但是也需要有一个恶心的提示)。

3、非常酷
因为native app可以调用IOS中的UI控件以UI方法,它可以实现WebApp无法实现的一些非常酷的交互效果

4、Native app是被Apple认可的
Native app可以被Apple认可为一款可信任的独立软件,可以放在Apple Stroe出售,但是Web app却不行。

Web App:
1、开发成本较低
使用web开发技术就可以轻松的完成web app的开发

2、升级较简单
升级不需要通知用户,在服务端更新文件即可,用户完全没有感觉

3、维护比较轻松
和一般的web一样,维护比较简单,它其实就是一个站点

Webapp说白了就是一个针对Iphone、Android优化后的web站点,它使用的技术无非就是HTML或HTML5、CSS3、JavaScript,服务端技术JAVA、PHP、ASP。

当然,因为这些高端智能手机(Iphone、Android)的内置浏览器都是基于webkit内核的,所以在开发WEBAPP时,多数都是使用 HTML5和CSS3技术做UI布局。当使用HTML5和CSS3l做UI时,若还是遵循着一般web开发中使用HTML4和CSS2那样的开发方式的 话,这也就失去了WEBAPP的本质意义了,且有些效果也无法实现的,所以在此又回到了我们的主题–webapp的布局方式和技术。

在此所说的移动平台前端开发是指针对高端智能手机(如Iphone、Android)做站点适配也就是WebApp,并非是针对普通手机开发 Wap 2.0,所以在阅读本篇文章以前,你需要对webkit内核的浏览器有一定的了解,你需要对HTML5和CSS3有一定的了解。如果你已经对此有 所了解,那现在就开始往下阅读吧……

1、首先我们来看看webkit内核中的一些私有的meta标签,这些meta标签在开发webapp时起到非常重要的作用
1 <meta content=”width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;” name=”viewport” />
2 <meta content=”yes” name=”apple-mobile-web-app-capable” />
3 <meta content=”black” name=”apple-mobile-web-app-status-bar-style” />
4 <meta content=”telephone=no” name=”format-detection” />

第一个meta标签表示:强制让文档的宽度与设备的宽度保持1:1,并且文档最大的宽度比例是1.0,且不允许用户点击屏幕放大浏览;
第二个meta标签是iphone设备中的safari私有meta标签,它表示:允许全屏模式浏览;
第三个meta标签也是iphone的私有标签,它指定的iphone中safari顶端的状态条的样式;
第四个meta标签表示:告诉设备忽略将页面中的数字识别为电话号码

2、HTML5标签的使用
在开始编写webapp时,哥建议前端工程师使用HTML5,而放弃HTML4,因为HTML5可以实现一些HTML4中无法实现的丰富的WEB应用程序 的体验,可以减少开发者很多的工作量,当然了你决定使用HTML5前,一定要对此非常熟悉,要知道HTML5的新标签的作用。比如定义一块内容或文章区域 可使用section标签,定义导航条或选项卡可以直接使用nav标签等等。

3、放弃CSS float属性
在项目开发过程中可以会遇到内容排列排列显示的布局(见下图),假如你遇见这样的视觉稿,哥建议你放弃float,可以直接使用display:block;

4、利用CSS3边框背景属性
这个按钮有圆角效果,有内发光效果还有高光效果,这样的按钮使用CSS3写是无法写出来的,当然圆角可以使用CSS3来写,但高光和内发光却无法使用 CSS3编写,这个时候你不妨使用-webkit-border-image来定义这个按钮的样式。-webkit-border-image就个很复杂 的样式属性。

5、块级化a标签
请保证将每条数据都放在一个a标签中,为何这样做?因为在触控手机上,为提升用户体验,尽可能的保证用户的可点击区域较大。

6、自适应布局模式
在编写CSS时,我不建议前端工程师把容器(不管是外层容器还是内层)的宽度定死。为达到适配各种手持设备,我建议前端工程师使用自适应布局模式(支付宝 采用了自适应布局模式),因为这样做可以让你的页面在ipad、itouch、ipod、iphone、android、web safarik、 chrome都能够正常的显示,你无需再次考虑设备的分辨率。

7、学会使用webkit-box
上一节,我们说过自适应布局模式,有些同学可能会问:如何在移动设备上做到完全自适应呢?很感谢webkit为display属性提供了一个webkit-box的值,它可以帮助前端工程师做到盒子模型灵活控制。

8、如何去除Android平台中对邮箱地址的识别
看过iOS webapp API的同学都知道iOS提供了一个meta标签:用于禁用iOS对页面中电话号码的自动识别。在iOS中是不自动识别邮件地 址的,但在Android平台,它会自动检测邮件地址,当用户touch到这个邮件地址时,Android会弹出一个框提示用户发送邮件,如果你不想 Android自动识别页面中的邮件地址,你不妨加上这样一句meta标签在head中 1 <meta content=”email=no” name=”format-detection” />

9、如何去除iOS和Android中的输入URL的控件条
你的老板或者PD或者交互设计师可能会要求你:能否让我们的webapp更加像nativeapp,我不想让用户看见那个输入url的控件条?

答案是可以做到的。我们可以利用一句简单的javascript代码来实现这个效果
1 setTimeout(scrollTo,0,0,0);

请注意,这句代码必须放在window.onload里才能够正常的工作,而且你的当前文档的内容高度必须是高于窗口的高度时,这句代码才能有效的执行。

10、如何禁止用户旋转设备
我曾经也想禁止用户旋转设备,也想实现像某些客户端那样:只能在肖像模式或景观模式下才能正常运行。但现在我可以很负责任的告诉你:别想了!在移动版的webkit中做不到!

至少Apple webapp API已经说到了:我们为了让用户在safari中正常的浏览网页,我们必须保证用户的设备处于任何一个方位 时,safari都能够正常的显示网页内容(也就是自适应),所以我们禁止开发者阻止浏览器的orientationchange事件,看来苹果公司的出 发点是正确的,苹果确实不是一般的苹果。

iOS已经禁止开发者阻止orientationchange事件,那Android呢?对不起,我没有找到任何资料说Android禁止开发者阻止浏览器orientationchange事件,但是在Android平台,确实也是阻止不了的。

11、如何检测用户是通过主屏启动你的webapp
看过Apple webapp API的同学都知道iOS为safari提供了一个将当前页面添加主屏的功能,按下 iphoneipodipod touch底部工具中的小加号,或者ipad顶部左侧的小加号,就可以将当前的页面添加到设备的主屏,在设备的主屏会自动 增加一个当前页面的启动图标,点击该启动图标就可以快速、便捷的启动你的webapp。从主屏启动的webapp和浏览器访问你的webapp最大的区别 是它清除了浏览器上方和下方的工具条,这样你的webapp就更加像是nativeapp了,还有一个区别是window对像中的navigator子对 象的一个standalone属性。iOS中浏览器直接访问站点时,navigator.standalone为false,从主屏启动webapp 时,navigator.standalone为true, 我们可以通过navigator.standalone这个属性获知用户当前是否是从主屏访 问我们的webapp的。在Android中从来没有添加到主屏这回事!

12、如何关闭iOS中键盘自动大写
我们知道在iOS中,当虚拟键盘弹出时,默认情况下键盘是开启首字母大写的功能的,根据某些业务场景,可能我们需要关闭这个功能,移动版本webkit为 input元素提供了autocapitalize属性,通过指定autocapitalize=”off”来关闭键盘默认首字母大写。

13、iOS中如何彻底禁止用户在新窗口打开页面
有时我们可能需要禁止用户在新窗口打开页面,我们可以使用a标签的target=”_self“来指定用户在新窗口打开,或者target属性保持空,但 是你会发现iOS的用户在这个链接的上方长按3秒钟后,iOS会弹出一个列表按钮,用户通过这些按钮仍然可以在新窗口打开页面,这样的话,开发者指定的 target属性就失效了,但是可以通过指定当前元素的-webkit-touch-callout样式属性为none来禁止iOS弹出这些按钮。这个技 巧仅适用iOS对于Android平台则无效。

14、iOS中如何禁止用户保存图片\复制图片
我们在第13条技巧中提到元素的-webkit-touch-callout属性,同样为一个img标签指定-webkit-touch-callout为none也会禁止设备弹出列表按钮,这样用户就无法保存\复制你的图片了。

15、iOS中如何禁止用户选中文字
我们通过指定文字标签的-webkit-user-select属性为none便可以禁止iOS用户选中文字。

16、iOS中如何获取滚动条的值
桌面浏览器中想要获取滚动条的值是通过document.scrollTop和document.scrollLeft得到的,但在iOS中你会发现这两 个属性是未定义的,为什么呢?因为在iOS中没有滚动条的概念,在Android中通过这两个属性可以正常获取到滚动条的值,那么在iOS中我们该如何获 取滚动条的值呢?
通过window.scrollY和window.scrollX我们可以得到当前窗口的y轴和x轴滚动条的值。

17、如何解决盒子边框溢出
当你指定了一个块级元素时,并且为其定义了边框,设置了其宽度为100%。在移动设备开发过程中我们通常会对文本框定义为宽度100%,将其定义为块级元 素以实现全屏自适应的样式,但此时你会发现,该元素的边框(左右)各1个像素会溢了文档,导致出现横向滚动条,为解决这一问题,我们可以为其添加一个特殊 的样式-webkit-box-sizing:border-box;用来指定该盒子的大小包括边框的宽度。

18、如何解决Android 2.0以下平台中圆角的问题
如果大家够细心的话,在做wap站点开发时,大家应该会发现android 2.0以下的平台中问题特别的多,比如说边框圆角这个问题吧。
在对一个元素定义圆角时,为完全兼容android 2.0以下的平台,我们必须要按照以下技巧来定义边框圆角:
1\-webkit这个前缀必须要加上(在iOS中,你可以不加,但android中一定要加);
2\如果对针对边框做样式定义,比如border:1px solid #000;那么-webkit-border-radius这属性必须要出现在border属性后。
3\假如我们有这样的视觉元素,左上角和右上角是圆角时,我们必须要先定义全局的(4个角的圆角值)-webkit-border- radius:5px;然后再依次的覆盖左下角和右下角,-webkit-border-bottom-left-radius:0;-webkit- border-bottom-right-border:0;否则在android 2.0以下的平台中将全部显示直角,还有记住!-webkit这个前 缀一定要加上!

19、如何解决android平台中页面无法自适应
虽然你的html和css都是完全自适应的,但有一天如果你发现你的页面在android中显示的并不是自适应的时候,首先请你确认你的head标签中是否包含以下meta标签:
1 <meta name=”viewport” content=”width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0;” />
如果有的话,那请你再仔细的看清楚有没有这个属性的值width=device-width,如果没有请立即加上吧!

20、如何解决iOS 4.3版本中safari对页面中5位数字的自动识别和自动添加样式
新的iOS系统也就是4.3版本,升级后对safari造成了一个bug:即使你添加了如下的meta标签,safari仍然会对页面中的5位连续的数字进行自动识别,并且将其重新渲染样式,也就是说你的css对该标签是无效的。
1 <meta name=”format-detection” content=”telphone=no” />

我们可以用一个比较龌龊的办法来解决。比如说支付宝wap站点中显示金额的标签,我们都做了如下改写:
1 <button class=”t-balance”style=”background:none;padding:0;border:0;”>95009.00</button>元 

 

http://www.cnblogs.com/duanhuajian/archive/2012/11/09/2763171.html

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



为了经营无秘的体验,专注个性化阅读的无觅网要下线了?

$
0
0

我想很多朋友在看到标题后会满腹疑虑,无秘、无觅,傻傻分不清楚。 无觅是一个做个性化阅读推荐社区,和社交性内容聚合的网站。而 无秘,原名又叫秘密,是一款熟人匿名社交软件。无觅和无秘都是由无觅团队开发的,这只团队由一群海归组成,推出无觅网是为了通过数据挖掘和语义分析打造一个个性化的互联网。

今天在无觅网上看到了这样一段对白,其中新产品,指的就是无秘应用:

三年前,无觅最早是从一个 简单的社交型内容聚合网站开始的,做的主要是个性化阅读社区,通过学习和记载用户喜欢的文章来推荐内容,有点像 今日头条的操作方式。不过无觅网还涵盖了社交的功能,右上方的用户信息区域会显示你的“喜欢”、评论、关注和被关注。后来,你还可以将喜欢的内容分享给同在无觅网上的朋友。

当无觅网发第二版的时候, 原本的站外链接改成了站内,团队开始猛推一个叫无觅网络的系统,用来连接所有自愿加入的网站,通过一个网站的文章引出相关内容,向另一个网站导流。然后无觅网两年前发了个2.0的版本,加入了微博账户绑定,把核心功能聚焦在“信息流”和“阅读发现”上。信息流则可以帮助用户看到别人在读什么,从而增加社交属性。

如今无觅网停止维护面临下线,自称是为了无秘的体验。虽然在微信朋友圈里,无秘还是非常活跃的,不过无秘最近被AppStore下架两次,还面临一些版权问题,所谓维护体验,不知道是不是跟无秘和美国版秘密的博弈有关……

顺带提一下,无觅网出来的时候,团队还补充做了个 相关文章插件,帮助网站建查找相关文章的机制,用的是语义分析和深度挖掘,在算法中加入用户互动情况,目前这个插件会继续存在。

除非注明,本站文章均为原创或编译,转载请注明: 文章来自 36氪

36氪官方iOS应用正式上线,支持『一键下载36氪报道的移动App』和『离线阅读』立即下载!

Google式的搜索引擎实现

$
0
0

Nutch是一个基于Lucene,类似Google的完整网络搜索引擎解决方案,基于Hadoop的分布式处理模型保证了系统的性能,类似Eclipse的插件机制保证了系统的可客户化,而且很容易集成到自己的应用之中。

  Nutch 0.8 完全使用Hadoop重写了骨干代码,另有很多地方作了合理化修正,非常值得升级。

  

1.Nutch 0.8 的安装与运行

 

  nutch 0.7.2的中文安装文档满街都是,nutch 0.8的安装文档见Tutorial (0.8) , 要注意两点:

  一是 crawl命令里的urls参数从指定文件变为了指定目录, 即原来的urls 要改存到urls/foo 里。

  二是 nutch-default.xml里http.agent.name属性默认为空,必须在nutch-site.xml中为该属性设值,否则会出错。

  注意nutch 爬行时的信息用log4j输出在/logs 目录下了,默认不再直接输出到屏幕,除非你在配置文件里设fetcher.verbose为true。

  Luke(http://www.getopt.org/luke) 是一个必备的索引阅读工具。

  另外,nutch需要在unix下奔跑,如果要装在windows上,大家可以先装个cygwin。(下载它的setup.exe 在线安装很快装完)。

  最后,nutch 0.8的recawl 脚本也不同了。

  

2.Nutch You should know 

2.1 一份文档

 

  nutch的文档不多,而且多是安装文档,要深入nutch,就必须一字不漏的阅读:

  Introduction to Nutch, Part 1 Crawling  和 Introduction to Nutch, Part 2 Searching

  然后就是看源码了,好在nutch的源码非常均匀,简短,没有花哨的技巧,很容易把事情看明白。

  

2.2 三个目录

 

  首先理解nutch的三个数据目录:

  1.crawdb,linkdb 是web link目录,存放url 及url的互联关系,作为爬行与重新爬行的依据,页面默认30天过期。

  2.segments 是主目录,存放抓回来的网页。页面内容有bytes[]的raw content 和 parsed text的形式。nutch以广度优先的原则来爬行,因此每爬完一轮会生成一个segment目录。

  3.index 是lucene的索引目录,是indexs里所有index合并后的完整索引,注意索引文件只对页面内容进行索引,没有进行存储,因此查询时要去访问segments目录才能获得页面内容。

  

2.3 爬行过程

 

  爬行过程在Introduction to Nutch, Part 1 Crawling 里已有详细说明,或许直接看Crawl类来理解爬行的过程。

  这里有一幅更直观的图:

  

  Nutch用入口地址,地址正则表达式,搜索深度三种形式来限制。

  因为使用了Hadoop(下篇再讲),Nutch的代码都按照Hadoop的模式来编写以获得分布式的能力,因此要先了解一下Hadoop,明白它Mapper,Reducer, InputFormat, OutputFormat类的作用才能更好的阅读。

  1.Fetcher类, 在run()里多线程运行FetcherThread,并调用恰当的Protocol插件(支持http,ftp等协议)获取内容,调用恰当的Parser将内容(html,pdf,excel)分析为文本,然后把内容放到FetcherOutput类里,最后由FetcherOutputFormat类定义写盘到segments的过程。

  2.Indexer类,使用hadoop遍历所有segments 目录,将parseData文件序列化成ParseData类,从中获得各种资料然后调用插件进行索引,最后仍然由ouputFormat类完成写入索引的工作。

  注意,如果你仅想使用Nutch的爬虫,而不是其索引功能,可以仿照Indexer重写自己的实现,比如把segments内容直接搬进数据库。

  3.Nutch 每条索引记录的字段

  url: 作为唯一标标识值,由BasicIndexingFilter类产生。

  segment:由Indexer类产生。Nutch抓回来的页面内容放在segments目录,lucene只会索引,不会store原文内容,因此在查询时要以segment与url作为外键,由FetchedSegments类根据hitsDetail从segments目录获得content。

  boost:优先级,由Indexer类调用插件计算产生。

  title:显示标题,在BasicIndexingFilter插件中被索引和存储。

  content: 主要的被搜索项,在BasicIndexingFilter插件中被索引。

  

2.4 搜索过程

 

  Nutch提供了一个Fascade的NutchBean类供我们使用,一段典型的代码如下

  

 
    NutchBean bean = new NutchBean();

 

  Query query = Query.parse(args[0]);

  Hits hits = bean.search(query, NUM_HITS,"title",true);

  for (int i = 0; i < hits.getLength(); i++) {

  Hit hit = hits.getHit(i);

  HitDetails details = bean.getDetails(hit);

  String title = details.getValue("title");

  String url = details.getValue("url");

  String summary =bean.getSummary(details, query);

  }

  

这里NutchBean为我们做了几样事情:

 

  一是按Title field来排序。

  二是支持分布式查询,如果有配置servers,就会使用hadoop的IPC系统,调用所有server上的nutchBeans,最后规约出总的结果。

  三是每个站点像Google一样只显示分数最高的一页,如果用户还想看同站的其他结果,就需要进一步调用API访问。

  四是生成Summary,从segments目录按segments和url 获得content, 并按一定算法抽取出像Google一样的包含关键字的文档片断。

  

3. 修改源码或编写插件

 

  Nutch的源码很容易修改和重新编译,注意新编译的class要压回nutch-0.8.job(实际是一个jar)才能生效。

  Nutch的插件机制及度类似Eclipse, 详看http://wiki.apache.org/nutch/WritingPluginExample,只要实现某个插件接口,然后在plugins.xml里定义class,扩展点和依赖的jar,如

  

<plugin   id="index-basic"   version="1.0.0"   provider-name="nutch.org">

 

  <runtime>

  <library name="index-basic.jar">

  <export name="*"/>

  </library>

  </runtime>

  <requires>

  <import plugin="nutch-extensionpoints"/>

  </requires>

  <extension id="org.apache.nutch.indexer.basic"

  name="Nutch Basic Indexing Filter" 

  point="org.apache.nutch.indexer.IndexingFilter">

  <implementation id="BasicIndexingFilter"  class="org.apache.nutch.indexer.basic.BasicIndexingFilter"/>

  </extension>

  </plugin>

 

 

参考 https://today.java.net/pub/a/today/2006/01/10/introduction-to-nutch-1.html

https://today.java.net/pub/a/today/2006/02/16/introduction-to-nutch-2.html



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



java使用memcached缓存

$
0
0
服务器端安装,部署,启动:

1.下载libevent,安装libevent
cd /tmp
wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
tar -zxvf libevent-2.0.21-stable.tar.gz
cd libevent-2.0.21-stable
./configure --prefix=/usr/local/libevent
make && make install

2.下载memcached,安装memcached
wget http://memcached.org/latest 
tar -zxvf memcached-1.4.17.tar.gz
cd memcached-1.4.17
./configure --prefix=/usr/local/memcache --with-libevent=/usr/local/libevent/
make &&  make install
cd /usr/local/memcached/bin
./memcached -d -m 64 -u root -p 55001 -c 2048 

查看memcached的状态
ps -ax|grep memcache

链接到memcache
telnet cache.expai.com 55001
查看状态
stats

查看缓存占了多少空间
cat /proc/id/statm
启动参数
./memcached -d -m 1024 -u root -p 55001 -c 2048

memcached启动参数
 
-p 指定端口号(默认11211)  
-U <num> UDP监听端口 (默认: 11211, 0 时关闭) 
-s <file>     用于监听的UNIX套接字路径(禁用网络支持)
-a <mask>     UNIX套接字访问掩码,八进制数字(默认:0700)
-m 指定最大使用内存大小(默认64MB)   
-t 线程数(默认4)
 
-l <ip_addr> 绑定地址 (默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问) 
-d start 启动memcached服务   
-d restart 重起memcached服务   
-d stop|shutdown 关闭正在运行的memcached服务   
-u <username> 绑定使用指定用于运行进程 <username>  (只有root用户可以使用这个参数)
-P <file> 将PID写入文件<file>,这样可以使得后边进行快速进程终止, 需要与 -d 一起使用
-m 最大内存使用,单位MB。默认64MB     www.2cto.com  
 
-M 内存耗尽时返回错误,而不是删除项   
-c 最大同时连接数,默认是1024 
-f 块大小增长因子,默认是1.25 
-n <bytes>最小分配空间,key+value+flags默认是48
-k锁定所有内存页。注意你可以锁定的内存上限。
 
试图分配更多内存会失败的,所以留意启动守护进程时所用的用户可分配的内存上限。
(不是前面的 -u <username> 参数;在sh下,使用命令"ulimit -S -l NUM_KB"来设置。)
-v 提示信息(在事件循环中打印错误/警告信息。)
-vv 详细信息(还打印客户端命令/响应)
-vvv 超详细信息(还打印内部状态的变化)
-h 打印这个帮助信息并退出。
-i  打印memcached和libevent的许可。
-L 尝试使用大内存页(如果可用的话)。提高内存页尺寸可以减少"页表缓冲(TLB)"丢失次数,提高运行效率。  www.2cto.com  
 
              为了从操作系统获得大内存页,memcached会把全部数据项分配到一个大区块。
-D <char>     使用 <char> 作为前缀和ID的分隔符。
              这个用于按前缀获得状态报告。默认是":"(冒号)。
              如果指定了这个参数,则状态收集会自动开启;如果没指定,则需要用命令"stats detail on"来开启。
-t <num>      使用的线程数(默认:4)
-R 每个连接可处理的最大请求数。
-C 禁用CAS。
-b 设置后台日志队列的长度(默认:1024)
-B 绑定协议 - 可能值:ascii,binary,auto(默认)
-I 重写每个数据页尺寸。调整数据项最大尺寸。

默认memcache会监听11221端口,如果想清空服务器上memecache的缓存,大家一般使用的是:
telnet localhost 11211
flush_all

同样也可以使用:
echo "flush_all" | nc localhost 11211

使用flush_all 后并不是删除memcache上的key,而是置为过期

java客户端使用:
package com.expai.utils;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
import com.expai.mapper.advertise.AdverTiseMapper;
import com.expai.mapper.user.UserMapper;
import com.expai.model.hotimage.HotImage;
import com.expai.model.ir.Advertise;
import com.expai.model.user.User;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;

/**
 * 
 * Description:
 * DateTime 2014年1月21日 下午4:19:28
 * @author louyj
 * @company expai
 * @version 1.0
 *
 */
public class MemCachedUtil {
	
	private static final Logger logger = Logger.getLogger(MemCachedUtil.class);
	
	 //构建缓存客户端
	 private static MemCachedClient  cachedClient;
	// 单例模式实现客户端管理类  
     private static MemCachedUtil INSTANCE = new MemCachedUtil();
     private MemCachedUtil() {  
         cachedClient = new MemCachedClient();  
         cachedClient.setPrimitiveAsString(true);
         // cachedClient.setSanitizeKeys(arg0)
         //获取连接池实例  
         SockIOPool pool = SockIOPool.getInstance();  
         // http://:/
         //设置缓存服务器地址,可以设置多个实现分布式缓存  服务器列表和其权重
         // pool.setServers(new String[]{"115.29.251.56:55001,115.29.251.56:55002,115.29.251.56:55003"});  
         //pool.setServers(new String[]{"10.162.57.11:55001"});  
        pool.setServers(new String[]{"s4.expai.com:55001"});  
        //  pool.setServers(new String[]{"192.168.81.137:55001"});  
        Integer[] weights = {3};
        //,"10.162.57.11:55001","10.162.57.11:55002","10.162.57.11:55003"
        pool.setWeights( weights );
         //pool.setServers(new String[]{"192.168.4.39:55001"});  
         //设置初始连接5  
         pool.setInitConn(5);  
         //设置最小连接5  
         pool.setMinConn(5);  
         //设置最大连接2048  
         pool.setMaxConn(2048);  
         //设置每个连接最大空闲时间3个小时  
         pool.setMaxIdle(1000 * 60 * 60 * 3);  
   
         pool.setMaintSleep(30);  
   
         pool.setNagle(false);  
         pool.setSocketTO(3000);  
         pool.setSocketConnectTO(0);  
         pool.initialize(); 
     } 
     
     /** 
      * 获取缓存管理器唯一实例 
      * @return 
      */  
     public static MemCachedUtil getInstance() {  
         return INSTANCE;  
     } 
     
     public void add(String key, Object value) {  
         cachedClient.add(key, value);  
     }  
   
       //int设置缓存失效时间,相对时间毫秒
     public void add(String key, Object value, int milliseconds) {  
         cachedClient.add(key, value, milliseconds);  
     }  
     public void set(String key, Object value) {  
    	 cachedClient.set(key, value);  
     }  
     
     //int设置缓存失效时间,相对时间毫秒
     public void set(String key, Object value, int milliseconds) {  
    	 cachedClient.set(key, value, milliseconds);  
     }  
   
       
     public void remove(String key) {  
         cachedClient.delete(key);  
         cachedClient.flushAll();
     }  
   
       
     @SuppressWarnings("deprecation")
	public void remove(String key, int milliseconds) {  
         cachedClient.delete(key, milliseconds, new Date());  
         cachedClient.flushAll();
     }  
     public void update(String key, Object value, int milliseconds) {  
         cachedClient.replace(key, value, milliseconds);  
     }  
     public void update(String key, Object value) {  
         cachedClient.replace(key, value);  
     }  
     public Object get(String key) {  
         return cachedClient.get(key);  
     }  
     public void getAll(){
      logger.debug(cachedClient);
     }
     /**
      * 初始化识别信息缓存
      */
     public static void initMemcachedIdenData(){
     	SqlSession session = null;
 		session = SessionFactory.getSession();
 	    AdverTiseMapper adMap = null;
 	    adMap = session.getMapper(AdverTiseMapper.class);
 	    List<Advertise> advertiseList = adMap.getAdvertises();
 	    if(advertiseList!=null&&advertiseList.size()>0){
 	    	for(Advertise advertise:advertiseList){
 	    		if(null!=advertise.getUrl()&&!advertise.getUrl().equals("")){
 	    			logger.debug("Advertise"+advertise.getId()+"的识别结果为:"+advertise.getUrl());
 	    			MemCachedUtil.getInstance().set("adveriden"+advertise.getId(), advertise.getUrl());
 	    		}else{
 	    			logger.debug("Advertise"+advertise.getId()+"的识别结果为:"+advertise.getUrl());
 	    			MemCachedUtil.getInstance().set("adveriden"+advertise.getId(), "url is null");
 	    		}
 	    		if(null!=advertise.getKeyword()&&!advertise.getKeyword().equals("")){
 	    			logger.debug("Advertise"+advertise.getId()+"的关键字为:"+advertise.getKeyword());
 	    			MemCachedUtil.getInstance().set("adverkey"+advertise.getId(), advertise.getKeyword());
 	    		}else{
 	    			logger.debug("Advertise"+advertise.getId()+"的关键字为:"+advertise.getKeyword());
 	    			MemCachedUtil.getInstance().set("adverkey"+advertise.getId(), "key is null");
 	    		}
 	    		if(null!=advertise.getImage()&&!advertise.getImage().equals("")){
 	    			logger.debug("Advertise"+advertise.getId()+"的图片地址为:"+advertise.getImage());
 	    			MemCachedUtil.getInstance().set("adverimage"+advertise.getId(), advertise.getImage());
 	    		}else{
 	    			logger.debug("Advertise"+advertise.getId()+"的图片地址为:"+advertise.getImage());
 	    			MemCachedUtil.getInstance().set("adverimage"+advertise.getId(), "image is null");
 	    		}
 	    	}
 	    }
 	    //初始化tb_newspaper里的识别信息
 	   List<Advertise> newspaperList = adMap.getNewspapers();
	    if(newspaperList!=null&&newspaperList.size()>0){
	    	for(Advertise advertise:newspaperList){
	    		if(null!=advertise.getUrl()&&!advertise.getUrl().equals("")){
	    			logger.debug("Advertise"+advertise.getId()+"的识别结果为:"+advertise.getUrl());
	    			MemCachedUtil.getInstance().set("newsiden"+advertise.getId(), advertise.getUrl());
	    		}else{
	    			logger.debug("Advertise"+advertise.getId()+"的识别结果为:"+advertise.getUrl());
	    			MemCachedUtil.getInstance().set("newsiden"+advertise.getId(), "url is null");
	    		}
	    		if(null!=advertise.getKeyword()&&!advertise.getKeyword().equals("")){
 	    			logger.debug("Advertise"+advertise.getId()+"的关键字为:"+advertise.getKeyword());
 	    			MemCachedUtil.getInstance().set("newskey"+advertise.getId(), advertise.getKeyword());
 	    		}else{
 	    			logger.debug("Advertise"+advertise.getId()+"的关键字为:"+advertise.getKeyword());
 	    			MemCachedUtil.getInstance().set("newskey"+advertise.getId(), "key is null");
 	    		}
	    		if(null!=advertise.getImage()&&!advertise.getImage().equals("")){
 	    			logger.debug("Advertise"+advertise.getId()+"的图片地址为:"+advertise.getImage());
 	    			MemCachedUtil.getInstance().set("newsimage"+advertise.getId(), advertise.getImage());
 	    		}else{
 	    			logger.debug("Advertise"+advertise.getId()+"的图片地址为:"+advertise.getImage());
 	    			MemCachedUtil.getInstance().set("newsimage"+advertise.getId(), "image is null");
 	    		}
	    	}
	    }
     }
     */
     /**
      * 初始化广告信息tb_embedAdvertise
      * @throws UnsupportedEncodingException 
      */
     public static void initMemcachedEmbedDate() throws UnsupportedEncodingException{
    	 long st = System.currentTimeMillis();
     	DB db = MongdbUtil.startMongoDBConn();
     	DBCollection inputCollection =db.getCollection("tb_embedAdvertise"); 
     	DBObject ref = new BasicDBObject();
     	DBCursor cursor = inputCollection.find(ref);
 		List<DBObject> list = cursor.toArray();
 		long et = System.currentTimeMillis();
 		long diff = et-st;
 		logger.info("query all advertise expand time : " + diff);
 		MemCachedUtil instance = MemCachedUtil.getInstance();
  		if(list!=null&&list.size()>0){
  			logger.info("all advertise total number : " + list.size());
  			for(int i =0, n = list.size(); i < n; i++){
  				DBObject object = list.get(i);
  				Object url = object.get("url");
  				Object loc = object.get("loc");
  				String str = new String(object.toString().getBytes("UTF-8"));
 				if(null!=url && !url.toString().equals("")){
 					logger.debug("The is cache Advertise url======"+"em" + new MD5().getMD5ofStr(url.toString()));
 					instance.add("em" + new MD5().getMD5ofStr(url.toString()), str);
 				}
 				if(null != loc && !loc.toString().equals("")){
 					logger.debug("The is cache Advertise loc======"+"em" + new MD5().getMD5ofStr(loc.toString()));
 					instance.add("em" + new MD5().getMD5ofStr(loc.toString()), str);
 				}
  				Utils.writeText(str, "/data/memcached.txt");
  			}
  			logger.info("memcached add complete");
  		}
  		MongdbUtil.stopMondoDBConn();
     }
     public static void initMemcachedImageAll(){
    	 	DB db = MongdbUtil.startMongoDBConn();
	    	DBCollection inputCollection =db.getCollection("tb_hotimage_failure"); 
	    	DBCursor cursor = inputCollection.find();
	    	List<DBObject> list = cursor.toArray();
	    	for(int i =0, n = list.size(); i < n; i++){
				DBObject object = list.get(i);
				Object shortlocation = object.get("shortlocation");
				if(null!=shortlocation && !shortlocation.toString().equals("")){
					logger.debug("add tb_hotimage_failure======================"+shortlocation);
					MemCachedUtil.getInstance().set(new MD5().getMD5ofStr(String.valueOf(shortlocation)),"failure");
				}
			}
	    	DBCollection inputCollection1 =db.getCollection("tb_hotimage"); 
	    		BasicDBObject obj = new BasicDBObject();
	    		BasicDBObject query = new BasicDBObject();
	    		BasicDBList values = new BasicDBList();  
	    		values.add("sdchina.com");
	    		values.add("gywb.cn");
	    		values.add("nen.com");
	    		values.add("yunying");
	    		values.add("shangdu.com");
	    		values.add("voc.com");
	    		values.add("0554news.com");
	    		query.append("$in", values);
	    		obj.append("categoryId", query);
	    	DBCursor cursor1 = inputCollection1.find(obj);
	    	List<DBObject> list1 = cursor1.toArray();
	    	for(int i =0, n = list1.size(); i < n; i++){
				DBObject object1 = list1.get(i);
				Object shortlocation = object1.get("shortlocation");
				if(null!=shortlocation && !shortlocation.toString().equals("")){
					logger.debug("add tb_hotimage======================"+shortlocation);
					MemCachedUtil.getInstance().set(new MD5().getMD5ofStr(String.valueOf(shortlocation)),"success");
				}
			}
	    	MongdbUtil.stopMondoDBConn();
     }
	public static void main(String[] args) {
		initMemcachedImageAll();
	}
}


memcached jar包:
<dependency><groupId>memcached</groupId><artifactId>java_memcached-release</artifactId><version>2.6.6</version></dependency>


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Mozilla开发基于Firefox OS的流媒体电视棒

$
0
0
在踏入智能手机领域之后,Mozilla正在研发另一个秘密项目:类似Chromecast的流媒体电视棒,运行Firefox OS操作系统。和Firefox OS智能手机一样,Mozilla的电视棒也将没有任何限制,将会开放启动引动程序。Chromecast限制了成人内容,而Mozilla的电视棒将不会有此类的内容限制。Mozilla不参合硬件制造,不限制厂商修改操作系统,不像Google那样严密控制Chromecast的开发和制造。







『轉』复活你的GoAgent

$
0
0

由于种种原因, GoAgent不能用了。满屏的黄血红血。作为高端的姿势分子,我们显然不能放弃治疗!

『轉』复活你的GoAgent

之前帖子里有人发布了可以访问Google的IP,今天我们来点可以用GoAgent的IP.

* 本文原文链接: 『轉』复活你的GoAgent -  美博园 *
GoGo Tester 2 正式版发布,能够帮你找出那些适合你的,能用而且好用的IP!绝对没有红字黄字!https://drive.google.com/folderview?id=0BzKpXHh8y0PRRllpUE8wMEpiLTQ&usp=sharing

使用这个工具可以找到可以用的GoAgent IP,然后复制到proxy.ini文件中就能用了!!

这里是几个最近可用的IP
218.253.0.174|218.253.0.80|218.253.0.81|218.253.0.181|218.253.0.154|218.253.0.91|218.253.0.148|218.253.0.82|218.189.25.159|210.61.221.172|218.253.0.86|218.253.0.87|218.253.0.152|218.253.0.89|218.253.0.88|218.189.25.174|218.253.0.144|203.66.124.167|218.253.0.159|203.66.124.231|218.253.0.84|218.189.25.181|210.61.221.114|203.66.124.241|210.61.221.113|202.39.143.93|210.61.221.182|202.39.143.104|61.219.131.113|61.219.131.94|61.219.131.118|61.219.131.89|202.39.143.98|61.219.131.103|218.253.0.187|61.219.131.237|218.253.0.163|61.219.131.212|203.66.124.153|203.66.124.237|61.219.131.109|203.66.124.178|203.66.124.251|210.61.221.119|203.66.124.222|203.66.124.172|203.66.124.152|203.66.124.163|218.253.0.170|203.66.124.168|210.61.221.177|203.66.124.162|210.61.221.123|202.39.143.35|203.66.124.177|103.25.178.42|103.25.178.19|103.25.178.27|103.25.178.30|203.66.124.148|218.176.242.20|203.66.124.173|218.176.242.118|218.176.242.109|218.176.242.168|218.189.25.167|203.116.165.187|203.66.124.236|218.176.242.103|218.176.242.119|218.189.25.153|203.116.165.231|218.253.0.185|218.176.242.88|218.189.25.166|203.66.124.217|202.39.143.119|218.176.242.178|218.176.242.158|218.176.242.39|203.66.124.226|203.66.124.232|218.189.25.160|61.219.131.222|218.176.242.30|218.176.242.251|203.66.124.227|118.174.25.109|218.176.242.157|203.66.124.247|218.253.0.85|218.176.242.29|210.61.221.94|218.176.242.148|218.176.242.108|202.39.143.109|203.116.165.153|203.116.165.251|93.123.23.18|203.66.124.158|1.179.250.88|203.66.124.187|203.66.124.157|103.25.178.38|218.189.25.180|203.116.165.173|203.211.0.55|218.253.0.177|203.211.0.44|203.211.0.20|178.45.251.123|178.45.251.113|1.179.251.246|203.116.165.148|203.211.0.59|203.211.0.24|203.211.0.25|93.123.23.24|203.116.165.152|123.205.251.80|203.66.124.246|218.253.0.176|202.39.143.55|218.176.242.98|203.117.34.187|203.117.34.148|62.197.198.240|61.219.131.108|123.205.251.112|62.197.198.227|210.61.221.168|61.219.131.226|202.39.143.123|60.199.175.117|218.253.0.165|218.253.0.90|123.205.250.80|62.201.216.212|202.39.143.113|210.61.221.183|203.66.124.221|61.219.131.251|218.253.0.155|61.219.131.88|203.66.124.216|218.176.242.173|61.219.131.98|202.39.143.89|203.66.124.183|61.219.131.104|203.66.124.212|203.66.124.182|218.189.25.146|61.219.131.114|210.61.221.173|210.61.221.157|210.61.221.158|202.39.143.30|61.219.131.236|202.39.143.29|202.39.143.39|210.61.221.109|202.39.143.108|202.39.143.20|61.219.131.84|61.219.131.93|210.61.221.178|210.61.221.104|202.39.143.84|61.219.131.123|210.61.221.103|202.39.143.88|210.61.221.153|61.219.131.247|210.61.221.108|210.61.221.163|210.61.221.99|61.219.131.241|210.61.221.88|210.61.221.84|61.219.131.232|61.219.131.99|210.61.221.89|210.61.221.167|210.61.221.152|210.61.221.187|202.39.143.114|61.219.131.119|202.39.143.59|210.61.221.162|210.61.221.98|210.61.221.148

直接复制就ok了

『轉』复活你的GoAgent

当然还可以请出GoAgent的好集邮WallProxy,速度飞快么么哒~

『轉』复活你的GoAgent

原文: http://allinfa.com/resurrection-goagent.html


为什么移动平台还是 Native 更流行,较少 HTML5 应用?

$
0
0
主要还是Html5 Native渲染不过关,Network Access已经不是问题了
优秀的Html5&Javascript Container出现才能根本解决问题,现在要想效果好只能拼硬件
本人经验是硬件越好效果越好,iOS webkit效果好于Android webkit,Samsung 的Rom对Browser core有优化同样的配置效果更好些
Html5渲染效果比不上Native App 跟 Android App没有iOS App流畅是一样一样滴,中间隔太多层了,除非OS内核直接嵌入渲染引擎,也许我想多了
——————————————————————下面反驳@水云逸
  • 每次使用都要打開瀏覽器( 多重的打開步驟
现在Html5跨平台应用的解决方案是一次开发,分平台打包,请把思维从desktop绕过来吧
  • 反複讀取同樣的素材和function( 花費額外的流量和等待時間,服務器壓力也會更大)( 你得再等個好幾年,讓網絡上去了再說
Html JS Resource files 都是打包的本地的,不占流量,何况这年头的网速还不够快么
  • 沒有或很少有足夠流暢的圖像,比如按鈕和列表效果( 打斷用戶享受的心情
有足够的效果,性能的确是问题,不过CSS3硬件加速提高很多
  • 離開網絡和瀏覽器無法工作,對於內容型的產品是個什麽效果?還是說你打算要求用戶每次保存網頁?( 無法離線使用)(要是有解決方案請務必告訴我)
请参照前两点,打包,或者以后会有Chrome App的类似方式,现在Chrome OS的App也是有离线可以用的,哪天Html5雄起了,Google Android一秒钟变 Chrome Mobile(firefox mobile os 太超前了,逃不了壮烈的命运)
  • 缺少與平臺相適應的功能或風格,比如手勢【1】、分享【2】( 需要用戶改變使用習慣
去查查Html5的Touch API吧,drag神马的应有尽有,以后会更全哦
  • 真的能夠跨平臺?現在都爲了網銀保留著IE呢,瀏覽器那不同的HTML5實現和網頁那不同的瀏覽器目標擱一起你打算怎麼辦?( 跨平臺成本並不低
讲Mobile您怎么能提到IE,好远古啊,想MS windows phone的browser即使是desktop的IE10,也不敢不遵循标准了,当然有的实现Chrome跟Firefox对象名都不一样,但是适配的工作比分平台开发代价低很多,何况Mobile的实现还是比较统一的
————————————————————————————
好吧~ 我真的不是Html5的脑残粉,我是吃过亏的好不好,我们用Html5做壳跨平台,下面还要跑C的协议栈,协议栈性能再高也受不了webkit总是给我卡啊!
Html5取代Native App?过五年再议吧~

— 完 —
本文作者: 王乐

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 29 个回答,查看全部。
延伸阅读:
移动互联网的未来,究竟是属于浏览器(HTML5),还是属于应用(Native)?
哪个开源的移动 HTML5 框架更好一点?此问题提出于2011年

Java线程与Linux内核线程的映射关系

$
0
0

http://blog.sina.com.cn/s/blog_605f5b4f010198b5.html


Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程。 

Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是由JVM的实现来确定的。Linux 2.6上的HotSpot使用了NPTL机制, JVM线程跟内核轻量级进程有一一对应的关系。线程的调度完全交给了操作系统内核,当然jvm还保留一些策略足以影响到其内部的线程调度,举个例子,在linux下,只要一个Thread.run就会调用一个fork产生一个线程。


Java线程在Windows及Linux平台上的实现方式,现在看来,是内核线程的实现方式。 这种方式实现的线程,是直接由操作系统内核支持的——由内核完成线程切换,内核通过操纵调度器(Thread Scheduler)实现线程调度,并将线程任务反映到各个处理器上。内核线程是内核的一个分身。程序一般不直接使用该内核线程,而是使用其高级接口,即轻量级进程(LWP),也即线程。这看起来可能很拗口。看图:


(说明:KLT即内核线程Kernel Thread,是“内核分身”。每一个KLT对应到进程P中的某一个轻量级进程LWP(也即线程),期间要经过用户态、内核态的切换,并在Thread Scheduler 下反应到处理器CPU上。)


        这种线程实现的方式也有它的缺陷:在程序面上使用内核线程,必然在操作系统上多次来回切换用户态及内核态;另外,因为是一对一的线程模型,LWP的支持数是有限的。


对于一个大型程序,我们可以 开辟的线程数量至少等于运行机器的cpu内核数量。java程序里我们可以通过下面的一行代码得到这个数量:
Runtime.getRuntime().availableProcessors();
  

所以最小线程数量即时cpu内核数量。如果所有的任务都是计算密集型的,这个最小线程数量就是我们需要的线程数。开辟更多的线程只会影响程序的性能,因为线程之间的切换工作,会消耗额外的资源。如果任务是IO密集型的任务,我们可以开辟更多的线程执行任务。当一个任务执行IO操作的时候,线程将会被阻塞,处理器立刻会切换到另外一个合适的线程去执行。如果我们只拥有与内核数量一样多的线程,即使我们有任务要执行,他们也不能执行,因为处理器没有可以用来调度的线程。
         如果线程有50%的时间被阻塞,线程的数量就应该是内核数量的2倍。如果更少的比例被阻塞,那么它们就是计算密集型的,则需要开辟较少的线程。如果有更多的时间被阻塞,那么就是IO密集型的程序,则可以开辟更多的线程。于是我们可以得到下面的线程数量计算公式:
线程数量=内核数量 / (1 - 阻塞率)

作者:working_brain 发表于2014-6-23 15:11:29 原文链接
阅读:88 评论:0 查看评论

sql优化-6(索引)

$
0
0
<一>索引开销
1.访问开销
访问集中导致热块竞争
索引查询要尽可能的避免回表,如果不可避免,需要关注聚合因子是否过大。
举个例子:
select a from test_db where b=5
A、假设b上没有索引
那么该条SQL将进行表扫描,扫描所有该表的数据块
从数据块中找到记录,并且进行过滤
可想而知,没有索引将会导致扫描该表所有数据块,性能低下
B、 假设b上有索引
那么该条SQL将进行索引扫描,在索引中找到b=5的位置,一般只需要扫描3个块左右就找到了
获得所有b=5的行的rowid
根据rowid再查询数据(这就是回表),如果数据量少,那么回表次数就少,如果需要的数据全部在索引中,那么就不会再回表了,例如a也在索引中,如果a不在索引中,那么仍然要回表一次查出a。
2.更新开销
在无索引的情况下,表的记录越大,插入的速度只会受到很小的影响,基本不会越慢。
在无索引的情况下,分区表的插入要比普通表更慢,因为插入的数据需要做判断落在哪个分区。有这方面的开销。
在有索引的情况下,表记录越大,索引越多,插入速度越慢。
在有索引的情况下,如果表非常大,索引也很多,在条件允许下,可以将索引先失效再生效,速度可以更快。
在有索引的情况下,分区表如果只是有局部索引,一般来说,分区表的插入速度比普通表更快,因为每个分区的分区索引都比较小,更新的开销自然也小。
3.建立开销
建索引过程产生全表锁
普通的对表建索引将会导致针对该表的更新操作无法进行,需要等待索引建完。更新操作将会被建索引动作阻塞
ONLINE建索引的方式,这种建索引的方式不会阻止针对该表的更新操作,与建普通索引相反的是,ONLINE建索引的动作是反过来被更新操作阻塞。
建索引的过程会产生排序,排序的开销一般比较大,所以要尽量避免在生产缓慢的时候建索引。

<二>索引失效
逻辑失效:
1.类型转换导致索引失效(是存放字符的字段就设varchar2类型,是存放数值的字段就设置number类型,是存放日期的字段就设置date类型)
2.列上使用函数运算导致索引失效,比如substr(列),trunc(列)
3.单独引用符合索引非第一位置的索引列
4.not in,not exist
5.表未进行分析
6.索引遇到like '%LJB' 或者是'%LJB%'的查询,是用不到索引,不过like 'LJB%'是可以用到索引
7.索引能够消除排序,但是如果排序是部分升序部分降序,就必须建对应部分升降序的索引,否则无法用这个来消除排序。
比如order by col1 desc col2 asc,我们可以建(col1 desc,col2 asc)的索引。
物理失效:
1.LONG修改为CLOB,居然会导致其他列的索引失效
2.用ALTER TABLE MOVE的方式来降低高水平,这个操作会导致索引失效
3.alter table t shrink的方式降低表的高水平位,也不会导致索引失效,却无法消除索引的大量空块。最终导致虽然索引不失效,查询依然不用索引
4.分区表操作导致全局索引失效
truncate分区会导致全局索引失效,不会导致局部索引失效。如果truncate 增加update global indexes,全局索引不会失效。
drop分区会导致全局索引失效,局部索引因为drop分区,所以也不存在该分区的局部索引了。如果drop分区增加update global indexes,全局索引不会失效。
split分区会导致全局索引失效,也会导致局部索引失效。如果split分区增加update global indexes,全局索引不会失效。
exchange会导致全局索引失效,不会导致局部索引失效。如果exchange分区增加update global indexes,全局索引不会失效。

<三>索引需注意问题:
1.一个表索引个数不宜过多(低于5);
2.外键应创建索引;
3.组合索引列不宜过多(小于4);
4.大表应该建索引(大于2G);
5.索引聚合因子不应该很大(聚簇因子是指,按照索引列值进行了排序的索引行序和对应表中数据行序的相似程度);
如果越有序,即相邻的键值存储在相同的block,那么这时候ClusteringFactor 的值就越低。
如果不是很有序,即键值是随即的存储在block上,这样在读取键值时,可能就需要一次又一次的去访问相同的block,从而增加了I/O.
Clustering Factor 的计算方式如下:
扫描一个索引(large index range scan)
比较某行的rowid和前一行的rowid,如果这两个rowid不属于同一个数据块,那么cluster factor增加1
整个索引扫描完毕后,就得到了该索引的cluster factor。
如果ClusteringFactor接近于表存储的块数,说明这张表是按照索引字段的顺序存储的。
如果ClusteringFactor接近于行的数量,那说明这张表不是按索引字段顺序存储的。
6.索引是否失效(普通表、分区表);
7.组合索引与单列索引存在交叉情况;
8.索引高度不宜过高(低于5);
9.索引是否设置并行属性(影响查询性能);
10.索引统计信息太旧


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Web项目中获取SpringBean——在非Spring组件中获取SpringBean

$
0
0

转自:http://www.cnblogs.com/Johness/archive/2012/12/25/2833010.html

 最近在做项目的时候我发现一个问题:Spring的IOC容器不能在Web中被引用(或者说不能被任意地引用)。我们在配置文件中让Spring自动装配,但并没有留住ApplicationContext的实例。我们如果希望在我们的项目中任何位置都能拿到同一个ApplicationContext来获取IOC容器中的资源,就要让Spring将上下文环境填充到我们能获取的地方,比如下面的做法(来自网络资源):

  自定义一个工具类,实现自ApplicationContextAware接口,接口的方法是setApplicationContext,我们实现它,并让其为我们服务,因为Spring在load自己的时候会将上下文环境填充进来。我们所要做的就是将得到的ApplicationContext保存下来用。

复制代码
 1 package org.coderecord.ccms.web.action.util;
 2 
 3 import org.springframework.beans.BeansException;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.context.ApplicationContextAware;
 6 
 7 /**
 8  * Spring IOC上下文工具类
 9  * 
10  * @author Ryan Shaw
11  * 
12  */
13 public class SpringUtil implements ApplicationContextAware {
14 
15     /**
16      * 当前IOC
17      */
18     private static ApplicationContext applicationContext;
19 
20     /**
21      * 设置当前上下文环境,此方法由spring自动装配
22      */
23     @Override
24     public void setApplicationContext(ApplicationContext arg0)
25             throws BeansException {
26         applicationContext = arg0;
27     }
28 
29     /**
30      * 从当前IOC获取bean
31      * 
32      * @param id
33      *            bean的id
34      * @return
35      */
36     public static Object getObject(String id) {
37         Object object = null;
38         object = applicationContext.getBean(id);
39         return object;
40     }
41 
42 }
复制代码

  上文的类就是我们要用的,而其中的setApplicationContext是接口中需要实现的,Spring会自动进行填充。我们在Spring的配置文件中注册一下:

1 <bean id="springUtil" class="org.coderecord.ccms.web.action.util.SpringUtil" />

  这样就可以了,Spring把我们需要的东西给我们了。

  我们就可以在需要的地方这样做:

1 YouClass obj = (YouClass)SpringUtil.getObject("beanid");

  当然,前提是你需要让Spring自动装配哦。

  

  以下为方法二,使用了注解和静态化的方式来产生SpringFactory对象

  来自网络资源,修改于2013-04-11 15:25:57 

  上文的方法有个麻烦的地方:需要配置。而Spring2.5及之后的版本实际上加入了注解的方式进行依赖项的注入,使用如下代码也许更好:

复制代码
 1 package org.ahe.util;
 2 
 3 import org.springframework.beans.factory.BeanFactory;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.web.context.support.SpringBeanAutowiringSupport;
 6 
 7 public class SpringWiredBean extends SpringBeanAutowiringSupport {
 8 
 9     /**
10      * 自动装配注解会让Spring通过类型匹配为beanFactory注入示例
11      */
12     @Autowired
13     private BeanFactory beanFactory;
14 
15     private SpringWiredBean() {
16     }
17 
18     private static SpringWiredBean instance;
19 
20     static {
21         // 静态块,初始化实例
22         instance = new SpringWiredBean();
23     }
24 
25     /**
26      * 实例方法
27      * 使用的时候先通过getInstance方法获取实例
28      * 
29      * @param beanId
30      * @return
31      */
32     public Object getBeanById(String beanId) {
33         return beanFactory.getBean(beanId);
34     }
35 
36     public static SpringWiredBean getInstance() {
37         return instance;
38     }
39 }
复制代码

  如果使用@Autowired注解自动装配的话,继承SpringBeanAutowiringSupport类是不能少的。当然,使用@Component等注解也是可以的。使用注解的话配置就需要改动了,不过因为我们为支持Spring注解的配置是可以多用的,所以还好。如下:

1 <context:component-scan base-package="org.ahe"></context:component-scan>

  该配置即可让org.ahe下所有包(您依然可以通过子标签的正则表达式匹配来进行更多设置)下的注解起作用。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Viewing all 15843 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>