Pengenalan kepada Smooks

1. Gambaran keseluruhan

Dalam tutorial ini, kami akan memperkenalkan kerangka Smooks.

Kami akan menerangkan apa itu, menyenaraikan ciri utamanya, dan akhirnya belajar bagaimana menggunakan beberapa fungsi yang lebih maju.

Pertama sekali, mari kita jelaskan secara ringkas apa kerangka yang ingin dicapai.

2. Merokok

Smooks adalah kerangka untuk aplikasi pemprosesan data - berurusan dengan data berstruktur seperti XML atau CSV.

Ia menyediakan API dan model konfigurasi yang membolehkan kita menentukan transformasi antara format yang telah ditentukan (contohnya XML ke CSV, XML ke JSON dan banyak lagi).

Kami juga dapat menggunakan sejumlah alat untuk mengatur pemetaan kami - termasuk skrip FreeMarker atau Groovy.

Selain transformasi, Smooks juga memberikan ciri lain seperti pengesahan mesej atau pemisahan data.

2.1. Ciri-ciri utama

Mari lihat kes penggunaan utama Smooks:

  • Penukaran mesej - transformasi data dari pelbagai format sumber ke pelbagai format output
  • Pengayaan mesej - mengisi mesej dengan data tambahan, yang berasal dari sumber data luaran seperti pangkalan data
  • Pemisahan data - memproses fail besar (GB) dan membelahnya menjadi lebih kecil
  • Java binding - membina dan mengisi objek Java dari mesej
  • Pengesahan mesej - melakukan pengesahan seperti regex, atau bahkan membuat peraturan pengesahan anda sendiri

3. Konfigurasi Awal

Mari kita mulakan dengan kebergantungan Maven yang perlu kita tambah pada pom.xml kita :

 org.milyn milyn-smooks-all 1.7.0 

Versi terbaru boleh didapati di Maven Central.

4. Java Binding

Mari mulakan sekarang dengan memberi tumpuan kepada mengikat mesej ke kelas Java. Kami akan melalui penukaran XML ke Java yang sederhana di sini.

4.1. Konsep asas

Kita akan mulakan dengan contoh mudah. Pertimbangkan XML berikut:

 771 IN_PROGRESS 

Untuk menyelesaikan tugas ini dengan Smooks, kita harus melakukan dua perkara: menyediakan POJO dan konfigurasi Smooks.

Mari lihat bagaimana model kami:

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

Sekarang, mari kita beralih ke pemetaan Smooks.

Pada dasarnya, pemetaan adalah fail XML yang mengandungi logik transformasi. Dalam artikel ini, kami akan menggunakan tiga jenis peraturan:

  • kacang - mentakrifkan pemetaan bahagian berstruktur konkrit ke kelas Java
  • nilai - mentakrifkan pemetaan untuk harta tanah kacang tertentu. Boleh mengandungi logik yang lebih maju seperti penyahkod, yang digunakan untuk memetakan nilai ke beberapa jenis data (seperti format tarikh atau perpuluhan)
  • w iring - membolehkan kita memasukkan kacang ke kacang lain (contohnya kacang Pembekal akan disambungkan ke Pesanan kacang)

Mari kita lihat pemetaan yang akan kita gunakan dalam kes kita di sini:

      yyyy-MM-dd   

Sekarang, dengan konfigurasi yang siap, mari cuba uji apakah POJO kita dibina dengan betul.

Pertama, kita perlu membina objek Smooks dan memasukkan input XML sebagai aliran:

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(); } }

Dan akhirnya, tegaskan jika konfigurasi dilakukan dengan betul:

@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. Pengikatan Lanjutan - Merujuk Kacang dan Senarai Lain

Mari berikan contoh sebelumnya dengan tag pembekal dan item pesanan :

 771 IN_PROGRESS  Company X 1234567    1 PX1234 9.99   1 RX990 120.32   

Dan sekarang mari kita kemas kini model kami:

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; // ... }

Kita juga harus memperluas pemetaan konfigurasi dengan definisi pembekal dan kacang item .

Perhatikan bahawa kami juga telah menentukan bean item yang dipisahkan , yang akan menyimpan semua elemen item dalam ArrayList .

Akhirnya, kami akan menggunakan atribut pendawaian Smooks , untuk menggabungkan semuanya.

Lihat bagaimana pemetaan akan kelihatan dalam kes ini:

      yyyy-MM-dd                 

Akhirnya, kami akan menambahkan beberapa penekanan pada ujian sebelumnya:

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. Pengesahan Mesej

Smooks dilengkapi dengan mekanisme pengesahan berdasarkan peraturan. Mari kita lihat bagaimana ia digunakan.

Definisi peraturan disimpan dalam fail konfigurasi, bersarang di tag ruleBases , yang dapat berisi banyak elemen ruleBase .

Setiap elemen ruleBase mesti mempunyai sifat berikut:

  • name – unique name, used just for reference
  • src – path to the rule source file
  • provider – fully qualified class name, which implements RuleProvider interface

Smooks comes with two providers out of the box: RegexProvider and MVELProvider.

The first one is used to validate individual fields in regex-like style.

The second one is used to perform more complicated validation in the global scope of the document. Let's see them in action.

5.1. RegexProvider

Let's use RegexProvider to validate two things: the format of the customer name, and phone number. RegexProvider as a source requires a Java properties file, which should contain regex validation in key-value fashion.

In order to meet our requirements, we'll use the following setup:

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

5.2. MVELProvider

We'll use MVELProvider to validate if the total price for each order-item is less then 200. As a source, we'll prepare a CSV file with two columns: rule name and MVEL expression.

In order to check if the price is correct, we need the following entry:

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

5.3. Validation Configuration

Once we've prepared the source files for ruleBases, we'll move on to implementing concrete validations.

A validation is another tag in Smooks configuration, which contains the following attributes:

  • executeOn – path to the validated element
  • name – reference to the ruleBase
  • onFail – specifies what action will be taken when validation fails

Let's apply validation rules to our Smooks configuration file and check how it looks like (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):

Now, with the configuration ready, let's try to test if validation will fail on supplier's phone number.

Again, we have to construct Smooks object and pass input XML as a stream:

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(); } } 

And finally assert, if validation error occurred:

@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. Message Conversion

The next thing we want to do is convert the message from one format to another.

In Smooks, this technique is also called templating and it supports:

  • FreeMarker (preferred option)
  • XSL
  • String template

In our example, we'll use the FreeMarker engine to convert XML message to something very similar to EDIFACT, and even prepare a template for the email message based on XML order.

Let's see how to prepare a template for EDIFACT:

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

And for the email message:

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:  ${item.quantity} X ${item.code} (total price ${item.price * item.quantity}) 

The Smooks configuration is very basic this time (just remember to import the previous configuration in order to import Java binding settings):

    /path/to/template.ftl  

Kali ini kita hanya perlu lulus StringResult kepada enjin Smooks:

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

Dan tentu saja kita dapat mengujinya:

@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. Kesimpulannya

Dalam tutorial ini, kami memfokuskan cara mengubah mesej ke format yang berbeda, atau mengubahnya menjadi objek Java menggunakan Smooks. Kami juga melihat bagaimana melakukan pengesahan berdasarkan peraturan logik regex atau perniagaan.

Seperti biasa, semua kod yang digunakan di sini boleh didapati di GitHub.