Bolg地址迁移

新Blog的地址:wangchao.de

不小心点进来的同行,不妨去看看~~

Android:利用Google GeoCoding API替代Geocoder & 解决地址语言问题

摘要:Android定位开发中碰到GeoCoder间歇抽风问题,查证后得知可以用Google GeoCoding API来Workaround,这里记录此过程中遇到的两个收获吧,一是对这个Workaround给出自己的简单多线程解决方案,并未做太多封装。二是解决解析结果中地址的语言问题。

一.问题描述

最近在使用Android SDK中Geocoder类进行地址解析时发现有很大概率发生下面的悲剧…..

 java.io.IOException: Service not Available

具体原因有各种说法吧,也有文档

The Geocoder class requires a backend service that is not included in the core android framework. The Geocoder query methods will return an empty list if there no backend service in the platform. Use the isPresent() method to determine whether a Geocoder implementation exists.
意思应该是Geocoder类的使用描述在使用的前提是必须有 后台服务的支持,但是andorid sdk中不包含该服务的,Google可真够开玩笑的。在真机上不一定存在。据称可以用isPresent() 检测一下,就知道有没有了。

二.锁定解决方案

我在Android 的Google Code上发现各国的Developer都碰到这个问题了(http://code.google.com/p/android/issues/detail?id=8816),当然他们也提出了一些解决方案,简单总结下:

1.使用GoogleMap请求KML来解析位置(KML的Wiki传送门),当然要了解怎么使用KML的话,还得去http://code.google.com/apis/kml/documentation/,看看文档。具体的解决方案是使用URL请求,这是Issues里给的示例,Comment 20 by musicwit…@gmail.com

http://maps.google.com.tw/maps?f=q&source=s_q&hl=zh-TW&geocode=&q=%E5%8F%B0%E5%8D%97%E7%81%AB%E8%BB%8A%E7%AB%99&ie=UTF8&0&om=0&output=kml

2.像Comment21里说的我们可以直接利用http地址,实现地址查询:如:

根据地址查询经纬度:

http://maps.googleapis.com/maps/api/geocode/json?address=SFO&sensor=false

根据经纬度查询地址:

http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=false

bounds的作用

http://maps.googleapis.com/maps/api/geocode/json?address=Winnetka&sensor=false

http://maps.googleapis.com/maps/api/geocode/json?address=Winnetka&bounds=34.172684,-118.604794|34.236144,-118.500938&sensor=false

region的作用

http://maps.googleapis.com/maps/api/geocode/json?address=Toledo&sensor=false

http://maps.googleapis.com/maps/api/geocode/json?address=Tole

具体可以查看GoogleMap服务的文档http://code.google.com/intl/zh-CN/apis/maps/documentation/geocoding/

因为项目时间的原因,我果断采用了第二种我比较熟悉的方法。

三.多线程完成HTTP地址解析

这方面的教程网上已经有很多了,我就不列出我的方案了,给大家一个传送门吧

四.中文地址问题

我的需求是由地理位置解析出中文地址,但由Google Map  GeoCoding API返回的确实英文地址,我试过在HTTP请求中带Charset参数,但并没有成功返回中文…..

在网上搜了一大圈以后才发现一个解决方法,原来可以直接在Url里带language=zh-CN参数,服了,估计经常使用GoogleAPI的才知道吧,也没发现相关文档,示例:

http://maps.google.com/maps/api/geocode/json?latlng=39.9727642,116.3753401&sensor=true&language=zh-CN

可以返回中文了,Problem Done!

Update 2011-09-22:使用使用Google GeoCoding API过程的问题

千万别觉得这就结束了,下面列举在实际使用Google GeoCoding API过程中发现的几个问题:

1.HTTP连接不太稳定,注意多次尝试,而不是仅发送一次请求就使用,而要判断在没有返回值的时候尝试一定次数。

2.有时候Google GeoCodingAPI会返回错误格式的地址,记得做处理,例如:

请求:返回formatted_address字段,Url:

Request URL: http://maps.googleapis.com/maps/api/geocode/json?latlng=30.511381,114.401893&sensor=false&language=zh-CN

返回: “formatted_address”: “中国湖北省武汉市洪山区鲁磨路118号 邮政编码: 430079″

崩溃了,居然错带了邮编…..所以还要人工处理下,防止以上情况的发生!

参考文献:

Android Google Code Issue 8816: service not available

Android:用户定位User Localtion和利用HTTP解析地址—GeoCoding

Google Geocoding API 开发语言问题

【转】陈皓:程序员技术练级攻略

这篇文章取名叫Build Your Programming Technical Skills,我实在不知道用中文怎么翻译,但我在写的过程中,我觉得这很像一个打网游做任务升级的一个过程,所以取名叫“技术练级攻略”,题目有点大,呵呵,这个标题纯粹是为了好玩这里仅仅是在分享Mailper和我个人的学习经历。(注:省去了我作为一个初学者曾经学习过的一些技术(今天明显过时了),如:Delphi/Power builder,也省去了我学过的一些我觉得没意思的技术Lotus Notes/ActiveX/COM/ADO/ATL/.NET ……)
前言
你是否觉得自己从学校毕业的时候只做过小玩具一样的程序?走入职场后哪怕没有什么经验也可以把以下这些课外练习走一遍(朋友的抱怨:学校课程总是从理论出发,作业项目都看不出有什么实际作用,不如从工作中的需求出发)
建议:

  • 不要乱买书,不要乱追新技术新名词,基础的东西经过很长时间积累而且还会在未来至少10年通用。
  • 回顾一下历史,看看历史上时间线上技术的发展,你才能明白明天会是什么样。
  • 一定要动手,例子不管多么简单,建议至少自己手敲一遍看看是否理解了里头的细枝末节。
  • 一定要学会思考,思考为什么要这样,而不是那样。还要举一反三地思考。

:你也许会很奇怪为什么下面的东西很偏Unix/Linux,这是因为我觉得Windows下的编程可能会在未来很没有前途,原因如下:

  • 现在的用户界面几乎被两个东西主宰了,1)Web,2)移动设备iOS或Android。Windows的图形界面不吃香了。
  • 越来越多的企业在用成本低性能高的Linux和各种开源技术来构架其系统,Windows的成本太高了。
  • 微软的东西变得太快了,很不持久,他们完全是在玩弄程序员。详情参见《Windows编程革命史》

所以,我个人认为以后的趋势是前端是Web+移动,后端是Linux+开源。开发这边基本上没Windows什么事。
启蒙入门
1、学习一门脚本语言,例如Python/Ruby
可以让你摆脱对底层语言的恐惧感,脚本语言可以让你很快开发出能用得上的小程序。实践项目:

  • 处理文本文件,或者csv(关键词 python csv, python open, python sys)读一个本地文件,逐行处理(例如word count,或者处理log)
  • 遍历本地文件系统(sys, os, path),例如写一个程序统计一个目录下所有文件大小并按各种条件排序并保存结果
  • 跟数据库打交道(python sqlite),写一个小脚本统计数据库里条目数量
  • 学会用各种print之类简单粗暴的方式进行调试
  • 学会用Google (phrase, domain, use reader to follow tech blogs)

为什么要学脚本语言,因为他们实在是太方便了,很多时候我们需要写点小工具或是脚本来帮我们解决问题,你就会发现正规的编程语言太难用了。
2、用熟一种程序员的编辑器(不是IDE)和一些基本工具

  • Vim / Emacs / Notepad++,学会如何配置代码补全,外观,外部命令等。
  • Source Insight (或 ctag)

使用这些东西不是为了Cool,而是这些编辑器在查看、修改代码/配置文章/日志会更快更有效率。
3、熟悉Unix/Linux Shell和常见的命令行

  • 如果你用windows,至少学会用虚拟机里的linux,vmware player是免费的,装个Ubuntu吧
  • 一定要少用少用图形界面。
  • 学会使用man来查看帮助
  • 文件系统结构和基本操作 ls/chmod/chown/rm/find/ln/cat/mount/mkdir/tar/gzip …
  • 学会使用一些文本操作命令 sed/awk/grep/tail/less/more …
  • 学会使用一些管理命令 ps/top/lsof/netstat/kill/tcpdump/iptables/dd…
  • 了解/etc目录下的各种配置文章,学会查看/var/log下的系统日志,以及/proc下的系统运行信息
  • 了解正则表达式,使用正则表达式来查找文件。

