В веб-приложении, которое использует Spring Data JPA с Hibernate, мы используем веб-пагинация для обеспечения возможности разбиения по страницам и сортировки в различных списках объектов.
@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, что приводит к недопустимому синтаксису.
Например, если URL-адрес изменен для сортировки по «noSuchProperty»:
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)
(Существует также третий вариант исключений, который приводит к org.hibernate.QueryException
, когда @Query
явно определен в методе репозитория.)
Spring Data JPA абстрагирует детали сортировки, разбиения по страницам и обработки этих параметров; однако, похоже, что он не может корректно обрабатывать эти сценарии (т.е. когда указан недопустимый параметр сортировки).
Мы могли бы добавить некоторую дополнительную настраиваемую логику для проверки того, что свойство сортировки действительно существует в сущности; однако мне интересно, есть ли более чистый и централизованный подход для этого, чтобы мы не теряли преимущества и простоту абстракций Spring Data JPA. Мы используем эту возможность сортировки во всем нашем приложении с множеством различных сущностей, поэтому в идеале нам нужен более общий подход, а не необходимость явно определять или проверять свойства сортировки для каждой запрошенной страницы сущности.
В частности, мы фактически расширяем PageableArgumentResolver
, чтобы принять аннотированное значение сортировки по умолчанию, которое предоставляется в нашем контроллере (не показано в примерах кода для простоты), поэтому мы хотели бы просто вернуться к этому порядку сортировки по умолчанию или просто к сортировке по умолчанию порядок для объекта, а не выбросить исключение.
Некоторые идеи и попытки ... Я мог бы использовать QueryCreationListener
, чтобы перехватить создание запроса и получить параметр сортировки; однако на данный момент я не могу изменить запрос. Или я могу расширить и использовать пользовательский PageableArgumentResolver
(мы уже делаем это), чтобы получить параметры сортировки; однако в этот момент у меня нет доступа к объекту или возможности определить, действительно ли объект имеет свойство с таким именем. Мы могли бы явно объявить поддерживаемые свойства; однако, опять же, это подрывает идею централизованной и автоматической обработки этого сценария, не требуя конкретных или заявленных знаний об объектах.
Есть ли какой-либо другой тип перехватчика или аналогичная конструкция, которую я могу использовать для централизованной проверки параметров сортировки на странице и изменения, если необходимо, перед вызовом запроса? Или есть какой-либо тип конфигурации или способ, которым Spring может автоматически обрабатывать этот сценарий, чтобы он более изящно обрабатывал недопустимые параметры сортировки?