Restful-quick-guide

提供:Dev Guides
移動先:案内検索

RESTful Webサービス-はじめに

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

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

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

HTTPメソッド

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

  • GET -リソースへの読み取り専用アクセスを提供します。
  • POST -新しいリソースを作成するために使用されます。
  • DELETE -リソースを削除するために使用されます。
  • PUT -既存のリソースの更新または新しいリソースの作成に使用されます。

RESTFul Webサービスの概要

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

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

RESTFul Webサービスの作成

次の章では、次の機能を持つユーザー管理と言うWebサービスを作成します-

Sr.No. URI HTTP Method POST body Result
1 /UserService/users GET empty Show list of all the users.
2 /UserService/addUser POST JSON String Add details of new user.
3 /UserService/getUser/:id GET empty Show details of a user.

RESTful Webサービス-環境設定

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

Java開発キット(JDK)のセットアップ

最新バージョンのSDKは、OracleのJavaサイト-https://www.oracle.com/technetwork/java/javase/downloads/indexl[Java SE Downloads]からダウンロードできます。 ダウンロードしたファイルに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の。

Eclipse IDEのセットアップ

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

Eclipse IDEをインストールするには、https://www.eclipse.org/downloads/から最新のEclipseバイナリをダウンロードします。 インストールをダウンロードしたら、バイナリ配布物を便利な場所に解凍します。 たとえば、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

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

Eclipseホームページ

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

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

  • JerseyをWindowsにインストールするか、Unixにインストールするかを選択してから、次の手順に進み、Windows用の.zipファイルをダウンロードしてから、Unix用の.tzファイルをダウンロードします。
  • 次のリンクから最新バージョンのJerseyフレームワークバイナリをダウンロードしてください– [[1]]
  • このチュートリアルを書いている時点で、Windowsマシンに jaxrs-ri-2.17.zip をダウンロードしました。ダウンロードしたファイルを解凍すると、E:\ jaxrs-ri-2.17 \ jaxrs-ri内のディレクトリ構造が得られます。次のスクリーンショットに示すように。

Jaxrsディレクトリ

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

Apache Tomcatのセットアップ

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

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

