JSP Part IV (Actions)

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

 
  XML Syntax
ในปัจจุบันนี้ XML (Extensible Markup Language)  ได้กลายเป็นส่วนหนึ่งของมาตรฐานที่ใช้กันอย่างกว้างขวางในวงการ* web application เพื่อทำหน้าที่เป็นเอกสารที่ใช้ในการสื่อสารระหว่างจุดหนึ่งไปยังอีกจุดหนึ่ง รวมไปถึงประโยชน์ทั่ว ๆ  ในการเป็นตัวกลางในการเก็บข้อมูล ก่อนที่ข้อมูลเหล่านั้นจะถูกเปลี่ยนแปลงไป โดย appliction ที่ทำการประมวลผลข้อมูลเหล่านั้น 
เพื่อที่จะสนันสนุนและสามารถทำงานร่วมกับระบบที่มี XML เข้ามาเกี่ยวข้องได้อย่างมีประสิทธิภาพ, Syntax ต่าง ๆ ใน JSP จึงถูกออกแบบ ให้สามารถเขียนอยู่ในรูปของ XML format ได้   โดยเฉพาะอย่างยิ่งในส่วนของ JSP Actions 
* XML  ถูกนำไปใช้ประโยชน์ในหลาย ๆ วงการ แต่เรากล่าวถึงเฉพาะที่ใช้สำหรับ web application เท่านั้น

โดยทั่วไป Tag ต่าง ๆ ที่อยู่ในรูปของ XML syntax จะต้องมีลักษณะของการเปิดและปิดของ Tag ยกตัวอย่างเช่น

<mytag attr1="attribute value" ...>
body
</mytag>

ถ้าเป็น Tag ที่ไม่มี body, ตัวของ Tag จะต้องถูกปิดโดยตัวของมันเอง โดยใช้ชื่อของ Tag นั้น ๆ ปิด หรือใส่ / ไว้ที่ท้ายสุดของตัว Tag ยกตัวอย่างเช่น

<mytag attr1="attribute value"></mytag>
<mytag attr1="attribute value" .../>

จะสังเกตเห็นว่า การเขียน Tag ต่าง ๆ ในรูปแบบของ XML จะต้องการระเบียบแบบแผนมากกว่าการเขียน Tag เดียวกันในรูปแบบของ HTML ยกตัวอย่างเช่น
HTML:
<img src="http://www.jarticles.com/images/jar.gif"> ไม่ต้องมี </img> ปิดท้าย แต่

XML:
<img src="http://www.jarticles.com/images/jar.gif"></img> หรือ
<img src="http://www.jarticles.com/images/jar.gif"/>

case sensitive ก็เป็นส่วนหนึ่งของข้อบังคับในการเขียน XML  ยกตัวอย่างเช่น
HTML:
<head><title>My messy html code</TITLE><Head>
ไม่สนใจว่า case จะเป็นอย่างไร

XML:
<head><title>My clean xml code<title><head> 
<HEAD><TITLE>My clean xml code<TITLE><HEAD> 
<head><TITLE>My clean xml code<TITLE><head> 
<HEAD><title>My clean xml code<title><HEAD>
จะเขียนอย่างไรก็ได้ แต่ Tag แต่ละตัว จะต้องมี case ที่เหมือนกัน

ยังมีรายละเอียดอีกหลายอย่างที่ควรรู้สำหรับผู้ที่สนใจการเขียน XML แต่ส่วนที่กล่าวถึงข้างต้นก็เพียงพอสำหรับที่เราจะใช้ในการเขียน JSP Actions แล้ว (สำหรับผู้ที่สนใจเกี่ยวกับ XML ผู้เขียนอยากให้เริ่มเรียนรู้จาก http://www.webmonkey.com)

JSP Actions
JSP Actions สามารถใช้ในการควบคุมและเปลี่ยนแปลงการทำงานของไฟล์ JSP ที่เราเขียน ซึ่งอาจจะเป็นในลักษณะของ
1) insert ไฟล์ต่าง ๆ เข้ามาเป็นส่วนหนึ่งของไฟล์ JSP ปัจจุบัน โดยใช้ <jsp:include page="exfile.jsp" .../> tag 
2) ใช้สำหรับควบคุมการทำงานของ JavaBean ที่เป็นส่วนประกอบหนึ่งของไฟล์ JSP นั้น โดยใช้ <jsp:useBean .../>, <jsp:setProperty .../>, <jsp:getProperty .../> tag
3) ใช้ในการส่งผ่าน (forward) request ของ client ไปยังไฟล์ JSP อื่น ๆ โดยใช้  <jsp:forward .../> tag 
4) ใช้ <jsp:plugin type="... /> tag เพื่อทำการสร้าง OBJECT หรือ EMBED code ที่ใช้สำหรับเรียก(หรือโหลด) Java plugin เพื่อทำการรัน Applet  หรือ JavaBean  ในตัว browser  ที่กำลังเปิดไฟล์ JSP ดังกล่าวอยู่

