English
Skip to page content Skip to main navigation

e.g. "templates" or "datastore"

# Using JSPs

While we could output the HTML for our user interface directly from the Java servlet code, this would be difficult to maintain as the HTML gets complicated. It's better to use a template system, with the user interface designed and implemented in separate files with placeholders and logic to insert data provided by the application. There are many template systems available for Java, any of which would work with App Engine.

For this tutorial, we'll use JavaServer Pages (JSPs) to implement the user interface for the guest book. JSPs are part of the servlet standard. App Engine compiles JSP files in the application's WAR automatically, and maps them to URL paths.

## Hello, JSP!

Our guest book app writes strings to an output stream, but this could also be written as a JSP. Let's begin by porting the latest version of the example to a JSP.

In the directory `war/`, create a file named `guestbook.jsp` with the following contents:

    <%@ 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>

By default, any file in `war/` or a subdirectory (other than `WEB-INF/`) whose name ends in `.jsp` is automatically mapped to a URL path. The URL path is the path to the `.jsp` file, including the filename. This JSP will be mapped automatically to the URL `/guestbook.jsp`.

For the guest book app, we want this to be the application's home page, displayed when someone accesses the URL `/`. An easy way to do this is to declare in `web.xml` that `guestbook.jsp` is the "welcome" servlet for that path.

Edit `war/WEB-INF/web.xml` and replace the current `<welcome-file>` element in the `<welcome-file-list>`. Be sure to remove `index.html` from the list, as static files take precedence over JSP and servlets.

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

Tip: If you are using Eclipse, the editor may open this file in "Design" mode. To edit this file as XML, select the "Source" tab at the bottom of the frame.

Stop then start the development server. Visit the following URL:

- http://localhost:8080/

The app displays the contents of `guestbook.jsp`, including the user nickname if the user is signed in.

When you load a JSP for the first time, the development server converts the JSP into Java source code, then compiles the Java source into Java bytecode. The Java source and the compiled class are saved to a temporary directory. The development server regenerates and compiles JSPs automatically if the original JSP files change.

When you upload your application to App Engine, the SDK compiles all JSPs to bytecode, and only uploads the bytecode. When your app is running on App Engine, it uses the compiled JSP classes.

## The Guestbook Form

Our guest book application will need a web form so the user can post a new greeting, and a way to process that form. The HTML of the form will go into the JSP. The destination of the form will be a new URL, `/sign`, to be handled by a new servlet class, `SignGuestbookServlet`. `SignGuestbookServlet` will process the form, then redirect the user's browser back to `/guestbook.jsp`. For now, the new servlet will just write the posted message to the log.

Edit `guestbook.jsp`, and put the following lines just above the closing `</body>` tag:

      ...

      <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>

Create a new class named `SignGuestbookServlet` in the package `guestbook`. (Non-Eclipse users, create the file `SignGuestbookServlet.java` in the directory `src/guestbook/`.) Give the source file the following contents:

    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("/guestbook.jsp");
        }
    }

Edit `war/WEB-INF/web.xml` and add the following lines to declare the `SignGuestbookServlet` servlet and map it to the the `/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>

This new servlet uses the `java.util.logging.Logger` class to write messages to the log. You can control the behavior of this class using a `logging.properties` file, and a system property set in the app's `appengine-web.xml` file. If you are using Eclipse, your app was created with a default version of this file in your app's `src/` and the appropriate system property.

If you are not using Eclipse, you must set up the Logger configuration file manually. Copy the example file from the SDK `appengine-java-sdk/config/user/logging.properties` to your app's `war/WEB-INF/` directory. Then edit the app's `war/WEB-INF/appengine-web.xml` file as indicated:

    <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>

The servlet logs messages using the `INFO` log level (using `log.info()`). The default log level is `WARNING`, which suppresses `INFO` messages from the output. To change the log level for all classes in the `guestbook` package, edit the `logging.properties` file and add an entry for `guestbook.level`, as follows:

    .level = WARNING
    guestbook.level = INFO

    ...

Tip: When your app logs messages using the java.util.logging.Logger API while running on App Engine, App Engine records the messages and makes them available for browsing in the Admin Console, and available for downloading using the AppCfg tool. The Admin Console lets you browse messages by log level.

Rebuild and restart, then test http://localhost:8080/. The form displays. Enter some text in the form, and submit. The browser sends the form to the app, then redirects back to the empty form. The greeting data you entered is logged to the console by the server.

## Next...

We have a user interface for prompting the user to enter a greeting. Now we need a way to remember the greetings users post, and show them to other visitors. For that, we'll use the App Engine datastore.

Continue to Using the Datastore with JDO.