Tomcatの設定と実行に関する詳細情報は、このページに含まれるドキュメントに記載されています。 この情報は、Tomcat Webサイト(https://tomcat.apache.org [[[2]]])にも記載されています。

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の例に進む準備ができています。

RESTful Webサービス-最初のアプリケーション

Jerseyフレームワークを使用して、実際のRESTful Webサービスの作成を始めましょう。 Jerseyフレームワークを使用して最初の例を書き始める前に、リンク:/restful/restful_environment [RESTful Web Services-Environment Setup]の章で説明されているように、Jersey環境が適切にセットアップされていることを確認する必要があります。 ここでは、Eclipse IDEの実用的な知識があることも前提としています。

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

Javaプロジェクトの作成

最初のステップは、Eclipse IDEを使用して動的Webプロジェクトを作成することです。 [ファイル]→[新規]→[プロジェクト]オプションを選択し、最後にウィザードリストから[動的Webプロジェクト]ウィザードを選択します。 次のスクリーンショットに示すように、ウィザードウィンドウを使用して、プロジェクトに UserManagement という名前を付けます-

ダイナミックWebプロジェクトウィザード

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

ユーザー管理ディレクトリ

必要なライブラリを追加する

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

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

ここで、プロジェクト名 UserManagement を右クリックし、コンテキストメニューで利用可能なオプション-*ビルドパス→ビルドパスの設定*に従って、Javaビルドパスウィンドウを表示します。

ここで、 Libraries タブにある Add JARs ボタンを使用して、WEBINF/libディレクトリにあるJARを追加します。

ソースファイルの作成

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

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

*User.java*
package com.finddevguides;

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

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

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フレームワークサーブレットを指定するために使用されるWeb xml構成ファイルを作成する必要があります。

*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.finddevguides</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インストールディレクトリ→webappsディレクトリ*に配置し、Tomcatを起動します。

プログラムを実行する

Chromeの拡張機能であるhttps://www.getpostman.com/[Postman]を使用して、Webサービスをテストしています。

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

RESTful API、すべてのユーザー

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

RESTful Webサービス-リソース

リソースとは何ですか?

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

リソースの表現

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

たとえば、リンク:/restful/restful_first_application [RESTful Web Services-First Application]の章では、ユーザーは次の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サービス-メッセージ

RESTful Webサービスは、クライアントとサーバー間の通信の媒体としてHTTPプロトコルを使用します。 クライアントはHTTPリクエストの形式でメッセージを送信し、サーバーはHTTPレスポンスの形式で応答します。 この手法は、メッセージングと呼ばれます。 これらのメッセージには、メッセージデータとメタデータが含まれます。 メッセージ自体に関する情報。 HTTP 1.1のHTTPリクエストおよびHTTPレスポンスメッセージを見てみましょう。

HTTPリクエスト

HTTPリクエスト

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

  • 動詞-GET、POST、DELETE、PUTなどのHTTPメソッドを示します。
  • URI -サーバー上のリソースを識別するUniform Resource Identifier(URI)。
  • * HTTPバージョン*-HTTPバージョンを示します。 たとえば、HTTP v1.1。
  • リクエストヘッダー-キーと値のペアとしてHTTPリクエストメッセージのメタデータが含まれています。 たとえば、クライアント(またはブラウザー)の種類、クライアントでサポートされている形式、メッセージ本文の形式、キャッシュ設定など。
  • リクエストボディ-メッセージコンテンツまたはリソース表現。

HTTP応答

HTTP応答

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

  • ステータス/レスポンスコード-要求されたリソースのサーバーステータスを示します。 たとえば、404はリソースが見つからないことを意味し、200は応答が正常であることを意味します。
  • * HTTPバージョン*-HTTPバージョンを示します。 たとえば、HTTP v1.1。
  • Response Header -HTTP応答メッセージのメタデータがキーと値のペアとして含まれています。 たとえば、コンテンツの長さ、コンテンツタイプ、応答日、サーバータイプなど。
  • 応答本文-応答メッセージのコンテンツまたはリソース表現。

リンク:/restful/restful_first_application [RESTful Webサービス-最初のアプリケーションの章]で説明したように、GETリクエストを使用してhttp://localhost:8080/UserManagement/rest/UserService/usersをPOSTMANに配置します。 Postmanの送信ボタンの近くにある[プレビュー]ボタンをクリックしてから[送信]ボタンをクリックすると、次の出力が表示される場合があります。

HTTPリクエスト/レスポンス

ご覧のとおり、ブラウザはGETリクエストを送信し、XMLとして応答本文を受信しました。

RESTful Webサービス-アドレス指定

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

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

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

URIの目的は、Webサービスをホストするサーバー上のリソースを見つけることです。 リクエストの別の重要な属性は、リソースで実行される操作を識別するVERBです。 たとえば、link:/restful/restful_first_application [RESTful Web Services-First Application]の章では、URIは http://localhost:8080/UserManagement/rest/UserService/users で、VERBはGETです。

標準URIの構築

以下は、URIを設計する際に考慮すべき重要な点です-

  • 複数名詞を使用-複数名詞を使用してリソースを定義します。 たとえば、ユーザーをリソースとして識別するためにユーザーを使用しました。
  • スペースの使用を避ける-長いリソース名を使用するときは、アンダースコア(_)またはハイフン(-)を使用します。 たとえば、authorized%20usersの代わりにauthorized_usersを使用します。
  • 小文字を使用-URIは大文字と小文字を区別しませんが、小文字のみでURLを保持することをお勧めします。
  • 下位互換性の維持-Webサービスはパブリックサービスであるため、一度公開されたURIは常に利用可能でなければなりません。 URIが更新された場合、HTTPステータスコード300を使用して古いURIを新しいURIにリダイレクトします。
  • * HTTP Verbを使用する-GET、PUT、DELETEなどのHTTP Verbを常に使用して、リソースに対する操作を実行します。 URIで操作名を使用するのは良くありません。

以下は、ユーザーを取得するための貧弱なURIの例です。

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

以下は、ユーザーを取得するのに適したURIの例です。

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

RESTful Webサービス-メソッド

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

HTTP Method GET
URI http://localhost:8080/UserManagement/rest/UserService/users
Operation Get list of users
Operation Type Read Only
HTTP Method GET
URI http://localhost:8080/UserManagement/rest/UserService/users/1
Operation Get user of Id 1
Operation Type Read Only
HTTP Method POST
URI http://localhost:8080/UserManagement/rest/UserService/users/2
Operation Insert user with Id 2
Operation Type Non-Idempotent
HTTP Method PUT
URI http://localhost:8080/UserManagement/rest/UserService/users/2
Operation Update User with Id 2
Operation Type N/A
HTTP Method DELETE
URI http://localhost:8080/UserManagement/rest/UserService/users/1
Operation Delete User with Id 1
Operation Type Idempotent
HTTP Method OPTIONS
URI http://localhost:8080/UserManagement/rest/UserService/users
Operation List the supported operations in web service
Operation Type Read Only
HTTP Method HEAD
URI http://localhost:8080/UserManagement/rest/UserService/users
Operation Returns only HTTP Header, no Body
Operation Type Read Only

考慮すべき重要な点は次のとおりです。

  • GET操作は読み取り専用で安全です。
  • PUTおよびDELETE操作はi等です。これらの操作が何度呼び出されても、結果は常に同じです。
  • PUT操作とPOST操作はほぼ同じですが、PUT操作がi等で、POST操作が異なる結果を引き起こす可能性のある結果にのみ違いがあります。

link:/restful/restful_first_application [RESTful Web Services-First Application]チュートリアルで作成したサンプルを更新して、CRUD(作成、読み取り、更新、削除)操作を実行できるWebサービスを作成してみましょう。 簡単にするために、ファイル操作を使用してデータベース操作を置き換えました。

com.finddevguidesパッケージの下にある UserService.javaUser.javaUserDao.java ファイルを更新します。

User.java

package com.finddevguides;

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

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

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

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

   @PUT
   @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と宛先フォルダーを選択します。 Tomcatにwarファイルをデプロイするには、* Tomcatインストールディレクトリ*> webappsディレクトリにUserManagement.warを配置し、Tomcatを起動します。

Webサービスのテスト

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

WebServiceTester.java

package com.finddevguides;

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)
         .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: 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)
         .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: 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を使用してテスターを実行します。 ファイルを右クリックし、[として実行→ Javaアプリケーション]オプションに従います。 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

