Resource

Resource は読み込むコンテンツを表し、ResourceLoader は resources:mail.txt のようなロケーション文字列を Resource に変換します。

使う理由

ファイルを読む Bean は、ロケーションを設定から受け取って読むだけにするべきで、保存先ごとのコードを持つべきではありません。各プレフィックスの意味はローダーが知っています。

  1. 登録された ProtocolResolver(登録順。例: Flutter のアセット)。
  2. resources:: ジェネレーターが埋め込んだ lib/resources/ のファイル。
  3. file:: ディスク上のファイル。パーセントデコードされる(file:my%20dir/a.txt)。
  4. http: と https:: 非同期で読む UrlResource。
  5. package:: パッケージ設定を通したパッケージのファイル(Web と AOT 実行ファイルでは使えない)。
  6. その他の scheme:: 存在しないリソース。
  7. プレーンなパス(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,
    ),
  ],
);

パターンについて:

メンバー

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");
  }
}

重要な違い:

関連項目