jsp:include action
อย่างที่กล่าวมาข้างต้น action นี้ ถูกใช้สำหรับ insert ไฟล์ต่าง ๆ เข้ามาที่ไฟล์ JSP ปัจจุบัน  โดยใช้

<jsp:include page="relativeURL" flush="true"/>

relativeURL คือ ที่อยู่ของไฟล์ที่เราจะทำการ insert ซึ่งจะต้องอยู่ในรูปของ relative URL กับไฟล์ JSP ปัจจุบัน
flush คือ ตัวที่บอก JSP Container ให้ทำการ flush สิ่งต่าง ๆ ที่อยู่ใน buffer ของ page output ออกไปที่ outputStream ก่อนที่จะทำการ insert ไฟล์นี้เข้าไป โดยใช้ค่า flush="true"
Note: ค่า flush="true" เป็นค่าบังคับสำหรับ <jsp:include .../> เราไม่สามารถใช้ค่า flush="false" ได้ใน JSP 1.1

หลาย ๆ คนอาจสงสัยว่า ข้อแตกต่างระหว่าง <%@ include file="relativeURL" %> (Part II)  กับ  <jsp:include page="relativeURL"/>คืออะไร?  สำหรับ  <%@ include ...%>  ไฟล์ relativeURL จะถูกใส่เข้าไปเป็นส่วนหนึ่งของไฟล์ JSP ที่มี include directive นี้อยู่ ในช่วงของการแปลงไฟล์ JSP ให้กลายเป็น servlet ข้อดีก็คือจะเร็ว แต่ข้อเสียคือไฟล์ relativeURL ที่ถูก insert เข้าไปอาจจะไม่อัพเดท ซึ่งจะเกิดขึ้นในกรณีที่ไฟล์ relativeURL ดังกล่าวถูกเปลี่ยนแปลงไป แต่เกิดขึ้นหลังจากที่ไฟล์ JSP ที่บรรจุไฟล์ relativeURL นี้อยู่ถูกแปลงเป็น servlet แล้ว
แต่ในลักษณะของ <jsp:include .../> ตัว JSP Container จะทำการ insert ไฟล์ relativeURL นี้เข้าไปในไฟล์ JSP ทุก ๆ ครั้ง ที่ไฟล์ JSP ดังกล่าวถูก  request โดย client ซึ่งข้อดีก็คือ เราจะได้ไฟล์ relativeURL ที่เป็นเวอร์ชั่นอัพเดทอยู่เสมอ แต่ข้อเสียคือ จะเสียเวลาในการโหลดและ insert ไฟล์ relativeURL นี้เข้ามาอยู่ด้วยทุกครั้ง

ประโยชน์ของ <jsp:include .../> ที่ใช้กันโดยทั่วไป ก็เช่นการโหลดหรือซ่อนส่วนใดส่วนหนึ่งของเพจ โดยใช้ attribute ของ user ที่ล๊อกอินเข้ามาในระบบเป็นตัวตัดสิน ยกตัวอย่างเช่น

<HTML>
<HEAD>
...
<% 
int userRole = userInfo.getUserRoleFromDB();
if (userRole == UserType.ADMIN) {
%>
  <jsp:include page="jsp/AdminMenu.jsp" flush="true"/>
<%
} else {
%>
  <jsp:include page="template/UserMenu.html" flush="true"/>
<%
}
%>
...
</BODY>
</HTML>

JavaBean
ในการเขียน JSP สำหรับระบบใหญ่ ๆ  นักพัฒนาจะไม่นิยมใส่ java code ลงไปในไฟล์ JSP มากนัก สิ่งที่อยู่ในไฟล์มักจะเป็นเพียง HTML code และค่าของ variables ต่าง ๆ ที่ได้มาจาก JavaBeans เท่านั้น. ข้อดีของการใช้ JavaBean คือการง่ายต่อการเปลี่ยนแปลงลักษณะของ look-and-feel ของไฟล์ JSP ที่เป็นเช่นนี้เพราะ ส่วนที่เป็น data (variables) กับส่วนที่เป็น presentation (HTML) จะอยู่ด้วยกันอย่างหลวม ๆ ดังนี้เราจึงสามารถเปลี่ยนตัว presentation เมื่อไหร่ก็ได้ โดยตัว JavaBean ที่ใช้เก็บค่าของ variables ต่าง ๆ ยังคงเหมือนเดิม 

สำหรับคนที่ไม่คุ้นกับ JavaBean ให้นึกถึง JavaBean เป็นลักษณะของกล่อง โดยกล่องนี้มีส่วนที่ใช้ติดต่อกับโลกภายนอกอยู่สองส่วนหลัก ๆ คือ 