link:/cgi-bin/printpage.cgi [__印刷]

RESTful Webサービス-ステートレス

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

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

次のURLを考慮します-

[[3]]

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

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

ステートレスの利点

以下は、RESTful Webサービスのステートレス性の利点です-

  • Webサービスは、各メソッド要求を個別に処理できます。
  • Webサービスは、クライアントの以前の対話を維持する必要はありません。 アプリケーションの設計を簡素化します。
  • HTTPはそれ自体がステートレスプロトコルであるため、RESTful WebサービスはHTTPプロトコルとシームレスに連携します。

無国籍の短所

以下は、RESTful Webサービスのステートレス性の欠点です-

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

RESTful Webサービス-キャッシュ

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

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

Sr.No. Header & Description
1

Date

リソースが作成されたときの日付と時刻。

2

Last Modified

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

3

Cache-Control

キャッシングを制御するプライマリヘッダー。

4

Expires

キャッシュの有効期限。

5

Age

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

Cache-Controlヘッダー

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

Sr.No. Directive & Description
1

Public

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

2

Private

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

3

no-cache/no-store

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

4

max-age

キャッシュが最大有効期間(秒)まで有効であることを示します。 この後、クライアントは別の要求を行う必要があります。

5

must-revalidate

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

ベストプラクティス

  • 有効期限が2〜3日の画像、CSS、JavaScriptなどの静的コンテンツを常にキャッシュ可能にします。
  • 有効期限を高くしすぎないでください。
  • 動的コンテンツは、数時間だけキャッシュする必要があります。

Cache-Controlのベストプラクティス

RESTful Webサービス-セキュリティ

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

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

  • 検証-サーバー上のすべての入力を検証します。 サーバーをSQLまたはNoSQLインジェクション攻撃から保護します。
  • セッションベース認証-Webサービスメソッドにリクエストが行われるたびに、セッションベース認証を使用してユーザーを認証します。
  • * URLに機密データはありません*-URLでユーザー名、パスワード、またはセッショントークンを使用しないでください。これらの値はPOSTメソッドを介してWebサービスに渡す必要があります。
  • メソッド実行の制限-GET、POST、DELETEメソッドなどのメソッドの使用制限を許可します。 GETメソッドはデータを削除できません。
  • 不正な形式のXML/JSONの検証-Webサービスメソッドに渡された整形式の入力を確認します。
  • 一般的なエラーメッセージをスロー-Webサービスメソッドは、403などのHTTPエラーメッセージを使用してアクセス禁止などを表示する必要があります。

HTTPコード

Sr.No. HTTP Code & Description
1

200

  • OK* -成功を示します。
2

201

  • CREATED* -POSTまたはPUT要求を使用してリソースが正常に作成されたとき。 ロケーションヘッダーを使用して、新しく作成されたリソースへのリンクを返します。
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* -メソッドの実行中にサーバーが何らかの例外をスローしたことを示します。

RESTful Webサービス-Java(JAX-RS)

*JAX-RS* は、RESTful Webサービス用のJAVA APIの略です。 JAX-RSは、作成されたRESTful Webサービスのサポートを提供するJAVAベースのプログラミング言語APIおよび仕様です。 2.0バージョンは2013年5月24日にリリースされました。 JAX-RSは、Java SE 5から利用可能な注釈を使用して、JAVAベースのWebサービスの作成と展開の開発を簡素化します。 また、RESTful Webサービスのクライアントを作成するためのサポートも提供します。

仕様

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

Sr.No. Annotation & Description
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-formurlencodedは、POST要求中にHTTP本文のフォームデータを受け入れます。

9

@PathParam

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

10

@QueryParam

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

11

@MatrixParam

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

12

@HeaderParam

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

13

@CookieParam

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

14

@FormParam

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

15

@DefaultValue

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

16

@Context

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

注意-link:/restful/restful_first_application [RESTful Web Services-First Application]およびlink:/restful/restful_methods [RESTful Web Services-Methods]でOracleによるJAX-RS 2.0のリファレンス実装であるJerseyを使用しました章。 Restful-questions-answers