2013年11月10日日曜日

JSP のリファレンス

JSP タグ
<% java-code %> スクリプトレット
<%! declaration %> 宣言
<%= expression %><%-- comment --%> コメント
<%@ dir-type dir-attr %> ディレクティブ
<jsp:action ... > アクション
 スクリプトレット
<% java-code %>
Java コードを記述
 宣言
<%! declaration %>
JSP サーブレットのメンバ変数やメソッドを定義
 
<%= expression %>
式を評価した結果を出力
 ディレクティブ
<%@ dir-type dir-attr %>
JSP に関するサーバへの指示
  ディレクティブ: page
<%@ page attribute="value" %>
JSP の属性
   属性: language
<%@ page language="java" %>
使用する言語
   属性: contentType
<%@ page contentType="MIME-type[; charset=character-encoding]" %>
レスポンスの MIME タイプ、レスポンスと JSP ファイルが使用している文字コード
   属性: pageEncoding
<%@ page pageEncoding="encoding" %>
JSP ファイルが使用している文字コード
   属性: import
<%@ page import="package.Class" %>
使用するクラス
   属性: extends
<%@ page extends="package.ServletClass" %>
JSP のスーパークラス
   属性: buffer
<%@ page buffer="sizekb|none" %>
レスポンスをバッファするサイズ
   属性: autoFlush
<%@ page autoFlush="true|false" %>
レスポンスのバッファがいっぱいになったときにクライアントに送信を開始するか
   属性: isThreadSafe
<%@ page isThreadSafe="true|false" %>
リクエストが同時に処理されるか
   属性: isELIgnored
<%@ page isELIgnored="true|false" %>
EL を無視するか
   属性: isScriptingEnabled
<%@ page isScriptingEnabled="true|false" %>
スクリプトを有効にするか
   属性: info
<%@ page info="text" %>
サーブレットの情報文字列
   属性: isErrorPage
<%@ page isErrorPage="true|false" %>
エラーページか
   属性: errorPage
<%@ page errorPage="url" %>
例外が発生したときに表示するエラーページ
  ディレクティブ: taglib
<%@ taglib uri="taglib-uri" prefix="prefix" [tagdir="tagdir"] %>
taglib を使用
  ディレクティブ: include
<%@ include file="path" %>
ファイルをインクルード
 アクション
<jsp:action ... >
JavaBean の操作やリクエストの転送など
   アクション: useBean
<jsp:useBean id="name" [beanName="beanName"] [class="class"] [type="type"] [scope="scope"] />
<jsp:useBean id="name" [beanName="beanName"] [class="class"] [type="type"] [scope="scope"]>
    JavaBean をインスタンス化するときの本文
</jsp:useBean>
JavaBean オブジェクトを取得・作成
   アクション: setProperty
<jsp:setProperty name="name" property="propertyName" [value="value"] [param="param"] />
JavaBean のプロパティに値を設定
   アクション: getProperty
<jsp:getProperty name="name" property="propertyName" />
JavaBean のプロパティの値を取得
   アクション: forward
<jsp:forward page="path" />
<jsp:forward page="path">
    <jsp:param name="name" value="value" />
    ...
</jsp:forward>
リクエストの転送
   アクション: include
<jsp:include page="path" flush="true|false" />
<jsp:include page="path" flush="true|false">
    <jsp:param name="name" value="value" />
    ...
</jsp:include>
リクエストのインクルード
   アクション: plugin
<jsp:plugin type="applet" code="class" codebase="codebase" ...>
    <jsp:params>
        <jsp:param name="name" value="value" />
        ...
    </jsp:params>
    <jsp:fallback>
        サポートされていないブラウザ用の HTML
    </jsp:fallback>
</jsp:plugin>
アプレットのデプロイメント
暗黙的オブジェクト
 request javax.servlet.HttpServletRequest オブジェクト
 response javax.servlet.HttpServletResponse オブジェクト
 out javax.jsp.JspWriter のインスタンス
 pageContext javax.servlet.jsp.PageContext オブジェクト
 session javax.servlet.http.HttpSession オブジェクト
 application javax.servlet.ServletContext オブジェクト
 config javax.servlet.ServletConfig オブジェクト
 page JSP ページから生成されたサーブレットのインスタンス

JSP タグ
短縮形:
<% java-code %> スクリプトレット
<%! declaration %> 宣言
<%= expression %><%-- comment --%> コメント
<%@ dir-type dir-attr %> ディレクティブ
<jsp:action ... > アクション
XML 形式:
<jsp:scriptlet>java-code</jsp:scriptlet> スクリプトレット
<jsp:declaration>declaration;</jsp:declaration> 宣言
<jsp:expression>expression</expression><jsp:directive.dir-type dir-attr /> ディレクティブ
 JSP に関するサーバへの指示を行います。

 <div> <a> などの HTML タグに似ていますが、HTML はクライアント側でブラウザが解釈されるのに対し、JSP はサーバ側で解釈・実行されます。

