RESTful记录-RESTful内容

什么是资源?

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 Request

HTTP请求有五个主要部分:

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

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

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

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

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

HTTP 响应

HTTP Response

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近发送按钮预览按钮,然后点击发送按钮,您可能会看到下面的输出。

HTTP Request/Response

在这里,你可以看到,浏览器发送一个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
posted @ 2017-10-24 11:20  信方  阅读(367)  评论(0编辑  收藏  举报