什么是资源?

REST架构对待每一个内容都作为一种资源。这些资源可以是文本文件,HTML网页,图片,视频或动态业务数据。 REST服务器只是提供资源,REST客户端可访问和修改的资源。这里每个资源由URI标识/全局标识。 REST采用各种交涉代表的资源如文本,JSON,XML。 XML和JSON是资源的最流行的表示。

资源表示

在REST资源是在面向对象编程或数据库类似于实体类似的对象。一旦资源被标识则其表示是用一个标准的格式来决定,以便服务器可以发送资源上文所述的格式和客户端可以理解的格式。

例如,在REST Web服务 - 第一个应用教程,用户是使用下面的XML格式表示资源:

<user>
<id>1</id>
<name>Mahesh</name>
<profession>Teacher</profession>
</user>

同样的资源也可以使用JSON格式表示如下:

{
"id":1,
"name":"Mahesh",
"profession":"Teacher"
}

好的资源表示

REST并没有对资源表示格式有任何限制。客户端可以请求JSON表示,其中作为另一种客户端可能会要求同一资源的XML表示到服务器等。它是REST服务器的负责传递客户端的资源到客户端可以理解的格式。

以下是在设计资源的表示形式在一个RESTful Web服务要考虑的重要因素。

  • 易懂: 服务器和客户端应能够理解和使用的资源的表示格式。

  • 完整: 格式应当能够完全代表一个资源。例如,一个资源可以包含其他资源。格式应该能够代表简单以及资源的复杂的结构。

  • 可链接: 资源可以有一个联动到另一个资源,一个格式应当能够处理这种情况。

然而,目前大多数的Web服务使用XML或JSON格式代表的资源。有很多可用的理解,分析,并修改XML和JSON数据库和工具。

RESTful web services使用HTTP协议的客户端和服务器之间的通信媒介。 一个客户在一个HTTP响应形式的HTTP请求和服务器响应的形式发送消息。这种技术被称为消息。这些消息包含的信息数据和元数据,即有关消息本身的信息。让我们一起来看看在HTTP请求和HTTP响应消息HTTP1.1。

HTTP 请求

HTTP请求有五个主要部分:

  • Verb- 表示HTTP方法,如GET,POST,DELETE,PUT等

  • URI- 统一资源标识符(URI)来标识服务器上的资源

  • HTTP Version- 表示HTTP版本,例如HTTP1.1版。

  • Request Header- 包含元数据的HTTP请求消息作为键 - 值对。 例如,客户端(或浏览器)型,由客户端支持的格式,邮件正文的格式,缓存设置等。

  • Request Body- 消息内容或资源的表示。

HTTP 响应

HTTP响应有四个主要部分:

  • Status/Response Code - 表示对所请求的资源服务器状态。例如404表示未找到资源,200表示响应正常。

  • HTTP Version- 表示HTTP版本,例如HTTP1.1版。

  • Response Header- 包含元数据的HTTP响应消息作为键 - 值对。 例如,内容长度,内容类型,响应时间,服务器类型等

  • Response Body- 响应消息的内容或资源表示。

例子

正如我们在已经解释 RESTful Web服务第一个应用教程, 让我们把 http://localhost:8080/UserManagement/rest/UserService/users 在POSTMAN使用GET请求。如果你点击Postman近发送按钮预览按钮,然后点击发送按钮,您可能会看到下面的输出。

在这里,你可以看到,浏览器发送一个GET请求,并得到了响应的内容主体作为XML。

地址是指查找资源或多个资源位于服务器上。它类似于定位的人的邮寄地址。

REST架构中的每个资源都由其URI,统一资源标识符。 URI是以下格式:

<protocol>://<service-name>/<ResourceType>/<ResourceID>

一个URI的目的是要找到承载Web服务的服务器上的资源。请求的另一个重要属性是动词,标识要在资源上执行的操作。例如,在REST Web服 第一应用教程, URI 就是http://localhost:8080/UserManagement/rest/UserService/users 和动词是GET。

构建一个标准的URI

