My favorites | 中文(繁體) | Sign in
英文版或許有比此中譯版新的內容

使用 JSP

雖然我們可以直接從 Java servlet 程式碼為使用者介面輸出 HTML,但是隨著 HTML 越來越複雜,維護將變得十分困難。建議您使用範本系統,其使用者介面已經過設計並實作至個別檔案,您只需要使用位置保留元和邏輯插入應用程式所提供的資料即可。我們為 Java 提供許多範本系統,且每個範本系統都能夠與「應用服務引擎」搭配使用。

在本教學課程中,我們將使用 JavaServer Page (JSP) 實作訪客留言板的使用者介面。JSP 屬於 servlet 標準。「應用服務引擎」會自動在應用程式的 WAR 中編譯 JSP 檔案,然後將它們對應至 URL 路徑。

JSP,您好!

我們的訪客留言板應用程式會將字串寫入輸出串流,不過這也可以寫成 JSP。讓我們將最新版本的範例移植到 JSP,從這個步驟著手。

war/ 目錄中,建立具備下列內容的 guestbook.jsp 檔案:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.google.appengine.api.users.User" %>
<%@ page import="com.google.appengine.api.users.UserService" %>
<%@ page import="com.google.appengine.api.users.UserServiceFactory" %>

<html>
  <body>

<%
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();
    if (user != null) {
%>
<p>Hello, <%= user.getNickname() %>! (You can
<a href="<%= userService.createLogoutURL(request.getRequestURI()) %>">sign out</a>.)</p>
<%
    } else {
%>
<p>Hello!
<a href="<%= userService.createLoginURL(request.getRequestURI()) %>">Sign in</a>
to include your name with greetings you post.</p>
<%
    }
%>

  </body>
</html>

按照預設,所有在 war/ 或子目錄 (除了 WEB-INF/ 以外) 中,名稱結尾為 .jsp 的檔案都會自動對應至 URL 路徑。URL 路徑為 .jsp 檔的路徑,包括檔名。這個 JSP 將自動對應至 URL /guestbook.jsp

在訪客留言板應用程式中,我們希望以此做為應用程式的首頁,當人們存取 URL / 時即予以顯示。一個簡單的執行方法是,在 web.xml 中宣告 guestbook.jsp 為該路徑的「welcome」servlet。

編輯 war/WEB-INF/web.xml 並以此取代 <welcome-file-list> 目前的 <welcome-file> 元素。請務必從清單中移除 index.html,因為靜態檔案的優先性高於 JSP 和 servlet。

    <welcome-file-list>
        <welcome-file>guestbook.jsp</welcome-file>
    </welcome-file-list>

提示:如果您使用的是 Eclipse,編輯器可能會使用「Design」(設計) 模式開啟這個檔案。如要使用 XML 模式編輯這個檔案,請選取框架下方的 [Source] (原始碼) 標籤。

停止再啟動開發伺服器。瀏覽下列 URL:

應用程式會顯示 guestbook.jsp 的內容,包括使用者的暱稱 (如果使用者已登入)。

當您首次載入 JSP 時,開發伺服器會將 JSP 轉換成 Java 原始程式碼,然後將 Java 原始碼編譯成 Java 位元組碼。Java 原始碼和經過編譯的類別會儲存至暫存目錄。如果原始的 JSP 檔案遭到變更,開發伺服器將自動重新產生與編譯 JSP。

當您將應用程式上傳至「應用服務引擎」時,SDK 會將所有的 JSP 編譯成位元組碼,然後只上傳位元組碼。當您的應用程式在「應用服務引擎」上執行時,它會使用經過編譯的 JSP 類別。

訪客留言板表單