スクリプトレット
<% java-code %>
 Java コードを記述します。

使用例:
<%
    String message = "abc";
    out.println(message + "<br />");
%>

宣言
<%! declaration %>
 JSP サーブレットのメンバ変数やメソッドを定義します。

 Serlvet でメンバ変数やメソッドを定義するのと同等です。そのため、オブジェクトは複数のリクエスト間でマルチスレッドで共有されます。

使用例:
<%!
    String message = "abc";

    private String getMessage() {
        return message;
    }
%>


<%= expression %>
 式を評価し、結果を出力します。

使用例:
<%= getMessage() %>

ディレクティブ
<%@ dir-type dir-attr %>
 JSP に関するサーバへの指示を行います。

ディレクティブ: page
<%@ page attribute="value" %>
 JSP ページ内の属性を指定します。

使用例:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="test.model.*" %>

属性: language
<%@ page language="java" %>
デフォルト:
<%@ page language="java" %>
 使用する言語を指定します。使用できる言語は java です。

属性: contentType
<%@ page contentType="MIME-type[; charset=character-encoding]" %>
デフォルト:
<%@ page contentType="text/html; charset=ISO-8859-1" %>
 レスポンスの MIME タイプと、レスポンスおよび JSP ファイルが使用している文字コードを指定します。

 include された JSP 内では無視され、include 元の JSP ファイルの指定が使用されます。

使用例: 次を参照

属性: pageEncoding
<%@ page pageEncoding="encoding" %>
デフォルト:
<%@ page pageEncoding="ISO-8859-1" %>
 JSP ファイルが使用している文字コードを指定します。contentType でも指定できますが、こちらの指定が優先されます。

 レスポンスの文字コードと JSP ファイルが使用している文字コードが違う場合は、contentType でレスポンスの文字コードを、pageEncoding で JSP ファイルが使用している文字コードを指定します。

 include された JSP 内では contentType の指定は無視されるため、pageEncoding で JSP ファイルが使用している文字コードを指定します。

使用例:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP test</title>
</head>
<body>
JSP test<br />
<%@ include file="include.jsp" %>
</body>
</html>
include.jsp
<%@ page language="java" pageEncoding="UTF-8" %>
included page<br />
出力結果:
JSP test
included page

属性: import
<%@ page import="package.Class" %>
 使用するクラスのパッケージ名を省略する場合、パッケージを特定するために指定します。Java の import と同等です。

 以下のパッケージはデフォルトでインポートされています。
java.lang.*
javax.servlet.*
javax.servlet.jsp.*
javax.servlet.http.*

 複数指定する場合に ,(カンマ)や *(アスタリスク)を使用できます。
<%@ page import="java.io.*, java.sql.*" %>
使用例:
<%@ page import="java.util.Date" %>
<%=new Date() %>
出力結果:
Mon Nov 04 02:38:51 JST 2013

属性: extends
<%@ page extends="package.ServletClass" %>
 スーパークラスとなる Servlet クラスを指定します。

 処理の共通化やフィルタリングなどの使用例が考えられますが、Filter などの別の方法を使用するべきでしょう。

使用例:
package test.servlet;

import org.apache.jasper.runtime.HttpJspBase;

public abstract class MyJspServlet extends HttpJspBase {
 private static final long serialVersionUID = 1L;

 protected String myMessage() {
  return "subclass of MyJspServlet";
 }
}
<%@ page extends="test.servlet.MyJspServlet" %>
<%=myMessage() %>
出力結果:
subclass of MyJspServlet

属性: buffer
<%@ page buffer="sizekb|none" %>
デフォルト:
<%@ page buffer="8kb" %>
 出力されるレスポンスをバッファリングするサイズを指定します。none を指定するとバッファリングされません。

属性: autoFlush
<%@ page autoFlush="true|false" %>
デフォルト:
<%@ page autoFlush="true" %>
 バッファがいっぱいになったときに自動的にクライアントに転送を開始するかを指定します。

 false を指定した場合、バッファがいっぱいになった、あるいは buffer="none" を指定していた場合は例外が発生します。

属性: isThreadSafe
<%@ page isThreadSafe="true|false" %>
デフォルト:
<%@ page isThreadSafe="true" %>
 このページへのリクエストが同時に処理されるかを指定します。

属性: isELIgnored
<%@ page isELIgnored="true|false" %>
デフォルト:
<%@ page isELIgnored="false" %>
 EL を無視するかを指定します。

属性: isScriptingEnabled
<%@ page isScriptingEnabled="true|false" %>
デフォルト:
<%@ page isScriptingEnabled="true" %>
 スクリプトを有効にするかを指定します。

※当方の環境(JDK 1.7, Servlet 3.0, Tomcat 7.x)では
Page directiveは無効な属性を持っています: isScriptingEnabled
という例外が発生して使用できませんでした。

属性: info
<%@ page info="text" %>
 Servlet.getServletInfo() が返す文字列を指定します。作者、バージョン、著作権といった Servlet に関する情報を指定します。

