2012年9月26日 星期三

JSP 入門


JSP 入門

All examples are solely used for educational purposes. This document is provided as is. You are welcomed to use it for non-commercial purpose.
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu 在以下的範例中,我們假設你已經在你自己的電腦上面安裝好了 Apache Tomcat 而且 port 為 8080。如果你還沒安裝好,你可以 參考 安裝 Tomcat 5.5.x

請勿轉貼
看其他教材

目錄

  1. Hello World -- JSP
  2. 互動式 Hello World -- JSP
  3. JSP 存取資料庫
  4. JSP 生命週期
    1. <%! %>
    2. <%@ include %>
  5. 從 web.xml 讀取初始值
  6. Cookie
  7. Session
  8. Custom Tag Library

這篇 JSP 入門的介紹非常精簡,它假設讀者已經熟悉了 Java 程式語言, 關聯性資料庫 SQL 語法,以及大概看過了Java Servlet 入門

Hello World -- JSP

JavaServer Page (JSP) 和 Java Servlet 一樣都是伺服器端的程式, 功能也差不多,只是語法與使用上比較像 PHP 和 ASP 之類的 script 語言。也因為如此,JSP 避免了許多在 Java Servlet 中必須出現的 println() 之類的敘述。可是 JSP 也跟 PHP 和 ASP 一樣比較難 debug。 首先我們先看一個小程式 -- Hello World -- JSP 版。請將這個網頁命名為 Hello.jsp 並將他 置放於 tomcat/webapps/test 的目錄內。為了能夠執行以下程式, 我們假設你們已經安裝好了 Apache Tomcat。
<html>
<head>
<title>
Hello World
</title>
</head>

<body>
<% String s = "Eric"; %>
<h1>Hello <%=s%></h1>
</body>
</html>
如果你能夠正確無誤的執行上面這一個範例,你可以檢查一下在 tomcat/work/DEFAULT 的目錄裡面有一個叫做 test 的子目錄,而這個子目錄裡面有 compile 好的 Hello_1.java 以及 Hello_1.class 檔。為什麼會有這兩個檔案呢?原來當使用者要求 Hello.jsp 的時候,Tomcat 會把 jsp 檔先轉換成 java 檔,然後再把 java compile 成 class 檔,最後才執行這個剛產生 的 class 檔。而這些新產生的 java 和 class 檔都會被放置在 tomcat/work 目錄之下。當這個 jsp 檔被再次呼叫的時候, Tomcat 會直接執行 tomcat/work 內的 class 檔。

互動式 Hello World -- JSP

以下只是使用 HTML 表格的部分元件範例,其他的元件請自行學習或者可以參考作者 非長久以前所寫的 Form Pages
  • 網頁: Greeting.html 置放於 tomcat/webapps/test 內。為了避免 中文的部份會出現亂碼,請記得加上 <meta> 那一行。
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html;charset=Big5">
    <title>
    Hello Form
    </title>
    </head>
    
    <body>
    <form method="post" action="http://localhost:8080/test/Greeting.jsp">
    <input type="text" value="老呂" name="data">
    <input type="submit">
    </form>
    </body>
    </html>
    
  • JSP 程式: Greeting.jsp
    • <%@ page language="java" contentType="text/html;charset=Big5" %> 這一行的目的在於告訴接收端(也就是瀏覽器)即將送過來的資料是以 Big5 編碼的。
    • String(request.getParameter("data").getBytes("ISO-8859-1"), "Big5"); 這一行的目的在於將客戶端傳送過來的 ISO-8859-1 資料轉換成 Big5。在客戶端 網頁內輸入的中文(也就是 Greeting.html 的文字欄位內的資料),會被傳送到 伺服器端;由於伺服器是 Tomcat,而 Tomcat 的預設編碼方式是 ISO-8859-1,因此我們 需要將 ISO-8859-1 的資料轉碼為 Big5;至於進一步的細節,如果讀者有興趣, 請閱讀細談 URL 編碼請注意: 雖然這個寫法感覺上比較複雜,但是無論 客戶端以 GET 或者 POST 的方式,都能正確的解碼。
    • 每一個 JSP 的程式都有四個已經定義的隱式物件(implicit object): request、response、session、以及 out。request 是 HttpServletRequest 的實體,response 是 HttpServletResponse 的實體,session 是 HttpSession 的實體,而 out 是 JspWriter 的實體。

    <%@ page language="java" contentType="text/html;charset=Big5" %>
    <html>
    <head>
    <title>
    Greetings
    </title>
    </head>
    
    <body>
    <% String s = 
       new String(request.getParameter("data").getBytes("ISO-8859-1"), "Big5");
    %>
    <h1>Hello <%=s%></h1>
    <%
       out.println("<h1>試試看 out 物件</h1>");
    %>
    </body>
    </html>
    