我們的訪客留言板應用程式需要網頁表單,以便使用者張貼新的訊息,另外它還需要表單處理方法。表單的 HTML 會嵌入 JSP。表單的目的地會是一個新的 URL (/sign),而這個 URL 將由新的 servlet 類別 (SignGuestbookServlet) 負責處理。SignGuestbookServlet 會處理表單,然後將使用者的瀏覽器重新導向 /guestbook.jsp。 就目前來說,新的 servlet 會將張貼的訊息寫入記錄。

編輯 guestbook.jsp,並在結尾的 </body> 標記上方加入下列程式碼:

  ...

  <form action="/sign" method="post">
    <div><textarea name="content" rows="3" cols="60"></textarea></div>
    <div><input type="submit" value="Post Greeting" /></div>
  </form>

  </body>
</html>

guestbook 套件中建立 SignGuestbookServlet 新類別。(非 Eclipse 使用者,請在 src/guestbook/ 中建立 SignGuestbookServlet.java 檔案)。請為來源檔案設定下列內容:

package guestbook;

import java.io.IOException;
import java.util.logging.Logger;
import javax.servlet.http.*;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class SignGuestbookServlet extends HttpServlet {
    private static final Logger log = Logger.getLogger(SignGuestbookServlet.class.getName());

    public void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();

        String content = req.getParameter("content");
        if (content == null) {
            content = "(No greeting)";
        }
        if (user != null) {
            log.info("Greeting posted by user " + user.getNickname() + ": " + content);
        } else {
            log.info("Greeting posted anonymously: " + content);
        }
        resp.sendRedirect("/intl/zh-TW/guestbook.jsp");
    }
}

編輯 war/WEB-INF/web.xml 並添加下列程式碼以宣告 SignGuestbookServlet servlet,然後將它對應至 /sign URL:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    ...

    <servlet>
        <servlet-name>sign</servlet-name>
        <servlet-class>guestbook.SignGuestbookServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sign</servlet-name>
        <url-pattern>/sign</url-pattern>
    </servlet-mapping>

    ...
</web-app>

這個新的 servlet 使用 java.util.logging.Logger 類別,將訊息寫入記錄。您可以使用 logging.properties 檔案控制這個類別的行為,以及在應用程式的 appengine-web.xml 檔案中所設定的系統屬性。如果您使用的是 Eclipse,您的應用程式會使用這個檔案 (位於應用程式的 src/ 中) 的預設版本以及適當的系統屬性完成建立。

如果您使用的不是 Eclipse,您必須手動設定 Logger 設定檔。將範例檔案從 SDK 的 appengine-java-sdk/config/user/logging.properties 複製到應用程式的 war/WEB-INF/ 目錄。然後,按照所述指示,編輯應用程式的 war/WEB-INF/appengine-web.xml 檔:

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    ...

    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>

</appengine-web-app>

Servlet 會使用 INFO 記錄等級 (使用 log.info()) 記錄訊息。預設的記錄等級為 WARNING,它會抑制來自輸出的 INFO 訊息。如要變更 guestbook 套件中所有類別的記錄等級,請編輯 logging.properties 檔並新增 guestbook.level 的項目,如下所示:

.level = WARNING
guestbook.level = INFO

...

提示:當「應用服務引擎」的執行應用程式透過 java.util.logging.Logger API 記錄訊息時,「應用服務引擎」會記錄訊息,且可以透過「管理控制台」顯示記錄,也可以透過 AppCfg 工具提供下載。「管理控制台」可讓您按照記錄等級瀏覽訊息。

重新建置與重新啟動,然後測試 http://localhost:8080/。表單隨即顯示。在表單輸入一些文字,然後提交。瀏覽器會將表單傳送給應用程式,然後重新導向空白表單。伺服器會將您輸入的訊息資料記錄到控制台。

接下來...

我們有一個使用者介面,可提示使用者輸入訊息。現在,我們需要一種方法記住使用者張貼的訊息,再向其他的訪客顯示。為此,我們將使用「應用服務引擎」資料存放區。

繼續瀏覽「透過 JDO 使用資料存放區」一節。