JavaでのRESTful Webサービスチュートリアル

JavaでのRestful Webサービスチュートリアルへようこそ。RESTは、REpresentational State Transferの頭字語です。RESTは、ネットワークを介してアクセス可能なアプリケーションを開発するためのアーキテクチャスタイルです。RESTアーキテクチャスタイルは、2000年にRoy Fieldingによって彼の博士論文で提唱されました。

Restful Webサービス

Restful Webサービスは、ステートレスなクライアントサーバーアーキテクチャであり、Webサービスはリソースであり、それらのURIによって識別できます。RESTクライアントアプリケーションは、HTTP GET/POSTメソッドを使用してRestful Webサービスを呼び出すことができます。RESTは使用する特定のプロトコルを指定しませんが、ほとんどの場合はHTTP/HTTPSを使用します。SOAP Webサービスと比較すると、これらは軽量であり、標準に従いません。リクエストとレスポンスには、XML、JSON、テキスト、または他の任意のデータ形式を使用できます。

Java RESTful WebサービスAPI

Java API for RESTful Webサービス(JAX-RS)は、REST Webサービスを作成するためのJava APIです。JAX-RSは、アノテーションを使用してWebサービスの開発と展開を簡素化します。JAX-RSはJDKの一部ですので、アノテーションを使用するためには何も追加する必要はありません。

Restful Web Servicesの注釈

重要なJAX-RSの注釈の一部は次のとおりです。

  • @Path:クラスやメソッドの相対パスを指定するために使用されます。Path注釈の値をスキャンすることで、ウェブサービスのURIを取得することができます。
  • @GET@PUT@POST@DELETE、および@HEAD:メソッドのHTTPリクエストタイプを指定するために使用されます。
  • @Produces@Consumes:リクエストとレスポンスのタイプを指定するために使用されます。
  • @PathParam:パスの値を解析してメソッドパラメータにバインドするために使用されます。

Restful Web ServicesとSOAP

  1. SOAPはプロトコルであり、RESTはアーキテクチャスタイルです。
  2. SOAPサーバーとクライアントアプリケーションは緊密に結合され、WSDL契約と結びついていますが、RESTウェブサービスとクライアントには契約はありません。
  3. 学習曲線はSOAPウェブサービスと比較してRESTの方が容易です。
  4. RESTウェブサービスのリクエストとレスポンスのタイプはXML、JSON、テキストなどがありますが、SOAPはXMLのみで動作します。
  5. JAX-RSは、RESTウェブサービスのためのJava APIであり、一方、JAX-WSはSOAPウェブサービスのためのJava APIです。

REST APIの実装

JAX-RS APIの主要な実装は2つあります。

  1. Jersey: Jerseyは、Sunが提供する参照実装です。JerseyをJAX-RSの実装として使用するためには、web.xmlでサーブレットを設定し、必要な依存関係を追加する必要があります。JAX-RS APIはJerseyの一部ではなく、JDKの一部ですので、アプリケーションに依存関係のJARファイルを追加する必要があります。
  2. RESTEasy: RESTEasyは、JAX-RSの実装を提供するJBossプロジェクトです。

JavaのRESTfulウェブサービスチュートリアル

では、JerseyとRESTEasyを使用して簡単にRestfulウェブサービスを作成する方法を見てみましょう。次のメソッドをHTTP経由で公開し、これらをテストするためにChromeのPostman拡張機能を使用します。

URI HTTP Method Description
/person/{id}/getDummy GET Returns a dummy person object
/person/add POST Adds a person
/person/{id}/delete GET Delete the person with ‘id’ in the URI
/person/getAll GET Get all persons
/person/{id}/get GET Get the person with ‘id’ in the URI

JerseyのRestfulウェブサービス

動的Webプロジェクトを作成し、それをMavenに変換してWebサービスプロジェクトの骨組みを取得します。下の画像は最終プロジェクトのプロジェクト構造を示しています。 pom.xmlファイルにあるJerseyの依存関係を見てみましょう。

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>JAXRS-Example</groupId>
  <artifactId>JAXRS-Example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <dependencies>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.19</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-servlet</artifactId>
            <version>1.19</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
            <version>1.19</version>
        </dependency>
  </dependencies>
  
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

jersey-clientの依存関係を追加する必要はありませんが、Jerseyを使用してREST Webサービスを呼び出すJavaプログラムを書いている場合は必要です。次に、Jerseyを設定してWebアプリケーションを作成する方法を学ぶためにデプロイ記述子を見てみましょう。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee https://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>JAXRS-Example</display-name>

<!-- Jersey Servlet configurations -->
    <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.journaldev</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
  <!-- Jersey Servlet configurations -->

</web-app>

これでJerseyをWebアプリケーションに組み込むために必要なすべてです。Javaコードでは、JAX-RSアノテーションを使用します。initパラメータcom.sun.jersey.config.property.packagesの値に注目して、Webサービスのリソースとメソッドをスキャンするパッケージを指定します。

RESTの例:モデルクラス

まず、アプリケーションデータ用のPersonと、クライアントシステムに応答を送信するためのResponseの2つのモデルビーンを作成します。XML応答を送信するため、ビーンには@XmlRootElementがアノテーションされている必要があります。したがって、このクラスが存在します。

package com.journaldev.jaxrs.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement (name="person")
public class Person {
	private String name;
	private int age;
	private int id;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
	
