Java JAX-RS Webサービスで Hello World する

# Java JAX-RS Webサービスで Hello World する

こんにちは、@studio_meowtoon です。今回は、WSL の Ubuntu 22.04 で Java JAX-RS Web アプリケーションを作成して Hello World を出力する方法を紹介します。
![java_on_jetty.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/a1aad788-22d9-8c9c-a6d6-467ac799340e.png)

## 目的

Windows 11 の Linux でクラウド開発します。

こちらから記事の一覧がご覧いただけます。

https://qiita.com/studio_meowtoon/items/6119ab05d8b13527efd8

## 実現すること

ローカル環境の Ubuntu で、Java JAX-RS の WAR ファイル形式のアプリをビルド、起動します。

**WAR ファイル形式のアプリを起動**
```mermaid
flowchart LR
  terminal --> app.war
  subgraph Ubuntu
    subgraph JVM
      subgraph jetty
        app.war
      end
    end
  end
style Ubuntu fill:#FFBCA4, stroke:#E0460F
style JVM fill:#DCFFDC, stroke:#2F872F
```

|要素|概要|
|:--|:--|
|terminal|ターミナル|
|Ubuntu|OS|
|JVM|Java 実行環境|
|jetty|Web サーバー|
|app.war|Java アプリケーション|

## 技術トピック

### JAX-RS とは？  

<details>
<summary>こちらを展開してご覧いただけます。</summary>

### [JAX-RS](https://jakarta.ee/specifications/restful-ws/)

:::note info
JAX-RS は、Java API for RESTful Web Services の略称で、Java プラットフォーム上で RESTful Web サービスを開発するための API です。JAX-RS は、HTTP リクエストを受け取り、レスポンスを生成するための標準的な方法を提供します。

|特徴|
|:--|
|Java EE の一部であり、Java プラットフォーム上で RESTful Web サービスを開発するための API です。|
|HTTP リクエストを受け取り、レスポンスを生成するための標準的な方法を提供します。|
|Java メソッドやクラスに RESTful リソースをマッピングするためのアノテーションを提供します。|
|HTTP リクエストの解析や生成、HTTP レスポンスの生成など、RESTful Web サービスのための機能を提供するためのクラスやインターフェースを含んでいます。|
|RESTful Web サービスの開発に必要な多くの機能を提供するため、Java ベースのウェブサービス開発に広く採用されています。|
|Java EE アプリケーションサーバーの標準機能としてサポートされているため、Java EE アプリケーションの一部として使用されることもあります。|
|HTTP メソッド、HTTP ヘッダー、クエリパラメータ、パスパラメータなど、RESTful Web サービスの開発に必要な機能を提供します。|
|JSON や XML などのさまざまなデータフォーマットに対応しています。|
|拡張性が高く、カスタムの機能を追加することができます。|
|軽量で、シンプルな API を提供するため、RESTful Web サービスの開発に向いています。|
:::

:::note warn
**Java EE** は、2018年に **Jakarta EE** に名前が**変更**されました。これは、Oracle が Java EE の商標権を Eclipse Foundation に譲渡したことが理由です。Java EE からの変更点としては、主に商標やライセンスの変更があります。
:::

</details>

## 開発環境

+ Windows 11 Home 22H2 を使用しています。  

