JDBI SQL对象查询中的动态顺序

如何在JDBI中使用SQL对象查询进行排序?

我想做的事情如下:

@SqlQuery( "SELECT * FROM users " + "WHERE something = :something " + "ORDER BY :orderBy :orderDir" ) List getUsers( @Bind("something") Integer something , @BindOrderBy("orderBy") String orderBy , @BindOrderDir("orderDir") String orderDir ); 

要么

 @SqlQuery( "SELECT * FROM users " + "WHERE something = :something " + "ORDER BY :orderBy :orderDir" ) List getUsers( @Bind("something") Integer something , @Bind("orderBy") OrderBy orderBy , @Bind("orderDir") OrderDir orderDir ); 

我最近一直在探索与JDBI捆绑在一起的DropWizard,很快就遇到了同样的问题。 不幸的是,JDBI的文档乏善可陈(JavaDoc和git存储库上的一些样本unit testing并没有单独测试),这令人失望。

这是我发现的基于我的示例DAO在JDBI的Sql对象API中实现动态顺序:

 @UseStringTemplate3StatementLocator public interface ProductsDao { @RegisterMapperFactory(BeanMapperFactory.class) // will map the result of the query to a list of Product POJOs(Beans) @SqlQuery("select * from products order by   limit :limit offset :offset") List getProducts(@Define("orderby") String orderBy, @Define("order") String order, @Bind("limit") int limit, @Bind("offset") int offset); @SqlQuery("select count(*) from products") int getProductsCount(); } 

@ UseStringTemplate3StatementLocator – 这个注释允许我们在查询中使用语法。 这些参数将被我们通过@Define注释提供的任何值替换。

为了能够使用此function,我不得不另外将此依赖项添加到我的pom.xml文件中:

  antlr stringtemplate 2.3b6   

SQL注意警告应该注意,这会使我们开始使用Sql Injection因为这些值直接插入到查询中。 (在查询和@Bind注释中使用:arg语法,它使用预处理语句并防止sql注入)。 至少应该清理将用于@Define字段的参数。 (下面的DropWizard的简单示例)。

 @Path("/products") @Produces(MediaType.APPLICATION_JSON) public class ProductsResource { private static ImmutableSet orderByChoices = ImmutableSet.of("id", "name", "price", "manufactureDate"); private final ProductsDao dao; public ProductsResource(ProductsDao dao) { this.dao = dao; } @GET // Use @InjectParam to bind many query parameters to a POJO(Bean) instead. // https://jersey.java.net/apidocs/1.17/jersey/com/sun/jersey/api/core/InjectParam.html // ie public List index(@InjectParam ProductsRequest request) // Also use custom Java types for consuming request parameters. This allows to move such validation/sanitization logic outside the 'index' method. // https://jersey.java.net/documentation/1.17/jax-rs.html#d4e260 public List index(@DefaultValue("id") @QueryParam("orderby") String orderBy, @DefaultValue("asc") @QueryParam("order") String order, @DefaultValue("20") @QueryParam("perpage") IntParam perpage, @DefaultValue("0") @QueryParam("page") IntParam page) int limit, offset; order = order.toLowerCase(); orderBy = orderBy.toLowerCase(); if (!orderByChoices.contains(orderBy)) orderBy = "id"; //sanitize  if (order != "asc" && order != "desc") order = "asc"; //sanitize  limit = perpage.get(); offset = page.get() < 0 ? 0 : page.get() * limit; return dao.getProducts(orderBy, order, limit, offset); } } 

我认为这是因为假定提供了字符串模板库,并且该假设在运行时失败。 在应用程序POM中添加以下内容应该可以解决问题:

  org.antlr stringtemplate 3.2.1  

通过查看JDBI 2 pom,您可以看到以下内容:

  org.antlr stringtemplate 3.2.1 true  

意思是JDBI不会抱怨没有stringtemplate lib。

事实certificate,您可以像这样将ORDER BY添加到查询中

 @SqlQuery("SELECT * FROM incident_events WHERE incident_id=:incidentId ORDER BY event_time DESC LIMIT :limit OFFSET :offset") List getPaginated(@Bind("incidentId") int incidentId, @Bind("limit") int limit, @Bind("offset") int offset);