วันอาทิตย์ที่ 13 เมษายน พ.ศ. 2557

ทบทวน Compiler ด้วยกันนะ part 2


- กล่าวถึงออบเจ็กต์ที่ถูกเรียกใช้แบบ instance และแบบ object เอง
- สร้าง array ของคำ โดยสร้างสมาชิกแบบ object
- การเขียน for-each และ for แบบธรรมดาเพื่อเรียกดูลายละเอียดของออบเจ็กต์

       ยังแนะนำการเขียน get และ set ด้วยครับ กล่าวคือสมาชิกที่เป็น attribute ของคลาสใดๆ เราสามารถขอดูค่าหรือเปลี่ยนค่าให้ใหม่ได้ ถามว่ามีประโยชน์อย่างไรน่ะหรือ มันเป็นแนวคิดที่ต้องการให้ attribute เหล่านั้นปลอดภัยที่สุด ด้วยการระบุการเข้าถึงเป็น private ไว้ก่อน จากนั้นจงใจให้มี get หรือ set หรือทั้งสองอย่างตามแต่ผู้สร้างคลาสเห็นควรครับ หากยังไม่เข้าใจพวก public หรือ private หรือเทือกนี้ให้ข้ามไปก่อนครับ มันเป็นแง่มุมของ OOP ซึ่งตอนนี้ขอไม่กล่าวถึงละเอียดนัก

       ควรทำความเข้าใจเรื่อง array ว่าประกาศอย่างไร ใช้อย่างไร หมุนลูปอย่างไร เหล่านี้อย่าให้สงสัยเป็นอันขาด ระวังเรื่องรอบในการหมุนลูป นับให้ดี เพราะโค้ดที่เกิด error บ่อยมักวนอยู่ในลูป หรือเงื่อนไขของลูปไม่ครอบคลุมงานที่อยากจะได้ครับ

ทบทวน Compiler ด้วยกันนะ part 1


       สวัสดีเพื่อนๆที่รัก ณ มหาวิทยาลัยของเรามีหลักสูตรการสอนเขียนโปรแกรม Compiler ด้วยใช่ไหม ดังนั้นเรามาคุยกันว่ามันยากตรงไหน และตรงไหนที่ว่าเราจะสามารถช่วยเหลือกันได้อย่างไร ดีไหมล่ะ

       โดยส่วนตัวแล้วผมรู้สึกว่าไม่ได้ยาก แม้เนื้อหาจะลึกแต่ก็มีเรื่องสนุกๆอยู่เต็มไปหมด (จริงเหรอ) จริงแท้เลยล่ะครับ เวลาที่ผมได้พบปะกับเพื่อนหลายๆคน เรื่องทฤษฎีไม่มีติดขัดกันเลย ทำได้หมดไม่ว่าจะมาแนวไหน แล้วปัญหาที่แท้จริงมันอยู่ที่ไหนล่ะ เอาเข้าจริงๆผมกลับเป็นฝ่ายที่อ่อนทฤษฎีวิชานี้อย่างแรง! ก็เลยอยากเสนอให้เรามาเขียนโปรแกรมร่วมกันครับ ใช่แล้วล่ะครับ ที่ผมจะบอกก็คือ เพื่อนๆส่วนใหญ่พื้นฐานการเขียนโปรแกรมไม่ค่อยกล้าแข็ง ผมเองก็ปีกหักหลายครั้ง กระทั่งครั้งนี้คิดว่าบินพอไหวก็เลยอยากจะแชร์และแนะแนวทางการเขียนโปรแกรมด้วยภาษา C# และ Java ประกอบการสร้างโปรแกรม Compiler นี้ครับ

       ไม่รู้ว่าจะไปได้ไกลสักแค่ไหน ตอนนี้มีไฟก็ทุ่มเทไปก่อน อ่านมาถึงตอนนี้ก็อยากให้ลองดูวีดีโอที่ผมได้โพสต์ไว้ข้างต้น เนื้อหาทั้งหมดของหน้านี้สรุปได้ดังนี้ครับ

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

- เลือกสักภาษาหนึ่งสำหรับเริ่มต้น จะใช้ C# หรือ Java (ส่วนตัวผมแนะนำ Java อย่าถามเหตุผลเลย ส่วนตัวจริงๆ)

- บอกตัวเองให้ได้ว่า คลาส สร้างอย่างไร ประกอบไปด้วยอะไรบ้าง (เท่าที่อยู่ในวีดีโอพอ)

- จำเอาไว้ว่า คลาส คือจุดเริ่มต้นของทั้งสองภาษา คลาสที่มีเมธอด (ตอนนี้จะเรียกว่าฟังก์ชันไปก่อนก็ได้นะ) คือจุดเริ่มต้นของโปรแกรม

- สุดท้ายอย่าท้อ อย่ามะโนเอาเอง เขียน + ทำตาม เขียน + ทำตาม ทำซ้ำๆ ทำไปเรื่อยๆ จนมือหงิกก็จะเห็นผลเอง สู้ๆ

คึกอยากจะทบทวน GWT Framework part 8

Sample GWT Picture

: MVP concept & Event Bus

ในที่สุดก็มาถึงหัวใจของ project นี้เสียทีกับ Model, View และ Presenter

คำถาม : เดี๋ยวๆ controller คืออะไรนะ แล้วกับ presenter นี่ยังไงเหรอ?
คำตอบ : เราทราบว่า controller จะทำ business logic กับข้อมูล โดยอาจรับมาจาก view หรือ model ก็ได้ สำหรับ web application เจ้า controller จะมีหน้าที่จัดการ URL เพิ่มด้วย (สถาปัตยกรรมของ Spring เรียก controller ลักษณะนี้ว่า front-controller) ทีนี้เจ้า presenter นี่จะอยู่ระหว่างกลาง controller กับ view ครับ จากคำถามจึงตอบได้ว่า controller นั้นติดต่อกับ view โดยตรง แต่ว่าหากมี presenter เจ้า presenter จะเข้าไปอยู่ตรงกลาง รับ input และหรือแสดง output จาก view เข้ามากระทำ business logic แทน controller อ๊ะๆ แต่ controller ไม่ได้หายไปไหนนะครับ เขาก็จะควบคุมแต่ละ presenter ที่มีความสำพันธ์ต่อกันในเรื่องนั้นๆอีกทีหนึ่ง จากภาพ controller ที่ว่าก็คือ Application Controller นั่นเอง

คำถาม : แล้ว controller แตกต่างอย่างไรกับ presenter ขอชัดๆ
คำตอบ : (-*-) ถ้าเราให้ controller เป็นส่วน business logic ของ view ฉันใด แนวคิดของ presenter นี้ก็คือ business logic ของ view ฉันนั้น

หากเป็นการ input สำหรับ MVC เจ้า input จะไปยัง controller ก่อน แต่หากเป็น MVP เจ้า input จะไปยัง presenter ก่อน

คำถาม : อะไรคือ Event Bus ในภาพ?
คำตอบ : คือกลไกประการหนึ่งที่ใช้จัดการเหตุการณ์ของ presenter กับ presenter โดยโครงสร้างข้อมูลของ event bus ก็เหมือนกับ queue

สมมติตัวอย่างง่ายๆว่า A presenter รับผิดชอบ X view และ B presenter รับผิดชอบ Y view จากนั้นต้องการแสดงผลข้อมูลที่ update แล้วไปยังส่วนแสดงผลทั้งสอง ไม่ว่า X หรือ Y view พอกดปุ่ม update ข้อมูลปุ๊บ ข้อมูลก็จะไป update ทั้งสองหน้าในเวลาแทบจะใกล้เคียงกันปั๊บ ว้าว! นี่แหละครับงานที่เกิดขึ้นโดย event bus

จงอธิบายภาพตามความเข้าใจ : จากภาพทรัพยากรจะถูกเตรียมไว้สองแห่งใหญ่ๆ หนึ่งคือที่ Application Controller (AppController) และสองคือแต่ละ View ที่ใช้เป็น UI สำหรับแสดงผล

หนึ่ง Presenter จะรับผิดชอบ business logic ของหนึ่ง View (มากกว่าหนึ่ง View ก็คงได้) โดย presenter รู้จักกับ view ผ่าน interface ที่มีชื่อว่า Display (นิยมตั้งชื่อนี้จ๊ะ) ด้วยกติกาของ interface ส่งผลให้ presenter และ view สามารถแยกกันพัฒนาได้ หรือกล่าวว่าการออกแบบ view เป็นอิสระมากขึ้น ส่งผลให้ logic design กับ UI design ไม่ผูกติดกันอีกต่อไป โหย~สุดยอดอะ

ภาพนี้อธิบายกลไกการเพิ่มลบและแก้ไขรายชื่อผู้ติดต่อ (Contact) โดยออกแบบไว้สอง presenter ได้แก่
- ContactsPresenter รับผิดชอบแสดงรายชื่อผู้ติดต่อทั้งหมด
- และ ContactEditPresenter รับผิดชอบส่วนแก้ไขชื่อผู้ติดต่อนั้นๆที่ถูกเลือก

