habe ich vor kurzem DropWizard erforscht, die mit JDBI kommt gebündelt und kam schnell über das gleiche Problem. Leider hat JDBI eine lustlose Dokumentation (JavaDoc und einige Sample-Unit-Tests auf seinem git-Repository machen es nicht alleine), was enttäuschend ist.
Hier ist, was ich herausgefunden, dass erzielt eine dynamische Ordnung in einem Objekt-API SQL-Code für JDBI basiert auf meiner Probe DAO:
@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 - diese Anmerkung ist das, was uns die <arg>
Syntax verwenden können in die Abfragen. Diese Argumente werden durch einen beliebigen Wert ersetzt, den wir über die @Define
Annotation bereitstellen.
Um in der Lage sein, diese Funktion, die ich zusätzlich diese Abhängigkeit zu meiner pom.xml
Datei hinzufügen musste verwenden:
<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-WARNUNG Es sollte beachtet werden, dass diese uns da die Werte bis zu Sql Injection
eröffnet werden direkt in die Abfrage eingefügt. (Im Gegensatz zu :arg
Syntax in der Abfrage und @Bind
Annotation, die vorbereitete Anweisungen verwendet und schützt gegen SQL-Injektion). Zumindest sollten Sie die Parameter bereinigen, die für die Felder @Define
verwendet werden. (Einfaches Beispiel für DropWizard unten).
@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);
}
}
Das hat mich die ganze Nacht verrückt gemacht, vor allem der Mangel an Dokumentation. @ krdx Ihre Antwort ist gründlich und sehr hilfreich, danke. Wenn möglich, könnten Sie erklären, warum '@Bind ("foo") String foo' den String nicht mit ': foo' in die Abfrage einfügt? oder wenn Sie eine Dokumentation gefunden haben, die dies abdeckt? –
Diese Antwort rettet mein Leben auch. ''org.antlr: singtemplate: 3.2.1'' funktioniert auch für mich, aber die neueste' 4.0.2' nicht. Darf ich fragen, warum diese Annotation '@ UseStringTemplate3StatementLocator' eine solche Abhängigkeit benötigt, damit sie funktioniert – DerekY