Spring Boot - CommandLineRunner vs. ApplicationRunner

Si necesitas correr algún código específico al arranque de la aplicación con Spring Boot, puedes implementar las interfaces CommandLineRunner o ApplicationRunner. Ambas funcionan del mismo modo y ambas tienen un método run con una sola diferencia que podemos explotar según sea el caso de lo que necesitamos.

1. Si quieres correr código al arranque tienes que utilizar CommandLineRunner y tiene su propio parámetro que es un arreglo de String.

2. Si quieres correr código al arranque pero también quieres acceder a los argumentos de la aplicación con un objeto ApplicationRunner es la que debes implementar ya que esta recibe un objeto de tipo ApplicationArguments para el manejo de los argumentos de la aplicación.

 

A modo de ejemplo vamos a utilizar una base de datos embebida y JPA para el manejo de la capa de datos. Al final vamos a exponer los datos en un servicio RESTful.

 

Prerequisitos

1. Generar tu proyecto con el Initializr de Spring Boot (o lo puedes generar manualmente).

- Incluye los siguientes starters: Web, Rest Repositories, JPA y H2.

IMPORTANTE: Recuerda generar un jar, vayámonos olvidando de los odiosos archivos war.

 

2. Abre tu IDE favorito y abre el proyecto que acabas de generar.

 

IMPORTANTE

Te puedes descargar el código directamente del repositorio en github o en formato zip.

 

1. Configuración MAVEN (para el momento en que escribí este código los chicos de Pivotal movieron algo y ya no se estaba importando la librería context de Spring, así que la agregué manualmente).

<groupId>com.ledze</groupId>
<artifactId>ledzedev-commandlinerunner-applicationrunner</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>ledzedev-commandlinerunner-applicationrunner</name>
<description>Demo project for Spring Boot - CommandLineRunner and ApplicationRunner</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.4.RELEASE</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

2. Código Java

/**
* Source code generated by Gerardo Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 2/23/2017
*/
@SpringBootApplication
public class LedzedevCommandlinerunnerApplicationrunnerApplication {

private static Logger logger = LoggerFactory.getLogger(LedzedevCommandlinerunnerApplicationrunnerApplication.class);

public static void main(String[] args) {
SpringApplication.run(LedzedevCommandlinerunnerApplicationrunnerApplication.class, args);
}

/**
* Source code generated by Gerardo Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 2/23/2017
*/
@Bean
CommandLineRunner cargaEquiposClasicos(LigaRepository ligaRepository) {

logger.info("Cargando con CommandLineRunner");
return x -> {
logger.info("CommandLineRunner tiene como parámetros un arreglo de Strings: "+ Arrays.toString(x));
Arrays.asList(
new EquipoDeFutbol("América"),
new EquipoDeFutbol("Cruz Azul"),
new EquipoDeFutbol("Chivas"),
new EquipoDeFutbol("Pumas")
).forEach(e -> {
logger.info(e.toString());
ligaRepository.save(e);
});
logger.info("Carga inicial finalizada.");
};
};

/**
* Source code generated by Gerardo Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 2/23/2017
*/
@Bean
ApplicationRunner cargaEquiposDelNorte(LigaRepository ligaRepository){

logger.info("Cargando con ApplicationRunner");
return x -> {
logger.info("ApplicationRunner tiene como parámetro un objeto ApplicationArguments");

logger.info("non option args: "+ Arrays.toString(x.getNonOptionArgs().toArray()) );
logger.info("contiene files? "+x.containsOption("files"));
logger.info("source args: "+ Arrays.toString(x.getSourceArgs()));
logger.info("option values: "+x.getOptionValues("files"));
logger.info("option names: "+x.getOptionNames());

 Arrays.asList(
new EquipoDeFutbol("Monterrey"),
new EquipoDeFutbol("Tigres"),
new EquipoDeFutbol("Xolos")
).forEach(e -> {
logger.info(e.toString());
ligaRepository.save(e);
});
logger.info("Carga equipos del norte finalizada");
};
};
}

/**
* Source code generated by Gerardo Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 2/23/2017
*/
@RepositoryRestResource
interface LigaRepository extends JpaRepository<EquipoDeFutbol, Long> {

Collection<EquipoDeFutbol> findByNombre(@Param("n") String nombre);
}

/**
* Source code generated by Gerardo Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 2/23/2017
*/
@Entity
class EquipoDeFutbol {


@Id
@GeneratedValue
private Long id;


private String nombre;

public EquipoDeFutbol() {
}

public EquipoDeFutbol(String nombre) {
this.nombre = nombre;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}

@Override
public String toString() {

return "EquipoDeFutbol{" +
"id=" + id +
", nombre='" + nombre + '\'' +
'}';
}
}

