JavaServer Pages (JSP) Part II

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

 
  Standard Syntax and Semantics
ก่อนอื่น ให้ทำการรันโค๊ดข่างล่างนี้ (hellojsp1.jsp) แล้วดูผลที่ได้

<%-- This is comment --%>
<%@ page info="a hello jsp example" %>
<%@ page import="java.util.Date" %>
<HTML>
<HEAD><TITLE>Hello, JSP</TITLE></HEAD>
<BODY bgcolor="#ffffff">
<H1>Hello JSP</H1>
<BR>
<%! private int accessCount = 0; %> 
<%  accessCount++; 
    Date rightNow = new Date(); %>
Access Page: <%= accessCount %> times... at <%= rightNow.toString() %>
</BODY>
</HTML> 

จากโค๊ด เราจะเห็นว่ามี script ที่อยู่ในรูปของ <% ... %> (Directives and Scripting Elements) แตกต่างกัน 5 แบบ คือ
 

JSP Directives and Scripting Elements
  Directives <%@ directive %>
  Declarations <%! declaration %>
  Expressions <%= expression %>
  Code Fragment/Scriptlet <% code fragment %>
  Comments <%-- comment --%>

Directives 
JSP Directives  เป็นส่วนที่เรียกว่า "message" ที่ใช้ส่งไปถึง JSP Container  ในลักษณะของ <%@ ... %> โดย message นี้จะเป็นตัวบอกว่า  Container  ควรจะทำอะไรกับ JSP Page ต่อไป ซึ่ง directives ในส่วนนี้จะไม่มีผลต่อหน้าตาที่ออกมาของ JSP Page เมื่อถูกแปลงออกมาในรูปของ html แล้ว
Directives แบ่งออกเป็นสามส่วน ส่วนที่เราใช้ทั่ว ๆ ไปคือ page และ include กับส่วนที่สามซึ่งเป็น taglib (เราจะไม่กล่าวถึงในที่นี้) ซึ่งใช้สำหรับสร้าง Tag ของเราเองใน JSP

page directive เป็นส่วนที่ปกติเราจะเห็นอยู่บนสุดของ JSP page ซึ่งใช้ในการกำหนดค่าต่าง ๆ ที่เกี่ยวข้องกับ JSP page นั้น ๆ หรือเกี่ยวข้องกับการติดต่อสื่อสารกับ JSP Container ยกตัวอย่างเช่น 
ถ้าเราอยากเรียกใช้คลาสที่ชื่อ java.util.Date (เหมือนใน hellojsp1.jsp ) เราก็สามารถที่จะ import คลาสนี้ได้โดยใช้
<%@ page import="java.util.Date" %>

หรือเวลาที่เกิดข้อผิดพลาดใน JSP page ของเรา แล้วเราอยากให้โชว์ข้อผิดพลาดที่เกิดขึ้นที่ error page ที่ชื่อ errorPage.jsp เราก็ใช้ 
<%@ page errorPage="errorPage.jsp" %>

หรือแม้กระทั่งเวลาที่เราอยากจะเก็บ states ของ user ในรูปของ session เราก็สามารถใช้
<%@ page session="true" %> 

เพื่อบอก container ว่า JSP Page นี้สามารถเรียกใช้ HttpSession ในการเปลี่ยนแปลงและเก็บ states  ของ user ได้ เป็นต้น

include directive   เป็นส่วนที่ช่วยให้เราสามารถนำไฟล์ JSP อื่น ๆ มาเป็นส่วนประกอบของไฟล์ JSP ปัจจุบัน โดยใช้
<%@ include file="filename.jsp" %>

ประโยชน์ที่เห็นได้ชัดอย่างหนึ่งของการใช้ include directive คือ การง่ายต่อการเปลี่ยนแปลงและบำรุงรักษา ยกตัวอย่างเช่น สมมุติว่าทุกหน้าของเราต้องการ header หรือ footer ที่เหมือนกัน เราก็แค่ใช้ <%@ include file="header.jsp" %> ใส่ลงไปในทุก ๆ JSP ไฟล์ หลังจากนั้น ทุกครั้งที่เราต้องการเปลี่ยนแปลง header นี้ เราก็แค่เปลี่ยนไฟล์ที่ชื่อ header.jsp  ซึ่งไฟล์ทุกไฟล์ที่ include ไฟล์นี้เข้าไป ก็จะเปลี่ยนไปด้วยโดยอัตโนมัติ

