Problem statements

มี feature ใหม่ใน product ที่ทำอยู่คือทำการสร้าง report จากข้อมูลที่ user ส่งมาให้ จากนั้นให้ upload file ขึ้น Object Store แน่นอนว่าข้อมูลที่ต่างกันย่อมเกิด report ที่ต่างกัน ดังนั้นเราต้องนำข้อมูลมาแปะลงไปใน report สมมติว่า format เป็น HTML code ก็จะออกมาหน้าตาประมาณนี้

ซึ่งปัญหาที่เห็นได้เลยคือ code ดูแลรักษายากมาก เนื่องจาก business logic กับ presentation logic ผูกมัดกัน

Web Template System

อธิบายการทำงานของ web template ด้วยส่วนประกอบ 3 ส่วนหลักๆ

  1. Content เนื้อหาที่จะนำใช้ใน template ซึ่งจะมาในรูปแบบ hash หรือ object ก็ได้ เช่น JSON หรือ database
  2. Template รูปแบบที่ยังไม่มี content ใส่เข้าไป ซึ่งจะมาในรูปแบบ HTML หรือ config file ก็ได้
  3. Template engine ระบบที่นำ content ไปใส่ใน template และประมวลผลออกมากลายเป็น file ใหม่

Web Template System
Alfresco Customization and Java Stuffs

ข้อดีของ web template คือ เราสามารถจัดการส่วนของ business logic แยกกันกับ presentation logic เช่น ส่วนของการแสดงผลเป็น list เป็นต้น > ทำให้ code ของเราดูแลง่ายขึ้น (นึกถึง Separation of concerns)

Example

Dependencies

ในตัวอย่างเราจะใช้ Mustache เป็น template engine และ Amazon S3 เป็น Object Store ดังนั้นเราจะมาเริ่มด้วยการติดตั้ง dependencies ใน Spring framework กันก่อน

Content

จากนั้นทำการ define content ที่เราต้องการจะเอาไปใส่ใน template ครับ

Template

ทำการเขียน template file ขึ้นมา โดยเราจะใช้เป็น HTML สร้าง file extension เป็น .mustache และเก็บไว้ใน classpath:/templates/ (เช่น src/main/resources/templates แล้วแต่ว่า configure classpath ยังไง) โดยเราจะอิง syntax ตาม Official documentation เลย ชื่อ section ของ template file จะล้อตาม attribute ของ content ครับ (ยกเว้นตรง familyWrapper เดี๋ยวจะมาอธิบายทีหลังครับ)

โดยค่าตั้งต้น Mustache จะอ่าน file ที่มี extension เป็น .mustache ครับ แต่เราสามารถ customize มันได้ผ่าน spring.mustache.suffix ครับ (อ้างอิงจาก Spring Boot Reference Documentation)

Template engine

ขั้นตอนการ generate report เป็นไปตามนี้ครับ

  1. ดึง template file มาจาก resource classpath
  2. สร้าง file ใหม่ที่จะเป็น result จาก Mustache
  3. Mustache ทำการ compile ตัว template file
  4. Mustache ทำการ execute Object ที่ wrap content ไว้อีกที (เป็นเหตุผลว่าทำไมใน template ถึงใส่ familyWrapper)
  5. บันทึก result ลง file ที่สร้างจากข้อ 2

จะได้ code หน้าตาออกมาประมาณนี้

สังเกตว่า spring-boot-starter-mustache ถูกต่อยอดมาจาก samskivert/jmustache อีกที ดังนั้นเราใช้ repo นี้เป็น manuals ได้

Upload file to S3 (ข้ามได้)

มาถึงตรงนี้เราจะนำ template ไปทำอะไรก็ได้แล้วครับ ตัวอย่างคือเราจะ upload file ขึ้น Amazon S3 เราจะทำการ configure AWS client กันก่อน สำหรับตัวอย่างนี้จะใช้เป็น basic credentials (access key, secret key) สามารถดูวิธีการซ่อน credentials สำหรับ local ได้ใน blog นี้ครับ

ปิดท้ายด้วยการ inject AmazonS3Client เป็น dependencies และทำการ upload file ขึ้นไป

แถม Unit test

เราใช้ Apache Commons เพื่อตรวจสอบว่า file content เหมือนกับที่เราคาดหวังไว้ไหม

Limitations

project ตัวอย่างนี้มี limitation ที่เราควรรู้เพื่อใช้ในการตัดสินใจในการเลือก tool ที่เหมาะสมดังนี้

  1. Mustache โฆษณาไว้ว่าเป็น “Logic-less templates” ดังนั้นมันจึงไม่ได้รองรับพวก if-else statements เลย ถ้า requirement ของเรามี if-else แน่ๆ ลองเปลี่ยนไปดู handlebars แทนครับ สำหรับชาว Java Spring แนะนำว่าไปดูตาม Template Engines for Spring ดีกว่าครับ
  2. AWS S3 ใน Java ใช้ได้กับแค่ Spring v2.3.x (ณ เวลาที่เขียน blog นี้) ดังนั้นใครที่จะ upgrade อาจจะต้องระวังกันหน่อยครับ