RESTfulWebサービス-クイックガイド

RESTアーキテクチャとは何ですか?

RESTは、REpresentational StateTransferの略です。RESTはWeb標準ベースのアーキテクチャであり、HTTPプロトコルを使用します。これは、すべてのコンポーネントがリソースであり、HTTP標準メソッドを使用して共通のインターフェースによってリソースにアクセスされるリソースを中心に展開されます。RESTは、2000年にロイフィールディングによって最初に導入されました。

RESTアーキテクチャでは、RESTサーバーは単にリソースへのアクセスを提供し、RESTクライアントはリソースにアクセスして変更します。ここで、各リソースはURI /グローバルIDによって識別されます。RESTはさまざまな表現を使用して、テキスト、JSON、XMLなどのリソースを表現します。JSONが最も人気があります。

HTTPメソッド

以下の4つのHTTPメソッドは、RESTベースのアーキテクチャで一般的に使用されます。

  • GET −リソースへの読み取り専用アクセスを提供します。

  • POST −新しいリソースを作成するために使用されます。

  • DELETE −リソースを削除するために使用されます。

  • PUT −既存のリソースを更新するか、新しいリソースを作成するために使用されます。

RESTFulWebサービスの概要

Webサービスは、アプリケーションまたはシステム間でデータを交換するために使用されるオープンなプロトコルと標準のコレクションです。さまざまなプログラミング言語で記述され、さまざまなプラットフォームで実行されるソフトウェアアプリケーションは、Webサービスを使用して、単一のコンピューターでのプロセス間通信と同様の方法で、インターネットなどのコンピューターネットワークを介してデータを交換できます。この相互運用性(たとえば、JavaとPythonの間、またはWindowsとLinuxアプリケーションの間)は、オープンスタンダードの使用によるものです。

RESTアーキテクチャに基づくWebサービスは、RESTfulWebサービスとして知られています。これらのWebサービスは、HTTPメソッドを使用してRESTアーキテクチャの概念を実装します。RESTful Webサービスは通常、URI、サービスのURI、Uniform Resource Identifierを定義し、JSONやHTTPメソッドのセットなどのリソース表現を提供します。

RESTFulWebサービスの作成

次の章では、次の機能を備えたユーザー管理などのWebサービスを作成します。

シニア番号 URI HTTPメソッド POST本文 結果
1 / UserService / users 取得する空の すべてのユーザーのリストを表示します。
2 / UserService / addUser 役職 JSON文字列 新しいユーザーの詳細を追加します。
3 / UserService / getUser /:id 取得する空の ユーザーの詳細を表示します。

このチュートリアルでは、作業を開始するための開発環境を準備する方法について説明します。 Jersey FrameworkRESTfulWebサービスを作成します。ジャージーフレームワークは実装しますJAX-RS 2.0API。RESTfulWebサービスを作成するための標準仕様です。このチュートリアルでは、セットアップ方法も説明しますJDK, Tomcat そして Eclipse ジャージーフレームワークをセットアップする前に、マシン上で。

Java Development Kit(JDK)のセットアップ

-あなたは、OracleのJavaサイトからSDKの最新バージョンをダウンロードすることができたJava SEダウンロード。ダウンロードしたファイルにJDKのインストール手順が記載されています。所定の手順に従って、セットアップをインストールおよび構成します。最後に設定しますPATH そして JAVA_HOME を含むディレクトリを参照する環境変数 Java そして Javac、通常はそれぞれjava_install_dir / binと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シェルを使用している場合、.cshrcファイルに次のように記述します。

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

または、Borland JBuilder、Eclipse、IntelliJ IDEA、Sun ONE Studioなどの統合開発環境(IDE)を使用している場合は、簡単なプログラムをコンパイルして実行し、IDEがJavaのインストール場所を認識していることを確認します。それ以外の場合は、所定のドキュメントに従って適切なセットアップを行います。 IDEの。

EclipseIDEのセットアップ