JSP 存取資料庫

存取資料庫的常見方式有兩種,分別是利用 JDBC-ODBC 以及純 JDBC 驅動程式兩種。JDBC-ODBC 的好處在於不必另外安裝驅動程式以避免 不必要的麻煩,但是其事前的準備動作(例如設定 DSN 等)以及存取速度比 純 JDBC 慢則是它的缺點。在這一段文件,我們分別提供一個範例程式來說明 這兩種方式。
  1. JDBC-ODBC 驅動程式:
    • 網頁:假設 DBServ.jsp 已經安裝於 tomcat/webapps/test/ 這個目錄內, 而且你已經依據MySQL Server 簡介的介紹 安裝了 MySQL 並且設定好了 ODBC。
      DSN:
      User ID:
      Password:
    • 程式
      <%@ page contentType="text/html;charset=Big5"
              language="java"
              import="java.sql.*" %>
      
      <%
          String dsn = request.getParameter("dsn");
          String uid = request.getParameter("uid");
          String pwd = request.getParameter("pwd");
      
          // initialize query string
          String aQuery = null;
          Connection conn = null;
      
          try
          {
            // load the JDBC-ODBC bridge driver
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
      
            // connect to Database
            aQuery = "select * from Product";
            conn = DriverManager.getConnection("jdbc:odbc:"+ dsn, uid, pwd);
      %>
      
            <html><head><title>
      <%
            out.println("Database " + dsn + " Query");
      %>
            </title></head><body>
      
      <%
            // Construct a SQL statement and submit it
            Statement aStatement = conn.createStatement();
            ResultSet rs = aStatement.executeQuery(aQuery);
      
            // Get info about the query results
            ResultSetMetaData rsmeta = rs.getMetaData();
            int cols = rsmeta.getColumnCount();
      
            // contruct table  
            out.println("<table border=\"1\">");
            out.println("<tr>");
      
            // Display column headers
            for(int i=1; i<=cols; i++)
            {
              out.print("<th>");
              out.print(rsmeta.getColumnLabel(i));
              out.print("</th>");
            }
            out.println("\n</tr>");
      
            // Display query results.
            while(rs.next())
            {
              out.print("<tr>");
              for(int i=1; i<=cols; i++)
              {
                out.print("<td>");
                out.print(rs.getString(i));
                out.print("</td>"); 
              }
              out.println("</tr>");
            }
      
            // Clean up
            rs.close();
            aStatement.close();
            conn.close();
          }
          // a better exception handling can be used here.
          catch (Exception e)
          {
            System.out.println("Exception Occurs: " + e);
          }
      %>
          </body></html>
      
    • 請仔細的比較這個 JSP 檔跟之前的 servlet 有什麼不同?看到這裡你 應該慢慢有「要學好 JSP 還是得學好 Java」的感覺吧!
    • 如果你需要 import 更多的類別,你可以以 "," 當作類別名稱之間的 分隔記號。
    • 練習題:請將之前的 Worker 範例轉換成 JSP 版。使用者可以從 網頁輸入工作時數後,然後由 JSP 計算出薪資。切記,請保持 Worker 這個類別。(提示:可以以 import 的方式把 Worker 這個類別載入。)
  2. 純 JDBC 驅動程式:
    • 網頁:假設 JDBCServ.jsp 已經安裝於 tomcat/webapps/test/ 這個目錄 內,而且你已經依據MySQL Server 簡介的介紹 安裝了 MySQL 並且已經在 Tomcat 內安置好了 JDBC 驅動程式。
      User ID:
      Password:
    • 程式
      <%@ page contentType="text/html;charset=Big5"
              language="java"
              import="java.sql.*" %>
      
      <%
          String uid = request.getParameter("uid");
          String pwd = request.getParameter("pwd");
      
          // 初始化變數
          String aQuery = null;
          Connection conn = null;
      
          try
          {
            // 載入 JDBC 的驅動程式
            Class.forName("com.mysql.jdbc.Driver");
      
            // 欲執行之 SQL 查詢語法
            aQuery = "select * from Product";
      
            // 產生程式和資料庫之間的連線
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/eric", uid, pwd);
      %>
      
            <html><head><title>
            查詢產品資料表的結果
            </title></head><body>
      
      <%
            // 查詢產品資料表的結果
            Statement aStatement = conn.createStatement();
            ResultSet rs = aStatement.executeQuery(aQuery);
      
            // 取得產品資料表的 metadata
            ResultSetMetaData rsmeta = rs.getMetaData();
            int cols = rsmeta.getColumnCount();
      
            // 建立 HTML table 來顯示資料表的內容
            out.println("<table border=\"1\">");
            out.println("<tr>");
      
            // 顯示欄位名稱
            for(int i=1; i<=cols; i++) {
              out.print("<th>");
              out.print(rsmeta.getColumnLabel(i));
              out.print("</th>");
            }
            out.println("\n</tr>");
      
            // 顯示資料表內的內容
            while(rs.next()) {
              out.print("<tr>");
              for(int i=1; i<=cols; i++) {
                out.print("<td>");
                out.print(rs.getString(i));
                out.print("</td>"); 
              }
              out.println("</tr>");
            }
      
            // 結束前,把該關閉的關閉
            rs.close();
            aStatement.close();
            conn.close();
          }
          // 可以考慮設計成比較好的例外處理:例如載入驅動程式錯誤、連接資料庫失敗等
          catch (Exception e) {
            System.out.println("發生錯誤: " + e.getMessage());
          }
      %>
          </body></html>
      

