Resource
Resource は読み込むコンテンツを表し、ResourceLoader は resources:mail.txt のようなロケーション文字列を Resource に変換します。
使う理由
ファイルを読む Bean は、ロケーションを設定から受け取って読むだけにするべきで、保存先ごとのコードを持つべきではありません。各プレフィックスの意味はローダーが知っています。
- 登録された
ProtocolResolver(登録順。例: Flutter のアセット)。 resources:: ジェネレーターが埋め込んだlib/resources/のファイル。file:: ディスク上のファイル。パーセントデコードされる(file:my%20dir/a.txt)。http:とhttps:: 非同期で読むUrlResource。package:: パッケージ設定を通したパッケージのファイル(Web と AOT 実行ファイルでは使えない)。- その他の
scheme:: 存在しないリソース。 - プレーンなパス(
app.properties):resources:のリソース。
Bean が受け取るローダーはアプリケーションコンテキストです。コンテキストは ResourcePatternResolver でもあり、resources:mail/*.txt のようなパターンに一致するファイルをすべて見つけます。
固定のロケーションなら @Value('resources:...') Resource が最も短い書き方です。設定値を読むなら、ファイルを読まずに ${...} 付きの @Value を使ってください。
例
import 'package:spring_core_dart/spring_core_dart.dart';
@Service()
class Imports {
Imports(this.resources, @Value(r'${shop.import.file}') this.location);
// アプリケーションコンテキスト: ResourceLoader かつ ResourcePatternResolver。
final ResourcePatternResolver resources;
// 本番では `file:./import.csv`、開発では `resources:demo.csv`。
final String location;
Future<String> read() => resources.getResource(location).readAsString();
// lib/resources/mail/ に同梱したメールテンプレートすべて。
List<Resource> templates() => resources.getResources('resources:mail/*.txt');
}
同期読み込みは、リソースが対応している場合にだけ使えます。
final resource = DefaultResourceLoader().getResource('resources:banner.txt');
if (resource.exists() && resource.supportsSyncRead) {
// ファイルと埋め込みの lib/resources/ は待たずに読める。
final banner = resource.readAsStringSync();
}
新しいプレフィックスは ProtocolResolver で追加します。組み込みのルールより先に問い合わせられます。
// `inline:greeting` をメモリから返す。
final loader = DefaultResourceLoader(
protocolResolvers: [
FunctionProtocolResolver(
(location, _) => location == 'inline:greeting'
? ByteArrayResource.fromString('hello=world')
: null,
),
],
);
パターンについて:
resources:は、パターンのベースディレクトリを持つ最初のクラスパスルートだけを検索します。resources*:はすべてのルート(Resources.addDirectoryで追加したディレクトリ、次に埋め込みファイル)を検索します。- ワイルドカードは AntPathMatcher に従います。一致したディレクトリも返されます。
- ベースディレクトリが存在しない
resources:パターンは空のリストを返します。
メンバー
Resource:
| 名前 | 型 | 意味 |
|---|---|---|
exists() |
bool |
コンテンツが存在するか。UrlResource は常に true。サーバーに問い合わせるには existsAsync() を使う。 |
isReadable |
bool |
読み込めるか。ディレクトリは false。 |
filename |
String? |
パスの最後の部分。ない場合(メモリ上のバイト列)は null。 |
description |
String |
エラーメッセージ用の説明。例: file [/app/config/application.properties]。 |
uri |
Uri? |
リソースの URI。ない場合は null。 |
supportsSyncRead |
bool |
...Sync の読み込みが使えるか。ファイルと埋め込みリソースでは true。 |
readAsBytes() |
Future<Uint8List> |
内容全体を読む。 |
readAsString({encoding}) |
Future<String> |
内容全体をテキストとして読む。指定がなければ UTF-8。 |
readAsBytesSync() |
Uint8List |
同期読み込み。supportsSyncRead でなければ UnsupportedError。 |
readAsStringSync({encoding}) |
String |
テキストとしての同期読み込み。 |
createRelative(relativePath) |
Resource |
このリソースからの相対パスにあるリソース。存在は確認しない。 |
ローダーと実装:
| 名前 | 意味 |
|---|---|
ResourceLoader.getResource(location) |
ロケーション文字列に対応するリソース。 |
ResourcePatternResolver.getResources(pattern) |
パターンに一致するすべてのリソース。 |
DefaultResourceLoader({protocolResolvers}) |
標準のローダー。addProtocolResolver でリゾルバーを追加できる。 |
PathMatchingResourcePatternResolver({resourceLoader, pathMatcher}) |
標準のパターンリゾルバー。 |
ProtocolResolver、FunctionProtocolResolver、InMemoryProtocolResolver |
ローダーに新しいプレフィックスを教える。 |
FileSystemResource、UrlResource、ByteArrayResource、DescriptiveResource |
ディスク上、URL、メモリ上のリソース、および存在しないことを表すプレースホルダー。 |
Resources.addDirectory(directory) |
resources: がディスク上のディレクトリを先に探すようにする。解除する関数を返す。 |
Spring (Java) との対応
@Service
class Imports {
private final ResourcePatternResolver resources;
Imports(ResourcePatternResolver resources) {
this.resources = resources;
}
String read(String location) throws IOException {
return resources.getResource(location)
.getContentAsString(StandardCharsets.UTF_8);
}
Resource[] templates() throws IOException {
return resources.getResources("classpath:mail/*.txt");
}
}
重要な違い:
- プレフィックスは
classpath:(とclasspath*:)ではなくresources:(とresources*:)です。「クラスパス」はlib/resources/です。 - Flutter のアセットや URL は非同期でしか読めないため、読み込みは基本的に非同期です。
getInputStream()やgetFile()はなく、内容全体を読みます。 UrlResource.exists()はリクエストを送りません。existsAsync()がHEADリクエストを送ります。- クラスパスルートより上に出る
..は何も見つけません。file:パターンでは\を使った Windows のパスも使えます。