Tutorialspoint RESTful 教程

来源：易百教程

RESTful教程™

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

REST是什么 ?

REST表示代表性状态传输。REST是一种基于Web标准的架构，并使用HTTP协议进行数据通信。它围绕着资源，其中每一个组件是资源和一个资源是由一个共同的接口，使用HTTP的标准方法获得。REST最初是由Roy Fielding在2000年推出。

在REST架构中，REST服务器只是提供的资源以及在REST客户端访问时提供资源。这里每个资源由URI标识/全局标识。REST采用各种申述表示类似文本，JSON和XML资源。现在JSON是Web服务所使用的最流行的格式。

HTTP 方法

下列著名的HTTP方法是常用于基于REST的架构。

GET - 提供的资源的只读访问。

PUT - 用于创建一个新的资源。

DELETE - 用于删除资源。

POST - 用于更新现有资源或创建新的资源。

OPTIONS - 用于得到支持的操作上的资源。

RESTful Web服务

Web服务是用于交换应用程序或系统之间的数据开放的协议和标准的集合。编写各种编程语言和运行在不同平台上的软件应用程序可以使用Web服务来以类似于进程间通信在单台计算机上的方式通过计算机网络进行交换数据，如因特网。 这份互联特性（如Java和Python，或Windows和Linux应用程序之间），是由于使用开放标准。

基于REST架构的Web服务称为RESTful web服务。这些Web服务使用HTTP方法来实现REST架构的概念。RESTful Web服务通常定义URI，统一资源标识符的服务，提供资源的表示，如JSON，并设置HTTP方法。

创建RESTful Web服务

本教程将创建一个Web服务使用以下用户管理功能：

Sr. No. | HTTP 方法 | URI | 操作 | 操作类型
1 | GET | /UserService/users | 获取用户列表 | 只读
2 | GET | /UserService/users/1 | 读取用户ID为1用户信息 | 只读
3 | PUT | /UserService/users/2 | 插入Id为2的用户信息 | 等幂
4 | POST | /UserService/users/2 | 更新Id为2的用户信息 | N/A
5 | DELETE | /UserService/users/1 | 删除Id为1的用户信息 | 等幂
6 | OPTIONS | /UserService/users | 列出Web服务支持的操作 | 只读

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful教程

RESTful环境安装设置 - RESTful教程™

本教程将指导你如何准备一个开发环境，开始使用Jersey框架工作，以创建基于REST的Web服务。Jersey 框架实现JAX-RS2.0 API，这是建立标准规范REST Web服务。本教程也将教你如何设置JDK，Tomcat和Eclipse在安装JerseyFramework之前：

第1步 - 安装Java开发工具包(JDK)：

您可以从甲骨文的Java网站上的最新版本的JDK：Java SE 下载. 会找到安装说明在下载的文件中，请按照说明安装JDK和配置设置。最后，设置PATH和JAVA_HOME环境变量指向包含java和javac的目录，通常java的安装目录分别为java_install_dir和java_install_dir。

如果使用的是Windows，并安装了JDK在C:\jdk1.7.0_75, 必须把下面的行放在 C:\autoexec.bat 文件中.

set PATH=C:\jdk1.7.0_75\bin;%PATH%
set JAVA_HOME=C:\jdk1.7.0_75

另外，如果使用 Windows NT/2000/XP, 你也可以在"我的电脑"，选择"属性"，然后右键单击"高级"，然后"环境变量"。 然后更新PATH值，然后按OK按钮。

在Unix（Solaris和Linux等），如果SDK安装在 /usr/local/jdk1.7.0_75 而你使用的是C shell，干脆把以下内容加入到.bashrc文件。

setenv PATH /usr/local/jdk1.7.0_75/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.7.0_75

另外，如果您使用的集成开发环境（IDE），如 Borland JBuilder, Eclipse, IntelliJ IDEA, 或Sun ONE Studio, 编译和运行一个简单的程序，以确认IDE知道你在哪里安装了Java，否则按说明文档为IDE做适当设置。

第2步 - 设置Eclipse IDE

在本教程中的所有示例是使用Eclipse IDE编写。所以建议你应该在计算机上安装最新版本的Eclipse。

要安装Eclipse IDE，请下载最新的Eclipse二进制文件：http://www.eclipse.org/downloads/ 当下载安装，解压二进制分发到一个方便的位置。例如：在window 上为C:\eclipse, 或/usr/local/eclipse 在Linux/Unix，最后适当设置PATH变量。

Eclipse可以通过在Windows计算机上执行下面的命令来启动，或者可以简单地双击eclipse.exe

 %C:\eclipse\eclipse.exe

