วันอาทิตย์ที่ 29 พฤศจิกายน พ.ศ. 2558

ws part 1 ลองมาเขียน RESTful web services

>> เบื่อเกมแพ้ก็ลองมาสร้าง ws เองบ้าง ทำความเข้าใจมันอยู่พักไม่ลงมือคงไม่ได้แล้ว ความเข้าใจจริงหรือจะเท่าลงมือทำเอง

>> ที่จะเอามาแชร์ก็เพราะผมไม่ค่อยเข้าใจพวก jar ไฟล์ซึ่งถือเป็นกลไกขับเครื่องสำคัญที่มากรุ่นต่างเวอร์ชันเสียจนอย่าได้ใช้ความจำกับพวกมันเลย โปรเจ็กค์ใหญ่ๆของจาวาเนี่ยเท่าที่เห็นมาก็มี jar อยู่รกรุงรัง ไม่ใช้ก็อยู่ใช้ก็อยู่ จะเอาออกก็กลัวมันพัง เอาล่ะเรามาลอง Hello World เจ้า RESTful web services กันนะ

>> เริ่มจากสร้างโปรเจ็กค์ที่เป็น Dynamic Web Project (อ้อ เครื่องผมจาวาเวอร์ชัน 8 นะครับ) แล้วก็ไปหาจาร์ (jar) ตามภาพประกอบนี้มาใส่ ณ WebContent/WEB-INF/lib


>> สำคัญเลยเป็นอะไรไม่รู้ มันบอกว่าหา org.jvnet.hk2.external.runtime.ServiceLocatorRuntimeBean ไม่เจอ ผมหาอยู่พักก็ไม่เจอ จึงต้องสร้าง package ออกมาเอง (แท็บสีเหลืองที่ป้ายในรูปไง) และตามไปโหลดคลาสเจ้ากรรมมาใส่ ลิงค์นี้เลย
http://grepcode.com/file/repo1.maven.org/maven2/net.maritimecloud.mms/mc-mms-server-standalone/0.3/org/jvnet/hk2/external/runtime/ServiceLocatorRuntimeBean.java

>> RESTful คือวิธีการหรือก็คือหลักการใช้เทคโนโลยีเพื่อให้บริการทรัพยากร (resource) จากเครื่องเซอร์เวอร์ (เครื่องให้บริการ) สู่เครื่องที่เรียกใช้บริการ (client) ผ่านเส้นทางของ HTTP protocol

>> ประโยชน์ข้อหนึ่งที่ผมชอบมันก็เพราะมันทำตัวเป็นคนกลาง (middle layer) ระหว่างฐานข้อมูลกับเว็บแอพพลิเคชันที่จะต้องพูดคุยกันว่าอยากจะใช้โน่นนี่นั่นโดยไม่ต้องเขียนโค้ดระดับติดต่อฐานข้อมูลเองซึ่งไม่ปลอดภัยนักหากมีผู้ขอใช้บริการที่ไม่สามารถควบคุมได้ ตัวอย่างเช่น คนซื้อปลา (client ใดๆ) อยากได้ปลาไม่ต้องไปจับปลาเองในบ่อเลี้ยงปลา (ฐานข้อมูล) จะมีคนไปจับมาให้หรือคอยจัดการคำขอนี้ให้ (เว็บเซอร์วิส) เฉือนเนื้อแบหนังพร้อมชั่งใส่ถุงยื่นให้กับมือ ขอแค่คนซื้อปลาบอกว่าจะเอากี่ขีดกี่กิโลกรัมก็พอ (ตามเอกสารที่เว็บเซอร์วิสประกาศหรือกำหนดไว้ว่าทำอะไรได้บ้าง) โดยตัวปลาก็คือ resource ที่คนจับปลานำมาให้

>> สำคัญคือ RESTful มุ่งที่ resource ไม่ใช่ข้อมูล แถมใช้ protocol ยอดนิยมอย่าง HTTP ลำเลียงมาส่ง แหม!ดุจสายพาน ตาม HTTP methods เลย
- GET คือ client ขอ resource จากเครื่องที่ให้บริการ
- PUT คือ client ขอปรับปรุง (update) resource นั่นๆที่เครื่องให้บริการ
- POST คือ client ขอสร้าง resource ขึ้นที่เครื่องให้บริการ
- DELETE คือ client ขอลบ resource นั้นๆที่เครื่องให้บริการ

>> กลับมาที่โปรเจ็กค์ อย่าลืม config เส้นทางที่จะมุ่งสู่คลาสที่เราต้องการกำหนดให้มันเป็น resource ในไฟล์ web.xml


>> ด้วยว่า resource หรือก็คือคลาส HelloWorldResource ได้ให้บริการ Get และเมื่อเรียกมาเฉยๆมันก็จะทำงานเมธอดชื่อ greet แล้วพ่น Hello World ออกไปจ้า


>> อ้อ สภาพแวดล้อมที่พัฒนา
- eclipse mars.1 release (4.5.1)
- jre 1.8.0_65
- สร้างด้วย dynamic web project (module version 3.0)
- implement ws นี้ด้วย jersey 2.0
- tomcat 8.0

Edit and Update a Table Row

