Spring Boot入門  アノテーションをラベルで例える

# はじめに
これまでSpring BootのDI（依存性注入）とAOP（アスペクト指向プログラミング）について触れてきました。本記事ではアノテーションについて解説します。

前回記事、前々回記事はコチラです。

≪前々回記事≫

https://qiita.com/matsuuranext0303/items/d95b6980494607558bb2

≪前回記事≫

https://qiita.com/matsuura_nt/items/12e2a5f0e6288f80c65c

# 1.アノテーションとは
これまでの記事でごく当たり前のようにアノテーションを使ってきましたが、改めてその役割について確認しましょう。
DIではクラスに`@Component`、AOPにおいてはクラスには`@Aspect`、メソッドには`@Before`など各宣言行の前に記述したこれらの@～から始まるものがアノテーションです。
アノテーションは、コードにメタデータ（説明書き）を追加するためのもので、例えば、`@Component`（DI用）や`@Aspect`（AOP用）、`@Before`（AOPメソッド呼び出し前）など、これらはコードの動作に影響を与える指示を示しています。Spring Bootにおいては、アノテーションが実行時にフレームワークに対して特定の処理や挙動を指示する役割を担っています。
フレームワークを使わない場合もJava標準のアノテーションがありますが、これらは開発者の補助的な注釈であり、処理に直接影響することはありません。ただSpring Bootなどのフレームワーク環境下においては、特定の処理や挙動を指示することができます。


# 2.ラベルに例える
Spring Bootを使う際、アノテーションは非常に重要な役割を果たします。しかしアノテーションが実際にどんなものなのか、少し難しく感じるかもしれません。そこで、アノテーションを「ラベル」のようなものだと考えてみてください。

**アノテーションを「ラベル」として考える**

日常生活では、ラベルを使ってモノを分類し整理や振分を行うと思います。
たとえば、冷蔵庫に「お弁当用」「調味料」とラベルを貼っておけば、どの食品がどの場所に保管されているのか、誰でもすぐに分かり、ジップロックに消費期限を記載して期限が到来していれば廃棄といった作業を行うと思います。

同じように、Spring Bootではアノテーションが「ラベル」として、リクエストの処理方法を決定する役割を果たします。

### 配送システムで考える
次に、配送システムを例にアノテーションがどのように使われるかを見てみましょう。お客様が配送依頼をするとき、配送センターはアノテーション（ラベル）を使って、リクエストを処理します。

**1 通常配送：荷物追跡**

お客様が荷物の現在地を確認したいとき、「今、私の荷物はどこにあるか？」というリクエストを配送センターに送ります。この場合、配送センターはそのリクエストを受けて、荷物の追跡情報を返します。

ラベルで例えるなら、「荷物追跡用」のラベルを貼ったリクエストが送られてくるイメージです。配送センターはこのリクエストに従い、追跡番号に基づいて情報を返すわけです。

**2. クール便配送：特別配送**

クール便（冷蔵・冷凍便）など、特別な取扱が必要な配送の場合、お客様は「冷蔵品を送るための配送依頼」をします。この場合、配送センターは温度管理に注意を払いながら配送手配を進めます。

この場合、ラベルは「冷蔵品専用」のラベルを貼るようなイメージです。配送センターは、このラベルがついている荷物に対して、特別な取り扱いを行います。

**3. サイズ指定配送：バリデーションチェック**

配送センターでは、荷物のサイズ制限が設けられていることがあります。お客様が荷物を送る際、その荷物のサイズが規定内かどうかを確認します。この場合、「サイズ確認用」のラベルがリクエストに貼られており、そのサイズが適切かどうかを配送センターがチェックします。

このように、アノテーションはリクエストに「ラベル」を貼ることで、リクエストがどのように処理されるべきかを示しているのです。
Spring Boot では本来コーディングが必要な処理をアノテーションによって補完することが可能となります。


# 3.アノテーションの実例

さて、次はこの配送システムをSpring Bootのアノテーションを使って実際にコードに落とし込んでみましょう。
今回アノテーションで実現したいことは以下の3つです。

お客様からは2通りのリクエストが依頼される。
**・通常配送の荷物追跡**
**・クール便の配送依頼**

また配送する荷物のサイズは以下の制限を設ける。
**・全辺100cm以内**

### 1） 通常配送：荷物追跡
お客様が荷物の追跡情報を確認したい場合、`@GetMapping`を使って配送センターからその情報を取得します。`@GetMapping`はHTTPサーバーから送信されるGetリクエストの処理を行います。「データの取得」の目的で使用されるアノテーションです。

