Skip to content

Commit

Permalink
Add sample job based on PetClinic application
Browse files Browse the repository at this point in the history
Signed-off-by: Mahmoud Ben Hassine <[email protected]>
  • Loading branch information
fmbenhassine committed Jan 7, 2025
1 parent aa8fb75 commit 90e7e9f
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 0 deletions.
11 changes: 11 additions & 0 deletions spring-batch-samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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) {
}
Original file line number Diff line number Diff line change
@@ -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<Owner> ownersReader(DataSource dataSource) {
return new JdbcCursorItemReaderBuilder<Owner>().name("ownersReader")
.sql("SELECT * FROM OWNERS")
.dataSource(dataSource)
.rowMapper(new DataClassRowMapper<>(Owner.class))
.build();
}

@Bean
public FlatFileItemWriter<Owner> ownersWriter() {
return new FlatFileItemWriterBuilder<Owner>().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<Owner> ownersReader, FlatFileItemWriter<Owner> ownersWriter) {
return new JobBuilder("ownersExportJob", jobRepository)
.start(new StepBuilder("ownersExportStep", jobRepository).<Owner, Owner>chunk(5, transactionManager)
.reader(ownersReader)
.writer(ownersWriter)
.build())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -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
```
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch="http://www.springframework.org/schema/batch"
xsi:schemaLocation="
http://www.springframework.org/schema/batch https://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<batch:job id="ownersExportJob" xmlns="http://www.springframework.org/schema/batch">
<batch:step id="ownersExportStep">
<batch:tasklet>
<batch:chunk reader="ownersReader" writer="ownersWriter" commit-interval="5"/>
</batch:tasklet>
</batch:step>
</batch:job>

<bean id="ownersReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="dataSource"/>
<property name="sql" value="select * from owners"/>
<property name="rowMapper">
<bean class="org.springframework.jdbc.core.DataClassRowMapper">
<constructor-arg value="org.springframework.batch.samples.petclinic.Owner"/>
</bean>
</property>
</bean>

<bean id="ownersWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:owners.csv" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value=","/>
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.RecordFieldExtractor">
<constructor-arg value="org.springframework.batch.samples.petclinic.Owner"/>
<property name="names" value="id,firstname,lastname,address,city,telephone"/>
</bean>
</property>
</bean>
</property>
</bean>

</beans>
Original file line number Diff line number Diff line change
@@ -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());
}

}

0 comments on commit 90e7e9f

Please sign in to comment.