使用例:
<%@ page info="JSP test page, Copyright(C) 2013 matsushima." %>

属性: isErrorPage
<%@ page isErrorPage="true|false" %>
デフォルト:
<%@ page isErrorPage="false" %>

属性: errorPage
<%@ page errorPage="url" %>

ディレクティブ: taglib
<%@ taglib uri="taglib-uri" prefix="prefix" [tagdir="tagdir"] %>
 JSP ページ内の属性を指定します。

使用例:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

ディレクティブ: include
<%@ include file="path" %>
 現在の位置にファイルをインクルードします。
file
 インクルードするファイルのパスを指定します。サーバのサーブレットのローカル上のパスであり、URL ではありません。  / で始まる絶対パスを指定した場合は、ドキュメントルート(WebContent, src/main/webapp など)からのパスになります。  それ以外はインクルード元からの相対パスになります。
 JSP 以外のテキストファイルもインクルードすることができます。ただし <, などの文字はエスケープされるので注意してください。

使用例:
<%@ include file="/WEB-INF/jsp/header.jsp" %>

アクション
<jsp:action ... >
 JavaBean の操作やリクエストの転送などを行います。

アクション: useBean
<jsp:useBean id="name" beanName="beanName" class="class"
 type="type" scope="scope" />
<jsp:useBean id="name" beanName="beanName" class="class"
 type="type" scope="scope">
    JavaBean をインスタンス化するときの本文
</jsp:useBean>
 登録されている JavaBean オブジェクトを取得します。bean が登録されていなければ新たにインスタンス化します。
id (必須)
bean の名前。setAttribute() で登録された属性名と、JSP で参照するときの変数名を表します。
class (beanName と同時指定不可)
bean の実体クラス。setAttribute() で登録されたオブジェクトのデータ型と、JSP でインスタンス化する場合のクラスを表します。
abstract class や interface は指定できません。
type (beanName 指定時必須、class 未指定時必須)
bean のデータ型。JSP で参照するときのデータ型を表します。実体クラスからキャストできる型でなければなりません。
beanName (class と同時指定不可)
bean の名前。bean をインスタンス化する場合、java.beans.Beans.instantiate() によって使用される、シリアライズされたオブジェクトの名前または JSP 式、またはクラスの名前を表します。
scope
bean のスコープ。page, request, session, application のいずれかを指定します。省略した場合は page です。
 id で指定された名前で、scope で指定されたスコープ内に登録された bean が取得されます。
bean が登録されていない場合、class または beanName のいずれかの指定によってインスタンス化されます。どちらも指定しない場合や引数なしのコンストラクタをクラスを指定した場合など、インスタンス化できない場合は例外が発生するため、必ず登録しておく必要があります。

bean の登録例:
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		// request スコープでの登録:
		TestBean requestBean = new TestBean();
		requestBean.setMessage(String.format("request bean %1$tF %1$tT", new Date()));
		request.setAttribute("requestBean", requestBean);

		// session スコープでの登録:
		TestBean sessionBean = new TestBean();
		sessionBean.setMessage(String.format("application bean %1$tF %1$tT", new Date()));
		request.getSession().setAttribute("sessionBean", sessionBean);

		// application スコープでの登録:
		TestBean applicationBean = new TestBean();
		applicationBean.setMessage(String.format("application bean %1$tF %1$tT", new Date()));
		this.getServletContext().setAttribute("applicationBean", applicationBean);

		getServletContext().getRequestDispatcher("/WEB-INF/jsp/jsptest.jsp").forward(request, response);
	}
<%@ page import="test.model.TestBean" %>
<%
	// page スコープでの登録(JSP):
	TestBean pageJspTempBean = new TestBean();
	pageJspTempBean.setMessage(String.format("page jsp bean %1$tF %1$tT", new Date()));
	pageContext.setAttribute("pageJspBean", pageJspTempBean);

	// request スコープでの登録(JSP):
	TestBean requestJspTempBean = new TestBean();
	requestJspTempBean.setMessage(String.format("request jsp bean %1$tF %1$tT", new Date()));
	request.setAttribute("requestJspBean", requestJspTempBean);

	// session スコープでの登録(JSP):
	TestBean sessionJspTempBean = new TestBean();
	sessionJspTempBean.setMessage(String.format("application jsp bean %1$tF %1$tT", new Date()));
	session.setAttribute("sessionJspBean", sessionJspTempBean);

	// application スコープでの登録(JSP):
	TestBean applicationJspTempBean = new TestBean();
	applicationJspTempBean.setMessage(String.format("application jsp bean %1$tF %1$tT", new Date()));
	application.setAttribute("applicationJspBean", applicationJspTempBean);
