ステップ3:プログラムの記述
GAEプロジェクトの生成によって、「Hello world!」を表示する簡単なサンプルプログラム(サーブレットとHTML)が自動生成されます。生成されているプログラムのコードを上書きするのが効率的です。
[A]サーブレットコードの記述
最初にサーブレットですが、ここでは自動生成されるサーブレット名GuestbookServletをそのまま使用してコードをリスト1で上書きします。ただしpackage指定は、プロジェクト生成時に指定したpackage名に修正してください。
package guestbook;
import com.google.appengine.api.rdbms.AppEngineDriver; //(1)
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class GuestbookServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html; charset=utf-8"); //(2)
PrintWriter out = resp.getWriter();
Connection con = null;
try {
DriverManager.registerDriver(new AppEngineDriver()); //(3)
con = DriverManager.getConnection("jdbc:google:rdbms://branecosmology:cloudsqlsample/guestbook"); //(4)
String fname = req.getParameter("fname");
String content = req.getParameter("content");
if (fname == "" || content == "") {
out.println("<html><body>メッセージまたは名前が入力されていません。 3秒後に画面が再表示されます..</body></html>");
} else {
String statement ="INSERT INTO entries (guestName, content) VALUES( ? , ? )"; //(5)
PreparedStatement stmt = con.prepareStatement(statement);
stmt.setString(1, fname);
stmt.setString(2, content);
int success = 2;
success = stmt.executeUpdate(); //(6)
if(success == 1) {
out.println("<html><body>成功!! 3秒後 に画面が再表示されます..</body></html>");
} else if (success == 0) {
out.println("<html><body>失敗! やり直してください! 3秒後に画面が再表示されます..</body></html>");
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (con != null)
try {
con.close();
} catch (SQLException ignore) {
}
}
resp.setHeader("Refresh","3; url=/guestbook.jsp"); //(7)
}
}
このサーブレットはRDBアクセスを行うごく普通のコードに見えますが、ポイントになる点を述べてみます。
-
(1)JDBCドライバの指定
import com.google.appengine.api.rdbms.AppEngineDriver;
Cloud SQLを使用するJavaアプリケーションでは専用のドライバ(JDBCドライバ)を使用する必要がありますが、Eclipse用のGoogle Pluginにはこの専用ドライバが用意されており、上記のimport文で指定します。
-
(2)日本語表示に対応
resp.setContentType("text/html; charset=utf-8");GoogleのCloud SQLサイトにはサンプルが掲載されていますが、この記述がないためそのまま使用した場合日本語の文字バケが発生します。当然の指定とも言えますが、確認のためここで取り上げています。
-
(3)専用ドライバをDriverManagerに登録
DriverManager.registerDriver(new AppEngineDriver());
専用ドライバのインスタンスを生成し、これをJDBCドライバとしてDriverManagerに登録しています。
-
(4)指定されたデータベースへの接続
con = DriverManager.getConnection("jdbc:google:rdbms://branecosmology:cloudsqlsample/guestbook");指定されたデータベースのURLへ接続を行っています。データベース接続ではユーザー名とパスワードを指定できます。設定するにはまず、SQL Prompt画面からGRANT文でユーザーとパスワードを作成します。例えば、パスワード「pass1」のユーザー「user1」に、すべてのデータベース/テーブルに対して登録と参照を許可する場合には次のSQL文を実行します。
GRANT INSERT,SELECT ON *.* TO user1 IDENTIFIED BY 'pass1';
次に、リスト1でデータベース接続を行う(4)を次のように変更します。
con = DriverManager.getConnection("jdbc:google:rdbms://branecosmology:cloudsqlsample/guestbook", "user1", "pass1"); -
(5)~(6)SQL文の指定と実行
(5)で登録用のSQL文を指定していますが、通常のMySQLのSQL文です。ここでは動的SQLを使用しているため、SQL文の値指定では「?」を使用し、実際の値はその下のsetStringメソッドで文字列として指定されています。ここまででSQL文実行の準備は完了し、その後(6)の.executeUpdate()で登録を実行しています。
-
(7)JSPのリダイレクト指定
メッセージの登録では、3秒で画面が再表示されますが、これは(6)のsetHeaderメソッドで行われています。
setHeaderはクライアントにレスポンスを返す際にヘッダーを新規に追加したり上書きしたりできます。ここでは3秒後に、JSPのページに自動的にジャンプすることを指定していますが、これはHTMLヘッダで<meta http-equiv="refresh" content="3;URL=/guestbook.jsp">と指定しているのと等価です。
[B]JSPの記述
次に、JSPのコード記述を行います。JSPでは、画面ロード時に登録済のメッセージを全件表示し、その下のHTMLで記述されたフォームから新しいメッセージを登録するようになっています。Cloud SQL用のJDBCドライバ設定などは、サーブレットのサンプルで確認しているので問題ありません。そのほかは、普通のJSPプログラムです。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.List" %>
<%@ page import="java.sql.*" %>
<%@ page import="com.google.appengine.api.rdbms.AppEngineDriver" %>
<html>
<body>
<%
Connection con = null;
con = DriverManager.getConnection("jdbc:google:rdbms://branecosmology:cloudsqlsample/guestbook");
ResultSet rs = con.createStatement().executeQuery("SELECT guestName, content, entryID FROM entries"); //(1)
%>
<table border="1" bordercolor="#bbbbbb" cellspacing="0" cellpadding="0" width="440">
<tr>
<th width="22%" style="background-color: #CCFFCC; margin: 5px">名前</th>
<th style="background-color: #CCFFCC; margin: 5px">メッセージ</th>
<th width="7%" style="background-color: #CCFFCC; margin: 5px">ID</th>
</tr>
<%
while (rs.next()){ //(2)
String guestName = rs.getString("guestName");
String content = rs.getString("content");
int id = rs.getInt("entryID");
%>
<tr>
<td><%= guestName %></td>
<td><%= content %></td>
<td><%= id %></td>
</tr>
<% }
con.close(); %>
</table>
<hr />
<p><strong>ゲストブックにメッセージ書き込み</strong></p>
<form action="/sign" method="post">
<div>名前: <input type="text" name="fname" /></div>
<div>メッセージ:
<br /><textarea name="content" rows="3" cols="60"></textarea>
</div>
<div><input type="submit" value="メッセージ送信" /></div>
<input type="hidden" name="guestbookName" />
</form>
</body>
</html>
[C]web.xmlの記述
自動生成されているweb.xmlを、次のように修正します。
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>sign</servlet-name>
<servlet-class>guestbook.GuestbookServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sign</servlet-name>
<url-pattern>/sign</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>guestbook.jsp</welcome-file>
</welcome-file-list>
</web-app>
