Más Spring Data Couchbase

0
1372
server room 3d illustration with node base programming data design element.concept of big data storage and cloud computing technology.

Índice de contenidos

Introducción

En el tutorial Spring Data Couchbase se creó una aplicación de ejemplo con mapeo de entidad, consultas y caso de creación para empezar a jugar un poco con el soporte que da Spring Data sobre Couchbase. Ahora vamos a profundizar un poco más sobre las posibilidades que nos ofrece el framework para esta base de datos noSQL.

Para seguir los ejemplos de este tutorial se da por hecho que se tiene ya instalado el servidor de Couchbase con el bucket travel-sample y todos los cambios que se le añadieron en el tutorial anterior.

El código de este tutorial se encuentra en el mismo repositorio, pero en la rama more_couchbase:

Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: MacBook Pro Retina 15’ (2,5 GHz Intel Core i7, 16GB DDR3)
  • Sistema operativo: macOS Mojave 10.14.2
  • Versiones del software:
    • Docker: 18.09.0
    • Couchbase Server: 5.0.1
    • Java: 8
    • Spring Boot: 2.1.1.RELEASE

Multiples buckets

Lo primero que vamos a hacer es añadir otro bucket al servidor de Couchbase. Para ello vamos a «Settings» y en la pestaña «Sample Buckets» instalamos «beer-sample». A continuación en «Security» creamos un usuario «beer-sample» con permisos sobre el bucket.

En el proyecto vamos a modelar la entidad Beer.

Al igual que en el ejemplo de los aeropuertos, añadimos en base de datos el campo «_class» para que Spring discrimine los registros de la entidad e indexamos.

Tras crear el repositorio BeerRepository, extendiendo a la interfaz PagingAndSortingRepository, podemos pasar a configurar la referencia al nuevo bucket en la clase de configuración CouchbaseConfig.

Luego creamos el CouchbaseTemplate que usará el nuevo bucket.

Por último ya podemos mapear el repositorio creado de forma que la entidad Beer use la template beerSampleTemplate con el bucket creado, mientras que las demás entidades seguirán usando la template por defecto couchbaseTemplate.

Mapeo de fechas

El ejemplo anterior todavía no va a funcionar tal cual lo tenemos, ya que Spring Data Couchbase no va a saber convertir de String a fecha. Por defecto si sabrá convertir los Date, Calendar y JodaTime (si se encuentra en el classpath) a un timestamp. También es capaz de convertir desde Date a String y viceversa en formato ISO-8601 estableciendo en application.properties:

En nuestro caso, para mapear un LocalDateTime de Java, vamos a tener que configurar nuestros propios conversores. Por lo que creamos dos conversores, uno de String a LocalDateTime y viceversa:

Para hacer los conversores sin ambigüedades se utilizan las anotaciones @WritingConverter y @ReadingConverter. En el caso del BigDecimal también necesitaremos un conversor. Al leer los datos no habrá problemas, pero si hiciéramos el caso de creación veríamos que si fallaría.

Finalmente registramos los conversores en CouchbaseConfig sobrescribiendo el método customConversions():

Ahora sí podemos hacer el servicio y el controlador para mostrar las cervezas 🍻😋.

Implementación de repositorios personalizados

Para nuestro caso en particular con la entidad Beer no nos va a servir la autogeneración de identificadores de Spring, ya que éste no persiste los campos de prefijos y sufijos, en nuestro caso los campos «name» y «brewery_id», campos que seguramente no queramos perder. Hasta que Spring nos de una alternativa tendremos que crear el identificador nosotros mismos.

https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#couchbase.autokeygeneration:

Prefix and suffix for the key can be provided as part of the entity itself, these values are not persisted, they are only used for key generation.

Aprovecharemos la necesidad de crear un identificador antes de insertar la entidad para probar la implementación de repositorios personalizados. Para ello vamos a sobrescribir la implementación del método «save» del CrudRepository de Spring Data.

Como por defecto Spring va a usar la convención por nombres, a partir de aquí, los nombres que elijamos van a tener mucha importancia.

Para reimplementar el método save vamos a crear una nueva interfaz para definirlo sólo a él y no tener que reimplementar todos los métodos de PagingAndSortingRepository.

A continuación creamos la implementación para la entidad Beer que implemente esta nueva interfaz.

Lo siguiente es hacer que la interfaz del repositorio original BeerRepository también extienda a la nueva interfaz que acabamos de crear.

Los repositorios pueden estar compuestos de múltiples implementaciones personalizadas que serán importadas en el orden de su declaración. Las implementaciones personalizadas tendrán más prioridad que las implementaciones bases y que los aspectos de los repositorios. Además, como ya habíamos advertido, la elección de nombres aquí es muy importante. Las implementaciones deben seguir la convención de nombres y acabar en «Impl», como siempre Spring nos dejará cambiar esto por configuración. Para resolver la ambigüedad de múltiples implementaciones del mismo método, Spring usará el nombre de las clases. Debido a todo esto, por ejemplo, si tuviéramos una tercera implementación del método save en una clase llamada CustomSaveRepositoryImpl, Spring usará ésta y no la que tenemos implementada dentro de BeerRepositoryImpl. Y si ninguna de nuestras implementaciones casa con el «nombre de la interfaz + Impl» Spring usará la suya por defecto.

Auditoría

Lo siguiente que vamos a hacer es que la entidad Beer se audite automáticamente.

Antes que nada hay que tener en cuenta que sólo las entidades que poseen un campo con @Version pueden ser auditadas para la creación, si no lo tiene, el framework interpretará la creación como una actualización.

Para auditar una entidad tenemos las siguientes anotaciones:

  • @CreatedBy
  • @CreatedDate
  • @LastModifiedBy
  • @LastModifiedDate

Spring inyectará automáticamente estos valores cuando se persistan las entidades. Los campos anotados con «@xxxDate» deben tener un tipo de fecha compatible, mientras que los anotados con «@xxxBy» pueden ser de cualquier tipo T (pero ambos campos deben ser del mismo tipo).

Ya con la entidad anotada, comenzamos a configurar. Lo primero que debemos crear es un componente AuditorAware que será el que obtenga el valor a inyectar en @LastModifiedBy y @CreatedBy, por ejemplo obtener el usuario del contexto de seguridad que está realizando la operación. Como en la entidad estos campos son String, nuestro AuditorAware trabajará con String.

A continuación debemos de ir a la configuración para declarar este componente y activar la auditoría:

Por último implementamos un pequeño caso de creación, donde lógicamente no añadiremos estos campos al comando para ver cómo el framework nos los rellena.

Ya podemos crear una cerveza haciendo POST a «/beer» y vemos como en la respuesta vienen todos los campos de auditoría rellenos y el identificador generado:

Conclusiones

Hemos podido avanzar un poco más con Spring Data Couchbase ampliando su configuración y posibilidades. Todo dentro de las convenciones y prácticas a las que Spring siempre nos tiene acostumbrados, por lo que la curva de aprendizaje del framework es muy sencilla.

Referencias

Dejar respuesta

Please enter your comment!
Please enter your name here