在Unix（Solaris和Linux等）机器下面Eclipse可以通过执行下面命令来启动：

$/usr/local/eclipse/eclipse

成功启动后，如果一切都很好，然后它应该显示以下结果：

第4步 - 设置Jersey框架库

现在，如果一切正常，那么你可以继续设置Jersey框架。以下是简单的步骤，下载并在计算机上安装框架。

做出选择是否要在Windows或Unix上安装Jersey，然后进行下一步的下载.zip文件在windows，或.tz文件在Unix。

下载Jersey框架二进制文件的最新版本：https://jersey.java.net/download.html.

在写这篇教程的时候，下载是jaxrs-ri-2.17.zip 在Windows机器上，当解压缩下载的文件时，它会给出以下目录结构 E:\jaxrs-ri-2.17\jaxrs-ri 在window中。

你会发现所有的Jersey库的目录在C:\jaxrs-ri-2.17\jaxrs-ri\lib并依赖于C:\jaxrs-ri-2.17\jaxrs-ri\ext。确保这个目录上设置CLASSPATH变量正确，否则在运行应用程序面临的问题。如果使用的是Eclipse，则不需要设置CLASSPATH，因为所有的设置将通过Eclipse来完成。

第5步：安装Apache Tomcat：

可以下载Tomcat的最新版本：http://tomcat.apache.org/。一旦下载安装，解压二进制分发到一个方便的位置。如在windows上为 C:\apache-tomcat-7.0.59, 或在 Linux/Unix上为 /usr/local/apache-tomcat-7.0.59 并设置CATALINA_HOME环境变量指向安装位置。

Tomcat既可以通过在Windows机器上执行以下命令来启动，或者可以简单地双击执行startup.bat

 %CATALINA_HOME%\bin\startup.bat

 or

 C:\apache-tomcat-7.0.59\bin\startup.bat

Tomcat也可以通过在Unix（Solaris和Linux等）的机器执行下面的命令来启动：

$CATALINA_HOME/bin/startup.sh

or

/usr/local/apache-tomcat-7.0.59/bin/startup.sh

成功启动后，包含在Tomcat默认的Web应用程序将可以通过访问 http://localhost:8080/. 如果一切顺利，然后它应该显示以下结果：

有关配置和运行Tomcat的更多信息，可以这里include文档里找到，以及关于Tomcat网站： http://tomcat.apache.org

Tomcat可以执行在Windows机器下面的命令停止：

%CATALINA_HOME%\bin\shutdown

or

C:\apache-tomcat-7.0.59\bin\shutdown

Tomcat可以在Unix（Solaris和Linux等）的机器执行下面的命令停止：

$CATALINA_HOME/bin/shutdown.sh

or

/usr/local/apache-tomcat-7.0.59/bin/shutdown.sh

到这最后一步完成后，就可以开始你的第一个Jersey例子，将在下一章中看到。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful环境安装设置

RESTful Web Services示例程序 - RESTful教程™

让我们使用Jersey框架开始编写实际的RESTful web服务。 在开始使用Jersey框架编写第一个例子，必须确保设置环境REST Web服务正常。我也假设你有一点点的使用Eclipse IDE工作的经验。

因此，让我们继续编写一个简单的应用程序Jersey将公开一个Web服务方法来显示用户列表。

第1步 - 创建Java项目：

第一步是创建使用Eclipse IDE动态Web项目。按照选项 File -> New -> Project 并最后选择 Dynamic Web Project 从向导列表向导。现在使用的向导窗口如下项目命名为UserManagement：

一旦项目成功创建，目录结构在 Project Explorer:

第2步 - 添加必需的库：

第二步，让我们在项目中添加Jersey框架和它的依赖（库）。复制所有jar文件在下载ZIP的jersey文件夹的目录下面的所有文件到项目的WEB-INF/ lib目录下。

\jaxrs-ri-2.17\jaxrs-ri\api

\jaxrs-ri-2.17\jaxrs-ri\ext

\jaxrs-ri-2.17\jaxrs-ri\lib

现在，右键点击你的项目名称用户管理，然后按照下面选项中的上下文菜单: Build Path -> Configure Build Path 显示Java构建路径窗口。

现在，使用添加JAR文件可用按钮下的库选项卡，添加JAR文件到WEB-INF/lib目录下。

第3步 - 创建源文件：

现在，让我们在UserManagement 项目中创建实际的源文件。首先，我们需要创建一个名为包 com.yiibai. 要做到这一点，右键单击src在包资源管理部分并按照选项： New -> Package.

下一步，我们将创建 User.java, UserDao.java, 和 UserService.java 文件在 com.yiibai 包下.

File - 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;
   }
}