เมื่อชื่อผู้ติดต่อถูกเลือกจากรายการฝั่ง ContactsPresenter เพื่อนำมาแก้ไข ContactEditPresenter จะมี message ไปบอกต่อ Event Bus ให้ส่ง event ไปสะกิด handler ฝั่ง ContactsPresenter การนี้ข้อมูลที่ถูกแก้ไขจากฝั่ง ContactEditPresenter ก็จะ update ในฝั่ง ContactsPresenter เป็นที่เรียบร้อย จบข่าว

ไว้เจอกันใหม่กับการทดลองทำ sample project นะครับ
อ่านเพิ่มเติม : http://www.gwtproject.org/articles/mvp-architecture.html

คึกอยากจะทบทวน GWT Framework part 7-2 (end)

Sample GWT Picture

: Remote Procedure Calls (RPC) Code Example

จาก part ที่ 7-1 แนะนำไปแล้วสี่คลาส ได้แก่ Product bean, ProductService remote service interface, ProductServiceAsync interface และ ProductServiceImpl class implementation

คราวนี้ก็มาทำ test ง่ายๆด้วยคลาส TestBeginMVP และเรื่องหยุมหยิมของ servlet เพื่อ config พวกมันให้ทำงานร่วมกัน ดังนี้ครับ

(ดูภาพประกอบนะ ถ้าไม่เข้าใจอะ) ลอจิกของคลาส TestBeginMVP ก็คือสร้างออบเจ็กต์จาก interface โดยมี instance ชื่อว่า productServiceAsync เจ้า instance นี้เมื่อร้องขอรายการสินค้าทั้งหมดจาก getProducts ผลคือมันบังคับให้เรา implement ผลลัพธ์ต่อไปนี้ที่เป็นลักษณะของ async callback
1) onSuccess ผลสำเร็จนี้เท่านั้นผลลัพธ์จึงจะถูกส่งกลับมาแสดงผลได้
2) onFailure ล้มเหลวด้วยนานาสาเหตุ อาจเป็นที่เน็ตเวิร์คด้วยก็ได้

โดยผลลัพธ์ทั้งสองส่วนนี้มีเวลาตอบสนองไม่แน่นอน เราอาจคอยนานเป็นนาทีหรือมากกว่ากว่ามันจะบอกได้ว่า onSuccess หรือ onFailure ฉะนั้นระหว่างที่คอยเราก็ไปทำงานอื่นๆของหน้านี้ได้จ๊ะ (ถ้ามี)

ต่อมาด้านขวาของภาพคือการ config servlet แบ่งเป็นสองส่วนคือ
- servlet
- servlet-mapping

servlet เฉยๆและ servlet-mapping ต้องใช้ชื่อเดียวกัน (ดูกรอบสีส้ม) เจ้า servlet เฉยๆนี้จะบอกว่าคลาสที่เราต้องการลงทะเบียนอยู่ที่ไหนใน project ของเรา (ไล่ไปตามชื่อ package)

ส่วน servlet-mapping จะบอกว่าคลาสที่เราต้องการลงทะเบียนนั้นน่ะจะถูกเรียกด้วย URL อะไร (ตั้งมา แนะว่าเป็นตัวเล็ก) โดยใช้เครื่องหมาย / คั่นต่อจากชื่อของ project

***นิดหน่อย ใครที่ยังรันไม่ผ่านให้กลับไปดูที่ ProductService interface เพราะ GWT มีกลไกชื่อ @RemoteServiceRelativePath ซึ่งหมายความว่า หาก URL ข้างต้นส่งจากเครื่องผู้ใช้มายัง server ให้ URL นั้นมาทำงานกับ RemoteService interface ตัวนี้นะ (ก็ตัวที่เขียน @RemoteServiceRelativePath ไว้ข้างบนเนี่ย) มันก็จะสามารถจัดการคำร้องขอนั้นๆได้อย่างไรล่ะ

โอเคจบแล้วจร้า อ้อ ถ้าเกิดว่าผลลัพธ์มันออกมารกๆ (คือมีโค้ด HTML ปะปน ก็ให้ไปเปิดไฟล์ที่ชื่อ TestBeginMVP.html นะครับ (ดูกรอบสีเขียวในภาพ) จากนั้นก็ลบโค้ดในส่วนของ body ให้สะอาดตาหน่อย เป็นใช้ได้แล้วล่ะ

คราวหน้ามาดูว่าเราจะเพิ่ม MVP concept ให้กับ project นี้อย่างไร
เคเค ฝันดีครับคืนนี้

คึกอยากจะทบทวน GWT Framework part 7-1

Sample GWT Picture

: Remote Procedure Calls (RPC) Code Example

จาก part ที่ 6 ที่ผ่านมาเราเรียนรู้แนวคิดของ RPC ไปแล้ว ตอนนี้เราก็จะเขียนโค้ดตัวอย่างเพื่อ implement แนวคิดดังกล่าวครับ

1) สร้างคลาส Product เป็น bean เก็บไว้ที่ package ชื่อ
com.sample.shred
ประกอบด้วย String name และ double price

2) สร้างตัว remote interface จากแนวคิด RPC ให้ชื่อว่า ProductService เก็บไว้ที่ package ชื่อ
com.sample.client
เขียนบริการ getProducts เพื่อขอสินค้าทั้งหมดจาก database

3) สร้าง Async (Asynchronous) interface จากแนวคิด RPC จึงชื่อว่า ProductServiceAsync เก็บไว้ที่ package ชื่อ
com.sample.client
interface นี้จะบังคับผลลัพธ์เป็น Asynchronous Callback เสมอ หมายความง่ายๆว่า ทำงานเสร็จเมื่อไรเดี๋ยวส่งผลลัพธ์กลับมาเอง ไม่ต้องคอยเค้านะจ๊ะ (ผลลัพธ์ของการ callback มีสองแบบคือ onSuccess กับ onFailure) ประมาณนั้น (เราจึงไปทำงานอื่นต่อได้ไงล่ะ)

เอาละครับฝั่ง client เตรียมเสร็จเรียบร้อย (shred คือถูกคอมไพล์ได้ทั้งสองฝั่ง) ต่อไปก็เตรียมฝั่ง server กันบ้าง

4) สร้างคลาส ที่รับเอากติกาของ ProductService มาใช้ เพื่อที่มันจะได้รู้จักคำร้องขอจากฝั่ง client คำร้องขอที่ว่าคือ getProducts นั่นเอง โดยตั้งชื่อตามแนวคิว RPC ว่า ProductServiceImpl
ที่คลาสนี้เราจะสร้างข้อมูลปลอมๆขึ้นมาก่อน (ยังไม่ต่อฐานข้อมูลจริงๆนะ มันเยอะ) แล้วก็ return กลับไปให้ฝั่ง client

ทีนี้พอ client ร้องขอ getProducts จาก server ผลลัพธ์ที่ได้จึงมีสองแบบคือ
- ได้ผลลัพธ์ onSuccess
- หรือล้มเหลว onFailure

เท่านี้ก่อนครับ ไว้ต่อ part 7-2

คึกอยากจะทบทวน GWT Framework part 6

Sample GWT Picture

: Remote Procedure Calls (RPC) concept

งานของ GWT แม้นจะเป็น web app แต่ลักษณะคือ web app แบบ Desktop Application กล่าวคือได้อารมณ์การใช้โปรแกรมบน browser เสมือนใช้โปรแกรมที่ถูกติดตั้งไว้ในเครื่องคอมพิวเตอร์ส่วนบุคคล เช่น โปรแกรมสร้างเอกสารอย่าง MS Word ก็ถูกทำให้สามารถรันบน browser ได้แล้ว หรือเกมลับสมองเล็กๆตอนนี้ก็ไปวางอยู่บน browser แทบหมดสิ้น

GWT มีกลไกที่ใช้ส่งข้อมูลจากฝั่ง browser หรือ client ไปยังฝั่ง server โดยอาศัย javaScript ด้วยการ Asynchronous ครับ

การ Asynchronous ในที่นี้ก็คือการส่งข้อมูลหรือร้องขอข้อมูลจาก server โดยไม่ต้องรอผลลัพธ์กลับมาก่อน เราสามารถทำงานอื่นๆที่อยู่ในหน้านั้นต่อไปได้ (อ่านเพิ่มเติมในเรื่องของ AJAX)

ภาพนี้อธิบายได้ว่า client และ server จะติดต่อกันด้วย interface ซึ่งต้องเป็น interface ที่สืบทอดมาจาก RemoteService Interface ข้อกำหนดหรือกติกาที่เกิดขึ้นนี้แบ่งการใช้งานออกเป็นสองส่วนครับ ส่วนแรกฝั่ง client กับส่วนที่สองฝั่ง server

