Spring MVC REST WEBサービスの Hello World!

# Spring MVC REST WEBサービスの Hello World!

## 目的

Spring MVC REST で最小構成のWEBサービスを作成して理解を深めます。  

## 実現すること

ローカル環境 (Ubuntu) で Spring MVC war ファイル形式のWEBアプリをビルド・起動します。

## 技術背景

### Spring MVC REST とは？  

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

### [Spring MVC](https://spring.pleiades.io/spring-framework/docs/current/reference/html/web.html#mvc)

Spring MVC REST の特徴とメリットは以下の通りです。  

#### 優れた柔軟性

Spring MVC REST は、異なる種類のリクエストやレスポンスを処理するための豊富な機能を提供しており、フレキシブルな REST API を構築することができます。

#### 豊富な機能

Spring MVC REST には、JSON や XML などのさまざまなデータフォーマットをサポートするための機能が含まれています。また、HTTP メソッドに対応したアノテーションや、パラメーターのバリデーション、例外処理などの機能も提供されています。

#### 簡単なテスト

Spring MVC REST は、JUnit などのユニットテストフレームワークを使用して簡単にテストすることができます。

#### ビジネスロジックとの分離

Spring MVC REST は、ビジネスロジックとの分離をサポートするため、ビジネスロジックによって提供されるサービスを使用して、REST API の機能を実装することができます。

#### ドキュメンテーションの容易さ

Spring MVC REST は、Swagger などのツールを使用して、REST API のドキュメンテーションを簡単に生成することができます。これにより、開発者は API の使用方法を簡単に理解することができます。

</details>

## 開発環境

