tutorial mediante framework example español desarrollo aplicaciones spring spring-data spring-data-jpa spring-data-rest querydsl

mediante - spring boot querydsl



¿Se puede utilizar la integración QueryDSL de Spring Data REST para realizar consultas más complejas? (3)

Como se publicó en algún comentario, también tuve la necesidad de tener un comportamiento diferente según el nombre de campo creationDateFrom y creationDateTo . Para hacerlo funcionar hice lo siguiente:

Primero agregué la anotación @QueryEntity y dos campos más a mi clase de entidad. Los campos fueron anotados con:

  • @Transient para que los campos no sean persistentes
  • @Getter(value = AccessLevel.PRIVATE) ya que estamos usando Lombok, la anotación oculta el campo del cuerpo de la respuesta
  • @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) se encarga del formato para analizar la fecha en el parámetro de consulta url

@QueryEntity @Entity public class MyEntity implements Serializable { ... @Column(updatable = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private Date creationDate; @Transient @Getter(value = AccessLevel.PRIVATE) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private Date creationDateTo; @Transient @Getter(value = AccessLevel.PRIVATE) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private Date creationDateFrom; ... }

Luego cambié la forma de generar las clases JPAAnnotationProcessor de JPAAnnotationProcessor a QuerydslAnnotationProcessor . De esta manera, los campos anotados con @Transient todavía se generan en QMyEntity pero no se conservan. Configuracion de plugin en pom:

<plugin> <groupId>com.mysema.maven</groupId> <artifactId>apt-maven-plugin</artifactId> <version>1.1.3</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>process</goal> </goals> <configuration> <outputDirectory>target/generated-sources/annotations</outputDirectory> <processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor> </configuration> </execution> </executions> </plugin>

Finalmente, extendí el QuerydslBinderCustomizer y personalicé los enlaces relacionados con creationDateFrom y creationDateTo pero aplicando la lógica correcta a la creationDate

@Override default void customize(QuerydslBindings bindings, QMyEntity root) { bindings.bind(root.creationDateFrom).first((path, value) -> root.creationDate.after(value)); bindings.bind(root.creationDateTo).first((path, value) -> root.creationDate.before(value)); }

Con todo esto, puede hacer consultas de rango de fechas utilizando uno, ambos o ninguno de los criterios:

http://localhost:8080/myentities?creation_date_to=2017-05-08 http://localhost:8080/myentities?creation_date_from=2017-01-01 http://localhost:8080/myentities?creation_date_from=2017-01-01&creation_date_to=2017-05-08

Actualmente estoy creando una API REST en la que quiero que los clientes filtren fácilmente la mayoría de las propiedades de una entidad específica. El uso de QueryDSL en combinación con Spring Data REST ( un ejemplo de Oliver Gierke ) me permite obtener fácilmente el 90% de lo que quiero al permitir a los clientes filtrar mediante la combinación de parámetros de consulta que se refieren a propiedades (por ejemplo, /users?firstName=Dennis&lastName=Laumen ).

Incluso puedo personalizar la asignación entre los parámetros de consulta y las propiedades de una entidad implementando la interfaz QuerydslBinderCustomizer (por ejemplo, para búsquedas que no distinguen entre mayúsculas y minúsculas o coincidencias parciales de cadenas). Todo esto es genial, sin embargo, también quiero que los clientes puedan filtrar algunos tipos usando rangos. Por ejemplo, con respecto a una propiedad como la fecha de nacimiento, me gustaría hacer algo como lo siguiente, /users?dateOfBirthFrom=1981-1-1&dateOfBirthTo=1981-12-31 . Lo mismo ocurre con las propiedades basadas en números, /users?idFrom=100&idTo=200 . Tengo la sensación de que esto debería ser posible utilizando la interfaz de QuerydslBinderCustomizer pero la integración entre estas dos bibliotecas no está documentada en forma extensa.

En conclusión, ¿es posible usar Spring Data REST y QueryDSL? ¿Si es así, cómo?


Creo que deberías poder hacer que esto funcione con la siguiente personalización:

bindings.bind(user.dateOfBirth).all((path, value) -> { Iterator<? extends LocalDate> it = value.iterator(); return path.between(it.next(), it.next()); });

La clave aquí es usar ?dateOfBirth=…&dateOfBirth= (usar la propiedad dos veces) y el enlace ….all(…) que le dará acceso a todos los valores proporcionados.

Asegúrese de agregar la anotación @DateTimeFormat a la dateOfBirth dateOfBirth - User para que Spring pueda convertir las Strings entrantes en instancias de LocalDate correctamente.

La lambda actualmente recibe una Collection<? extends T> Collection<? extends T> que hace que desenredar los elementos individuales sea un poco más doloroso de lo necesario, pero creo que podemos cambiar esto en una versión futura para exponer una List .


Esto es lo que usé para un enlace genérico para todos los campos de fecha, siempre esperando 2 valores, desde y hasta.

bindings.bind(Date.class).all((final DateTimePath<Date> path, final Collection<? extends Date> values) -> { final List<? extends Date> dates = new ArrayList<>(values); Collections.sort(dates); if (dates.size() == 2) { return path.between(dates.get(0), dates.get(1)); } throw new IllegalArgumentException("2 date params(from & to) expected for:" + path + " found:" + values); });

Esto es para los campos de fecha y hora. Para un campo de fecha, al obtener un solo parámetro, path.eq() tiene sentido, supongo.