Servlet 至 JSP 的簡單轉換


Servlet 與 JSP 是一體的兩面,JSP 會轉換為 Servlet,Servlet 作的到的也可以用 JSP 作的到,通常 JSP 會來作爲畫面顯示之用,在這邊,將用一個顯示畫面的 Servlet,將之轉換為 JSP,從中了解各元素的對照。

假設原本有個 Servlet 負責畫面顯示如下:

package cc.openhome.view;

import cc.openhome.model.Bookmark;
import cc.openhome.model.BookmarkService;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ListBookmark extends HttpServlet {    
    @Override
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
                       throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println(
           "<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("<meta charset=\"UTF-8\">");
        out.println("<title>觀看線上書籤</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<table style=\"text-align: left; width: 100%;\" border=\"0\" >");
        out.println("  <tbody>");
        out.println("  <tr>");
        out.println("  <td style=\"background-color: rgb(51, 255, 255);\">網頁</td>");
        out.println("  <td style=\"background-color: rgb(51, 255, 255);\">分類</td>");
        out.println("  </tr>");

        BookmarkService bookmarkService =
                (BookmarkService) getServletContext().getAttribute("bookmarkService");

         bookmarkService.getBookmarks()
                        .forEach(bookmark -> {
                            out.println("    <tr>");
                            out.println("      <td><a href=\"http://" +
                               bookmark.getUrl() + "\">" +
                               bookmark.getTitle() + "</a></td>");
                            out.println("      <td>" +
                                    bookmark.getCategory() + "</td>");
                            out.println("    </tr>"); 
                         });

        out.println("  </tbody>");
        out.println("</table>");
        out.println("</body>");
        out.println("</html>");
    } 
}

你可以建立一個檔案,副檔名為 .jsp,首先把 doGet() 中所有的程式碼貼上去,接著看到第一行:

response.setContentType("text/html;charset=UTF-8");

這可以使用 JSP 的指示(Directive)元素在 JSP 頁面的第一行寫下:

<%@page contentType="text/html" pageEncoding="UTF-8"%>

這告訴容器在將 JSP 轉換為 Servlet 時,使用 UTF-8 將 JSP 轉譯為 .java,然後編譯時也用 UTF-8,並設定內容型態為 text/html。接著這行可以直接刪除:

PrintWriter out = response.getWriter();

這是因為 JSP 中有隱含物件(Implicit object),out 這個名稱就是一個隱含物件名稱。接著 out.println() 的部份可以寫成:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>觀看線上書籤</title>
    </head>
    <body>
        <table style="text-align: left; width: 100%;" border="0">
            <tbody>
                <tr>
                    <td style="background-color: rgb(51, 255, 255);">網頁</td>
                    <td style="background-color: rgb(51, 255, 255);">分類</td>
                </tr>

這是你為什麼要用 JSP 處理畫面的原因,因為你不必用 "" 包括字串來作那些 HTML 的輸出了。接下來這個部份:

         BookmarkService bookmarkService =
            (BookmarkService) getServletContext().getAttribute("bookmarkService");
         bookmarkService.getBookmarks()
                        .forEach(bookmark -> {

可以直接用 Scriptlet 元素,也就是用 <%%> 包括起來,在 JSP 中要撰寫 Java 程式碼,就是這麼作的:

<%
         BookmarkService bookmarkService = 
            (BookmarkService) application.getAttribute("bookmarkService");
         bookmarkService.getBookmarks()
                        .forEach(bookmark -> {
%>

在上面可以看到,ServletContext 的取得,在 JSP 中是透過 application 隱含物件,而 BookmarkServiceBookmark,其完整名稱其實必須包括 cc.openhome.model 套件名稱,在 JSP 中,若要作到與 Servlet 中 import 同樣的目的,可以使用指示元素,告訴容器轉譯時,必須包括的 import 語句,也就是在 JSP 的開頭寫下:

<%@page import="cc.openhome.model.*, java.util.*" %>

再來的這邊:

        out.println("    <tr>");
        out.println("      <td><a href=\"http://" +
           bookmark.getUrl() + "\">" +
           bookmark.getTitle() + "</a></td>");
        out.println("      <td>" +
                bookmark.getCategory() + "</td>");
        out.println("    </tr>");

這當中夾雜了 HTML 與 Java 物件取值的動作,這可以轉換為以下:

            <tr>
                <td><a href="http://<%= bookmark.getUrl()%>">
                         <%= bookmark.getTitle()%></a></td>
                <td><%= bookmark.getCategory()%></td>
            </tr>

HTML 的部份直接撰寫即可,至於 Java 物件取值的動作,可以透過運算(Expression)元素,也就是 <%=%> 來包括。接著注意到,之前用 <%%> 包括的部份,forEach 方法的區塊語法並沒有完成,因為還少了個 },所以必須再補上:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>觀看線上書籤</title>
    </head>
    <body>
        <table style="text-align: left; width: 100%;" border="0">
            <tbody>
                <tr>
                    <td style="background-color: rgb(51, 255, 255);">網頁</td>
                    <td style="background-color: rgb(51, 255, 255);">分類</td>
                </tr>   
<%
                         });
%>

最後:

    out.println("  </tbody>");
    out.println("</table>");
    out.println("</body>");
    out.println("</html>");

可以在JSP中直接寫下:

            </tbody>
        </table>
    </body>
</html>

所完成的JSP頁面完整結果如下:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page import="cc.openhome.model.*, java.util.*" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>觀看線上書籤</title>
    </head>
    <body>
        <table style="text-align: left; width: 100%;" border="0">
            <tbody>
                <tr>
                    <td style="background-color: rgb(51, 255, 255);">網頁</td>
                    <td style="background-color: rgb(51, 255, 255);">分類</td>
                </tr>
<%
         BookmarkService bookmarkService = 
            (BookmarkService) application.getAttribute("bookmarkService");
         bookmarkService.getBookmarks()
                        .forEach(bookmark -> {
%>
            <tr>
                <td><a href="http://<%= bookmark.getUrl()%>">
                         <%= bookmark.getTitle()%></a></td>
                <td><%= bookmark.getCategory()%></td>
            </tr>

<%
                         });
%>
            </tbody>
        </table>
    </body>
</html>

雖然 HTML 與 Java 程式碼夾雜的情況仍在,但至少 HTML 撰寫的部份輕鬆多了,如果你想要進一步消除 Java 程式碼,則可以嘗試使用 JSTL 之類的自訂標籤,這在之後還會說明。

最主要的是了解,每個 JSP 中的元素,都可以對照至 Servlet 中某個元素或程式碼,所以要了解 JSP,必先了解 Servlet,你也可以嘗試看看這個 JSP 轉譯後的 Servlet 程式碼,就更能了解兩者之間的關係。