このチュートリアルのすべての例は、EclipseIDEを使用して作成されています。したがって、最新バージョンのEclipseをマシンにインストールすることをお勧めします。

Eclipse IDEをインストールするには、から最新のEclipseバイナリをダウンロードします。 https://www.eclipse.org/downloads/。インストールをダウンロードしたら、バイナリディストリビューションを便利な場所に解凍します。たとえば、WindowsのC:\ eclipse、またはLinux / Unixの/ usr / local / eclipseで、最後にPATH変数を適切に設定します。

Eclipseは、Windowsマシンで次のコマンドを実行することで起動できます。または、eclipse.exeをダブルクリックするだけです。

%C:\eclipse\eclipse.exe

Eclipseは、Unix(Solaris、Linuxなど)マシンで次のコマンドを実行することで起動できます。

$/usr/local/eclipse/eclipse

起動が成功した後、すべてが正常であれば、画面に次の結果が表示されます-

ジャージーフレームワークライブラリのセットアップ

これで、すべてが正常であれば、Jerseyフレームワークのセットアップに進むことができます。以下は、フレームワークをダウンロードしてマシンにインストールするためのいくつかの簡単な手順です。

  • ジャージーをWindowsにインストールするかUnixにインストールするかを選択し、次の手順に進んでWindows用の.zipファイルをダウンロードしてから、Unix用の.tzファイルをダウンロードします。

  • 次のリンクからJerseyフレームワークバイナリの最新バージョンをダウンロードします– https://jersey.java.net/download.html。

  • このチュートリアルを書いている時点で、私はダウンロードしました jaxrs-ri-2.17.zip 私のWindowsマシンでは、ダウンロードしたファイルを解凍すると、次のスクリーンショットに示すように、E:\ jaxrs-ri-2.17 \ jaxrs-ri内のディレクトリ構造が表示されます。

すべてのJerseyライブラリはディレクトリにあります C:\jaxrs-ri-2.17\jaxrs-ri\lib と依存関係 C:\jaxrs-ri-2.17\jaxrs-ri\ext。このディレクトリにCLASSPATH変数を正しく設定してください。そうしないと、アプリケーションの実行中に問題が発生します。Eclipseを使用している場合、すべての設定はEclipseを介して行われるため、CLASSPATHを設定する必要はありません。

ApacheTomcatをセットアップする

Tomcatの最新バージョンはからダウンロードできます。 https://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

または

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

Tomcatは、Unix(Solaris、Linuxなど)マシンで次のコマンドを実行することで起動できます。

$CATALINA_HOME/bin/startup.sh

または

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

正常に起動すると、Tomcatに含まれているデフォルトのWebアプリケーションが次のURLにアクセスして利用できるようになります。 http://localhost:8080/。すべてが正常であれば、次の結果が表示されます-

Tomcatの構成と実行の詳細については、このページに含まれているドキュメントを参照してください。この情報は、TomcatのWebサイトにもあります-https://tomcat.apache.org.

Windowsマシンで次のコマンドを実行すると、Tomcatを停止できます-

%CATALINA_HOME%\bin\shutdown

または

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

Unix(Solaris、Linuxなど)のマシンで次のコマンドを実行すると、Tomcatを停止できます。

$CATALINA_HOME/bin/shutdown.sh

または

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

この最後のステップが完了すると、次の章で説明する最初のジャージーの例に進む準備が整います。

JerseyFrameworkを使用して実際のRESTfulWebサービスの作成を始めましょう。Jersey Frameworkを使用して最初の例を書き始める前に、RESTful Webサービス-環境設定の章で説明されているように、Jersey環境が正しく設定されていることを確認する必要があります。ここでは、EclipseIDEの実用的な知識があることも前提としています。

それでは、ユーザーのリストを表示するWebサービスメソッドを公開する簡単なJerseyアプリケーションの作成に進みましょう。

Javaプロジェクトの作成

