【问题标题】:Spring Data JPA Invalid page.sort ParametersSpring Data JPA 无效的 page.sort 参数
【发布时间】:2012-06-29 05:31:33
【问题描述】:

在将 Spring Data JPA 与 Hibernate 结合使用的 Web 应用程序中,我们利用 web pagination 功能在各种实体列表中提供分页和排序功能。

@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 中将实体属性定义为特殊排序 request parameters,其中 page.sort 值实际上与要排序的实体中的属性匹配。

<table>
    <thead>
        <tr>
            <th><a href="?page.sort=propertyX&amp;page.sort.dir=asc">Property X</a></th>
            <th><a href="?page.sort=propertyY&amp;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)

(当 @Query 在 Repository 方法上显式定义时,还有第三种类型的异常会导致 org.hibernate.QueryException。)

Spring Data JPA 抽象出这些参数的排序、分页和处理的细节;但是,它似乎不能很好地处理这些场景(即指定了无效的排序参数)。

我们可以添加一些额外的自定义逻辑来验证实体上确实存在排序属性;但是,我想知道是否有一种更清洁、更集中的方法来做到这一点,这样我们就不会失去 Spring Data JPA 抽象的好处和简单性。我们在整个应用程序中使用这种排序功能来处理许多不同的实体,因此理想情况下,我们需要更多的通用方法,而不是必须为请求的每个实体页面显式定义或检查排序属性。

具体来说,我们实际上扩展了PageableArgumentResolver 以接受控制器中提供的带注释的排序默认值(为简单起见,代码示例中未说明),因此我们只想回退到此默认排序顺序,或者只是实体的默认排序顺序,而不是抛出异常。

一些想法和尝试.. 我可以使用QueryCreationListener 来拦截查询创建并获取排序参数;但是,此时我实际上无法修改查询。或者,我可以扩展并使用自定义的PageableArgumentResolver(我们已经这样做了)来获取排序参数;但是,我当时无权访问该实体,也无法确定该实体是否实际上具有该名称的属性。我们可以显式声明支持的属性;然而,这再次违背了集中和自动处理这种情况而不需要特定或声明的实体知识的想法。

是否有任何其他类型的拦截器或类似构造可以用来集中验证可分页排序参数并在调用查询之前进行必要的修改?或者 Spring 是否有任何类型的配置或方式可以自动处理这种情况,以便更优雅地处理无效的排序参数?

【问题讨论】:

    标签: java spring spring-data spring-data-jpa


    【解决方案1】:

    我正在查看代码,我认为更多的堆栈跟踪会有所帮助。但据我所知,如果你有心情重写一些 Spring 代码,我认为有两个地方可能需要解决。

    这里有两种情况,第一种情况是您传递对象/表中不存在的排序字段。您真正想要的是始终默默地忽略该错误参数,而不仅仅是在传递 1PageableArgumentResolver]1 时。我认为它应该是AbstractQueryCreator(因此是JpaQueryCreator)上的一个选项,以忽略排序中的错误参数。

    应该解决的第二部分可能是PageableArgumentResolver。如果您传递空字符串或像%20 这样没有意义的东西,那么它应该忽略该参数并且不将其发送到PageRequest

    快乐的黑客和好运。阅读您的帖子让我意识到我的网站很容易遇到同样的问题,我真的没有好的解决方案。

    【讨论】:

      【解决方案2】:

      我认为改进PageableArgumentResolver 以优雅地处理这些场景。它可以尝试从作为Sort 提交的String 创建一个PropertyPath 实例,从而确保它是一个有效的实例。我对默认情况下简单地删除无效的String 是否有意义感到有些不安,这将返回根本没有排序的结果。这可能是最无缝的体验,但也可能导致寻找结果未排序原因的繁琐尝试。

      但是,它。如果您可以针对 Spring Data Commons 提出 JIRA 票并在此处链接此票,那就太酷了。如果您已经充实了一个可行的实现,请随意打开一个拉取请求。感谢您已经提出这个问题!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-24
        • 2019-01-27
        • 2018-06-01
        • 2019-07-02
        • 1970-01-01
        • 2015-02-28
        • 2021-01-15
        • 2023-02-22
        相关资源
        最近更新 更多