Declarations
Declarations ใช้ในการประกาศค่าตัวแปร (variable) หรือสร้างฟังก์ชั่นต่าง ๆ (method) เพื่อจะใช้ใน JSP page นั้น
โดยทั่วไป Declarations จะถูก initialize เมื่อ JSP page ถูก initialize ซึ่งจะทำให้ตัวแปร หรือฟังก์ชั่นใน Declartions พร้อมใช้งานได้ทันที ตัวอย่างเช่น
<%! int i = 0; %>
<%! public String f(int i) {
      if (i<3) return "...";
      ...
    }
%>

* Declarations เป็นส่วนที่ถูกประมวลผลในช่วง Translation time

Expressions
โดยการใช้  expressions สิ่งต่าง ๆ ที่อยู่ใน <%= ... %> จะถูกประมวลผลแล้วเปลี่ยนให้อยู่ในรูปของ  String  และส่วนที่ได้นี้จะถูกรวมเข้าไปอยู่ใน output page (html) โดยตรง เช่น
<%= i %>
Container จะดึงค่า i ออกมา แล้วเปลี่ยนเป็นสตริงโดยใช้ Integer.toString(i)

<%= "Hello" %> 
Container จะนำค่า Hello ใส่เข้าไปใน output page

ข้อควรจำอย่างหนึ่งคือ  ห้ามทำการใส่ semicolon (;) ลงไปใน <%= ... %> ยกเว้นถ้า semicolon นั้นเป็นส่วนหนึ่งของสตริง เช่น 
<%= "Hello semicolon ;" %>

* Expressions เป็นส่วนที่ถูกประมวลผลในช่วง Translation time

Code Fragments/Scriptlets
เราสามารถใส่โค๊ด หรือส่วนหนึ่งของโค๊ดเข้าไปยัง JSP page ได้โดยใช้ <% ... %> โค๊ดที่ใส่เข้าไปนี้จะไปอยู่ในส่วนของ service() ฟังก์ชั่นของ Servlet ซึ่งจะถูกเรียกใช้เมื่อมี request จาก client ยกตัวอย่างเช่น

<% int userId = request.getParameter("userId");
     if (userId == 9999) {
       out.print("You are admin!!!");
     } else {
       out.print("You are who you are");
     }
%>

บางทีเราอาจใส่เพียงส่วนหนึ่งของโค๊ดเข้าไปในแต่ละ <% ... %> ก็ได้ เช่น

<% if (Calendar.getInstance().get(Calendar.AM_PM) == Calendar.AM) { %>
Good morning
<% } else { %>
Good Afternoon
<% } %>

เหตุผลที่เราสามารถทำเช่นนี้ได้เพราะถ้าเราดู code หลังจากการแปลงเป็น Servlet แล้ว จะเป็นดังนี้
...
if (Calendar.getInstance().get(Calendar.AM_PM) == Calendar.AM) {  // by <% ... %>
  out.print("Good Morning"); // plain html will be replaced by out.print("...");
} else { // by <% ...%>
  out.print("Good Afternoon"); // plain html
}
...
ซึ่งจะกลายเป็นโค๊ดที่สมบูรณ์ขึ้นมา
* Code Fragments/Scriptlets เป็นส่วนที่ถูกประมวลผลในช่วง Client request time

Comments
comments ใน JSP มีอยู่สองแบบคือ
1) comment ที่ปกติถูกใช้ใน html ไฟล์ ซึ่งจะไม่ถูก skip ไปโดย JSP Container เมื่อไฟล์ JSP ถูกแปลงเป็น .class แล้ว (จะยังคงปรากฎที่ client side ในส่วนของ html source code) ตัวอย่างเช่น
<!-- This is my comment -->

บางทีเราอาจเปลี่ยนแปลง comment ที่อยู่ข้างใน <!-- ... -->  ได้ โดยใช้ expression เช่น
<!-- <%= expression %> more comment -->

