こちらの続き
【java+spring boot】ローカルでファイル添付処理を実装してみた
【読み解き】実装を調べてみた
主には参考にしたページで解説されているがちょっと難しい。
実装みながら自分なりにまとめてみる。
実装箇所の概要
メイン
- Controller
- StorageService(interface)
- FileSystemStorageService (implements StorageService)
- StorageProperties
- MainApplication
例外
- StorageException extends RuntimeException
- StorageFileNotFoundException extends StorageException
その他
- html(template)
- application.properties
→ それぞれの役割と処理についてざっと書き出して最後にまとめる。
書き出し順は適当。
役割と処理を書き出す
StorageProperties
まず最初の記事にも記載したように、ここではファイルデータを保管するロケーションのパスを指定している。今回は"upload-dir"
を設定。
これをBean登録することで、パスを処理するときに簡単に呼び出して使うことができる。
@Component // ConfigurationPropertiesを付けたクラスに付けることでBeanに登録する
@ConfigurationProperties("storage") //DIコンテナに登録されたBeanに対してプロパティを設定するためのアノテーション
public class StorageProperties {
/**
* Folder location for storing files
*/
private String location = "upload-dir";
}
@ConfigurationProperties("storage")
を詳しく...
参考:Spring Bootの@ ConfigurationPropertiesで型安全なプロパティ設定
@ConfigurationPropertiesアノテーションをつけることで、プロパティ値が各フィールドにインジェクションされます。 prefix属性をつけることで、プロパティ値のプリフィクスを設定することもできます。
@ConfigurationPropertiesは正確に言うと、プロパティクラスを定義するアノテーションではなく、 DIコンテナに登録されたBeanに対してプロパティを設定するためのアノテーションです。 この例だと、@ComponentをつけてDIコンテナに登録されたtargetPropertiesというBeanの hostプロパティに対してプロパティファイル中のtarget.hostの値を設定し、 portプロパティに対してプロパティファイル中のtarget.portの値を設定しています。 インジェクション対象のBeanにSetter/Getterが必要なのはこのためです。
ふむ、本記事にそって言い換えると、
@Component
をつけてDIコンテナに登録されたStorageProperties
というBeanの storage
プロパティに対してプロパティファイル中のstorage.location
の値を設定している。初期値はupload-dir
。
また、インジェクション対象のBeanにSetter/Getterが必要(今回はLombokでアノテーション追加しているのでOK)。
StorageService(interface)
サービスは主にController で呼び出す基本的な処理を切り分けて実装する。こちらはインターフェースなので、実際の処理はimplements
してFileSystemStorageService
に実装されている。敢えてインターフェースにしているということは、ファイル処理に最低限必要な処理を定義しているということ、か。
それぞれの役割を簡潔にコメントで記載。
public interface StorageService {
void init(); // 保管先の親ディレクトリを作成、アプリ実行度に実行(※)
void store(MultipartFile file); // ファイル保存 ※storeの動詞は「保管する」の意味
Stream<Path> loadAll(); // 保管しているファイルパスを走査(画面表示に利用)
Path load(String filename); // 「保存場所のパス+ファイル名」のパスを返す
Resource loadAsResource(String filename); // 引数のfilenameが保管先に存在し、リソースとして読み取り可能かチェックする
void deleteAll(); // 保管用の親ディレクトリごと削除、アプリ実行度に実行(※)
}
これらを用いてあれやこれやして、ファイルの保管や取得を行う。
ファイル操作の流れ別に処理を見ていく...は長くなるので次の投稿で