13

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
);
4

3 に答える 3

31

私は最近、JDBI にバンドルされている DropWizard を調べていて、すぐに同じ問題に遭遇しました。残念ながら、JDBI のドキュメントは精彩を欠いており (JavaDoc と、その git リポジトリのいくつかのサンプル単体テストはそれだけでは不十分です)、残念です。

私のサンプル 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 <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 インジェクションの警告Sql Injection値がクエリに直接挿入されるため、 これによって可能性が開けることに注意してください。(準備されたステートメントを使用し、SQL インジェクションから保護する:argクエリおよび注釈の構文とは対照的に)。@Bind少なくとも、@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);

  }
}
于 2013-10-05T17:55:02.847 に答える
2

String Template ライブラリが提供されていると想定されており、その想定が実行時に失敗するためだと思います。アプリケーション 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 が存在しない場合に文句を言うことはありません。

于 2016-10-24T12:57:50.100 に答える