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

# 概要

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

- [【初心者向け】10分で絶対にわかる！JavaBeansとは - Qiita](https://qiita.com/s_hino/items/0e3234b8feefe2d14315)
- [Java Beansクラスについて - はしくれエンジニアもどきのメモ](https://cartman0.hatenablog.com/entry/2015/12/25/032107)

また、JSPでJavaBeansへのアクセスや、[以前はがっつりとJavaのコードでループ処理を実装していた](https://qiita.com/zaki-lknr/items/32690b071abf202281d6#jsp%E5%81%B4)のを、JSTLのループ処理を使ってすっきり記述する。

- [JSTL coreタグライブラリの利用 - Qiita](https://qiita.com/sculptcat/items/53d1a3a2d3b973354085)

話の流れ

- [Eclipseを使ってTomcat+JSP+Servlet+MySQLでメモアプリ作成 - Qiita](https://qiita.com/zaki-lknr/items/32690b071abf202281d6)
- [[Eclipse/Tomcat] MavenのwebappプロジェクトでServlet+JSP - Qiita](https://qiita.com/zaki-lknr/items/8137ac40ebd8f5bdb3c5)

# Beanクラスの作成

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

```java: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](https://qiita-image-store.s3.amazonaws.com/0/256859/aba94e01-f603-c3ef-ce09-bbd9b0b8dfc0.png)

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

```java: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を使ったサーブレットの修正

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

```java: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);
        }
```

```java: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>`の定義を記述する)

- [Maven Repository: org.apache.taglibs » taglibs-standard-impl](https://mvnrepository.com/artifact/org.apache.taglibs/taglibs-standard-impl)
- [Maven Repository: javax.servlet » jstl](https://mvnrepository.com/artifact/javax.servlet/jstl)

## 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`の部分に合わせている。

---

参考

- [Java - リストに入ったオブジェクトをＪＳＰに渡し、ＪＳＴＬで表示させたい｜teratail](https://teratail.com/questions/15900)

## 改行の処理

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

```xml
<%@ 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`をセットしている。

---

参考

- [JSTLのfn:replaceで改行を置換したい - こせきの技術日記 - 技術日記](http://tech.g.hatena.ne.jp/koseki/20050706/jstlreturnreplace)
- [string - "fn:replace" 正規表現 - JSPとJSTLを使用して改行文字を置き換えるにはどうすればよいですか？ - CODE Q&A 問題解決](https://code.i-harness.com/ja/q/e2c6)

# 備考

## `<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" />
```

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

- [&lt;jsp:useBean&gt;のclassとtypeの違い : SJC-WC合格対策サイト](http://sjcwc.web.fc2.com/08_5_jsp_usebean_class_type.html)
- [jsp:useBeanでジェネリックスを使う場合、classとtypeを両方指定する – こぶたのラッパ](http://hello.lumiere-couleur.com/smilkobuta/2009/02/26/jspusebean%E3%81%A7%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88%E3%80%81class%E3%81%A8type%E3%82%92%E4%B8%A1%E6%96%B9%E6%8C%87%E5%AE%9A/)
- [JSPについて - おちラボ](http://www.ochi-lab.org/course/j2ee/jsp)