JSP Part V (JavaBean Example)

  โดย  ประดับเก่ง

 
Using JavaBean in JSP
หลังจากที่เรียนรู้การเขียน JavaBean สำหรับ JSP แล้ว เรามาดูตัวอย่างวิธีการใช้กัน
สมมุติว่าเราต้องการสร้างเพจขึ้นมาเพจหนึ่งซึ่งใช้สำหรับให้ user เลือกค่าของลูกเต๋าซึ่งอยู่ระหว่าง 1-6 โดยค่าที่เลือกจะถูกส่งไปที่ JavaBean ที่ชื่อ DiceBean ซึ่งถ้าค่าที่ user เลือกตรงกับค่าที่ DiceBean สุ่ม ก็ให้ทำการพิมพ์ output ออกมาบอกว่าถูกต้อง แต่ถ้าเลือกผิดก็ให้บอก user ให้เลือกอีกครั้งหนึ่ง  ไฟล์ที่เกี่ยวข้องก็อาจประกอบด้วย
1) guess.html เป็นไฟล์ HTML ใช้สำหรับเป็นตัว front end เพื่อให้ user ส่งค่าที่เลือกไปให้ DiceBean
2) dice.jsp เป็นไฟล์ที่ใช้สำหรับรับค่าที่ส่งมาจาก guess.html โดยไฟล์นี้จะทำการเรียก DiceBean อีกทีหนึ่ง
3) DiceBean.java เป็นไฟล์ที่ใช้เก็บ JavaBean ที่ชื่อ DiceBean ซึ่งเราจะกล่าวถึงเป็นอันดับแรก

DiceBean.java
package com.jarticles;

import java.util.Random;

public class DiceBean {
  private Random rand;
  private int inputNumber = -1;

  public DiceBean() {
    rand = new Random();
  }

  public void setInputNumber(int i) {
    inputNumber = i;
  }

  public int getInputNumber() {
    return inputNumber;
  }

  public int getResult() {
    if (inputNumber < 0 || inputNumber > 6) {
      return -1;
    }
    // return a number between 1-6
    return rand.nextInt(6)+1;
  }
}

อย่างที่เรากล่าวถึงในบทก่อนว่า เราสามารถบอก JSP Container ให้ทราบว่ามี property อะไรที่อยู่ใน Bean บ้างโดยการใช้ Setter และ Getter กับ property name ที่เราจะสร้างขึ้น. ถ้าดูจากโค๊ดในคลาส DiceBean เราจะเห็นว่าคลาสนี้มี Bean's properties อยู่สองตัวคือ inputNumber และ result เหตุผลคือ คลาส DiceBean มีฟังก์ชั่นที่ชื่อ setInputNumber(int) และ getInputNumber() ซึ่งก็คือ Setter และ Getter สำหรับ property ที่ชื่อ inputNumber นั่นเอง ส่วนอีกตัวหนึ่งคือ result โดยเราสร้างฟังก์ชั่นที่ชื่อ getResult() เป็นตัว Getter ให้
ข้อแตกต่างระหว่าง property สองตัวนี้คือ เราสามารถใช้ <jsp:setProperty> และ <jsp:getProperty> กับ inputNumber ได้ เพราะ property ดังกล่าวมีทั้งตัว Setter และ Getter แต่สำหรับ result แล้ว เราสามารถใช้ <jsp:getProperty> ทำการอ่านค่าของมันได้อย่างเดียว เพราะว่า property นี้มีแต่ตัว Getter เท่านั้น
ตัว Setter ของ inputNumber ไม่ได้ทำอะไรมากมาย เพียงแต่นำค่าที่ได้ไปเซ็ตให้อยู่ใน  instance  variable* ที่ชื่อ inputNumber เท่านั้น  โดยในทางกลับกัน ตัว Getter ของ inputNumber ก็เพียงแต่นำค่าที่เก็บอยู่ใน instance variable ที่ชื่อ inputNumber ออกมาให้เรา
* property และ instance variable ไม่จำเป็นต้องเป็นสิ่งเดียวกัน แต่โดยทั่วไปเรานิยมให้มี property ที่ชื่อเดียวกับ instance  variable สำหรับใช้ในการเซ็ตค่าและอ่านค่า instance variable นั้น 
มาดูในส่วนของ Getter ของ property ที่ชื่อ result  บ้าง

public int getResult() {
    if (inputNumber < 0 || inputNumber > 6) {
      return -1;
    }
    // return a number between 1-6
    return rand.nextInt(6)+1;
  }