最初のステップは、EclipseIDEを使用して動的Webプロジェクトを作成することです。オプションに従ってくださいFile → New → Project 最後に Dynamic Web Projectウィザードリストからのウィザード。プロジェクトに次の名前を付けますUserManagement 次のスクリーンショットに示すように、ウィザードウィンドウを使用します-

プロジェクトが正常に作成されると、次のコンテンツが作成されます。 Project Explorer

必要なライブラリの追加

2番目のステップとして、Jersey Frameworkとその依存関係(ライブラリ)をプロジェクトに追加しましょう。プロジェクトのWEB-INF / libディレクトリにあるダウンロードジャージzipフォルダの次のディレクトリからすべてのjarファイルをコピーします。

  • \jaxrs-ri-2.17\jaxrs-ri\api
  • \jaxrs-ri-2.17\jaxrs-ri\ext
  • \jaxrs-ri-2.17\jaxrs-ri\lib

次に、プロジェクト名を右クリックします UserManagement 次に、コンテキストメニューで使用可能なオプションに従います- Build Path → Configure Build Path Javaビルドパスウィンドウを表示します。

今すぐ使用 Add JARs 下で利用可能なボタン Libraries タブをクリックして、WEBINF / libディレクトリに存在するJARを追加します。

ソースファイルの作成

それでは、実際のソースファイルを UserManagement事業。まず、というパッケージを作成する必要がありますcom.tutorialspoint。これを行うには、パッケージエクスプローラーセクションのsrcを右クリックし、オプション-に従います。New → Package

次に作成します UserService.java, User.java,UserDao.java com.tutorialspointパッケージの下のファイル。

User.java

package com.tutorialspoint;  

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

UserDao.java

package com.tutorialspoint;  

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; 
   } 
   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.tutorialspoint;  

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(); 
   }  
}

メインプログラムについて注意すべき2つの重要なポイントがあります。

UserService.java

  • 最初のステップは、UserServiceへの@Pathアノテーションを使用してWebサービスのパスを指定することです。

  • 2番目のステップは、UserServiceのメソッドへの@Pathアノテーションを使用して、特定のWebサービスメソッドのパスを指定することです。

Web.xml構成ファイルの作成

