Статьи

Spring Integration — Создание и изменение файла опроса

1. Введение

Поддержка файлов — это еще одна конечная точка Spring Integration для связи с внешними системами. В этом случае он предоставляет несколько компонентов для чтения, записи и преобразования файлов. В этом посте мы собираемся написать приложение, которое отслеживает каталог, чтобы прочитать все файлы в нем. В бетоне это делает следующее:

  • Когда приложение запускается, оно читает все файлы, присутствующие в каталоге.
  • Затем приложение будет следить за каталогом, чтобы обнаружить новые файлы и существующие файлы, которые были изменены.

Исходный код можно найти в Github .

2 Конфигурация

Приложение построено с использованием Spring Boot, поскольку оно значительно облегчает настройку. Чтобы создать начальную инфраструктуру приложения, вы можете перейти по адресу https://start.spring.io/ , выбрать модуль интеграции и сгенерировать проект. Затем вы можете открыть ZIP-файл в вашей любимой IDE.

Я добавил пару зависимостей в pom.xml, например commons.io или Spring Integration Java DSL. Мой файл pom.xml выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?xml version="1.0" encoding="UTF-8"?>
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>xpadro.spring.integration</groupId>
  <artifactId>file-read-directory</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>file-read-directory</name>
  <description>Demo project for Spring Boot</description>
 
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>
 
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-integration</artifactId>
    </dependency>
 
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
 
    <!-- Spring Integration - Java DSL -->
    <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-java-dsl</artifactId>
      <version>1.0.0.RELEASE</version>
    </dependency>
 
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.5</version>
    </dependency>
 
  </dependencies>
 
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
 
</project>

Отправной точкой является FileReadDirectoryApplication:

1
2
3
4
5
6
7
@SpringBootApplication
public class FileReadDirectoryApplication {
 
    public static void main(String[] args) throws IOException, InterruptedException {
        SpringApplication.run(FileReadDirectoryApplication.class, args);
    }
}

Начиная с этого момента, мы собираемся добавить компоненты Spring Integration для чтения из определенной папки файловой системы.

3 Добавление адаптера

Для чтения из файловой системы нам нужен адаптер входящего канала. Адаптер является источником сообщений для чтения файлов, который отвечает за опрос файловой системы в каталоге и создает сообщение из каждого найденного файла.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@Bean
@InboundChannelAdapter(value = "fileInputChannel", poller = @Poller(fixedDelay = "1000"))
public MessageSource<File> fileReadingMessageSource() {
    CompositeFileListFilter<File> filters = new CompositeFileListFilter<>();
    filters.addFilter(new SimplePatternFileListFilter("*.txt"));
    filters.addFilter(new LastModifiedFileFilter());
     
    FileReadingMessageSource source = new FileReadingMessageSource();
    source.setAutoCreateDirectory(true);
    source.setDirectory(new File(DIRECTORY));
    source.setFilter(filters);
     
    return source;
}

Мы можем предотвратить опрос некоторых типов файлов, установив список фильтров для источника сообщений. Для этого примера были включены два фильтра:

  • SimplePatternFileListFilter : Фильтр предоставлен Spring. Только файлы с указанным расширением будут опрошены. В этом случае принимаются только текстовые файлы.
  • LastModifiedFileFilter : пользовательский фильтр. Этот фильтр отслеживает уже опрошенные файлы и отфильтровывает файлы, не измененные с момента последнего отслеживания.

4 Обработка файлов

Для каждого опрашиваемого файла мы преобразуем его содержимое в строку, прежде чем передать его процессору. Для этого Spring уже предоставляет компонент:

1
2
3
4
@Bean
public FileToStringTransformer fileToStringTransformer() {
    return new FileToStringTransformer();
}

Следовательно, вместо получения сообщения <File>, процессор получит сообщение <String>. Файловый процессор — это наш пользовательский компонент, который будет выполнять такие же сложные функции, как печать содержимого файла:

01
02
03
04
05
06
07
08
09
10
11
public class FileProcessor {
    private static final String HEADER_FILE_NAME = "file_name";
    private static final String MSG = "%s received. Content: %s";
     
    public void process(Message<String> msg) {
        String fileName = (String) msg.getHeaders().get(HEADER_FILE_NAME);
        String content = msg.getPayload();
         
        System.out.println(String.format(MSG, fileName, content));
    }
}

5 Построение потока

Теперь, когда у нас есть все необходимые компоненты, давайте создадим поток. Мы используем Spring Integration Java DSL, поскольку он делает поток более читабельным:

01
02
03
04
05
06
07
08
09
10
11
12
@Bean
public IntegrationFlow processFileFlow() {
    return IntegrationFlows
        .from("fileInputChannel")
        .transform(fileToStringTransformer())
        .handle("fileProcessor", "process").get();
    }
     
    @Bean
    public MessageChannel fileInputChannel() {
        return new DirectChannel();
    }

6 Запуск приложения

В моем каталоге у меня уже есть файл с именем «previousFile.txt». После запуска приложения мы создадим два файла и изменим один из них.

01
02
03
04
05
06
07
08
09
10
public static void main(String[] args) throws IOException, InterruptedException {
    SpringApplication.run(FileReadDirectoryApplication.class, args);
    createFiles();
}
 
private static void createFiles() throws IOException, InterruptedException {
    createFile("file1.txt", "content");
    createFile("file2.txt", "another file");
    appendFile("file1.txt", " modified");
}

Если мы запустим приложение, мы должны увидеть следующие операторы печати:

1
2
3
4
previousFile.txt received. Content: previous content
file1.txt received. Content: content
file2.txt received. Content: another file
file1.txt received. Content: content modified

7 Заключение

В этом примере показано, как просто читать файлы из каталога с помощью Spring Integration, очевидно, с помощью Spring Boot, чтобы упростить настройку. В зависимости от ваших потребностей, вы можете добавить свои собственные пользовательские фильтры к источнику сообщений или использовать другой из предоставляемых Spring, например RegexPatternFileListFilter . Вы можете проверить другие реализации здесь .

Если вы нашли этот пост полезным, поделитесь им или пометьте мой репозиторий 🙂

Я публикую свои новые сообщения в Google Plus и Twitter. Следуйте за мной, если вы хотите быть в курсе нового контента.