ส่วนแรกฝั่ง client เราจะต้องสร้าง interface ที่มีชื่อเหมือนกับลูกของ RemoteService Interface โดยเติมคำต่อท้ายชื่อไปว่า Async
จากในภาพลูกของ RemoteService ก็คือ HelloService Interface ดังนั้น interface ของเราจึงได้ชื่อว่า HelloServiceAsync

ส่วนที่สองฝั่ง server เราจะต้องสร้างคลาสที่สืบทอด RemoteServiceServlet เพื่อให้มันเข้าใจ RemoteService Interface ของฝั่ง client จากนั้นจึง implements เอาทุกๆกติกามาใช้ เพื่อให้ทาง server เข้าใจคำร้องขอหรือสามารถจัดการกับข้อมูลที่ถูกส่งมาจากฝั่ง client ได้ โดยคลาสที่ต้องสร้างนี้มักเติมคำต่อท้ายว่า Impl ครับ

มีใครคนหนึ่งถามว่า GWT เข้าใจได้อย่างไรว่า HelloServiceAsync Interface จะถูกต้องกับ HelloService Interface เพียงแค่เติมคำว่า Async ท้ายชื่อ?

คำตอบคือเจ้าสี่เหลี่ยมสีเขียวที่เขียนว่า HelloServiceProxy ด้านล่างของภาพครับ เพราะว่ามันจะถูกสร้างขึ้นมาเป็นดั่ง Proxy (หาอ่านเพิ่มเติมเรื่องแนวคิด Proxy จากในเว็บนะ) อัตโนมัติที่ implements เอาทุกๆกติกาของ HelloServiceAsync Interface มาใช้ จึงเกิดเป็นวงจรตรวจสอบระหว่าง HelloServiceAsync Interface กับ HelloService Interface แบบอ้อมไปด้วยโดยปริยาย (แต่มันมีหน้าที่สำคัญกว่านี้ ซึ่งจะไม่ขอกล่าวถึง)

สรุป RPC concept อย่างง่ายๆก็คือแนวคิดที่จะให้ฝั่ง client ติดต่อกับฝั่ง server โดยกระบวนการ RemoteService นั่นเองครับ

แนวคิดลักษณะนี้มีอยู่มากมายครับ อาจใช้วิธีการของ AJAX เพียวๆก็ได้ แต่ Google เขาคิดการ RemoteService ขึ้นมาให้ใช้ เราก็ศึกษาว่าใช้อย่างไร แล้วก็ใช้เท่านั้นเอง จบข่าว

part หน้าเราจะมาเริ่ม project ที่ใช้ RPC ขอข้อมูลจาก server มาแสดงผลที่ฝั่ง client กันนะเพื่อนๆ

คึกอยากจะทบทวน GWT Framework part 5

Sample GWT Picture

: Event ถูกส่ง เราเขียน Handler มาดักจับ

จากโค้ดในรูปอธิบายได้ว่า มีปุ่มสองปุ่ม ต่างก็มีชื่อเป็นของตัวเอง ยามใดที่มันถูก Click ตัว Handler ของมันก็จะทำงานทันที

ในที่นี้ถ้าเป็นปุ่มแรกก็จะได้ message ว่า Hello World! I am Button No.1
และถ้าเป็นปุ่มที่สองก็จะได้ message ว่า Hello World! I am Button No.2

ส่วนคีย์ final ที่เติมไว้ด้านหน้าพารามิเตอร์ของเมธอด buttonOnClick นั่นก็เพื่อกำกับว่า หนึ่งปุ่มใดๆต่อหนึ่ง Handler นะ และปุ่มที่ใส่มานั้นหามเปลี่ยนการอ้างอิงเด็ดขาด

part หน้าเรามาลุย RPC concept พร้อม project ตัวอย่างกันครับเพื่อนๆ

คึกอยากจะทบทวน GWT Framework part 4

Sample GWT Picture

: onClick Event กับ Alert Message

จากภาพด้านล่างประกาศการใช้คลาส Button สร้างปุ่มออกมาหนึ่งปุ่ม เขียนข้อความบนปุ่มว่า "Click" และเขียนโค้ดรอรับการกดปุ่มดังกล่าว

โค้ดที่เขียนรอรับการกดปุ่มหรือโค้ดลักษณะเขียนเพื่อรอการตอบสนองต่อเหตุการณ์ใดๆนี้เราเรียกว่า Handler ครับ พูดง่ายๆก็คือ เมื่อเกิด Event (แล้วแต่การถูกกระตุ้นให้เกิด อาจเป็นเราเองหรือระบบส่งออกมา) แล้วเราต้องการจับ Event นั้น เราก็จะเขียน Handler มาดักนั่นเอง

ในที่นี้ Handler มีชื่อว่า ClickHandler ซึ่งดักจับ Event ที่ชื่อว่า onClick ครับ

เมื่อกดปุ่ม เราก็ไปเรียก javaScript คำสั่ง Window.alert ให้แสดงข้อความตามรูป