1. ส่วนที่ใช้สำหรับรับข้อมูลต่าง ๆ โดยข้อมูลเหล่านี้จะถูกใช้เป็นตัวแปรในการควบคุมหรือเปลี่ยนแปลงคุณสมบัติและการทำงานของกล่อง (Setter)
2. ส่วนที่ใช้สำหรับอ่านคุณสมบัติของกล่อง (Getter) ซึ่งโดยส่วนมาก(แต่ไม่ทั้งหมด) ก็คือค่าของตัวแปรต่าง ๆ ที่บรรจุอยู่ในกล่อง

ในการใช้งานกล่อง (JavaBean) ดังกล่าวร่วมกับ JSP เราสามารถที่จะสร้างกล่องขึ้นมาโดยใช้ <jsp:useBean .../>, ส่งค่าเข้าไปในกล่องโดยใช้ <jsp:setProperty .../> และอ่านค่าต่าง ๆ ที่อยู่ในกล่อง โดยใช้ <jsp:getProperty .../> tag แต่ก่อนที่เราจะเรียนรู้ถึงการใช้ tag เหล่านี้ เรามาพูดถึง JavaBean ในรายละเอียดอีกซักเล็กน้อยเสียก่อน

Bean Conventions
สำหรับคนที่เคยเขียน application ที่เกี่ยวกับ JavaServlet หรือ RMI จะพบว่า แต่ละคลาสที่เราเขียนขึ้น อาจจะต้องมีการ extend คลาสใดคลาสหนึ่งก่อน เช่น HttpServlet (ในกรณีของการเขียน JavaServlet) หรืออาจต้องทำการ implement interface ต่าง ๆ เช่น Serializable (ในกรณีของการเขียน RMI) แต่สำหรับการเขียนคลาสให้กลายเป็น JavaBean แล้ว เราไม่จำเป็นต้องทำสิ่งต่าง ๆ ที่กล่าวมาข้างต้นเลย. JavaBean จริงๆ แล้วก็คือ จาว่าคลาสธรรมดา ๆ แต่ถูกเขียนขึ้นโดยใช้ naming และ design conventions ที่อยู่ใน JavaBean Specification เท่านั้น.  Conventions หลัก ๆ ที่เราจะพูดสำหรับการเขียน JavaBean เพื่อใช้ใน JSP มีดังต่อไปนี้คือ

1) The Bean Constructor
ในการเขียน Bean* ให้สามารถใช้ได้กับ <jsp:useBean .../> สิ่งหนึ่งที่ Bean ของเราจะต้องมีคือ ตัว constructor ที่ไม่ต้องการ  argument สำหรับการ initialize  ของ Bean ยกตัวอย่างเช่น
* JavaBean และ Bean ในที่นี้จะหมายถึงสิ่งเดียวกัน

public class UselessBean { }

หรือ

public class AnotherUselessBean {
  public AnotherUselessBean() { }
}

หรือ

public class TimeBean {
  private int hours;
  private int minutes;

  public TimeBean() {
    java.util.Date rightNow = new java.util.Date();
    hours = rightNow.getHours();
    minutes = rightNow.getMinutes();
  }
}

คลาสทั้งสาม UselessBean, AnotherUselessBean และ TimeBean เขียนถูกต้องตาม Bean Convention ทุกอย่าง คือมี constructor ที่ไม่ต้องการ argument สำหรับการ initialize ดังนั้นเราสามารถเรียกคลาสทั้งสามว่า JavaBean*. 
* เราสามารถนำคลาสเหล่านี้ไปใช้กับ <jsp:useBean ... /> ได้ อย่างไรก็ตามคลาสทั้งสามนี้ยังไม่มีประโยชน์อะไรสำหรับไฟล์ JSP จริง ๆ  ประโยชน์ที่เราจะได้จาก Bean ก็คือการส่งค่าต่าง ๆ เพื่อทำการควบคุมและเปลี่ยนแปลงคุณสมบัติของ Bean รวมไปถึงการอ่านค่าคุณสมบัติต่าง ๆ ของ Bean ซึ่งสิ่งเหล่านี้จะเกิดขึ้นได้โดยอาศัยสิ่งหนึ่งที่เรียกว่า Bean's Properties

2) Bean's Properties
Bean's Properties คือตัวที่บอกว่า เราสามารถทำอะไรกับ JavaBean นั้นได้บ้าง [โดยส่วนมาก(แต่ไม่ทั้งหมด) ก็คือการเปลี่ยนและอ่านค่าต่าง ๆ ของ instance variables  ที่บรรจุอยู่ข้างใน Bean นั้น ๆ] ซึ่งผลที่ได้ก็คือ การควบคุมและเปลี่ยนแปลงคุณสมบัติต่าง ๆ ของ Bean อย่างไรก็ตามบางที  properties ที่เรากำหนดขึ้น อาจจะไม่ได้ทำอะไรที่เกี่ยวข้องกับ instance variables ที่อยู่ข้างใน Bean นั้นเลย 

