Hibernate で Spring Data JPA を使用する Web アプリケーションでは、Web ページネーション機能を利用して、エンティティのさまざまなリストでページングおよびソート機能を提供します。
@Controller
public class MyEntityController {
@RequestMapping(method = RequestMethod.GET)
public ModelAndView list(Pageable pageable) { ... }
}
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
super.addArgumentResolvers(argumentResolvers);
argumentResolvers.add(new PageableArgumentResolver());
}
}
public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, String> {
Page<MyEntity> findByPropertyX(String propertyX, Pageable pagable);
}
これにより、レンダリングされた html でエンティティ プロパティを特別な並べ替えリクエスト パラメータとして定義できます。このpage.sort
値は、並べ替え対象のエンティティ内のプロパティと実際に一致します。
<table>
<thead>
<tr>
<th><a href="?page.sort=propertyX&page.sort.dir=asc">Property X</a></th>
<th><a href="?page.sort=propertyY&page.sort.dir=asc">Property Y</a></th>
</tr>
</thead>
<tbody>...</tbody>
</table>
これにより、次のような結果の URL が生成されます。
http://host/context-root/entities/?page.sort=propertyX&page.sort.dir=asc
問題は、ユーザーが URL を変更して、page.sort
存在しない列/プロパティ名を参照する無効なプロパティを使用するか、さらに悪いことに、構文が無効になる無効な JPA クエリ文字を使用する可能性があることです。
たとえば、「noSuchProperty」でソートするように URL を変更した場合:
http://host/context-root/entities/?page.sort=noSuchProperty&page.sort.dir=asc
ただし、このプロパティは存在しないため、次の例外がスローされます。
java.lang.IllegalArgumentException: No property noSuchProperty found for type class com.my.company.MyEntity
at org.springframework.data.repository.query.parser.Property.<init>(Property.java:76)
. . .
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:86)
. . .
at $Proxy68.findByPropertyX(Unknown Source)
at com.my.company.MyEntityRepository.findByPropertyX(MyEntityRepository.java:17
同様に、URL が """ などの無効なクエリ構文文字に変更された場合:
http://host/context-root/entities/?page.sort=%22&page.sort.dir=asc
次のエラーが発生します。
java.lang.StackOverflowError
java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)
. . .
org.springframework.data.repository.query.parser.Property.create(Property.java:326)
org.springframework.data.repository.query.parser.Property.create(Property.java:326)
org.springframework.data.repository.query.parser.Property.create(Property.java:326)
org.springframework.data.repository.query.parser.Property.create(Property.java:326)
( Repository メソッドで が明示的に定義されているorg.hibernate.QueryException
場合に発生する 3 番目の種類の例外もあります。)@Query
Spring Data JPA は、これらのパラメーターの並べ替え、ページング、および処理の詳細を抽象化します。ただし、これらのシナリオ (つまり、無効な並べ替えパラメーターが指定されている場合) を適切に処理していないようです。
追加のカスタム ロジックを追加して、エンティティに並べ替えプロパティが実際に存在することを検証できます。ただし、Spring Data JPA 抽象化の利点とシンプルさを失わないように、これを行うためのよりクリーンで集中化されたアプローチがあるかどうか疑問に思っています。この並べ替え機能はアプリ全体でさまざまなエンティティを使用して使用するため、要求されたすべてのエンティティ ページの並べ替えプロパティを明示的に定義または確認するのではなく、より一般的なアプローチが必要になるのが理想的です。
PageableArgumentResolver
具体的には、コントローラーで提供される注釈付きの並べ替えのデフォルト値を受け入れるように を実際に拡張します (簡単にするためにコード例には示されていません)。例外をスローするのではなく、エンティティに対して。
いくつかのアイデアと試み.. a を使用しQueryCreationListener
て、クエリの作成を傍受し、並べ替えパラメーターを取得できます。ただし、その時点でクエリを実際に変更することはできません。または、カスタムを拡張して使用することもできますPageableArgumentResolver
(これは既に行っています)。並べ替えパラメーターを取得します。ただし、その時点でエンティティにアクセスすることも、エンティティが実際にその名前のプロパティを持っているかどうかを判断することもできません。サポートされているプロパティを明示的に宣言できます。ただし、繰り返しになりますが、これは、エンティティの特定または宣言された知識を必要とせずに、このシナリオを一元的かつ自動的に処理するという考えを無効にします。
ページング可能な並べ替えパラメーターを一元的に検証し、クエリを呼び出す前に必要に応じて変更するために利用できる他のタイプのインターセプターまたは同様の構造はありますか? または、Spring がこのシナリオを自動的に処理して、無効な並べ替えパラメーターをより適切に処理できるような構成または方法はありますか?