ง่ายและสนุกดีใช่ไหมครับ ต่อไป part หน้า เราจะโมโค้ดไปดักจับ event แบบเมธอด (คล้ายใน C# : window app) กันบ้าง

คึกอยากจะทบทวน GWT Framework part 3

Sample GWT Picture

: Hello World กับ onModuleLoad

จาก part ที่ผ่านมา เราลบโค้ดออกเกือบหมด คงเหลือไว้เพียง

package com.sample.client;
import com.google.gwt.core.client.EntryPoint;
public class TestBeginMVP implements EntryPoint {
    @Override
    public void onModuleLoad() {

    }
}

จะเห็นได้ว่า ตอนนี้เรากำลังอยู่ที่ฝั่ง client (ดูจาก package) และรับเอากติกาชื่อ EntryPoint เข้ามาใช้ เพื่อกำหนดให้คลาสนี้มี onModuleLoad ซึ่งจะเป็นเมธอดแรกสำหรับเริ่มการทำงานตลอดทั้ง project

เมื่อดูจากรูป ผมเรียกใช้คลาส HTML สองครั้งเพื่อสร้างสตริง
"Hello World!" กับสตริง
"ProSbeginner or PhaiPanda"
โดยให้มันทั้งสองถูกวางไว้บน panel ที่เกิดจากคลาส VerticalPanel เสียก่อนแล้วค่อยนำมันไปวางไว้บน panel หลักที่เรียกว่า RootPanel อีกทีหนึ่ง

คำถามคือ RootPanel คืออะไร? สำคัญอย่างไร?
ตอบ RootPanel คือพื้นที่โดย default ที่เป็นตัวเริ่มต้นที่ทำหน้าที่เป็นรากฐานที่ใช้แสดง Widgets ทั้งหลาย

ลองคิดถึงจานหนึ่งใบที่ถูกกำหนดให้วางอยู่อย่างนั้น (วางไว้ที่ไหนสักแห่ง) ขอเรียกจานใบนี้ว่า จาน RootPanel ทีนี้หากเราต้องการวางจานอีกใบลงไปหรือวางสิ่งของอย่างอื่น กติกาคือเราต้องวางลงบนจาน RootPanel นี้ก่อนแล้วกองซ้อนกันขึ้นไป ไม่อย่างนั้นมันก็จะไม่แสดงผลออกมา

สิ่งที่จะวางบน RootPanel ได้ก็คือ Widget (คลาสใดๆที่ฝั่ง GWT เรียกใช้) ในตัวอย่างก็คือคลาส VerticalPanel (วางแบบแนวตั้ง) ซึ่งเราอาจเปลี่ยนเป็น HorizontalPanel (วางแบบแนวนอน) ก็ได้
อ่านเพิ่มเติมเกี่ยวกับ GWT Javadoc
http://www.gwtproject.org/javadoc/latest/allclasses-noframe.html

และ part หน้าเราจะลองใช้ปุ่มเพื่อแสดง Alert ง่ายๆกันครับ

คึกอยากจะทบทวน GWT Framework part 2

Sample GWT Picture

: องค์ประกอบหลักของ Packages ของ Sample GWT Project

เมื่อเราเริ่ม project GWT เราจะพบกับ project ตัวอย่าง และเมื่อสร้างมันขึ้นมาก็จะได้ดังภาพด้านล่างนี้ครับ

ดูกรอบสีส้มเป็นหลักนะครับ ด้านซ้ายมือคือองค์ประกอบหลักซึ่งผมได้ตั้งชื่อ package ว่า com.sample ก็จะได้ package ย่อยสำคัญๆดังนี้
- com.sample.client
- com.sample.server
- com.sample.shared

com.sample.client เก็บ .java ไฟล์ทั้งหมดที่ต้องคอมไพล์ด้วย GWT compiler ได้แก่ ส่วนติดต่อผู้ใช้ (User Interface) รวมถึงแนวคิด RPC (Remote Procedure Calls) ที่ใช้กลไก asynchronous จัดการกับ Input และ Output เช่นการขอข้อมูลจาก database เป็นต้น

com.sample.server เก็บ .java ไฟล์ทั้งหมดที่ต้องคอมไพล์ด้วย Java compiler (งานหลังบ้าน) หากมีการใช้ RPC งานหลังบ้านจะต้องรู้จัก interface ที่ remote ระหว่างฝั่ง client กับ server ซึ่งจะกล่าวอย่างละเอียดในภายหลังครับ
อ่านเพิ่มเติม : http://www.gwtproject.org/doc/latest/DevGuideServerCommunication.html

com.sample.shared เก็บ .java ไฟล์ ที่สามารถถูกคอมไพล์ได้ทั้ง GWT compiler และ Java compiler เช่นพวกบีน (beans) และคลาสกลางต่างๆ (พวก utility)

ทั้งสาม package ย่อยสำคัญข้างต้นนี้ ยังสามารถถูกแบ่งย่อยเพิ่มเติมออกเป็นอีกหลายส่วน ขึ้นอยู่กับ concept ที่ใช้

ต่อไปคือทางขวาของภาพ คลาสชื่อ TestBeginMVP (ตอนนี้ยังไม่ใช้ MVP concept) มีเมธอดชื่อ onModuleLoad ทำหน้าที่เสมือน
public static void main(String[] args)
ของภาษาจาวาธรรมดานั่นแหละครับ

และเพื่อเป็นการง่ายต่อการศึกษา part หน้าเราจะลบโค้ดที่ไม่จำเป็นออกให้หมด ให้เหลือโค้ดหลักๆที่จำเป็นต่อการรันโปรแกรม ไว้เจอกันครับ ^^

คึกอยากจะทบทวน GWT Framework part 1

ถาม : Google Web Toolkit (GWT) คืออะไร?
ตอบ : ง่ายและตรงที่สุดก็คือ เครื่องมือสำหรับสร้าง Web Application ที่เขียนด้วยภาษา Java โดยผลลัพธ์ที่ได้มาคือภาษา JavaScript (หัวใจของเรื่อง)

ทำไมจึงน่าสนใจ? เพราะ GWT สามารถจัดการปัญหาการใช้งานภาษา JavaScript กับ Browser หลากหลายยี่ห้อได้ (ในระดับดีเลยทีเดียว)

ต้องเข้าใจก่อนนะว่า ปัญหาสำคัญตอนนี้สำหรับ Dynamic Web Application คือเจ้า JavaScript ชอบงอแง กล่าวคือ (สมมติ) ทดสอบกับ IE ผลคือน่ารัก ทีนี้ทดสอบกับ Firefox ชักเหลวไหล หรือทดสอบกับ Chrome ยิ่งไปกันใหญ่ หนีออกจากบ้านไปเลย (ทำงานไม่ได้) และยิ่งกับพวกจอหลากหลายขนาดอย่าง Smart Phone หรือ Tablet ด้วยแล้ว JavaScript อย่าได้ทำงานเพี้ยนเป็นอันขาด (โม้ไปอ่านไปนะ)

ทำให้เหล่าประดานักเขียนโปรแกรมต้องมาคอยทดสอบ test งานเดียวกันกับสารพัดค่ายหลากยี่ห้อที่เป็นกลุ่มลูกค้าส่วนใหญ่ เกิดคำว่า 'เสียเวลา' กลายเป็นเรื่องเมียน้อยที่ไม่ได้ใช้เวลากับเนื้อของงาน (Business Logic) จริงๆอย่างเต็มที่ สร้างความปวดหัวและผมร่วงเป็นจำนวนมาก

เอาละในเมื่อเหลืองยืนสงบนิ่ง และแดงเตรียมจะถอย (จริงหรือเปล่า) ก็ร้อนถึงทหารต้องเข้ามาคลี่คลาย (อ่าวคนละเรื่อง) ดังนั้น Google ในฐานะแม่ใหญ่ 'รื้อค้น' จึงเป็นคนกลางจัดคิด GWT ออกมาแก้ปัญหาของภาษา JavaScript โดยชีตีลังการับประกันว่าทุก Browser ทำงานกับ JavaScript ได้ผลลัพธ์เหมือนกันหมด โอ้บระเจ้า!

โอเค ต้องเตรียมอะไรบ้าง?
ข้อ 1) ตัว IDE ช่วยเขียนเจ้าเก่าขั้นเทพ Eclipse IDE ในขณะนี้แนะนำ Eclipse Standard 4.3.1 (Eclipse 4.3 (Kepler)) ตามลิงค์ โหลดเลย
http://www.eclipse.org/downloads/

ข้อ 2) ถัดมาคือ GWT Plugin เอาไว้ให้พี่ Eclipse เขารู้จัก GWT ไง เวลา compile ก็จะได้ตามนี้ .java -> .class -> .js ซึ่งควรจะตรงกับรุ่นของพี่ Eclipse ข้างต้น (Eclipse 4.3 (Kepler)) ดังนั้นแนะนำหน้านี้ (ไม่ใช่ลิงค์โหลดนะ เดี๋ยวบอกว่าทำไง)
https://developers.google.com/eclipse/docs/download

ติดตั้งอย่างไร?
- ลองดูหน้านี้ก่อน (ยังไม่ต้องทำตาม)
http://bunyiam.com/?name=knowledge&file=readknowledge&id=2989

- จากนั้นเปิด Eclipse แล้วเลือกเมนู Help > Install New Software..
แล้วเริ่มขั้นตอนได้เลย ทำตามลิงค์ด้านบนนี้นะ เพียงเปลี่ยน URL ที่จะโหลด GWT SDKs เป็นตามเนื้อหาของข้อ 2)

- ก็จะปรากฏหน้าต่าง Available Software ตรงนี้สำคัญมาก ขั้นพื้นฐานนี้ไม่ต้องบอก Eclipse ให้โหลดมาหมดนะครับ (ซักผ้าได้หลายกะละมัง มันนานมาก) เลือกแค่
1) Google Plugin for Eclipse (required)
2) SDKs โดยโปรดเลือกย่อยลงไปอีก เอาแค่
2.1) Google Web Toolkit SDK 2.5.1

จบแล้ว... ถ้าท่านทำการนี้สำเร็จ ท่านก็จะได้ทั้ง Eclipse และ GWT SDKs เวอร์ชันล่าสุด (latest) เลยทีเดียวเทียว (ม.ค. 2014) แน่นอนว่า Eclipse ของท่านจะต้องมีไอคอนรูปตัวจี (g) สีฟ้าผุดออกมา เพื่อไว้ New Web Application Project นะครับ มิเช่นนั้นแสดงว่าหงายเงิบ

อ่านเพิ่มเติม
https://sites.google.com/site/jatupornmabangcru/google/google-web-toolkit-gwt
http://www.doesystem.com

คึกอยากจะทบทวน Spring Framework part 7

: Injection เหล่าคลาสโดยการใช้ Autowire

ถาม : ขอคำตอบง่ายๆทำไมต้อง Injection?
ตอบ : เพราะไม่อยาก new object เอง ถึงเวลา (want) ก็ฉีด (injection) object นั้นให้ไปใช้เลย

ถาม : ขอคำตอบง่ายๆทำไมต้อง Autowire?
ตอบ : เพราะไม่อยากเขียน config ที่ไฟล์ XML เยอะๆไง (มันเยอะมันยุ่ง มันงง)

ถาม : แล้ว Injection เกี่ยวกับ Autowire อย่างไร?
ตอบ : มันเป็น concept บวกกับวิธีการที่ว่า How to? อธิบายง่ายๆได้ว่า โดยปกติแล้ว object ที่จะถูกใช้งานก็ต้อง new มันขึ้นมาก่อนใช่ไหม? ใช่ นอกจากนี้บรรดา object อาจต้องการทรัพยากร (arguments) หนึ่งสองสามสี่ห้า ไม่รู้แหละ (ใครเคยโค้ดโปรแกรมใหญ่ๆจะรู้ว่ามันทรมารใจมากที่เห็น parameter ยาวเป็นหางงู) จึงต้องหาวิธีการสักอย่างที่จะนำทรัพยากรดังกล่าวใส่ลงไปใน object แบบโค้ดสะอาดที่สุด
- โค้ดในไฟล์ .xml น้อยลงก็ต้องใช้ Autowire
- เตรียม object พร้อมใช้ ก็แค่รอฉีด (injection) มันเข้าไป (ไม่ต้อง new เอง)

ถาม : ชักอยากเห็นการใช้ Injection และ Autowire
ตอบ : เอา project จาก part 6 มาแก้และเพิ่มเติมโค้ดดังนี้สิ

>> autowire="constructor"

เปิดไฟล์ applicationContext.xml ลบหรือ comment แท็ก <property ... ></property> แล้วเพิ่ม autowire เข้าไปแทน (ลดโค้ด โค้ดน้อยลง โค้ดก็สะอาดขึ้น) ดังด้านล่าง

<bean name="customerService" class="com.sample.service.CustomerServiceImpl" autowire="constructor" >
</bean>