จากโค๊ดเราจะเห็นว่าขั้นแรก getResult()จะทำการเช็คว่า inputNumber ที่เราใส่เข้าไปว่ามีค่าน้อยกว่า 0 หรือมากกว่า 6 หรือเปล่า (ลูกเต๋ามีค่าได้แค่ 1-6) โดยถ้าใช่ ค่าที่ได้จาก getResult() (หรือ property ที่ชื่อ result ) ก็จะเป็น -1 แต่ถ้าค่า inputNumber ที่มีอยู่ อยู่ในช่วง 1-6 เราก็จะเรียกฟังก์ชั่น nextInt(...) ซึ่งอยู่ในคลาส java.util.Random  ทำการสุ่มตัวอย่างระหว่าง 0-5 ขึ้นมา โดยถ้าเราต้องการให้ค่าออกมาเป็น 1-6 แบบลูกเต๋า เราจะต้องทำการ +1 เข้าไป
ค่าที่ได้จาก getResult()นี้จะเป็นค่าสมมุติที่ DiceBean นึกขึ้นมาเพื่อใช้ในการเทียบกับค่า inputNumber ที่ได้จากการเดาแต้มลูกเต๋าของ user จากไฟล์ guess.html ข้างล่าง

<HTML>
<HEAD>
<TITLE>Tell me what you think</TITLE>
</HEAD>
<BODY>
Guess 1-6 <br>
<form action="jsp/dice.jsp" method="post" name="guessForm">
<input type="text" name="inputNumber">
<input type="submit" name="Submit" VALUE="Guess">
</form>
</BODY>
</HTML>

ไฟล์ guess.html เป็น front end ที่ใช้สำหรับให้ user ใช้ติดต่อกับ DiceBean โดยเรียกไปที่ dice.jsp ซึ่งเป็นไฟล์ JSP ที่เราใช้เรียก DiceBean อีกทีหนึ่ง โดยหน้าตาของ guess.html ก็อาจจะเป็นดังนี้

รูปที่ 1.  guess.html

เราจะสังเกตเห็นว่า ในส่วนของ <form> tag ตัว action จะถูกเซ็ตให้ส่ง request ไปให้ไฟล์ที่ชื่อ "dice.jsp" โดยวิธีการ post (ที่เราสามารถส่ง parameters ต่าง ๆ ที่อยู่ใน <form> tag ไปให้ไฟล์ JSP ได้เพราะการส่ง request ไปให้ไฟล์ JSP ก็คือการส่ง request ไปให้ Servlet นั่นเอง)

อย่างที่กล่าวมาแล้วในส่วนของ <jsp:setProperty> ว่าเราสามารถทำการแมปค่าของ element ต่าง ๆ ที่อยู่ใน <form> tag เข้ากับ property ต่าง ๆ ที่อยู่ใน Bean ได้โดยใช้

<jsp:setProperty name="myBeanInstance" property="myProperty" param="myFormElementName"/>

ดังนั้น ถ้าเราต้องการเซ็ตค่าของ property ที่ชื่อ inputNumber โดยรับค่าจาก <form> tag  เราก็สามารถทำได้โดยใช้

<jsp:setProperty name="diceBean" property="inputNumber" param="myFormElementName"/>

โดย myFormElementName สามารถใช้ชื่ออะไรก็ได้ แต่ขอให้ตรงกับชื่อของ element ที่อยู่ใน <form> tag. อย่างไรก็ตามเพื่อให้ง่ายต่อการ debug  เราจึงตั้งชื่อ element เป็น inputNumber ดังที่ปรากฎอยู่ใน guess.html  ข้างต้น ซึ่ง <jsp:setProperty> ของเราก็จะกลายเป็น

<jsp:setProperty name="diceBean" property="inputNumber" param="inputNumber"/>

ไฟล์ต่อไปที่เราจะกล่าวถึงคือ dice.jsp ซึ่งเป็นตัวรับ request จาก guess.html

<!-- dice.jsp -->
<jsp:useBean id="diceBean" class="com.jarticles.DiceBean" scope="session"/>
<jsp:setProperty name="diceBean" property="inputNumber" param="inputNumber"/>
<% String inputStr = request.getParameter("inputNumber");
   int inputNumber = Integer.parseInt(inputStr);
   int result = diceBean.getResult();
   if (result == -1) { %>
    Only, number 1-6 you can pick man!!!<br>
<% } else if (inputNumber == result) { %>
      Number: <jsp:getProperty name="diceBean" property="inputNumber"/><br>
<%    out.print("Wow you're right!!! Like it huh?</br>");
   } else {
      out.print("Sorry, I like " + result + " but you picked " + inputNumber + ".<br>");
   } %>
Guess 1-6 <br>
<form method="post" name="guessForm">
<input type="text" name="inputNumber">
<input type="submit" name="Submit" value="Guess">
</form>