```java
@GetMapping("/track/{trackingNumber}")
public String trackPackage(@PathVariable String trackingNumber) {
    return "荷物追跡情報：" + trackingNumber;
}
```
この例では、`@GetMapping`が「荷物追跡」のリクエストに対応しています。このアノテーション（ラベル）がリクエストに貼られていることで、「荷物追跡」の処理が行われることが分かります。
`@Pathvariable`はURLの一部を変数として受け渡すための機能を備えています。
例えば今回リクエストされたURLが「/track/12345」の場合、{tracknumber}に12345を割り当て、メソッドの引数として使うことができ、動的なパラメータの取得を行います。


**実行結果** 
リクエストURL: http://localhost:8080/track/12345

＜ブラウザへのレスポンス＞
```
荷物追跡情報：12345
```
この例では、@GetMappingが「荷物追跡」のリクエストに対応しており、指定したトラッキング番号に基づいた情報が返されます。
<br>

### 2）クール便配送：特別配送手配
クール便を手配するためには、`@PostMapping`を使って新しい配送依頼を送ります。
`@PostMapping`はHTTPサーバーから送信されるPostリクエストの処理を行います。「データの登録」で使用されるアノテーションです。
また送信するリクエストは`@RequestBody`を使用します。これはHTTPリウエストボディに含まれるJSON形式のデータをJavaオブジェクトとして受け取ることが出来ます。
今回は以下のShippingDetailsクラスを考えます。このクラスは配送に関する情報（例えば、配送先住所）を保持するためのものです。

```java
public class ShippingDetails {
    private String destination;  // 配送先住所

    // getter
    public String getDestination() {
        return destination;
    }

    // setter
    public void setDestination(String destination) {
        this.destination = destination;
    }
}
```
このクラスに対して、`@RequestBody`アノテーションを使って、クライアントが送ったJSONデータ（例えば、{"destination": "東京"}）をShippingDetailsオブジェクトに変換し、destinationフィールドに値をセットすることができます。
次に送ったデータから新規配送依頼を作成するメソッドを見てみましょう。
```java
@PostMapping("/cool-shipping")
public String shipCoolPackage(@RequestBody ShippingDetails details) {
    return "冷蔵便が手配されました。配送先：" + details.getDestination();
}
```
ここでは、`@PostMapping`が「新しい配送依頼」のリクエストに対応しています。このアノテーションが「冷蔵便」の配送依頼に貼られているので、特別な取扱を必要とする配送が手配されます。
処理内容としてはクライアントが送った配送情報（例えば、配送先住所：東京）を`@RequestBody`でShippingDetailsオブジェクトとして受け取っています。その後、details.getDestination()で配送先住所を取り出し、処理を行っています。
<br>

**実行結果** 
配送先を「東京」としたときの実行結果は以下のようになります。

＜ブラウザへのレスポンス＞
```
冷蔵便が手配されました。配送先：東京
```
<br>

### ３）サイズ指定配送：バリデーションチェック
配送する荷物のサイズが規定内かどうかをチェックする場合、`@Max`と`@Valid`を使ってバリデーションを行います。これにより、サイズが規定内であることを確認できます。

```java
import javax.validation.constraints.Max;

public class PackageDetails {
    @Max(100)  // 最大サイズ100cm
    private int size;

    // Getter
    public int getSize() {
        return size;
    }

    // Setter
    public void setSize(int size) {
        this.size = size;
    }
}

@PostMapping("/send-package")
public String sendPackage(@Valid @RequestBody PackageDetails packageDetails) {
    return "サイズ" + packageDetails.getSize() + "cm の荷物が送信されました。";
}
```
`@Valid`がリクエストボディに付与されることによって、Spring Boot はリクエストが送信される前にこのバリデーションを自動的に実行し、`@Max`は「荷物のサイズ制限」に関するバリデーションを行います。もし荷物のサイズが100cmを超えていた場合、`@Valid`によってリクエストが送信される前にバリデーションエラーを返します。


**実行結果** 
サイズが80cmの場合の実行結果は以下のようになります。

＜ブラウザへのレスポンス＞
```
サイズ80cm の荷物が送信されました。
```
またサイズが100cmを超える数値が送られた場合、HTTP400エラーが返されます。
※環境によってはエラー情報がJSON形式で返されることもあります。
```
400 Bad Request

The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, size too large, etc.).
```

# まとめ
このようにラベル付けを行うことで処理の振分やバリデーションチェックをSpring Bootでは標準機能として持ち合わせているため、使いこなせればコード量を必要最低限に抑えることが可能です。
今回紹介したのはアノテーションの中でも基礎的な部分に過ぎません。
Spring Bootのアノテーションだけでもおよそ100種類以上存在するので、必要に応じ調べて使いこなせるようにしましょう！