用spring处理动态查询

ha5z0ras  于 2021-07-23  发布在  Java
关注(0)|答案(3)|浏览(537)

我试图解决的问题是,使用用户提供的动态查询过滤表。需要描述问题的实体:
表格: run_events 柱: user_id, distance, time, speed, date, temperature, latitude, longitude 问题陈述是基于filterquery获取用户的run\u事件。查询的格式为,

((date = '2018-06-01') AND ((distance < 20) OR (distance > 10))

这个查询可以组合多个字段和多个and/or操作。
解决这个问题的一种方法是使用hibernate并将filterquery与您的查询连接起来。

"select * from run_events where user_id=:userId and "+filterQuery;

这需要您编写整个实现并使用会话,即。

String q = select * from run_events where user_id=:userId and "+filterQuery;

        Query query = getSession().createQuery(q);
        query.setParameter("userId", userId);

        List<Object[]> result = query.list();
        List<RunEvent> runEvents = new ArrayList<>();
        for(Object[] obj: result){
            RunEvent datum = new RunEvent();
            int index = -1;
            datum.setId((long) obj[++index]);
            datum.setDate((Timestamp) obj[++index]);
            datum.setDistance((Long) obj[++index]);
            datum.setTime((Long) obj[++index]);
            datum.setSpeed((Double) obj[++index]);
            datum.setLatitude((Double) obj[++index]);
            datum.setLongitude((Double) obj[++index]);
            datum.setTemperature((Double) obj[++index]);
            runEvents.add(datum);
        }

这看起来不是很优雅,我想使用@query注解来实现这一点。

@Query(value = "select run_event from RunEvent where user_id = :userId and :query order by date asc")
    List<RunEvent> getRunningData(@Param("userId") Long userId,
                                      @Param("query") String query,
                                   );

但这不起作用,因为在查询中不能以这种方式提供作为参数的查询。
有没有更好的、优雅的方法来使用jpa完成这个任务?
对于这种查询,使用规范和 predicate 似乎非常复杂。

6g8kf2rb

6g8kf2rb1#

回答一个简单的问题:这是不可能的 @Query .
在至少99%的情况下,这也是一个糟糕的设计决策,因为使用用户(或任何不受严格控制的源代码)提供的字符串通过字符串连接构造sql查询会使您面临sql注入攻击。
相反,您应该用某种api(criteria、querydsl、querybyexample)对查询进行编码,并使用它来创建查询。关于这个问题有很多问题和答案,所以我在这里不重复了。请参见带有任意and子句的动态spring数据jpa存储库查询示例
如果您坚持使用sql或jpql代码段作为输入,那么使用字符串连接的自定义实现就是一个不错的选择。

0sgqnhkj

0sgqnhkj2#

这为sql注入打开了攻击。也许这就是为什么这个功能是不可能的。
通常,通过在末尾附加随机过滤器并运行它们来构造查询是个坏主意。
如果查询字符串做了一些尴尬的事情,比如
选择*from foo,其中id=1234或true;
从而返回所有行并给db带来沉重的负载,从而可能停止整个应用程序?
解决方案:您可以使用多个条件在jpa中动态过滤它,但是您需要自己解析querystring并添加必要的条件。

cnwbcb6i

cnwbcb6i3#

您可以使用kolobok并忽略具有空值的字段。例如,创建一个类似于bellow的方法

findByUserIdAndDistanceaLessThanAndDistancebGreaterThan....(String userid,...)

并仅使用筛选器参数调用该方法,而其他参数为null

相关问题