Vårstøvel med vårparti

1. Oversikt

Spring Batch er et kraftig rammeverk for utvikling av robuste batch-applikasjoner. I vår forrige opplæring introduserte vi Spring Batch.

I denne opplæringen vil vi bygge videre på den forrige og lære å sette opp og lage en grunnleggende batchdrevet applikasjon ved hjelp av Spring Boot.

2. Maven-avhengigheter

La oss først legge til spring-boot-starter-batch til vår pom.xml:

 org.springframework.boot spring-boot-starter-batch 2.4.0.RELEASE 

Vi legger også til org.hsqldb avhengighet, som også er tilgjengelig fra Maven Central:

 org.hsqldb hsqldb 2.5.1 kjøretid 

3. Definere en enkel vårpartijobb

Vi skal bygge en jobb som importerer en kaffeliste fra en CSV-fil, forvandler den ved hjelp av en tilpasset prosessor og lagrer de endelige resultatene i en database i minnet.

3.1. Starter

La oss starte med å definere inngangspunktet for applikasjonen:

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

Som vi kan se, er dette en standard Spring Boot-applikasjon. Ettersom vi ønsker å bruke standardkonfigurasjonsverdier der det er mulig, skal vi bruke et veldig lett sett med applikasjonskonfigurasjonsegenskaper.

Vi definerer disse egenskapene i vår src / main / resources / application.properties fil:

file.input = kaffe-liste.csv

Denne egenskapen inneholder plasseringen til vår inngående kaffeliste. Hver linje inneholder merket, opprinnelsen og noen kjennetegn ved kaffen vår:

Blue Mountain, Jamaica, Fruity Lavazza, Colombia, Strong Folgers, America, Smokey

Som vi skal se, er dette en flat CSV-fil, noe som betyr at Spring kan håndtere den uten spesiell tilpasning.

Deretter legger vi til et SQL-skript schema-all.sql å skape vårt kaffe tabell for å lagre dataene:

DROP TABELL kaffe HVIS EKSISTERER; OPPRETT BORD kaffe (kaffe_id BIGINT IDENTITET IKKE NULL PRIMÆR NØKKEL, merke VARCHAR (20), opprinnelse VARCHAR (20), egenskaper VARCHAR (30));

Spring Boot vil kjøre dette skriptet automatisk under oppstart.

3.2. Kaffe domene klasse

Deretter trenger vi en enkel domene klasse for å holde kaffeproduktene våre:

offentlig klasse Kaffe {private String merkevare; privat String opprinnelse; private strengegenskaper; offentlig kaffe (strengmerke, strengopprinnelse, strengkarakteristikker) {this.brand = merkevare; dette.origin = opprinnelse; dette. egenskaper = egenskaper; } // getters og setters}

Som tidligere nevnt, vår Kaffe objektet inneholder tre egenskaper:

  • Et merke
  • Et opphav
  • Noen ekstra egenskaper

4. Jobbkonfigurasjon

Nå, videre til nøkkelkomponenten, vår jobbkonfigurasjon. Vi går trinn for trinn, bygger opp vår konfigurasjon og forklarer hver del underveis:

@Configuration @EnableBatchProcessing public class BatchConfiguration {@Autowired public JobBuilderFactory jobBuilderFactory; @Autowired offentlig StepBuilderFactory stepBuilderFactory; @Value ("$ {file.input}") privat strengfilInput; // ...}

For det første starter vi med en standard vår @Konfigurasjon klasse. Deretter legger vi til en @EnableBatchProcessing kommentar til klassen vår. Spesielt gir dette oss tilgang til mange nyttige bønner som støtter jobber og vil spare oss for mye beinarbeid.

Videre gir bruk av denne kommentaren oss også tilgang til to nyttige fabrikker som vi vil bruke senere når vi bygger jobbkonfigurasjonen og jobbtrinnene.

For den siste delen av vår opprinnelige konfigurasjon inkluderer vi en referanse til file.input eiendom vi erklærte tidligere.

4.1. En leser og skribent for jobben vår

Nå kan vi fortsette og definere en leserbønne i vår konfigurasjon:

@Bean public FlatFileItemReader reader () {return new FlatFileItemReaderBuilder (). Name ("coffeeItemReader") .resource (new ClassPathResource (fileInput)) .delimited () .names (new String [] {"brand", "origin", " egenskaper "}) .fieldSetMapper (ny BeanWrapperFieldSetMapper () {{setTargetType (Coffee.class);}}) .build (); }

Kort oppsummert, vår leserbønne som er definert ovenfor, ser etter en fil som heter kaffe-liste.csv og analyserer hver artikkel i en Kaffe gjenstand.

På samme måte definerer vi en forfatterbønne:

@Bean offentlig JdbcBatchItemWriter-skribent (DataSource dataSource) {returner ny JdbcBatchItemWriterBuilder () .itemSqlParameterSourceProvider (ny BeanPropertyItemSqlParameterSourceProvider ()) .sql ("INSERT INTO kaffe, merke: VALG: egenskaper: merkevare, opprinnelse: merkevare, merkevare:" .dataSource (dataSource) .build (); }

Denne gangen inkluderer vi SQL-setningen som trengs for å sette inn et enkelt kaffeelement i databasen vår, drevet av Java bønneegenskapene til vår Kaffe gjenstand. Handily den datakilde blir automatisk opprettet av @EnableBatchProcessing kommentar.

4.2. Sette jobben vår sammen

Til slutt må vi legge til de faktiske jobbtrinnene og konfigurasjonen:

@Bean public Job importUserJob (JobCompletionNotificationListener listener, Step step1) {return jobBuilderFactory.get ("importUserJob") .incrementer (new RunIdIncrementer ()) .listener (listener) .flow (step1) .end () .build (); } @Bean offentlig trinn trinn 1 (JdbcBatchItemWriter skribent) {return stepBuilderFactory.get ("trinn1"). klump (10) .leser (leser ()). prosessor (prosessor ()). skribent (skribent) .bygg (); } @Bean offentlig CoffeeItemProcessor-prosessor () {returner ny CoffeeItemProcessor (); }

Som vi kan se, er jobben vår relativt enkel og består av ett trinn definert i trinn 1 metode.

La oss ta en titt på hva dette trinnet gjør:

  • Først konfigurerer vi trinnet vårt slik at det vil skrive opptil ti poster om gangen ved hjelp av del (10) erklæring
  • Deretter leser vi inn kaffedataene ved hjelp av leserbønnen, som vi angir ved hjelp av leser metode
  • Deretter sender vi hvert av kaffeproduktene våre til en tilpasset prosessor der vi bruker en spesiell forretningslogikk
  • Til slutt skriver vi hvert kaffeelement til databasen ved hjelp av forfatteren vi så tidligere

På den annen side, vår importUserJob inneholder vår jobbdefinisjon, som inneholder en id ved hjelp av innebygd RunIdIncrementer klasse. Vi setter også en JobbFullføringNotifikasjonLytter, som vi bruker for å få beskjed når jobben er fullført.

For å fullføre jobbkonfigurasjonen, viser vi hvert trinn (selv om denne jobben bare har ett trinn). Vi har nå en perfekt konfigurert jobb!

5. En tilpasset kaffeprosessor

La oss se nærmere på den tilpassede prosessoren vi definerte tidligere i jobbkonfigurasjonen:

offentlig klasse CoffeeItemProcessor implementerer ItemProcessor {private static final Logger LOGGER = LoggerFactory.getLogger (CoffeeItemProcessor.class); @ Override offentlig kaffeprosess (endelig kaffe kaffe) kaster unntak {String brand = coffee.getBrand (). ToUpperCase (); Strengopprinnelse = kaffe.getOrigin (). ToUpperCase (); String chracteristics = kaffe.getCharacteristics (). ToUpperCase (); Kaffe transformedCoffee = ny kaffe (merke, opprinnelse, chracteristics); LOGGER.info ("Konvertering ({}) til ({})", kaffe, transformedCoffee); retur transformedCoffee; }}

Av spesiell interesse, er ItemProsessor Grensesnittet gir oss en mekanisme for å anvende en bestemt forretningslogikk under jobben.

For å holde ting enkelt, vi definerer vår CoffeeItemProsessor, som tar et innspill Kaffe motstand og transformerer hver av egenskapene til store bokstaver.

6. Jobbavslutning

I tillegg skal vi også skrive en JobCompletionNotificationListener for å gi tilbakemelding når jobben vår er ferdig:

@ Overstyr offentlig ugyldighet etterJob (JobExecution jobExecution) {if (jobExecution.getStatus () == BatchStatus.COMPLETED) {LOGGER.info ("!!! JOBB FERDIG! Tid til å verifisere resultatene"); Strengspørsmål = "VELG merke, opprinnelse, egenskaper FRA kaffe"; jdbcTemplate.query (spørring, (rs, rad) -> ny kaffe (rs.getString (1), rs.getString (2), rs.getString (3))). forEach (kaffe -> LOGGER.info ("Fant i databasen. ", kaffe)); }}

I eksemplet ovenfor overstyrer vi etterJob metode og sjekk fullført jobb. Videre kjører vi et trivielt spørsmål for å kontrollere at hvert kaffeelement ble lagret i databasen.

7. Kjører jobben vår

Nå som vi har alt på plass for å kjøre jobben vår, her kommer den morsomme delen. La oss gå videre og kjøre jobben vår:

... 17: 41: 16.336 [main] INFO c.b.b.JobCompletionNotificationListener - !!! JOBB FERDIG! Tid for å verifisere resultatene 17: 41: 16.336 [main] INFO c.b.b.JobCompletionNotificationListener - Funnet i databasen. 17: 41: 16.337 [main] INFO c.b.b.JobCompletionNotificationListener - Funnet i databasen. 17: 41: 16.337 [main] INFO c.b.b.JobCompletionNotificationListener - Funnet i databasen. ... 

Som vi ser, gikk jobben vår vellykket, og hvert kaffeelement ble lagret i databasen som forventet.

8. Konklusjon

I denne artikkelen har vi lært hvordan du lager en enkel Spring Batch-jobb ved hjelp av Spring Boot. Først startet vi med å definere noen grunnleggende konfigurasjoner.

Så så vi hvordan du legger til en filleser og databaseforfatter. Til slutt tok vi en titt på hvordan vi kan bruke litt tilpasset behandling og sjekke at jobben vår ble utført.

Som alltid er hele kildekoden til artikkelen tilgjengelig på GitHub.