ทดสอบการ run ก็จะได้ผลลัพธ์ตามเดิม เรียกวิธีการนี้ว่า 'Constructor Injection' โดยจะมองไปที่ไทป์และจำนวนของไทป์ที่จะส่งให้ constructor นั้นๆเป็นสำคัญ

ทดลองเปลี่ยน autowire เป็นแบบ byName และ byType แล้ว run สลับกับการ comment หรือ uncomment ในไฟล์ CustomerServiceImpl.java พลางสังเกตผลลัพธ์ ด้วยเงื่อนไขต่างๆต่อไปนี้

>> autowire="byName"

ทำงานกับชื่อของ setter method ต่างๆ ดังนั้น setCustomerRepository จึงถูกเรียกให้ทำงาน โดยจะตัด set ออกเหลือเพียง customerRepository แล้วเทียบกับแท็ก bean ในไฟล์ .xml ที่ระบุชื่อเดียวกันนี้ นั่นก็คือ

<bean name="customerRepository" class="com.sample.repository.HibernateCustomerRepositoryImpl" />

หมายความว่าอย่างไร? หมายความว่า ถ้าเราเขียน setter method ในไฟล์ CustomerServiceImpl.java เป็น setCustomerRepository1 ก็ต้องเขียน bean name ข้างต้นเป็น customerRepository1 ด้วย นี่จึงเรียกว่าการ 'Injection by Name'

*** หมายเหตุ หากว่ารันเจอ error แบบนี้หมายความว่าอย่างไร?

- แสดงว่าคลาส CustomerServiceImpl ขาด default constructor ตามที่มันบอกงั้นเหรอ? ไม่เชิงเสียทีเดียว เพราะว่าเราได้ไปสร้าง constructor ขึ้นมาเองและบังคับให้มันผ่านออบเจ็กต์ของคลาส CustomerRepository ซึ่งไม่ใช่ constructor แบบที่มันต้องการ, มันต้องการ constructor เพิ่มอีกหนึ่งตัว (หากว่าเราไม่ลบ constructor เดิมทิ้งก่อน) ที่มีหน้าตาเหมือน default constructor เป๊ะๆ ดังรูปนี้ครับ


>> autowire="byType"

ทำงานกับไทป์ของ setter method ต่างๆ ขอเพียงไทป์ตรงกัน setter method นั้นๆก็จะถูกเรียกให้ทำงานทันที

หมายความว่าอย่างไร? หมายความว่า สมมติว่าถ้ามี
setCustomerRepository1,
setCustomerRepository2,
setCustomerRepository3 และ setFoo (ชื่อไม่เกี่ยวกับชาวบ้านเลย)
ที่รับไทป์แบบเดียวกันทั้งหมด มันก็จะไล่ทำ setter ข้างต้นนี้หมดเบยไงก๊าบ นี่จึงเรียกว่าการ 'Injection by Type'

*** ตามที่ได้บอกไป ทั้ง byName และ byType จะต้องมี default constructor แบบเขียนเองด้วยเสมอ (ยกเว้นเราไม่เขียน constructor เลยสักตัว แต่ปล่อยให้จาวาสร้างให้ ก็จะมี default constructor ให้ใช้โดยอัตโนมัติ)


part นี้ไม่มีไฟล์ให้นะครับ คืนนี้ฝันดีครับ

>> กลับมาตอบข้อสงสัยของเพื่อนๆที่ว่า มันเรียงลำดับการทำงานของ setter methods อย่างไรกับ autowire="byType"
คำตอบนี้ตามภาพเลยครับ

ขอบคุณเพื่อน Phruds Kaewmuang ที่ช่วยให้คำตอบครับ :)

คึกอยากจะทบทวน Spring Framework part 6

: XML กับ Default Constructor และ Constructor

กลับมาทบกวน applicationContext.xml กันอีกครั้งก่อนจะเพิ่ม config ให้กับ constructor ของคลาส CustomerServiceImpl

คลาส CustomerServiceImpl เราได้เขียน setCustomerRepository เป็นเหตุให้ต้องเขียน setter config ที่ไฟล์ .xml เป็น
property name="customerRepository" จริงไหมล่ะ

ดูด้านล่างนี้ประกอบ (ตัดเอาบางส่วนมา และก็อย่าไปงงกับ property ref ล่ะ)

<bean name="customerService" class="com.sample.service.CustomerServiceImpl">
     <property name="customerRepository" ref="customerRepository" ></property>
</bean>

จากนั้นลองกลับไปดูโค้ดจาวาที่ไฟล์ Application.java เจาะจงท่อนที่เขียนว่า

CustomerService service = applicationContext.getBean("customerService", CustomerService.class);

โค้ดข้างบนนี้ทำอะไร? มันสั่งให้ไฟล์ .xml สร้างออบเจ็กต์คลาส CustomerServiceImpl ผ่าน default constructor ครับ (default constructor หน้าตาเป็นไงคงรู้กันนะ ซึ่งเราไม่จำเป็นต้องเขียนเอง)

คำถามคือ default constructor ไม่มีพารามิเตอร์ส่งค่าให้ออบเจ็กต์ แล้วอีกท่อนที่เขียนว่า service.findAll().get(0).getFirstName() ทำงานได้อย่างไรครับ?

ใครตาไวก็จะตอบได้เลยว่ามาจาก setter config ที่เขียนบอกไว้ในไฟล์ .xml นั่นไง ถูกต้องนะครับ! หากไม่เชื่อลองลบท่อนด้านล่างนี้ออกไปสิ

<property name="customerRepository" ref="customerRepository" ></property>

ผลคือเมื่อมันพยายามเรียก findAll() ค่าที่ได้ก็จะเป็น null ทันที

สรุปได้ว่าเมื่อเราสั่งให้ไฟล์ .xml สร้างออบเจ็กต์คลาส CustomerServiceImpl ผ่าน default constructor หลังจากนั้นมันก็จะไปเรียก setter ของคลาส CustomerServiceImpl ให้ทำงานด้วย เหตุนี้มันจึงสร้างออบเจ็กต์คลาส HibernateCustomerRepositoryImpl ให้เลยโดยอัตโนมัติครับ (แท้จริงก็ตาม config ที่เขียนไว้นั่นแหละ)

ทีนี้มีบางคนเกิดอยากรู้ว่า ถ้าไม่ต้องการให้ setter ทำงานล่ะ จะมีวิธีอื่นอีกไหมในการเขียน config ในไฟล์ .xml ?

คำตอบคือ มีครับ หนึ่งในนั้นคือการเขียน constructor config ที่รับค่าออบเจ็กต์ของคลาส HibernateCustomerRepositoryImpl เข้าไปแทน ดังนี้ (ลบ setter config ออกไปได้เลย หรือจะใส่ comment ไว้ก็ได้ ในที่นี้ผมลบไปเลย)

<bean name="customerService" class="com.sample.service.CustomerServiceImpl">
     <constructor-arg index="0" ref="customerRepository"></constructor-arg>
</bean>

เอาล่ะ constructor-arg index="0" คือตำแหน่งแรกของ args ตัวที่หนึ่ง
และ ref="customerRepository" ก็มีไว้อ้างไปยังคลาส HibernateCustomerRepositoryImpl ที่เขียน config ไว้ไง

เสร็จแล้ว save จะพบกับ error ทันตา นั่นเพราะคลาส CustomerServiceImpl ไม่มี constructor ดังที่เขียนไว้ใน constructor config (ส่วน default constructor ตายไปแล้วเรียบร้อย เพราะเราพยายามเขียน constructor ขึ้นมาเอง)

เราก็ต้องไปเพิ่ม constructor ลักษณะดังกล่าวให้กับคลาส CustomerServiceImpl ครับ

public class CustomerServiceImpl implements CustomerService {
...

     public CustomerServiceImpl(CustomerRepository customerRepository) {
          this.customerRepository = customerRepository;
     }

...
}

ได้อย่างนี้แล้ว setter ในคลาสนี้ก็จะไร้ความหมายไปเลยนะ ใครอยากลองก็ comment มันออกไป แล้ว run ดูผลลัพธ์ ก็จะได้ตามเดิมครับ

ข้อสังเกตที่ผมได้รับคือ การสร้างออบเจ็กต์ด้วย xml ในกรณีตัวอย่างนี้ constructor ที่ผ่านค่าได้โดยตรงสำคัญกว่า default constructor

part ต่อไปเราจะเริ่ม injection เหล่าคลาสโดยการใช้ autowire กันนะครับ
และนี้คือโค้ดทั้งหมดของ part นี้ (ง่วงนอนแล้ว ฝันดีเพื่อนๆ)
http://www.mediafire.com/download/e75264xnp9kjbsc/spring_sample_xml_2.zip

คึกอยากจะทบทวน Spring Framework part 5

: เตรียมลุย Spring กับ XML Setter Method

จาก part 4 และก่อนหน้านี้เราคงทราบกันแล้วว่า interface มีความสำคัญอย่างไร และในโอกาสนี้เราจะเริ่มใช้งานไฟล์ XML เพื่อเข้าถึง constructor และ set methods แทนการ new object โดยตรง

