2010年12月20日星期一

国内搜索引擎提交网站入口

新域名、新网站还没被搜索引擎收录,那就主动提交一下网址吧。常用的各大搜索引擎都有提交网站的入口:

谷歌(Google) : http://www.google.com/addurl/?hl=zh-CN&continue=/addurl

新网站被收录的速度都比较慢,不同搜索引擎收录更新的快慢也差很多。

2010年12月5日星期日

Java捕获系统全局的键盘事件

我们常用的QQ、MSN程序有一个Idle功能,也就是当用户一段时间没有任何鼠标、键盘事件的时候自动把用户状态设为离开,有事件的时候自动设为在线。

鼠标可以通过 MouseInfo.getPointerInfo() 得到当前的鼠标位置,判断鼠标的位置有没有变化。

那么Java如何捕获系统全局的键盘事件呢?


1. Java可以捕获自身GUI中某个组件上或全局的整个java程序上发生的键盘事件。


捕获整个java程序上发生的键盘事件:
方法一:Toolkit.getDefaultToolkit().addAWTEventListener( listener, eventMask)
listener是回调函数
eventMask是要关注的事件,如果只关注键盘事件,填 AWTEvent.KEY_EVENT_MASK 就可以


方法二:替换默认实现的EventQueue(事件队列),覆盖dispatchEvent方法,增加键盘处理。
EventQueue e = Toolkit.getDefaultToolkit().getSystemEventQueue();
e.push(new EventQueue() {
@Override
protected void dispatchEvent(AWTEvent event) {
if (event instanceof KeyEvent) {
// do your code
}
super.dispatchEvent(event);
}
});

如果Java程序处于当前操作系统的焦点,就可以捕获到所有键盘事件。


2. 但是Java本身是无法捕获Java之外的键盘事件的,也就是你无法知道在其它程序上发出的键盘事件。没办法,Java的设计就是这样。在一般的受管环境下,如 .net 一般也是只能捕获自己的键盘事件,而不是系统全局的hook,不过网上倒是有一篇文章介绍使用C#捕获全局系统键盘的办法。


