Spring MVC WEBアプリの Hello World!

# Spring MVC WEBアプリの Hello World!

## 目的

Spring MVC で最小構成のWEBアプリを作成して理解を深めます。  

## 実現すること

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

## 技術背景

### Spring MVC とは？  

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

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

Spring MVC は、Java プログラミング言語で記述された WEB アプリケーションを構築するためのフレームワークの1つです。 Spring MVC は、Model-View-Controller (MVC) アーキテクチャを採用しており、アプリケーションのビジネスロジック、ビュー、およびコントローラの分離を可能にします。このアーキテクチャにより、アプリケーションのテスト、保守、拡張が容易になります。  

Spring MVC の主な特徴は、柔軟性、拡張性、軽量性、セキュリティなどです。 Spring MVC は、多くの拡張機能を提供しており、Bean の注入、AOP、データバインディング、バリデーション、テンプレートエンジン、JSON のシリアル化など、開発者が効率的にアプリケーションを開発できるように設計されています。また、Spring Security との統合により、セキュリティを容易に実装できます。  

Spring MVC のメリットには、高速開発、保守性、可読性、テスト容易性、セキュリティなどがあります。Spring MVC は、開発者がアプリケーションをよりスムーズに開発できるようにすることで、プロジェクトの開発時間を短縮することができます。また、Spring MVC は、ビジネスロジック、ビュー、コントローラを分離するため、アプリケーションの保守性や可読性が向上します。さらに、Spring MVC は、テストをより容易に実施できるため、アプリケーションの品質を維持するのに役立ちます。  

</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-mvc をプロジェクトフォルダとします。

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

### 設定クラスの作成

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

ファイルの内容

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

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

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

    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setPrefix("classpath:/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("HTML");
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        viewResolver.setCharacterEncoding("UTF-8");
        return viewResolver;
    }
}
```

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

このコードは、Spring MVC アプリケーションの WebMvcConfigurer を実装している WebMvcConfig クラスで、Thymeleaf を使用して HTML ビューをレンダリングするための構成を提供しています。  

+  @Configuration アノテーションを使用して、このクラスが Spring の構成クラスであることを示し、 @EnableWebMvc アノテーションを使用して、Spring MVCの機能を有効化しています。

+ @ComponentScan アノテーションを使用して、アプリケーションでコンポーネントスキャンを行うパッケージを指定しています。

このクラスは、3つのメソッドから構成されています。  

+ 1つ目のメソッドは、Thymeleaf ビューを解決するための SpringResourceTemplateResolver を作成します。  

+ 2つ目のメソッドは、SpringTemplateEngine を作成し、SpringResourceTemplateResolver をテンプレートリゾルバーとして設定します。  

+  3つ目のメソッドは、ThymeleafViewResolver を作成し、SpringTemplateEngine をビューリゾルバーとして設定します。  

このクラスは、Thymeleaf を使用して HTML ビューを簡単に作成できるようにします。  

</details>

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

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

ファイルの内容

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

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.springmvc.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/springmvc/controller
$ vim src/main/java/com/example/springmvc/controller/HelloController.java
```

ファイルの内容

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

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "Hello World!");
        return "hello";
    }
}
```

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

このコードは Spring MVC のコントローラークラスであり、@Controller アノテーションが付与されています。  

@GetMapping("/hello") アノテーションは HTTP GET メソッドにマッピングされ、"/hello" エンドポイントにリクエストが送信されたときに実行されます。  

Model パラメーターには、ビューに渡されるデータを追加できます。この例では、"message" という名前の属性に "Hello World!" という値が設定されています。  

最後に、ビュー名 "hello" が返され、Thymeleaf テンプレートエンジンによって処理されます。  

</details>

### HTML テンプレートの作成

```sh
$ mkdir -p src/main/resources/templates/
$ vim src/main/resources/templates/hello.html
```

ファイルの内容

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="utf-8">
        <title>Hello</title>
    </head>
    <body>
        <h1 th:text="${message}"></h1>
    </body>
</html>
```

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

このコードは、Thymeleaf テンプレートエンジンを使用して作成された HTML ページであり、"Hello" というタイトルを持ち、"message" という変数から取得した文字列を表示します。  

具体的には、Thymeleaf の名前空間を使用しているため、h1 要素の th:text 属性に "${message}" という式を指定することで、変数 "message" の値を表示しています。  

つまり、このページは "Hello World!" というメッセージを表示します。  

</details>

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

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

ファイルの内容

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

    <properties>
        <thymeleaf.version>3.0.11.RELEASE</thymeleaf.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>
        <!-- Spring MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Thymeleaf -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>${thymeleaf.version}</version>
        </dependency>
        <dependency>
              <groupId>org.thymeleaf</groupId>
              <artifactId>thymeleaf-spring5</artifactId>
              <version>${thymeleaf.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
        │           └── springmvc
        │               ├── WebApplication.java
        │               ├── config
        │               │   └── WebMvcConfig.java
        │               └── controller
        │                   └── HelloController.java
        └── resources
            └── templates
                └── hello.html
```

### ビルドと起動

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

```sh
$ mvn clean install
```

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

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

WEBブラウザで確認

```sh
http://localhost:8080/hello
```

WEBブラウザに "Hello World!" と表示することが出来ました。

## まとめ

+ Ubuntu でのシンプルな構成の Java 開発環境で Spring MVC 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)