From 90e7e9fefacfe8cae1ee188e114d402ef7e7e3f1 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Tue, 7 Jan 2025 12:07:32 +0100 Subject: [PATCH] Add sample job based on PetClinic application Signed-off-by: Mahmoud Ben Hassine --- spring-batch-samples/README.md | 11 +++ .../batch/samples/petclinic/Owner.java | 19 +++++ .../OwnersExportJobConfiguration.java | 71 ++++++++++++++++++ .../batch/samples/petclinic/README.md | 21 ++++++ .../samples/common/business-schema-hsqldb.sql | 23 ++++++ .../samples/petclinic/job/ownersExportJob.xml | 42 +++++++++++ .../PetClinicJobFunctionalTests.java | 73 +++++++++++++++++++ 7 files changed, 260 insertions(+) create mode 100644 spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/Owner.java create mode 100644 spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/OwnersExportJobConfiguration.java create mode 100644 spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/README.md create mode 100644 spring-batch-samples/src/main/resources/org/springframework/batch/samples/petclinic/job/ownersExportJob.xml create mode 100644 spring-batch-samples/src/test/java/org/springframework/batch/samples/petclinic/PetClinicJobFunctionalTests.java diff --git a/spring-batch-samples/README.md b/spring-batch-samples/README.md index eb26857fc..770c7fd93 100644 --- a/spring-batch-samples/README.md +++ b/spring-batch-samples/README.md @@ -61,6 +61,7 @@ The IO Sample Job has a number of special instances that show different IO featu | [multiResource Sample](#multiresource-input-output-job) | x | | | | | | | x | | x | | x | | [XML Input Output Sample](#xml-input-output) | | | x | | | | | | | | | | | [MongoDB sample](#mongodb-sample) | | | | | x | | | | x | | | | +| [PetClinic sample](#petclinic-sample) | | | | | x | x | | | | | | | ### Common Sample Source Structures @@ -615,6 +616,16 @@ $>docker run --name mongodb --rm -d -p 27017:27017 mongo Once MongoDB is up and running, run the `org.springframework.batch.samples.mongodb.MongoDBSampleApp` class without any argument to start the sample. +### PetClinic sample + +This sample uses the [PetClinic Spring application](https://github.com/spring-projects/spring-petclinic) to show how to use +Spring Batch to export data from a relational database table to a flat file. + +The job in this sample is a single-step job that exports data from the `owners` table +to a flat file named `owners.csv`. + +[PetClinic Sample](src/main/java/org/springframework/batch/samples/petclinic/README.md) + ### Adhoc Loop and JMX Sample This job is simply an infinite loop. It runs forever so it is diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/Owner.java b/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/Owner.java new file mode 100644 index 000000000..7a66d7d29 --- /dev/null +++ b/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/Owner.java @@ -0,0 +1,19 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.samples.petclinic; + +public record Owner(int id, String firstname, String lastname, String address, String city, String telephone) { +} diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/OwnersExportJobConfiguration.java b/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/OwnersExportJobConfiguration.java new file mode 100644 index 000000000..4a27ffb23 --- /dev/null +++ b/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/OwnersExportJobConfiguration.java @@ -0,0 +1,71 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.samples.petclinic; + +import javax.sql.DataSource; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +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.batch.item.database.JdbcCursorItemReader; +import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder; +import org.springframework.batch.item.file.FlatFileItemWriter; +import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder; +import org.springframework.batch.samples.common.DataSourceConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.FileSystemResource; +import org.springframework.jdbc.core.DataClassRowMapper; +import org.springframework.jdbc.support.JdbcTransactionManager; + +@Configuration +@EnableBatchProcessing +@Import(DataSourceConfiguration.class) +public class OwnersExportJobConfiguration { + + @Bean + public JdbcCursorItemReader ownersReader(DataSource dataSource) { + return new JdbcCursorItemReaderBuilder().name("ownersReader") + .sql("SELECT * FROM OWNERS") + .dataSource(dataSource) + .rowMapper(new DataClassRowMapper<>(Owner.class)) + .build(); + } + + @Bean + public FlatFileItemWriter ownersWriter() { + return new FlatFileItemWriterBuilder().name("ownersWriter") + .resource(new FileSystemResource("owners.csv")) + .delimited() + .names("id", "firstname", "lastname", "address", "city", "telephone") + .build(); + } + + @Bean + public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager, + JdbcCursorItemReader ownersReader, FlatFileItemWriter ownersWriter) { + return new JobBuilder("ownersExportJob", jobRepository) + .start(new StepBuilder("ownersExportStep", jobRepository).chunk(5, transactionManager) + .reader(ownersReader) + .writer(ownersWriter) + .build()) + .build(); + } + +} diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/README.md b/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/README.md new file mode 100644 index 000000000..12be08e09 --- /dev/null +++ b/spring-batch-samples/src/main/java/org/springframework/batch/samples/petclinic/README.md @@ -0,0 +1,21 @@ +# PetClinic Job + +## About the sample + +This sample uses the [PetClinic Spring application](https://github.com/spring-projects/spring-petclinic) to show how to use +Spring Batch to export data from a relational database table to a flat file. + +The job in this sample is a single-step job that exports data from the `owners` table +to a flat file named `owners.csv`. + +## Run the sample + +You can run the sample from the command line as following: + +``` +$>cd spring-batch-samples +# Launch the sample using the XML configuration +$>../mvnw -Dtest=PetClinicJobFunctionalTests#testLaunchJobWithXmlConfiguration test +# Launch the sample using the Java configuration +$>../mvnw -Dtest=PetClinicJobFunctionalTests#testLaunchJobWithJavaConfiguration test +``` \ No newline at end of file diff --git a/spring-batch-samples/src/main/resources/org/springframework/batch/samples/common/business-schema-hsqldb.sql b/spring-batch-samples/src/main/resources/org/springframework/batch/samples/common/business-schema-hsqldb.sql index b02b0b89a..ffd682304 100644 --- a/spring-batch-samples/src/main/resources/org/springframework/batch/samples/common/business-schema-hsqldb.sql +++ b/spring-batch-samples/src/main/resources/org/springframework/batch/samples/common/business-schema-hsqldb.sql @@ -100,3 +100,26 @@ CREATE TABLE ERROR_LOG ( STEP_NAME CHAR(20) , MESSAGE VARCHAR(300) NOT NULL ) ; + +-- PetClinic sample tables + +CREATE TABLE OWNERS ( + ID INTEGER IDENTITY PRIMARY KEY, + FIRSTNAME VARCHAR(30), + LASTNAME VARCHAR(30), + ADDRESS VARCHAR(255), + CITY VARCHAR(80), + TELEPHONE VARCHAR(20) +); + +INSERT INTO OWNERS VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); +INSERT INTO OWNERS VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); +INSERT INTO OWNERS VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); +INSERT INTO OWNERS VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); +INSERT INTO OWNERS VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); +INSERT INTO OWNERS VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); +INSERT INTO OWNERS VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); +INSERT INTO OWNERS VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); +INSERT INTO OWNERS VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); +INSERT INTO OWNERS VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); + diff --git a/spring-batch-samples/src/main/resources/org/springframework/batch/samples/petclinic/job/ownersExportJob.xml b/spring-batch-samples/src/main/resources/org/springframework/batch/samples/petclinic/job/ownersExportJob.xml new file mode 100644 index 000000000..0247f5511 --- /dev/null +++ b/spring-batch-samples/src/main/resources/org/springframework/batch/samples/petclinic/job/ownersExportJob.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/samples/petclinic/PetClinicJobFunctionalTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/samples/petclinic/PetClinicJobFunctionalTests.java new file mode 100644 index 000000000..5f790cba9 --- /dev/null +++ b/spring-batch-samples/src/test/java/org/springframework/batch/samples/petclinic/PetClinicJobFunctionalTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.samples.petclinic; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringJUnitConfig(locations = { "/simple-job-launcher-context.xml", + "/org/springframework/batch/samples/petclinic/job/ownersExportJob.xml" }) +class PetClinicJobFunctionalTests { + + @Autowired + private JobLauncherTestUtils jobLauncherTestUtils; + + @BeforeEach + public void setup() throws IOException { + Files.deleteIfExists(Paths.get("owners.csv")); + } + + @Test + void testLaunchJobWithXmlConfiguration() throws Exception { + // when + JobExecution jobExecution = jobLauncherTestUtils.launchJob(); + + // then + assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus()); + } + + @Test + void testLaunchJobWithJavaConfiguration() throws Exception { + // given + ApplicationContext context = new AnnotationConfigApplicationContext(OwnersExportJobConfiguration.class); + JobLauncher jobLauncher = context.getBean(JobLauncher.class); + Job job = context.getBean(Job.class); + + // when + JobExecution jobExecution = jobLauncher.run(job, new JobParameters()); + + // then + assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus()); + } + +}