-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
80 changed files
with
25,360 additions
and
9,666 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# Categoría - Spring Batch | ||
|
||
Ya tenemos todo configurado de los pasos anteriores asi que proseguimos con el último ejemplo. | ||
|
||
|
||
## Código | ||
|
||
Vamos a implementar un batch que limpie de ficheros un determinado directorio. Esta vez y dado que no necesitamos realizar ningún tipo de lectura ni trasformación ni escritura y queremos hacerlo todo al mismo tiempo, es buen momento para utilizar un `Tasklet`. | ||
|
||
### Tasklet | ||
|
||
En primer lugar, vamos a crear `CleanTasklet` dentro del package `com.ccsw.tutorialbatch.tasklet`. | ||
|
||
=== "CleanTasklet.java" | ||
``` Java | ||
import java.io.File; | ||
|
||
public class CleanTasklet implements Tasklet, InitializingBean { | ||
|
||
private Resource directory; | ||
|
||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { | ||
File dir = directory.getFile(); | ||
|
||
File[] files = dir.listFiles(); | ||
|
||
for (File file : files) { | ||
boolean deleted = file.delete(); | ||
if (!deleted) { | ||
throw new UnexpectedJobExecutionException("Could not delete file " + file.getPath()); | ||
} | ||
} | ||
return RepeatStatus.FINISHED; | ||
} | ||
|
||
public void setDirectoryResource(Resource directory) { | ||
|
||
this.directory = directory; | ||
} | ||
|
||
public void afterPropertiesSet() throws Exception { | ||
|
||
if (directory == null) { | ||
throw new UnexpectedJobExecutionException("Directory must be set"); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
La implementación de la interface `Tasklet` consiste en sobreescribir el método `execute` de forma muy similar como lo hacíamos en los `Processors`. En este método emplazamos nuestra lógica de negocio que básicamente consiste en borrar todos los ficheros que se encuentren en el directorio proporcionado como atributo. | ||
|
||
|
||
### Step y Job | ||
|
||
Posteriormente, como en el caso anterior, emplazamos la configuración junto al resto de beans dentro del package `com.ccsw.tutorialbatch.config`. | ||
|
||
=== "CleanBatchConfiguration.java" | ||
``` Java | ||
package com.ccsw.tutorialbatch.config; | ||
|
||
import com.ccsw.tutorialbatch.tasklet.CleanTasklet; | ||
import org.springframework.batch.core.Job; | ||
import org.springframework.batch.core.Step; | ||
import org.springframework.batch.core.job.builder.JobBuilder; | ||
import org.springframework.batch.core.repository.JobRepository; | ||
import org.springframework.batch.core.step.builder.StepBuilder; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.core.io.FileSystemResource; | ||
import org.springframework.transaction.PlatformTransactionManager; | ||
|
||
@Configuration | ||
public class CleanBatchConfiguration { | ||
|
||
@Bean | ||
public CleanTasklet cleanTasklet() { | ||
CleanTasklet tasklet = new CleanTasklet(); | ||
|
||
tasklet.setDirectoryResource(new FileSystemResource("target/test-outputs")); | ||
|
||
return tasklet; | ||
} | ||
|
||
@Bean | ||
public Step step1Clean(JobRepository jobRepository, PlatformTransactionManager transactionManager) { | ||
return new StepBuilder("step1Clean", jobRepository) | ||
.tasklet(cleanTasklet(), transactionManager) | ||
.build(); | ||
} | ||
|
||
@Bean | ||
public Job jobClean(JobRepository jobRepository, Step step1Clean) { | ||
return new JobBuilder("jobClean", jobRepository) | ||
.start(step1Clean) | ||
.build(); | ||
} | ||
|
||
} | ||
``` | ||
|
||
* **CleanTasklet**: El bean del `Tasklet` que hemos creado anteriormente. | ||
* **Step**: La creación del `Step` se realiza mediante él `StepBuilder` al que únicamente le añadimos el `Tasklet` que se va a ejecutar de forma atómica. | ||
* **Job**: Finalmente, debemos definir él `Job` que será lo que se ejecute al lanzar nuestro proceso. La creación se hace mediante el builder correspondiente como en los casos anteriores. | ||
|
||
|
||
### Pruebas | ||
|
||
Ahora ya tenemos varios `Jobs` en nuestro batch por lo que debemos especificar en el arranque cuál queremos ejecutar. | ||
|
||
Como en el caso anterior pasamos como `VM option` la siguiente propiedad en el arranque de la aplicación: | ||
``` | ||
-Dspring.batch.job.name=jobClean | ||
``` | ||
|
||
Hecho esto y ejecutado el batch, podremos ver la traza de la ejecución en nuestro `log` y que el fichero generado en el `target` del proyecto de la ejecución del batch de autores ya no está. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Ahora hazlo tú! | ||
|
||
Ahora vamos a ver si has comprendido bien el tutorial. ¡Vamos alla! | ||
|
||
## Exportación de juegos a fichero | ||
|
||
### Requisitos | ||
|
||
En este ejercicio vamos a simular la exportación de datos desde una tabla de base de datos a fichero. | ||
|
||
El objetivo es que en función del número de stock de un determinado juego, generemos un fichero con su nombre y si el juego está disponible. | ||
|
||
Par ello debemos tener una tabla de juegos con los siguientes atributos: | ||
|
||
- Identificador | ||
- Título | ||
- Edad recomendada | ||
- Stock | ||
|
||
El proceso batch debe consultar los registros y convertirlos a la siguiente estructura: | ||
|
||
- Título: Título del juego (el mismo que en la tabla de BBDD). | ||
- Disponibilidad: Si el stock es mayor que cero estará disponible y si es cero debera aparecer que no está disponible. | ||
|
||
Una vez realizada la conversion, se debe escribir dicha información a fichero y guardarlo en el `target` del proyecto. | ||
|
||
### Consejos | ||
|
||
Para empezar te daré unos consejos: | ||
|
||
- Recuerda crear la tabla de la BBDD y sus datos. | ||
- Intenta re-aprovechar lo que hemos aprendido en los ejemplos. | ||
- Consulta la documentación para utilizar un `Reader` apropiado para la lectura desde BBDD. | ||
- Date cuenta de que el `Processor` que necesitas es algo más complejo esta vez y necesitaras más de un modelo diferente. | ||
|
||
|
||
## ¿Ya has terminado? | ||
|
||
Si has llegado a este punto es porque ya tienes terminado el tutorial. Por favor no te olvides de subir los proyectos a algún repositorio Github propio (puedes revisar el anexo [Tutorial básico de Git](../../appendix/git.md)) y avísarnos para que podamos echarle un ojo y darte sugerencias y feedback :relaxed:. |
Oops, something went wrong.