以下是要考虑在设计一个URI要点:

  • 使用复数名词 - 使用复数名词来定义的资源。例如,我们已经使用的用户识别用户的资源。

  • 避免使用空格 - 利用下划线(_)或连字符( - ),使用一个长的资源的名称,例如,使用authorized_users代替authorized%20users。

  • 使用小写字母 - 虽然URI是区分大小写,这是很好的做法,以保持网址只有小写字母。

  • 保持向后兼容 - 由于Web服务是一种公共服务,URI一旦做出公开应始终可用。在某些情况下URI更新,使用HTTP状态码,300表示旧的URI重定向到新的URI。

  • 使用HTTP动词 - 始终使用HTTP动词像GET,PUT和DELETE做业务上的资源。这是不好用操作名字URI。

例子

下面是一个URI的例子来获取的用户。

正如我们讨论至今认为RESTful web服务使得重用HTTP动词,以确定要执行所指定的资源(多个)的操作。 下表使用HTTP动词常用状态的例子。

S.N. HTTP方法,URI和操作
1 GET
http://localhost:8080/UserManagement/rest/UserService/users
获取用户列表
(只读)
2 GET
http://localhost:8080/UserManagement/rest/UserService/users/1
获取ID为1的用户
(只读)
3 PUT
http://localhost:8080/UserManagement/rest/UserService/users/2
使用ID为2插入用户
(等幂)
4 POST
http://localhost:8080/UserManagement/rest/UserService/users/2
更新ID为2的用户
(N/A)
5 DELETE
http://localhost:8080/UserManagement/rest/UserService/users/1
删除ID为2用户
(等幂)
6 OPTIONS
http://localhost:8080/UserManagement/rest/UserService/users
列出Web服务支持的操作
(只读)
7 HEAD
http://localhost:8080/UserManagement/rest/UserService/users
仅返回HTTP头,没有主体。
(只读)

下面是要考虑的重要问题:

  • GET 仅是读操作并且是安全的。

  • PUT 和 DELETE 操作幂等意味着他们的结果总是相同的,无论多少次,这些操作可被调用。

  • PUT 和 POST 动作几乎相同,区别仅位于在结果其中PUT操作是等幂,POST操作可能导致不同的结果。

例子

让我们来更新RESTful Web服务创建示例 - 第一应用教程创建Web服务它可以执行CRUD(创建,读取,更新,删除)操作。为简单起见,这里使用了一个文件I/O,以取代数据库操作。

现在更新User.java,UserDao.java和UserService.java文件在com.yiibai包下。

User.java

package com.yiibai;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "user")
public class User implements Serializable { private static final long serialVersionUID = 1L;
private int id;
private String name;
private String profession; public User(){} public User(int id, String name, String profession){
this.id = id;
this.name = name;
this.profession = profession;
} public int getId() {
return id;
}
@XmlElement
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
@XmlElement
public void setName(String name) {
this.name = name;
}
public String getProfession() {
return profession;
}
@XmlElement
public void setProfession(String profession) {
this.profession = profession;
} @Override
public boolean equals(Object object){
if(object == null){
return false;
}else if(!(object instanceof User)){
return false;
}else {
User user = (User)object;
if(id == user.getId()
&& name.equals(user.getName())
&& profession.equals(user.getProfession())
){
return true;
}
}
return false;
}
}

UserDao.java