3. Ejecución de la clase principal

Se observa la carga inicial que programamos y ambas lo hacen sin problema. La única diferencia es que ApplicacionRunner tiene un manejo de los argumentos del programa con un objeto que tiene algunos métodos convenientes para el manejo de los mismos. Se muestra en la imagen lo que regresan los métodos de ApplicationArguments.

 

 

4. Conclusión

A mi parecer CommandLineRunner es la interfaz que por excelencia deberíamos usar, sin embargo está la otra  opción para un manejo conveniente.

Aquí cuando se consulta en web como un servicio RESTful.

 

 

Add a comment

Spring Boot y Apache Kafka: Plataforma de streaming distribuido. Envío y recepción de mensajes

Prerequisitos

- Tener instalado y corriendo Apache Kafka

- Apache Kafka utiliza un servidor de Zookeeper, así que:

if (tienes un servidor Zookeeper instalado)

     utiliza ese servidor;

else

     Apache Kafka trae un script para levantar uno. /*Te indico abajo como arrancarlo desde la distribución de Kafka*/

 

Consulta la documentación de Apache Kafka para mayor detalle, pero la forma de levantar el servicio rápidamente es:

1. Cambiarse al directorio donde instalaste Apache Kafka.

NOTA: Si no estás en windows quítale la palabra windows y la extensión .bat 

2. Arranca Zookeeper (en caso de que no tengas uno previamente instalado)

     bin/windows/zookeeper-server-start.bat config/zookeeper.properties

3. Arranca Apache Kafka

     bin/windows/kafka-server-start.bat config/server.properties

 

IMPORTANTE

Te puedes clonar el código directamente del repositorio en github o descárgatelo en formato zip.

 

1. Configuración Maven

<groupId>com.ledzedev</groupId>
<artifactId>ledze-spring-kafka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>ledze-spring-kafka</name>
<description>Ledze Demo project for Spring Boot with Apache Kafka</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

 

2. Código Java

2.1 Recibir mensajes

/**
* Source code generated by Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 25/01/2017
*/
@Test
public void pruebaReceptorDeMensajes() throws Exception {

logger.info("\n\n\n");
logger.info("Inicia contenedor de mensajes...");

ContainerProperties containerProps = new ContainerProperties("topicoLedze", "topic2");
containerProps.setMessageListener((MessageListener<Integer, String>) message -> {
logger.info("recibido: " + message);
});

KafkaMessageListenerContainer<Integer, String> container = createContainer(containerProps);
container.setBeanName("testAuto");
container.start();
//container.stop();
}


private KafkaMessageListenerContainer<Integer, String> createContainer(ContainerProperties containerProps) {
Map<String, Object> props = consumerProps();
DefaultKafkaConsumerFactory<Integer, String> cf = new DefaultKafkaConsumerFactory<Integer, String>(props);
KafkaMessageListenerContainer<Integer, String> container = new KafkaMessageListenerContainer<>(cf, containerProps);
return container;
}

private Map<String, Object> consumerProps() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "grupoLedze");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
return props;
}

Al ejecutar el consumidor de mensajes se pueden ver todos los parámetros de configuración.



2.2 Enviar mensajes

/**
* Source code generated by Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 25/01/2017
*/
@Test
public void pruebaEnviaMensajes(){

logger.info("\n\n\n");
logger.info("Inicia el envío de mensajes...");

KafkaTemplate<Integer, String> template = createTemplate();
template.setDefaultTopic("topicoLedze");

ListenableFuture<SendResult<Integer, String>> future1 = template.sendDefault(0, "foo");
this.addListenableFutureCallback(future1);

ListenableFuture<SendResult<Integer, String>> future2 = template.sendDefault(2, "bar");
this.addListenableFutureCallback(future2);

ListenableFuture<SendResult<Integer, String>> future3 = template.sendDefault(0, "baz");
this.addListenableFutureCallback(future3);

ListenableFuture<SendResult<Integer, String>> future4 = template.sendDefault(2, "qux");
this.addListenableFutureCallback(future4);

template.flush();

}
private void addListenableFutureCallback(ListenableFuture<SendResult<Integer, String>> future){
future.addCallback(new ListenableFutureCallback<SendResult<Integer, String>>() {
@Override
public void onFailure(Throwable motivoFalla) {
logger.info("EL ENVÍO DEL MENSAJE FALLÓ.", motivoFalla);
}
@Override
public void onSuccess(SendResult<Integer, String> integerStringSendResult) {
logger.info("ENVÍO DE MENSAJE EXITOSO! Mensaje=" + integerStringSendResult.getProducerRecord().value());
}
});
}