%>
bean の登録例:
page スコープでの取得:<br />
<jsp:useBean id="pageBean" class="test.model.TestBean" scope="page" />
<%=pageBean.getMessage() %><br />
<br />
request スコープでの取得:<br />
<jsp:useBean id="requestBean" class="test.model.TestBean" scope="request" />
<%=requestBean.getMessage() %><br />
<br />
session スコープでの取得:<br />
<jsp:useBean id="sessionBean" class="test.model.TestBean" scope="session" />
<%=sessionBean.getMessage() %><br />
<br />
application スコープでの取得:<br />
<jsp:useBean id="applicationBean" class="test.model.TestBean" scope="application" />
<%=applicationBean.getMessage() %><br />
<br />
page スコープでの取得(JSP):<br />
<jsp:useBean id="pageJspBean" class="test.model.TestBean" scope="page" />
<%=pageJspBean.getMessage() %><br />
<br />
request スコープでの取得(JSP):<br />
<jsp:useBean id="requestJspBean" class="test.model.TestBean" scope="request" />
<%=requestJspBean.getMessage() %><br />
<br />
session スコープでの取得(JSP):<br />
<jsp:useBean id="sessionJspBean" class="test.model.TestBean" scope="session" />
<%=sessionJspBean.getMessage() %><br />
<br />
application スコープでの取得(JSP):<br />
<jsp:useBean id="applicationJspBean" class="test.model.TestBean" scope="application" />
<%=applicationJspBean.getMessage() %><br />
実行結果:
page スコープでの取得:
null

request スコープでの取得:
request bean 2013/11/15 11:22:42

session スコープでの取得:
application bean 2013/11/15 11:22:42

application スコープでの取得:
application bean 2013/11/15 11:22:42

page スコープでの取得(JSP):
page jsp bean 2013/11/15 11:22:43

request スコープでの取得(JSP):
request jsp bean 2013/11/15 11:22:43

session スコープでの取得(JSP):
application jsp bean 2013/11/15 11:22:43

application スコープでの取得(JSP):
application jsp bean 2013/11/15 11:22:43
 EL を使用する場合は <jsp:useBean ... > は必要ありません。登録されたスコープが page, request, session, application の順で検索され bean が取得されます。

EL での取得例:
${requestBean.message}
 <jsp:useBean ... >本文</jsp:useBean> の形式では、bean がインスタンス化される際に本文が評価されます。

使用例:
request スコープでの取得:<br />
<jsp:useBean id="requestNewBean" class="test.model.TestBean" scope="request">
	create at jsp:useBean<br />
	<jsp:setProperty name="requestNewBean" property="message" value='<%=String.format("request new bean create at jsp:useBean %1$tF %1$tT", new Date()) %>' />
</jsp:useBean>
<%=requestNewBean.getMessage() %><br />
実行結果:
request スコープでの取得:
create at jsp:useBean
request new bean create at jsp:useBean 2013/11/15 12:30:43

アクション: setProperty
<jsp:setProperty name="name" property="propertyName" [value="value"] [param="param"] />
 JavaBean のプロパティに値を設定します。
name (必須)
bean の名前。<jsp:useBean> の id で指定した名前でなければなりません。
property (必須)
値を設定するプロパティ名。JavaBean の場合、プロパティの setter が呼ばれます。* を指定した場合、リクエストパラメータの値を対応するプロパティに設定します。
param (name="beanName" 指定時 value とどちらか必須、property="*" 指定時指定不可)
リクエストパラメータ名。指定されたリクエストパラメータの値をプロパティに設定します。
value (name="beanName" 指定時 param とどちらか必須、property="*" 指定時指定不可)
設定する値。文字列または JSP 式が使用できます。
使用例:
jsp:setProperty test<br />
<br />
URL: <%=request.getRequestURL() %><br />
queryString: <%=request.getQueryString() %><br />

<jsp:useBean id="setPropertyTestBean" class="test.model.TestBean" scope="request">
	<jsp:setProperty name="setPropertyTestBean" property="message" value="test" />
</jsp:useBean>
<br />
setPropertyTestBean(property="message" value="test"):<br />
<%=setPropertyTestBean.getMessage() %><br/>
<br />
setPropertyTestBean(property="message" param="name"):<br />
<jsp:setProperty name="setPropertyTestBean" property="message" param="name" />
<%=setPropertyTestBean.getMessage() %><br/>
<br />
setPropertyTestBean(property="*"):<br />
<jsp:setProperty name="setPropertyTestBean" property="*" />
<%=setPropertyTestBean.getMessage() %><br/>
出力結果:
jsp:setProperty test

URL: http://localhost:8080/servlet-test2/WEB-INF/jsp/jsptest.jsp
queryString: name=matsushima&message=param-value

setPropertyTestBean(property="message" value="test"):
test

setPropertyTestBean(property="message" param="name"):
matsushima

setPropertyTestBean(property="*"):
param-value

アクション: getProperty
<jsp:getProperty name="name" property="propertyName" [value="value"] [param="param"] />
 JavaBean のプロパティから値を取得します。