package com.yiibai;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List; public class UserDao {
public List<User> getAllUsers(){
List<User> userList = null;
try {
File file = new File("Users.dat");
if (!file.exists()) {
User user = new User(1, "Mahesh", "Teacher");
userList = new ArrayList<User>();
userList.add(user);
saveUserList(userList);
}
else{
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
userList = (List<User>) ois.readObject();
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return userList;
} public User getUser(int id){
List<User> users = getAllUsers(); for(User user: users){
if(user.getId() == id){
return user;
}
}
return null;
} public int addUser(User pUser){
List<User> userList = getAllUsers();
boolean userExists = false;
for(User user: userList){
if(user.getId() == pUser.getId()){
userExists = true;
break;
}
}
if(!userExists){
userList.add(pUser);
saveUserList(userList);
return 1;
}
return 0;
} public int updateUser(User pUser){
List<User> userList = getAllUsers(); for(User user: userList){
if(user.getId() == pUser.getId()){
int index = userList.indexOf(user);
userList.set(index, pUser);
saveUserList(userList);
return 1;
}
}
return 0;
} public int deleteUser(int id){
List<User> userList = getAllUsers(); for(User user: userList){
if(user.getId() == id){
int index = userList.indexOf(user);
userList.remove(index);
saveUserList(userList);return1;}}return0;}privatevoid saveUserList(List<User> userList){try{File file =newFile("Users.dat");FileOutputStream fos; fos =newFileOutputStream(file);ObjectOutputStream oos =newObjectOutputStream(fos);
oos.writeObject(userList);
oos.close();}catch(FileNotFoundException e){
e.printStackTrace();}catch(IOException e){
e.printStackTrace();}}}

UserService.java

package com.yiibai;

import java.io.IOException;
import java.util.List; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; @Path("/UserService")
public class UserService { UserDao userDao = new UserDao();
private static final String SUCCESS_RESULT="<result>success</result>";
private static final String FAILURE_RESULT="<result>failure</result>"; @GET
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
public List<User> getUsers(){
return userDao.getAllUsers();
} @GET
@Path("/users/{userid}")
@Produces(MediaType.APPLICATION_XML)
public User getUser(@PathParam("userid") int userid){
return userDao.getUser(userid);
} @PUT
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String createUser(@FormParam("id") int id,
@FormParam("name") String name,
@FormParam("profession") String profession,
@Context HttpServletResponse servletResponse) throws IOException{
User user = new User(id, name, profession);
int result = userDao.addUser(user);
if(result == 1){
return SUCCESS_RESULT;
}
return FAILURE_RESULT;
} @POST
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String updateUser(@FormParam("id") int id,
@FormParam("name") String name,
@FormParam("profession") String profession,
@Context HttpServletResponse servletResponse) throws IOException{
User user = new User(id, name, profession);
int result = userDao.updateUser(user);
if(result == 1){
return SUCCESS_RESULT;
}
return FAILURE_RESULT;
} @DELETE
@Path("/users/{userid}")
@Produces(MediaType.APPLICATION_XML)
public String deleteUser(@PathParam("userid")int userid){int result = userDao.deleteUser(userid);if(result ==1){return SUCCESS_RESULT;}return FAILURE_RESULT;}@OPTIONS@Path("/users")@Produces(MediaType.APPLICATION_XML)publicString getSupportedOperations(){return"<operations>GET, PUT, POST, DELETE</operations>";}}

现在使用Eclipse,导出应用程序为war文件,并部署在Tomcat中。要使用eclipse创建WAR文件,按照选项 File -> export -> Web > War File 最后选择项目UserManagement和目标文件夹。 要将WAR文件部署在Tomcat,将UserManagement.war文件放置在Tomcat的安装目录下 > webapps 目录并启动Tomcat。

测试Web服务

Jersey提供的API来创建Web服务客户端并测试Web服务。我们已经创建了一个示例测试类 WebServiceTester.java 在com.yiibai下在的同一个项目中。

WebServiceTester.java

package com.yiibai;

import java.util.List;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType; public class WebServiceTester { private Client client;
private String REST_SERVICE_URL = "http://localhost:8080/UserManagement/rest/UserService/users";
private static final String SUCCESS_RESULT="<result>success</result>";
private static final String PASS = "pass";
private static final String FAIL = "fail"; private void init(){
this.client = ClientBuilder.newClient();
} public static void main(String[] args){
WebServiceTester tester = new WebServiceTester();
//initialize the tester
tester.init();
//test get all users Web Service Method
tester.testGetAllUsers();
//test get user Web Service Method
tester.testGetUser();
//test update user Web Service Method
tester.testUpdateUser();
//test add user Web Service Method
tester.testAddUser();
//test delete user Web Service Method
tester.testDeleteUser();
}
//Test: Get list of all users
//Test: Check if list is not empty
private void testGetAllUsers(){
GenericType<List<User>> list = new GenericType<List<User>>() {};
List<User> users = client
.target(REST_SERVICE_URL)
.request(MediaType.APPLICATION_XML)
.get(list);
String result = PASS;
if(users.isEmpty()){
result = FAIL;
}
System.out.println("Test case name: testGetAllUsers, Result: " + result );
}
//Test: Get User of id 1
//Test: Check if user is same as sample user
private void testGetUser(){
User sampleUser = new User();
sampleUser.setId(1); User user = client
.target(REST_SERVICE_URL)
.path("/{userid}")
.resolveTemplate("userid", 1)
.request(MediaType.APPLICATION_XML)
.get(User.class);
String result = FAIL;
if(sampleUser != null && sampleUser.getId() == user.getId()){
result = PASS;
}
System.out.println("Test case name: testGetUser, Result: " + result );
}
//Test: Update User of id 1
//Test: Check if result is success XML.
private void testUpdateUser(){
Form form = new Form();
form.param("id", "1");
form.param("name", "suresh");
form.param("profession", "clerk"); String callResult = client
.target(REST_SERVICE_URL)
.request(MediaType.APPLICATION_XML)
.post(Entity.entity(form,
MediaType.APPLICATION_FORM_URLENCODED_TYPE),
String.class);
String result = PASS;if(!SUCCESS_RESULT.equals(callResult)){
result = FAIL;}System.out.println("Test case name: testUpdateUser, Result: "+ result );}//Test: Add User of id 2//Test: Check if result is success XML.privatevoid testAddUser(){Form form =newForm();
form.param("id","2");
form.param("name","naresh");
form.param("profession","clerk");String callResult = client
.target(REST_SERVICE_URL).request(MediaType.APPLICATION_XML).put(Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE),String.class);String result = PASS;if(!SUCCESS_RESULT.equals(callResult)){
result = FAIL;}System.out.println("Test case name: testAddUser, Result: "+ result );}//Test: Delete User of id 2//Test: Check if result is success XML.privatevoid testDeleteUser(){String callResult = client
.target(REST_SERVICE_URL).path("/{userid}").resolveTemplate("userid",2).request(MediaType.APPLICATION_XML).delete(String.class);String result = PASS;if(!SUCCESS_RESULT.equals(callResult)){
result = FAIL;}System.out.println("Test case name: testDeleteUser, Result: "+ result );}}