หลังจากที่ได้รับ request มาจากไฟล์ guess.html, ไฟล์ dice.jsp จะทำการสร้าง instance ของคลาส DiceBean ที่ชื่อ diceBean โดยใช้ <jsp:useBean> ซึ่งในกรณีของเรา คลาส DiceBean อยู่ใน package ที่ชื่อ "com.jarticles" ดังนั้นในการอ้างถึงคลาสนี้ เราจึงใช้ class="com.jarticles.DiceBean". ในกรณีที่ user ส่ง request มาที่ไฟล์นี้หลายครั้ง เราอาจทำการเก็บ instance ของ DiceBean ไว้ใน HttpSession เพื่อที่ instance ดังกล่าวสามารถถูกนำมาใช้ได้ใหม่ โดยไม่ต้องทำการสร้างขึ้นอีกในทุก ๆ ครั้งที่ Bean นี้ถูกเรียกใช้ โดยการเซ็ต scope ของ Bean เท่ากับ session.
จากนั้น property ที่ชื่อ inputNumber จะถูกเซ็ตค่า โดยใช้ <jsp:setProperty> ซึ่ง JSP Container จะนำค่า input ของ user ที่ได้จาก form element ที่ชื่อ inputNumber จากไฟล์ guess.html ใส่เข้าไปโดยอัตโนมัติ. เราจะเห็นว่าค่าของ inputNumber จาก form element ยังสามารถเรียกดูได้ โดยผ่านคำสั่ง getParameter(...) ของ ServletRequest อีกด้วย.
เพราะว่า DiceBean ก็คือ java class ดังนั้นนอกจากเราจะติดต่อกับ DiceBean โดยผ่านทาง <jsp:getProperty> หรือ <jsp:getProperty> แล้ว เรายังสามารถทำได้ในส่วนของ scriptlet (<% ...%>) ดัง code snippet ข้างล่าง
...
<% String inputStr = request.getParameter("inputNumber");
   int inputNumber = Integer.parseInt(inputStr);
   int result = diceBean.getResult();
   if (result == -1) { %>
...

ท้ายสุดเรานำค่าของ inputNumber ที่ user เลือกมาเทียบกับค่าของ result ที่ได้จาก DiceBean.getResult() ซึ่งจะได้ผลเป็นสามแบบคือ

รูปที่ 2. ผลที่ได้จาก dice.jsp เมื่อ user เลือกค่าของลูกเต๋าน้อยกว่า 0 หรือมากกว่า 7

รูปที่ 3. ผลที่ได้จาก dice.jsp เมื่อ user เลือกค่าของลูกเต๋าได้ตรงกับค่าที่ DiceBean สร้างขึ้นมา

รูปที่ 4. ผลที่ได้จาก dice.jsp เมื่อ user เลือกค่าของลูกเต๋าไม่ตรงกับค่าที่ DiceBean เลือก

จะสังเกตเห็นว่าไม่ว่าผลจะออกมาเป็นเช่นไร ส่วนของ <form> ที่คล้ายกับที่ปรากฏอยู่ใน guess.html จะถูกใส่ไว้ข้างล่างสุดของผลที่ได้จาก "dice.jsp" เพื่อให้ user ทายค่าลูกเต๋าครั้งต่อไปเสมอ.
Note: <form> ที่อยู่ใน "dice.jsp" จะไม่มีส่วนที่เป็น action ซึ่งในกรณีนี้การส่ง request ครั้งต่อไปจะถูกส่งไปที่ไฟล์ JSP เดิมที่เป็นตัวสร้าง output นี้มาให้ ซึ่งก็คือ "dice.jsp" นั่นเอง

การติดตั้ง
ตัวอย่างของเรา ประกอบด้วย 3 ไฟล์ด้วยกันคือ guess.html, dice.jsp และ DiceBean.java.
ขั้นแรกให้ทำการใส่ไฟล์ guess.html ไว้ที่ root ของ web application  (ดู Part I) หลังจากนั้นใส่ไฟล์ dice.jsp ไว้ที่ subdirectory ที่ชื่อ jsp ซึ่งเป็น directory ถัดลงมาจาก root ของ web application  นั้น.  โดยทั่วไปจาว่าคลาสต่าง ๆ จะถูกใส่ไว้ที่ไดเรคทรอรี่ /WEB-INF/classes/ ซึ่งในกรณีของเราคลาส DiceBean อยู่ใน package ที่ชื่อ com.jarticles ดังนั้น เราจะต้องสร้าง subdirectory ขึ้นมาเพื่อแสดงถึงโครงสร้างของ package ที่ DiceBean นี้ถูกจัดอยู่ ดังนั้นไฟล์ DiceBean.java ก็จะอยู่ที่ /WEB-INF/classes/com/jarticles/DiceBean.java. เสร็จแล้วให้ทำการ compile ไฟล์นี้เหมือนจาว่าไฟล์ปกติ

การรัน
start Tomcat แล้วเปิด browser โดย connect ไปที่ http://127.0.0.1:8080/(your context)/guess.html  ในกรณีที่รัน Tomcat ที่เครื่องเดียวกับ browser โดย (your context) คือ Context Path ของ web application ที่เราติดตั้งไฟล์ guess.html เข้าไป


Copyright (C) 2000 www.jarticles.com.