REST 基础(二):Web 服务编程,REST 与 SOAP
应用场景介绍(在线用户管理)
本文将借助于一个应用场景,通过基于 REST 和 SOAP Web 服务的不同实现,来对两者进行对比。该应用场景的业务逻辑会尽量保持简单且易于理解,以有助于把我们的重心放在 REST 和 SOAP Web 服务技术特质对比上。
需求描述
这是一个在线的用户管理模块,负责用户信息的创建,修改,删除,查询。用户的信息主要包括:
用户名(唯一标志在系统中的用户)
头衔
公司
EMAIL
描述
需求用例图如下:
如图 1 所示,客户端 1(Client1)与客户端 2(Client2)对于信息的存取具有不同的权限,客户端 1 可以执行所有的操作,而客户端 2 只被允许执行用户查询(Query User)与用户列表查询(Query User List)。关于这一点,我们在对 REST Web 服务与 SOAP Web 服务安全控制对比时会具体谈到。下面我们将分别向您介绍如何使用 REST 和 SOAP 架构实现 Web 服务。
使用 REST 实现 Web 服务
本部分将基于 Restlet 框架来实现该应用。Restlet 为那些要采用 REST 结构体系来构建应用程序的 Java 开发者提供了一个具体的解决方案。关于更多的 Restlet 相关内容,本文不做深入讨论,请见参考资源列表。
设计
我们将采用遵循 REST 设计原则的 ROA(Resource-Oriented Architecture,面向资源的体系架构)进行设计。ROA 是什么?简单点说,ROA 是一种把实际问题转换成 REST 式 Web 服务的方法,它使得 URI、HTTP 和 XML 具有跟其他 Web 应用一样的工作方式。
在使用 ROA 进行设计时,我们需要把真实的应用需求转化成 ROA 中的资源,基本上遵循以下的步骤:
分析应用需求中的数据集。
映射数据集到 ROA 中的资源。
对于每一资源,命名它的 URI。
为每一资源设计其 Representations。
用 hypermedia links 表述资源间的联系。
接下来我们按照以上的步骤来设计本文的应用案例。
在线用户管理所涉及的数据集就是用户信息,如果映射到 ROA 资源,主要包括两类资源:用户及用户列表。用户资源的 URI 用 http://localhost:8182/v1/users/{username} 表示,用户列表资源的 URI 用 http://localhost:8182/v1/users 表示。它们的 Representation 如下,它们都采用了如清单 1 和清单 2 所示的 XML 表述方式。
清单 1. 用户列表资源 Representation
清单 2. 用户资源 Representation
客户端通过 User List Resource 提供的 LINK 信息 ( 如 : <link>http://localhost:8182/v1/users/tester</link> ) 获得具体的某个 USER Resource
Restful Web 服务架构
首先给出 Web 服务使用 REST 风格实现的整体架构图,如下图所示:
图 2. REST 实现架构
接下来,我们将基于该架构,使用 Restlet 给出应用的 RESTful Web 服务实现。
下面的章节中,我们将给出 REST Web 服务实现的核心代码片段。关于完整的代码清单,读者可以通过资源列表下载。
客户端实现
清单 3 给出的是客户端的核心实现部分,其主要由四部分组成:使用 HTTP PUT 增加、修改用户资源,使用 HTTP GET 得到某一具体用户资源,使用 HTTP DELETE 删除用户资源,使用 HTTP GET 得到用户列表资源。而这四部分也正对应了图 2 关于架构描述的四对 HTTP 消息来回。关于 UserRestHelper 类的完整实现,请读者参见本文所附的代码示例
清单 3. 客户端实现
服务器端实现
清单 4 给出的是服务器端对于用户资源类(UserResourc)的实现,其核心的功能是响应有关用户资源的 HTTP GET/PUT/DELETE 请求,而这些请求响应逻辑正对应了 UserRestHelper 类中关于用户资源类的 HTTP 请求。
清单 4. 服务器端实现
UserResource 类是对用户资源类的抽象,包括了对该资源的创建修改(put 方法),读取(handleGet 方法 )和删除(delete 方法),被创建出来的 UserResource 类实例被 Restlet 框架所托管,所有操纵资源的方法会在相应的 HTTP 请求到达后被自动回调。
另外,在服务端,还需要实现代表用户列表资源的资源类 UserListResource,它的实现与 UserResource 类似,响应 HTTP GET 请求,读取当前系统内的所有用户信息,形成如清单 1 所示的用户列表资源 Representation,然后返回该结果给客户端。具体的实现请读者参见本文所附的代码示例。
使用 SOAP 实现 Web 服务
本文对于 SOAP 实现,就不再像 REST 那样,具体到代码级别的实现。本节将主要通过 URI,HTTP 和 XML 来宏观上表述 SOAP Web 服务实现的技术本质,为下一节 REST Web 服务与 SOAP Web 服务的对比做铺垫。
SOAP Web 服务架构
同样,首先给出 SOAP 实现的整体架构图,如下图所示:
图 3. SOAP 实现架构
可以看到,与 REST 架构相比,SOAP 架构图明显不同的是:所有的 SOAP 消息发送都使用 HTTP POST 方法,并且所有 SOAP 消息的 URI 都是一样的,这是基于 SOAP 的 Web 服务的基本实践特征。
获得用户信息列表
基于 SOAP 的客户端创建如清单 5 所示的 SOAP XML 文档,它通过类 RPC 方式来获得用户列表信息。
清单 5. getUserList SOAP 消息
客户端将使用 HTTP 的 POST 方法,将上述的 SOAP 消息发送至 http://localhost:8182/v1/soap/servlet/messagerouter URI,SOAP SERVER 收到该 HTTP POST 请求,通过解码 SOAP 消息确定需要调用 getUserList 方法完成该 WEB 服务调用,返回如下的响应:
清单 6. getUserListResponse 消息
获得某一具体用户信息
清单 7. getUserByName SOAP 消息
同样地,客户端将使用 HTTP 的 POST 方法,将上述的 SOAP 消息发送至 http://localhost:8182/v1/soap/servlet/messagerouter URI,SOAP SERVER 处理后返回的 Response 如下
清单 8. getUserByNameResponse SOAP 消息
实际上,创建新的用户,过程也比较类似,在这里,就不一一列出,因为这两个例子对于本文在选定的点上对比 REST 与 SOAP 已经足够了。
REST 与 SOAP 比较:略
实例参加下面附件code_rest.zip
from:http://www.ibm.com/developerworks/cn/webservices/0907_rest_soap/
本文将借助于一个应用场景,通过基于 REST 和 SOAP Web 服务的不同实现,来对两者进行对比。该应用场景的业务逻辑会尽量保持简单且易于理解,以有助于把我们的重心放在 REST 和 SOAP Web 服务技术特质对比上。
需求描述
这是一个在线的用户管理模块,负责用户信息的创建,修改,删除,查询。用户的信息主要包括:
用户名(唯一标志在系统中的用户)
头衔
公司
描述
需求用例图如下:
如图 1 所示,客户端 1(Client1)与客户端 2(Client2)对于信息的存取具有不同的权限,客户端 1 可以执行所有的操作,而客户端 2 只被允许执行用户查询(Query User)与用户列表查询(Query User List)。关于这一点,我们在对 REST Web 服务与 SOAP Web 服务安全控制对比时会具体谈到。下面我们将分别向您介绍如何使用 REST 和 SOAP 架构实现 Web 服务。
使用 REST 实现 Web 服务
本部分将基于 Restlet 框架来实现该应用。Restlet 为那些要采用 REST 结构体系来构建应用程序的 Java 开发者提供了一个具体的解决方案。关于更多的 Restlet 相关内容,本文不做深入讨论,请见参考资源列表。
设计
我们将采用遵循 REST 设计原则的 ROA(Resource-Oriented Architecture,面向资源的体系架构)进行设计。ROA 是什么?简单点说,ROA 是一种把实际问题转换成 REST 式 Web 服务的方法,它使得 URI、HTTP 和 XML 具有跟其他 Web 应用一样的工作方式。
在使用 ROA 进行设计时,我们需要把真实的应用需求转化成 ROA 中的资源,基本上遵循以下的步骤:
分析应用需求中的数据集。
映射数据集到 ROA 中的资源。
对于每一资源,命名它的 URI。
为每一资源设计其 Representations。
用 hypermedia links 表述资源间的联系。
接下来我们按照以上的步骤来设计本文的应用案例。
在线用户管理所涉及的数据集就是用户信息,如果映射到 ROA 资源,主要包括两类资源:用户及用户列表。用户资源的 URI 用 http://localhost:8182/v1/users/{username} 表示,用户列表资源的 URI 用 http://localhost:8182/v1/users 表示。它们的 Representation 如下,它们都采用了如清单 1 和清单 2 所示的 XML 表述方式。
清单 1. 用户列表资源 Representation
- <?xml version= "1.0" encoding= "UTF-8" standalone= "no" ?>
- <users>
- <user>
- <name>tester</name>
- <link>http://localhost:8182/v1/users/tester</link>
- </user>
- <user>
- <name>tester1</name>
- <link>http://localhost:8182/v1/users/tester1</link>
- </user>
- </users>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<users>
<user>
<name>tester</name>
<link>http://localhost:8182/v1/users/tester</link>
</user>
<user>
<name>tester1</name>
<link>http://localhost:8182/v1/users/tester1</link>
</user>
</users>
清单 2. 用户资源 Representation
- <?xml version= "1.0" encoding= "UTF-8" standalone= "no" ?>
- <user>
- <name>tester</name>
- <title>software engineer</title>
- <company>IBM</company>
- <email>tester@cn .ibm.com</email>
- <description>testing!</description>
- </user>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<user>
<name>tester</name>
<title>software engineer</title>
<company>IBM</company>
<email>[email protected]</email>
<description>testing!</description>
</user>
客户端通过 User List Resource 提供的 LINK 信息 ( 如 : <link>http://localhost:8182/v1/users/tester</link> ) 获得具体的某个 USER Resource
Restful Web 服务架构
首先给出 Web 服务使用 REST 风格实现的整体架构图,如下图所示:
图 2. REST 实现架构
接下来,我们将基于该架构,使用 Restlet 给出应用的 RESTful Web 服务实现。
下面的章节中,我们将给出 REST Web 服务实现的核心代码片段。关于完整的代码清单,读者可以通过资源列表下载。
客户端实现
清单 3 给出的是客户端的核心实现部分,其主要由四部分组成:使用 HTTP PUT 增加、修改用户资源,使用 HTTP GET 得到某一具体用户资源,使用 HTTP DELETE 删除用户资源,使用 HTTP GET 得到用户列表资源。而这四部分也正对应了图 2 关于架构描述的四对 HTTP 消息来回。关于 UserRestHelper 类的完整实现,请读者参见本文所附的代码示例
清单 3. 客户端实现
- public class UserRestHelper {
- //The root URI of our ROA implementation.
- public static final tring APPLICATION_URI = "http://localhost:8182/v1" ;
- //Get the URI of user resource by user name.
- private static String getUserUri(String name) {
- return APPLICATION_URI + "/users/" + name;
- }
- //Get the URI of user list resource.
- private static String getUsersUri() {
- return APPLICATION_URI + "/users" ;
- }
- //Delete user resource from server by user name.
- //使用 HTTP DELETE 方法经由 URI 删除用户资源
- public static void deleteFromServer(String name) {
- Response response = new Client(Protocol.HTTP).delete(getUserUri(name));
- ……
- }
- //Put user resource to server.
- //使用 HTTP PUT 方法经由 URI 增加或者修改用户资源
- public static void putToServer(User user) {
- //Fill FORM using user data.
- Form form = new Form();
- form.add("user[title]" , user.getTitle());
- form.add("user[company]" , user.getCompany());
- form.add("user[email]" , user.getEmail());
- form.add("user[description]" , user.getDescription());
- Response putResponse = new Client(Protocol.HTTP).put(
- getUserUri(user.getName()), form.getWebRepresentation());
- ……
- }
- //Output user resource to console.
- public static void printUser(String name) {
- printUserByURI(getUserUri(name));
- }
- //Output user list resource to console.
- //使用 HTTP GET 方法经由 URI 显示用户列表资源
- public static void printUserList() {
- Response getResponse = new Client(Protocol.HTTP).get(getUsersUri());
- if (getResponse.getStatus().isSuccess()) {
- DomRepresentation result = getResponse.getEntityAsDom();
- //The following code line will explore this XML document and output
- //each user resource to console.
- ……
- } else {
- System.out.println("Unexpected status:" + getResponse.getStatus());
- }
- }
- //Output user resource to console.
- //使用 HTTP GET 方法经由 URI 显示用户资源
- private static void printUserByURI(String uri) {
- Response getResponse = new Client(Protocol.HTTP).get(uri);
- if (getResponse.getStatus().isSuccess()) {
- DomRepresentation result = getResponse.getEntityAsDom();
- //The following code line will explore this XML document and output
- //current user resource to console.
- ……
- } else {
- System.out.println("unexpected status:" + getResponse.getStatus());
- }
- }
- }
public class UserRestHelper {
//The root URI of our ROA implementation.
public static final tring APPLICATION_URI = "http://localhost:8182/v1";
//Get the URI of user resource by user name.
private static String getUserUri(String name) {
return APPLICATION_URI + "/users/" + name;
}
//Get the URI of user list resource.
private static String getUsersUri() {
return APPLICATION_URI + "/users";
}
//Delete user resource from server by user name.
//使用 HTTP DELETE 方法经由 URI 删除用户资源
public static void deleteFromServer(String name) {
Response response = new Client(Protocol.HTTP).delete(getUserUri(name));
……
}
//Put user resource to server.
//使用 HTTP PUT 方法经由 URI 增加或者修改用户资源
public static void putToServer(User user) {
//Fill FORM using user data.
Form form = new Form();
form.add("user[title]", user.getTitle());
form.add("user[company]", user.getCompany());
form.add("user[email]", user.getEmail());
form.add("user[description]", user.getDescription());
Response putResponse = new Client(Protocol.HTTP).put(
getUserUri(user.getName()), form.getWebRepresentation());
……
}
//Output user resource to console.
public static void printUser(String name) {
printUserByURI(getUserUri(name));
}
//Output user list resource to console.
//使用 HTTP GET 方法经由 URI 显示用户列表资源
public static void printUserList() {
Response getResponse = new Client(Protocol.HTTP).get(getUsersUri());
if (getResponse.getStatus().isSuccess()) {
DomRepresentation result = getResponse.getEntityAsDom();
//The following code line will explore this XML document and output
//each user resource to console.
……
} else {
System.out.println("Unexpected status:"+ getResponse.getStatus());
}
}
//Output user resource to console.
//使用 HTTP GET 方法经由 URI 显示用户资源
private static void printUserByURI(String uri) {
Response getResponse = new Client(Protocol.HTTP).get(uri);
if (getResponse.getStatus().isSuccess()) {
DomRepresentation result = getResponse.getEntityAsDom();
//The following code line will explore this XML document and output
//current user resource to console.
……
} else {
System.out.println("unexpected status:"+ getResponse.getStatus());
}
}
}
服务器端实现
清单 4 给出的是服务器端对于用户资源类(UserResourc)的实现,其核心的功能是响应有关用户资源的 HTTP GET/PUT/DELETE 请求,而这些请求响应逻辑正对应了 UserRestHelper 类中关于用户资源类的 HTTP 请求。
清单 4. 服务器端实现
- public class UserResource extends Resource {
- private User _user;
- private String _userName;
- public UserResource(Context context, Request request, Response response) {
- //Constructor is here.
- ……
- }
- //响应 HTTP DELETE 请求逻辑
- public void delete() {
- // Remove the user from container.
- getContainer().remove(_userName);
- getResponse().setStatus(Status.SUCCESS_OK);
- }
- //This method will be called by handleGet.
- public Representation getRepresentation(Variant variant) {
- Representation result = null ;
- if (variant.getMediaType().equals(MediaType.TEXT_XML)) {
- Document doc = createDocument(this ._user);
- result = new DomRepresentation(MediaType.TEXT_XML, doc);
- }
- return result;
- }
- //响应 HTTP PUT 请求逻辑。
- public void put(Representation entity) {
- if (getUser() == null ) {
- //The user doesn't exist, create it
- setUser(new User());
- getUser().setName(this ._userName);
- getResponse().setStatus(Status.SUCCESS_CREATED);
- } else {
- getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
- }
- //Parse the entity as a Web form.
- Form form = new Form(entity);
- getUser().setTitle(form.getFirstValue("user[title]" ));
- getUser().setCompany(form.getFirstValue("user[company]" ));
- getUser().setEmail(form.getFirstValue("user[email]" ));
- getUser().setDescription(form.getFirstValue("user[description]" ));
- //Put the user to the container.
- getApplication().getContainer().put(_userName, getUser());
- }
- //响应 HTTP GET 请求逻辑。
- public void handleGet() {
- super .handleGet();
- if ( this ._user != null ) {
- getResponse().setEntity(getRepresentation(
- new Variant(MediaType.TEXT_XML)));
- getResponse().setStatus(Status.SUCCESS_OK);
- } else {
- getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- }
- }
- //build XML document for user resource.
- private Document createDocument(User user) {
- //The following code line will create XML document according to user info.
- ……
- }
- //The remaining methods here
- ……
- }
public class UserResource extends Resource {
private User _user;
private String _userName;
public UserResource(Context context, Request request, Response response) {
//Constructor is here.
……
}
//响应 HTTP DELETE 请求逻辑
public void delete() {
// Remove the user from container.
getContainer().remove(_userName);
getResponse().setStatus(Status.SUCCESS_OK);
}
//This method will be called by handleGet.
public Representation getRepresentation(Variant variant) {
Representation result = null;
if (variant.getMediaType().equals(MediaType.TEXT_XML)) {
Document doc = createDocument(this._user);
result = new DomRepresentation(MediaType.TEXT_XML, doc);
}
return result;
}
//响应 HTTP PUT 请求逻辑。
public void put(Representation entity) {
if (getUser() == null) {
//The user doesn't exist, create it
setUser(new User());
getUser().setName(this._userName);
getResponse().setStatus(Status.SUCCESS_CREATED);
} else {
getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
}
//Parse the entity as a Web form.
Form form = new Form(entity);
getUser().setTitle(form.getFirstValue("user[title]"));
getUser().setCompany(form.getFirstValue("user[company]"));
getUser().setEmail(form.getFirstValue("user[email]"));
getUser().setDescription(form.getFirstValue("user[description]"));
//Put the user to the container.
getApplication().getContainer().put(_userName, getUser());
}
//响应 HTTP GET 请求逻辑。
public void handleGet() {
super.handleGet();
if(this._user != null ) {
getResponse().setEntity(getRepresentation(
new Variant(MediaType.TEXT_XML)));
getResponse().setStatus(Status.SUCCESS_OK);
} else {
getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
}
}
//build XML document for user resource.
private Document createDocument(User user) {
//The following code line will create XML document according to user info.
……
}
//The remaining methods here
……
}
UserResource 类是对用户资源类的抽象,包括了对该资源的创建修改(put 方法),读取(handleGet 方法 )和删除(delete 方法),被创建出来的 UserResource 类实例被 Restlet 框架所托管,所有操纵资源的方法会在相应的 HTTP 请求到达后被自动回调。
另外,在服务端,还需要实现代表用户列表资源的资源类 UserListResource,它的实现与 UserResource 类似,响应 HTTP GET 请求,读取当前系统内的所有用户信息,形成如清单 1 所示的用户列表资源 Representation,然后返回该结果给客户端。具体的实现请读者参见本文所附的代码示例。
使用 SOAP 实现 Web 服务
本文对于 SOAP 实现,就不再像 REST 那样,具体到代码级别的实现。本节将主要通过 URI,HTTP 和 XML 来宏观上表述 SOAP Web 服务实现的技术本质,为下一节 REST Web 服务与 SOAP Web 服务的对比做铺垫。
SOAP Web 服务架构
同样,首先给出 SOAP 实现的整体架构图,如下图所示:
图 3. SOAP 实现架构
可以看到,与 REST 架构相比,SOAP 架构图明显不同的是:所有的 SOAP 消息发送都使用 HTTP POST 方法,并且所有 SOAP 消息的 URI 都是一样的,这是基于 SOAP 的 Web 服务的基本实践特征。
获得用户信息列表
基于 SOAP 的客户端创建如清单 5 所示的 SOAP XML 文档,它通过类 RPC 方式来获得用户列表信息。
清单 5. getUserList SOAP 消息
- <?xml version= "1.0" encoding= "UTF-8" standalone= "no" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" >
- <soap:Body>
- <p:getUserList xmlns:p="http://www.exmaple.com" />
- </soap:Body>
- </soap:Envelope>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<p:getUserList xmlns:p="http://www.exmaple.com"/>
</soap:Body>
</soap:Envelope>
客户端将使用 HTTP 的 POST 方法,将上述的 SOAP 消息发送至 http://localhost:8182/v1/soap/servlet/messagerouter URI,SOAP SERVER 收到该 HTTP POST 请求,通过解码 SOAP 消息确定需要调用 getUserList 方法完成该 WEB 服务调用,返回如下的响应:
清单 6. getUserListResponse 消息
- <?xml version= "1.0" encoding= "UTF-8" standalone= "no" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" >
- <soap:Body>
- <p:get
- UserListResponse xmlns:p="http://www.exmaple.com" >
- <Users>
- <username>tester<username>
- <username>tester1<username>
- ......
- </Users>
- <p: getUserListResponse >
- </soap:Body>
- </soap:Envelope>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<p:get
UserListResponse xmlns:p="http://www.exmaple.com">
<Users>
<username>tester<username>
<username>tester1<username>
......
</Users>
<p: getUserListResponse >
</soap:Body>
</soap:Envelope>
获得某一具体用户信息
清单 7. getUserByName SOAP 消息
- <?xml version= "1.0" encoding= "UTF-8" standalone= "no" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" >
- <soap:Body>
- <p:getUserByName xmlns:p="http://www.exmaple.com" >
- <username>tester</username>
- </p:getUserByName >
- </soap:Body>
- </soap:Envelope>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<p:getUserByName xmlns:p="http://www.exmaple.com">
<username>tester</username>
</p:getUserByName >
</soap:Body>
</soap:Envelope>
同样地,客户端将使用 HTTP 的 POST 方法,将上述的 SOAP 消息发送至 http://localhost:8182/v1/soap/servlet/messagerouter URI,SOAP SERVER 处理后返回的 Response 如下
清单 8. getUserByNameResponse SOAP 消息
- <?xml version= "1.0" encoding= "UTF-8" standalone= "no" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" >
- <soap:Body>
- <p:getUserByNameResponse xmlns:p="http://www.exmaple.com" >
- <name>tester</name>
- <title>software engineer</title>
- <company>IBM</company>
- <email>tester@cn .ibm.com</email>
- <description>testing!</description>
- </p:getUserByNameResponse>
- </soap:Body>
- </soap:Envelope>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<p:getUserByNameResponse xmlns:p="http://www.exmaple.com">
<name>tester</name>
<title>software engineer</title>
<company>IBM</company>
<email>[email protected]</email>
<description>testing!</description>
</p:getUserByNameResponse>
</soap:Body>
</soap:Envelope>
实际上,创建新的用户,过程也比较类似,在这里,就不一一列出,因为这两个例子对于本文在选定的点上对比 REST 与 SOAP 已经足够了。
REST 与 SOAP 比较:略
实例参加下面附件code_rest.zip
from:http://www.ibm.com/developerworks/cn/webservices/0907_rest_soap/
- code_rest.zip (9.5 KB)