JSP 的生命週期

JSP 的生命週期跟 servelt 很像,根據 Sun 的文件:一旦 JSP 的網頁被轉換成 servlet(ie. translate)以及編譯之後,這個 JSP servlet 的生命週期基本上 就會遵循 servlet 的生命週期。JSP 生命週期如下所述:
  1. 如果 JSP 網頁的 servlet 物件不存在,那麼 tomcat 會:
    1. 載入這個 JSP servlet 的類別
    2. 產生並初始化這個類別的物件
    3. 一旦物件形成了之後,tomcat 會經由 jspInit 方法來呼叫這個物件
  2. 如果 JSP 網頁的 servlet 物件存在,那麼 tomcat 會呼叫這個物件的 _jspService 方法,並將 requestresponse 的物件傳遞給它。
如果 tomcat 需要移除某個JSP 網頁的 servlet 物件,它會呼叫該物件的 jspDestroy 方法。 在了解的 JSP 的生命週期之後,我們可以讓包含有資料庫連線的 JSP 網頁更有效率。 仔細觀察之前 JSP 與資料庫的範例:在該範例中(其實所有資料庫連線的 JSP 網頁 都可以檢查),每一次使用者要求執行該程式的時候,它都會產生 一個 connection 物件,這樣子一來,由於 (1) 產生 connection 的成本很高, 且 (2) 每一個資料庫伺服器能接受的 connection 數又有上限的限制, 這會造成這個程式非常沒有效率。根據之前所說明的 JSP 生命週期,我們能不能 重新修改這個程式使其更有效率?
  • 網頁:我們假設你已經將 NewDBServ.jsp 安裝於 tomcat/webapps/test/ 目錄內,而且已經設定好了 dsn 為 csie 的 ODBC。
    Price >
  • 程式:這個程式裡面有幾件需要注意的事項
    • 第一個就是 <%! 的用法:之前所說的 JSP 程式碼都是屬於 _jspService() 這個方法內的;如果我們需要宣告一些程式碼,而這些 程式碼不屬於 _jspService() 內的,我們必須加上 <%!。 或者從物件導向的角度來看,凡是宣告在 <%! 內的變數即為該 servlet 類別的資料成員,該類別的所有方法成員都可以存取它們;而宣告在 <%! 內的方法也是該類別的方法成員。
    • 為了避免 connection 不斷的被產生、連接、以及結束,我們在 jspInit() 產生一個 connection 物件;由於同樣的 JSP servlet 物件 (在這個範例中就是 NewDBServ)共用宣告出來的 connection 物件,如此 JSP 程式的執行速度會變快。
    • 變數 count 在這個程式中只是用來表現出 jspInit() 只被執行一次。
    <%@page contentType="text/html;charset=Big5"
            language="java"
            import="java.sql.*" %>
    
    <html>
    
    <!-- 加上 ! 宣告成為類別的屬性,否則便成為方法內的變數 -->
    <%! private Connection conn = null;
        private int count = 0;
    %>
    
    <%!
        // 用來產生一個資料庫的連線,提供所有使用這個 JSP 檔的要求使用
        public void jspInit() {
          count = 10;
          try {
            // 載入 JDBC-ODBC 驅動程式
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
    
            // 請記得設定適當的 UID 和 PWD。
            conn = DriverManager.getConnection("jdbc:odbc:csie", UID, PWD);
          }
          catch (Exception e) {
            System.out.println("Fail to connect to database.");
          }
        }
    
        // 在這個 JSP 檔從 tomcat 卸載時,將之前的資料庫連線結束掉
        public void jspDestroy() {
          try {
            conn.close();
          } catch (Exception e) {
            System.out.println("Fail to close connection.");
          }
        }
    %>
    
    <%
        count++;
    
        String salary = request.getParameter("price");
    
        // initialize query string
        String aQuery = null;
    
        try {
          // connect to Database
          aQuery = "select * from Product where Price > " + salary;
    %>
    
          <head><title>Database Query</title></head>
          <body>
          <h3>Accessed <%=count%> times</h3>
    
    <%
          // Construct a SQL statement and submit it
          Statement aStatement = conn.createStatement();
          ResultSet rs = aStatement.executeQuery(aQuery);
    
          // Get info about the query results
          ResultSetMetaData rsmeta = rs.getMetaData();
          int cols = rsmeta.getColumnCount();
    
          // contruct table  
          out.println("<table border=\"1\">");
          out.println("<tr>");
    
          // Display column headers
          for(int i=1; i<=cols; i++) {
            out.print("<th>");
            out.print(rsmeta.getColumnLabel(i));
            out.print("</th>");
          }
          out.println("\n</tr>");
    
          // Display query results.
          while(rs.next()) {
            out.print("<tr>");
            for(int i=1; i<=cols; i++) {
              out.print("<td>");
              out.print(rs.getString(i));
              out.print("</td>"); 
            }
            out.println("</tr>");
          }
    
          // Clean up
          rs.close();
          aStatement.close();
        }
        // a better exception handling can be used here.
        catch (Exception e) {
          System.out.println("Exception Occurs: " + e);
        }
    %>
        </body></html>
    

  • 如果你有許多個 JSP 網頁都需要宣告 conn 的物件以及相同的資料庫 連結,比較好的方法就是把 <%! 內的敘述把他包成一個 檔案(例如 initdestroy.jsp 並把這個檔案放到 tomcat/webapps/test/ 目錄內),然後把這些敘述從 NewDBServ.jsp 內去除,並加入
    <%@include file="initdestroy.jsp" %>
    

