如何在JDBI中使用SQL对象查询进行排序?
我想做类似的事情:
@SqlQuery(
"SELECT * FROM users " +
"WHERE something = :something " +
"ORDER BY :orderBy :orderDir"
)
List<User> 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<User> getUsers(
@Bind("something") Integer something
, @Bind("orderBy") OrderBy orderBy
, @Bind("orderDir") OrderDir orderDir
);
答案 0 :(得分:29)
我最近一直在探索与JDBI捆绑在一起的DropWizard,很快就遇到了同样的问题。不幸的是,JDBI的文档乏善可陈(JavaDoc和它的git存储库上的一些样本单元测试并没有单独测试),这令人失望。
这是我发现的基于我的示例DAO在JDBI的Sql Object 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 <orderby> <order> limit :limit offset :offset")
List<Product> 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 - 此注释允许我们在查询中使用<arg>
语法。这些参数将被我们通过@Define
注释提供的任何值替换。
为了能够使用此功能,我必须另外将此依赖项添加到我的pom.xml
文件中:
<dependency>
<groupId>antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>2.3b6</version> <!-- I am not sure if this specific version is meant to be used though -->
</dependency>
SQL INJECTION WARNING
应该注意的是,由于这些值直接插入到查询中,因此我们可以使用Sql Injection
。 (与查询中的:arg
语法相对应,@Bind
注释使用预准备语句并防止sql注入)。至少应该清理将用于@Define
字段的参数。 (下面的DropWizard的简单示例)。
@Path("/products")
@Produces(MediaType.APPLICATION_JSON)
public class ProductsResource {
private static ImmutableSet<String> 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
// i.e. public List<Product> 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<Product> 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 <orderby>
if (order != "asc" && order != "desc") order = "asc"; //sanitize <order>
limit = perpage.get();
offset = page.get() < 0 ? 0 : page.get() * limit;
return dao.getProducts(orderBy, order, limit, offset);
}
}
答案 1 :(得分:2)
我认为这是因为假设提供了字符串模板库,并且该假设在运行时失败。在应用程序POM中添加以下内容应该可以解决问题:
<dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>3.2.1</version>
</dependency>
通过查看JDBI 2 pom,您可以看到以下内容:
<dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>3.2.1</version>
<optional>true</optional>
</dependency>
意思是JDBI不会因缺少stringtemplate lib而抱怨。
答案 2 :(得分:-1)
@SqlQuery("SELECT * FROM incident_events WHERE incident_id=:incidentId ORDER BY event_time DESC LIMIT :limit OFFSET :offset")
List<IncidentEvent> getPaginated(@Bind("incidentId") int incidentId, @Bind("limit") int limit, @Bind("offset") int offset);