Введение в Smooks

Введение в Smooks

1. обзор

В этом руководстве мы познакомим вас сSmooks framework.

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

Прежде всего, давайте вкратце объясним, для чего предназначена эта структура.

2. Smooks

Smooks - это платформа для приложений обработки данных, работающая со структурированными данными, такими как XML или CSV.

Он предоставляет как API, так и модель конфигурации, которая позволяет нам определять преобразования между предопределенными форматами (например, XML в CSV, XML в JSON и т. Д.).

Мы также можем использовать ряд инструментов для настройки нашего отображения, включая скрипты FreeMarker или Groovy.

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

2.1. Ключевая особенность

Давайте посмотрим на основные варианты использования Smooks:

  • Преобразование сообщений - преобразование данных из различных исходных форматов в различные выходные форматы.

  • Обогащение сообщения - заполнение сообщения дополнительными данными, поступающими из внешнего источника данных, такого как база данных

  • Разделение данных - обработка больших файлов (ГБ) и разбиение их на более мелкие

  • Привязка к Java - создание и заполнение объектов Java из сообщений

  • Проверка сообщения - выполнение проверок, таких как регулярное выражение, или даже создание собственных правил проверки

3. Начальная конфигурация

Начнем с зависимости Maven, которую нам нужно добавить к нашемуpom.xml:


    org.milyn
    milyn-smooks-all
    1.7.0

Последнюю версию можно найти наMaven Central.

4. Java Binding

Давайте теперь начнем с привязки сообщений к классам Java. Здесь мы рассмотрим простое преобразование XML в Java.

4.1. Базовые концепции

Начнем с простого примера. Рассмотрим следующий XML:


    771
    IN_PROGRESS

Чтобы выполнить эту задачу с помощью Smooks, нам нужно сделать две вещи: подготовить POJO и конфигурацию Smooks.

Посмотрим, как выглядит наша модель:

public class Order {

    private Date creationDate;
    private Long number;
    private Status status;
    // ...
}
public enum Status {
    NEW, IN_PROGRESS, FINISHED
}

Теперь перейдем к сопоставлениям Smooks.

По сути, отображения представляют собой XML-файл, который содержит логику преобразования. В этой статье мы будем использовать три разных типа правил:

  • bean – определяет отображение конкретного структурированного раздела в класс Java

  • value - определяет отображение для конкретного свойства bean-компонента. Может содержать более продвинутую логику, такую ​​как декодеры, которые используются для сопоставления значений с некоторыми типами данных (такими как дата или десятичный формат)

  • wiring – позволяет нам связать bean-компонент с другими bean-компонентами (например, bean-компонентSupplier будет подключен к bean-компонентуOrder)

Давайте посмотрим на сопоставления, которые мы будем использовать в нашем случае:




    
        
        
        
            yyyy-MM-dd
        
    

Теперь, когда конфигурация готова, давайте попробуем проверить, правильно ли построен наш POJO.

Во-первых, нам нужно создать объект Smooks и передать входной XML в виде потока:

public Order converOrderXMLToOrderObject(String path)
  throws IOException, SAXException {

    Smooks smooks = new Smooks(
      this.class.getResourceAsStream("/smooks-mapping.xml"));
    try {
        JavaResult javaResult = new JavaResult();
        smooks.filterSource(new StreamSource(this.class
          .getResourceAsStream(path)), javaResult);
        return (Order) javaResult.getBean("order");
    } finally {
        smooks.close();
    }
}

И наконец, убедитесь, что конфигурация выполнена правильно:

@Test
public void givenOrderXML_whenConvert_thenPOJOsConstructedCorrectly() throws Exception {
    XMLToJavaConverter xmlToJavaOrderConverter = new XMLToJavaConverter();
    Order order = xmlToJavaOrderConverter
      .converOrderXMLToOrderObject("/order.xml");

    assertThat(order.getNumber(), is(771L));
    assertThat(order.getStatus(), is(Status.IN_PROGRESS));
    assertThat(
      order.getCreationDate(),
      is(new SimpleDateFormat("yyyy-MM-dd").parse("2018-01-14"));
}

4.2. Расширенное связывание - ссылки на другие бины и списки

Давайте расширим наш предыдущий пример тегамиsupplier иorder-items:


    771
    IN_PROGRESS
    
        Company X
        1234567
    
    
        
            1
            PX1234
            9.99
        
        
            1
            RX990
            120.32
        
    

А теперь давайте обновим нашу модель:

public class Order {
    // ..
    private Supplier supplier;
    private List items;
    // ...
}
public class Item {

    private String code;
    private Double price;
    private Integer quantity;
    // ...
}
public class Supplier {

    private String name;
    private String phoneNumber;
    // ...
}

Мы также должны расширить отображение конфигурации с помощью определений bean-компонентовsupplier иitem.

Обратите внимание, что мы также определили разделенный bean-компонентitems, который будет содержать все элементыitem вArrayList.

Наконец, мы будем использовать атрибут Smookswiring, чтобы связать все это вместе.

Посмотрите, как будут выглядеть сопоставления в этом случае:




    
        
        
        
            yyyy-MM-dd
        
        
        
    

    
        
        
    

    
        
    
    
        
        
        
    

Наконец, мы добавим несколько утверждений к нашему предыдущему тесту:

assertThat(
  order.getSupplier(),
  is(new Supplier("Company X", "1234567")));
assertThat(order.getItems(), containsInAnyOrder(
  new Item("PX1234", 9.99,1),
  new Item("RX990", 120.32,1)));

5. Проверка сообщений

Smooks поставляется с механизмом проверки на основе правил. Давайте посмотрим, как они используются.

Определение правил хранится в файле конфигурации, вложенном в тегruleBases, который может содержать множество элементовruleBase.

Каждый элементruleBase должен иметь следующие свойства:

  • name – уникальное имя, используется только для справки

  • src – путь к исходному файлу правила

  • provider - полное имя класса, реализующего интерфейсRuleProvider

Smooks поставляется с двумя поставщиками из коробки:RegexProvider иMVELProvider.

Первый используется для проверки отдельных полей в стиле регулярных выражений.

Второй используется для выполнения более сложной проверки в глобальной области документа. Давайте посмотрим на них в действии.

5.1. RegexProviderс

Давайте используемRegexProvider для проверки двух вещей: формата имени клиента и номера телефона. RegexProvider в качестве источника требует файла свойств Java, которыйshould contain regex validation in key-value fashion.

Чтобы соответствовать нашим требованиям, мы будем использовать следующую настройку:

supplierName=[A-Za-z0-9]*
supplierPhone=^[0-9\\-\\+]{9,15}$

5.2. MVELProviderс

Мы будем использоватьMVELProvider, чтобы проверить, меньше ли общая цена для каждогоorder-item 200. В качестве источника мы подготовим файл CSV с двумя столбцами: имя правила и выражение MVEL.

Чтобы проверить правильность цены, нам нужна следующая запись:

"max_total","orderItem.quantity * orderItem.price < 200.00"

5.3. Конфигурация проверки

После того, как мы подготовили исходные файлы дляruleBases, мы перейдем к реализации конкретных проверок.

Проверка - это еще один тег в конфигурации Smooks, который содержит следующие атрибуты:

  • executeOn - путь к проверенному элементу

  • name - ссылка наruleBase

  • onFail - указывает, какое действие будет предпринято в случае сбоя проверки

Давайте применим правила проверки к нашему файлу конфигурации Smooks и проверим, как он выглядит (note that if we want to use the MVELProvider, we’re forced to use Java binding, so that’s why we’ve imported previous Smooks configuration):




    

    
        
        
    

    
    
    

Теперь, когда конфигурация готова, давайте попробуем проверить, не удастся ли проверить номер телефона поставщика.

Опять же, мы должны создать объектSmooks и передать входной XML в виде потока:

public ValidationResult validate(String path)
  throws IOException, SAXException {
    Smooks smooks = new Smooks(OrderValidator.class
      .getResourceAsStream("/smooks/smooks-validation.xml"));
    try {
        StringResult xmlResult = new StringResult();
        JavaResult javaResult = new JavaResult();
        ValidationResult validationResult = new ValidationResult();
        smooks.filterSource(new StreamSource(OrderValidator.class
          .getResourceAsStream(path)), xmlResult, javaResult, validationResult);
        return validationResult;
    } finally {
        smooks.close();
    }
}

И, наконец, подтвердите, если произошла ошибка проверки:

@Test
public void givenIncorrectOrderXML_whenValidate_thenExpectValidationErrors() throws Exception {
    OrderValidator orderValidator = new OrderValidator();
    ValidationResult validationResult = orderValidator
      .validate("/smooks/order.xml");

    assertThat(validationResult.getErrors(), hasSize(1));
    assertThat(
      validationResult.getErrors().get(0).getFailRuleResult().getRuleName(),
      is("supplierPhone"));
}

6. Преобразование сообщений

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

In Smooks, this technique is also called templating и поддерживает:

  • FreeMarker (предпочтительный вариант)

  • XSL

  • String шаблон

В нашем примере мы будем использовать механизм FreeMarker для преобразования сообщения XML во что-то очень похожее на EDIFACT и даже подготовим шаблон для сообщения электронной почты на основе порядка XML.

Давайте посмотрим, как подготовить шаблон для EDIFACT:

UNA:+.? '
UNH+${order.number}+${order.status}+${order.creationDate?date}'
CTA+${supplier.name}+${supplier.phoneNumber}'
<#list items as item>
LIN+${item.quantity}+${item.code}+${item.price}'

И для сообщения электронной почты:

Hi,
Order number #${order.number} created on ${order.creationDate?date} is currently in ${order.status} status.
Consider contacting the supplier "${supplier.name}" with phone number: "${supplier.phoneNumber}".
Order items:
<#list items as item>
${item.quantity} X ${item.code} (total price ${item.price * item.quantity})

Конфигурация Smooks на этот раз очень проста (просто не забудьте импортировать предыдущую конфигурацию, чтобы импортировать настройки привязки Java):




    

    
        /path/to/template.ftl
    

На этот раз нам нужно просто передатьStringResult движку Smooks:

Smooks smooks = new Smooks(config);
StringResult stringResult = new StringResult();
smooks.filterSource(new StreamSource(OrderConverter.class
  .getResourceAsStream(path)), stringResult);
return stringResult.toString();

И мы можем, конечно, проверить это:

@Test
public void givenOrderXML_whenApplyEDITemplate_thenConvertedToEDIFACT()
  throws Exception {
    OrderConverter orderConverter = new OrderConverter();
    String edifact = orderConverter.convertOrderXMLtoEDIFACT(
      "/smooks/order.xml");

   assertThat(edifact,is(EDIFACT_MESSAGE));
}

7. Заключение

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

Как всегда, весь используемый здесь код находится вover on GitHub.