>> มาบอกเล่าสู่กันฟังเฉยๆนะครับ ไม่ได้แปะโค้ดให้แต่อย่างใด ทว่าอยากจะบอกว่าทำได้แล้ว!!! เพราะว่าผมกำลังเขียน Vaadin และผมกำลังงง ทว่าที่สุดมันก็เรียบร้อยดีตามเป้าหมายที่วาดไว้



>> บอกกับเพื่อนๆที่ไม่รู้จัก Vaadin มันคือเครื่องมือสร้างเว็บแอพพลิเคชัน (ที่มีลักษณะดั่งโปรแกรมใดๆที่ถูกติดตั้งบนเครื่องคอมของเรา) ด้วยข้อดีที่ว่า เขียนด้วยภาษาจาวา, รากเหง้ามันคือ GWT (คุณปู่), ไม่ต้องคิดถึงแท็ก HTML, ไม่ต้องคิดถึง JavaScript และจัดการ CSS ด้วย SCSS ได้ครับ

>> เป้าหมายของผมคือสร้างตารางขึ้นมา ใส่ product เข้าไปสองสามชิ้น โดยที่หนึ่ง row คือข้อมูลของ product ที่ถูกสร้างขึ้นมา ส่วน product ดังกล่าวก็มีรายละเอียดปลีกย่อยของมันเองครับ เรามาดู POJO ของคลาสทั้งสองนี้กัน

>> แรกเลยคือคลาสที่หุ่ม product เอาไว้ หรือก็คือหนึ่ง row ในตารางนั่นแหละครับ
public class RecievingProduct {
private String id;
private Date modifiedDate;
private Product product;
// ...getter and setter
}

>> สองคือคลาส product ที่มีรายละเอียดปลีกย่อยเป็นของมันเอง
public class Product {
private String id;
private String name;
// ...getter and setter
}

>> จะเห็นได้ว่า RecievingProduct ได้ห่อหุ่ม Product ไว้ด้านใน และผมต้องการนำเอาทั้งหมดนี้ไปแสดงเป็นหนึ่งแถวของตารางครับ (ดูภาพประกอบ) ปัญญาก็คือเมื่อผมกดที่ปุ่มดินสอเพื่อต้องการแก้ไขรายละเอียด เป็นต้นว่าวันเวลาที่มีสินค้าชิ้นนี้เข้ามาในคลัง (modified date) หรือแก้ไขชื่อสินค้า (name) หากเป็นชนิดที่ Vaadin ได้จัดเตรียม converters ไว้ให้ มันก็จะจัดการเปลี่ยนชนิดข้อมูลนั้นๆเป็น ui (user interface) ให้เลย ประเด็นคือไม่มี ui สำหรับคลาส Product ของผม? เอ้า!

>> จะไปมีได้อย่างไรล่ะใช่ไหม ก็คลาส Product นี่เราสร้างเองกับมือ ไม่ใช่อย่างคลาส String, Date หรือ Boolean ที่จาวารู้จักเป็นทุนอยู่แล้ว อื่ม...ทีนี้จะต้องศึกษาเรื่องอะไรบ้างล่ะ?

>> แรกเลยคือจัดการ converter ก่อน ด้วยการจัดเตรียมคลาส StringToProductConverter เพื่อเปลี่ยน product เป็น String หรือเปลี่ยน String เป็น Product สับไปสับมา

>> แต่... ตัว Product ผมก็อยากให้มันแก้ไขได้เฉพาะแค่ชื่อสินค้าเท่านั้น (name) รหัสมันไม่ต้องแก้ ดังนั้นจัดหา field หรือก็คือ ui สักตัวมารับชื่อนี้ เอาเป็น TextField แล้วกัน เจออีกประเด็น! จะสร้าง field นี้ได้อย่างไร?

>> อ้อ Vaadin มันบอกว่าทุกครั้งที่สร้าง field หรือ ui ใดๆ คลาสที่ทำหน้าที่นี้ก็คือ DefaultFieldFactory เคร งั้นก็สืบทอดมันมาซะ ตั้งชื่อว่า RecievingProductFieldFactory โว๊ะฮ่าๆๆๆ แล้วจัดการ override เมธอดที่ใช้สร้าง field นั่นก็คือเมธอด createField อุว่ะฮ่าๆๆๆ

>> หือ?... ทำไมเวลาแก้ไขชื่อสินค้าค่าที่ได้กลับกลายเป็น null? แบบนี้แสดงว่าอะไรครับ แบบนี้แสดงว่า converter ที่เราเพิ่งสร้างมีจุดบกพร่องอย่างไม่ต้องสัยสง แกะดูแล้วเดินพิจารณา เพื่อคิดก่อนว่าทำไงดี...

>> อ้อ เจ้า converter นี่มันรับข้อมูลมาสองรูปแบบ ตอนจะเปลี่ยน Product เป็น String นี่มันนำออบเจ็กค์ Product เข้ามา, และพอตอนจะเปลี่ยน String เป็น Product นี่มันก็นำ String เข้ามา สลับกันอย่างนี้ ฮี่ๆๆๆ จะๆจังๆ ผมก็สร้างออบเจ็กค์ product temp เพื่อเก็บออบเจ็กค์ตอนเปลี่ยน Product เป็น String และพอมันจะเอา String ผมก็ยื่น product temp นี้ให้มัน จบข่าว อุว่ะฮ่าๆๆๆ! ว่ะฮ่าๆๆๆ รอกลุ้มเรื่องใหม่ เห้อ~