JSP Container จะสามารถทราบว่า JavaBean ของเรามี properties อะไรบ้าง ได้จากวิธีการที่เรียกว่า introspection หลักการก็คือ JSP Container จะทำการวิเคราะห์ฟังก์ชั่นที่เป็น  public  ของ Bean นั้น ซึ่งจะต้องเขียนขึ้นอย่างถูกต้องตามหลักของ JavaBean API โดยจะถือว่า property ใด ๆ ก็ตามจะเกิดขึ้นได้ก็ต่อเมื่อ Bean คลาสนั้นมี 

1. public ฟังก์ชั่นที่ใช้สำหรับควบคุมหรือเปลี่ยนแปลงค่าของ property นั้น (Setter) หรือ
2. public ฟังก์ชั่นที่ใช้สำหรับอ่านค่าของ property นั้น (Getter) หรือ
3. มีทั้งสองฟังก์ชั่นข้างต้น
พูดง่าย ๆ ก็คือ ในการกำหนด property ขึ้นมาอันหนึ่ง เราจะต้องสร้าง public ฟังก์ชั่นที่ขึ้นต้นด้วยคำว่า set (Setter) ซึ่งใช้สำหรับควบคุมหรือเปลี่ยนแปลงค่าของ property นั้น และหรือ public ฟังก์ชั่นที่ขึ้นต้นด้วยคำว่า get (Getter) ซึ่งใช้สำหรับอ่านค่าของ property นั้น  โดยรูปแบบโดยทั่วไปก็คือ

public void setPropertyName(PropertyType value);
public PropertyType getPropertyName();

ยกตัวอย่างเช่น ถ้าเราต้องการกำหนด property ที่ชื่อ hours ซึ่งมีค่าเป็นแบบ int โดยที่เราสามารถเปลี่ยนค่าและอ่านค่าของ hours ได้ ฟังก์ชั่นที่เราจะต้องสร้างขึ้นเพื่อบอกให้ Container ทราบว่ามี property นี้อยู่ใน Bean ก็คือ

public void setHours(int hour);
public int getHours();

หรือ ถ้าเราต้องการกำหนด property ที่ชื่อ firstName ซึ่งมีค่าเป็นค่าแบบ String เราก็สามารถบอก Container ให้ทราบว่ามี property นี้อยู่ใน JavaBean ได้โดยใช้

public void setFirstName(String firstName);
public String getFirstName();

ย้อนกลับมาที่ TimeBean โดยเพิ่มส่วนที่เป็น Setter และ Getter เข้าไป เราจะได้

public class TimeBean {
  private int hours;
  private int minutes;

  public TimeBean() {
    java.util.Date rightNow = new java.util.Date();
    hours = rightNow.getHours();
    minutes = rightNow.getMinutes();
  }

  public int getHours() {
    return hours;
  }

  public void setHours(int hours) {
    this.hours = hours;
  }

  public int getMinutes() {
    return minutes;
  }
}

Note: จะสังเกตว่า property ที่ชื่อ minutes  จะไม่มี Setter  แต่อย่างที่กล่าวมาข้างต้นก็คือ เราสามารถบอก Container ให้ทราบว่า JavaBean ของเรามี properties อะไรบ้างโดยการสร้าง public ฟังก์ชั่นที่เป็น Setter หรือ Getter หรือ สร้างทั้ง Setter และ Getter ก็ได้
ใน JSP ไฟล์ เราสามารถเรียกใช้ TimeBean ได้ดังตัวอย่างข้างล่าง (จะกล่าวถึงรายละเอียดต่อไป)

<jsp:useBean id="time" class="TimeBean" scope="request"/>
<HTML>
<BODY>
Time is <jsp:getProperty name="time" property="hours"/>
with minutes = <jsp:getProperty name="time" property="minutes"/>
...

ในการเขียน JavaBean เพื่อกำหนด properties ต่าง ๆ หลายคนมักเข้าใจผิดคิดว่า properties ก็คือ instance variables.  ในตัวอย่างของ TimeBean จะเห็นว่า property ที่ชื่อ hours และ minutes จะเกี่ยวข้องกับ instance variable ที่ชื่อ hours และ minutes แต่อย่างไรก็ตาม เราสามารถกำหนด properties ต่าง ๆ ขึ้นมา โดยไม่เกี่ยวข้องกับ instance variable ใด ๆ เลยก็ได้ ยกตัวอย่างเช่น