File - 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;
   }
}

File - UserService.java

package com.yiibai;

import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/UserService")
public class UserService {

   UserDao userDao = new UserDao();

   @GET
   @Path("/users")
   @Produces(MediaType.APPLICATION_XML)
   public List<User> getUsers(){
      return userDao.getAllUsers();
   }
}

有以下两个要点需要注意下面的主程序，UserService.java:

第一步是指定用于使用@Path注释到UserService的Web服务的路径。

第二个步骤是，以指定用于使用@Path注释到UserService的方法的特定web服务方法的路径。

第4步 - 创建web.xml配置文件：

需要创建一个Web XML配置文件，该文件是一个XML文件，用于指定Jersey框架的servlet应用。

File - web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   id="WebApp_ID" version="3.0">
   <display-name>User Management</display-name>
   <servlet>
      <servlet-name>Jersey RESTful Application</servlet-name>
      <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
         <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.yiibai</param-value>
         </init-param>
      </servlet>
   <servlet-mapping>
   <servlet-name>Jersey RESTful Application</servlet-name>
      <url-pattern>/rest/*</url-pattern>
   </servlet-mapping>
</web-app>

第5步 - 部署程序

一旦你使用创建源和Web配置文件完成，这一步是准备好编译和运行程序。要做到这一点，使用Eclipse，导出您的应用程序为war文件，并部署在Tomcat中。 要使用eclipse创建WAR文件，按照选项 File -> export -> Web > War File 最后选择项目UserManagement和目标文件夹。 要在Tomcat部署WAR文件，将用户Management.war在Tomcat的安装目录 > webapps 目录并启动Tomcat。

第6步 - 运行程序

我们使用Postman，一个Chrome扩展来测试Web服务。

提出一个请求到UserManagement，让所有的用户列表。http://localhost:8080/UserManagement/rest/UserService/users POSTMAN使用GET请求，看看下面的结果。

恭喜你，已经创建了第一个基于REST的应用成功。此外，让我们开始做一些更有趣事情在接下来的几章。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Web Services示例程序

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数据库和工具。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful资源

RESTful Web服务消息 - RESTful教程™

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。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Web服务消息

RESTful Web服务地址 - RESTful教程™

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

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的例子来获取的用户。

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

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

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

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Web服务地址

RESTful Web Services方法 - RESTful教程™

正如我们讨论至今认为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);
            return 1;
         }
      }
      return 0;
   }

   private void saveUserList(List<User> userList){
      try {
         File file = new File("Users.dat");
         FileOutputStream fos;

         fos = new FileOutputStream(file);

         ObjectOutputStream oos = new ObjectOutputStream(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)
   public String 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.
   private void testAddUser(){
      Form form = new Form();
      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.
   private void 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://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Web Services方法

RESTful Web服务无状态 - RESTful教程™

按照REST架构，一个RESTful Web服务不应该继续服务器的客户端的状态。这种限制被称为无状态。它负责客户以它的上下文传递给服务器，然后服务器可以存储这样的上下文，以处理客户端的进一步请求。例如，通过会话服务器维护标识由客户端传递会话标识符。

RESTful Web服务应遵守此限制。我们已经看到了REST Web服务 - 方法教程，该Web服务方法不存储它们从调用的客户端的任何信息。

考虑以下网址：

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

如果您使用的浏览器，使用基于Java的客户端或使用postman，那么输入上面的网址，结果永远是用户XML ID为1，因为服务器没有存储有关客户的任何信息。

<user>
<id>1</id>
<name>mahesh</name>
<profession>1</profession>
</user>

无状态的优点

以下是无状态的RESTful web服务的好处

Web服务可以独立对待每一个方法的请求。

Web服务不需要维护客户端之前的交互。它简化了应用程序的设计。

由于HTTP本身是一个无状态协议，RESTful Web服务无缝地与HTTP协议的工作。

无状态的缺点

以下是无状态的RESTful web服务的缺点

Web服务需要得到每个请求的额外信息，然后解释得到的情况下客户端交互客户端的状态都被照应。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Web服务无状态

RESTful Web Services缓存 - RESTful教程™

缓存是指存储服务器响应客户端本身，使客户端无须做出了对同样的资源服务器的请求连连。服务器的响应有关于缓存是如何做到使客户端缓存的响应一段时间或永远捕捉服务器响应信息。

以下是其中一个服务器响应可以具有以配置客户端的缓存的报头：

S.N. | 消息头和说明
1 | Date 日期和创建时的资源的时间。
2 | Last Modified 资源的日期和时间，它的最后修订。
3 | Cache-Control 主要头控制缓存。
4 | Expires 到期日和缓存时间
5 | Age 在几秒钟时间，从资源服务器获取时。

Cache-Control头

以下是Cache-Control头的细节

S. N. | 指令和说明
1 | Public 指示资源是可缓存任何组件。
2 | Private 指示资源是可缓存只有客户端和服务器，无中介可以缓存资源。
3 | no-cache/no-store 表示资源是不可缓存
4 | max-age 表示缓存有效期为max-age以秒为单位。在此之后，客户端必须使另一个请求。
5 | must-revalidate 指示服务器来验证资源，如果最大到期时间已经过去了。

最佳实践

始终保持静态内容，如图像，CSS，JavaScript的缓存，以2〜3天有效期。

不要让过期日期太长。

动态内容应只能缓存几个小时。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Web Services缓存

RESTful Web服务安全 - RESTful教程™

正如RESTfulWeb服务以HTTP URL的路径工作，所以这是非常重要的，在相同的方式维护一个RESTful Web服务的网站是安全的。以下是在设计一个RESTful Web服务应遵循的最佳实践。

验证 - 验证服务器上的所有输入。防止SQL或NoSQL注入攻击你的服务器。

基于会话的认证 - 使用基于会话的认证，每当一个请求到Web服务的方法来验证用户的身份。

URL没有敏感数据 - 千万不要使用用户名，密码或会话令牌的URL，这些值应通过POST方法传递给Web服务。

方法执行限制 - 允许限制使用像GET，POST，DELETE等方法。 GET方法不应该用于删除数据。

验证格式错误 XML/JSON - 检查以及表单输入传递到Web服务方法。

抛出通用错误信息 - Web服务方法应使用HTTP错误信息像403，显示禁止访问等。

HTTP 代码:

S.N. | HTTP 代码 & 描述
1 | 200 正确/正常, 显示成功。
2 | 201 创建，当使用POST或PUT请求成功创建了资源。返回链接使用位置标头新创建的资源。
3 | 204 无内容, 当响应主体是空的，例如，一个DELETE请求。
4 | 304 不修改, 用于减少以防条件GET请求的网络带宽的使用。响应主体应该是空的。头应该有日期，位置等。
5 | 400 错误的请求, 状态表示无效输入，例如提供验证错误，数据丢失。
6 | 401 未经授权, 指出用户正在使用无效或错误的身份验证令牌。
7 | 403 被禁止, 指出用户没有访问方法的使用，例如，删除权限没有管理员权限。
8 | 404 未找到, 状态表示这个方法不可用。
9 | 409 冲突, 执行方法，例如，添加重复条目状态的冲突的情况。
10 | 500 内部服务器错误,状态该服务器已经在执行方法抛出了一些异常。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Web服务安全

RESTful Services Java (JAX-RS) - RESTful教程™

JAX-RS代表RESTful Web服务的Java API。JAX-RS是一款基于JAVA的编程语言和API规范，为创建基于RESTful Web服务提供支持。它的2.0版本发布于2013年5月24日。JAX-RS大量使用从Java SE5注释可用来简化基于Java Web服务创建和部署开发。 它还提供支持创建客户端RESTful Web服务。

规范

下面是通常用于注解映射的资源作为Web服务的资源。

S.N. | 注解 & 描述
1 | @Path 资源类/方法的相对路径。
2 | @GET HTTP GET请求，用于获取资源。
3 | @PUT HTTP PUT请求，用于建立资源。
4 | @POST HTTP POST请求，用于创建/更新资源。
5 | @DELETE HTTP DELETE请求，用于删除的资源。
6 | @HEAD HTTP HEAD请求，用来获取方法可用状态。
7 | @Produces 状态通过Web服务产生的HTTP响应，例如APPLICATION/XML, TEXT/HTML, APPLICATION/JSON等。
8 | @Consumes 状态的HTTP请求类型，例如 application/x-www-form-urlencoded 接受POST请求的过程中HTTP主体表单数据。
9 | @PathParam 结合传递到方法，在路径中的值的参数。
10 | @QueryParam 结合传递给方法的路径中的查询参数的参数。
11 | @MatrixParam 结合传递给方法的路径中的HTTP矩阵参数的参数。
12 | @HeaderParam 结合传递到方法到HTTP头中的参数。
13 | @CookieParam 结合传递给方法一个Cookie参数。
14 | @FormParam 结合传递到方法的一种形式值的参数。
15 | @DefaultValue 分配一个默认值，以传递一个参数给方法。
16 | @Context 上下文中资源，例如HTTP请求的上下文。

本站代码下载：http://www.yiibai.com/siteinfo/download.html

本文属作者原创，转载请注明出处：易百教程 » RESTful Services Java (JAX-RS)