对于程序员来说Unix/Linux比Windows简单多了。(参看我四年前CSDN的博文《其实Unix很简单》)学会使用Unix/Linux你会发现图形界面在某些时候实在是太难用了,相当地相当地降低工作效率。
4、学习Web基础(HTML/CSS/JS)+服务器端技术(LAMP)
未来必然是Web的世界,学习Web基础的最佳网站是W3School。

  • 学习HTML基本语法
  • 学习CSS如何选中HTML元素并应用一些基本样式(关键词:box model)
  • 学会用 Firefox + Firebug 或 Chrome 查看你觉得很炫的网页结构,并动态修改。
  • 学习使用Javascript操纵HTML元件。理解DOM和动态网页。网上有免费的章节,足够用了。。
  • 学会用 Firefox + Firebug 或 Chrome 调试 Javascript 代码(设置断点,查看变量,性能,控制台等)
  • 在一台机器上配置Apache或Nginx
  • 学习PHP,让后台PHP和前台HTML进行数据交互,对服务器相应浏览器请求形成初步认识。实现一个表单提交和反显的功能。
  • 把PHP连接本地或者远程数据库 MySQL(MySQL 和 SQL现学现用够了)
  • 跟完一个名校的网络编程课程(例如:http://www.stanford.edu/~ouster/cgi-bin/cs142-fall10/index.php )不要觉得需要多于一学期时间,大学生是全职一学期选3-5门课,你业余时间一定可以跟上
  • 学习一个Javascript库(例如jQuery或ExtJS)+ Ajax(异步读入一个服务器端图片或者数据库内容)+ JSON数据格式。
  • HTTP: The Definite Guide 读完前4章你就明白你每天上网用浏览器的时候发生的事情了(proxy, gateway, browsers)
  • 做个小网站(例如:一个小的留言板,支持用户登录,Cookie/Session,增、删、改、查,上传图片附件,分页显示)
  • 买个域名,租个空间,做个自己的网站。

进阶加深
1、 C语言和操作系统调用

  • 重新学C语言,理解指针和内存模型,用C语言实现一下各种经典的算法和数据结构。推荐《计算机程序设计艺术》、《算法导论》和《编程珠玑》。
  • 学习(麻省理工免费课程)计算机科学和编程导论
  • 学习(麻省理工免费课程)C语言内存管理
  • 学习Unix/Linux系统调用(Unix高级环境编程),了解系统层面的东西。
    • 用这些系统知识操作一下文件系统,用户(实现一个可以拷贝目录树的小程序)
    • 用fork/wait/waitpid写一个多进程的程序,用pthread写一个多线程带同步或互斥的程序。多进程多进程购票的程序。
    • 用signal/kill/raise/alarm/pause/sigprocmask实现一个多进程间的信号量通信的程序。
    • 学会使用gcc和gdb来编程和调试程序(参看我的《用gdb调试程序》)
    • 学会使用makefile来编译程序。(参看我的《跟我一起写makefile》)
    • IPC和Socket的东西可以放到高级中来实践。
  • 学习Windows SDK编程(《Windows程序设计》 ,《MFC Windows程序设计》)
    • 写一个窗口,了解WinMain/WinProcedure,以及Windows的消息机制。
    • 写一些程序来操作Windows SDK中的资源文件或是各种图形控件,以及作图的编程。
    • 学习如何使用MSDN查看相关的SDK函数,各种WM_消息以及一些例程。
    • 这本书中有很多例程,在实践中请不要照抄,试着自己写一个自己的例程。
    • 不用太多于精通这些东西,因为GUI正在被Web取代,主要是了解一下Windows 图形界面的编程。

2、学习Java

  • Java 的学习主要是看经典的Core Java 《Java核心编程技术》和《Java编程思想》(有两卷,我仅链了第一卷,足够了,因为Java的图形界面了解就可以了)
  • 学习JDK,学会查阅Java API Doc http://download.oracle.com/javase/6/docs/api/
  • 了解一下Java这种虚拟机语言和C和Python语言在编译和执行上的差别。从C、Java、Python思考一下“跨平台”这种技术。
  • 学会使用IDE Eclipse,使用 Eclipse 编译,调试和开发Java程序。
  • 建一个Tomcat的网站,尝试一下JSP/Servlet/JDBC/MySQL的Web开发。把前面所说的那个PHP的小项目试着用JSP和Servlet实现一下。

3、Web的安全与架构

  • 学习HTML5,网上有很多很多教程,以前酷壳也介绍过很多,我在这里就不罗列了。
  • 学习Web开发的安全问题(参考新浪微博被攻击的这个事,以及Ruby的这篇文章)
  • 学习HTTP Server的rewrite机制,Nginx的反向代理机制,fast-cgi(如:PHP-FPM)
  • 学习Web的静态页面缓存技术。
  • 学习Web的异步工作流处理,数据Cache,数据分区,负载均衡,水平扩展的构架。
  • 实践任务:
    • 使用HTML5的canvas 制作一些Web动画。
    • 尝试在前面开发过的那个Web应用中进行SQL注入,JS注入,以及XSS攻击。
    • 把前面开发过的那个Web应用改成构造在Nginx + PHP-FPM + 静态页面缓存的网站。

4、一些开发工具

  • 学会使用SVN或Git来管理程序版本。
  • 学会使用JUnit来对Java进行单元测试。
  • 学习C语言和Java语言的 coding standard 或 coding guideline。(我N年前写过一篇关C语言非常简单的文章——《编程修养》,这样的东西你可以上网查一下,一大堆)。
  • 推荐阅读《代码大全》《重构》《代码整洁之道

高级深入
1、C++ / Java 和面向对象
我个人以为学好C++,Java也就是举手之劳。但是C++的学习曲线相当的陡。不过,我觉得C++是最需要学好的语言了。参看两篇趣文“C++学习信心图”和“21天学好C++”

  • 学习(麻省理工免费课程)C++面向对象编程
  • 读我的“如何学好C++”中所推荐的那些书至少两遍以上(如果你对C++的理解能够深入到像我所写的《C++虚函数表解析》或是《C++对象内存存局(上)(下)》,或是《C/C++返回内部静态成员的陷阱》那就非常不错了)
  • 然后反思为什么C++要干成这样,Java则不是?你一定要学会对比C++和Java的不同。比如,Java中的初始化,垃圾回收,接口,异常,虚函数,等等。
  • 实践任务:
    • 用C++实现一个BigInt,支持128位的整形的加减乘除的操作。
    • 用C++封装一个数据结构的容量,比如hash table。
    • 用C++封装并实现一个智能指针(一定要使用模板)。
  • 设计模式》必需一读,两遍以上,思考一下,这23个模式的应用场景。主要是两点:1)钟爱组合而不是继承,2)钟爱接口而不是实现。(也推荐《深入浅出设计模式》)
  • 实践任务:
    • 使用工厂模式实现一个内存池。
    • 使用策略模式制做一个类其可以把文本文件进行左对齐,右对齐和中对齐。
    • 使用命令模式实现一个命令行计算器,并支持undo和redo。
    • 使用修饰模式实现一个酒店的房间价格订价策略——旺季,服务,VIP、旅行团、等影响价格的因素。
  • 学习STL的用法和其设计概念 -容器,算法,迭代器,函数子。如果可能,请读一下其源码。
  • 实践任务:尝试使用面向对象、STL,设计模式、和WindowsSDK图形编程的各种技能
    • 做一个贪吃蛇或是俄罗斯方块的游戏。支持不同的级别和难度。
    • 做一个文件浏览器,可以浏览目录下的文件,并可以对不同的文件有不同的操作,文本文件可以打开编辑,执行文件则执行之,mp3或avi文件可以播放,图片文件可以展示图片。
  • 学习C++的一些类库的设计,如: MFC(看看候捷老师的《深入浅出MFC》),Boost, ACE, CPPUnit,STL (STL可能会太难了,但是如果你能了解其中的设计模式和设计那就太好了,如果你能深入到我写的《STL string类的写时拷贝技术》那就非常不错了,ACE需要很强在的系统知识,参见后面的“加强对系统的了解”)
  • Java是真正的面向对象的语言,Java的设计模式多得不能再多,也是用来学习面向对象的设计模式的最佳语言了(参看Java中的设计模式)。
  • 推荐阅读《Effective Java》 and 《Java解惑
  • 学习Java的框架,Java的框架也是多,如Spring, Hibernate,Struts 等等,主要是学习Java的设计,如IoC等。
  • Java的技术也是烂多,重点学习J2EE架构以及JMS, RMI,等消息传递和远程调用的技术。
  • 学习使用Java做Web Service (官方教程在这里)
  • 实践任务: 尝试在Spring或Hibernate框架下构建一个有网络的Web Service的远程调用程序,并可以在两个Service中通过JMS传递消息。

C++和Java都不是能在短时间内能学好的,C++玩是的深,Java玩的是广,我建议两者选一个。我个人的学习经历是:

  • 深究C++(我深究C/C++了十来年了)
  • 学习Java的各种设计模式。

