Выбрать главу

<dependency>

    <groupId>org.springframework.integration</groupId>

    <artifactId>spring-integration-file</artifactId>

</dependency>

Класс EmailToOrderTransformer является реализацией интерфейса Spring Integration Transformer посредством расширения AbstractMailMessageTransformer (показано в следующем листинге).

Листинг 9.6. Преобразование входящих писем в тако-заказы с использованием интеграционного преобразователя

@Component

public class EmailToOrderTransformer

        extends AbstractMailMessageTransformer<Order> {

    @Override

    protected AbstractIntegrationMessageBuilder<Order> doTransform(Message mailMessage)

            throws Exception {

        Order tacoOrder = processPayload(mailMessage);

        return MessageBuilder.withPayload(tacoOrder);

    }

    …

}

AbstractMailMessageTransformer - удобный базовый класс для обработки сообщений, чья полезная нагрузка - это электронная почта. Он заботится о извлечении информации электронной почты из входящего сообщения в объект Message, который передается в метод doTransform().

В методе doTransform() вы передаете Message private методу с именем processPayload() для анализа электронной почты на получения объекта Order. Несмотря на то, что этот объект Order не похож на объект Order, используемый в основном приложении TacoCloud; это немного проще:

package tacos.email;

import java.util.ArrayList;

import java.util.List;

import lombok.Data;

@Data

public class Order {

    private final String email;

    private List<Taco> tacos = new ArrayList<>();

    public void addTaco(Taco taco) {

        this.tacos.add(taco);

    }

}

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

Парсинг электронных писем в тако-заказы является нетривиальной задачей. На самом деле, даже простенькая реализация включает в себя несколько десятков строк кода. И эти несколько десятков строк кода ничего не дадут для дальнейшего обсуждения Spring Integration и того, как реализовать трансформер. Поэтому, чтобы сэкономить место, я опускаю детали метода processPayload().

Последнее, что делает EmailToOrderTransformer, это возвращает MessageBuilder с полезной нагрузкой, содержащей объект Order. Сообщение, сгенерированное MessageBuilder, отправляется последнему компоненту в потоке интеграции: обработчику сообщений, который отправляет заказ в Taco Cloud API. OrderSubmitMessageHandler, показанный в следующем листинге, реализует GenericHandler в Spring Integration для обработки сообщений с полезной нагрузкой Order.

Листинг 9.7. Отправка заказов в Taco Cloud API через обработчик сообщений

package tacos.email;

import java.util.Map;

import org.springframework.integration.handler.GenericHandler;

import org.springframework.stereotype.Component;

import org.springframework.web.client.RestTemplate;

@Component

public class OrderSubmitMessageHandler implements GenericHandler<Order> {

    private RestTemplate rest;

    private ApiProperties apiProps;

 

    public OrderSubmitMessageHandler(

            ApiProperties apiProps, RestTemplate rest) {

        this.apiProps = apiProps;

        this.rest = rest;

    }

 

    @Override

    public Object handle(Order order, Map<String, Object> headers) {

        rest.postForObject(apiProps.getUrl(), order, String.class);

        return null;

    }

}

Чтобы удовлетворить требования интерфейса GenericHandler, OrderSubmitMessageHandler переопределяет метод handle(). Этот метод получает входящий объект Order и использует внедренный RestTemplate для отправки Order посредством POST запроса на URL-адрес, полученный из объекте ApiProperties. Наконец, метод handle() возвращает null, чтобы указать, что этот обработчик отмечает конец потока.

ApiProperties используется, чтобы избежать жесткого кодирования URL-адреса при вызове postForObject(). Это файл свойств конфигурации, который выглядит следующим образом:

@Data

@ConfigurationProperties(prefix="tacocloud.api")

@Componentpublic class ApiProperties {

    private String url;

}

А в application.yml URL-адрес для Taco Cloud API может быть настроен следующим образом:

tacocloud:

    api:

        urclass="underline" http://api.tacocloud.com

Чтобы сделать RestTemplate доступным в проекте, чтобы его можно было внедрить в OrderSubmitMessageHandler, необходимо добавить веб-стартер Spring Boot в сборку проекта:

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

</dependency>

В то время как это делает RestTemplate доступным в classpath, оно также запускает автоконфигурирование для Spring MVC. В качестве автономного потока Spring Integration приложению не требуется Spring MVC или даже встроенный Tomcat, который обеспечивает автоконфигурация. Поэтому вам следует отключить автоконфигурирование Spring MVC с помощью следующей записи в application.ymclass="underline"

spring:

    main:

        web-application-type: none

Свойство spring.main.web-application-type может быть установлено в servlet, reactive или none. Когда Spring MVC находится в classpath, автоконфигурация устанавливает его значение в servlet. Но здесь вы переопределяете его на none, чтобы Spring MVC и Tomcat не были автоматически сконфигурированы. (Мы поговорим подробнее о том, что означает, что приложение является reactive веб-приложением в главе 11.)