LoginSignup
2
9

More than 5 years have passed since last update.

JSPのカスタムタグを作成するサンプル

Posted at

jspのカスタムタグを作成することがあったので、そのメモ――というよりサンプルです。ご査収ください(´・ω・`)

まずは要件定義から! サンプルということで簡単ですが、次のようにまとめてみました。

  • データベースの検索結果をプルダウンとして表示する
    • ただしサンプルなので、データベースはモックとして実装する。
  • タグ名はsample:select。必須属性としてgroupを持ち、これをキーにしてデータベースを検索する。

事前準備: DBアクセス層とServletを作成する。

DBの検索結果を表示するカスタムタグを作りたいということで、DBへのアクセスとその検索結果を示すクラスを作成します。またjspを表示するためのServletも必要となるので、これも作成します。以下がそのサンプルコードになりますが、package宣言、import宣言、GetterおよびSetterは冗長なため省略しています。ただしパッケージ構成については最初に示す、画像をもとに判断してもらえると幸いです(´・ω・`)

image

DB.java
/**
 * データベースへのアクセス・クラス。ただしサンプルのためモック実装とする。
 */
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());
    }
}
Row.java
/**
 * 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;
    }
}
SampleServlet.java
/**
 * 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を実装することにより実現し、そのサンプルコードは以下の通りです。

Select.java
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形式です。

sample.tld
<?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>

おわり(`・ω・´)シャキーン

2
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
9