2、加强系统了解
重要阅读下面的几本书:

  • UNIX编程艺术》了解Unix系统领域中的设计和开发哲学、思想文化体系、原则与经验。你一定会有一种醍醐灌顶的感觉。
  • UNIX网络编程(卷1):套接字联网API》这是一本看完你就明白网络编程的书。重要注意TCP、UDP,以及多路复用的系统调用select/poll/epoll的差别。
  • TCP/IP详解卷1:协议》-这是一本看完后你就可以当网络黑客的书。了解以太网的的运作原理,了解TCP/IP的协议,运作原理以及如何TCP的调优。
  • 实践任务:
    • 理解什么是阻塞(同步IO),非阻塞(异步IO),多路复用(select, poll, epoll)的IO技术。
    • 写一个网络聊天程序,有聊天服务器和多个聊天客户端(服务端用UDP对部分或所有的的聊天客户端进Multicast或Broadcast)。
    • 写一个简易的HTTP服务器。
  • UNIX网络编程.卷2:进程间通信》信号量,管道,共享内存,消息等各种IPC……这些技术好像有点老掉牙了,不过还是值得了解。
  • 实践任务:
    • 主要实践各种IPC进程序通信的方法。
    • 尝试写一个管道程序,父子进程通过管道交换数据。
    • 尝试写一个共享内存的程序,两个进程通过共享内存交换一个C的结构体数组。
  • 学习《Windows核心编程》一书。把CreateProcess,Windows线程、线程调度、线程同步(Event, 信号量,互斥量)、异步I/O,内存管理,DLL,这几大块搞精通。
  • 实践任务:使用CreateProcess启动一个记事本或IE,并监控该程序的运行。把前面写过的那个简易的HTTP服务用线程池实现一下。写一个DLL的钩子程序监控指定窗口的关闭事件,或是记录某个窗口的按键。
  • 有了多线程、多进程通信,TCP/IP,套接字,C++和设计模式的基本,你可以研究一下ACE了。使用ACE重写上述的聊天程序和HTTP服务器(带线程池)
  • 实践任务:通过以上的所有知识,尝试
    • 写一个服务端给客户端传大文件,要求把100M的带宽用到80%以上。(注意,磁盘I/O和网络I/O可能会很有问题,想一想怎么解决,另外,请注意网络传输最大单元MTU)
    • 了解BT下载的工作原理,用多进程的方式模拟BT下载的原理。

3、系统架构

  • 负载均衡。HASH式的,纯动态式的。(可以到Google学术里搜一些关于负载均衡的文章读读)
  • 多层分布式系统–客户端服务结点层、计算结点层、数据cache层,数据层。J2EE是经典的多层结构。
  • CDN系统 – 就近访问,内容边缘化。
  • P2P式系统,研究一下BT和电驴的算法。比如:DHT算法。
  • 服务器备份,双机备份系统(Live-Standby和Live-Live系统),两台机器如何通过心跳监测对方?集群主结点备份。
  • 虚拟化技术,使用这个技术,可以把操作系统当应用程序一下切换或重新配置和部署。
  • 学习Thrift,二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。
  • 学习Hadoop。Hadoop框架中最核心的设计就是:MapReduce和HDFS。MapReduce的思想是由Google的一篇论文所提及而被广为流传的,简单的一句话解释MapReduce就是“任务的分解与结果的汇总”。HDFS是Hadoop分布式文件系统(Hadoop Distributed File System)的缩写,为分布式计算存储提供了底层支持。
  • 了解NoSQL数据库(有人说可能是一个过渡炒作的技术),不过因为超大规模以及高并发的纯动态型网站日渐成为主流,而SNS类网站在数据存取过程中有着实时性等刚性需求,这使得目前NoSQL数据库慢慢成了人们所关注的焦点,并大有成为取代关系型数据库而成为未来主流数据存储模式的趋势。当前 NoSQL数据库很多,大部分都是开源的,其中比较知名的有:MemcacheDB、Redis、Tokyo Cabinet(升级版为Kyoto Cabinet)、Flare、MongoDB、CouchDB、Cassandra、Voldemort等。

写了那么多,回顾一下,觉得自己相当的有成就感。希望大家不要吓着,我自己这十来年也在不断地学习,今天我也在学习中,人生本来就是一个不断学习和练级的过程。

—————————————————分割线———————————————

这篇文章我个人比较喜欢,对整理自己的思路很有帮助,特地收藏一下~~

MBTI测试结果

摘要:今天看到美团的产品总监王慧文的招聘启事,上面提到要MBTI测试结果邮件给他,我就想起来去年在雁南飞上做过一次,刚才想再做就放弃了,觉得应该不带目的的来做测试,呵呵,其实以前的结果我觉得还比较准,建议也不错,就贴出来自己参考。

MBTI测试结果

性格类型:
你的性格类型是“ENTJ”( 外向 + 直觉 + 思维 + 判断 )

你性格外向,活泼、热情,喜欢社交和新鲜事物,认为生活是充满很多可能性。能很快地将事情和信息联系起来,然后很自信地根据自己的判断解决问题。需要别人的肯定,也乐于支持和关心别人。

MBTI各维度详细得分:

维度 1 :驱动力的来源: 外向 54%
维度 2 :接受信息的方式: 直觉 65%
维度 3 :决策的方式: 思维 59%
维度 4 :对待不确定性的态度: 判断 57%

性别的差异
如果你是个男性:
你的苦恼在于,你的热情和关爱心,容易被误解为暧昧,但如果你特意塑造自己的强硬一面,又容易丧失自己的天赋优势。

如果你是个女性:
你的苦恼在于,由于社会对女性的普遍看法是传统和矜持,如果任由自己的性格发挥,容易被扣上肤浅无知的评语。

工作优势
敢于不断尝试并积极行动;

具备较强的社交能力;

具备流畅的语言能力;

有良好的创造力;

思想不墨守成规,善于发现做事情的新方法;

充满灵感,足智多谋;

具有洞察力,能捕捉常规以外的事物,理解力很强;

你有思想,善于思考,重视逻辑与客观分析,独立工作能力很强;

工作劣势
不能胜任比较沉闷的工作;

独立工作能力较差;

容易好心办错事;

可能会陷入在一些具体工作细节与日常操作中无法自拔;

过于追求原则与效率,会让你的工作环境充满压抑与敌意,使员工士气不高,动力降低,也使自己的精神处于压力之中;

难以做出充满感情色彩的决定,缺乏人际、人情事件的处理能力;

难以营造出快乐、有趣、融洽的工作环境;

个人发展建议
你的性格适合IT创业,项目经理,产品经理,咨询师等工作。

在大多数的社交场合中,你很友善,富有魅力、轻松自如而受 人欢迎。在任何有他们的场合中,你总是爽直、多才多艺和有趣,总有没完没了的笑话和故事。善于通过缓和气氛以及使冲突的双方相互协调,从而化解紧张的局势。
可能的盲点
由于你关注外界各种变化信息,喜欢处理紧急情况,不愿意制订规划去预防紧急情况的发生。常常一次着手许多事情,超出自己的负荷,不能履行诺言,可能使周围的人陷入混乱。你需要试着找到一些能让自己按时完成任务的方法。
你的注意力完全集中在有趣的活动上,喜欢不断地接受新的挑战,不愿意在目前沉闷的工作中消磨时间,难以估计自己行为带来的结果。你需要为自己订立一个行为标准。
你的性格外向,往往喜欢与同事更多的交流,并希望得到他们注意和认可,会容易显得浮躁与不够踏实,甚至是自大与骄傲。
当情况环境转变时,你很容易忽视他人的情感,变得迟钝和鲁莽。

个人发展建议:

— 全面审视现实情况,三思而后行
— 考虑别人的情感
— 分清事情的轻重缓急,作好计划,善始善终
— 需要抑制其独断而忽视他人感情的方面
— 需要在迅速决定之前,事先计划,考虑细节,三思而行
— 注意规划性,发展持之以恒
— 适合的时候,主动承担一些工作对你的发展更有利
— 尽量思考成熟后再采取行动,碰到困难时,你需要坚持

雁南飞给您的IT职业发展建议:

— 总的原则:首先积累好自己的核心竞争力——再图转变
— 提高自身技术能力,因为无论是技术管理型人才、技术精英,都需要让下面的人服你
— 如果走纯管理/职业经理人路线,提高自身管理能力
— 纯做技术也未必没有前途,比如“做技术,如果公司里的关键技术都是你发明的,你的价值比总经理还高。”
— 系统学习项目管理体系的知识,弥补技术人员这块的缺失
— 提高自身的交际和沟通能力(如果是外企,还需英语能力)
— 提高职业成熟度,将个人价值观与现实中的“游戏规则”区分开来
— 借助现在平台多做项目,积累人脉,待资源积累成熟时,寻找机会进入大型企业或跨国企业做项目管理等工作
— 提高和控制自己的情商,克服自身性格的一些劣势(做技术是智商上的挑战,做管理是情商上的挑战)