private
KafkaTemplate<Integer, String> createTemplate() {

Map<String, Object> senderProps = senderProps();
ProducerFactory<Integer, String> pf = new DefaultKafkaProducerFactory<Integer, String>(senderProps);
KafkaTemplate<Integer, String> template = new KafkaTemplate<>(pf);
return template;
}

private Map<String, Object> senderProps() {
Map<String, Object> props = new HashMap<>();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.RETRIES_CONFIG, 0);
props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
props.put(ProducerConfig.LINGER_MS_CONFIG, 1);
props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
return props;
}

Al ejecutar el envío de mensajes se pueden ver los parámetros de configuración del sender.

 

 

3. Resultados

 Después de ejecutar los tests varias veces alcanzamos a verificar que la recepción de las respuestas son ASÍNCRONAS, justo como configuramos nuestro callback en el envío de mensajes.

 

Add a comment

Spring Boot - Servicio de configuracion en la nube (github o svn) / Spring Cloud Config Server

Importante

Este tipo de servicios se utilizan para sistemas distribuidos como las arquitecturas de microservicios en el que los servicios están altamente desacoplados pero que aún así deben compartir configuraciones. Este tipo de servicios permite gestionar la configuración de forma 100% independiente del desarrollo, permitiendo incrementar la productividad de los programadores que se integran a los equipos de trabajo.

 

- Prerequisitos

Genera tu proyecto con Spring Boot Initializr, si lo deseas puedes generar el proyecto llenando solo los campos básicos.

Agrega en la sección de Dependencias:

- Config Server

 

1. Configuración Maven.

<groupId>com.example</groupId>
<artifactId>ledzedev-config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>ledzedev-config-server</name>
<description>Demo de Spring Boot levantando un servidor de configuración que administra recursos en SVN o gitHub</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>

 

2. Repositorio en gitHub.com

Genera tu repositorio en github o svn y sube tus archivos de configuración. Recuerda que este servicio está pensado para centralizar la configuración en la nube, para sistemas distribuidos como las arquitecturas de microservicios (microservices), y que únicamente se dedique a proporcionar la configuración desde arranque o gestión de otros servicios.

 

También se puede trabajar de manera local con esos archivos, siempre y cuando estén gestionados por el servicio de nube, en mi caso github.

 

3. Configuración del properties del proyecto.

- Abrir el archivo application.properties y agregarle la ruta donde se encuentran los archivos de configuración y por convención se utiliza el puerto 8888 para servicios de configuración en la nube:

#spring.cloud.config.server.git.uri=/Users/ledzedev/config-files
spring.cloud.config.server.git.uri=https://github.com/CypraxPuch/config-files
server.port=
8888

Nota: Como podemos ver, si lo deseamos, podemos clonar el repositorio en nuestro equipo local e indicarle al servidor que nuestra URI es la ruta local. Por lo pronto nos quedaremos con la ruta directa en la nube.

 

4. Habilitamos el servicio en nuestra clase principal.

 Unicamente le agregamos la anotación @EnableConfigServer.

 

/**
* Código generado por Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 18/Nov/2016.
*/
@EnableConfigServer
@SpringBootApplication
public class LedzedevConfigServerApplication {


public static void main(String[] args) {
SpringApplication.run(LedzedevConfigServerApplication.class, args);
}
}

 

5. Levantamos nuestro servidor de configuración en la nube (Spring Cloud Config Server) y probamos que nuestros archivos de configuración estén expuestos en la web.

 

 

Comprobamos el archivo YAML en web.

 

Te puedes descargar mi código directamente los archivos de configuración administrados en github, el servicio se encuentra separado de los archivos de configuración para contribuir en el alto nivel de acoplamiento, descárgatelo aquí ledzedev-config-server o te los puedes descargar en formato zip.

 

Artículos Relacionados

- Spring Boot Eureka Discovery Server

 

 

 

 

 

Add a comment

Spring Boot - Envío y recepción de mensajería con RabbitMQ

Prerequisitos

- Tener instalado ERLANG.

- Tener instalado el servidor de RabbitMQ. Seguir la guía de instalación.

 

IMPORTANTE

Te puedes descargar el código directamente del repositorio en github o en formato zip

 

1. Configuración Maven

 <groupId>com.ledzedev</groupId>

