JSP(Java Server Pages)とは
JSPを素直にいうとHTMLタグの中に、Javaの処理を書くものです(ファイルの拡張子は「.jsp」)
HTMLページ内にJavaコードを埋め込むことで、ユーザのリクエストに応じた動的なWebページを生成するテンプレート技術となっています。
<%@ page language="java" contentType="text/html; charset=UTF-8" import="java.util.*" %>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<%=new Date() %><%-- アクセス日時を表示 --%>
</body>
</html>
このようにJSPファイルは、HTMLの中にJavaのコードを埋め込んで作成。
Javaのコード部分は全て「<%〜 %>」で囲みます。
Javaをバックエンドとして使い、サーバーサイドで動的にコンテンツを生成することで、クライアントに生成されたHTML情報を提供します。
JSPとサーブレットはペアとして使われます。
JSPとはつまり
HTMLにJavaコードを埋め込むためのテンプレートエンジンです。
JSPの特徴
JSPはサーバー側でコンパイル・実行され、クライアントには生成されたHTMLが返されます。
JSPファイルは最終的にJava Servletとして実行されるため、Servletと同様の処理が行えます。
ブラウザがJSPファイルをリクエストすると、アプリケーションサーバがJSPファイルをサーブレットクラスに変換・コンパイルし、そのインスタンスを生成して実行します。
具体的な説明は次でします▼
サーバ側の処理手順例
HTML内にJavaプログラムが書ける = JSPもJavaファイルということです。
そのためJSPファイルは、ユーザーからリクエストされると、「Java Servletクラス」に変身します。
お仕事の依頼が来ると「サーブレットコンテナ」と呼ばれるJava Servletを動かすソフトによってJava Servletに変換され、Java Servletとしてお仕事をするのです。
つまり、最終的にJSPも、コンパイルされ.classファイルができます。
ユーザからJSPファイル(ここではindex.jsp)へリクエストがきた例だとこうなります。
ユーザからJSPファイル(index.jsp)へリクエストがきた例
- index.jsp → index_jsp.java (javaファイル(Servlet)へ変換)
- index_jsp.java → index_jsp.class(コンパイルされclassファイルが生成)
- classファイルからJava処理実行(出力するHTMLを生成)
- 出力するHTMLをレスポンスとして返す
まずユーザのリクエストはアプリケーションサーバ(Apache TomcatやJettyなど)に届きます。
アプリケーションサーバ内で動くサーブレットコンテナは、ユーザからのリクエストを処理し、ユーザに処理結果を返します。
JSPを使わないと、ユーザに返すHTMLを、Javaコードの中に書かないといけなくなるので大変。
JSPとHTMLの違い
JSPは、サーバサイドのサーブレットコンテナが処理する
HTMLは、クライアントのブラウザが処理する
JSPの書き方
JSPの書き方として、下記のようなものがある。
名称 | 説明 | 構文 |
---|---|---|
pageディレクティブ | JSPファイルに関する様々な設定を行える | <%@ page 属性名=”値”%> |
スクリプトレット | Javaプログラムを記入する場所 | <% %> |
スクリプト式 | 変数やメソッドの戻り値などを出力できます | <%= %> |
コメント | コメントを挿入できる | <%-- comment -- %> |
独自タグでJava処理と組み合わせることが可能
pageディレクティブ( <%@ page 属性名=”値”%> )
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<%@ page import="jp.co.tbs.Resister.sql.OrderListFromDB" %>
pageディレクティブを使うと、JSPファイルに関する様々な設定を行える。
pageディレクティブで使える主な属性と意味
- contentType
- レスポンスのContent-Typeヘッダ(text/html; charset=UTF-8)
- import
- インポートするクラスまたはインタフェース
- 例)「java.util." 」「javax.servlet.」
(パッケージ名.クラス名)
- pageEncoding
- JSPファイルの文字コード
- language
- 使用する言語
- session
- セッション使用の可否
- errorPage
- キャッチされなかった例外の処理(エラーページ)
- ifErrorPage
- エラーページかどうかの判断
よく使う書き方はこう
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ page pageEncoding="UTF-8"%>
<%@ page errorPage="/jsp/jspError.jsp"%>
<%@ page import="java.util.Date" %>
<%@ page import="jp.co.tbs.hoge.dto.UserTable" %>
<%
Date today = new Date(System.currentTimeMillis());
%>
import で JSP内で使用するオブジェクトを定義したりする。
スクリプトレット( <% Javaのコード %> )
<% %>で囲まれた部分は、JSPスクリプトとして処理する部分を表します。
スクリプトレットを使うと、JSPファイルにJavaのコードを埋め込むことが可能です。
複数行も書けます。
HTMLをまたいで書くこともできますね。
<% int x = 10, y = 20 %>
<%
String username = "Alice";
%>
<%
EditProjectForm editProjectForm = (EditProjectForm)pageContext.getAttribute("editProjectForm");
%>
スクリプトレットと、HTMLタグを組み合わせて条件分岐なども可能。
<c:if test="${!empty MessageSet}">
<c:set var="msgList" value="${MessageSet.messageList}"/>
<c:forEach var="msg" items="${msgList}">
<c:set var="messageId" value="${msg.messageId}" />
<%
String messageId = (String) pageContext.getAttribute("messageId");
boolean normalMessage = messageId.contains("IF");
%>
<% if (normalMessage) { %>
<c:out value="${msg.value}"/>
<% } else { %>
<p>何もなし</p>
<% } %>
</c:forEach>
</c:if>
MessageSetには、下記のようなList情報が入っている。
ーーー
[ messageId = IF00050001 args = null value = レイアウト登録が完了しました。 messageGroup = null messageType = null ]
ーーー
「pageContext」はページスコープを扱うための暗黙オブジェクト。
ページスコープとは、JSPページ内で定義された変数。
ページスコープは、同じページを表示している間維持されるスコープです。
ページスコープは、初期表示 や リダイレクト表示 で開始されます。
初期表示 や リダイレクト表示 で他のページがリクエストされると破棄されて、新しいページスコープが開始されるということ。
スクリプト式( <%= %> )
<% %>は処理を行うだけであるのに対し、<%= %>は出力をします。
変数やメソッドの戻り値などを出力できます。
お馴染みの System.out.println()メソッドと同様、様々なものを出力することが可能。
<%
String name="ヤマザキ";
int age=24;
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>サンプル</title>
</head>
<body>
私の名前は<%=name %>。年齢は<%=age %>才です
<% for(int i=0;i<10;i++){ %>
<%=i %><br>
<% } %>
</body>
</html>
JSPのコメント
<%-- コメント -- %>
EL式:${ ~ }
EL式(Expression Langage)は、JSP2.0で導入されたオブジェクトのアクセスを簡略化して記述できる式言語です。
${ ~ }タグを使用して記述。
JSTL(JavaServer Pages Standard Tag Library)とは
歴史の長い JSP で描画を書く際には、 JSTL を使うと便利なんですよね。
JSTLはApacheが提供している無料で使えるオープンソースのライブラリ。
JSTL は JSP 内でよく使われる機能をライブラリLibrar(= 図書館)としてまとめたものです。
JSTLを使用するメリット
結論:使える環境なら絶対JSTLを使った方がいい。効率がいいし
EL式という書き方と組み合わせることで、スクリプトレットが不要になり、可読性・保守性が向上します。
<% xxx %>(スクリプトレット)を使うとJSPのフォーマットなどは階層をきれいに整理できないため、メンテナンス性が悪いです。
JSTLを使うには
下記の2つのjarファイルをJettyの WEB-INF/lib/ 配下に置く必要がある。
https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api/2.0.0
--> 「jakarta.servlet.jsp.jstl-api-2.0.0.jar」 という名前
https://jakarta.ee/specifications/tags/2.0/
--> 「jakarta.servlet.jsp.jstl-2.0.0.jar」 という名前
JSPファイルでのJSTLタグの使用
JSTLライブラリをプロジェクトに追加した後。
JSPファイル内でJSTLタグを使用するためには?
→ 対応するタグライブラリの宣言をJSPファイルの先頭に追加する。
JSPの1行目に以下のように、PrefixとURIを指定するだけでJSTLが使えるようになります。
<%@ taglib prefix="接頭辞" uri=”使用するタグライブラリのURI (TLDファイルのURI)" %>
例えば、Coreタグライブラリを使いたいならこう。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Coreタグライブラリとは、変数、条件分岐、繰り返しなどの基本的な処理に関するタグです。
主な組み合わせは下記です。
タグライブラリ | prefix属性とURI属性の組み合わせ |
---|---|
Core | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
|18N | <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> |
Database | <%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %> |
XML | <%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %> |
Functions | <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> |
独自のタグライブラリを使う場合
たとえば、test は お手製のライブラリです。
<%@ taglib uri="/WEB-INF/test.tld" prefix="test" %>
(中略)
<test:user name="project.userId" default="テスト” />
uri="/WEB-INF/hogwan.tld" で、ローカルの tld ファイルを指定するんです。
tldファイル
カスタムタグの動作を定義するXML形式のファイルのこと
Coreタグライブラリ:変数出力/条件分岐/ループ..
Coreタグは全て <c:タグの種類> のように書きます。
Coreタグライブラリを使用すると、変数宣言、分岐と繰り返し、例外処理などのJavaプログラミングの基本処理をタグで行えるようになる。
タグ | 説明 |
---|---|
c:set | 変数をセット |
c:remove | 変数を削除 |
c:out | 変数を出力 |
c:if | if文(単一の条件分岐) |
c:choose, c:when, c:otherwise | if-else,if-elseif-else文(複数の条件分岐) |
c:forEach | ループ |
c:redirect | リダイレクト |
他にも下記がある。
- c:forTokens
文字列を区切り文字で分割 - c:import
ファイルをインポート - c:url
URLを生成 - c:catch
例外処理 - c:param
パラメータを指定
変数出力( <c:out> )
<c:out value="${human.GetUserName()}" />さんがログイン中
<c:out value="${editProjectForm.personalInfoExist}" />
<c:out value="test" />
上記の場合「サーブレットで定義したログインユーザ名」「"test"」が出力されます。
変数の値を単に出力するだけなら、「${human.name}」というEL式でも可能。
しかし、<c:out> を使うと出力内容に < や > といったHTMLにとって特殊な記号が出力内容に含まれていた場合。
それを無効にする処理(エスケープ)を行ってから出力を行ってくれるから、セキュリティの点でより優れています。
特に ユーザが入力した内容を出力する場合は を使用する 方がいいでしょう。
値のセット(<c:set>)
スコープに値を登録したり、Beanのプロパティをセットしたりできる。
<c:set var="myset" value="${3 + 12 / 5}" />
<c:set var="myBodySet"><div> body set </div></c:set>
<c:out value="${myset}" />
<c:out value="${myBodySet}" />
↓結果
↓
5.4
<div> body set </div>
Coreライブラリを使って item という変数に「りんご」の代入を行います。
<c:set var="item" value="りんご" />
↓
このように書いてもOK
<c:set var="item">りんご</c:set>
<:set>で使えるパラメータ
<c:set
var="値を格納する変数名"
target="オブジェクト名" (JavaBeansやMapに値を格納する場合)
property="プロパティ名" (JavaBeansのプロパティ、Mapのキー)
value="値"
scope="変数のスコープ" (デフォルトはpage)
/>
条件分岐(<c:if>)
c:if は条件分岐で使用し、c:choose は複数の条件分岐で使用されます。
<c:if test=”条件式”>
条件式がTrueなら実行される処理
</c:if>
例1)
<c:if test="${checkSetOnlineUser == '1' }">
<c:out value="${checkSetOnlineUser}"/>
</c:if>
例2)
<c:if test="${editProjectForm.personalInfoExist == Project.PERSONAL_INFO_EXIST}">test</c:if>
複数の条件分岐(<c:choose>)
<c:choose>
<c:when test = 判定条件1> 判定条件1が真の場合の処理 </c:when>
<c:when test = 判定条件2> 判定条件2が真の場合の処理 </c:when>
<c:otherwise> 判定条件1,2がともに偽の場合の処理 </c:otherwise>
</c:choose>
例で書くと下記のような感じ。
<c:choose>
<c:when test="${human.age >= 20}">
あなたは成人
</c:when>
<c:otherwise>
あなたは未成年
</c:otherwise>
</c:choose>
※ELの関係演算子
ELの場合は == で文字列の比較ができる。
(JavaSEではequals()メソッドを使う必要がある)
繰り返し(<c:forEach>)
<c:forEach>タグを使用します。
<c:forEach var=”変数名” items=”インスタンスの集合”>
繰り返し実行する処理
</c:forEach>
items属性には、下記のみ指定可能。
- 「リスト」
- 「マップ」
- 「セット」
- 「インスタンスの配列」
List を利用したループ例
リストを指定した場合、リストに格納されているインスタンスの数だけループが実行されます。
<%
List <String> names = new ArrayList<>();
names.add("今田");
names.add("佐藤");
names.add("久保川");
request.setAttribute("names", names);
%>
<c:forEach var="name" items="${names}">
${name}<br>
</c:forEach>
これだと、「今田」と「佐藤」「久保川」が出力されます。
暗黙オブジェクトによって、\${requestScope.names} は \${names} と書いても問題ないです。
<c:forEach var="onlineUser" items="${editProjectForm.allOnlineUserList}" varStatus="i">
onlineUserArray[<c:out value="${i.index}"/>] = new Object();
onlineUserArray[<c:out value="${i.index}"/>].userId = "<c:out value="${onlineUser.userId}" />";
onlineUserArray[<c:out value="${i.index}"/>].loginId = "<c:out value="${onlineUser.loginId}" />";
onlineUserArray[<c:out value="${i.index}"/>].name = "<c:out value="${onlineUser.userNm}" />";
</c:forEach>
varStatus は、現在のループの状態を表すステータス変数。
\${onlineUser.userId}、\${onlineUser.loginId}など、
ステータス変数の子要素からいろいろな情報を参照できます。
JSTLでのEL式:「${ ~ }」
EL式(Expression Langage)は、JSP2.0で導入されたオブジェクトのアクセスを簡略化して記述できる式言語です。
EL式:${ ~ }タグを使用して記述します。
EL式は、「静的HTMLの出力」「タグライブラリ」、「アクションの属性値」として使用します。
${"Hello World"}
<br>
${'Hello World'}
<br>
${42 * 42}
<br>
I'm ${20 + 3} years old.
<br>
Hello World has ${"Hello World".length()} characters.
<br>
ELで文字列をシングルクォーテーションでも囲むことができるのは、ダブルクォーテーションの中に入れられるようにするためのルールです。
つまり、「"\${bloodType == "A"}"」とすることはできませんが、
「"\${bloodType == 'A'}"」あるいは「'${bloodType == "A"}'」とすることはできます。
また、リクエストスコープに設定されたMAP情報を非常にシンプルな記述で取得できます。
他にも、JavaBeansのプロパティを簡単に出力する。
<%
HashMap map = new HashMap();
map.put("mapKey","TEST!!");
request.setAttribute("mapData",map);
request.setAttribute("message", "Hello World");
%>
${mapData.mapKey}
${message}
EL式とJavaBeans
EL式を使うと JavaBeansのプロパティを簡単に出力できます。
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("message", "Hello World");
// Getメソッド(リクエスト)を受け取った時に、order-management.jspにforwardする。
request.getRequestDispatcher("order-management.jsp").forward(request, response);
}
}
<c:if test="${message == "Hello World"}">test</c:if>
<input type="text" value="${message}">
この場合、「Hello World」が出力される。
ELを使用してタグの名前や属性名、属性値として動的に値を生成する場合には、ダブルクォーテーションが必要です。
これは、ELが評価される前にJSPコンテナが適切にその部分を処理する必要があるからです。
他にもこんな書き方がある。
<%
CustomerBean cb1 = new CustomerBean();
cb1.setCustomerId(1);
cb1.setName("今井");
request.setAttribute("customer1", cb1);
%>
${customer1}
<br>
${customer1.getName()}
<br>
${customer1.name}
セッションスコープでも同様
session.setAttribute(SESSION_PROJECT_REGIST_FORM, form);
${editProjectForm}
${editProjectForm.projectCur.spotResponsibleUserEmail}
〜
<c:set var="editProjectFormTest" value="${editProjectForm}"/>
これで form の内容が、${editProjectForm} の部分で出力される。
また、${editProjectForm.projectCur.spotResponsibleUserEmail}でユーザのメールアドレスだけが出力されるようになる。
また、変数 editProjectFormTest に form の値が代入できたりする。
$!{responsibleUserName} だと、値がない時は空が入るようになる。