	@Override
	public String toString(){
		return id+"::"+name+"::"+age;
	}

}
package com.journaldev.jaxrs.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Response {

	private boolean status;
	private String message;

	public boolean isStatus() {
		return status;
	}

	public void setStatus(boolean status) {
		this.status = status;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

REST Webサービスチュートリアルサービス

URI構造に基づいて、以下はサービスインターフェースとその実装コードです。

package com.journaldev.jaxrs.service;

import com.journaldev.jaxrs.model.Person;
import com.journaldev.jaxrs.model.Response;

public interface PersonService {

	public Response addPerson(Person p);
	
	public Response deletePerson(int id);
	
	public Person getPerson(int id);
	
	public Person[] getAllPersons();

}
package com.journaldev.jaxrs.service;


import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.journaldev.jaxrs.model.Person;
import com.journaldev.jaxrs.model.Response;

@Path("/person")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public class PersonServiceImpl implements PersonService {

	private static Map<Integer,Person> persons = new HashMap<Integer,Person>();
	
	@Override
	@POST
    @Path("/add")
	public Response addPerson(Person p) {
		Response response = new Response();
		if(persons.get(p.getId()) != null){
			response.setStatus(false);
			response.setMessage("Person Already Exists");
			return response;
		}
		persons.put(p.getId(), p);
		response.setStatus(true);
		response.setMessage("Person created successfully");
		return response;
	}

	@Override
	@GET
    @Path("/{id}/delete")
	public Response deletePerson(@PathParam("id") int id) {
		Response response = new Response();
		if(persons.get(id) == null){
			response.setStatus(false);
			response.setMessage("Person Doesn't Exists");
			return response;
		}
		persons.remove(id);
		response.setStatus(true);
		response.setMessage("Person deleted successfully");
		return response;
	}

	@Override
	@GET
	@Path("/{id}/get")
	public Person getPerson(@PathParam("id") int id) {
		return persons.get(id);
	}
	
	@GET
	@Path("/{id}/getDummy")
	public Person getDummyPerson(@PathParam("id") int id) {
		Person p = new Person();
		p.setAge(99);
		p.setName("Dummy");
		p.setId(id);
		return p;
	}

	@Override
	@GET
	@Path("/getAll")
	public Person[] getAllPersons() {
		Set<Integer> ids = persons.keySet();
		Person[] p = new Person[ids.size()];
		int i=0;
		for(Integer id : ids){
			p[i] = persons.get(id);
			i++;
		}
		return p;
	}

}

ほとんどのコードは自己説明的ですが、JAX-RSの注釈@Path@PathParam@POST@GET@Consumes、および@Producesに慣れるために時間をかけてください。

Restful Webサービステスト

以上です。ウェブサービスは準備完了です。WARファイルとしてエクスポートし、Tomcatのwebappsディレクトリに配置するか、選択した他のコンテナにデプロイしてください。以下は、このウェブサービスに対してPostman Chrome拡張機能を使用して行われたテストの一部です。以下の画像に示すように、リクエストヘッダに「application/xml」というAcceptおよびContent-Typeの値を指定する必要があることに注意してください。

  • getDummy
  • 追加
  • 取得
  • 全て取得
  • 削除

これでJersey JAX-RS実装を使用したWebサービスの作成が完了です。ほとんどのコードはJAX-RSの注釈を使用しており、Jerseyはデプロイメント記述子と依存関係を介してプラグインされています。

RESTEasy RESTful Webサービスの例

Jerseyプロジェクトで開発されたすべてのビジネスロジックを使用しますが、同じプロジェクトに変更を加える代わりに、新しいプロジェクトを作成しました。ダイナミックWebプロジェクトを作成し、Mavenプロジェクトに変換します。次に、Person、Response、PersonService、およびPersonServiceImplというすべてのJavaクラスをコピーします。以下は、すべての変更が完了した後の最終プロジェクトです。 pom.xmlファイルに以下のRESTEasyの依存関係を追加します。

<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-jaxrs</artifactId>
	<version>3.0.13.Final</version>
</dependency>
<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-jaxb-provider</artifactId>
	<version>3.0.13.Final</version>
</dependency>

以下は、Resteasyサーブレットを設定するweb.xmlファイルです。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee https://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>JAXRS-Example-RestEasy</display-name>
     
    <listener>
      <listener-class>
         org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
      </listener-class>
   	</listener>
   
    <servlet>
        <servlet-name>resteasy-servlet</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
        <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.journaldev.jaxrs.resteasy.app.MyApp</param-value>
    </init-param>
    </servlet>
  
    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
	
</web-app>

以下のinit-paramには、値としてMyAppクラスを指定しています。ここでは、javax.ws.rs.core.Applicationクラスを拡張しています。

package com.journaldev.jaxrs.resteasy.app;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Application;

import com.journaldev.jaxrs.service.PersonServiceImpl;

public class MyApp extends Application {
	
	private Set<Object> singletons = new HashSet<Object>();

	public MyApp() {
		singletons.add(new PersonServiceImpl());
	}

	@Override
	public Set<Object> getSingletons() {
		return singletons;
	}

}

RESTEasy Webサービステスト

以上です。RESTEasy JAX-RSの実装が完了したWebサービスが準備されました。以下は、Postman Chrome拡張機能のテストからのいくつかの出力です。

  • getDummy
  • 追加する
  • 取得する

これでRestful Webサービスチュートリアルは終わりです。JAX-RSの注釈について学び、コードの再利用とJerseyからRESTEasyへの移行の利点が理解できたことを願っています。

Source:
https://www.digitalocean.com/community/tutorials/restful-web-services-tutorial-java