+ Windows 11 Home 22H2 を使用しています。  
+ [WSL](https://learn.microsoft.com/ja-jp/windows/wsl/about) の Ubuntu を操作していきますので macOS の方も参考にして頂けます。  

<details>

WSL (Microsoft Store アプリ版)

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

Ubuntu

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

Java JDK [※ Java JDK の導入と Hello World!](https://qiita.com/hiroxpepe/items/8650664e466906a57996)

```sh
$ java -version
openjdk version "11.0.17" 2022-10-18
OpenJDK Runtime Environment (build 11.0.17+8-post-Ubuntu-1ubuntu222.04)
OpenJDK 64-Bit Server VM (build 11.0.17+8-post-Ubuntu-1ubuntu222.04, mixed mode, sharing)
```

Maven [※ Maven の導入と Hello World!](https://qiita.com/hiroxpepe/items/40f7f199b9be7f9e3b5b)

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

</details>

※ この記事では基本的に Ubuntu のターミナルで操作を行います。

## "Hello World" を表示する手順

### プロジェクトフォルダの作成

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

```sh
$ cd ~
$ mkdir -p tmp/hello-spring-rest
$ cd tmp/hello-spring-rest
```

### 設定クラスの作成

```sh
$ mkdir -p src/main/java/com/example/springrest/config
$ vim src/main/java/com/example/springrest/config/WebMvcConfig.java
```

ファイルの内容

```java:WebMvcConfig.java
package com.example.springrest.config;

import java.util.List;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example")
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter());
    }
}
```

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

このコードは、Spring MVC アプリケーションの Web MVC 構成を定義するためのクラスです。  

以下のような役割を果たします。  

+ @Configuration アノテーションにより、このクラスが Spring アプリケーションコンテキストの設定を定義することを示します。  

+ @EnableWebMvc アノテーションにより、Spring MVC を有効にすることを示します。  

+ @ComponentScan アノテーションにより、このクラスが含まれるパッケージ以下のコンポーネントをスキャンし、自動的に Spring のコンポーネントスキャンに追加することを示します。  

+ WebMvcConfigurer インタフェースの実装により、Spring MVC の構成をカスタマイズするためのメソッドを提供します。この例では、JSON データを HTT レスポンスに変換するために、MappingJackson2HttpMessageConverter を追加するように設定されています。

</details>

### アプリケーションクラスの作成

```sh
$ mkdir -p src/main/java/com/example/springrest/config
$ vim src/main/java/com/example/springrest/WebApplication.java
```

ファイルの内容

```java:WebApplication.java
package com.example.springrest;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import com.example.springrest.config.WebMvcConfig;

public class WebApplication implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {

        // Load Spring web application configuration
        final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(WebMvcConfig.class);

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcher", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}
```

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

このコードは、Spring MVC アプリケーションの WEB アプリケーションの設定を定義するためのクラスです。  

以下のような役割を果たします。  

+ WebApplicationInitializer インタフェースの実装により、WEB アプリケーションの開始時に実行するカスタムコードを提供します。

+ AnnotationConfigWebApplicationContext クラスを使用して、Spring の WEB アプリケーションコンテキストを作成し、WebMvcConfig クラスの構成をロードします。

+ DispatcherServlet を作成して、WEB リクエストを処理するための中心的なコントローラーとして機能するように構成します。

+ ServletRegistration.Dynamic オブジェクトを使用して、DispatcherServlet を WEB アプリケーションに登録し、/ にマッピングします。

このクラスは、Spring MVC の WEB アプリケーションを構成する上で、非常に重要な役割を果たしています。特に、WebApplicationInitializer を実装しているため、WEB アプリケーションが開始されるときに、Spring のコンテキストと DispatcherServlet が適切に初期化され、動作するようになります。  

</details>

### コントローラークラスの作成

```sh
$ mkdir -p src/main/java/com/example/springrest/controller
$ vim src/main/java/com/example/springrest/controller/HelloController.java
```

ファイルの内容

```java:HelloController.java
package com.example.springrest.controller;

import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloController {

    @GetMapping("/data")
    public Map<String, String> getData() {
        Map<String, String> map = Map.of("message", "Hello World!");
        return map;
    }
}
```

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

このコードは、RESTful API を実装するための Spring MVC コントローラーです。  

以下のような役割を持ちます。  

+ @RestController アノテーションにより、クラスが RESTful API の実装であることを示しています。

+ @RequestMapping("/api") アノテーションにより、クラスレベルでのリクエストマッピングを定義しています。つまり、このコントローラーは /api パスにマッピングされます。

+ @GetMapping("/data") アノテーションにより、HTTP GET メソッドに対するリクエストマッピングを定義しています。つまり、このメソッドは /api/data にマッピングされます。

+ getData() メソッドは、Map を返すように構成されており、Map.of("message", "Hello World!") によって、単一のキー message と値H ello World! を含む Map を返します。

このように、HelloController クラスは、RESTful API の実装に必要なすべての要素を持っています。そして、HTTP GET リクエストが /api/data パスに送信されると、getData() メソッドが呼び出され、Map 形式で "Hello World!" というメッセージが返されます。  

</details>

### pom.xml (Maven) の作成

```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-spring-rest</artifactId>
    <packaging>war</packaging>
    <version>1.0</version>
    <name>hello-spring-rest</name>

    <properties>
        <jackson.version>2.11.2</jackson.version>
        <spring.version>5.3.3</spring.version>
        <javax.servlet.version>4.0.1</javax.servlet.version>
        <java.version>11</java.version>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <!-- Spring MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</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>${name}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </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>
```

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

```sh
$ tree
.
├── pom.xml
└── src
    └── main
        └── java
            └── com
                └── example
                    └── springrest
                        ├── WebApplication.java
                        ├── config
                        │   └── WebMvcConfig.java
                        └── controller
                            └── HelloController.java
```

### ビルドと起動

ビルド  
※ target/hello-spring-rest.war ファイルが作成されます。  
※ war ファイルは Java WEBアプリケーションのファイル形式です。  

```sh
$ mvn clean install
```

実行  
※ Maven のプラグインにより Jetty WEBサーバーを一時的に立ち上げ、その中で war ファイル形式の WEB アプリケーションが実行されます。  
※ アプリケーションは、Ctrl + C で終了出来ます。  

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

WEBブラウザで確認

```sh
http://localhost:8080/api/data
```

WEBブラウザに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。  

別ターミナルのコマンドで確認

```
$ curl -v http://localhost:8080/api/data
*   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: Sat, 25 Feb 2023 07:40:22 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: Jetty(10.0.13)
<
* Connection #0 to host localhost left intact
{"message":"Hello World!"}
```

ターミナルに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。  

## まとめ

+ Ubuntu でのシンプルな構成の Java 開発環境で Spring MVC REST WEBサービスをビルド・実行することが出来ました。
+ [Spring Framework](https://docs.spring.io/spring-framework/docs/current/reference/html/overview.html#overview) は事実上 Java におけるデファクトのフレームワークとなっていますので、Java WEB サービスの基本的な動作理解の助けにして頂けます。
+ また [Spring MVC](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc) 自体は Servlet API を使用しているので、Servlet のシンプルな構成を確認されたい方は次の記事を参考にして頂けます。  
    + [Java Servlet WEBアプリの Hello World!](https://qiita.com/hiroxpepe/items/003fd9c0d9222026f2f3)