เตรียม project ให้พร้อม...

ผมเลือกใช้ IDE ที่มีชื่อว่า Spring Tool Suite (3.4.0.RELEASE) เพราะต่อไปนี้เราจะต้องอาศัยความสามารถและคุณสมบัติต่างๆของมัน (เพื่ออำนวยความสะดวกไงล่ะ) ติดตั้งให้เรียบร้อยนะ

เริ่มต้นโดยเปิด project เดิมของ part 4 (spring_sample) จากนั้น copy และ paste ให้ได้อีก project หนึ่งโดยเปลี่ยนชื่อเป็น spring_sample_xml จากนั้น close เจ้า spring_sample ไปก่อน (มันรกหูรกตา)

โหลด library ของ spring framework (เวอร์ชัน 3.2.3.RELEASE) ได้จาก
http://goo.gl/szdN1P
ซึ่งประกอบด้วย
- Sources
- Javadocs
- และ Binaries

คลาย .zip ที่ได้แล้วเปิดไปที่ [เครื่องใครเครื่องมัน]\spring-framework-3.2.3.RELEASE-dist\spring-framework-3.2.3.RELEASE\libs จะเห็น .jar เต็มไปหมด

กลับมาที่ project มองหา folder ชื่อ libs (ไม่มีให้สร้างขึ้นมา) ให้เราเลือกและ copy เจ้า library สกุล .jar (ที่คลาย .zip มากี้อะ) เข้าไปใน folder ชื่อ libs ของ project ได้แก่
- spring-beans-xxx.jar
- spring-context-xxx.jar
- spring-core-xxx.jar
- และ spring-expression-xxx.jar

โหลด library ของ Apache Commons มาด้วยจาก
http://commons.apache.org/proper/commons-logging/download_logging.cgi
มองหา commons-logging-xxx-bin.zip ในหมวดของ Binaries

คลาย .zip ที่ได้แล้วเปิดไปที่ [เครื่องใครเครื่องมัน]\commons-logging-1.1.3-bin\commons-logging-1.1.3
มองหา commons-logging-xxx.jar

กลับมาที่ project มองหา folder ชื่อ libs เดิม แล้ว copy เจ้า commons-logging-xxx.jar เข้าไปรวมกับ .jar ทั้งสี่ไฟล์ก่อนหน้านี้ (ส่วนใครสงสัยว่าแต่ละ .jar ใช้ทำอะไรบ้าง ให้ลองค้นหาเพิ่มเติมเอาเองนะก๊าบ)

สุดท้ายของการเตรียมการคือเลือก .jar ทั้งห้าไฟล์แล้วคลิกขวาเลือก Build Path ต่อด้วย Add Build Path
ผลคือได้ไฟล์กระปุกแยมมาแทน ซึ่งจะอยู่ภายใต้ Referenced Libraries ทั้งหมด

เริ่มต้นสร้าง .xml ไฟล์แรก

- คลิกขวาที่ project เลือก New ต่อด้วย Spring Bean Configuration File
- ตั้งชื่อ applicationContext.xml ในช่อง File name และเลือกที่อยู่ของมันเป็น spring_sample_xml/src แล้วจึงกดปุ่ม Finish

มันจะสร้างไฟล์ applicationContext.xml ให้ เปิดไปจะพบกับโค้ด xml ดังด้านล่าง (ไม่ต้องสนใจ แค่บอกให้รู้เฉยๆ)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

A (วางไว้เผื่อขั้นตอนด้านล่าง)
B (วางไว้เผื่อขั้นตอนด้านล่าง)

</beans>

ณ ตำแหน่ง A แทนด้วยการบอก xml ให้รู้จักกับคลาส HibernateCustomerRepositoryImpl ซึ่งจัดว่าเป็น repository เพื่อเรียกใช้เมธอด findAll เราจึงเขียน config (บางทีเรียกว่าการลงทะเบียน) ดังนี้

<bean name="customerRepository" class="com.sample.repository.HibernateCustomerRepositoryImpl" />

โดย name คือชื่อ (อะไรก็ได้) ขณะนี้ตั้งเป็น customerRepository
ส่วน class คือแหล่งอ้างอิงตาม package เพื่อระบุยังคลาส HibernateCustomerRepositoryImpl

ณ ตำแหน่ง B เมื่อ xml รู้จักกับ repository แล้ว ก็มาถึงคราวของ service ต้องลงทะเบียนบ้าง (ถ้าสงสัยว่า repository สัมพันธ์อย่างไรกับ service ให้ย้อนไปอ่าน part ก่อนหน้านี้นะ) เขียน config ได้ดังนี้

 <bean name="customerService" class="com.sample.service.CustomerServiceImpl">
 <property name="customerRepository" ref="customerRepository" ></property>
 </bean>