public class RandomBean {
  private java.util.Radom rand;

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

  public int getRandomNumber() {
    // return a number between 0-10
    return rand.nextInt(10);
  }

  public int getRandomDice() {
    // return a number bewteen 1-6
    return rand.nextInt(6) +1;
  }
}

จากตัวอย่าง จะเห็นว่า property ที่ชื่อ randomNumber และ randomDice ไม่ได้เกี่ยวข้องกับ instance variables ใด ๆ ทั้งสิ้น ค่าต่าง ๆ ของ properties เหล่านี้ถูกสร้างขึ้นโดยใช้คลาส  java.util.Random. 
สำหรับการใช้ RandomBean ในไฟล์ JSP ก็อาจเป็นดังตัวอย่างข้างล่าง

<jsp:useBean id="random" class="RandomBean" scope="session"/>
<HTML>
<BODY>
Our random number is <jsp:getProperty name="random" property="ramdomNumber"/>
Random number by dice is <jsp:getProperty name="random" property="randomDice"/>
...

Property Name Conventions
โดยทั่วไป การเขียนชื่อของ properties ต่าง ๆ จะเป็นในลักษณะของลูกผสมคือ มีทั้งตัวใหญ่และตัวเล็ก ซึ่งจะขึ้นต้นด้วยตัวเล็กในคำแรกและจะตามด้วยตัวใหญ่ในคำถัด ๆ มา ยกตัวอย่างเช่น firstName, lastName, randomNumber, timeInHour เป็นต้น สำหรับตัว setter และ getter ของ properties ดังกล่าวก็จะเป็น setFirstName, setLastName, setRandomNumber, setTimeInHour และ getFirstName, getLastName, getRandomNumber, getTimeInHour ตามลำดับ. 
เราจะสังเกตเห็นว่า ชื่อของ properties และตัว setter, getter ของ properties เหล่านั้นจะต่างกันที่ตัวแรก หลักจากคำว่า set  หรือ get เท่านั้น  ในการตีความ setter, getter เพื่อหา properties ต่าง ๆ ของ JavaBean โดย JSP Container, JSP Container  จะทำการแปลง case ต่าง ๆ ให้แมชกับชื่อของ properties ที่อยู่ใน <jsp:getProperties .../>, <jsp:setProperty .../> โดยอัตโนมัติ
(สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ JavaBean สามารถหาอ่านได้จาก http://java.sun.com/beans/

 Loading a Bean - <jsp:useBean>
ก่อนที่เราจะสามารถใช้ JavaBean ใน JSP ได้ สิ่งแรกที่เราต้องทำคือ การโหลด instance ของ Bean
เราสามารถโหลด instance ของ Bean เข้ามาในระบบได้โดยใช้ <jsp:useBean .../> โดยเราจะต้อง

1. กำหนดชื่อที่จะใช้ในการอ้างถึง instance ของ Bean นี้  (id)
2. กำหนดคลาสของ Bean ที่จะโหลด  (class)
3. ทำการเซ็ต scope (หรือช่วงชีวิต) ของ Bean ว่าจะยาวนานแค่ไหน  (scope)
ดังรูปแบบข้างล่าง

<jsp:useBean id="myBeanInstance" class="com.myPackage.BeanClass" scope="page|request|session|application">
...body...
</jsp:useBean>

เพราะว่า <jsp:useBean> เขียนในรูปแบบของ XML ดังนั้นจึงต้องมีตัวปิด tag </jsp:useBean> 
จากตัวอย่างจะเห็นว่าใน <jsp:useBean> จะมีส่วนที่เป็น ...body... อยู่ โดยส่วนนี้จะถูกเรียกเพียงครั้งเดียวในช่วงที่ instance ของ Bean  ถูกโหลด ในกรณีที่ไม่มี ...body... เราสามารถเขียน <jsp:useBean> ให้อยู่ในรูปของ Empty tag ได้ โดยใช้

<jsp:useBean id="myBeanInstance" class="com.myPackage.BeanClass" scope="page|request|session|application"/>

สมมุติว่า TimeBean อยู่ใน package ที่ชื่อ com.jarticles.utils.TimeBean โดยเราต้องการอ้างถึง Bean นี้โดยใช้ instance ที่ชื่อ time และกำหนดช่วงชีวิตให้อยู่แค่ในแต่ละ request ของ client เราสามารถโหลด TimeBean นี้ได้โดยใช้

<jsp:useBean id="time" class="com.jarticles.utils.TimeBean" scope="request">
...body...
</jsp:useBean> 

หรือ 

<jsp:useBean id="time" class="com.jarticles.utils.TimeBean" scope="request"/>

บางครั้ง <jsp:useBean> อาจจะไม่ทำการโหลด new instance ของ Bean ขึ้นมา ถ้าหากว่า instance ดังกล่าวถูกโหลดขึ้นมาก่อนแล้ว โดยบรรทัดฐานของการโหลด Bean จะขึ้นอยู่กับ scope ที่เซ็ตไว้ให้กับ instance ของ Bean นั้น 

Initializing a Bean - <jsp:setProperty>
ใน Bean Conventions เรากล่าวถึง Bean Constructor ที่ไม่ต้องการ arguments ซึ่งถูกใช้สำหรับ <jsp:useBean> อย่างไรก็ตามบางครั้ง Bean ที่เราใช้อาจต้องการค่าเริ่มต้นในการ initialize ซึ่งเราสามารถทำการเซ็ตค่าต่าง ๆ ให้  Bean ได้โดยใช้ <jsp:setProperty .../>
ค่าที่เราจะเซ็ตให้  Bean บางครั้งอาจมาจากค่าที่เรากำหนดขึ้น หรืออาจจะเป็นค่าที่ได้จาก request ของ client ซึ่งมาจาก element ต่าง ๆ ใน <FORM> tag ของ html ดังนั้นการเซ็ตค่า Bean จึงถูกแบ่งออกเป็นสองแบบคือ
1. การเซ็ตค่าให้ Bean โดยใช้ค่าที่เรากำหนดขึ้น  เช่น

<jsp:useBean id="myBeanInstance" class="com.myPackage.BeanClass" scope="request">
  <jsp:setProperty name="myBeanInstance" property="myProperty" value="definedValue"/>
</jsp:useBean>

name คือ ชื่อของ Bean instance ที่เราต้องการอ้างถึง
property คือ ชื่อของ property ที่เราต้องการเซ็ตค่า
value คือ ค่าที่เราจะใส่เข้าไปให้ property นั้น

2. การเซ็ตค่าให้ Bean โดยใช้ค่าที่ได้จาก element ต่าง ๆ ของ <FORM> tag เช่น

<jsp:useBean id="myBeanInstance" class="com.myPackage.BeanClass" scope="request">
  <jsp:setProperty name="myBeanInstance" property="myProperty" param="myFormElementName"/>
</jsp:useBean>

param คือ ชื่อของ element ที่อยู่ใน <FORM> tag ที่ส่ง request มาที่ไฟล์ JSP ที่มี <jsp:useBean> นี้อยู่

Note: เราไม่สามารถใช้ value และ param พร้อมกันได้ เพราะ JSP Container  จะไม่ทราบว่าเราจะใช้ค่าไหนในการเซ็ตให้ Bean 
ในกรณีที่ค่าทุกค่าใน  Bean ขึ้นอยู่กับ ค่าของ element ต่าง ๆ ใน <FORM > tag เราสามารถบอกให้ JSP Container แมปค่าของ element เข้ากับ ค่า property ต่าง ๆ  ของ Bean ได้โดยอัตโนมัติ โดยการใช้ property="*" ดังตัวอย่างข้างล่าง

<jsp:useBean id="myBeanInstance" class="com.myPackage.BeanClass" scope="request">
  <jsp:setProperty name="myBeanInstance" property="*"/>
</jsp:useBean>

เพิ่มเติมอีกนิดหนึ่งคือ <jsp:setProperty> ไม่จำเป็นจะต้องอยู่ใน <jsp:useBean>... </jsp:useBean> เสมอไป เราสามารถเรียกใช้ tag นี้เมื่อไหร่ก็ได้ ที่เราต้องการเปลี่ยนหรือเซ็ตค่าของ property ของ Bean

Displaying  Dynamic Content - <jsp:getProperty>
หลังจากที่เราทำการโหลด และเซ็ตค่าของ property ต่าง ๆ ใน Bean แล้ว เราสามารถดูผลที่เกิดขึ้นได้ โดยใช้

<jsp:getProperty name="myBeanInstance" property="myProperty"/>

ค่าที่ได้จาก <jsp:getProperty> อาจจะเป็นค่าของ instance variables ของ Bean ที่เปลี่ยนไปหลังจากที่เราใช้ <jsp:setProperty> หรือบางครั้ง อาจจะเป็นลิสของตารางรายชื่อ ในกรณีที่ค่า property ที่เราเซ็ตผ่าน <jsp:setProperty> เป็นตัว trigger ให้ Bean  ส่ง query ไปที่เดต้าเบส เป็นต้น

The scope Attribute 
โดยทั่วไปในการสร้าง instance ของ Bean แต่ละตัว เราจะต้องกำหนดว่าช่วงชีวิตของ instance นั้นจะยาวนานแค่ไหน. scope เป็นตัวที่ถูกใช้ในการกำหนดช่วงชีวิตของ instance เหล่านั้น โดยเราสามารถเซ็ต scope ได้เป็นสี่แบบคือ
 

Scope in JSP
  page Object is accessible only by a single client from the page on which it is created.
  request Object is accessible by a single client for the lifetime of a single client request.
  session Object is accessible by a client from anywhere in the application for the lifetime of an entire user session.
  application Object is accessible by any client from any page within the application for the lifetime of the application.

Instance ของ Bean ที่ถูกเซ็ต scope="page" จะมีช่วงชีวิตอยู่ตั้งแต่ JSP page ที่มี instance ดังกล่าวอยู่ทำการประมวลผล ไปจนถึงระยะเวลาที่เพจดังกล่าวเสร็จสิ้นการประมวลผลแล้ว.  ถ้า scope ถูกเซ็ตเท่ากับ request, instance ของ Bean จะมีช่วงชีวิตอยู่ตั้งแต่ request ของ client ถูกส่งมาถึง JSP Container จนถึงช่วงที่ client ได้รับ page output ทั้งหมดกลับไปแล้ว (ซึ่งส่งกลับไปโดย ServletResponse).  ข้อแตกต่างระหว่างสอง scope นี้คือ ในหนึ่ง HttpRequest อาจจะมีการเกี่ยวข้องกับ JSP page หลาย ๆ เพจ ยกตัวอย่างเช่น การใช้ include directive เพื่อประกอบ JSP page  หลาย ๆ เพจเข้าด้วยกัน หรือแม้กระทั่งการใช้ <jsp:forward> ซึ่งจะทำการส่ง ServletRequest จาก JSP page หนึ่งไปยังอีกเพจหนึ่ง ดังนั้นเราอาจพูดได้ว่า ในหนึ่ง scope ของ request(ServletRequest) จะประกอบด้วยหลาย ๆ scope ที่เป็น page(javax.servlet.jsp.PageContext)

ในกรณีของ scope="session", instance ของ Bean จะมีช่วงชีวิตยาวนานเท่ากับ HttpSession ของ client นั้น ๆ ซึ่งก็คือ ตั้งแต่ client เริ่มทำการติดต่อกับ server ที่มี JSP เพจดังกล่าวอยู่ จนถึงเวลาที่ client นั้นหายไป ซึ่งอาจเกิดขึ้นจากการปิด browser หรือการขาดการติดต่อกับ  server เป็นเวลานาน ๆ (timeout). scope แบบสุดท้ายก็คือ application (ServletContext) ซึ่งจะยาวนานตั้งแต่ instance ของ Bean นั้นถูกสร้างขึ้นจนถึงระยะเวลาที่ server ที่มี Bean นั้นอยู่ถูก shutdown หรือ restart.

ในส่วนของ <jsp:useBean> แล้ว scope จะเป็นตัวกำหนดว่า JSP Container จะต้องทำการโหลด instance ของ Bean ขึ้นมาใหม่หรือไม่ ยกตัวอย่างเช่น ถ้า instance ของ Bean ถูกเซ็ต scope ให้เป็น request, JSP Container จะทำการสร้าง Bean instance ขึ้นมาใหม่ ในทุกครั้งที่มี request ใหม่ถูกส่งมาจาก client โดยหลังจากที่ request ดังกล่าวเสร็จสิ้นลง Bean instance ที่ถูกสร้างขึ้นโดย request นั้นจะถูกทำลาย โดย JSP Container จะทำการสร้างขึ้นมาใหม่อีกครั้ง สำหรับ request อันถัดไป
ในกรณีของ Bean instance ที่ถูกเซ็ต scope ให้เป็น session, JSP Container  จะทำการสร้าง instance ดังกล่าวขึ้นในครั้งแรกที่ instance นั้นถูกเรียกใช้เท่านั้น ถ้า instance นี้ถูกเรียกใช้อีกในอนาตค, JSP Container จะไม่ทำการสร้าง Bean instance ขึ้นมาอีก แต่จะทำการโหลด instance ที่สร้างขึ้นไว้แล้วมาใช้แทน application อันหนึ่งที่ใช้ประโยชนจาก Bean instance ที่มี scope="session" ก็คือ shopping cart ซึ่ง Bean instace นี้จะถูกใช้เป็นตัวเก็บรายชื่อสินค้าที่ client  ทำการเลือกไว้

<jsp:forward> Action
Action นี้อนุญาติให้เราส่งผ่าน (forward) ตัว request ของ client จาก JSP page ปัจจุบันไปยังเพจอื่น ๆ ซึ่งอาจจะเป็น JSP หรือ Servlet (ที่อยู่ใน ServletContext) เดียวกันก็ได้  ซึ่งตัว <jsp:forward> จะทำลาย content ของเพจปัจจุบันที่จะส่งให้กับ client โดยจะแทนด้วย content ของเพจที่ถูก forward ไปแทน ลักษณะการใช้ก็คือ

<jsp:forward page="urlSpec" /> 

urlSpec คือ relative URL ของเพจที่เราส่งผ่าน request ไปให้
ตัวอย่างที่ใช้กัน ก็อาจจะเป็น
<jsp:forward page="/utils/errorPage.jsp" />
<jsp:forward page="<%= whereTo %>" />

จะสังเกตเห็นว่า ในส่วนของ page attribute เราสามารถใส่ค่าที่เป็น  dynamic ก็ได้

<jsp:plugin> Action
ถ้าใครเคยเขียน HTML code ที่ใช้ในการโหลด Java Plugin  ไว้สำหรับรัน Applet จะทราบว่าจะต้องเขียนอย่างน้อย 2 เวอร์ชันไว้สำหรับสนันสนุน Netscape และ IE  ยกตัวอย่างเช่น ถ้าเราต้องการรัน Applet โดยใช้ Java Plugin, HTML code ที่เราจะต้องเขียนสำหรับ Netscape และ IE ก็จะเป็นอย่างข้างล่าง

<APPLET> tag ที่ใช้สำหรับโหลดและรัน Applet โดยไม่ใช้ Java plugin
<APPLET code="XYZApp.class" codebase="html/" align="baseline"
    width="200" height="200">
<PARAM NAME="model" VALUE="models/HyaluronicAcid.xyz">
    No Java 2 SDK, Standard Edition v 1.3 support for APPLET!!
</APPLET>

EMBED Tag   เพื่อบอก Netscape ให้ใช้ Java Plugin (หรือโหลด ถ้ายังไม่มี)  สำหรับ <APPLET> tag ข้างต้น
<EMBED type="application/x-java-applet;version=1.3" width="200"
   height="200" align="baseline" code="XYZApp.class"
   codebase="html/" model="models/HyaluronicAcid.xyz"
   pluginspage="http://java.sun.com/products/plugin/1.3/plugin-install.html">
<NOEMBED>
   No Java 2 SDK, Standard Edition v 1.3 support for APPLET!!
</NOEMBED>
</EMBED>
 
Object Tag   เพื่อบอก IE ให้ใช้ Java Plugin (หรือโหลด ถ้ายังไม่มี)  สำหรับ <APPLET> tag ข้างต้น
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
    width="200" height="200" align="baseline" 
    codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-win32.cab#Version=1,3,0,0">
    <PARAM NAME="code" VALUE="XYZApp.class">
    <PARAM NAME="codebase" VALUE="html/">
    <PARAM NAME="type" VALUE="application/x-java-applet;version=1.3">
    <PARAM NAME="model" VALUE="models/HyaluronicAcid.xyz">
    <PARAM NAME="scriptable" VALUE="true">
        No Java 2 SDK, Standard Edition v 1.3 support for APPLET!!
</OBJECT>

 จะเห็นว่าโค๊ดแต่ละแบบค่อนข้างจะซับซ้อนและใช้เวลาในการเขียน ซึ่งทาง SUN ก็เห็นใจนักพัฒนาสำหรับเรื่องนี้ จึงมีโปรแกรมที่ชื่อ HTMLConverter ไว้สำหรับเปลี่ยน  <Applet> code แบบที่ไม่ใช้ Plugin ให้กลายเป็นเวอร์ชันที่ใช้ Plugin สำหรับ Netscape และ IE โดยเฉพาะ
แต่สำหรับ JSP แล้ว เราไม่จำเป็นต้องเขียนโค๊ดดังกล่าว โดยเราสามารถใช้ <jsp:plugin> ซึ่งจะทำการตรวจชนิดของ browser และทำการสร้างโค๊ด <EMBED> หรือ <OBJECT>  ใส่เข้าไปแทนโดยอัตโนมัติ แต่เราอาจจะต้องใส่ค่า  parameter ต่าง ๆ ที่จำเป็นสำหรับ <APPLET> เข้าไปใน <jsp:plugin> ด้วย ยกตัวอย่างเช่น

<jsp:plugin type="applet" code="Molecule.class" codebase="/html">
     <jsp:params>
         <jsp:param name="molecule" value="molecules/benzene.mol"/>
     </jsp:params>
     <jsp:fallback>
         <p> unable to start plugin </p>
     </jsp:fallback>
</jsp:plugin>

<jsp:param> เป็นตัวบ่งบอกถึง parameter  ต่าง ๆ ที่ใช้สำหรับ Applet
<jsp:fallback> เป็นตัวที่ใช้ใส่ข้อความเพื่อบอกว่าเกิดอะไรขึ้น ในกรณีที่ Java Plugin ไม่สามารถ start หรือเกิดข้อผิดพลาดบางอย่างขึ้น

Next >>


Copyright (C) 2000 www.jarticles.com.