LoginSignup
7

More than 3 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" />

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

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
What you can do with signing up
7