ให้สังเกตุ property name กับ property ref ให้ดีๆนะครับ (ลอง copy วางใน Notepad กล่าวคือ
- name หมายถึง set method ซึ่งยังไม่ได้เขียนขึ้น (เดี๋ยวเขียน)
- ref หมายถึง ชื่อที่อ้างไปยัง name ของ repository ข้างต้น ซึ่งก็คือ customerRepository

ทีนี้ service ก็จะรู้จักกับ repository แล้วจ๊ะ ขาดก็แค่ set method ของคลาส CustomerServiceImpl เท่านั้น ดังนั้นเปิดไฟล์ CustomerServiceImpl.java

- ยกเลิกการ new HibernateCustomerRepositoryImpl เพราะ xml ทำให้แล้ว จากนั้นเพิ่ม set method เข้าไปแทน ได้ดังนี้

package com.sample.service;
import java.util.List;
import com.sample.model.Customer;
import com.sample.repository.CustomerRepository;
import com.sample.repository.HibernateCustomerRepositoryImpl;

public class CustomerServiceImpl implements CustomerService {

     /*private CustomerRepository customerRepository = new HibernateCustomerRepositoryImpl();*/
     private CustomerRepository customerRepository;

     public void setCustomerRepository(CustomerRepository customerRepository) {
          this.customerRepository = customerRepository;
     }

     public List<Customer> findAll() {
          return customerRepository.findAll();
     }
}

เพียงเท่านี้เจ้าไฟล์ applicationContext.xml ก็จะไม่ error แล้วล่ะ

กลับไปแก้ไขการเรียกใช้ setCustomerRepository ในไฟล์ main เพื่อจะได้ run ดูผลลัพธ์ (รันตอนนี้เจอ null error แน่นอน) เปิดไฟล์ Application.java

- ยกเลิกการ new CustomerServiceImpl โดยตรง แต่จะ new ผ่าน .xml

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sample.service.CustomerService;

public class Application {
     public static void main(String[] args) {
          /*CustomerService service = new CustomerServiceImpl();*/
          ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

          CustomerService service = applicationContext.getBean("customerService", CustomerService.class);
          System.out.println(service.findAll().get(0).getFirstName());
     }
}

ผลการ run ก็จะได้
... mework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4aad08: defining beans [customerRepository,customerService]; root of factory hierarchy
Phai

ดูตรงท้ายได้ Phai ออกมาก็เป็นอันว่าเรียบร้อยครับ ซึ่งต่อไปเราจะมา config ไฟล์ xml กับ constructor กันบ้าง (เยอะไปแฮะ)

ส่วนนี่คือไฟล์ที่ทำเสร็จแล้ว แนะนำให้เปิดกับ Spring Tool Suite นะครับ
http://www.mediafire.com/download/0xv59z65g65g7s1/spring_sample_xml.zip

คึกอยากจะทบทวน Spring Framework part 4

: Sample Project กับ Model, Repository และ Service

ถาม : จาก part 3 ที่ผ่านไป อยากให้จำลองการทำงานแบบใช้ concept ของ model, repository และ service ด้วยกลไกของภาษาจาวาแบบไม่ซับซ้อน
ตอบ : ถ้าอย่างนั้นสร้าง project ใหม่ แล้วลองทำตามข้าพเจ้า
- สร้าง project ใหม่ชื่อ spring_sample
- สร้าง package ชื่อ com.sample.model สำหรับจำลอง model
- สร้าง package ชื่อ com.sample.repository สำหรับจำลอง repository
- สร้าง package ชื่อ com.sample.service สำหรับจำลอง service
- สร้าง package ชื่อ com.sample.server สำหรับจำลอง server (คลาสทดสอบพร้อม main เมธอด)


- สร้าง class ชื่อ Customer ให้เป็น bean ใน model ดังนี้

package com.sample.model;

public class Customer {
     private String firstName;
     private String lastName;

     public Customer() { }

     public String getFirstName() {
          return firstName;
     }

     public String getLastName() {
          return lastName;
     }

     public void setFirstName(String firstName) {
          this.firstName = firstName;
     }

     public void setLastName(String lastName) {
          this.lastName = lastName;
     }
}


- สร้าง interface ชื่อ CustomerRepository เก็บไว้ใน repository บังคับกติกา findAll (สมมติว่าสามารถดึงข้อมูลทั้งหมดจาก database) ดังนี้

package com.sample.repository;
import java.util.List;
import com.sample.model.Customer;

public interface CustomerRepository {
     List<Customer> findAll();
}


- เมื่อมี interface (เจ้า spring จะทำงานกับ interface เป็นสำคัญนะ) ก็ต้องมีการ implementation ไปใช้งาน ดังนั้นสร้าง class ชื่อ HibernateCustomerRepositoryImpl เพื่อรับเอากติกาดังกล่าวไปใช้ (ชื่อยาวไปนิด แต่เป็นข้อแนะนำที่ดีในการตั้งชื่อให้สื่อความหมายนะครับ ในที่นี้ใช้คำว่า Hibernate ด้วย คือจะสื่อสมมติว่าใช้ Hibernate เป็นตัวจัดการข้อมูลระหว่างโปรแกรมนี้กับ database นั่นเอง)

package com.sample.repository;
import java.util.ArrayList;
import java.util.List;
import com.sample.model.Customer;

public class HibernateCustomerRepositoryImpl implements CustomerRepository {
     public List<Customer> findAll() {
          List<Customer> customers = new ArrayList<Customer>();
          Customer customer = new Customer();
          customer.setFirstName("Phai");
          customer.setLastName("ProSbeginner");
          customers.add(customer);
          return customers;
     }
}

ในที่นี้เราก็ให้ว่าเมธอด findAll เมื่อถูกเรียกให้ทำงานจะไปค้นหาข้อมูลใน database มา คือเอามาใส่ไว้ใน List สมมติว่าได้ข้อมูลดังข้างต้น


- ทีนี้ก็ service เริ่มโดยสร้าง interface ชื่อ CustomerService บังคับให้มี findAll (เพื่อในอนาคตจะให้ไปเรียก repository) ดังนี้

package com.sample.service;
import java.util.List;
import com.sample.model.Customer;

public interface CustomerService {
     List<Customer> findAll();
}


- แล้วจึง implementation มันในชื่อ CustomerServiceImpl การทำงานให้สร้าง object ของ repository ที่จะไปดึงข้อมูลมาให้ ดังนี้

package com.sample.service;
import java.util.List;
import com.sample.model.Customer;
import com.sample.repository.CustomerRepository;
import com.sample.repository.HibernateCustomerRepositoryImpl;

public class CustomerServiceImpl implements CustomerService {
     private CustomerRepository customerRepository = new HibernateCustomerRepositoryImpl();
     public List<Customer> findAll() {
          return customerRepository.findAll();
     }
}


- สุดท้ายแล้วก็สร้าง class ทดสอบชื่อ Application เรียกไปที่ service แล้วถามหา findAll ในที่นี้มีข้อมุลเดียวก็เลยเรียกไปที่ get(0) ก็จะได้ชื่อออกมาครับ

package com.sample.server;
import com.sample.service.CustomerService;
import com.sample.service.CustomerServiceImpl;

public class Application {
     public static void main(String[] args) {
          CustomerService service = new CustomerServiceImpl();
          System.out.println(service.findAll().get(0).getFirstName());
     }
}


ผมอยากให้สังเกตการเรียกใช้งานที่เราจะมุ่งไปยัง interface เป็นสำคัญ ลองทำความเข้าใจไปทีละน้อย ส่วน part หน้า เราจะมาควบคุมการเรียกลักษณะคล้ายกันนี้ด้วย xml ครับ

คึกอยากจะทบทวน Spring Framework part 3

: Model, Repository และ Service Concept

ถาม : จาก part 2 ยังมีการจำแนก package จำลองอย่างอื่นนอกจาก client กับ server อีกหรือไม่?
ตอบ : โดยหลักทั่วไปแล้ว package มักถูกสร้างขึ้นเป็นพื้นฐานเพื่อใช้เล่าเรื่องของกลุ่มคลาสใดๆอยู่แล้ว ซึ่งอยู่ที่ความคิดหรือ concept ในการสร้างคลาสต่างๆเป็นสำคัญ จากคำถามขอตอบว่ามีครับ และในที่นี้จะขอกล่าวถึง model, repository และ service เพิ่มเติมให้ด้วย

ถาม : อะไรคือ Model?
ตอบ : model ในที่นี้ก็ M ของ MVC นั่นแหละครับ (บางทีก็เรียกว่า shared) เป็น package สำหรับเก็บประดา POJO ที่จะกลายร่างเป็น Bean (ย้อนกลับไปอ่านที่ part 1 เรื่องของ POJO ถ้าจำไม่ได้นะ) เจ้า model package นี้จะเป็นตัวกลางที่ client และ server จะหยิบ bean ไปใช้ เพราะ bean นี้สำคัญมาก มันคือ data class ที่ทำหน้าที่รับหรือส่งค่าใดๆนั่นเอง

ถาม : อะไรคือ Repository?
ตอบ : concept ของ repository กว้างมาก ในที่นี้ผมหมายถึง package ที่รวบรวมคลาสที่ห่อหุ้มหรือเกี่ยวข้องกับ database เป็นหลัก
- ถ้ากล่าวถึง repository ในแง่ของคลาสที่ห่อหุ้ม Java Database Connectivity (JDBC) ไว้ก็จะเรียกให้ชัดว่า Data Access Object (DAO) หรือก็คือคลาสที่เป็นตัวกลางในการเชื่อมต่อข้อมูลระหว่างฐานข้อมูลกับส่วนอื่นของโปรแกรมของเรา ยกตัวอย่างเช่น

       ส่วน server เรียกไปยัง service ทำโน่นนี่นั่นก่อน จากนั้น service เรียกไปยัง dao โดยที่ dao ยิง sql ไปกระทำกับ database อีกที และในทางกลับกันหรือหลังจากนั้น สมมติว่า dao ขอข้อมูลหนังสือทุกเล่มจาก database ได้แล้วก็จะส่งข้อมูลนี้กลับไปยัง service เพื่อทำโน่นนี่นั่น เมื่อเรียบร้อยแล้วจึงกลับไปหา server เป็นต้น

- ถ้ากล่าวถึง repository ในแง่ของคลาสที่ทำหน้าที่แทนความสำพันธ์ของฟิลด์ใน database ก็จะเรียกให้ชัดว่า Entity (แน่นอนว่าหนึ่ง entity เกี่ยวข้องกับฟิลด์ได้มากกว่าหนึ่งตาราง หรือทั้งตารางคือหนึ่ง entity ก็ได้)

ถาม : อะไรคือ Service?
ตอบ : มันคือคลาสบริการที่ server จะเรียกมาใช้งาน คลาสจำพวก service ต้องทำหน้าที่เฉพาะด้านมากๆ เช่น การเงิน, การขนส่ง, การคำนวณภาษี, การจัดการทรัพยากรบุคคล และอื่นๆ ในที่นี้ service จะเรียกใช้ repository เพื่อกระทำกับข้อมูลในรูปแบบต่างๆ แล้วส่งผลลัพธ์ในรูปของ bean กลับไปยัง server

ถาม : งั้นอะไรคือ Bean?
ตอบ : เจ้า bean ก็คือ POJO class (จาวาคลาสธรรมดา) ที่ถูกกำหนดให้มีระเบียบหรือกติกาดังนี้ต่อเติมเข้าไป
- จาวาคลาสธรรมดานั้นต้องมี default constructor เพื่อให้ประดา framework ต่างๆนำมาสร้างเป็น object ได้ง่าย
- จาวาคลาสธรรมดานั้นต้องมี accessible method หรือการเข้าถึงประเภท get, set, is (สำหรับชนิด boolean) ให้เข้าถึงคุณลักษณะ (attributes) ของมันจากภายนอก
- จาวาคลาสธรรมดานั้นควรที่จะทำ serializable ได้ เพื่อให้ประดาโปรแกรม application framework สามารถนำมันไปบันทึกหรือเรียกใช้โดย virtual machine ที่เป็นอิสระจาก platform ใดๆ
*** อ่านเพิ่มเติม https://en.wikipedia.org/wiki/JavaBeans

อย่างว่าล่ะครับ ใช้ framework ก็คือการศึกษาความคิด หรือก็คือ concept ที่เขาคิด ดังนั้นหากไม่เข้าใจความคิด ก็ยากที่จะเข้าใจ framework

และสำหรับ Spring Framework หัวใจของมันก็คือการใช้ Autowired กับ Dependency Injection (รู้แต่ว่าฉีด no config)

ไว้ต่อที่ part 4 แล้วกันนะ

คึกอยากจะทบทวน Spring Framework part 2

: Basic concept of "Hello Google"

ติดค้างจากคำถามที่ว่า : ไม่เคยใช้ framework อะไรมาก่อนเลย มีแต่พื้นฐานจาวาธรรมดา จะเรียนรู้ได้อย่างไรล่ะ?
ตอบ : อันที่จริงผมก็ไม่แม่นเรื่อง web application เหมือนกัน ดังนั้นเรามาเริ่มทำความเข้าใจร่วมกันอย่างนี้นะครับ
- โดยปกติแล้ว web application จะมีสองโลกที่แตกต่างกัน คือโลกของ server กับโลกของ client ทั้งสองโลกจะอาศัยข้อกำหนดที่เรียกว่า protocol เป็นตัวกลางในการติดต่อสื่อสารกัน
- protocol มีหลายประเภท (เช่น HTTP protocol) แต่ละประเภทก็มีข้อกำหนดหยุมหยิมแตกต่างกันไป ซึ่งเราจะไม่พูดถึง protocol จริงๆ แต่จะจำลองเอาว่า
- ให้ interface เป็นดั่ง protocol และ class เป็นดั่งโลกทั้งสอง

ถาม : Interface กับ Class เกี่ยวดองกันอย่างไร?
ตอบ : เมื่อฝึกเขียนจาวา เรียนรู้จาวา เราอาจยังไม่รู้จัก interface ทว่าผมอยากบอกว่าแท้จริงแล้วจาวานั้นเต็มไปด้วย interface มันเป็นข้อกำหนดประการหนึ่งที่ทำให้คลาสถูกบังคับให้เกิดพฤติกรรม มาถึงจุดนี้บางคนก็งงว่าคลาสนิยามพฤติกรรมของตัวเองได้ จะมี interface อีกทำไม ก็ขอย้ำว่า เพื่อบังคับให้เกิดพฤติกรรม หรือก็คือ กติกา นั่นเอง เช่น นักกีฬา (ให้เป็น class นักกีฬา) จะเล่นบาสได้ก็ต้องรู้จักกติกาของการเล่นบาสฯ (ให้เป็น interface ของกีฬาบาสฯ) ดังนั้น นักกีฬาที่ implements กติกาการเล่นบาสฯ ก็จะเป็นนักกีฬาที่เล่นบาสฯได้ เป็นต้น

ถาม : ไหนลองจำลองการสื่อสารกันระหว่างคลาส ที่ใช้ Interface?
ตอบ : ง่ายๆก่อนนะ เริ่ม NetBean หรือ Eclipse (ผมใช้ Eclipse นะ) แล้วทำตามขั้นตอนต่อไปนี้
1.1) สร้าง package ชื่อ sample.client
1.2) สร้าง package ชื่อ sample.server
1.3) สร้าง package ชื่อ sample.protocol
2.1) สร้าง class ชื่อ Browser ไว้ใน sample.client ให้มี main อยู่ด้านใน