雁南飞给您的IT职业定位忠告:

— 职业定位不要幻想,比如有人想做一个技术牛人,可一看代码就烦;还有人想成为经理,可就不喜欢跟人打交道;这样的人只会是南辕北辙的失败者。
— 职业定位要早,比如技术人员转型做售前/顾问,越早越好
— 职业定位要慎重,比如技术人员转型做售前,发现没前途,又转做技术人员,非常不利
— 职业定位要综合决定:比如做技术,还是做管理,要看个人特质/企业环境和需求/个人价值观等3方面的因素综合决定,不要盲从。

[教程] 将win7电脑无线网变身WiFi热点

摘要:本教程是让我的WP7能连接到无线网,因为本人遇到一个诡异的问题,我的WP7不能连接到工作室的无线网,原因可能是WP7允许的连接无线网的时间较短,在路由还没返回success信息之前WP7就认为连接失败了…

友情提示:以下操作您需要管理员权限
开启windows 7的隐藏功能:虚拟WiFi和SoftAP(即虚拟无线AP),就可以让电脑变成无线路由器,实现共享上网,节省网费和路由器购买费。宏碁、惠普笔记本和诺基亚N97mini亲测通过。
以操作系统为win7的笔记本或装有无线网卡的台式机作为主机。
主机设置如下:
1、以管理员身份运行命令提示符:
快捷键win+R→输入cmd→回车
2、启用并设定虚拟WiFi网卡:
运行命令:netsh wlan set hostednetwork mode=allow ssid=wuminPC key=wuminWiFi
此命令有三个参数,mode:是否启用虚拟WiFi网卡,改为disallow则为禁用。
                  ssid:无线网名称,最好用英文(以wuminPC为例)。
                  key:无线网密码,八个以上字符(以wuminWiFi为例)。
开启成功后,网络连接中会多出一个网卡为“Microsoft Virtual WiFi Miniport Adapter”的无线连接2,为方便起见,将其重命名为虚拟WiFi。若没有,只需更新无线网卡驱动就OK了。
3、设置Internet连接共享:
在“网络连接”窗口中,右键单击已连接到Internet的网络连接,选择“属性”→“共享”,勾上“允许其他······连接(N)”并选择“虚拟WiFi”。
确定之后,提供共享的网卡图标旁会出现“共享的”字样,表示“宽带连接”已共享至“虚拟WiFi”。
clip_image001
4、开启无线网络:
继续在命令提示符中运行:netsh wlan start hostednetwork
(将start改为stop即可关闭该无线网,以后开机后要启用该无线网只需再次运行此命令即可)
clip_image002
至此,虚拟WiFi的红叉叉消失,WiFi基站已组建好,主机设置完毕。笔记本、带WiFi模块的手机等子机搜索到无线网络wuminPC,输入密码wuminWiFi,就能共享上网啦!

5、开机启动无线网络

在桌面空白处右击鼠标新建一个记事本,命名为“wifi.txt”

clip_image003

打开wifi.txt,输入“netsh wlan start hostednetwork”,保存退出

clip_image005

将wifi.txt重命名为“wifi.bat”,确认更改,然后它会变成像wp7.bat那样的图标,就说明成功了

clip_image006

注:如果发现改扩展名没用的话,就到“计算机—组织—文件夹与搜索选项”里吧已知文件类型的扩展名显示出来

clip_image007

找到windows的启动文件夹(开始—所有程序—启动),右击打开

clip_image008

然后把wifi.bat放入启动文件夹中,以后就能开机启动这个虚拟无线网络了

clip_image010

Android REST Client架构实践 第二篇

摘要:本篇主要针对Google I/O 2010当中提到的Android REST Client架构做个解析,对比说明Google提出的最佳Android REST Client架构的优势。

一.传统REST客户端架构分析

传统的REST客户端的层次架构如图1.1所示。

图1.1 架构图

层次结构图简述:

(1) 当用户对资源做出操作(增删改查)时,在Activity里开个独立线程进行REST请求。

(2) 线程执行REST请求,用相应的REST方法从REST服务上取得相应的数据。

(3) 将取得的数据交给相应资源的Processor解析出资源的内容。

(4) 将解析出的资源的内容直接放入相应的模型中,即存在内存中。

(5) 最后用Cursor去取内存中的数据。

架构劣势:

(1) 系统可能会随时强制关闭程序。由于Android系统是为有限资源的手机设计的操作系统,这就意味着如果系统要启用一个新程序,又没有内存了,它就会强行关闭一个不在用户屏幕上而运行着的程序,很可能这个REST客户端就被杀掉了,这时候如果已经执行了GET等REST方法,则所有的数据都会下载,但没法被显示,带宽被浪费了。

(2) 下载的数据存储在内存上。这使得可能会重复从REST服务器上请求数据,这会浪费手机CPU资源,浪费电池,浪费带宽,同时造成REST服务器上大量的请求。

二.Google I/O上提出的REST客户端架构

系统架构的具体层次结构如图2.1所示。

图2.1 系统模块的具体层次结构图

层次结构图简述:

(1) 由用户在Activity上所做的操作(如增、删、改、查)和相应的被操作的资源的REST服务URI组合成表达式树

(2) 将表达式树传给SyscAdapter解析

(3) SyscAdapter解析后决定用相应的REST方法从REST服务上取得相应的数据

(4) 将取得的数据交给相应资源的Processor解析出资源的内容

(5) 将解析出的资源内容放入SQLite数据库相应的表中

(6) 完成数据入库的操作以后,向发出请求的Activity发出重新读取数据库的提醒,则该Activity用Cursor来重新读取数据库显示请求数据给用户

本章针对传统REST客户端架构进行劣势分析,然后对Google提出的REST客户端架构进行简单的解析,简要说明为何此套架构可以解决传统REST客户端架构的问题。

下一章开始将针对Google I/O提出的REST客户端架构如何实现做实践讲解……..

WP7 程序部署错误代码(Error Code)详解

摘要:详解WP7错误码的含义,并提供几个常见Error Code的Workaround。

      做开发的童鞋都懂得,做什么都得先应付各种Development Error,Windows Phone也不例外,无奈在WP7的MSDN文档里压根没找到这些错误码的解释…….

     当然对于用破解软件的童鞋,就更伤不起了,只是装个游戏,难道还得学学怎么搞Visual Studio这么重的东西吗?!

来看看这些Error Code吧:

Error Code 错误详解和Workaround
0x8973180E Zune还没有安装。请安装最新版本的Zune。下载地址:http://www.zune.net/zh-HK/
0x8973180F Zune软件版本不是最新。请在http://www.zune.net/zh-HK/下载最新版
0×89731810 错误的设备配置. 重装Visual Studio 2010 Express for Windows Phone可以解决此问题。
0×89731811 Zune software没有打开.。确认运行了Zune之后再次尝试。
0×89731812 连接硬件设备出错。 确定设备正确链接,并且不处于锁屏状态。
0×89731813 程序启动失败。请确定设备已经注册并解锁,如何注册的传送门http://go.microsoft.com/fwlink/?LinkId=195284.
0×81030110 安装程序失败。发生运行时错误。在WMAppManifest.xml文件中的<Capabilities>中有项目设定错误。(这个没遇到过,看MSDN的讨论版大家的Workaround都没有成功的样子……)
0×81030111 确保程序在部署前被完整卸载。(我遇到一次,似乎是我以前装过某App,之后用Reset方式清过所有数据,再装相同App的时候出现的。Workaround是当出现此错误,在WP7上会出现以前App的图标,黑色块的,长按之后Remove就可以了)
0×81030118 程序安装失败。设备未进行开发者解锁。运行Windows Phone Developer Tools里的Developer Register工具进行开发者注册。(注册分为普通开发者注册和学生开发者注册,普通开发者注册99$/年,需要美国社保号,现在大陆还未开放注册,本人通过Rocky搞到一个免费的美国学生开发者账号,以后会提交应用的,有意者也可联系我,共同开发哈)
0×81030119 不能再部署程序了。你已经到达了本账号部署的最多部署限制,请卸载以前部署的程序来完成部署。 (我的学生开发者账号最多只能部署三个程序!)

本文只做WP7程序部署的错误码详解,刚好碰到了就发上来了,之后做程序审核提交的时候还会把碰到的问题一并发出来的。