:::note info
[WSL](https://learn.microsoft.com/ja-jp/windows/wsl/about) の Ubuntu を操作していきますので macOS の方も参考にして頂けます。  
:::

<details>

WSL (Microsoft Store アプリ版) [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/2aaa6579cb8e4fa1d874)

```sh
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
```

Ubuntu [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/2aaa6579cb8e4fa1d874)

```sh
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
```

Java JDK [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/4d11e94a2389758759cd)

```sh
$ java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)
```

Maven [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/f4cdc4039158153365fb)

```sh
$ mvn -version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.18, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
```

</details>

:::note warn
この記事では基本的に **Ubuntu のターミナルで操作**を行います。**Vim を使用してコピペする方法**を初めて学ぶ人のために、以下の記事で手順を紹介しています。ぜひ挑戦してみてください。
:::

https://qiita.com/studio_meowtoon/items/7771ad48676926e41463

## 作成する Web アプリケーションの仕様

|No|エンドポイント|HTTPメソッド|MIME タイプ|
|:--|:--|:--|:--|
|1|/api/data|GET|application/json|

:::note info
**/api/data** というエンドポイントに対して HTTP GET リクエストを送信すると、JSON データがレスポンスされるシンプルな Web サービスを実装します。
**{"message":"Hello World!"}**
:::

## Hello World を表示する手順

### プロジェクトの作成

プロジェクトフォルダを作成します。  
※ ~/tmp/hello-jaxrs をプロジェクトフォルダとします。

```sh
$ mkdir -p ~/tmp/hello-jaxrs
$ cd ~/tmp/hello-jaxrs
```

### リソースクラスの作成

リソースクラスを作成します。

```sh
$ mkdir -p src/main/java/com/example/jaxrs
$ vim src/main/java/com/example/jaxrs/HelloResource.java
```

ファイルの内容

```java:HelloResource.java
package com.example.jaxrs;

import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("api")
public class HelloResource {

    @GET
    @Path("data")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, String> getData() {
        Map<String, String> map = Map.of("message", "Hello World!");
        return map;
    }
}
```

<details>
<summary>説明を開きます。</summary>

:::note info
このコードは、JAX-RS を使用して RESTful Web サービスのエンドポイントを作成しています。

|内容|
|:--|
|com.example.jaxrs というパッケージに HelloResource クラスを定義しています。|
|@Path("api") アノテーションを使用して、api というパスに関連付けられたリソースを作成しています。|
|@GET アノテーションを使用して、HTTP GET リクエストに応答するメソッドを作成しています。|
|@Produces(MediaType.APPLICATION_JSON) アノテーションを使用して、このメソッドが JSON 形式で応答することを指定しています。|
|@Path("data") アノテーションを使用して、data というパスに関連付けられたメソッドを作成しています。|
|public Map<String, String> getData() メソッドは、Map 形式で message キーと Hello World! の値を持つオブジェクトを返します。|

つまり、このコードは http://localhost:8080/api/data にアクセスすると、JSON 形式で {"message":"Hello World!"} というレスポンスを返す Web サービスのエンドポイントを作成しています。
:::

</details>

### web.xml の作成

web.xml ファイルを作成します。

```sh
$ mkdir -p src/main/webapp/WEB-INF
$ vim src/main/webapp/WEB-INF/web.xml
```

ファイルの内容

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    version="4.0">

    <servlet>
        <servlet-name>jaxrs-servlet</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.example.jaxrs</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>jaxrs-servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>
```

<details>
<summary>説明を開きます。</summary>

:::note info
この XML ファイルは、Java EE Web アプリケーションで Jersey を使用するための設定ファイルです。Web アプリケーションのサーブレットコンテナーによって読み込まれます。

|内容|
|:--|
|設定ファイルには、Jersey サーブレットの設定が含まれており、jersey.config.server.provider.packages パラメータを使用して、 Jersey がスキャンするパッケージを指定しています。|
|com.example.jaxrs パッケージが指定されており、Jersey はこのパッケージ内の RESTful Web サービスを検出し、適切に処理するようになります。|
:::

</details>

### pom.xml の作成

pom.xml ファイルを作成します。

```sh
$ vim pom.xml
```

ファイルの内容  

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>hello-jaxrs</artifactId>
    <packaging>war</packaging>
    <version>1.0</version>
    <name>hello-jaxrs</name>

    <properties>
        <javax.servlet.version>4.0.1</javax.servlet.version>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.2</version>
        </dependency>
        
        <!-- JAX-RS -->
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.1.1</version>
        </dependency>

        <!-- Jersey -->
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>2.39</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
            <version>2.39</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-binding</artifactId>
            <version>2.39</version>
        </dependency>

        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${javax.servlet.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.3</version>
              </plugin>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>10.0.13</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

<details>
<summary>説明を開きます。</summary>

:::note info
Maven プロジェクトのプロジェクトオブジェクトモデル (POM) です。プロジェクトの情報、依存関係、ビルド設定などが含まれています。

各項目は以下のとおりです。

|項目|内容|
|:--|:--|
|groupId|プロジェクトのグループIDを定義します。|
|artifactId|プロジェクトのアーティファクトIDを定義します。|
|packaging|プロジェクトのパッケージングタイプを定義します。(例えば、jar、war、pom など)|
|version|プロジェクトのバージョンを定義します。|
|name|プロジェクトの表示名を定義します。|
|properties|プロジェクトで使用されるプロパティー値を定義します。|
|javax.servlet.version|サーブレット API のバージョンを定義します。|
|java.version|Java のバージョンを定義します。|
|dependencies|依存関係のリストを定義します。ここでは、Web アプリケーションで使用される Servlet や JAX-RS のライブラリに依存しています。|
|build|プロジェクトのビルド設定を定義します。ここでは、Maven コンパイラプラグインを使用して Java バージョン11 でコンパイルするように指定し、Jetty Web サーバを Maven プラグインとして使用できるようにします。また、最終的に生成される WAR ファイルの名前を ${name} に設定しています。|

|依存関係|内容|
|:--|:--|
|Jackson|Java オブジェクトと JSON データの相互変換を行うためのライブラリです。|
|JAX-RS|Java で RESTful Web サービスを構築するための API 仕様です。|
|Jersey|JAX-RS API　を実装したライブラリで、サーブレットとして実行できる　RESTful Web サービスを構築するためのものです。|
|Servlet|Java Servlet API の実装ライブラリ。Maven の scope を provided に設定することで、アプリケーションが実行されるサーブレットコンテナから提供される Servlet API の実装を使用するように設定します。|
:::

</details>

### ディレクトリ・ファイル構成

プロジェクトのファイル構成を表示してみます。

```sh
$ tree
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── jaxrs
        │               └── HelloResource.java
        └── webapp
            └── WEB-INF
                └── web.xml
```

<details>
<summary>説明を開きます。</summary>

|No|ファイル|内容|
|:--|:--|:--|
|1|pom.xml|Maven プロジェクトの設定ファイルであり、プロジェクトの依存関係やビルド設定を定義します。|
|2|HelloResource.java|JAX-RS API を使用して HTTP GET リクエストを受信し、それに対するレスポンスを返します。特定の URL パスにマッピングされたメソッドを提供し、クライアントとの間でデータの受け渡しを行うために使用されます。|
|3|web.xml|アプリケーションの URL パターン、サーブレットのクラス名、JAX-RS アプリケーションクラスの名前など、サービスを定義するための設定が含まれます。|

:::note info
JAX-RS アプリを構成するために作成したファイルは、今回の例では3つだけです。これらのファイルを組み合わせることで、JAX-RS アプリケーションを構築することができます。
:::

</details>

### JAX-RS アプリをビルド、実行

Java アプリをビルドします。(※ 参考)
※ target/app.war が作成されます。  

```sh
$ mvn clean package
```

アプリを起動します。 (※ ctrl + C で停止します)

```sh
$ mvn jetty:run
```

:::note info
**mvn jetty:run** コマンドは、Maven のプラグインにより Jetty Web サーバーを一時的に立ち上げ、その中で WAR ファイル形式の Web アプリケーションが実行されます。
:::

別ターミナルから curl コマンドで確認します。

```sh
$ curl -v http://localhost:8080/api/data -w '\n'
```

出力

```sh
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/data HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 09 Mar 2023 05:42:30 GMT
< Content-Type: application/json
< Content-Length: 26
< Server: Jetty(10.0.13)
<
* Connection #0 to host localhost left intact
{"message":"Hello World!"}
```
:::note info
ここまでの手順で、ターミナルに **{"message":"Hello World!"}** と表示され、**JSON データ**を取得することが出来ました。  
:::

## まとめ

Ubuntu に構築したシンプルな Java 開発環境で、JAX-RS の Web サービスを実行することができました。

:::note warn
実際の業務での JAX-RS の使用ケースでは、構成ファイルなどが追加されるため、ここで示したようなシンプルな構成とは異なる場合があります。しかしながら、最小構成の例を学ぶことで、JAX-RS がどのような構成が必要なのかを理解することができます。
:::

どうでしたか？ WSL Ubuntu で、JAX-RS Web アプリケーションを手軽に実行することができます。ぜひお試しください。今後も Java の開発環境などを紹介していきますので、ぜひお楽しみにしてください。

## 推奨コンテンツ

https://qiita.com/studio_meowtoon/items/7951cecb164dbd53ecdd

## 関連記事

https://qiita.com/studio_meowtoon/items/37ac0082a3228e4de570