XMLファイルであり、アプリケーションのJerseyフレームワークサーブレットを指定するために使用されるWebxml構成ファイルを作成する必要があります。

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.tutorialspoint</param-value> 
      </init-param> 
   </servlet> 
   <servlet-mapping> 
      <servlet-name>Jersey RESTful Application</servlet-name> 
      <url-pattern>/rest/*</url-pattern> 
   </servlet-mapping>   
</web-app>

プログラムの展開

ソースおよびWeb構成ファイルの作成が完了したら、プログラムをコンパイルして実行するこのステップの準備が整います。これを行うには、Eclipseを使用して、アプリケーションをwarファイルとしてエクスポートし、同じものをTomcatにデプロイします。

Eclipseを使用してWARファイルを作成するには、オプションに従います File → export → Web → War File最後に、プロジェクトのUserManagementと宛先フォルダーを選択します。Tomcatにwarファイルをデプロイするには、UserManagement.warをTomcat Installation Directory → webapps directory Tomcatを起動します。

プログラムの実行

Chrome拡張機能であるPostmanを使用して、Webサービスをテストしています。

UserManagementにリクエストを送信して、すべてのユーザーのリストを取得します。http:// localhost:8080 / UserManagement / rest / UserService / usersをGETリクエストでPOSTMANに配置すると、次の結果が表示されます。

おめでとうございます。最初のRESTfulアプリケーションが正常に作成されました。

リソースとは何ですか?

RESTアーキテクチャは、すべてのコンテンツをリソースとして扱います。これらのリソースには、テキストファイル、HTMLページ、画像、ビデオ、または動的ビジネスデータがあります。RESTサーバーは単にリソースへのアクセスを提供し、RESTクライアントはリソースにアクセスして変更します。ここで、各リソースはURI /グローバルIDによって識別されます。RESTはさまざまな表現を使用して、テキスト、JSON、XMLのリソースを表します。リソースの最も一般的な表現はXMLとJSONです。

リソースの表現

RESTのリソースは、オブジェクト指向プログラミングの同様のオブジェクトであるか、データベースのエンティティのようなものです。リソースが識別されると、サーバーが上記の形式でリソースを送信し、クライアントが同じ形式を理解できるように、その表現は標準形式を使用して決定されます。

たとえば、RESTful Webサービス-最初のアプリケーションの章では、ユーザーは次のXML形式を使用して表されるリソースです-

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

同じリソースを次のようにJSON形式で表すことができます-

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

優れたリソース表現

RESTは、リソース表現の形式に制限を課しません。クライアントはJSON表現を要求できますが、別のクライアントはサーバーへの同じリソースのXML表現を要求する場合があります。クライアントが理解できる形式でリソースをクライアントに渡すのは、RESTサーバーの責任です。

以下は、RESTfulWebサービスでリソースの表現形式を設計する際に考慮すべきいくつかの重要なポイントです。

  • Understandability −サーバーとクライアントの両方が、リソースの表現形式を理解して利用できる必要があります。

  • Completeness−フォーマットはリソースを完全に表現できる必要があります。たとえば、リソースに別のリソースを含めることができます。フォーマットは、リソースの単純な構造と複雑な構造を表すことができる必要があります。

  • Linkablity −リソースは別のリソースへのリンクを持つことができ、フォーマットはそのような状況を処理できる必要があります。

ただし、現在、ほとんどのWebサービスは、XMLまたはJSON形式のいずれかを使用してリソースを表現しています。XMLおよびJSONデータを理解、解析、および変更するために利用できるライブラリとツールはたくさんあります。

RESTful Webサービスは、クライアントとサーバー間の通信媒体としてHTTPプロトコルを利用します。クライアントはHTTP要求の形式でメッセージを送信し、サーバーはHTTP応答の形式で応答します。この手法はメッセージングと呼ばれます。これらのメッセージには、メッセージデータとメタデータ、つまりメッセージ自体に関する情報が含まれています。HTTP1.1のHTTP要求メッセージとHTTP応答メッセージを見てみましょう。

HTTPリクエスト

HTTPリクエストには5つの主要な部分があります-

  • Verb − GET、POST、DELETE、PUTなどのHTTPメソッドを示します。

  • URI −サーバー上のリソースを識別するためのURI(Uniform Resource Identifier)。

  • HTTP Version−HTTPバージョンを示します。たとえば、HTTPv1.1です。

  • Request Header−HTTP要求メッセージのメタデータがキーと値のペアとして含まれています。たとえば、クライアント(またはブラウザ)の種類、クライアントでサポートされている形式、メッセージ本文の形式、キャッシュ設定などです。

  • Request Body −メッセージコンテンツまたはリソース表現。

HTTP応答

HTTP応答には4つの主要な部分があります-

  • Status/Response Code−要求されたリソースのサーバーステータスを示します。たとえば、404はリソースが見つからないことを意味し、200は応答に問題がないことを意味します。

  • HTTP Version−HTTPバージョンを示します。たとえば、HTTPv1.1です。

  • Response Header−HTTP応答メッセージのメタデータがキーと値のペアとして含まれています。たとえば、コンテンツの長さ、コンテンツタイプ、応答日、サーバータイプなどです。

  • Response Body −応答メッセージの内容またはリソース表現。

私たちが説明したようにRESTful Webサービス-まずアプリケーションの章、私たちはHTTPを入れてみましょう:// localhostを:GET要求にPOSTMANにおける8080 / UserManagement /残りは/ UserServiceの/ユーザー。Postmanの送信ボタンの近くにある[プレビュー]ボタンをクリックしてから[送信]ボタンをクリックすると、次の出力が表示される場合があります。

ここでは、ブラウザーがGET要求を送信し、応答本文をXMLとして受信したことがわかります。

アドレス指定とは、サーバー上にある1つまたは複数のリソースを見つけることです。これは、人の住所を見つけるのに似ています。

RESTアーキテクチャの各リソースは、そのURI(Uniform Resource Identifier)によって識別されます。URIは次の形式です-

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

URIの目的は、Webサービスをホストしているサーバー上のリソースを見つけることです。リクエストのもう1つの重要な属性は、リソースで実行される操作を識別するVERBです。たとえば、RESTful Webサービス-最初のアプリケーションの章では、URIはhttp://localhost:8080/UserManagement/rest/UserService/users 動詞はGETです。

標準URIの構築

URIを設計する際に考慮すべき重要な点は次のとおりです。

  • Use Plural Noun−複数形の名詞を使用してリソースを定義します。たとえば、ユーザーを使用してユーザーをリソースとして識別しました。

  • Avoid using spaces−長いリソース名を使用する場合は、アンダースコア(_)またはハイフン(-)を使用します。たとえば、authorized%20usersの代わりにauthorized_usersを使用します。

  • Use lowercase letters − URIでは大文字と小文字は区別されませんが、URLは小文字のみにすることをお勧めします。

  • Maintain Backward Compatibility− Webサービスはパブリックサービスであるため、一度パブリックにされたURIは常に利用可能である必要があります。URIが更新された場合は、HTTPステータスコード300を使用して、古いURIを新しいURIにリダイレクトします。

  • Use HTTP Verb−リソースの操作を行うには、常にGET、PUT、DELETEなどのHTTP動詞を使用します。URIで操作名を使用するのは適切ではありません。

以下は、ユーザーをフェッチするための不十分なURIの例です。

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

以下は、ユーザーをフェッチするための適切なURIの例です。

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

前の章で説明したように、RESTful Webサービスは多くのHTTP動詞を使用して、指定されたリソースで実行される操作を決定します。次の表に、最も一般的に使用されるHTTP動詞の例を示します。

シニア番号 HTTPメソッド、URI、および操作

1

GET

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

ユーザーのリストを取得します。

(読み取り専用)

2

GET

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

ID1のユーザーを取得します

(読み取り専用)

3

PUT

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

ID2のユーザーを挿入します

(べき等)

4

POST

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

ID2でユーザーを更新します

(N / A)

5

DELETE

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

ID1のユーザーを削除します

(べき等)

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サービス-最初のアプリケーションの章で作成された例を更新して、CRUD(作成、読み取り、更新、削除)操作を実行できるWebサービスを作成しましょう。簡単にするために、ファイルI / Oを使用してデータベース操作を置き換えました。

更新しましょう User.java, UserDao.java そして UserService.java com.tutorialspointパッケージの下のファイル。

User.java

package com.tutorialspoint; 

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.tutorialspoint;  

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.tutorialspoint;  

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 File同じものをTomcatにデプロイします。Eclipseを使用してWARファイルを作成するには、次のパスに従います–File → export → Web → War File最後に、プロジェクトのUserManagementと宛先フォルダーを選択します。TomcatにWARファイルをデプロイするには、UserManagement.warをTomcat Installation Directory → webapps ディレクトリと開始Tomcat。

Webサービスのテスト

Jerseyは、WebサービスをテストするためのWebサービスクライアントを作成するためのAPIを提供します。サンプルテストクラスを作成しましたWebServiceTester.java 同じプロジェクトのcom.tutorialspointパッケージの下。

WebServiceTester.java

package com.tutorialspoint;  

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

RESTアーキテクチャに従って、RESTfulWebサービスはサーバー上でクライアントの状態を維持するべきではありません。この制限は無国籍と呼ばれます。コンテキストをサーバーに渡すのはクライアントの責任であり、サーバーはこのコンテキストを保存してクライアントの追加の要求を処理できます。たとえば、サーバーによって維持されるセッションは、クライアントから渡されるセッション識別子によって識別されます。

RESTful Webサービスは、この制限に従う必要があります。これは、RESTful Webサービス-メソッドの章で確認しました。Webサービスメソッドは、呼び出されたクライアントからの情報を格納していません。

Consider the following URL −

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

ブラウザ、Javaベースのクライアント、またはPostmanを使用して上記のURLにアクセスすると、サーバーはクライアントに関する情報を保存しないため、結果は常にIDが1のユーザーXMLになります。

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

無国籍の利点

以下は、RESTfulWebサービスにおけるステートレスの利点です-

  • Webサービスは、各メソッド要求を個別に処理できます。

  • Webサービスは、クライアントの以前の対話を維持する必要はありません。これにより、アプリケーションの設計が簡素化されます。

  • HTTP自体がステートレスプロトコルであるため、RESTfulWebサービスはHTTPプロトコルとシームレスに連携します。

無国籍のデメリット

以下は、RESTfulWebサービスにおけるステートレスの欠点です。

  • Webサービスは、各要求で追加情報を取得し、クライアントとの対話が処理される場合に備えて、クライアントの状態を取得するために解釈する必要があります。

キャッシングとは、サーバーの応答をクライアント自体に保存することを指します。これにより、クライアントは同じリソースに対してサーバー要求を何度も行う必要がなくなります。サーバーの応答には、キャッシュの実行方法に関する情報が含まれている必要があります。これにより、クライアントは一定期間応答をキャッシュするか、サーバーの応答をキャッシュしません。

以下は、クライアントのキャッシュを構成するためにサーバーの応答が持つことができるヘッダーです。

シニア番号 ヘッダーと説明

1

Date

リソースが作成された日時。

2

Last Modified

リソースが最後に変更された日時。

3

Cache-Control

キャッシュを制御するためのプライマリヘッダー。

4

Expires

キャッシュの有効期限と時刻。

5

Age

サーバーからリソースがフェッチされてからの秒単位の期間。

キャッシュ制御ヘッダー

以下は、Cache-Controlヘッダーの詳細です-

シニア番号 指令と説明

1

Public

リソースが任意のコンポーネントによってキャッシュ可能であることを示します。

2

Private

リソースがクライアントとサーバーによってのみキャッシュ可能であり、仲介者がリソースをキャッシュできないことを示します。

3

no-cache/no-store

リソースがキャッシュ可能ではないことを示します。

4

max-age

キャッシュがmax-age(秒単位)まで有効であることを示します。この後、クライアントは別のリクエストを行う必要があります。

5

must-revalidate

max-ageが経過した場合にリソースを再検証するためのサーバーへの指示。

ベストプラクティス

  • 画像、CSS、JavaScriptなどの静的コンテンツは常にキャッシュ可能で、有効期限は2〜3日です。

  • 有効期限を高くしすぎないでください。

  • 動的コンテンツは、数時間だけキャッシュする必要があります。

RESTfulWebサービスはHTTPURLパスと連携するため、Webサイトを保護するのと同じ方法でRESTfulWebサービスを保護することが非常に重要です。

以下は、RESTfulWebサービスを設計する際に従うべきベストプラクティスです-

  • Validation−サーバー上のすべての入力を検証します。SQLまたはNoSQLインジェクション攻撃からサーバーを保護します。

  • Session Based Authentication −セッションベースの認証を使用して、Webサービスメソッドに対して要求が行われるたびにユーザーを認証します。

  • No Sensitive Data in the URL − URLでユーザー名、パスワード、またはセッショントークンを使用しないでください。これらの値は、POSTメソッドを介してWebサービスに渡す必要があります。

  • Restriction on Method Execution− GET、POST、DELETEメソッドなどのメソッドの使用を制限することを許可します。GETメソッドはデータを削除できないはずです。

  • Validate Malformed XML/JSON −Webサービスメソッドに渡された整形式の入力を確認します。

  • Throw generic Error Messages − Webサービスメソッドは、403などのHTTPエラーメッセージを使用して、アクセス禁止などを表示する必要があります。

HTTPコード

シニア番号 HTTPコードと説明

1

200

OK −成功を示しています。

2

201

CREATED−POSTまたはPUTリクエストを使用してリソースが正常に作成されたとき。locationヘッダーを使用して、新しく作成されたリソースへのリンクを返します。

3

204

NO CONTENT−応答本文が空の場合。たとえば、DELETEリクエスト。

4

304

NOT MODIFIED−条件付きGET要求の場合にネットワーク帯域幅の使用量を減らすために使用されます。応答本文は空にする必要があります。ヘッダーには、日付、場所などを含める必要があります。

5

400

BAD REQUEST−無効な入力が提供されたことを示します。たとえば、検証エラー、データの欠落。

6

401

UNAUTHORIZED −ユーザーが無効または間違った認証トークンを使用していることを示します。

7

403

FORBIDDEN−ユーザーが使用されているメソッドにアクセスできないことを示します。たとえば、管理者権限なしでアクセスを削除します。

8

404

NOT FOUND −メソッドが使用できないことを示します。

9

409

CONFLICT−メソッドの実行中に競合状況を示します。たとえば、重複するエントリを追加します。

10

500

INTERNAL SERVER ERROR −メソッドの実行中にサーバーが何らかの例外をスローしたことを示します。

JAX-RSRESTfulWebサービス用のJAVAAPIの略です。JAX-RSは、作成されたRESTfulWebサービスのサポートを提供するJAVAベースのプログラミング言語APIおよび仕様です。その2.0バージョンは2013年5月24日にリリースされました。JAX-RSはJavaSE 5から入手可能なアノテーションを使用して、JAVAベースのWebサービスの作成とデプロイメントの開発を簡素化します。また、RESTfulWebサービスのクライアントを作成するためのサポートも提供します。

仕様

以下は、リソースをWebサービスリソースとしてマップするために最も一般的に使用されるアノテーションです。

シニア番号 注釈と説明

1

@Path

リソースクラス/メソッドの相対パス。

2

@GET

リソースをフェッチするために使用されるHTTPGetリクエスト。

3

@PUT

リソースの更新に使用されるHTTPPUTリクエスト。

4

@POST

新しいリソースを作成するために使用されるHTTPPOSTリクエスト。

5

@DELETE

リソースを削除するために使用されるHTTPDELETEリクエスト。

6

@HEAD

メソッドの可用性のステータスを取得するために使用されるHTTPHEADリクエスト。

7

@Produces

Webサービスによって生成されたHTTP応答を示します。たとえば、APPLICATION / XML、TEXT / HTML、APPLICATION / JSONなどです。

8

@Consumes

HTTPリクエストタイプを示します。たとえば、アプリケーション/ x-www-formurlencodedは、POSTリクエスト中にHTTPボディのフォームデータを受け入れます。

9

@PathParam

メソッドに渡されたパラメーターをパスの値にバインドします。

10

@QueryParam

メソッドに渡されたパラメーターをパス内のクエリパラメーターにバインドします。

11

@MatrixParam

メソッドに渡されたパラメーターをパス内のHTTPマトリックスパラメーターにバインドします。

12

@HeaderParam

メソッドに渡されたパラメーターをHTTPヘッダーにバインドします。

13

@CookieParam

メソッドに渡されたパラメーターをCookieにバインドします。

14

@FormParam

メソッドに渡されたパラメーターをフォーム値にバインドします。

15

@DefaultValue

メソッドに渡されるパラメーターにデフォルト値を割り当てます。

16

@Context

リソースのコンテキスト。たとえば、コンテキストとしてのHTTPRequest。

Note−RESTfulWebサービス-最初のアプリケーションとRESTfulWebサービス-メソッドの章で、OracleによるJAX-RS2.0のリファレンス実装であるJerseyを使用しました。