diff --git a/build.gradle b/build.gradle index 9b95e86a..811f6cb3 100644 --- a/build.gradle +++ b/build.gradle @@ -100,7 +100,8 @@ ext { starterJms : "org.springframework.boot:spring-boot-starter-artemis:$bootVersion", starterRabbitmq : "org.springframework.boot:spring-boot-starter-amqp:$bootVersion", starterThyme : "org.springframework.boot:spring-boot-starter-thymeleaf:$bootVersion", - starterSecurity : "org.springframework.boot:spring-boot-starter-security:$bootVersion" + starterSecurity : "org.springframework.boot:spring-boot-starter-security:$bootVersion", + starterBatch : "org.springframework.boot:spring-boot-starter-batch:$bootVersion" ] @@ -141,6 +142,7 @@ ext { poi : "org.apache.poi:poi:$poiVersion", io : "commons-io:commons-io:2.5", ] + web = [ tiles : "org.apache.tiles:tiles-jsp:$tilesVersion", jstl : "jstl:jstl:1.2", diff --git a/chapter04/boot-simple/src/main/resources/banner.txt b/chapter04/boot-simple/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter04/boot-simple/src/main/resources/banner.txt +++ b/chapter04/boot-simple/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter04/boot-web/src/main/resources/banner.txt b/chapter04/boot-web/src/main/resources/banner.txt index 2ed5a24f..36704534 100755 --- a/chapter04/boot-web/src/main/resources/banner.txt +++ b/chapter04/boot-web/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) \ No newline at end of file +:: Spring Boot :: (v.2.0.0.M3) \ No newline at end of file diff --git a/chapter05/aspectj-boot/src/main/resources/banner.txt b/chapter05/aspectj-boot/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter05/aspectj-boot/src/main/resources/banner.txt +++ b/chapter05/aspectj-boot/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter06/spring-boot-jdbc/src/main/resources/banner.txt b/chapter06/spring-boot-jdbc/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter06/spring-boot-jdbc/src/main/resources/banner.txt +++ b/chapter06/spring-boot-jdbc/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter08/boot-jpa/src/main/resources/banner.txt b/chapter08/boot-jpa/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter08/boot-jpa/src/main/resources/banner.txt +++ b/chapter08/boot-jpa/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter09/boot-jta/src/main/resources/banner.txt b/chapter09/boot-jta/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter09/boot-jta/src/main/resources/banner.txt +++ b/chapter09/boot-jta/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter12/boot-amqp/src/main/resources/banner.txt b/chapter12/boot-amqp/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter12/boot-amqp/src/main/resources/banner.txt +++ b/chapter12/boot-amqp/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter12/boot-jms/src/main/resources/banner.txt b/chapter12/boot-jms/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter12/boot-jms/src/main/resources/banner.txt +++ b/chapter12/boot-jms/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter12/boot-rest/src/main/resources/banner.txt b/chapter12/boot-rest/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter12/boot-rest/src/main/resources/banner.txt +++ b/chapter12/boot-rest/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter15/boot-jmx/src/main/resources/banner.txt b/chapter15/boot-jmx/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter15/boot-jmx/src/main/resources/banner.txt +++ b/chapter15/boot-jmx/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter16/singer-webapp-boot/src/main/resources/banner.txt b/chapter16/singer-webapp-boot/src/main/resources/banner.txt index 829935ce..8f83b17f 100755 --- a/chapter16/singer-webapp-boot/src/main/resources/banner.txt +++ b/chapter16/singer-webapp-boot/src/main/resources/banner.txt @@ -4,4 +4,4 @@ / | \ |_> > | \/\ ___/ \___ \ \___ \ \____|__ / __/|__| \___ >____ >____ > ========\/|__|===============\/=====\/=====\/ -:: Spring Boot :: (v.2.0.0.M1) +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter18/batch-boot/build.gradle b/chapter18/batch-boot/build.gradle new file mode 100644 index 00000000..84400ad5 --- /dev/null +++ b/chapter18/batch-boot/build.gradle @@ -0,0 +1,22 @@ +buildscript { + repositories { + mavenLocal() + mavenCentral() + maven { url "http://repo.spring.io/release" } + maven { url "http://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/libs-snapshot" } + maven { url "http://repo.spring.io/milestone" } + maven { url "https://repo.spring.io/libs-milestone" } + } + + dependencies { + classpath boot.springBootPlugin + } +} + +apply plugin: 'org.springframework.boot' + +dependencies { + compile boot.starterBatch, db.hsqldb + testCompile testing.junit +} diff --git a/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/Application.java b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/Application.java new file mode 100644 index 00000000..fe76a1b1 --- /dev/null +++ b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/Application.java @@ -0,0 +1,25 @@ +package com.apress.prospring5.ch18; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Created by iuliana.cosmina on 7/30/17. + */ +@SpringBootApplication +public class Application { + + private static Logger logger = LoggerFactory.getLogger(Application.class); + + public static void main(String... args) throws Exception { + ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args); + assert (ctx != null); + logger.info("Application started..."); + + System.in.read(); + ctx.close(); + } +} diff --git a/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/BatchConfig.java b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/BatchConfig.java new file mode 100644 index 00000000..6617665c --- /dev/null +++ b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/BatchConfig.java @@ -0,0 +1,83 @@ +package com.apress.prospring5.ch18; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider; +import org.springframework.batch.item.database.JdbcBatchItemWriter; +import org.springframework.batch.item.file.FlatFileItemReader; +import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; +import org.springframework.batch.item.file.mapping.DefaultLineMapper; +import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.ResourceLoader; + +import javax.sql.DataSource; + +/** + * Created by iuliana.cosmina on 7/30/17. + */ +@Configuration +@EnableBatchProcessing +public class BatchConfig { + + @Autowired + private JobBuilderFactory jobs; + @Autowired + private StepBuilderFactory steps; + + @Autowired DataSource dataSource; + + @Autowired SingerItemProcessor itemProcessor; + + @Bean + public Job job(JobExecutionStatsListener listener) { + return jobs.get("singerJob").listener(listener) .flow(step1()) + .end() + .build(); + } + + @Bean + protected Step step1() { + return steps.get("step1") + .chunk(10) + .reader(itemReader()) + .processor(itemProcessor) + .writer(itemWriter()) + .build(); + } + + @Bean + public ItemReader itemReader() { + FlatFileItemReader itemReader = new FlatFileItemReader<>(); + itemReader.setResource(new ClassPathResource("support/test-data.csv")); + itemReader.setLineMapper(new DefaultLineMapper() {{ + setLineTokenizer(new DelimitedLineTokenizer() {{ + setNames(new String[] { "firstName", "lastName", "song" }); + }}); + setFieldSetMapper(new BeanWrapperFieldSetMapper() {{ + setTargetType(Singer.class); + }}); + }}); + return itemReader; + } + + @Bean + public ItemWriter itemWriter() { + JdbcBatchItemWriter itemWriter = new JdbcBatchItemWriter<>(); + itemWriter.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>()); + itemWriter.setSql("INSERT INTO SINGER (first_name, last_name, song) VALUES (:firstName, :lastName, :song)"); + itemWriter.setDataSource(dataSource); + return itemWriter; + } +} diff --git a/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/JobExecutionStatsListener.java b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/JobExecutionStatsListener.java new file mode 100644 index 00000000..a28bac04 --- /dev/null +++ b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/JobExecutionStatsListener.java @@ -0,0 +1,43 @@ +package com.apress.prospring5.ch18; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.listener.JobExecutionListenerSupport; +import org.springframework.batch.core.listener.StepExecutionListenerSupport; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +@Component +public class JobExecutionStatsListener extends JobExecutionListenerSupport { + + public static Logger logger = LoggerFactory.getLogger(JobExecutionStatsListener.class); + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public JobExecutionStatsListener(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @Override + public void afterJob(JobExecution jobExecution) { + if(jobExecution.getStatus() == BatchStatus.COMPLETED) { + logger.info(" --> Singers were saved to the database. Printing results ..."); + jdbcTemplate.query("SELECT first_name, last_name, song FROM SINGER", + (rs, row) -> new Singer(rs.getString(1), + rs.getString(2), rs.getString(3))).forEach( + singer -> logger.info(singer.toString()) + ); + } + } +} diff --git a/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/Singer.java b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/Singer.java new file mode 100644 index 00000000..68eec0bf --- /dev/null +++ b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/Singer.java @@ -0,0 +1,47 @@ +package com.apress.prospring5.ch18; + + +public class Singer { + private String firstName; + private String lastName; + //best song :D + private String song; + + public Singer() { + } + + public Singer(String firstName, String lastName, String song) { + this.firstName = firstName; + this.lastName = lastName; + this.song = song; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getFirstName() { + return firstName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getLastName() { + return lastName; + } + + public String getSong() { + return song; + } + + public void setSong(String song) { + this.song = song; + } + + @Override + public String toString() { + return "firstName: " + firstName + ", lastName: " + lastName + ", song: " + song; + } +} diff --git a/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/SingerItemProcessor.java b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/SingerItemProcessor.java new file mode 100644 index 00000000..c589a2ab --- /dev/null +++ b/chapter18/batch-boot/src/main/java/com/apress/prospring5/ch18/SingerItemProcessor.java @@ -0,0 +1,27 @@ +package com.apress.prospring5.ch18; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.stereotype.Component; + +@Component("itemProcessor") +public class SingerItemProcessor implements ItemProcessor { + private static Logger logger = LoggerFactory.getLogger(SingerItemProcessor.class); + + @Override + public Singer process(Singer singer) throws Exception { + String firstName = singer.getFirstName().toUpperCase(); + String lastName = singer.getLastName().toUpperCase(); + String song = singer.getSong().toUpperCase(); + + Singer transformedSinger = new Singer(); + transformedSinger.setFirstName(firstName); + transformedSinger.setLastName(lastName); + transformedSinger.setSong(song); + + logger.info("Transformed singer: " + singer + " Into: " + transformedSinger); + + return transformedSinger; + } +} diff --git a/chapter18/batch-boot/src/main/resources/application.properties b/chapter18/batch-boot/src/main/resources/application.properties new file mode 100644 index 00000000..a62b1c73 --- /dev/null +++ b/chapter18/batch-boot/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.datasource.schema=classpath:support/*.sql + + diff --git a/chapter18/batch-boot/src/main/resources/banner.txt b/chapter18/batch-boot/src/main/resources/banner.txt new file mode 100755 index 00000000..8f83b17f --- /dev/null +++ b/chapter18/batch-boot/src/main/resources/banner.txt @@ -0,0 +1,7 @@ + _____ + / _ \ _____________ ____ ______ ______ + / /_\ \\____ \_ __ \_/ __ \ / ___// ___/ +/ | \ |_> > | \/\ ___/ \___ \ \___ \ +\____|__ / __/|__| \___ >____ >____ > +========\/|__|===============\/=====\/=====\/ +:: Spring Boot :: (v.2.0.0.M3) diff --git a/chapter18/batch-boot/src/main/resources/logback.xml b/chapter18/batch-boot/src/main/resources/logback.xml new file mode 100755 index 00000000..3c41ebc6 --- /dev/null +++ b/chapter18/batch-boot/src/main/resources/logback.xml @@ -0,0 +1,21 @@ + + + + + true + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n + + + + + + + + + + + diff --git a/chapter18/batch-boot/src/main/resources/support/singer.sql b/chapter18/batch-boot/src/main/resources/support/singer.sql new file mode 100644 index 00000000..e452d453 --- /dev/null +++ b/chapter18/batch-boot/src/main/resources/support/singer.sql @@ -0,0 +1,8 @@ +DROP TABLE SINGER IF EXISTS; + +CREATE TABLE SINGER ( + singer_id BIGINT IDENTITY NOT NULL PRIMARY KEY, + first_name VARCHAR(20), + last_name VARCHAR(20), + song VARCHAR(100) +); diff --git a/chapter18/batch-boot/src/main/resources/support/test-data.csv b/chapter18/batch-boot/src/main/resources/support/test-data.csv new file mode 100644 index 00000000..54253c7b --- /dev/null +++ b/chapter18/batch-boot/src/main/resources/support/test-data.csv @@ -0,0 +1,4 @@ +John,Mayer,Helpless +Eric,Clapton,Change The World +John,Butler,Ocean +BB,King,Chains And Things \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index e861603c..c82c0ff0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -299,6 +299,9 @@ include 'chapter18:batch' findProject(':chapter18:batch')?.name = 'batch' include 'chapter18:batch-cfg' findProject(':chapter18:batch-cfg')?.name = 'batch-cfg' +include 'chapter18:batch-boot' +findProject(':chapter18:batch-boot')?.name = 'batch-boot' + include 'chapter18:batch-jsr352' findProject(':chapter18:batch-jsr352')?.name = 'batch-jsr352' @@ -314,4 +317,3 @@ rootProject.children.each { project -> assert project.buildFile.isFile() } -