Hace ya como un año publiqué un post en el que explicaba como configurar un proyecto con jOOQ, que es una librería de acceso a base de datos. Vuelvo con ello, esta vez con Spring Boot y su sencillez 🙂
Concepto:
Con la nueva versión de Spring Boot, la 1.3, aparte de cosas como las developer tools, se han añadido nuevas ‘autoconfiguraciones’, entre ellas, para jOOQ. En este post veremos como configurar fácilmente jOOQ en un proyecto Spring Boot. ¡Al lío!
Entorno usado:
Java JDK 1.8
Maven 3.3.9
Git 2.6.3
IDE Intellij 15.0.2 Ultimate version
Pasos:
1. Crearemos un nuevo proyecto Maven básico con Spring Boot igual que siempre. Nuestro pom inicial quedaría así:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edwise.springbootseries.jooq</groupId>
<artifactId>springboot-series-jooq</artifactId>
<version>0.1.0</version>
<packaging>jar</packaging>
<name>springboot-series-jooq</name>
<description>Test project for Spring Boot new featture: jooq autoconfig</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<testSource>${java.version}</testSource>
<testTarget>${java.version}</testTarget>
</configuration>
</plugin>
</plugins>
</build>
</project>
Para este caso no he añadido el starter web, simplemente el de logging para tener logback y slf4j. Así como el starter de tests, y assertj.
Añadimos también nuestra clase main para Spring Boot.
2. Añadimos ahora a nuestro pom la dependencia del nuevo ‘starter’ para jooq. Añadimos también la de H2 para usarlo como base de datos:
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
...
Y con esto ya casi está. Spring Boot configurará jOOQ con valores por defecto y tendremos disponible un bean de la clase DSLContext.
Solo nos falta el código generado por jOOQ para las tablas de nuestra BD. Vamos a generarlos.
3. Para hacer más sencilla la ejecución de nuestra aplicación, primero vamos a hacer unos scripts sql para la creación y borrado de nuestra base de datos, y los ejecutaremos con el plugin ‘sql-maven-plugin‘ de maven.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>execute</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:${basedir}/target/springbootseriesjooqDB</url>
<srcFiles>
<srcFile>${basedir}/src/main/resources/delete.sql</srcFile>
<srcFile>${basedir}/src/main/resources/schema.sql</srcFile>
<srcFile>${basedir}/src/main/resources/data.sql</srcFile>
</srcFiles>
</configuration>
</plugin>
Podéis consultar los tres ficheros .sql aquí. No tienen mucho misterio.
4. Ahora añadimos a nuestro pom.xml el plugin de jOOQ para la generación de su código:
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<jdbc>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:${basedir}/target/springbootseriesjooqDB</url>
</jdbc>
<generator>
<name>org.jooq.util.DefaultGenerator</name>
<database>
<name>org.jooq.util.h2.H2Database</name>
<includes>.*</includes>
<excludes/>
<inputSchema>PUBLIC</inputSchema>
</database>
<target>
<packageName>sample.jooq.domain</packageName>
<directory>${basedir}/generated-jooq-code/main/java</directory>
</target>
</generator>
</configuration>
</plugin>
El plugin es similar a como lo hicimos en el post anterior de jOOQ:
– Asignamos la ejecución del plugin al ‘goal’ generate de maven.
– Añadimos la dependencia de H2.
– En la configuración le pasamos la url de base de datos h2 (línea 21), la misma que en el sql-maven-plugin, y en la información para la generación de código, la ruta donde generarlo (línea 33).
Con ejecutar ahora un ‘mvn package’ tendremos generado el código de jOOQ.
5. Vamos ahora a probarlo. Para ello creamos un DAO simplón, anotado como @Repository, tal que así:
package com.edwise.springbootseries.jooq.dao;
// imports...
@Repository
public class BooksDao {
private static final Logger LOG = LoggerFactory.getLogger(BooksDao.class);
private final DSLContext create;
@Autowired
public BooksDao(DSLContext dslContext) {
this.create = dslContext;
}
public Result<Record> getAllBookCharacters() {
Result<Record> result = create
.select()
.from(Tables.BOOK_CHARACTER)
.fetch();
LOG.info("Resultado query getAllBookCharacters: \n{}", result);
return result;
}
public Result<Record> getAllBookCharactersOrderByName() {
Result<Record> result = create
.select()
.from(Tables.BOOK_CHARACTER)
.orderBy(Tables.BOOK_CHARACTER.NAME)
.fetch();
LOG.info("Resultado query getAllBookCharactersOrderByName: \n{}", result);
return result;
}
public Optional<Record> getBookCharacterById(int id) {
Optional<Record> result = create
.select()
.from(Tables.BOOK_CHARACTER)
.where(Tables.BOOK_CHARACTER.ID.equal(id))
.orderBy(Tables.BOOK_CHARACTER.NAME)
.fetchOptional();
LOG.info("Resultado query getBookCharacterById: \n{}",s result);
return result;
}
}
Lo que hacemos es nada más que injectar el bean DSLContext (por contructor). Implementamos también varios métodos para recuperar distinta información de nuestra base de datos, usando la sintaxis de jOOQ.
No necesitamos abrir la conexión ni instanciar nada, como hacíamos en el post de jOOQ. Todo nos lo gestiona Spring Boot.
6. Para automatizar la prueba, he implementado un test de integración (carga todo el contexto de Spring) para probar nuestro DAO y ver que jOOQ funciona:
package com.edwise.springbootseries.jooq.dao;
// imports...
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class BooksDaoIT {
private static final Logger LOG = LoggerFactory.getLogger(BooksDaoIT.class);
private static final int EXISTING_CHAR_ID = 4;
private static final int NOT_EXISTING_CHAR_ID = 13;
@Autowired
private BooksDao booksDao;
@Test
public void getAllBookCharactersShouldReturnAllTheChars() {
Result<Record> allBookCharacters = booksDao.getAllBookCharacters();
allBookCharacters.stream()
.map(record -> record.getValue(Tables.BOOK_CHARACTER.NAME))
.forEach(name -> LOG.info("Char: {}", name));
assertThat(allBookCharacters)
.extracting(record -> record.getValue(Tables.BOOK_CHARACTER.NAME))
.contains("Samwise", "Gandalf", "Frodo", "Saruman", "Aragorn");
}
@Test
public void getAllBookCharactersOrderByNameShouldReturnCharsSorted() {
Result<Record> allBookCharactersByName =
booksDao.getAllBookCharactersOrderByName();
assertThat(allBookCharactersByName)
.extracting(record -> record.getValue(Tables.BOOK_CHARACTER.NAME))
.isSorted();
}
@Test
public void getBookByIdThatExistsShouldReturnValidRecord() {
Optional<Record> bookCharacter =
booksDao.getBookCharacterById(EXISTING_CHAR_ID);
assertThat(
bookCharacter
.orElseThrow(() -> new AssertionError("Not existing character"))
.getValue(Tables.BOOK_CHARACTER.NAME))
.isEqualTo("Samwise");
}
@Test
public void getBookByIdThatNotExistsShouldReturnEmptyOptionalRecord() {
Optional<Record> bookCharacter =
booksDao.getBookCharacterById(NOT_EXISTING_CHAR_ID);
assertThat(bookCharacter.isPresent()).isFalse();
}
}
Como vemos, Spring Boot facilita mucho la integración con jOOQ, gestionandolo, como siempre, con autoconfiguraciones por defecto. Si por lo que sea necesitamos configurar jOOQ con algún parametro o configuración especial, podemos hacerlo con propiedades del tipo ‘spring.jooq.propiedad’ en el appication.properties, así como definir nuestro propio @Bean de la clase de configuración de jOOQ (org.jooq.Configuration).
Como siempre, tenéis el código disponible en mi github, proyecto springboot-series-jooq.