name (必須)
bean の名前。<jsp:useBean> の id で指定した名前でなければなりません。
property (必須)
値を取得するプロパティ名。JavaBean の場合、プロパティの getter が呼ばれます。
使用例:
jsp:getProperty test<br />
<br />
<jsp:useBean id="getPropertyTestBean" class="test.model.TestBean" scope="request">
	<jsp:setProperty name="getPropertyTestBean" property="message" value="test" />
</jsp:useBean>
<jsp:getProperty name="getPropertyTestBean" property="message" /><br />
jsp:getProperty test<br />
<br />
<jsp:useBean id="getPropBean" class="model.TestBean" scope="request">
	<jsp:setProperty name="getPropBean" property="message" value="test" />
</jsp:useBean>
<jsp:getProperty name="getPropBean" property="message" /><br />
出力結果:
jsp:getProperty test

test



暗黙的オブジェクト

スクリプトレットや式の中では、以下の暗黙オブジェクトが予約語が用意されています。

request

 javax.servlet.HttpServletRequest オブジェクトを表します。
cookie や HTTP ヘッダの取得や、request スコープ内のオブジェクトのアクセスなどを行います。
EL では pageContext.request を使用します。


使用例:
<%=request.getQueryString() %><br />
\${pageContext.request.getQueryString()}<br >
\${pageContext.request.queryString}<br >

<% for (Cookie c: request.getCookies()) { %>
<%=c.getName() %> = <%=c.getValue() %><br />
<% } %>

response

 javax.servlet.HttpServletResponse オブジェクトを表します。
cookie や HTTP ヘッダの設定などを行います。
EL では pageContext.response を使用します。
スクリプトレットからのレスポンスの出力には、response.getWriter() の代わりに out を使用してください。

使用例:
<%
    Cookie c = new Cookie("mycookie", "abc");
    c.setMaxAge(24 * 60 * 60);
    response.addCookie(c);

    response.setHeader("pragma", "no-cache");
    response.setHeader("Cache-Control", "no-cache");
%>

out

 javax.jsp.JspWriter のインスタンスを表します。
スクリプトレットからレスポンスの出力を行います。

使用例:
response sample<br />
<% out.println("out<br />"); %>

pageContext

 javax.servlet.jsp.PageContext オブジェクトを表します。

・page スコープ内のオブジェクトのアクセス
・page, request, response, session などのオブジェクトへのアクセス
・page, request, session, application スコープ内のオブジェクトのアクセスの共通化
・forward, include などのページ制御
などを行います。

session

 javax.servlet.http.HttpSession オブジェクトを表します。
セッションの管理や、session スコープ内のオブジェクトのアクセスを行います。

setAttribute:

<% session.setAttribute("abc", "123"); %>


getCreationTime:

<%=new java.util.Date(session.getCreationTime()) %>


session attributes:

<% for (Enumeration e = session.getAttributeNames(); e.hasMoreElements(); ) {
String name = e.nextElement();
out.println(name + " = " + session.getAttribute(name) + "
");
}
%>

application

 javax.servlet.ServletContext オブジェクトを表します。
application スコープ内のオブジェクトのアクセスなど、サーブレット全体へのアクセスを行います。

setAttribute:

<% application.setAttribute("abc", "123"); %>


getCreationTime:

<%=new java.util.Date(session.getCreationTime()) %>


application attributes:

<% for (Enumeration e = application.getAttributeNames(); e.hasMoreElements(); ) {
String name = e.nextElement();
out.println(name + " = " + application.getAttribute(name) + "
");
break;
}
%>


init parameters:

<% for (Enumeration e = application.getInitParameterNames(); e.hasMoreElements(); ) {
String name = e.nextElement();
out.println(name + " = " + application.getInitParameter(name) + "
");
}
%>

  <context-param>
    <param-name>application param-name</param-name>
    <param-value>application param-value</param-value>
  </context-param>


config

 javax.servlet.ServletConfig オブジェクトを表します。
application スコープ内のオブジェクトのアクセスなど、ほかのサーブレットを含むサーブレット全体へのアクセスを行います。

servletName:

<%=config.getServletName() %>


initParameter:

<% for (Enumeration e = config.getInitParameterNames(); e.hasMoreElements(); ) {
String name = e.nextElement();
out.println(name + " = " + config.getInitParameter(name) + "
");
}
%>

<servlet>
  <servlet-name>WebServletTest</servlet-name>
  <servlet-class>test.annotation.WebServletTest</servlet-class>
  <init-param>
    <param-name>name</param-name>
    <param-value>HELLO!!</param-value>
  </init-param>
</servlet>
 
<servlet-mapping>
  <servlet-name>WebServletTest</servlet-name>
  <url-pattern>/test</url-pattern>
</servlet-mapping>

@WebServlet(urlPatterns = {"/JspTest"}, initParams={@WebInitParam(name = "config name", value = "config value")})
public class JspTestServlet extends HttpServlet {

page

 JSP ページから生成されたサーブレットのインスタンスを表します。
application スコープ内のオブジェクトのアクセスなど、ほかのサーブレットを含むサーブレット全体へのアクセスを行います。

1-5-2. Spring MVC 3 + Hibernate 4 + HSQLDB

HSQLDB を使用するように修正します。

HSQLDB は Java で実装された RDB で、ほかの RDB 同様サーバを起動して外部プロクラムから接続して使用するほか、JDBC ドライバだけで使用することも可能です。

■In-Process Access to Database Catalogs


JDBC ドライバから直接データベースエンジンが呼び出されるので、別途サーバを起動する必要がありません。
file
 指定されたパスにファイルとして保存します。
 接続文字列の例: jdbc:hsqldb:file:/opt/db/testdb
mem
 メモリ内にデータを保持します。アプリケーションを終了するとデータは破棄されます。
 接続文字列の例: jdbc:hsqldb:mem:mymemdb
res
 指定された Java パスの Java リソースを読み取り専用で使用します。
 接続文字列の例: jdbc:hsqldb:res:org.my.path.resdb
ファイルモードの使用例:
クライアントツールから接続(HSQL Database Manager の例):
    HSQL Database Manager を起動
        java -cp hsqldb-2.3.1.jar org.hsqldb.util.DatabaseManager
    接続先
        Type: HSQL Database Engine Standalone
        Driver: org.hsqldb.jdbcDriver
        URL: jdbc:hsqldb:file:testdb
        User: SA
        Password:
クライアントプログラムから接続:
    Class.forName("org.hsqldb.jdbcDriver");
    Connection c = DriverManager.getConnection("jdbc:hsqldb:file:testdb", "sa", "");

■Server Modes


HSQLDB をサーバモードで起動し、クライアントからはネットワーク経由で接続します。
Server
 HSQLDB をサーバモードで起動し、クライアントからはネットワーク経由で接続します。
Web Server
 HSQLDB を Web サーバモードで起動し、クライアントからはネットワーク経由で HTTP で接続します。
Servlet
 HSQLDB を Tomcat などにサーブレットとして配置し、クライアントからはネットワーク経由で HTTP で接続します。
サーバモードの使用例:
サーバ起動:
    java -cp ../lib/hsqldb.jar org.hsqldb.Server -database.0 file:mydb -dbname.0 xdb
クライアントツールから接続(HSQL Database Manager の例):
    HSQL Database Manager を起動
        java -cp hsqldb-2.3.1.jar org.hsqldb.util.DatabaseManager
    接続先
        Type: HSQL Database Engine Server
        Driver: org.hsqldb.jdbcDriver
        URL: jdbc:hsqldb:hsql://localhost/
        User: SA
        Password:
クライアントプログラムから接続:
    Class.forName("org.hsqldb.jdbcDriver");
    Connection c = DriverManager.getConnection("jdbc:hsqldb:hsql://localhost/xdb", "sa", "");

■テスト

サーバモード
 HSQLDB のサイト http://hsqldb.org/ から HSQLDB をダウンロード
 hsqldb-2.3.1.jar を展開
 サーバの起動
  java -cp hsqldb-2.3.1.jar org.hsqldb.Server
 HSQL Database Manager を起動
  java -cp hsqldb-2.3.1.jar org.hsqldb.util.DatabaseManager
 Connect
  Type: HSQL Database Engine Server
  URL: jdbc:hsqldb:hsql://localhost/
 テーブルの作成
  create table test_table (
  id integer,
  name varchar(100)
  )
  Execute
 データの追加
  insert into test_table values (
  1,
  'matsushima'
  )
  Execute
 データの表示
  select * from test_table
  Execute
 サーバの終了
  shutdown
  Execute
スタンドアロンモード(CSV ファイルに保存)
 HSQL Database Manager を起動
  java -cp hsqldb-2.3.1.jar org.hsqldb.util.DatabaseManager
 Connect
  Type: HSQL Database Engine Standalone
  URL: jdbc:hsqldb:file:C:\USR\SRC\TEST\java\data\data
 テーブルの作成
  create text table user_mst (
  id integer generated by default as identity (start with 1),
  loginid varchar(255),
  password varchar(255),
  name varchar(255),
  primary key (id));
  Execute
 CSV に保存を指定
  set table user_mst source 'user_mst.csv;encoding=UTF-8';
  Execute
 データの追加
  insert into user_mst (
  loginid,
  password,
  name
  ) values (
  'matsushima',
  'aaa',
  '松島'
  )
  Execute
 データの表示
  select * from user_mst
  Execute
 データの表示
  shutdown
  Execute

■上記で作成した CSV データを使用するように修正します。

pom.xml にライブラリを追加
    <dependency>
      <groupId>org.hsqldb</groupId>
      <artifactId>hsqldb</artifactId>
      <version>2.3.1</version>
    </dependency>
applicationContext.xml の DB 接続設定を修正
 dataSource bean の JDBC ドライバの設定を修正します。
 また、起動時に SQL を実行するように指定します。
  <!-- DB 接続設定。 -->
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <!-- <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/test" />
    <property name="username" value="root" />
    <property name="password" value="root" /> -->
    <property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" />
    <property name="url" value="jdbc:hsqldb:file:C:\usr\src\test\java\data\data;shutdown=true" />
    <property name="username" value="sa" />
    <property name="password" value="" />
  </bean>
  <jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
    <jdbc:script location="classpath:/setup.sql" />
  </jdbc:initialize-database>
起動時に実行する SQL の追加
 src/main/resources 配下に setup.sql の名前で追加します。
drop table user_mst if exists;
create text table user_mst (
id integer generated by default as identity (start with 1),
loginid varchar(255),
password varchar(255),
name varchar(255),
primary key (id));
set table user_mst source 'user_mst.csv;encoding=UTF-8';
サーバを起動し、ブラウザから http://localhost:8080/spring-test/login にアクセスします。
DB に登録したログインID、パスワードを入力してログインボタンをクリックし、
xxx さんこんにちは。と表示されれば OK です。

プロジェクトの最新版はこちらで公開しています。
https://github.com/matsushima-terunao/blog_java/

→ 1-6. 認証機能追加
← 1-5. Spring MVC 3 + Hibernate 4 + MySQL
↑ 一覧

2013年10月28日月曜日

1-6-1. 認証機能のカスタマイズ

前回作成した認証機能を、前々回までに作成した DB とログイン画面を使って認証するように修正します。

DB に直接接続して認証

applicationContext-security.xml を編集
 http にログインページの URL を指定し、さらにどのユーザからもこのページアクセスできるように設定します。
 authentication-manager で DB 接続設定として applicationContext.xml で登録した dataSource を指定し、ユーザー情報を取得する SQL 文を記述します。
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns="http://www.springframework.org/schema/security"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

  <!-- アクセス設定。 -->
  <http auto-config="true">
    <form-login login-page="/login" /> <intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/**" access="ROLE_USER" /> </http>
  <!-- アカウント情報。 --> <!-- <authentication-manager> <authentication-provider> <user-service> <user name="admin" password="admin" authorities="ROLE_SUPERVISOR, ROLE_USER" /> <user name="user" password="user" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager> -->
<!-- SQL で DB からユーザー情報を取得。 --> <authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select loginid as username, password, true as enabled from user_mst where loginid = ?" authorities-by-username-query="select loginid as username, 'ROLE_USER' as authority from user_mst where loginid = ?" /> </authentication-provider> </authentication-manager>
</beans:beans>
login.jsp の修正
 サーバーに送信するアドレスやパラメータ名を、前回表示されたログイン画面に合わせます。
エラーメッセージはセッションから取得できます。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!-- 
/**
 * ログインページ。
 * 
 * @author 2013/10/20 matsushima
 */
 -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>index</title>
</head>
<body>
	<form action="<%=request.getContextPath() %>/j_spring_security_check" method="post">
		<label for="loginid">ログインID</label>
		<input type="text" id="loginid" name="j_username" value="${user.loginid}" />
		<br />
		<label for="password">パスワード</label>
		<input type="password" id="password" name="j_password" value="${user.password}" />
		<br />
		<div style="color: red;">${message}${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}</div>
		<input type="submit" name="login" value="ログイン" />
	</form>
</body>
</html>
index.jsp
 username は SecurityContextHolder から取得できます。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>index</title>
</head>
<body>
index page<br />
<%--<% if (null != request.getAttribute("user")) { %> ${user.name} さんこんにちは。 <% } %>--%>
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %> <%@ page import="org.springframework.security.core.userdetails.UserDetails" %> <% if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails) { %> <%=((UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() %> さんこんにちは。 <% } %>
</body> </html>
サーバを起動し、ブラウザから http://localhost:8080/spring-test/index にアクセスします。
DB に登録したログインID、パスワードを入力してログインボタンをクリックし、
xxx さんこんにちは。と表示されれば OK です。


ユーザー情報取得コードを実装して認証

applicationContext-security.xml 編集
 authentication-provider に org.springframework.security.authentication.dao.DaoAuthenticationProvider を 指定します。
userDetailsService には UserDetailsService インターフェースを実装したクラスを指定します。
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns="http://www.springframework.org/schema/security"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

  <!-- アクセス設定。 -->
  <http auto-config="true">
    <form-login login-page="/login" />
    <intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/**" access="ROLE_USER" />
  </http>

  <!-- アカウント情報を指定して認証。 -->
  <!-- <authentication-manager>
    <authentication-provider>
      <user-service>
        <user name="admin" password="admin" authorities="ROLE_SUPERVISOR, ROLE_USER" />
        <user name="user" password="user" authorities="ROLE_USER" />
      </user-service>
    </authentication-provider>
  </authentication-manager> -->
  <!-- SQL で DB からユーザー情報を取得して認証。 -->
  <!-- <authentication-manager>
    <authentication-provider>
      <jdbc-user-service data-source-ref="dataSource"
        users-by-username-query="select loginid as username, password, true as enabled from user_mst where loginid = ?"
        authorities-by-username-query="select loginid as username, 'ROLE_USER' as authority from user_mst where loginid = ?"
      />
    </authentication-provider>
  </authentication-manager> -->
  <!-- UserDetailsService クラスを実装して認証。 --> <authentication-manager> <authentication-provider ref="authenticationProvider" /> </authentication-manager> <beans:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <beans:property name="userDetailsService" ref="userDetailsService" /> </beans:bean> <beans:bean id="userDetailsService" class="jp.matsushima.spring_test.service.UserDetailsServiceImpl" />
</beans:beans>
Service, DAO の実装
 UserDetailsService インターフェースを実装したクラスを実装します。
loadUserByUsername メソッドのパラメータに username が渡ってくるので、そこからユーザー情報を取得し、UserDetails bean で返します。
package jp.matsushima.spring_test.service;

import java.util.ArrayList;
import java.util.Collection;

import jp.matsushima.spring_test.dao.UserDao;
import jp.matsushima.spring_test.model.User;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * ユーザー情報サービス。
 * 
 * @author 2013/10/25 matsushima
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

	@Autowired
	private UserDao userDao;

	class MyUserDetails implements UserDetails {

		private static final long serialVersionUID = 1L;

		/** ユーザーマスタ。 */
		private User user;

		public MyUserDetails(User user) {
			super();
			this.user = user;
		}

		/**
		 * ユーザーマスタ。を取得します。
		 * @return ユーザーマスタ。
		 */
		public User getUser() {
		    return user;
		}

		/**
		 * ユーザーマスタ。を設定します。
		 * @param user ユーザーマスタ。
		 */
		public void setUser(User user) {
		    this.user = user;
		}

		@Override
		public Collection<? extends GrantedAuthority> getAuthorities() {
			System.out.println("getAuthorities");
			ArrayList<GrantedAuthority> result = new ArrayList<>();
			result.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
			result.add(new SimpleGrantedAuthority("ROLE_USER"));
			return result;
		}

		@Override
		public String getPassword() {
			System.out.println("getPassword");
			return user.getPassword();
		}

		@Override
		public String getUsername() {
			System.out.println("getUsername");
			return user.getLoginid();
		}

		@Override
		public boolean isAccountNonLocked() {
			System.out.println("isAccountNonLocked");
			return true;
		}

		@Override
		public boolean isEnabled() {
			System.out.println("isEnabled");
			return true;
		}

		@Override
		public boolean isAccountNonExpired() {
			System.out.println("isAccountNonExpired");
			return true;
		}

		@Override
		public boolean isCredentialsNonExpired() {
			System.out.println("isCredentialsNonExpired");
			return true;
		}
	}

	/**
	 * ユーザー名からユーザー情報を取得。
	 * 
	 * @param username
	 * @return
	 */
	@Override
	@Transactional
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		User user = userDao.selectByLoginid(username);
		return (null == user ? null : new MyUserDetails(user));
	}
}
package jp.matsushima.spring_test.dao;

import jp.matsushima.spring_test.model.User;

/**
 * ユーザーマスタ。
 * 
 * @author 2013/10/15 matsushima
 *
 */
public interface UserDao {

	/**
	 * ログイン ID、パスワードからユーザーを取得。
	 * 
	 * @param param
	 * @return
	 */
	public User selectForAuth(User param);

/** * ログイン ID からユーザーを取得。 * * @param loginid * @return */ public User selectByLoginid(String loginid);
}
package jp.matsushima.spring_test.dao;

import jp.matsushima.spring_test.model.User;

import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

/**
 * ユーザーマスタ。
 * 
 * @author 2013/10/15 matsushima
 */
@Repository
public class UserDaoImpl implements UserDao {

	@Autowired
	private SessionFactory sessionFactory;

	/**
	 * ログイン ID、パスワードからユーザーを取得。
	 * 
	 * @param param
	 * @return
	 */
	@Override
	public User selectForAuth(User param) {
		return (User)sessionFactory.getCurrentSession().createCriteria(User.class)
				.add(Restrictions.eq("loginid", param.getLoginid()))
				.add(Restrictions.eq("password", param.getPassword()))
				.uniqueResult();
	}

/** * ログイン ID からユーザーを取得。 * * @param loginid * @return */ @Override public User selectByLoginid(String loginid) { return (User)sessionFactory.getCurrentSession().createCriteria(User.class) .add(Restrictions.eq("loginid", loginid)) .uniqueResult(); }
}
サーバを起動し、ブラウザから http://localhost:8080/spring-test/index にアクセスします。
DB に登録したログインID、パスワードを入力してログインボタンをクリックし、
xxx さんこんにちは。と表示されれば OK です。

プロジェクトの最新版はこちらで公開しています。
https://github.com/matsushima-terunao/blog_java/

← 1-6. 認証機能追加
↑ 一覧