從 web.xml 讀取初始值

在之前連結資料庫的範例中,我們都需要經由 HTML 表單元件中指定某些 參數(例如,表格或者 dsn 名稱)或者執行程式前的某些特定的初始值 (例如,JDBC 的驅動程式名稱)。這些初始值當然可以像之前的範例中 將它設定在程式碼中,但是這樣的作法不太有彈性。假設 dsn 或者 JDBC 驅動程式的名稱必須依據環境的變動而改變的時候,我們必須找出所有的程式碼, 然後在更改完正確的名稱之後,還要重新編譯程式,這樣一來非常沒效率; 更何況,如果漏了改幾個程式,這所衍生的麻煩不知道有多少。 為了解決這個問題,大多數系統開發人員會利用設定檔的方式來進行; 也就是說,我們把這些可能改變的資訊,放在一個設定檔中,然後每次執行 程式的時候,該程式會從設定檔讀取最新的資訊。Java 常用的設定檔 有兩個格式:一個是 使用 Properties 來初始化你的程式(Properties 是 java.util.Properties 物件), 另一個是 XML,而 tomcat 對於所有 JSP/servlet 的設定是由 web.xml 負責。
web.xml 內的資料分成兩種:一種是只能讓某些特定 JSP/servlet 讀取的資料 (在本範例中就是 HelloParam.jsp), 另一種是允許在某特定目錄(在本範例中就是 tomcat/webapps/test; 其實它比較正式的說法是"某特定 application"、"某特定 web application"、 或者"某特定 context")內所有 JSP/servlet 都能讀取的資料。 首先,我們先說明第一種資料的存取方式。
如果要讀取 web.xml 內設定給某特定 JSP/servlet(在本範例中為 HelloParam.jsp )的資料,我們利用 JSP 定義的一個內建物件 config, 而這個物件的類別是 javax.servlet.ServletConfig。
  • web.xml: web.xml 的根元素為 <web-app>,它的存放位置在 tomcat/webapps/test/WEB-INF 目錄內。在這個檔案內,我們設定了 兩對資料:一對是名為 dsn,而值為 csie;另一對是名為 param2,而值為 你好嗎。每一對資料由 <init-param> 所描述, 而名稱由 <param-name> 所描述,值由 <param-value> 所描述。由於這些設定是給 HelloParam.jsp 用的,所以這些資料的描述就成為 <servlet> 的子元素; <servlet> 還有兩個子元素需要設定:一個是 <servlet-name>(當作"該 servlet"的名稱),另一個是 <jsp-file>(用來指定 JSP 的檔案名稱,在名稱之前必須加上 "/")。 有了以上設定,我們還需要告訴 tomcat 當使用者輸入某個 URL 的時候,它會去 執行剛剛設定的 JSP 檔案;因此,我們需要加上 <servlet-mapping> 元素,該元素包含兩個子元素:一個是 servlet 的名稱,它的設定方式與之前的 <servlet-name> 必須完全相同;另一個就是指定 URL 的方式, 在本範例中,即為 <url-patterm>/HelloParam.jsp</url-patterm>
    <?xml version="1.0" encoding="Big5"?>
    <web-app>
      <servlet>
        <servlet-name>ReadParameters</servlet-name>
        <jsp-file>/HelloParam.jsp</jsp-file>
        <init-param>
          <param-name>dsn</param-name>
          <param-value>csie</param-value>
        </init-param>
        <init-param>
          <param-name>param2</param-name>
          <param-value>你好嗎</param-value>
        </init-param>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>ReadParameters</servlet-name>
        <url-pattern>/HelloParam.jsp</url-pattern>
      </servlet-mapping>
    </web-app>
    
  • HelloParam.jsp 的原始碼如下所示。在程式中,有兩個 config 物件的 方法:一個是 getParameter(name),它是用來存取名為 name 的值;如果 name 為 "dsn",則該名稱的值 csie 會被回傳。 另一個是 getServletName(),它是用來取得 <servlet-name> 的內容。
    <%@page contentType="text/html;charset=Big5" %>
    <html>
    <body>
    <%
      String p1 = config.getInitParameter("dsn");
      String p2 = config.getServletName();
      String p3 = config.getInitParameter("param2");
    %>
      <h3 align="center"><%=p1%></h3>
      <h3 align="center"><%=p2%></h3>
      <h3 align="center"><%=p3%></h3>
    </body>
    </html>
    
    執行 HelloParam.jsp 之後,其結果如下所示:

  • 練習題: 請把 web.xml 內 <url-pattern> 改成 <url-pattern>/hhh.jsp</url-pattern>,然後在瀏覽器 輸入 http://localhost:8080/test/hhh.jsp 並觀察其執行結果。想想看, 這樣做有什麼好處?



