jspのカスタムタグを作成することがあったので、そのメモ――というよりサンプルです。ご査収ください(´・ω・`)
まずは要件定義から! サンプルということで簡単ですが、次のようにまとめてみました。
- データベースの検索結果をプルダウンとして表示する
- ただしサンプルなので、データベースはモックとして実装する。
- タグ名は
sample:select
。必須属性としてgroup
を持ち、これをキーにしてデータベースを検索する。
事前準備: DBアクセス層とServletを作成する。
DBの検索結果を表示するカスタムタグを作りたいということで、DBへのアクセスとその検索結果を示すクラスを作成します。またjspを表示するためのServletも必要となるので、これも作成します。以下がそのサンプルコードになりますが、package宣言、import宣言、GetterおよびSetterは冗長なため省略しています。ただしパッケージ構成については最初に示す、画像をもとに判断してもらえると幸いです(´・ω・`)
/**
* データベースへのアクセス・クラス。ただしサンプルのためモック実装とする。
*/
public class DB implements Serializable {
private List<Row> rows;
/**
* コンストラクタ。インスタンスを生成するとともに、モックDBへの初期データ投入を行う。
*/
public DB() {
this.rows = new ArrayList<>();
this.rows.add(new Row("group1", "A", "AAA"));
this.rows.add(new Row("group1", "B", "BBB"));
this.rows.add(new Row("group1", "C", "CCC"));
this.rows.add(new Row("group1", "D", "DDD"));
this.rows.add(new Row("group1", "E", "EEE"));
this.rows.add(new Row("group2", "a", "あああ"));
this.rows.add(new Row("group2", "b", "いいい"));
this.rows.add(new Row("group2", "c", "ううう"));
this.rows.add(new Row("group2", "d", "えええ"));
this.rows.add(new Row("group2", "e", "おおお"));
}
/**
* groupをキーにDBを検索する。
* @param group groupカラムの値
* @return 検索結果
*/
public List<Row> select(String group) {
return rows.stream()
.filter(row -> row.getGroup().equals(group))
.collect(Collectors.toList());
}
}
/**
* com.sample.db.DBクラスが示すデータベースの行をしめすBeanクラス。
*/
final public class Row implements Serializable {
private String group;
private String id;
private String name;
public Row(String group, String id, String name) {
this.group = group;
this.id = id;
this.name = name;
}
}
/**
* sample.jspを表示するためのサーブレット。
*/
@WebServlet("/sample")
public class SampleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/sample.jsp");
dispatcher.forward(request, response);
}
}
タグハンドラを実装する。
前提条件が整ったところで、カスタムタグに対応するJavaクラスであるタグハンドラを実装します。タグハンドラはインターフェイスであるjavax.servlet.jsp.tagext.Tag
を実装することにより実現し、そのサンプルコードは以下の通りです。
public class Select implements Tag {
private Tag parent;
private PageContext pageContext;
private String group;
@Override
public int doStartTag() throws JspException {
return Tag.SKIP_BODY; // このタグはBody要素を持たない。
}
@Override
public int doEndTag() throws JspException {
// groupをもとにDBを検索する。
DB db = new DB();
List<Row> rows = db.select(this.group);
// DBへの検索結果をもとにselectタグを動的に生成する。
String select = rows.stream().map(row -> {
String id = row.getId();
String name = row.getName();
return String.format("<option value=\"%s\">%s</option>", id, name);
}).collect(Collectors.joining("", "<select>", "</select>"));
// 生成したselectタグを動的に生成する。
try {
JspWriter out = this.pageContext.getOut();
out.print(select);
} catch (IOException e) {
throw new JspException(e);
}
return Tag.EVAL_PAGE;
}
@Override
public void release() {
}
@Override
public Tag getParent() {
return this.parent;
}
@Override
public void setParent(Tag parent) {
this.parent = parent;
}
@Override
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
}
なおここでの「はまりポイント」としては次の二つがありました。
- 属性に対応するフィールドならびにGetterおよびSetterを実装する必要がある。
- 上記のサンプルでは
private String group;
getGroup
setGroup
がそれぞれ存在しないとうまくいかない。
- 上記のサンプルでは
-
JSPWriter
は明示的にclose
しない。
tldファイルを準備する。
Javaの世界の住人であるタグハンドラが用意できたところで、タグハンドラとjspの世界の住人であるタグを結びつける必要があります。これを設定するのがtldファイルであり、そのサンプルを以下に示します。なお拡張子はtldですが、実態としてはxml形式です。
<?xml version="1.0" encoding="UTF-8"?>
<taglib
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>sample</short-name>
<tag>
<name>select</name>
<tag-class>com.sample.tag.Select</tag-class>
<body-content>empty</body-content>
<attribute>
<name>group</name>
<required>true</required>
</attribute>
</tag>
</taglib>
jspファイルを作成してデプロイする。
あとは自作したタグを利用したjspファイルを作成し、サーバにアプリをデプロイします。
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="sample.tld" prefix="sample" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Sample</title>
</head>
<body>
<h1>JSP Sample</h1>
<p><sample:select group="group1" /></p>
<p><sample:select group="group2" /></p>
</body>
</html>
最後に結果確認としてWebブラウザなどで/jsp/sample
にアクセスすると、次のようなソースコードにより表現されるWebページが表示されるはずです。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Sample</title>
</head>
<body>
<h1>JSP Sample</h1>
<p>
<select>
<option value="A">AAA</option>
<option value="B">BBB</option>
<option value="C">CCC</option>
<option value="D">DDD</option>
<option value="E">EEE</option>
</select>
</p>
<p>
<select>
<option value="a">あああ</option>
<option value="b">いいい</option>
<option value="c">ううう</option>
<option value="d">えええ</option>
<option value="e">おおお</option>
</select>
</p>
</body>
</html>
おわり(`・ω・´)シャキーン