現在、REST APIを構築しています。このAPIを使用すると、特定のエンティティのほとんどのプロパティを簡単にフィルタリングできます。 QueryDSL と SpringデータREST ( 例:Oliver Gierke )を使用すると、プロパティを参照するクエリパラメーター(例:/users?firstName=Dennis&lastName=Laumen
)。
QuerydslBinderCustomizer
インターフェイスを実装することで、クエリパラメーターとエンティティのプロパティ間のマッピングをカスタマイズすることもできます(たとえば、大文字と小文字を区別しない検索や部分的な文字列の一致など)。これはすべて素晴らしいですが、クライアントが範囲を使用していくつかのタイプをフィルタリングできるようにしたいと思っています。たとえば、生年月日のようなプロパティに関して、次のようなことをしたいと思います、/users?dateOfBirthFrom=1981-1-1&dateOfBirthTo=1981-12-31
。同じことが数値ベースのプロパティ/users?idFrom=100&idTo=200
。これはQuerydslBinderCustomizer
インターフェイスを使用して可能であると感じていますが、これらの2つのライブラリ間の統合についてはあまり詳しく説明されていません。
結論、これはSpring Data RESTとQueryDSLを使用して可能ですか?そうであれば、どのようにですか?
次のカスタマイズを使用してこれを機能させることができるはずです。
_bindings.bind(user.dateOfBirth).all((path, value) -> {
Iterator<? extends LocalDate> it = value.iterator();
return path.between(it.next(), it.next());
});
_
ここで重要なのは、_?dateOfBirth=…&dateOfBirth=
_(プロパティを2回使用する)と….all(…)
バインディングを使用して、提供されたすべての値にアクセスできるようにすることです。
SpringがdateOfBirth
のUser
- propertyに_@DateTimeFormat
_アノテーションを追加して、Springが受信したStrings
をLocalDate
インスタンスに正しく変換できることを確認してください。
ラムダは現在、_Collection<? extends T>
_を取得しています。これにより、個々の要素のもつれを解消するのが少し難しくなりますが、将来のリリースでは、List
を公開するようにこれを変更できると思います。
コメントに投稿されたので、フィールド名creationDateFrom
とcreationDateTo
に応じて異なる動作をする必要もありました。それを機能させるために、私は次のことをしました:
最初に、_@QueryEntity
_アノテーションと2つのフィールドをエンティティクラスに追加しました。フィールドには次の注釈が付けられました。
@Transient
_したがって、フィールドは永続化されません@Getter(value = AccessLevel.PRIVATE)
Lombokを使用しているため、注釈によりフィールドが応答本文から非表示になります@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
は、urlクエリパラメータの日付を解析するための形式を処理します_@QueryEntity
@Entity
public class MyEntity implements Serializable {
...
@Column(updatable = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private Date creationDate;
@Transient
@Getter(value = AccessLevel.PRIVATE)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private Date creationDateTo;
@Transient
@Getter(value = AccessLevel.PRIVATE)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private Date creationDateFrom;
...
}
_
次に、querydslクラスの生成方法をJPAAnnotationProcessor
からQuerydslAnnotationProcessor
に変更しました。このようにして、_@Transient
_で注釈が付けられたフィールドは、引き続きQMyEntity
で生成されますが、永続化されません。 pomのプラグイン設定:
_<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/annotations</outputDirectory>
<processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
_
最後に、QuerydslBinderCustomizer
を拡張し、creationDateFrom
およびcreationDateTo
に関連するバインディングをカスタマイズしましたが、creationDate
に適切なロジックを適用しました
_@Override
default void customize(QuerydslBindings bindings, QMyEntity root) {
bindings.bind(root.creationDateFrom).first((path, value) ->
root.creationDate.after(value));
bindings.bind(root.creationDateTo).first((path, value) ->
root.creationDate.before(value));
}
_
これらすべてを使用して、基準のいずれか、両方、またはまったく使用せずに日付範囲クエリを実行できます。
_http://localhost:8080/myentities?creation_date_to=2017-05-08
http://localhost:8080/myentities?creation_date_from=2017-01-01
http://localhost:8080/myentities?creation_date_from=2017-01-01&creation_date_to=2017-05-08
_
これは、すべての日付フィールドの汎用バインディングに使用したものであり、常に2つの値、fromおよびtoを期待しています。
_bindings.bind(Date.class).all((final DateTimePath<Date> path, final Collection<? extends Date> values) -> {
final List<? extends Date> dates = new ArrayList<>(values);
Collections.sort(dates);
if (dates.size() == 2) {
return path.between(dates.get(0), dates.get(1));
}
throw new IllegalArgumentException("2 date params(from & to) expected for:" + path + " found:" + values);
});
_
これは日時フィールド用です。日付フィールドの場合、単一のパラメーターを取得する場合、path.eq()
は意味があると思います。