【java + spring boot】ローカルでファイル添付処理を実装してみた

## 開発環境
- java 17
- springboot
- thymeleaf

## やりたいこと
- ファイル添付を実装（しながら仕組みを学ぶ）
- ファイル保管場所：ローカル

### 手順
1. バックグラウンド側の各ファイル操作処理を実装
1. フロント側に添付ファイルのインターフェースになるフォームを実装

**こちら参考に実装：[ファイルのアップロード](https://spring.pleiades.io/guides/gs/uploading-files/)**

※私は適当なjavaアプリがあったため、**「アプリケーションクラスを作成する」** から部分的に移植する形で実装。Exceptionなど大体の追加ファイルはとりあえずcommonディレクトリにぶちこみ。

#### そのまま実装するとエラーになったので補足
ビルドは通るが実行すると失敗
```
***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.example.プロジェクト名.common.FileSystemStorageService required a bean of type 'com.example.プロジェクト名.common.StorageProperties' that could not be found.

Action:
Consider defining a bean of type 'com.example.プロジェクト名.common.StorageProperties' in your configuration.

Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

```
直訳
```
FileSystemStorageService のコンストラクターのパラメーター 0 には、「com.example.プロジェクト名.common.StorageProperties」タイプの Bean が必要でしたが、見つかりませんでした。
```
つまり、`StorageProperties` がBeanに登録されていない。

**■エラー発生箇所**
　FileSystemStorageService.java
```java
@Service
public class FileSystemStorageService implements StorageService {
    private final Path rootLocation;

    @Autowired
    public FileSystemStorageService(StorageProperties properties) { // ← 多分ここ
    
```

**■エラー原因**
`@Autowired`を付けるとインスタンス処理を spring boot が自動で行ってくれるが、
引数で引用しようとしている`StorageProperties`がBeanに登録されておらず、呼び出せない状態。

>`@Autowired` にインスタンス化を任せることができるのはSpringフレームワークが提供しているDIコンテナに登録されているクラスのみ。
利用したいクラスに`@Component`,`@Controller`,`@Service`,`@Repository`をつけることでDIコンテナへ登録が可能です。...[引用1](https://qiita.com/yuto-hatano/items/69d01343f710117e4243)

**■解決策**
`StorageProperties`クラスに`@Component`を付与（ほかにも方法はあるらしい）。
```java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; // 追加

@Component // 追加：ConfigurationPropertiesを付けたクラスに付けることでBeanに登録する
@ConfigurationProperties("storage") //DIコンテナに登録されたBeanに対してプロパティを設定するためのアノテーション
public class StorageProperties {
    private String location = "upload-dir";
}
...
```
**■その他**
場合によっては`StorageProperties.location`をget/setすためにgetter/setterが必要になる。
Lambok を使用している場合は下記で、使用しない場合は直で実装する必要がある。
```java
import lombok.Getter; // 追加
import lombok.Setter; // 追加
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Getter // 追加
@Setter // 追加
@Component
@ConfigurationProperties("storage")
public class StorageProperties { ...
```

### アプリ起動しファイル添付実行
#### ■添付ファイルが保存された場所

今回は↑に記載した通り`StorageProperties`クラスでファイルデータを保管するロケーションを`"upload-dir"`と指定している。
```java
public class StorageProperties {
    private String location = "upload-dir";
}
```
確認するとプロジェクト直下に`"upload-dir"`が作成され、ファイルアップロードが成功すると添付ファイル名でファイルが生成（※正しくはデータのコピー保存）されている。
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3572406/ed3a765e-2542-70ab-9b75-ae3ef9483882.png">

### 【読み解き】実装を調べてみた
...は次回の投稿に


### 引用リスト
1. [【Spring】＠Autowiredはコンストラクタインジェクションで使おう！](https://qiita.com/yuto-hatano/items/69d01343f710117e4243)
1. [ファイルのアップロード](https://spring.pleiades.io/guides/gs/uploading-files/)
1. [Spring Bootの@ ConfigurationPropertiesで型安全なプロパティ設定](https://ik.am/entries/376)