LoginSignup
4
7

More than 5 years have passed since last update.

JavaBeansとJSTLでJSP/Servletの記述を簡易にする

Posted at

概要

ServletからJSPへ渡すデータの量や構造が大きい場合、Javaコードそのままだと記述量が大きくなってしまうので、JavaBeansを使って自前のデータ型でやりとりを行う。(いろいろ定義や解説はあるけど、C言語わかる人むけだと「アクセサ付きの構造体」くらいの感覚で"とりあえず"はいいんじゃないかなぁ。。)

また、JSPでJavaBeansへのアクセスや、以前はがっつりとJavaのコードでループ処理を実装していたのを、JSTLのループ処理を使ってすっきり記述する。

話の流れ

Beanクラスの作成

「クラスの作成」から普通に…

MemoBean.java
package jp.example.www;

public class MemoBean {

    public MemoBean() {
    }

    private String title;
    private String memo;
    private String modify;
}

これだけ書いたらEclipseの「getterおよびsetterの生成」でアクセサは作成できる。

image.png

なくても動くことは動くんだけど、JavaBeansの仕様的にはSerializableを実装するのが決まりらしいのでimplementsする。

MemoBean.java
package jp.example.www;

import java.io.Serializable;

public class MemoBean implements Serializable {
    private static final long serialVersionUID = 1L;

    public MemoBean() {
    }

    private String title;
    private String memo;
    private String modify;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getMemo() {
        return memo;
    }

    public void setMemo(String memo) {
        this.memo = memo;
    }

    public String getModify() {
        return modify;
    }

    public void setModify(String modify) {
        this.modify = modify;
    }
}

Beanを使ったサーブレットの修正

HashMapArrayListで処理していた値の保持とJSPへのsetAttribute()の実装を、上記のBeanクラスに置き換える

before
        ArrayList<HashMap<String, String>> record_list = new ArrayList<>();
        while (result.next()) {
            HashMap<String, String> record = new HashMap<>();
            record.put("title", result.getString("title"));
            record.put("memo", result.getString("memo"));
            record.put("modified_date", result.getString("modified_date"));
            record_list.add(record);
        }
after
        ArrayList<MemoBean> memo_list = new ArrayList<>();

        String select_memo = "select title, memo, modified_date from memo_data;";
        ResultSet result = smt.executeQuery(select_memo);
        while (result.next()) {
            MemoBean memoBean = new MemoBean();
            memoBean.setTitle(result.getString("title"));
            memoBean.setMemo(result.getString("memo"));
            memoBean.setModify(result.getString("modified_date"));
            memo_list.add(memoBean);
        }

        request.setAttribute("memo_list", memo_list);

JSPでBeanの受け取りとループ処理

JSTL coreタグライブラリを使えるようにする

Mavenを使って、二つのライブラリを取り込む(pom.xml<dependency>の定義を記述する)

JSTLの有効化

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

これでJSPで<c:out>とか<c:forEach>とか使えるようになる。

EL式の有効化

<%@ page isELIgnored="false" %>

ignore=trueがデフォルトらしく、これを書かないと${value}とかの記述が解釈されない

Beanのループ処理

便利なことにArrayListなどのiterator処理は<c:forEach>が内部でよしなにしてくれるので、BeanクラスのArrayList処理はこれで動く。
(全ArrayList要素の各メンバをprint)

  <c:forEach var="data" items="${memo_list}">
    <hr/>
    <div><c:out value="${data.title}"/></div>
    <div><c:out value="${data.modify}"/></div>
    <div><c:out value="${data.memo}"/></div>
  </c:forEach>
  • forEachのitems属性がループ処理対象で、ServletのsetAttribute()のkey文字列を指定すれば中身を取り出してくれる
  • ループ内処理で各要素はvarで指定した変数名にセットされる
  • 直接${data.***}と書いても出力はされるが、<c:out>を使うとhtmlタグのエスケープとかしてくれる
  • ${data.title}の部分、privateメンバにアクセスしてるように見えてるけどそんなことはなく、getter/setterのgetXxx()xxxの部分に合わせている。

参考

改行の処理

サンプルにしてるアプリの仕様上、${data.memo}は複数行の文字列データが入っている。そのため、生データをそのままhtml上に出力しても<br/>がないため改行されない。また、単純に改行を<br/>に置換しても、<c:out>の機能でエスケープされてhtmlタグとして認識されない。
ということで、何がベストソリューションかは置いておいて、今回は改行でsplitして行ごとに出力してみた。

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

...snip...

  <% pageContext.setAttribute("newLineChar", "\n"); %>
  <c:forEach var="data" items="${memo_list}">
    <hr/>
    <div><c:out value="${data.title}"/></div>
    <div><c:out value="${data.modify}"/></div>
    <div>
    <c:forEach var="line" items="${fn:split(data.memo, newLineChar)}">
    <c:out value="${line}"/><br/>
    </c:forEach>
    </div>
  </c:forEach>

split(data_memo, "\n")は動作しないようなので、事前にnewLineCharという変数に\nをセットしている。


参考

備考

<c:forEach>で例外が出る場合

javax.servlet.ServletException: java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/LoopTag
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:349)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    jp.example.www.MemoAppMain.doGet(MemoAppMain.java:87)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

taglibs-standard-implは設定されているけどjstlが設定されてないとこの例外がでる。
https://mvnrepository.com/artifact/javax.servlet/jstl/1.2

<jsp:useBean>について

JSPに

<jsp:useBean type= "java.util.ArrayList<jp.example.www.MemoBean>" id="memo_list" scope="request" />

みたいな記述をする説明は多く見かけるけど、なくても動く。よくわからない(汗)

4
7
0

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
4
7