2) comments ที่ผู้เขียน JSP ใช้สำหรับ comment ไฟล์ JSP ที่เขียนอยู่ ซึ่งจะถูก skip ไปโดย JSP Container ในช่วงของ Translation time ตัวอย่างเช่น
<%-- comment for server side only --%> 

Hellojsp1.jsp Explanation
หลังจากที่ได้เรียนรู้เกี่ยวกับ syntax ต่าง ๆ ของ JSP แล้ว เรากลับมาที่ไฟล์ hellojsp1.jsp กันอีกครั้ง 

1:  <%-- This is comment --%>
2:  <%@ page info="a hello jsp example" %>
3:  <%@ page import="java.util.Date" %>
4:  <HTML>
5:  <HEAD><TITLE>Hello, JSP</TITLE></HEAD>
6:  <BODY bgcolor="#ffffff">
7:  <H1>Hello JSP</H1>
8:  <BR>
9:  <%! private int accessCount = 0; %> 
10: <%  accessCount++; 
11:    Date rightNow = new Date(); %>
12: Access Page: <%= accessCount %> times... at <%= rightNow.toString() %>
13: </BODY>
14: </HTML> 

line 1: เป็นลักษะของ JSP comment ที่จะถูก skip ไปโดย JSP Container หลังจากที่ไฟล์ JSP ถูกแปลงเป็น Servlet แล้ว
line 2: ใช้ page directive เพื่อเซ็ตค่า "a hello jsp example" ไปใส่ในฟังก์ชั่น Servlet.getServletInfo() ของไฟล์ Servlet ที่ได้จากการแปลงไฟล์ hellojsp1.jsp โดย JSP Container
line 3: เป็นการใช้ page directive เพื่อ import คลาส java.util.Date ก่อนที่จะทำการเรียกใช้
line 4-8: เป็น HTML template ซึ่งจะถูกแปลงอยู่ในรูปของ out.print(HTML)
line 9: มีการประกาศตัวแปร private int accessCount โดยใส่เข้าไปใน Declaration เพื่อใช้ในการนับจำนวนครั้งที่เพจนี้ถูกเรียกดู ซึ่ง accessCount จะกลายเป็นส่วนหนึ่งของ instance variable ของไฟล์ hellojsp1 ในเวอร์ชั่น Servlet 
line 10: ทำการเซ็ต accessCount+1 ในทุก ๆ ครั้งที่เพจนี้ถูกเรียก ซึ่งสามารถทำได้ในส่วนที่เป็น scriptlet (<% ... %>)
line 11: สร้าง object ใหม่ชื่อ rightNow ซึ่งมาจากคลาส java.util.Date ที่เรา import มาก่อนหน้านี้ ใช้สำหรับเรียกดูวันเวลาปัจจุบัน
line 12: ใช้ Expression เพื่อแสดงค่าของ accessCount และพิมพ์ค่าของเวลาปัจจุบันที่เก็บอยู่ใน rightNow ซึ่งทั้งสองค่าจะถูกแปลงออกมาอยู่ในรูปของ String

เพื่อเพิ่มความเข้าใจมากขึ้น ผู้อ่านอาจดู Servlet* ข้างล่างประกอบก็ได้
* Servlet ที่ได้จากการแปลงไฟล์ hellojsp1.jsp โดย Container จะซับซ้อนกว่าที่เราเห็นข้างล่าง แต่เราจะยังไม่กล่าวถึงในตอนนี้

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Date;

public class _hellojsp1 extends HttpServlet {

  private int accessCount = 0;

  public void service(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {

    response.setContentType("text/html");
    PrinterWriter out = response.getWriter();
    out.print("<HTML");

    out.print("<HEAD><TITLE>Hello, JSP</TITLE></HEAD>");
    out.print("<BODY bgcolor=\"#ffffff\">");
    out.print("<H1>Hello JSP</H1>");
    out.print("<BR>");

    accessCount++;
    Date rightNow = new Date();

    out.print("Access Page: ");
    out.print( Integer.toString(accessCount) ); 
    out.print(" times... at ");
    out.print( rightNow.toString() );
    out.print("</BODY>");
    out.print("</HTML");
  }

  public String getServletInfo() {
    return "a hello jsp example";
  }
}

Next >>