唯一的办法就是使用native的方式捕获系统底层的键盘事件。当然这是Java不鼓励的,也不能跨平台。
使用 JNA (Java Native Access, https://jna.dev.java.net/ )可以实现这点,按照其示例实现一个LowLevelKeyboardProc 的hook安装到系统来捕获底层的键盘事件。

Java为什么会死

我承认有点标题党,准确的说应该是“Java程序为什么会退出”,自己随便总结几条,欢迎大家补充。
  • 调用了System.exit
  • 所有非后台线程运行结束或异常退出
  • 线程内有没有捕获的异常,抛到了最外层,线程推出。如一个简单的main程序,出现一个未捕获的异常,程序就退了。但在GUI程序中一般不会,因为窗口线程总在。
  • 遇到各种致命error,内存方面问题常见的是 OutOfMemoryError,影响整个jvm,导致退出。
  • 无线递归导致线程堆栈溢出 StackOverflowError ,只影响该线程。
  • 界面死锁,程序没反应。程序没有退出,但这时也只能kill掉了

2010年11月29日星期一

聪明是难以验证的

聪明是难以验证的。你说你跑得快,那好跑一个我看看,恩,百米在11秒以内,果然很快。你说你聪明,聪明一个我看看......
聪明、能力强,自己说不算,人人都觉得自己聪明、有能力,很少有人觉得自己不聪明的。简历上写的一切在被验证之前,都是无法确认的,不能信以为真。
但是,像聪明这类的东西是难以验证的,具有很强的主观性,不同的人有不同的看法。这类东西是没有绝对的、唯一的、正确的方法判断,是带有主观性的,不同的人想出不同的招进行测试。有些办法可以达到很好的测试效果,但也不是说不满足的就一定不成。
单位要招人、学校要择优录取。
筛选还有一个成本问题,要在一定的成本下完成,因此很难做到理想化。比如,为什么大企业只去名校做校园招聘,为什么非要本科以上学历,为什么非要相关专业出身。当然,非名校也有人才,没学历也有能力强的,不是专业出身也有做得好的。但是筛选方的时间精力也是有限的,这是很现实的问题。
反过来,从结果上看也具有偶然性,这里不认可你不一定说明你真的不成。
招人和找对象差不多,哪个更难?
很多时候,我们就是面临着这样的问题,在根本没有正确答案的情况下,做出选择和判断。

2010年10月15日星期五

利用flash实现Web中的特殊功能

本文阅读对象是(我这样的)flash技术门外汉。

Web中有些功能看似很神奇,因为这些是难以用标准web技术实现的,其实是用flash实现的。我项目中最近的两个小功能用到了flash,分享一下。

flash 本质上不是web标准技术,而是系统上独立于浏览器之外的第三方插件程序(由Adobe公司提供)。
但因为其普及率非常之高, flash又是“事实上”web技术的一部分,是事实标准。

用它可以实现一些看似浏览器不支持的事情,另一个好处是跨浏览器、跨平台。

一、将web上的内容复制到系统剪切板

出于安全原因,有些浏览器不支持复制到剪切板,IE虽然可以,但也会给出个警告。前几天, 我用 zeroclipboard 实现了这个功能,zeroclipboard就是使用flash技术实现了在浏览器上复制javascript提供的内容到系统剪切板上。正因为用的是flash,所以这个实现就可以跨浏览器、跨平台。核心api:System.setClipboard() ,当然因为安全原因,flash只能set剪切板内容,不能get剪切板内容。


二、熟客识别——使用flash本地存储替代cookie,清除cookie也没用

在用户不登录验证的情况下,想识别出对方,基本的办法是在对方的电脑上加个用户标识,以此来识别。否则没人知道电脑面前坐的是一只狗。最常见的方法是利用存储在本地的cookie,这是标准技术,已经可以满足一般需求。当然用户清空浏览器cookie或使用别的浏览器cookie就没了。比如浏览器的隐私浏览模式中就不保存cookie(关闭窗口时清掉)。

flash也有本地存储功能,类似于cookie的技术,因此可以替代cookie完成同样的事。国内的很多在线客服产品都使用这种技术。打着所谓的“国际/国内领先技术”,描述只说是“非cookie技术,清空cookie也能识别”,但不说是什么技术,因为说了就不灵了。

既然技术上都是类似的,flash之所以比cookie更有效的关键在于多数网民不知道flash有本地存储、不知道可以清空flash本地存储。清除浏览器数据的时候是不会清除flash数据的,因为flash不受浏览器控制。这也要怪adobe公司没有在显眼的地方告诉用户,这可是用户的隐私呀。

用户实际上可以自己设置flash本地存储策略,在这里还可以清理flash本地存储:http://www.macromedia.com/support/documentation/cn/flashplayer/help/settings_manager07.html

2010年8月16日星期一

正确地对待bug的逻辑和态度

刚看了李笑来老师写的《关于举证责任》的系列短文,又联想到平时程序员在开发中常见的错误认识,结合自己的经验写一些总结。
以下内容不是讲调试和分析问题的技巧,而遇到bug时正确地对待问题的逻辑和态度。
  • 你写了一堆代码,不能因为别人没有证明你的代码有错误而认为自己的代码没有错误。
  • 自己要尽可能证明自己的代码没错误,这不是别人的责任。
  • 别人证明你的代码有错误的难度是很大的
    • 因为证明本身难度就很大,1000行的代码中有多少个可能的状态、条件变量有多少、它们之间的组合又有多少。
    • 多线程的偶然现象很难手工复现,往往需要编程来主动创造那种特殊的条件下才行,而这需要对复杂的代码有相当深入的整体和细节的掌握后才能做到。
    • 别人可能对你的代码实现一无所知,别人只是使用中发现了问题而已。
    • 出现问题后,如何复现问题往往很难。找到问题发生的条件,就像在一个巨大的状态空间中找到其中一点一样,可能需要做大量的实验。
  • 出现问题了就说明确实存在问题,只是还不清楚问题来自哪里,什么条件下发生的。不能因为没有找到复现问题的办法,而认为那个问题不存在。
  • 想办法复现问题、分析问题可能的情况(假设+求证)、定位问题、找到问题,这个过程往往是最费时间精力的事情。解决问题的主要工作量就在这里,而不是解决本身。
  • 找到问题后,解决问题往往很简单,可能就是1、2分钟的事情,甚至就是在找到问题的同时就解决完了。
  • 分析问题或证明问题不存在的责任在于程序的实现者,而不在于发现问题的人(尤其是普通用户)。
  • 发现问题的人最好能提供更多信息、最好能够说明问题复现方法、甚至最好能说明问题出在哪(但这个不太现实)。但反之,不能因为发现问题的人无法做到这些而否定问题。更不能要求别人把这个问题找到并且解决了,才承认有这个问题。
  • 最终找到的问题点可能离问题的表象很远,这也说明找到问题是不太容易的,也容易让人难于判断问题出在谁那里。
  • 做前端的人,往往首先承受了所有的问题,尽管问题很可能不在前端。因为程序的所有交互都要从前端进行,用户也只能看到前端的东西而看不到后台的东西。所以前端工程师往往要证明问题不是出在他这里,但也很难说出问题出在哪里,这等于要他来解决问题。
  • 问题最终可能不是出在你负责的这里,而是别的地方。
  • 程序员不应该推卸问题,尽管可能不是你的问题,但每个人都要积极的想协助解决问题。因为解决问题是整个团队的共同目标。
  • 自己写的简单测试没问题,并不能证明代码都没问题。因为测试代码只是证明给定那几个测试条件、数据下的结果是对的,既没有完整的覆盖所有情况(其它情况下是不是对的还不知道),也不能证明实现的过程是对的(结果对不一定过程对,可能碰巧、可能测试条件没有触发问题点)。
  • 代码测试覆盖率,你的测试覆盖了多少代码?如果非常低,那么隐藏问题的可能性很大;很高的覆盖率也很难做到,而且工作量很大。
  • 当你能够主动想到问题,而不是由别人告诉你哪里有问题的时候,你就已经提高一大截了。

2010年8月11日星期三

ExtJs 加载优化

ExtJS 是个功能丰富、强大的 javascript 库,适合做一些富客户端界面。但是其庞大的体积会导致网页加载时间长,给人很慢的感觉。

为了找到网页加载慢的真正原因,首先你应该用 YSlow 这样的工具仔细分析一下,看看到底是哪些方面导致的。ExtJS可能只是其中的一个原因,也许还有别的地方影响了加载速度。下面只谈谈如何解决 ExtJs 加载慢的问题。

就像任何软件一样,功能越多就会体积越大,这个在所难免。
对于ExtJs,最简单的傻瓜式使用方法就是在页面中引入这三个文件:
ext-all.css(138K)、ext-base.js(32K)、ext-all.js(635K)
另外js文件还有对应的debug版:ext-base-debug.js(78K)、ext-all-debug.js(1.13M)
这仅仅是ExtJS,你的页面中肯定还有很多其它东西,加在一起可就不小了。按照一般的网速,下载这些东西就要等半天了。

1.不要使用debug的js文件(体积缩小1/2)
debug版的js和非debug版的js完全一样,只是没有压缩而已,但体积大了一倍,ext-all-debug.js达到1.13M!
所以,不要使用debug的,除非你需要做相关调试。就算要调试,那也只是在开发的时候,别忘了换回去。

2.自定义裁减 extjs(体积进一步缩小几分之一)
extjs 功能众多,但大多数人只用到其中的少数功能。傻瓜式的方式只是在开发时简单,正是环境应该用多少使多少定制一份自己用到的部分,这样可以小很多。extjs也是模块化实现的,在其网站上可以自定义一份:http://www.sencha.com/products/js/build/

3.启用gzip压缩(体积又缩小了几分之一)
这个很重要。一般web服务器都支持gzip压缩,gzip压缩对于文本类型的文件都有很好的压缩效果。比如 635K 的 ext-all.js 经过gzip压缩后只有 168K,太棒了!
apache、nginx等服务器均支持gzip压缩,建议配置一下对所有超过2k的 js、css 文件启用gzip压缩。除了web服务器,像tomcat、jetty这样的应用服务器也都支持gzip压缩。具体查看配置文档就知道了,很简单的。

提示:建议使用 静态gzip压缩 或者叫 预压缩静态内容,因为server在运行时进行压缩要消耗一定的cpu资源,而对于js这些静态内容而言完全可以预先压缩好,如果有以 .gz 结尾的同名文件,server直接返回压缩好的内容即可,这样减轻一些服务器的负担。
常见的后台组合是动内容和静态内容分离,然后让Web服务器处理所有的静态资源,应用服务器专心处理动态内容。
中小型应用也可以只用tomcat这样的应用服务器(简单一些),如果JavaEE的servlet容器不支持静态压缩,可以编写一个filter来实现同样的压缩或缓存效果。
话说多了,这方面都属于性能优化了。

最后,别忘了利用客户端浏览器上的缓存,下载一次就可以了,以后全部使用本地缓存。主要适用于用户会多次访问的情况。

网上还有人说使用JSA这样的 javascript 脚本压缩、混淆工具还可以进一步缩小体积,实际上非debug的js已经是经过一定压缩的了,继续做语言层面的压缩效果不明显。并且如果已经使用gzip压缩了,就没必要做这个了。


2010年8月9日星期一

Ajax 同源策略限制的简单说明

出于安全原因,浏览器对页面中的ajax请求(XMLHTTPRequest)有同源策略的限制。

如果两个页面的协议、域名和端口是完全相同的,那么它们就是同源的。当前加载页面只能发出同源的ajax请求。
比如说你的当前页面是http://www.example.com/test.html,那么这个页面中的只能发出 http://www.example.com/ 下的请求。

一、协议指:http、https、ftp等属于不同的协议,尤其是http和https也是不同的协议。
二、域名指不同:
  1. 顶级域名不同。如 www.abc.com的页面中不能向 www.def.com发出http请求。
  2. IP与域名也被认为是不同的,即便他们是一回事。比如在开发的时候,你自己的本机局域网地址是192.168.1.106,你用 localhost 打开当前页面,而页面中请求的却是192.168.1.106也不行的。总之,域名和IP被认为是不同的域名,包括 localhost ,所以要么全用域名,要么全用IP。
  3. 相同顶级域名,但二级域名不同也是不同的。这个要求对同一域名下的各个子服务之间访问造成了一些限制。比如 www.example.com 和 download.example.com 就是不同的,www.example.com 和 example.com也是不同的。不过javascript中允许设置 document.domain 变量为 当前域名更短的域名,比如当前访问的是www.example.com,可以设置 document.domain 为example.com,这样就可以访问 example.com 下的请求。一种跨子域的解决方法就是,x子域的当前页面包括一个y子域的iframe,当前页面和这个frame分别将自己的document.domain设置为根域名,这样当前x子域的页面就可以通过这个y子域的页面代理访问y子域的请求。
三、端口不同:这个大家都明白,比如80和8080是不同的。

注意:script标签的src属性是没有同源限制的,你的网页上可以加载互联网上任何url的js,比如在页面中嵌入Google 分析的js代码。类似的,img标签也可以加载任何url的图片,比如你的网站上链接的是别人的图片,这些都不受同源策略的限制。利用这一点,也可以实现一定程度的跨域请求,比如你可以利用js修改script或img等标签的src属性,就等于在向任意url发出了一个get请求。
iframe也可以是任意url,但当前页面只能向自己的同源发出请求。


同源策略在带来安全性的同时,也对应用程序造成了很多限制,所以又引出了ajax跨域问题决方法。除了前面说到的方法,一般的跨域就是类似代理的方法了。

2010年8月8日星期日

Geo Location 地理位置信息小结

周末调研了一下Geo Location 地理位置信息方面的内容,自己小结一下。
一、通过 IP 地址获得用户的地理位置信息
也就是根据用户的IP,通过IP数据库查询获得信息。一般IP数据库中,
每条记录的基本结构:
IP地址段(起始、结束),以及对应的信息数据
一般包含的信息:国家、区域(省/州)、城市、街道、经纬度、ISP提供商等信息

因为IP数据库随着时间经常变化(不过一段时间内变化很小),所以需要有人经常维护和更新。这个数据也不可能完全准确、也不可能覆盖全。这是maxmind的城市准确度 http://www.maxmind.com/app/city_accuracy
因为没有权威的数据组织机构,且经常有变化。各家数据供应商,基本上做着做着就形成自己的一套数据了。

目前,国内用的比较有名的是“纯真IP数据库”,国外常用的是 maxmind、ip2location。

IP数据库是否收费:收费、免费都有。一般有人维护的数据往往都是收费的,准确率和覆盖率会稍微高一些。

质量方面:
  1. 主要概念是准确率和覆盖率。
  2. 记录数据总条数。纯真现在是38万条(2010年07月30日更新)
  3. 是否有人维护。
  4. 数据库更新频率:每月、每周。数据库会定期更新的,maxmind开源版是每月更新一次。

查询形式:
  • 本地,将IP数据库下载到本地使用,查询效率高、性能好。常用在统计分析方面。具体形式又分为:
    • 内存查询:将全部数据直接加载到内存中,便于高性能查询
    • 数据库查询:将数据导入到数据库,再用数据库查询。效率没有内存查询快。
  • 远程(web service或ajax),调用远程第三方服务。查询效率自然比较低,一般用在网页应用中。


是否提供API:有的IP数据库提供API,支持多语言(java、javascript、C#等),这样你就不用自己直接分析数据格式、整理、写查询代码了。

是否提供经纬度:纯真IP数据库不提供经纬度,Maxmind提供。如果做地图应用,一般是需要经纬度的。

语言方面:英文还是中文。maxmind提供的数据,所有信息都是英文的,国家是iso的国家码,如中国是China,北京是Beijing,国内环境使用不方便,除非你自己再维护一个中英对照表。而纯真IP数据库就中文信息。

另外,有些Web服务器也有这方面的功能集成。因为对Web应用而言,IP数据显然是通过Web服务器获得的,因此这部分工作也可以交给web 服务器来做。比如 Nginx 就带了一个GeoIP 的可选模块( http://wiki.nginx.org/NginxHttpGeoIPModule),集成了 MaxMind,安装时需要在configure中指定该模块。


Maxmindhttp://www.maxmind.com
有收费版,也有开源版本。
数据下载,http://geolite.maxmind.com/download/geoip/database/
准确度,http://www.maxmind.com/app/city_accuracy
支持多种语言,http://www.maxmind.com/app/city
Open Source binary API available for the following languages:
ip2location http://www.ip2location.com/ 和Maxmind类似,不多介绍了。

纯真IP数据库
http://www.cz88.net/
主要是国内信息,比较准确,也比较精确(可以到小区、网吧什么的),数据也是中文的。比较适合分析国内数据,国内够用了。国外数据非常少,如果主要处理国外的,不要用这个。没有经纬度。

官方组织:APNIC
http://www.apnic.net/
APNIC is an open, membership-based, not-for-profit organization providing Internet addressing services to the Asia Pacific.
数据下载:http://ftp.apnic.net/apnic/dbase/data/
http://ftp.apnic.net/apnic/dbase/data/country-ipv4.lst 提供了IP段到国家的映射。小工具chnroutes 就是利用这个数据。


二、通过 W3C Geo API 获得用户地理位置

也就是html5中关于地理位置的方面

geolocation api,地理位置由浏览器提供,需要浏览器支持。很多基于地理位置的网站都开始使用了,一般需要浏览器用户同意。

W3C 的 Geolocation API Specification:http://dev.w3.org/geo/api/spec-source.html

三、移动领域
手机:GPS(精确度高、刚开启时搜星比较慢、手机上比较费电)、根据手机信号的基站定位(不太精确、范围较大),
Wifi信号应该也可以,但要有这方面的数据收集


其它参考:

Web 地理定位(Geo-Location)知识大全,http://www.javaeye.com/news/13813-web-geo

根据IP定位地理位置,http://www.huachu.com.cn/read/readbookinfo.asp?sectionid=1000004203

2010年8月7日星期六

Tomcat无法正常关闭

Tomcat的正常启动和停止是用 startup 和 shutdown 两个脚本,但有时候tomcat因为其中部署的某个应用导致不能正常 shutdown 。判断是不是由应用引起的问题,很简单,试试tomcat不部署任何应用时是不是也有这个问题。

其实,不能正常shutdown八成是由于应用自身没有释放资源造成的,比如在应用中使用了非daemon的线程或Timer(timer是使用独立线程来实现的),而在容器stop时自己又不销毁就导致容器不能正常停止,只能kill。容器只按照Java EE规范来管理应用中标准组件的生命周期,但你自己创建出来的资源要自己负责处理,容器是不会替你管理的。JVM中,所有的非守护线程都停止了,JVM自然就停止了。

解决方法无非两种:
1.将应用自己创建的线程、timer、scheduler这类的资源设为守护线程(daemon)。因为这些东西一般就是用来在应用运行期间做些例行维护的工作。
2.自己管理非守护线程的生命周期,当容器停止时手工释放资源。比如你可以在 Servlet 或 ServletContextListener 的 init 方法中初始化资源,在 destroy 方法中释放资源。

后话:很多应用开发人员并没有很好地理解原理,不清楚容器替你做了什么也就不清楚自己应该负责什么。
这是在我维护别人的写的一个web应用时发现的问题。