如果要讀取 web.xml 內設定給"該 application"的資料,我們可以利用 JSP 定義的一個內建物件 application,而這個物件的類別是 javax.servlet.ServletContext。
  • web.xml: 除了之前的設定之外,我們加上了一些在"該 application"內所有 JSP/servlet 使用的資料,這些設定特別由綠色標示出來,內容如下:
    <?xml version="1.0" encoding="Big5"?>
    <web-app>
    
      <context-param>
        <param-name>jdbc_driver</param-name>
        <param-value>sun.jdbc.odbc.JdbcOdbcDriver</param-value>
      </context-param>
      <context-param>
        <param-name>db_server</param-name>
        <param-value>mysql</param-value>
      </context-param>
      <context-param>
        <param-name>db_port</param-name>
        <param-value>3306</param-value>
      </context-param>
    
    
      <servlet>
        <servlet-name>ReadParameters</servlet-name>
        <jsp-file>/HelloParam.jsp</jsp-file>
        <init-param>
          <param-name>dsn</param-name>
          <param-value>csie</param-value>
        </init-param>
        <init-param>
          <param-name>param2</param-name>
          <param-value>你好嗎</param-value>
        </init-param>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>ReadParameters</servlet-name>
        <url-pattern>/HelloParam.jsp</url-pattern>
      </servlet-mapping>
    </web-app>
    
    從 web.xml 的綠色部分可以看得出來,其設定的方式跟之前的類似,不一樣的 只是標籤的名稱不同:分別用 <context-param> 來設定一對 資料,資料名稱以及值仍然由 <param-name><param-value>來描述。
  • 由於定義方式不同,程式碼當然略有不同:
    <!-- HelloContext.jsp -->
    <%@page contentType="text/html;charset=Big5" %>
    <html>
    <body>
    <%
      String p1 = application.getInitParameter("jdbc_driver");
      String p2 = application.getInitParameter("db_server");
      String p3 = application.getInitParameter("db_port");
    %>
      <h3 align="center"><%=p1%></h3>
      <h3 align="center"><%=p2%></h3>
      <h3 align="center"><%=p3%></h3>
    </body>
    </html>
    
    仔細觀察的話,讀者會發現,HelloParam.jsp 和 HelloContext.jsp 不一樣的地方 只在於前者使用 config 存取資料,而後者使用 application。執行該網頁的結果 如下:

  • 請注意: 無論是 config 或者是 application,如果你希望在 <%! 的區塊內使欲用的話,在使用前你必須先取得它,取得方式如下:
    // 取得 config
    ServletConfig config = getServletConfig();
    
    // 取得 application
    ServletContext application = getServletContext();
    
  • 練習題: 由於兩種資料的有效範圍不同,請完成下列兩項工作:
    1. 請修改 HelloParam.jsp 使其能夠存取 <context-param> 的資料。
    2. 請修改 HelloContext.jsp 確認其無法存取 <init-param> 的資料。