2.2) สร้าง class ชื่อ Application ไว้ใน sample.server


3.1) สร้าง interface ชื่อ HttpProtocol ไว้ใน sample.protocol ระบุข้อบังคับเป็น
public String get(String websiteName);


4.1) บังคับให้ class ชื่อ Application จง implements เจ้า interface ที่ชื่อ HttpProtocol
4.2) แล้วเขียนรายละเอียดดังนี้
public String get(String websiteName) {
     return "Hello " + websiteName;
}


5.1) กลับไปที่ class ชื่อ Browser ใน main ให้เขียนว่า
HttpProtocol protocol = new Application();
System.out.println( protocol.get("Google") );
5.2) จากนั้น run ก็จะได้ผลลัพธ์เป็น
Hello Google


ต่อไปเมื่อเราศึกษา Spring Framework (แท้จริงเป็นเรื่องของ OOP อยู่แล้ว) เราจะพบว่ามี interface ก็จะมี class ที่ implements เจ้า interface นี้ไปใช้ และคลาสนั้นจะเขียนชื่อต่อท้ายว่า Impl (ข้อแนะนำของพวกเขา) เช่นคลาส A ใช้เจ้า interface ชื่อ B ก็จะเขียนชื่อคลาส A ใหม่ว่า AImpl เป็นต้น

เอาล่ะครับผมอยากให้เข้าใจตัวอย่างข้างต้นนี้เสียก่อน ถ้าเข้าใจว่า อ้อ เขาตกลงจะเขียนกันแบบนี้นะ เอา interface มารับ object ที่เกิดจาก class แล้วก็เรียกใช้บริการ (พฤติกรรม) ตามที่ interface นั้นระบุ เป็นอันว่าเราคุยเรื่องเดียวกันแล้ว

ต่อไป part 3 ก็จะบุกเข้าหา Spring มากขึ้นเรื่อยๆ ส่วนสุดท้ายนี้คือโค้ดตัวอย่างข้างต้นครับ (เปิดด้วย eclipse นะ)

http://www.mediafire.com/download/ocvp1v0rsax98hy/

คึกอยากจะทบทวน Spring Framework part 1

ถ้าเรายังหัดเดินเหมือนๆกัน เรามาร่วมกันแชร์นะครับ

ถาม : Framework คืออะไร สำคัญอย่างไรทำไมต้องศึกษา?
ตอบ : มันคือความคิดครับ เป็นความคิดในการแก้ไขปัญหา ก็ตามแต่ framework นั้นๆจะประกาศตนเองว่าสามารถจัดการกับปัญหาอะไรได้บ้างและได้อย่างไร ก็จะมีรูปแบบหรือวิธีการที่เรียกว่า API มาให้ใช้ และเมื่อเราปฏิบัติตามแนวทางที่มันได้วางไว้ ปัญหาก็จะถูกแก้ไขในที่สุด อย่างไรก็ตามก็ต้องเลือก framework ให้ถูกกับปัญหาที่ประสบอยู่ด้วยนะครับ

ถาม : Spring Framework เหตุใดจึงน่าใช้?
ตอบ : นั้นก็เพราะว่า framework ของจาวาที่มีมาก่อนหน้านี้ (เช่น Struts เป็นต้น) ผูกพันธ์กับ Enterprise Java Bean (EJB) มากเกินไป (ผมก็ไม่เคยเขียน EJB) เข้าใจว่าเมื่อ EJB มีความสามารถมากขึ้นก็จะซับซ้อนขึ้นเรื่อยๆ (คลาสถูกถ่ายทอดหลายลำดับชั้น) ผู้สร้าง Spring ต้องการลดความซับซ้อนของ EJB จึงได้คิด Spring Framework ขึ้น (ตัดสินใจไม่เอา EJB) เขาต้องการจาวาคลาสธรรมดาอย่างที่ธรรมดาสุดๆ และเรียกจาวาคลาสธรรมดาสุดๆนั้นว่า POJO พร้อมกับบอกว่า Spring นั้น...
- Reduce the complexities of Enterprise Java development
- POJO base and Interface driven
- Lightweight and unobtrusive compared to older J2EE methodologies
- AOP / Proxiex
- Built around patterns and best practices

ถาม : Plain Old (หรือ Ordinary) Java Object (POJO) แจ่มอย่างไร?
ตอบ : ผมเป็นผู้ชายชอบผู้หญิงสวย เก่งและเริด (EJB) แต่เมื่อคบพวกเธอไปสักระยะหนึ่งแล้ว (แน่นอนว่าอาจหลายปี) ผมไม่สามารถจัดการความ art พวกเธอได้ ตรงกันข้ามเมื่อผมได้รู้จักสาวบ้านนา คนบ้านนอก (POJO) ผมบอกกับตัวเองในวินาทีนั้นว่า เธอช่าง...
- Testability
- Maintainability
- Scalability
- Complexity
- Business Focus (ตรงนี้คือจุดขายสำคัญครับ คิดแต่การแก้ปัญหาพอ เรื่องอื่นไม่อาว จะ config จะ exception ฯลฯ ไปที่อื่น ไม่ต้องเขียนอยู่หน้าเดียวกัน)

ถาม : คิดถึง Spring Framework ต้องคิดถึง MVC ใช่ไหม?
ตอบ : ใช่เกือบ 100% สำหรับงานที่ผมเห็นโดยทั่วไปเมื่อมีการกล่าวถึง Spring Framework ครับ แต่ตัวของ framework ไม่ได้สร้างเพื่อ MVC เท่านั้น เสน่ห์ของมันอยู่ที่...
- Removes configuration / lookup code
- Developers can focus on the business needs
- Code can focus on testing
- Annotation or XML base development
ดังนั้นเรานำมันมาใช้กับ application ทั่วไปได้ด้วยนะเออ มันเวิร์กก็เพราะว่า (เน้นอีกครั้ง)
- Everything is a simple POJO
- Essentially a glorified HashMap
- Can be used as a Registry
เห็นไหม ยังไม่พูดถึง MVC เลย

ถาม : ไม่เคยใช้ framework อะไรมาก่อนเลย มีแต่พื้นฐานจาวาธรรมดา จะเรียนรู้ได้อย่างไรล่ะ?
ตอบ : งั้นตามผมมาสำหรับ part 2 เรามาจำลองการใช้จาวาธรรมดาแบบมี pattern กันก่อน