Android REST Client架构实践 第一篇

摘要:今年一直断断续续在做一个基于昊哥的一套很重的REST API的Android Client,其实也是第一次做Android,而且是按照Google I/O 2010 – Android REST client applications(请自行翻墙:)的指导做一个REST的客户端,遇到各种问题所以特地记录一下。第一篇就概述一下:

1.REST API以及我所调用的的REST API的特点

2.Google I/O大会上提出的Android REST Client的建议架构

一、关于REST API

REST架构的优势,广泛应用这些废话就不说了,网上的讨论都已经够多了,有兴趣的Google之吧,而REST的核心概念,解析这些我的另一个系列《REST学习实践》会陆续添加,这里就不赘述了。简单的说就是:1.用Url表示资源 2.对资源的操作包括获取、创建、修改和删除资源,这些操作正好对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法

二、从Dev角度总结我所调用的REST API的特点

1.提供两种Data Formats,JSON和XML,我用的JSON,插播一段JSON简介吧:

   JSON是一种传递对象的语法,对象可以是name/value对,数组和其他对象。

   下面是段JSON代码

   1: {

   2:     "skillz": {

   3:         "web": [{

   4:             "name": "html",

   5:             "years": "5"

   6:         },

   7:         {

   8:             "name": "css",

   9:             "years": "3"

  10:         }],

  11:         "database": [{

  12:             "name": "sql",

  13:             "years": "7"

  14:         }]

  15:     }

  16: }

使用JSON的原因主要是JSON的解析速度据称比XML快10倍,其实Javascript上用的更多一些,有比较好的支持。

2.Authentication 权限

由于REST本身并没有标准,所以似乎并没有对权限这块做什么规定,在一些需要登录使用的API上我们用的是一套类似于OAuth的授权机制:

     a.向REST Service请求Login

     b.取得一个临时Token

     c.在一段时间内在HTTP Header带Token请求受保护的内容

至于Token的生成和更新就是Server端的工作了。

3.REST Request Url内嵌查询表达式

昊哥的REST Service提供了一套强大的查询表达式,类似于一个简单的编译器,Client可以在Request中带类似“q=AND(keyword:智能手机)(NOT(keyword:Nokia))(price:<1000)(city:~湖北~武汉)”来查询“在武汉1000元以下不是Nokia的智能手机”.

那么在这套REST API当中一个标准请求的Example就是

http://www.restexample.com/items/@all?c={PAGEINDEX}&max-results={PAGESIZE}&q={QUERYEXPRESSION}&orderby={ORDERBY}&partial={WANTEDFIELDS}

三、Google I/O 2010 Session上建议的Android REST Client App的架构

第一篇的话我就先抛个引子吧,上两个Session里的架构示例:
1.错误的范例
Android_rest_wrong
这其实还算是一般HTTP Client写法中比较好的,因为另开线程去处理HTTP Client,不会阻塞UI线程,但缺点也一样突出:
     Android OS可能会随时干掉这个Activity,比如在运行APP的时候突然接个电话就有可能被杀死,那么数据没有持久化的话,只能再次请求,这样糟糕的体验加过多流量足以让用户跟你的APP说滚蛋了……..
2.最佳范例
Android_rest
这是Google I/O上主推的建议Android REST Client,它的优点自然是解决了上面例子的缺点了,但Google不太厚道呀,说了自己的Android 上GMail,GReader等都是用这套架构完成的,却没给Demo代码,这里面用到的IntentService和ResultReceiver的文档支持也很少,搞得各大论坛上都有人讨论但实现的方案倒不多,希望本系列能给出一个比较完整的解决方案吧~~
 
本文就完了,下一篇主要对比Google I/O Session上的Android REST Client架构……….
 

PS:关于昊哥很重的WCF REST Service,有兴趣的可传送至昊哥的Blog文章我的WCF4 Rest Service及Entity Framework with POCO之旅

升级Android SDK Tools, revision 11时遇到问题的解决方案

安装环境和升级版本

OS:Window 7 pro

JRE Version:1.6.0_25-b06

Android SDK Platform-tools:revision 4

Android SDK Tools:revision 8

要升级为Android SDK Tools,revision 11

遇到的问题:

-= warning! =-

A folder failed to be renamed or moved. On Windows this typically means that a program Is using that Folder (for example Windows Explorer or your anti-virus software.)

Please momentarily deactivate your anti-virus software.

Please also close any running programs that may be accessing the directory ‘D:\Code\Android\android-sdk_r07-windows\android-sdk-windows\tools’.

When ready, press YES to try again.

解决方法:

尝试了

1,管理员模式运行,失败

2,关了什么Adb.exe,杀毒软件,各种浏览器,皆失败

3,去Eclipse Android SDK Manager更新,失败

万般无语之后只有Google之,发现原来是个老Bug了,各种版本都是这样的,在Android Google Code是排4000多的Issues……

最后还是参考了StackOverflow上CommonsWare的回答http://stackoverflow.com/questions/4360894/android-trouble-updating-to-android-sdk-tools-revision-7

  1. 在SDK的文件夹里,复制 tools\所有文件 到 scrap\
  2. 在 scrap\ 里运行android.bat,启动SDK Manager
  3. 升级之
  4. 完成后删了scrap文件夹
至于提到的修改环境变量,和需要重启以后才能删scrap文件夹我都没碰到,如果碰到大伙自行了断就好了

 

 

REST学习实践 – 第一篇:解析REST

摘自《REST Service 的最佳实践,第 1 部分: 重新解析 REST Service》 – 马春娥, 软件工程师, IBM

————————————-分割线——————————————————–

三种流行 web 服务的架构

Web 服务是一种面向服务的架构的技术,通过标准的 Web 协议提供服务,目的是保证不同平台的应用服务可以互操作。根据 W3C 的定义,Web 服务(Web service)应当是一个软件系统,用以支持网络间不同机器的互动操作。网络服务通常是许多应用程序接口(API)所组成的,它们通过网络,例如国际互 联网(Internet)的远程服务器端,执行客户所提交服务的请求。流行的或者曾经流行的 Web 服务架构有三种:SOAP RPC over HTTP, XML RPC over HTTP, 和 REST over HTTP。下面分别简要介绍这三种架构。

SOAP RPC over HTTP

简单对象访问协议(SOAP,全写为 Simple Object Access Protocol)是一种标准化的通讯规范,主要用于 Web 服务(web service)中。SOAP 的出现是为了简化网页服务器(Web Server)在从 XML 数据库中提取数据时,无需花时间去格式化页面,并能够让不同应用程序之间透过 HTTP 通讯协定,以 XML 格式互相交换彼此的数据,使其与编程语言、平台和硬件无关。

用一个简单的例子来说明 SOAP 使用过程,一个 SOAP 消息可以发送到一个具有 Web Service 功能的 Web 站点,例如,一个图书价格信息的数据库,消息的参数中标明这是一个查询消息,此站点将返回一个 XML 格式的信息,其中包含了查询结果。由于数据是用一种标准化的可分析的结构来传递的,所以可以直接被第三方站点所利用。

SOAP RPC over HTTP,在 HTTP 上传送 SOAP 并不是说 SOAP 会覆盖现有的 HTTP 语义,而是 HTTP 上的 SOAP 语义会自然的映射到 HTTP 语义。在使用 HTTP 作为协议绑定的场合中, RPC 请求映射到 HTTP 请求上,而 RPC 应答映射到 HTTP 应答。然而,在 RPC 上使用 SOAP 并不仅限于 HTTP 协议绑定。SOAP 协议没有和 HTTP 有很好的结合,没有利用 HTTP 协议里面关于 request 和 response 的丰富词汇,而是鼓励应用设计人员定义任意的词汇(动词和名词),像 getUsers(),savePurchaseOrder(…),getBookPrice() 等。SOAP RPC Request 通过 HTTP POST 请求发送。清单 1 和清单 2 给出了 SOAP RPC over HTTP 的 request 和 response 的示例。请求和响应是封装在 SOAP Envelope 里面,以 HTTP request 和 response 的 body 传送。

XML RPC over HTTP

XML RPC over HTTP 和 SOAP RPC over HTTP 从结构上看很类似。这种远程过程调用使用 HTTP 作为传输协议,XML 作为传送信息的编码格式。XML-RPC 的定义尽可能的保持了简单,但同时能够传送、处理、返回复杂的数据结构。XML-RPC 是工作在 Internet 上的远程过程调用协议。一个 XML-RPC 消息就是一个请求体为 XML 的 HTTP POST 请求,被调用的方法在服务器端执行并将执行结果以 XML 格式编码后返回。清单 3 和清单 4 给出了 XML RPC over HTTP 的 request 和 response 的示例。请求和响应是封装在一个固定的格式里面,以 HTTP request 和 response 的 body 传送。