Cookie

The HTTP protocol does not support persistent information that could help a web server determine that a request is from a particular client. 例如,某些網頁需要知道使用者是否 已經登入,若已經登入便可以看網頁的內容,否則要求使用者登入。 一般來說,有兩種方式可以讓 web server 經由 persistent information 來判斷,而這兩種方法為 Cookie 和 Session。Cookie 是儲存於客戶端(browser 內)的資料。由於這是一種由 伺服器端的程式傳送資料到客戶端的一種簡易的方式,因此被大量 的使用於 web 為主的系統中,例如客戶輸入的資料,客戶的偏好 等等。這些資料先由伺服器端的程式寫到客戶端,然後之後的聯繫便可以 從這些資料來提供不同的服務。例如我們可以將使用者的帳號以及 密碼存放在 cookie 內,下一次使用者要登入的時候,就可以從 cookie 來判斷,如果已經存在就不需要再輸入一次。
不過,cookie 也有一些限制,例如一個 cookie 不可以超過 4KB, 而瀏覽器也會對 cookie 的總數作限制,cookie 有可能會有不見的 時候,所以程式寫作的時候要謹慎。另外,由於 cookie 大家都能 讀取,因此也有安全上的考量。
  • 讀取 cookie:建議先執行這個程式來了解究竟 cookie 寫進去了沒, 等到下一個程式(SetCookies)執行完後,再執行一次並比較兩次的不同。
    <!--
       UseCookies.jsp
    -->
    
    <%@ page language="java" contentType="text/html;charset=Big5" %>
    
    <html>
    <head><title>Use Cookies</title></head>
    <body>
    
    <%
        Cookie [] cookie = request.getCookies();
        if(cookie.length == 0)
    %>
          <h1>沒有 Cookie</h1>
    <%  else 
        {
          out.println("<h1>大家好</h1>");
          out.println("<ul>");
          for(int i=0; i<cookie.length; i++)
            out.println("<li> " + cookie[i].getName() + "=" +
                        cookie[i].getValue());
          out.println("</ul>");
        }
    %>
    </body>
    </html>
    
  • 寫入 cookie
    <!--
       SetCookies.jsp
    -->
    
    <%@ page language="java" contentType="text/html;charset=Big5" %>
    
    <html>
    <head><title>Set Cookies</title></head>
    <body>
    
    <%
        Cookie myck1 = new Cookie("UID", "123");
        response.addCookie(myck1);
        Cookie myck2 = new Cookie("PWD", "abc");
        response.addCookie(myck2);
    %>
    <h1>寫入 Cookies</h1>
    </body>
    </html>
    