<artifactId>ledze-messaging-rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>ledze-messaging-rabbitmq</name>
<description>Demo de mensajería con Spring Boot y RabbitMQ</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

2. Código Java

2.1 Receptor

/**
* Source code generated by Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 1/20/2017
*/
@Component
public class Receptor {


private static Logger log = LoggerFactory.getLogger(Receptor.class);

//Solo se agrega este contador para darle mas sentido al ejemplo, pero no se recomienda en un ambiente productivo.
private CountDownLatch latch = new CountDownLatch(1);


public void recibirMensaje(String mensaje){
log.info("Mensaje recibido: " +mensaje);
latch.countDown();
}

public CountDownLatch getLatch() {
return latch;
}

}

2.2 Clase principal donde se define la infraestructura de la mensajería (Queue, TopicExchange, Binding, Contenedor y Listener)

/**
* Source code generated by Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 1/20/2017
*/
@SpringBootApplication
public class LedzeMessagingRabbitmqApplication {


public static void main(String[] args) {
SpringApplication.run(LedzeMessagingRabbitmqApplication.class, args);
}

final static String nombreCola = "ledze-spring-boot";

/*
Spring AMQP requiere que los objetos Queue, TopicExchange y Binding sean creados como beans de Spring de alto nivel
para que sean configurados apropiadamente.
*/

@Bean
Queue cola(){

return new Queue(nombreCola, false);
}

@Bean
TopicExchange exchange(){

return new TopicExchange("ledze-spring-boot-exchange");
}

@Bean
Binding relaciona(Queue cola, TopicExchange topicExchange){

return BindingBuilder.bind(cola).to(topicExchange).with(nombreCola);
}

@Bean
SimpleMessageListenerContainer contenedor(ConnectionFactory connectionFactory, MessageListenerAdapter messageListenerAdapter){

SimpleMessageListenerContainer contenedor = new SimpleMessageListenerContainer();
contenedor.setConnectionFactory(connectionFactory);
contenedor.setQueueNames(nombreCola);
contenedor.setMessageListener(messageListenerAdapter);

return contenedor;
}

@Bean
MessageListenerAdapter listenerAdapter(Receptor receptor){

return new MessageListenerAdapter(receptor, "recibirMensaje");//método escuchador por defecto
}

}

3. Ejecutas la clase principal y el Listener se debe quedar esperando.

 

 

Bonus

Para probar he construido una clase para enviar los mensajes y la hacemos con un CommandLineRunner, solo para efectos de nuestro test y que se ejecute dentro del mismo contexto (ESTE TEST NO ES UNA SOLUCIÓN PARA PRODUCCIÓN).

/**
* Source code generated by Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 1/20/2017
*/
@Component
public class LedzeMandaMensajes implements CommandLineRunner {


private static Logger log = LoggerFactory.getLogger(LedzeMandaMensajes.class);

private final RabbitTemplate rabbitTemplate;
private final Receptor receptor;
private final ConfigurableApplicationContext contexto;

public LedzeMandaMensajes(RabbitTemplate rabbitTemplate, Receptor receptor, ConfigurableApplicationContext contexto) {
this.rabbitTemplate = rabbitTemplate;
this.receptor = receptor;
this.contexto = contexto;
}

@Override
public void run(String... strings) throws Exception {

log.info("Enviando mensaje a la cola de mensajería...");
rabbitTemplate.convertAndSend("ledze-spring-boot", "Hola desde RabbitMQ");

//Solo se agrega este contador para darle mas sentido al ejemplo, pero no se recomienda en un ambiente productivo.
receptor.getLatch().await(10000, TimeUnit.MILLISECONDS);


contexto.close();
}
}

Inyectamos en la clase principal LedzeMessagingRabbitmqApplication, una instancia de la clase que manda mensajes:

@Autowired
private LedzeMandaMensajes ledzeMandaMensajes;
 

Ejecutamos nuevamente la clase principal y el resultado debe mostrar en la consola el mensaje que mandamos a la cola "Hola desde RabbitMQ".

 

 

NOTA: JMS y AMQP tienen diferente semántica. Por ejemplo: JMS manda mensajes encolados a solo un consumidor (aunque también tiene el concepto de topicos, la forma natural de funcionar de JMS es uno a uno) y AMQP manda mensajes a un exchange que por su propia naturaleza puede ir a una cola o a varias colas, funcionando de manera nativa mas como el concepto de tópicos de JMS.

 

 

Add a comment

Spring Boot con Base de Datos