现在运行测试,使用Eclipse。右键单击该文件,并按照选项Run as -> Java Application. 你会看到下面的结果Eclipse控制台:

Test case name: testGetAllUsers, Result: pass
Test case name: testGetUser, Result: pass
Test case name: testUpdateUser, Result: pass
Test case name: testAddUser, Result: pass
Test case name: testDeleteUser, Result: pass
http://localhost:8080/UserManagement/rest/UserService/getUser/1

以下是良好的URL的一个例子来获取的用户。

http://localhost:8080/UserManagement/rest/UserService/users/1

RESTful记录-RESTful内容的更多相关文章

  1. RESTful记录-RESTful服务

    按照REST架构,一个RESTful Web服务不应该继续服务器的客户端的状态.这种限制被称为无状态.它负责客户以它的上下文传递给服务器,然后服务器可以存储这样的上下文,以处理客户端的进一步请求.例如 ...

  2. RESTful记录-RESTful介绍

    RESTful Web服务是基于REST架构的Web服务.在REST架构一切都是一种资源. RESTful Web服务是轻量级的,高度可扩展性和可维护性,并且非常常用于创建基于API的Web应用程序. ...

  3. PHP如何自动识别第三方Restful API的内容,自动渲染成 json、xml、html、serialize、csv、php等数据

    如题,PHP如何自动识别第三方Restful API的内容,自动渲染成 json.xml.html.serialize.csv.php等数据? 其实这也不难,因为Rest API也是基于http协议的 ...

  4. RESTful 架构 && RESTful API

    RESTful 架构 && RESTful API REpresentational State Transfer (REST) 具象状态传输https://en.wikipedia. ...

  5. 理解RESTful架构——Restful API设计指南

    理解RESTful架构 Restful API设计指南 理解RESTful架构 越来越多的人开始意识到,网站即软件,而且是一种新型的软件. 这种"互联网软件"采用客户端/服务器模式 ...

  6. 《码出高效:Java开发手册》第四章学习记录,内容想当的多,前后花了几天的时间才整理好。

    <码出高效:Java开发手册>第四章学习记录,内容想当的多,前后花了几天的时间才整理好. https://naotu.baidu.com/file/e667435a4638cbaa15eb ...

  7. 理解restful 架构 && RESTful API设计指南

    restful是前端和后端接口中都会使用的设计思想. 网站即软件,我们也常说的webapp,这种互联网软件采用的是“客户端/服务器”模式,建立在分布式体系上. 网站开发,也可以完全采用软件开发的模式, ...

  8. Python 逐行修改txt每条记录的内容

    Txt中保存以些数据,这些数据中我们要逐行read line出来进行处理,约定第一个字符为"#"的数据表示已经处理. 一个办法是读取txt,新增另外一个已完成处理txt来保存完成的 ...

  9. TADOTable 用过滤事件 后 记录数据和 记录的内容

    用 过滤事件,过滤后 ADOTbTrade.RecordCount 是总数, 但是,记录内容是 过滤后的 ADOTbTrade.First; while not ADOTbTrade.Eof do b ...