REST over HTTP

REST 风格的架构也并不强调和协议的绑定。HTTP 是 WWW 网上广泛使用的并且被证明是有效的通信协议,所以现在 RESTful 服务基本也是基于 HTTP 协议的。资源是由 URI 来指定。

资源的操作包括获取、创建、修改和删除资源,这些操作正好对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法。通过操作资源的 representation 来操作资源。资源的 representation 可以是 XML 也可以是 HTML,取决于读者是机器还是人,是消费 web 服务的客户软件还是 web 浏览器。当然也可以是任何其他的格式。

REST 在最大程度上充分利用了 HTTP,没有增加额外的词汇和约定。

通过前面的分析和比较,我们可以清楚地看到,REST 风格的 web 服务与 SOAP RPC 和 XML RPC 风格的 web 服务相比,http request 更简单,response 的语意更清楚。而且客户端不需要知道那么多关于应用的细节,比如 method name,method 调用的参数等等。

简言之,目前在三种主流的 Web 服务实现方案中,因为 REST 模式的 Web 服务与复杂的 SOAP 和 XML-RPC 对比来讲明显的更加简洁,越来越多的 web 服务开始采用 REST 风格设计和实现。例如,Amazon.com 提供接近 REST 风格的 Web 服务进行图书查找;雅虎提供的 Web 服务也是 REST 风格的。

REST 风格的 web 服务已被广泛的接受和使用,但是在使用的过程中,我们发现其实有很多号称 RESTful 的 web 服务并不是 Roy 定义的 REST 服务,或者违背了其中的一些约束。像 Amazon 和 Flickr 的 web 服务。接下来,我们首先结合实际经验,重新解读 REST 架构风格中的核心概念,帮助读者准确的掌握 REST 架构,最后给出一个完全符合 REST 风格架构的 web 服务定义的例子。

REST 核心概念解读

Representational State Transfer

在理解 REST 相关的核心概念之前,我们来看看“REST”本身应该怎么理解。“Representational State Transfer”是一个不完整的句子,“Representational”代表的是什么的“表示”?“State”又指的是什么的状态 ?“Transfer”的又是什么?如果我们要把它补全该如何呢?根据 Roy 的论文和我们的实践,应该是“Application States Transfer among the resource ’ s representation”。这里的“State”指的是“应用”的“状态”,这个“状态”是用“资源的表示”来代表的,用户可以在“状态”之间“跳 转”。

REST 架构风格定义的约束

REST 是一种架构的风格,它是对分布式 hypermidea 系统的架构元素的抽象,提供了一些核心的概念和指导思想。这种架构风格是“客户端 – 服务器”架构风格的一种,也就是说“客户端”发起“请求”,“服务器”处理“请求”并返回相应的结果。REST 的贡献是规定了一系列的方法论,在“请求”方面,规定“客户端”怎么发起“请求”,发的是什么样的“请求”,以什么协议发“请求”;在处理方面,规定“服 务器”怎么响应“请求”,返回什么样的“响应”,系统后续应该怎么“跳转”等等。让我们再回顾 Roy 定义的这些约束。

“无状态”(Stateless)

“客户端”和“服务器端”的交互是“无状态”的,也就是说“请求”之间是相互隔离的。“服务器端”不保存“客户端”的应用上下文 (context),每个从“客户端”来的“请求”都必须包括所有的必要的信息让“服务器端”能够完全理解“请求”并处理。“客户端”存了很多“会话”的 信息。让我们以搜索引擎为例来看看“有状态”和“无状态”的区别。

无状态的搜索引擎的交互示例

服务器把当前的状态隐含中结果中返回,客户端保存下这些隐含的状态,而不是保存在服务器端。客户端可以根据服务器端返回 来的状态构建下一个状态的请求。

“无状态”的好处是每个状态都有一个对应的 URI,这些 URI 可以 bookmark,可以使得用户方便的在浏览器中前进后退,可以在用户希望的任何时候访问任意多次。

有状态的搜索引擎的交互示例

有状态的搜索引擎的 request 和 response 的交互示例。可以看出,request 之间的时序依赖性。以“搜索 SOAP”为例,用户在看 1~10 个搜索结果并想看 11~20 个结果,客户端只需要发一个“start=10”的请求而是发“/search?q=SOAP&start=10”的请求,也就是客户端不用重复 前面的 request 的上下文。这使得 HTTP request 相对简单了很多。但是他使得 HTTP protocol 变得复杂。服务器端和客户端需要同步会话的状态,在可靠网络上,这是一个复杂的任务。

“无状态”带来了一些性能的提升。在“visibility”方面,对于监控系统而言,它不用去关心跨请求的数据对当前请求的影响,所以 “visibility”有所提升。在“reliability”方面,由于“客户端”保存了很多“会话”数据,因此减少了部分“服务器”端的故障或者网 络故障对应用的影响,因此对于用户来说,“reliability”有所提升。最值得一提的是“scalability”,由于“服务器”端能够独立的响 应每个 request,而不用依赖会话历史,因此少了很多“资源”的管理和同步,使得多个服务器可以同时服务不同的用户的请求,获得很好的自由扩展功能。

当然,事务都有两面性,“无状态”带来的不足之处包括可能的网络性能的降低,因为“服务器”会发很多重复的数据到不同的“客户端”,使得 “客户端”保存所有的会话信息;这也导致了另一个问题,就是“服务器”将失去对应用的一致行为的一部分控制权,而且还对“客户端”的实现产生依赖

“缓存”(Cacheable)

为了提高 REST 风格架构的网络性能,Roy 加入了“缓存”的约束。“缓存”不是一个新的概念,HTTP 协议提供机制,使得“客户端”可以“缓存”一些数据。在“服务器”返回的“响应”中,可以隐式或者显式的指明数据的“缓存”属性,这样,“客户端”可以在 未来使用“缓存”下来的数据,减少“客户端”和“服务器”端的交互次数,从而达到提高网络性能的目的。

统一的接口 (Uniform Interface)

这是 REST 风格的架构区别于其他架构的一个最关键的指标,就是 REST 风格的架构对于任意应用,规定了统一的接口定义。接口定义包括四个部分:

  • 1)identification of resources(标识资源);
  • 2)manipulation of resources through representations(通过资源的表示来操作资源);
  • 3)self-descriptive messages(自描述的信息);
  • 4)hypermedia as the engine of application state(超媒体作为应用状态的引擎)

下面分别对这些概念进行解析。

Identification of resources

第一部分“identification of resources”讲了 REST 架构风格的一个最核心的概念“Resource”以及 “Resource”的“identification”。“Resource”是信息系统的一种抽象,可以是任何重要的足以把本身作为一个引用 (reference)的事物。从应用的角度看,如果应用的用户需要“创建一个到它链接”,获取或者缓存它的“表示”,或者想对他做些操作,那么都可以创 建一个“Resource”。一个“Resource”可以是现实世界的事物,比如一本书,一辆车,一栋房子;也可以是一个虚拟的概念,也可以是一个算法 的结果。“identification”是“Resource”的全局唯一的标识,如果“Resource”没有 identification,那么他不能称为“Resource”。用 URI 来表示一个 Resource 的 identification。关于 URI 的最佳实践包括 URI 是自描述的,有结构的,这样可以使得“客户端”可以自己创建一些有预测性的请求。几个比较好的 Resource URI 示例:

http://www.example.com/books/123456

http://www.example.com/softwares/im/db2/9.5


http://www.example.com/blog/2010/09/10/1


http://www.example.com/bugs/by-state/new

前面解释了什么是 Resource,怎么用 URI 来标识一个 Resource,下面来看下 Resource 和 URI 的关系,他们之间是不是一一对应的呢?让我们来回答下面几个问题:1)两个 URI 能指向同一个 Resource 么?回答是肯定的。作为程序员,我们都有这样的经历,就是经常做一些 release,让我们考虑这两个 URI: http://www.example.com/releases/3.1.1 和 http://www.example.com/releases/latest,在特定的时刻,他们指向的就是同一个 resource,但是背后的概念是不一样的,一个是指向一个特定的 release 版本号,一个是指向一个随着时间演进的 resource,是两个完全不同的概念。所以一个 resource 可以有一个或者多个 URI 来标识。2)一个 URI 能指向不同的 resource 么?答案是否定的。这和 Universal Resource Identifier 的原则相违背。

Manipulation of resources through representations

接着来看看“Representation”。Representation 是 Resource 的表现形式。Resource 是信息系统的抽象,但是最终必须以人们能理解的一种形式提供出来。可以是一个 XML 文档,HTML 文档,CSV,file 等等。一个 Resource 可以有多种 Representation。那么服务器端怎么知道用户想要哪个 Representation 呢?通常来讲有两种方式:

1)在 resource 的 URI 里面指明,为不同的 Representation 提供不同的 URI。举个例子,我们有个 book 的 resource,我们提供几个不同的 URI 来表示不同的 representation。清单 7、8、9 分别是 XML、JSON、CSV 三种 representation 的 HTTP request 和 response 的示例。
清单 7. Representation 为 XML 的 request 和 response 示例

 GET /books/123456/xml HTTP/1.1
 Host: example.com 

 Reponse:
 HTTP/1.1 200 OK
 Date: Fri, 10 Sept 2010 17:15:33 GMT
 Last-Modified: Fri, 10 Sept 2010 17:15:33 GMT
 ETag: "2b3f6-a4-5b572640"
 Accept-Ranges: updated
 Content-Type: text/xml; charset="utf-8"
 <book category="CHILDREN">
     <title lang="en">Harry Potter</title>
     <author>J K. Rowling</author>
     <year>2005</year>
     <price>24.99</price>
 </book>

清单 8. Representation 为 JSON 的 request 和 response 示例

 GET /books/123456/json HTTP/1.1
 Host: example.com 

 Reponse:
 HTTP/1.1 200 OK
 Date: Fri, 10 Sept 2010 17:15:33 GMT
 Last-Modified: Fri, 10 Sept 2010 17:15:33 GMT
 ETag: "2b3f6-a4-5b572640"
 Accept-Ranges: updated
 Content-Type: text/json; charset="utf-8"

 [
"book":
 {
"title":Harry Potter,
"author":J K. Rowling,
"year":2005,
"price":24.99
 }
 ]

清单 9. Representation 为 CSV 的 request 和 response 示例

 GET /books/123456/csv HTTP/1.1
 Host: example.com 

 Reponse:
 HTTP/1.1 200 OK
 Date: Fri, 10 Sept 2010 17:15:33 GMT
 Last-Modified: Fri, 10 Sept 2010 17:15:33 GMT
 ETag: "2b3f6-a4-5b572640"
 Accept-Ranges: updated
 Content-Type: text/csv; charset="utf-8"

 title,author,year,price
 Harry Potter,J K. Rowling,2005,24.99

2) 利用 HTTP 的内容协商(content negotiation)机制。客户端可以利用“Accept”header 指明它希望的内容表示形式。还是拿 book 的例子来说,客户端发的 HTTP 请求如清单 9 所示:
清单 9. 利用 content negotiation 机制请求 representation 的 request 示例

 GET /books/123456 HTTP/1.1
 Host: example.com
 Accept: text/xml

对应的 response 和第一种方式相同,所以忽略了。

相比较这两种方式,根据我们的经验,第一种方式更好,URI 是一种好的实践,用来表示 resource 的各方面的信息,包括结果,版本,representation 形式,时间等等,它带来的好处是使客户端的工作大大降低,它很方便的可以在不同的应用之间共享。

那么怎么对 resource 进行下一步的操作(“manipulation”)呢? REST 对 Resource 的操作定义和 HTTP method 是对应起来的。HTTP 协议定义 GET、POST、PUT、DELETE 来表示对资源的获取、创建、更新和删除。“Manipulation of resources through representations”约束规定了 resource 的操作是通过 representation 来完成的,所以在 resource 的 representation 里面,需要包含对 resource 的操作怎么进行。APP(ATOM Publishing Protocol)提供了一个最佳实践,是用 <link> 的方式指明 Resource 响应的操作,下面是一个实例:

<link rel=”edit” href=”http://www.example.com/books/123456″/>

rel 定义了该 link 的 resource 和当前 resource 的关系,href 定义了 resource 的 HTTP endpoint。所以当用户想更新 id 为 123456 的 book 的价钱的时候,客户端会发一个 PUT 请求到指定的 URI。

Self-descriptive messages

REST 接口的定义强调了自描述“Self-descriptive”性。自描述性也是为了让客户端充分的理解当前的状态,下一步的状态怎么跳转。

前面讲了 resource 的 representation,只讲述了 representation 的数据的一部分。在 representation 里面,除了包含数据部分,还包括元数据,它是用来描述数据的信息,或者是一些客户端需要知道的一些领域知识。这里以 ATOM 协议为例看看怎么在 representation 里面提供自描述的信息。清单 12 是一个 ATOM 的片段。
清单 12. 一个 ATOM 形式的 resource representation

 <?xml version="1.0" encoding="UTF-8"?>
 <feed xmlns="http://www.w3.org/2005/Atom"
 xmlns:os="http://a9.com/-/spec/opensearch/1.1/"
 xmlns:catalog="http://www.ibm.com/opensearch/1.0">
  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 </id>
 <link href="http://www.example.com/books?q=harry potter&start=0" rel="self"></link>
 <link href="http://www.example.com/books?q=harry potter&start=10" rel="next"></link>
  <updated>2009-08-11T03:00:27.062Z</updated>
  <title type="text"> harry potter 相关的图书 </title>
  <os:startIndex xmlns:os="http://a9.com/-/spec/opensearch/1.1/">0</os:startIndex>
  <os:itemsPerPage xmlns:os="http://a9.com/-/spec/opensearch/1.1/">10</os:itemsPerPage>
  <os:totalResults xmlns:os="http://a9.com/-/spec/opensearch/1.1/">10</os:totalResults> 

 <entry>
 <title type="text"> Harry Potter </title>
    <id>urn:id:23-27</id>
 <updated>2009-07-09T11:01:26.000Z</updated>
    <category term="harry potter"></category>
   <category term="best seller"></category>
  <category term="book"></category>
   <category term="Hyper Service"></category>
   <content type="application/xml" xmlns= ’ http://www.example.com/books ’ >
    <book category="CHILDREN">
     <title lang="en">Harry Potter</title>
     <author>J K. Rowling</author>
     <year>2005</year>
     <price>31.99</price>
            </book>
    </content>
    </entry>
…
 </feed>

从上面的例子可以看出,除了 <content> 里面的内容是和 book 数据相关的信息以外,剩下的信息都是描述性的信息,通常包括翻页信息:一共有多少页,前后翻页的 link 是什么;分类信息,时间信息,还有一些文本信息供用户阅读。

总之,服务器端尽可能的返回详细的信息,帮助客户端理解当前的状态,以及发起下一个请求所需要的所有信息,以达到“服务器端无状态”和客户端发起“状态跳转”的目的。

Hypermedia as the engine of application state

“Hypermedia as the engine of application state”是“统一接口”的最后一个约束,也是最重要的一个约束,不幸的是, Roy 的 REST 论文中对这个约束的解释特别少,在这里,我们根据我们的经验和理解,对这个约束进行描述。这个约束其实规定的是应用系统是通过 Hypermedia 的方式在不同的状态之间跳转。这句话听起来有点拗口,还是来看一个例子吧。

Flickr 提供了 REST API,以 flickr.groups.members.getList 为例来看看这个 REST API 的 定义,清单 13 是一个响应示例(sample response),可以看出“members”是一个 resource,它是一系列“member”的集合,也就是说,它指向其他的 resource。
清单 13. flickr.groups.members.getList 的响应示例

 <members page="1" pages="1" perpage="100" total="33">
 <member nsid="123456@N01" username="foo" iconserver="1"
 iconfarm="1" membertype="2"/>
 <member nsid="118210@N07" username="kewlchops666"
 iconserver="0" iconfarm="0" membertype="4"/>
 <member nsid="119377@N07" username="Alpha Shanan"
  iconserver="0" iconfarm="0" membertype="2"/>
 <member nsid="67783977@N00" username="fakedunstanp1"
 iconserver="1003" iconfarm="2" membertype="3"/>
 ...
 </members>

如果用户还想对“Alpha Shanan”了解更多呢?这时,客户端会构建一个 HTTP request,URI 为:

 http://api.flickr.com/services/rest/?
 method=flickr.people.getInfo?auth_key=xxxx&user_id=119377@N07

如果系统按照这种方式运行,问题在哪呢?客户端和服务器端需要有很多的共享的知识和约定,客户端需要知道获取人员信息的 API 是 method=flickr.people.getInfo 以 user_id 作为参数。这不是 Hypermedia,同时也违背了 Roy 的关于“Hypermedia as the engine of application state”的约束,所以这个不是好的 RESTful 的实现