Primero generamos un proyecto con Spring Boot INITIALIZR.

 

1. Configuración de Maven

- Spring boot starter test

- Spring boot starter data JPA

- H2 como manejador de BD (esta en particular vive en memoria y solo es para esta cápsula). Puedes utilizar la BD que soporte Spring.

<modelVersion>4.0.0</modelVersion>

<groupId>com.ledzedev.springboot</groupId>
<artifactId>demo-spring-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>demo-spring-boot</name>
<description>Proyecto demo de Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>

 

2. Vamos a empezar escribiendo una entidad para escribir noticias en la base de datos.

/**
* Código generado por Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 04/Nov/2016.
*/
@Entity
class Noticia{


@Id
@GeneratedValue
private Long id;


private String tituloNoticia;

public Noticia() { //constructor vacío porque así lo dice JPA
}


public Noticia(String tituloNoticia) {
this.tituloNoticia = tituloNoticia;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getTituloNoticia() {
return tituloNoticia;
}

public void setTituloNoticia(String tituloNoticia) {
this.tituloNoticia = tituloNoticia;
}

@Override
public String toString() {

//es buena práctica sobreescribir el método toString para poder conocer el contenido de cada objeto
return "Noticia{" +

"id=" + id +
", tituloNoticia='" + tituloNoticia + '\'' +
'}';
}
}

 

3. Ahora necesitamos una interfaz que hable con la base de datos y que lea y escriba en ella.

/**
* Código generado por Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 04/Nov/2016.
*/
interface NoticiasRepositorio extends JpaRepository<Noticia, Long>{

//por convención hay que llamar los métodos en inglés y automáticamente SpringBoot intuye el nombre de la propiedad
// en este caso solo agrego el findBy=buscaPor
// TituloNoticia = nuestro objeto Noticia tiene una propiedad tituloNoticia
Collection<Noticia> findByTituloNoticia(String tn);

}

 

4. Ahora el programa principal

- una clase pública con un main y debe tener la anotación:

@SpringBootApplication

- utilizamos la interfaz CommandLineRunner que proporciona Spring Boot y cuya única función es cargar todo en el arranque de spring boot.

- escribimos algunos nombres de noticias

- leemos todas las noticias

- encontramos una noticia por su titulo.

/**
* Código generado por Gerado Pucheta Figueroa
* Twitter: @ledzedev
* http://ledze.mx
* 04/Nov/2016.
*/
@SpringBootApplication
public class DemoSpringBootApplication {

private static final Logger log = LoggerFactory.getLogger(DemoSpringBootApplication.class);

public static void main(String[] args) {
SpringApplication.run(DemoSpringBootApplication.class, args);
}

/*
- Utilizamos la interfa CommandLineRunner que nos proporciona SpringBoot y
tiene un solo método que tiene la función de cargar cuando se ejecuta el main.
- Recuerda que nuestra base de datos es h2 para este ejemplo, pero puedes utilizar el manejador de BD que te guste.
- Escribimos el runner como un bean para que sea detectado por spring boot y que cargue lo que necesitamos
al arranque*/
@Bean
CommandLineRunner commandLineRunner(NoticiasRepositorio nr){

//como es java 8 puedo ocupar un lambda ya que esta interfaz solo tiene 1 método
return args -> {

//inserto en la BD
log.info("Guardando en la BD.");

Arrays.asList("Donald Trump gana la presidencia en EUA.",
"El peso mexicano alcanza al dolar y su paridad es 1 a 1.",
"Nigeria tiene crisis por el tomate.",
"Brasil reinstala a Dilma Rouseff y la disculpan públicamente.",
"EPN renuncia a su cargo en México y la gente no se lo permite.")
.forEach( n -> nr.save(new Noticia(n)) );


log.info("Consulto todos los registros existentes en la BD.");
//busco los elementos y los imprimo en el log
nr.findAll().forEach(

n -> {log.info(n.getTituloNoticia() + " id: "+n.getId());
});


log.info("Consulta por el método que agregamos.");
//ahora busco con el método que nosotros hicimos.
nr.findByTituloNoticia("Donald Trump gana la presidencia en EUA.").forEach(

n -> {log.info("El id de la noticia es: "+n.getId());
});
};
};
}

 

5. El resultado debe ser el siguiente:

 

 

Te puedes descargar mi código directamente del repositorio en github o te lo puedes descargar en formato zip.

Artículo relacionado

- Spring Boot INITIALIZR

 

Como siempre dame un poquito de crédito y no le quites la firma a mi código.

 

 

 

Add a comment

Subcategories