随机推荐

  1. Android与单片机通信常用数据转换方法(汇总)

    下面直接贴代码 1.  将GB2312转化为中文,如BAFAC2DCB2B7→胡萝卜,两个字节合成一个文字 public static String stringToGbk(String string ...

  2. dokuwiki 配置 sendmail 邮件发送

    dokuwiki 发送邮件有2种方式: 一是直接使用 PHP 自带发送功能,需要配置 PHP.ini 文件, 我没试过,可参考官网 https://www.dokuwiki.org/tips:mail ...

  3. 虚拟机virtualBox安装linux系统 xshell远程连接linux

    虚拟机virtualBox安装linux系统 xshell远程连接linux 虚拟机概念: 通过软件, 使用虚拟化技术虚拟出电脑的硬件环境, 充当真实的电脑使用. 常见的虚拟软件: virtualBo ...

  4. selenium+ python自动化--断言assertpy

    前言: 在对登录验证时,不知道为何原因用unittest的断言不成功,就在网上发现这个assertpy,因此做个笔记 准备: pip install assertypy 例子: from assert ...

  5. GitHub笔记(一)——本地库基础操作

    零.基础概念理解——可以访问廖雪峰老师的网站https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c01 ...

  6. DevOps on AWS之Cloudformation概念介绍篇

    Cloudformation的相关概念 AWS cloudformation是一项典型的(IAC)基础架构即代码服务..通过编写模板对亚马逊云服务的资源进行调用和编排.借助cloudformation ...

  7. Scrum Meeting NO.2

    Scrum Meeting No.2 1.会议内容 今天,我们对已经确定的任务进行了分配,并针对界面设计方面的细节进行讨论. 由于这周其它课程任务繁重(编译+数据库).前端的任务主要分配给编程能力较好 ...

  8. Alpha冲刺——day6

    Alpha冲刺--day6 作业链接 Alpha冲刺随笔集 github地址 团队成员 031602636 许舒玲(队长) 031602237 吴杰婷 031602220 雷博浩 031602634 ...

  9. Alpha 冲刺五

    团队成员 051601135 岳冠宇 051604103 陈思孝 031602629 刘意晗 031602248 郑智文 031602234 王淇 会议照片 项目燃尽图 项目进展 暂无实质性进展. 项 ...

  10. jmeter 获取执行脚本的路径

    需求:向jmeter.jmx 的路径下 写日志 : import org.apache.jmeter.services.FileServer; import com.bzj.utils.*; Stri ...