Custom Tag Library

Custom Tag Library 是一種 JSP 的特殊使用的標籤,它允許開發人員 以自訂的標籤名稱來(如 XML )達成某些目標。為了達成上述之目標, 你需要定義一個 TLD 檔(tag library descriptor)來描述開發人員自訂 標籤的相關訊息,例如標籤名稱 name,tag 所符合的 tlibversionjspversion 等。除此之外,你也需要定義一個 tag 的處理器, 也就是說當 jsp engine 處理到這個自訂的 tag 之後,他所需要去呼叫 的程式,而由這個程式來處理這個 tag 的內容以及功能。 在以下的例子中,我們希望定義一個 hello 的標籤,而這個 標籤內有一個 name 的屬性,我們的 jsp engine 碰到 hello 時,就會把 name 的屬性以 table 的方式呈現。這個例題是從 Sue Spielman 的文章修改而成。
  • TLD 檔: tagclass 用來定義 tag 處理器的名稱。tag 的名稱 定義在 <tag><name>hello</name><tag>, 而這個 tag 有一個屬性定義在 <attribute><name>name</name></attribute>
    <?xml version="1.0" encoding="Big5" ?>
    <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" 
                            "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
    <taglib>
      <tlibversion>1.0</tlibversion>
      <jspversion>1.1</jspversion>
      <shortname>Hello 系列</shortname>
      <info>Hello 系列:沒 body 的範例</info>
    
      <tag>
        <name>hello</name>
        <tagclass>Hello.Hello1</tagclass>
        <bodycontent>empty</bodycontent>
        <attribute>
          <name>name</name>
          <required>false</required>
        </attribute>
      </tag>
    </taglib>
    
  • tag 處理器: 處理器至少要定義所有自訂 tag 的屬性的 setter 以及 getter。另外,還有 doStartTag() 來定義遇到 tag 的時候要如何處理, 以及 doEndTag() 來定義 tag 結束後要如何處理。
    package Hello;
    
    import javax.servlet.jsp.*;
    import javax.servlet.jsp.tagext.*;
    
    /**
     * This is a simple tag example to show how content is added to the
     * output stream when a tag is encountered in a JSP page. 
     */
    public class Hello1 extends TagSupport {
      private String name=null;
    
      // Getter/Setter for the attribute name
      public void setName(String value){
        name = value;
      }
    
      public String getName(){
        return(name);
      }
    
      /**
       * doStartTag is called by the JSP container when the tag is encountered
       */
      public int doStartTag() {
        try {
          JspWriter out = pageContext.getOut();
          out.println("<table border=\"1\">");
          if (name != null)
            out.println("<tr><td> Hello " + name + " </td></tr>");
          else
            out.println("<tr><td> Hello World </td></tr>");
        } catch (Exception ex) {
          throw new Error("All is not well in the world.");
        }
    
        // Must return SKIP_BODY because we are not supporting a body for this 
        // tag.
        return SKIP_BODY;
      }
    
      /**
       * doEndTag is called by the JSP container when the tag is closed
       */
      public int doEndTag(){
        try {
          JspWriter out = pageContext.getOut();
          out.println("</table>");
        } catch (Exception ex){
          throw new Error("All is not well in the world.");
        }
    
        return SKIP_BODY;
      }
    }
    
  • JSP 檔:
    <%@ taglib uri="Hello.tld" prefix="sample" %>
    <html>
    <head>
    <title>Your Standard Hello World Demo</title>
    </head>
    <body bgcolor="#ffffff">
      <hr />
      <sample:hello name="Sue"/>
      <hr />
    </body>
    </html>
    


Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu












3 則留言:

  1. 如果想要將html所輸入的數字轉到jsp裡做運算該怎麼用~謝謝

    回覆刪除
    回覆
    1. 假設輸入的是字串“12",希望轉成整數 12,那就 Integer.parseInt(input);其他類別,請參考 Java。

      刪除