Hypermedia 的实质是 hyperlink, 用 hyperlink 把这些相互依赖的 resource 联系起来,这些 hyperlink 是由服务器端生成并且在 representation 里面返回来的,包括了当前的状态集合和可能的下一步的状态集合。客户端不需要任何 domain specific 知识就能够实现状态的跳转。Hypermedia 类型的 sample response 如清单 14 所示。在清单 14 中可以看到,resource 和 resource 之间的联系通过 hyperlink 关联起来,并且在 resource 的 representation 里面表示。
清单 14. REST 风格的 flickr.groups.members.getList 的 sample response

 <members page="1" pages="1" perpage="100" total="33">
 <member href=" http://api.flickr.com/services/rest/?
 method=flickr.people.getInfo?auth_key=xxxx&user_id=123456@N01"
  username="foo" iconserver="1" iconfarm="1" membertype="2"/>
 <member href=" http://api.flickr.com/services/rest/?
 method=flickr.people.getInfo?auth_key=xxxx&user_id=118210@N07"
  username="kewlchops666" iconserver="0" iconfarm="0" membertype="4"/>
 <member href=" http://api.flickr.com/services/rest/?
 method=flickr.people.getInfo?auth_key=xxxx&user_id=119377@N07"
  username="Alpha Shanan" iconserver="0" iconfarm="0" membertype="2"/>
 <member href=" http://api.flickr.com/services/rest/?
 method=flickr.people.getInfo?auth_key=xxxx&user_id=67783977@N00"
  username="fakedunstanp1" iconserver="1003" iconfarm="2" membertype="3"/>
 ...
 </members>

通过前面关于“统一接口”的解析,我们清楚地知道,REST 风格的架构使得 web 服务的“客户端”和“服务器端”很好的分离开来。“客户端”不需要关心数据的存储,使得“客户端”的可移植性(portability)提高了。“服务器端”不用关心用户的接口和用户的状态,所以“服务器端”将变得更加简单,而且方便的获得更好的可伸缩性(scalability)。只要保持接口的定义不变 ,“客户端”和“服务器端”可以独立的开发和演变。

一个定义良好的 RESTful Web 服务接口

首先,用一个文档描述 web 服务的 capabilities 以及服务的 location。如清单 15 所示。


清单 15. 用 APP 协议描述的服务 capabilities 和 location

 <?xml version="1.0" encoding="UTF-8"?>
 <service xmlns="http://www.w3.org/2007/app"
  xmlns:atom="http://www.w3.org/2005/Atom">
 <workspace>
 <atom:title type="text"> InfoSphere MashupHub </atom:title> 

 <collection href="http://localhost:8080/mashuphub/atom?collection=all">
 <atom:title type="text"> All </atom:title>
 <accept> application/atom+xml; type=entry </accept>
 <categories> <categories> ALL </categories> </categories>
 </collection> 

 <collection href="http://localhost:8080/mashuphub/atom?collection=feeds">
 <atom:title type="text">Feeds</atom:title>
 <accept> application/atom+xml;type=entry </accept>
 <categories> <categories> feeds </categories> </categories>
 </collection>
…
 </workspace>
 </service>


这个服务文档指明 InfoSphere MashupHub 提供了一系列的 web 服务,包括 list 所有的资源,list 所有的 feeds 等等。并且还描述了每个 web 服务的 location 可以提供的 resource representation 的类型。这种描述文档对于 web 服务的客户端来说非常有益。这个服务描述文档本身也是一个 resource,可以用 HTTP URI 定位到。

其次,我们来看一下每个 web 服务是怎么定义的。


清单 16. RESTful web 服务接口的定义示例

 1) Resource:所有的 feeds
 2) Resource URI:

http://localhost:8080/mashuphub/atom?collection=feeds

 3) Resource representation:
 <feed xmlns="http://www.w3.org/2005/Atom">
  <id>
  http://9.186.64.113:8080/mashuphub/atom?collection=feed </id>
  <link href="http://9.186.64.113:8080/mashuphub/atom?collection=feeds"
  rel ="self"></link>
  <updated> 2010-09-11 T 15:12:24.968Z </updated>
  <title type = "text"> feeds Collection </title>
  <author>
    <name> InfoSphere MashupHub Search Feed</name>
  </author>
 <entry>
 <author>
      <name> InfoSphere MashupHub Search Feed </name>
    </author>
    <title type="html"> MyCo Customer List </title>
    <updated> 2010-09-07 T 05:08:52.000Z </updated>
    <id> urn:id:1460 </id>
 <link href="http://9.186.64.113:8080/mashuphub/atom?collection=feeds&amp;id=1460"
 rel="self"></link>
 <link href="http://9.186.64.113:8080/mashuphub/atom?collection=feeds&amp;id=1498"
 rel="related" title = "MyCo Customer List with weather info" > </link>
    <category term="feed"> </category>
    <content type = "application/xml" >
      <catalog:feed xmlns:catalog="http://www.ibm.com/xmlns/atom/opensearch/feed/1.0/">
        <catalog:version> 1.0 </catalog:version>
        <catalog:name> MyCo Customer List </catalog:name>
        <catalog:author> admin </catalog:author>
        <catalog:permission> public </catalog:permission>
        <catalog:description> </catalog:description>
        <catalog:rating> 0.0 </catalog:rating>
        <catalog:useCount> 320 </catalog:useCount>
        <catalog:dateModified> 1283836132 </catalog:dateModified>
        <catalog:numComments> 0 </catalog:numComments>
        <catalog:tags> </catalog:tags>
    <catalog:categories> </catalog:categories>
    <catalog:downloadURL>http://9.186.64.113:8080/mashuphub/client
    /plugin/generate/entryid/1460/pluginid/3
     </catalog:downloadURL>
        <catalog:mimetype> application/atom+xml </catalog:mimetype>
      </catalog:feed>
    </content>
 </entry>
 </feed>
 4) Http method: GET
 5) 和别的 resource 的关系。
 在 representation 中用 <link>
 定义了“MyCo Customer List”和“MyCo Customer List with weather info”的关系


总结一下,一个设计良好的 RESTful web 服务应该包括一下几个定义:

  • 1) 服务描述文档,如清单 15 所示;
  • 2) 资源 (resource) 及其 identification;
  • 3) 资源的 representation 的定义
  • 4) 用 HTTP method 表示的资源的 manipulation
  • 5) 在资源的 representation 里面以 Hyperlink 表述的资源和资源之间的关系

结束语

REST 是一种架构风格,汲取了 WWW 的成功经验:无状态,以资源为中心,充分利用 HTTP 协议和 URI 协议,提供统一的接口定义,使得它作为一种设计 Web 服务的方法而变得流行。在某种意义上,通过强调 URI 和 HTTP 等早期 Internet 标准,REST 是对大型应用程序服务器时代之前的 Web 方式的回归。

本文根据 Roy 的论文,结合实际的例子,重新解析了 REST 中的核心概念。根据作者多年的创建和使用 RESTful web 服务的经验,更多的是在观念上的澄清。最后通过一个 RESTful web 服务,告诉读者一个真正意义上的 RESTful web 服务是什么样子。但愿本文的讨论会您提供了一定意义上的思想上的指导和实践上的指导。


参考资料

学习

  • Roy Fielding 论文“Architectural Styles and the Design of Network-based Software Architectures” 描述了一个框架来使用架构样式理解软件架构,并演示了如何使用样式指导基于网络的应用程序软件的架构设计。
  • 构建 RESTful Web 服务 介绍如何使用 Restlet(一个面向 Java™ 应用程序的轻量级框架)构建 RESTful 应用程序。
  • 编写 REST 服务 介绍了 REST 和 Atom 发布协议(Atom Publishing Protocol,APP)的概念,展示了其在服务中的应用。
  • ATOM: ATOM specification.
  • RSS RSS specification.
  • ATOM Publishing Protocol: APP 协议标准。
  • 深入浅出 REST 对 REST(Web 架构)背后的概念提供快速的介绍。
  • RESTful Web Services 描述了如何利用可编程应用程序的 Web 功能。
  • Implementing RESTful Web services in Java 介绍如何编写遵从 JAX-RS: Java API for RESTful Web Services (JSR-311) 规范的 RESTful web 服务。
  • RESTful Web Services 描述了如何利用可编程应用程序的 Web 功能。

讨论

关于作者

马 春娥,工作在 IBM 中国软件开发中心 Web 2.0 开发小组,开发人员,曾参与 Project Zero 和 Lotus Mashup Center 的开发。主要的关注点在 Web 2.0 领域的数据的建模,数据的处理,数据的可视化,Web2.0 领域的数据的语义,数据的关联等。

——————————————————-分割线——————————————————–

摘了这么长,还有几件事需要自己做的,记一下先:

1.对比分析几个REST API:新浪微博,TWITTER

2.对ATOM和RSS做个了结

3.对昊哥REST Service的实现了解下先


Follow

Get every new post delivered to your Inbox.