Ya hemos visto anteriormente otros posts de Apache Camel. Hoy veremos como hacer las operaciones de BBDD con JPA.
Como siempre empezaremos por la configuración. En cuanto a librerías añadimos las siguientes:
- El componente camel-jpa-starter de Apache Camel que nos permitirá usar el componente JPA.
- La librería hibernate-entitymanager que nos permitirá utilizar las anotaciones de hibernate.
Debemos recordar un poco cual es el fundamento de JPA y es la cualidad de poder manejar datos relacionales como objetos Java. Permitiéndonos manejar más fácilmente dentro de clases Java la información de una BBDD. Estas clases serán las denominadas Entidades. Y como parte de la API de JPA se encuentra JPQL, un lenguaje que nos permitirá realizar consultas sobre esas entidades.
Gracias a Spring boot y los starter no tendremos que realizar mucha configuración, pero a nivel de la clase Java deberemos añadir una cuantas anotaciones:
@Entity(name = "BOOK") @Table(name = "BOOK") @NamedQuery(name = "findAll", query = "SELECT b FROM BOOK b") public class Book { @JsonProperty @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @JsonProperty private String name; @JsonProperty private String author; }
@Entity nos permitirá indicar que es una clase a ser gestionada a través de JPA. Con @Id indicaremos que cual es su primary key y con @GeneratedValue se gestionará su generación, en el caso de MySQL será Auto.
En el primer ejemplo que veremos será muy similar al del componente SQL solo que usaremos JPQL y debemos indicar cual es la entidad sobre la que vamos a realizar la consulta.
rest().get("book/{id}").description("Details of an book by id") .outType(Book.class).produces(MediaType.APPLICATION_JSON_VALUE).route() .toD("jpa://" + Book.class.getName() + "?query=select b from " + Book.class.getName()+ " b where b.id= ${header.id}", 5) .log("--- select a book ${body} ---");
Lo primero que tenemos que hacer es indicar cual es la entidad sobre la cual vamos a trabajar. Luego si queremos hacer una consulta JPQL debemos añadir el parámetro 'query'.
Además en este caso concreto queremos obtener un libro en base a un identificador que viene como parámetro de la request, a través del lenguaje de expresión. Para poder conseguir esto utilizaremos el método ToD en vez de To. El cual nos permitirá enrutar de forma dinámica el flujo y que sea interpretado el lenguaje de expresión.
Otra de las cualidades de JPA son las namedQuery, las cuales nos permiten definir consultas JPQL a nivel de la clase. En el siguiente ejemplo veremos como utilizar las namedQueries a través del componente JPA. La query a utilizar es findAll.
rest().get("book").produces(MediaType.APPLICATION_JSON_VALUE).route() .to("jpa://"+ Book.class.getName() + "?resultClass="+ Book.class.getName() + "&namedQuery=findAll") .log("---select all books---");
En este segundo ejemplo podemos ver la diferencia de usar el método outType para indicar el tipo de objeto a la salida. O si por lo contrario podemos indicarlo a través del query parameter resultClass del propio componente JPA.
También podemos hacer operaciones que nos permitan guardar o persistir dichos objetos en la BBDD. Como podemos ver en el ejemplo, en el caso de almacenar el valor, el funcionamiento es muy sencillo. Solo debemos indicar el objeto a persistir y utilizar el query parameter usePersist para indicar que debe almacenar el objeto. Por supuesto, en el flujo deben ir los datos del objeto a guardar.
rest().post("book").produces(MediaType.APPLICATION_JSON_VALUE).type(Book.class) .route().routeId("postBookRoute").log("--- binded ${body} ---") .to("jpa:" + Book.class.getName() + "?usePersist=true") .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(201)).setBody(constant(null));
Para el caso de las actualizaciones y borrado de datos, necesitamos utilizar el query parameter useExecuteUpdate. En este ejemplo haremos uso del método process para crear el objeto a actualizar a partir de los datos de la cabecera y el cuerpo del mensaje.
rest().put("book/{id}").produces(MediaType.APPLICATION_JSON_VALUE).type(Book.class).route().choice() .when().simple("${header.id} < 1").bean(BookRouter.class, "negativeId").otherwise() .process(new Processor() { @Override public void process(final Exchange exchange) { Book book = exchange.getIn().getBody(Book.class); Integer id = Integer.valueOf(exchange.getIn().getHeader("id").toString()); book.setId(id); exchange.getIn().setBody(book, Book.class); } }).to("jpa:" + Book.class.getName() + "?useExecuteUpdate=true") .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant(null));
Por último veremos el ejemplo asociado al borrado de datos. Y de paso veremos como realizar consultas nativas. Es decir utilizaremos lenguaje SQL común y no JPQL.
rest().delete("book/{id}").produces(MediaType.APPLICATION_JSON_VALUE).route() .toD("jpa:com.example.home.ApacheCamelRestExample.pojo.Book" + "?nativeQuery=DELETE FROM library.BOOK where id = ${header.id}&useExecuteUpdate=true") .setHeader(Exchange.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON_VALUE)) .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant(null));
Como veis algunas consultas pueden ser algo más difíciles que usar simple SQL. Pero también otras se simplifican muchísimo y siempre estamos trabajando con objetos. Lo cual, al programar en un lenguaje orientado a objetos es muy de agradecer.
No hay comentarios:
Publicar un comentario