В этой статье мы покажем вам, как использовать Spring Batch для чтения XML-файла с ItemReader с помощью StaxEventItemReader и записи его данных в NoSQL с помощью Custom ItemWriter с JpaRepository. Здесь мы использовали MongoDB.
Custom ItemReader или ItemWriter — это класс, в котором мы пишем свой собственный способ чтения или записи данных. В Custom Reader мы также должны обрабатывать логику фрагментирования. Это удобно, если наша логика чтения сложна и не может быть обработана с помощью Default ItemReader, предоставляемого spring.
Использованные инструменты и библиотеки:
1. Maven 3.5+
2. Весенний пакетный стартер
3. Весна ОКСМ
4. Данные Mongodb стартера
5. xstream
Вам также могут понравиться:
конвертирование XML в JSON, использование Raw в MongoDB и Spring Batch
Maven Dependency — нужно настроить проект.
XML
xxxxxxxxxx
1
2
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
<modelVersion>4.0.0</modelVersion>
5
<p>
6
<groupId>org.springframework.boot</groupId>
7
<artifactId>spring-boot-starter-parent</artifactId>
8
<version>2.2.2.RELEASE</version>
9
<relativePath ></relativePath> <!-- lookup parent from repository -->
10
</parent>
11
<groupId>com.example</groupId>
12
<artifactId>spring-batch-mongodb</artifactId>
13
<version>0.0.1-SNAPSHOT</version>
14
<name>spring-batch-mongodb</name>
15
<description>Demo project for Spring Boot</description>
16
<p>
19
<java.version>1.8</java.version>
20
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
21
</properties>
22
<dependencies>
25
<dependency>
26
<groupId>org.springframework.boot</groupId>
27
<artifactId>spring-boot-starter-batch</artifactId>
28
</dependency>
29
<dependency>
30
<groupId>org.springframework</groupId>
31
<artifactId>spring-oxm</artifactId>
32
</dependency>
33
<dependency>
34
<groupId>org.springframework.boot</groupId>
35
<artifactId>spring-boot-starter-data-mongodb</artifactId>
36
</dependency>
37
<dependency>
38
<groupId>com.thoughtworks.xstream</groupId>
39
<artifactId>xstream</artifactId>
40
<version>1.4.7</version>
41
</dependency>
42
<dependency>
43
<groupId>org.projectlombok</groupId>
44
<artifactId>lombok</artifactId>
45
<optional>true</optional>
46
</dependency>
47
<dependency>
48
<groupId>org.springframework.boot</groupId>
49
<artifactId>spring-boot-starter-test</artifactId>
50
<scope>test</scope>
51
<exclusions>
52
<exclusion>
53
<groupId>org.junit.vintage</groupId>
54
<artifactId>junit-vintage-engine</artifactId>
55
</exclusion>
56
</exclusions>
57
</dependency>
58
<dependency>
59
<groupId>org.springframework.batch</groupId>
60
<artifactId>spring-batch-test</artifactId>
61
<scope>test</scope>
62
</dependency>
63
<dependency>
64
<groupId>com.h2database</groupId>
65
<artifactId>h2</artifactId>
66
<scope>runtime</scope>
67
</dependency>
68
</dependencies>
69
<build>
70
<p>
71
<p>
72
<groupId>org.springframework.boot</groupId>
73
<artifactId>spring-boot-maven-plugin</artifactId>
74
</plugin>
75
</plugins>
76
</build>
77
</project>
CustomerWriter - это пользовательский модуль записи, который мы создали для записи данных о клиентах в MongoDB. Пользовательский писатель дает возможность выполнять сложные операции тоже.
Джава
xxxxxxxxxx
1
package com.example.writer;
2
import java.util.List;
4
import org.springframework.batch.item.ItemWriter;
6
import org.springframework.beans.factory.annotation.Autowired;
7
import com.example.domain.Customer;
8
import com.example.repository.CustomerRepository;
9
public class CustomerWriter implements ItemWriter<Customer>{
12
13
private CustomerRepository customerRepository;
14
15
16
public void write(List<? extends Customer> customers) throws Exception {
17
customerRepository.saveAll(customers);
18
}
19
}
CustomerRepository - это репозиторий Mongo, который взаимодействует с базой данных Mongo и выполняет операции по возврату данных.
Джава
xxxxxxxxxx
1
package com.example.repository;
2
import org.springframework.data.mongodb.repository.MongoRepository;
4
import com.example.domain.Customer;
5
public interface CustomerRepository extends MongoRepository<Customer, String>{
8
}
Клиент. Это класс документов Mongo, содержащий бизнес-данные.
Джава
xxxxxxxxxx
1
package com.example.domain;
2
import java.time.LocalDate;
4
import javax.xml.bind.annotation.XmlRootElement;
5
import org.springframework.data.annotation.Id;
6
import org.springframework.data.mongodb.core.mapping.Document;
7
import org.springframework.data.mongodb.core.mapping.Field;
8
import lombok.AllArgsConstructor;
9
import lombok.Builder;
10
import lombok.Data;
11
import lombok.NoArgsConstructor;
12
16
17
18
19
name = "Customer") (
20
21
public class Customer {
22
23
private Long id;
24
25
private String firstName;
26
27
private String lastName;
28
29
private LocalDate birthdate;
30
}
CustomerConverter - мы реализовали интерфейс конвертера. Этот класс используется для реализаций конвертера и отвечает за упорядочение объектов Java в / из текстовых данных. Если во время обработки возникает исключение, необходимо сгенерировать ConversionException. При работе с высокоуровневым фасадом com.thoughtworks.xstream.XStream вы можете зарегистрировать новые конвертеры с помощью метода XStream.registerConverter ().
Джава
xxxxxxxxxx
1
package com.example.config;
2
import java.time.LocalDate;
4
import java.time.format.DateTimeFormatter;
5
import com.example.domain.Customer;
6
import com.thoughtworks.xstream.converters.Converter;
7
import com.thoughtworks.xstream.converters.MarshallingContext;
8
import com.thoughtworks.xstream.converters.UnmarshallingContext;
9
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
10
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
11
public class CustomerConverter implements Converter {
15
private static final DateTimeFormatter DT_FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
16
17
18
public boolean canConvert(Class type) {
19
return type.equals(Customer.class);
20
}
21
23
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
24
// Don't do anything
25
}
26
28
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
29
reader.moveDown();
30
Customer customer = new Customer();
31
customer.setId(Long.valueOf(reader.getValue()));
32
33
reader.moveUp();
34
reader.moveDown();
35
customer.setFirstName(reader.getValue());
36
37
reader.moveUp();
38
reader.moveDown();
39
customer.setLastName(reader.getValue());
40
41
reader.moveUp();
42
reader.moveDown();
43
customer.setBirthdate(LocalDate.parse(reader.getValue(), DT_FORMATTER));
44
45
return customer;
46
}
47
}
JobConfiguration - это основной класс, отвечающий за выполнение пакетного задания. В этом классе мы использовали различные Бины для выполнения отдельных задач.
StaxEventItemReader - средство чтения элементов для чтения входных данных XML на основе StAX. Он извлекает фрагменты из входного XML-документа, который соответствует записям для обработки. Фрагменты обертываются событиями StartDocument и EndDocument, так что фрагменты могут быть далее обработаны как отдельные XML-документы. Реализация не является поточно-ориентированной.
CustomerWriter - это пользовательский класс, который записывает данные в MongoDB.
step1 - этот шаг настраивает ItemReader и ItemWriter, однако ItemProcessor - это необязательный шаг, который мы пропустили.
Работа - Пакетный объект домена, представляющий работу. Job - это явная абстракция, представляющая конфигурацию задания, указанную разработчиком. Следует отметить, что политика перезапуска применяется к работе в целом, а не к шагу.
Джава
xxxxxxxxxx
1
package com.example.config;
2
import java.util.HashMap;
4
import java.util.Map;
5
import org.springframework.batch.core.Job;
6
import org.springframework.batch.core.Step;
7
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
8
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
9
import org.springframework.batch.item.xml.StaxEventItemReader;
10
import org.springframework.beans.factory.annotation.Autowired;
11
import org.springframework.context.annotation.Bean;
12
import org.springframework.context.annotation.Configuration;
13
import org.springframework.core.io.ClassPathResource;
14
import org.springframework.oxm.xstream.XStreamMarshaller;
15
import com.example.domain.Customer;
16
import com.example.writer.CustomerWriter;
17
21
public class JobConfiguration {
22
23
private JobBuilderFactory jobBuilderFactory;
24
25
26
private StepBuilderFactory stepBuilderFactory;
27
29
public StaxEventItemReader<Customer> customerItemReader(){
30
Map<String, Class> aliases = new HashMap<>();
31
aliases.put("customer", Customer.class);
32
33
CustomerConverter converter = new CustomerConverter();
34
XStreamMarshaller ummarshaller = new XStreamMarshaller();
36
ummarshaller.setAliases(aliases);
37
ummarshaller.setConverters(converter);
38
39
StaxEventItemReader<Customer> reader = new StaxEventItemReader<>();
40
reader.setResource(new ClassPathResource("/data/customer.xml"));
41
reader.setFragmentRootElementName("customer");
42
reader.setUnmarshaller(ummarshaller);
43
44
return reader;
45
}
46
47
48
public CustomerWriter customerWriter() {
49
return new CustomerWriter();
50
}
51
52
53
public Step step1() throws Exception {
54
return stepBuilderFactory.get("step1")
55
.<Customer, Customer>chunk(200)
56
.reader(customerItemReader())
57
.writer(customerWriter())
58
.build();
59
}
60
61
62
public Job job() throws Exception {
63
return jobBuilderFactory.get("job")
64
.start(step1())
65
.build();
66
}
67
}
application.properties
Джава
xxxxxxxxxx
1
spring.data.mongodb.host=localhost
2
spring.data.mongodb.port=27017
Customer.xml - это пример данных, которые будут прочитаны Spring Batch.
XML
xxxxxxxxxx
1
2
<customers>
3
<customer>
4
<id>1</id>
5
<firstName>John</firstName>
6
<lastName>Doe</lastName>
7
<birthdate>10-10-1988 19:43:23</birthdate>
8
</customer>
9
<customer>
10
<id>2</id>
11
<firstName>James</firstName>
12
<lastName>Moss</lastName>
13
<birthdate>01-04-1991 10:20:23</birthdate>
14
</customer>
15
<customer>
16
<id>3</id>
17
<firstName>Jonie</firstName>
18
<lastName>Gamble</lastName>
19
<birthdate>21-07-1982 11:12:13</birthdate>
20
</customer>
21
<customer>
22
<id>4</id>
23
<firstName>Mary</firstName>
24
<lastName>Kline</lastName>
25
<birthdate>07-08-1973 11:27:42</birthdate>
26
</customer>
27
<customer>
28
<id>5</id>
29
<firstName>William</firstName>
30
<lastName>Lockhart</lastName>
31
<birthdate>04-04-1994 04:15:11</birthdate>
32
</customer>
33
<customer>
34
<id>6</id>
35
<firstName>John</firstName>
36
<lastName>Doe</lastName>
37
<birthdate>10-10-1988 19:43:23</birthdate>
38
</customer>
39
<customer>
40
<id>7</id>
41
<firstName>Kristi</firstName>
42
<lastName>Dukes</lastName>
43
<birthdate>17-09-1983 21:22:23</birthdate>
44
</customer>
45
<customer>
46
<id>8</id>
47
<firstName>Angel</firstName>
48
<lastName>Porter</lastName>
49
<birthdate>15-12-1980 18:09:09</birthdate>
50
</customer>
51
<customer>
52
<id>9</id>
53
<firstName>Mary</firstName>
54
<lastName>Johnston</lastName>
55
<birthdate>07-07-1987 19:43:03</birthdate>
56
</customer>
57
<customer>
58
<id>10</id>
59
<firstName>Linda</firstName>
60
<lastName>Rodriguez</lastName>
61
<birthdate>16-09-1991 09:13:43</birthdate>
62
</customer>
63
<customer>
64
<id>11</id>
65
<firstName>Phillip</firstName>
66
<lastName>Lopez</lastName>
67
<birthdate>18-12-1965 11:10:09</birthdate>
68
</customer>
69
<customer>
70
<id>12</id>
71
<firstName>Peter</firstName>
72
<lastName>Dixon</lastName>
73
<birthdate>09-05-1996 19:09:23</birthdate>
74
</customer>
75
</customers>
MainApp - SpringBatchMongodbApplication можно запустить как проект Spring Boot.
Джава
xxxxxxxxxx
1
package com.example;
2
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
4
import org.springframework.boot.SpringApplication;
5
import org.springframework.boot.autoconfigure.SpringBootApplication;
6
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
7
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
8
exclude = {DataSourceAutoConfiguration.class}) (
12
13
basePackages = "com.example.repository") (
14
public class SpringBatchMongodbApplication {
15
public static void main(String[] args) {
18
SpringApplication.run(SpringBatchMongodbApplication.class, args);
19
}
20
}
Вывод : можно сделать вывод, что Spring Batch прочитал данные и записал их в MongoDB с предложенным типом схемы / документа.
Джава
xxxxxxxxxx
1
db.getCollection('customer').find({})
2
/* 1 */
5
{
6
"_id" : NumberLong(1),
7
"firstName" : "John",
8
"lastName" : "Doe",
9
"birthdate" : ISODate("1988-10-09T18:30:00.000Z"),
10
"_class" : "com.example.domain.Customer"
11
}
12
/* 2 */
15
{
16
"_id" : NumberLong(2),
17
"firstName" : "James",
18
"lastName" : "Moss",
19
"birthdate" : ISODate("1991-03-31T18:30:00.000Z"),
20
"_class" : "com.example.domain.Customer"
21
}
22
/* 3 */
25
{
26
"_id" : NumberLong(3),
27
"firstName" : "Jonie",
28
"lastName" : "Gamble",
29
"birthdate" : ISODate("1982-07-20T18:30:00.000Z"),
30
"_class" : "com.example.domain.Customer"
31
}
32
/* 4 */
35
{
36
"_id" : NumberLong(4),
37
"firstName" : "Mary",
38
"lastName" : "Kline",
39
"birthdate" : ISODate("1973-08-06T18:30:00.000Z"),
40
"_class" : "com.example.domain.Customer"
41
}
42
/* 5 */
45
{
46
"_id" : NumberLong(5),
47
"firstName" : "William",
48
"lastName" : "Lockhart",
49
"birthdate" : ISODate("1994-04-03T18:30:00.000Z"),
50
"_class" : "com.example.domain.Customer"
51
}
52
/* 6 */
55
{
56
"_id" : NumberLong(6),
57
"firstName" : "John",
58
"lastName" : "Doe",
59
"birthdate" : ISODate("1988-10-09T18:30:00.000Z"),
60
"_class" : "com.example.domain.Customer"
61
}
62
/* 7 */
65
{
66
"_id" : NumberLong(7),
67
"firstName" : "Kristi",
68
"lastName" : "Dukes",
69
"birthdate" : ISODate("1983-09-16T18:30:00.000Z"),
70
"_class" : "com.example.domain.Customer"
71
}
72
/* 8 */
75
{
76
"_id" : NumberLong(8),
77
"firstName" : "Angel",
78
"lastName" : "Porter",
79
"birthdate" : ISODate("1980-12-14T18:30:00.000Z"),
80
"_class" : "com.example.domain.Customer"
81
}
82
/* 9 */
85
{
86
"_id" : NumberLong(9),
87
"firstName" : "Mary",
88
"lastName" : "Johnston",
89
"birthdate" : ISODate("1987-07-06T18:30:00.000Z"),
90
"_class" : "com.example.domain.Customer"
91
}
92
/* 10 */
95
{
96
"_id" : NumberLong(10),
97
"firstName" : "Linda",
98
"lastName" : "Rodriguez",
99
"birthdate" : ISODate("1991-09-15T18:30:00.000Z"),
100
"_class" : "com.example.domain.Customer"
101
}
102
/* 11 */
105
{
106
"_id" : NumberLong(11),
107
"firstName" : "Phillip",
108
"lastName" : "Lopez",
109
"birthdate" : ISODate("1965-12-17T18:30:00.000Z"),
110
"_class" : "com.example.domain.Customer"
111
}
112
/* 12 */
115
{
116
"_id" : NumberLong(12),
117
"firstName" : "Peter",
118
"lastName" : "Dixon",
119
"birthdate" : ISODate("1996-05-08T18:30:00.000Z"),
120
"_class" : "com.example.domain.Customer"
121
}
Спасибо за прочтение!
Дальнейшее чтение
Spring Batch: чтение XML-файла и запись в базу данных Oracle.