サーブレットとJSPを使ったフォームの作成

# はじめに
こんばんわ、きりです。
本記事は[Nablarchを使ってみよう](https://qiita.com/kirin1218/items/242ee0f174f1cb12ef17)のサブ記事として作成しております。

今回はWeb画面に入力フォーム、ボタン、コンボボックス、ラジオボタンを作成し、選択した内容をサーブレットで取得するといったものを作ってみようと思います。

本記事以外のコンテンツは[こちら](https://qiita.com/kirin1218/items/242ee0f174f1cb12ef17#nablarch%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E8%A8%98%E4%BA%8B%E4%B8%80%E8%A6%A7)から閲覧可能です。

なるべく、初心者目線で作成するつもりですが、分かりづらい部分ありましたら、コメント頂きたいです。

# 動作環境
|種類|バージョン|
|---|---|
|OS|Windows 11 Professional 21H2|
|Eclipse|2022 Full Edition|

※Eclipseのダウンロードについては、[こちら](https://qiita.com/kirin1218/items/02bfeb333335842c56ae)の記事をご確認ください。

# 画面とサーブレットの作成
メンバー登録の機能を想定してメンバー登録画面と登録確認画面を作成してみます。

MemberRegister.jspというJSPファイルをwebapp/View/Member フォルダに作成します。

```MemberRegister.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>メンバー登録画面</title>
</head>
<body>
  <form action="<%= request.getContextPath() %>/MemberConfirm" method="post">
    <h2>名前</h2>
    <input type="text" name="name" />
    <h2>ニックネーム</h2>
    <input type="text" name="nickname" />
    <h2>性別</h2>
    <input type="radio" name="gender" value="empty" checked>未指定<br>
    <input type="radio" name="gender" value="female">女性<br>
    <input type="radio" name="gender" value="male">男性
    <h2>出身地</h2>
    <SELECT name="birtharea">
      <OPTION value="empty" selected>未指定</OPTION>
      <OPTION value="hkd">北海道</OPTION>
      <OPTION value="thk">東北</OPTION>
      <OPTION value="knt">関東</OPTION>
      <OPTION value="chb">中部</OPTION>
      <OPTION value="knk">近畿</OPTION>
      <OPTION value="cgk">中国</OPTION>
      <OPTION value="skk">四国</OPTION>
      <OPTION value="kso">九州沖縄</OPTION>
    </SELECT>
    <h2>オプション</h2>
    <input type="checkbox" name="optionagree" value="collectlog" >ログの収集を許可します<br>
    <input type="checkbox" name="optionagree" value="sendinfomail" >お知らせメールの送信を許可します<br><br>
    <input type="submit" value="確認画面に進む">
  </form>
</body>
</html>
```

続いて、登録確認画面としてMemberConfirm.jspというJSPファイルをwebapp/View/Member フォルダに作成します。

```MemberConfirm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
  // Servletのデータ受け取り
  request.setCharacterEncoding("UTF8");
  String strName = (String) request.getAttribute("name");
  String strNickName = (String) request.getAttribute("nickname");
  String strGender = (String) request.getAttribute("gender");
  String strBirthArea = (String) request.getAttribute("birtharea");
  Boolean bAllowCollectLog = (Boolean) request.getAttribute("collectlog");
  Boolean bAllowSendInfoMail = (Boolean) request.getAttribute("sendinfomail");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>メンバー登録確認画面</title>
</head>
<body>
  <h2>名前</h2>
  <%=strName%>
  <h2>ニックネーム</h2>
  <%=strNickName%>
  <h2>性別</h2>
  <%=strGender%>
  <h2>出身地</h2>
  <%=strBirthArea%>
  <h2>オプション</h2>
  ・ログの収集：
  <%if( bAllowCollectLog != false ){%>
  同意
  <%}else{%>
  未同意
  <%}%>
  <br>
  ・お知らせメールの送信：
  <%if( bAllowSendInfoMail != false ){%>
  同意
  <%}else{%>
  未同意
  <%}%>
  <br>
  <br>
  <button type="button" onclick="history.back()">戻る</button>
</body>
</html>
```

サーブレット側も作成します。
登録画面の表示用にMemberRegister.javaファイルをsrc/main/java/com/example/member　フォルダに作成します。
|設定名|設定値|
|---|---|
|パッケージ名|com.example.member|
|クラス名|MemberRegister|

としてサーブレットを作成すると期待したフォルダに作成されます。

``` MemberRegister.java
package com.example.member;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class MemberRegister
 */
@WebServlet("/MemberRegister")
public class MemberRegister extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
   * @see HttpServlet#HttpServlet()
   */
  public MemberRegister() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
   * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    request.getRequestDispatcher("View/Member/MemberRegister.jsp").forward(request, response);
  }
```

最後に登録確認画面の表示用にMemberConfirm.javaファイルをsrc/main/java/com/example/member　フォルダに作成します。
|設定名|設定値|
|---|---|
|パッケージ名|com.example.member|
|クラス名|MemberConfirm|

としてサーブレットを作成すると期待したフォルダに作成されます。

``` MemberConfirm.java
package com.example.member;

import java.io.IOException;
import java.util.Arrays;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class MemberConfirm
 */
@WebServlet("/MemberConfirm")
public class MemberConfirm extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
   * @see HttpServlet#HttpServlet()
   */
  public MemberConfirm() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
   * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    // 各フォームデータを取得する
    String name = request.getParameter("name");
    String nickname = request.getParameter("nickname");
    String gender = request.getParameter("gender");
    String area = request.getParameter("birtharea");
    String options[] = request.getParameterValues("optionagree");
    Boolean b_collectLog = false;
    Boolean b_sendInfoMail = false;

    // 呼び出し先Jspに渡すデータセット
    request.setAttribute("name", name);
    request.setAttribute("nickname", nickname);
    if (gender.equals("empty") != false) {
      request.setAttribute("gender", "未指定");
    } else if (gender.equals("female") != false) {
      request.setAttribute("gender", "女性");
    } else if (gender.equals("male") != false) {
      request.setAttribute("gender", "男性");
    }

    if (area.equals("empty") != false) {
      request.setAttribute("birtharea", "未指定");
    } else if (area.equals("hkd") != false) {
      request.setAttribute("birtharea", "北海道");
    } else if (area.equals("thk") != false) {
      request.setAttribute("birtharea", "東北");
    } else if (area.equals("knt") != false) {
      request.setAttribute("birtharea", "関東");
    } else if (area.equals("chb") != false) {
      request.setAttribute("birtharea", "中部");
    } else if (area.equals("knk") != false) {
      request.setAttribute("birtharea", "近畿");
    } else if (area.equals("cgk") != false) {
      request.setAttribute("birtharea", "中国");
    } else if (area.equals("skk") != false) {
      request.setAttribute("birtharea", "四国");
    } else if (area.equals("kso") != false) {
      request.setAttribute("birtharea", "九州沖縄");
    }

    if (options != null) {
      if (Arrays.asList(options).contains("collectlog")) {
        b_collectLog = true;
      }
      if (Arrays.asList(options).contains("sendinfomail")) {
        b_sendInfoMail = true;
      }
    }
    request.setAttribute("collectlog", b_collectLog);
    request.setAttribute("sendinfomail", b_sendInfoMail);

    request.getRequestDispatcher("/View/Member/MemberConfirm.jsp").forward(request, response);
  }
}
```
想定されるフォルダ階層は以下となります。
```
src
 ┣　main
 ┃　┗　java
 ┃　　　　┗　com
 ┃　　　　　┗　example
 ┃　　　　　　　┗　member
　　┃　　　　　　　　┣　MemberRegister.java
　　┃　　　　　　　　┗　MemberConfirm.java
 ┗　webapp
　　　　┗　View
 　　　　　　┗　Member
　　　　　　　　　　┣　MemberRegister.jsp
　　　　　　　　　　┗　MemberConfirm.jsp
```

# 動作確認
まずは実行(実行>サーバーで実行）して、ブラウザでトップページを表示します。
※表示方法の詳細は[こちら](https://qiita.com/kirin1218/items/db1ba8af6c323c925919#tomcat%E3%81%A7%E5%AE%9F%E8%A1%8C)を御覧ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/46025a22-c787-50c3-4b3b-d1e8ee8c5627.png)

続いて、初期画面のURLに「MemberRegister」を追加して、ENTERを押下してみます。

下図のような画面が表示されれば成功です。
※スタイルを指定してないので、見た目がカッコ悪いのは一旦ご勘弁を。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/ad32eca6-fca2-d1d2-eca7-26507bad3ee9.png)

続いて、適当な値を入力、選択し「確認画面に進む」ボタンを押下してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/e79deb49-c471-df03-8ad5-015dee645a72.png)

下図のような確認画面が表示され、さきほど入力した値などが正しく表示されていれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803458/2ec04186-4c02-b63f-6409-caf22001bb26.png)

# ソースの説明
## MemberRegister.jsp
一旦、HTMLの基本知識はお持ちの方向けに説明します。

といっても、基本的にはHTMLのコードと一緒なので、jsp独自のコードは以下の2行です。
```
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
```

<%@ %>で括られたコードをディレクティブと呼び、JSPファイルの設定や構成を指定します。
ディレクティブには,page,include,taglibが存在し、今回はpageディレクティブを利用します。
上記で大事なのはcontentTypeとpageEncodingにてUTF-8を指定していることです。
ISO-8859-1のままでは日本語を取り扱う際に期待通りに動作しない可能性がありますので、UTF-8を指定しておきましょう。

[pageディレクティブ](https://www.javadrive.jp/servlet/jsp_directive/index2.html)
[ISO-8859-1](http://www.shtml.jp/mojibake/ichiran.php)

```
<form action="<%= request.getContextPath() %>/MemberConfirm" method="post">
```
フォームの送信先（action）を指定する際にコンテキストパスを取得してパスに利用しています。
jsp内では<%=  %>で括られた値を文字列として評価します。
即ち、「取得したコンテキストパス/MemberConfirm」という文字列がactionとして利用されるようになります。

[式の評価を出力](https://www.javadrive.jp/servlet/jsp_scripting/index2.html)
## MemberConfirm.jsp
```
<%
  // Servletのデータ受け取り
  request.setCharacterEncoding("UTF8");
  String strName = (String) request.getAttribute("name");
  String strNickName = (String) request.getAttribute("nickname");
  String strGender = (String) request.getAttribute("gender");
  String strBirthArea = (String) request.getAttribute("birtharea");
  Boolean bAllowCollectLog = (Boolean) request.getAttribute("collectlog");
  Boolean bAllowSendInfoMail = (Boolean) request.getAttribute("sendinfomail");
%>
```
1行目でrequestの値をUTF-8として扱うように指定します。そうしないと、日本語が指定されていた場合に文字化けが起きる可能性があります。
それ以降は、サーブレット内でAttributeに設定された値を取得しています。
AttributeはObject型(StringやBooleanクラスが継承している汎用的なクラス）のため、取得時は期待する型でキャストして取得します。

```
  <%=strName%>
  <%=strNickName%>
  <%=strGender%>
  <%=strBirthArea%>
```
は先のrequest.getContextPath()と同様に変数の値を文字列として表示します。
今回は値がそのまま画面に表示されます。

```
  <%if( bAllowCollectLog != false ){%>
  同意
  <%}else{%>
  未同意
  <%}%>
```
jspではJavaコードのif文を挿入することも可能で、上記のように<% %>の中にifやelseまた最後の閉じカッコを指定します。

## MemberRegister.java
こちらは、MemberRegister.jspにフォワードしているだけです。
※jspへのフォワードについては[こちら](https://qiita.com/kirin1218/items/9002dab5a30536559469#%E3%82%B5%E3%83%BC%E3%83%96%E3%83%AC%E3%83%83%E3%83%88%E3%81%AE%E5%A4%89%E6%9B%B4)を御覧ください。

## MemberConfirm.java
MemberConfirm.javaでは大きく分けて３つのことを行っています。
* MemberRegister.jsp画面からのリクエストパラメータ取得
* MemberConfirm.jspで参照するのAttributeの設定
* MemberConfirm.jspへのフォワード処理

### MemberRegister.jsp画面からのリクエストパラメータ取得
入力やラジオボタン、チェックボックス、コンボボックスで入力値をサーブレット側で取得するには、jsp(HTML)側でinputタグやselectタグのname属性を指定します。

また、ラジオボタンやチェックボックスをグループとして扱うために同じ名前をname属性に指定する必要があります。

サーブレット側ではreguest.getParameterやrequest.getParameterValuesなどのメソッドを使い、取得したい属性値を指定します。今回はnameやnickname,genderなどを指定しました。

※ チェックボックスの値(optionagree)はチェックされた項目のvalue値の配列がgetParameterValuesの結果として取得できますが、ひとつもチェックがされなかった場合はnullが返却されますので、参照時に注意が必要です。

### MemberConfirm.jspで参照するのAttributeの設定
[MemberConfirm.jsp](##memberconfirm.jsp)にて、参照する属性情報を設定します。
設定にはrequest.setAttributeメソッドを利用します。
属性名と属性値をセットで指定します。属性値はjava.lang.Object型のため文字列やブール値を指定できます。

# 最後に
今回はJSPファイルにおける入力やチェックボックスなどのコントロールの表示方法とサーブレットにおける値の受け渡し方法を整理しました。
基本的な処理ではありますが、そのまま利用できる処理もあると思いますので、ご自身で画面を作成する際の参考にしていただければと考えます。

他の記事については[こちら](https://qiita.com/kirin1218/items/242ee0f174f1cb12ef17#nablarch%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E8%A8%98%E4%BA%8B%E4%B8%80%E8%A6%A7)から御覧ください。

# 参考リンク
* [pageディレクティブ](https://www.javadrive.jp/servlet/jsp_directive/index2.html)
* [ISO-8859-1](http://www.shtml.jp/mojibake/ichiran.php)
* [式の評価を出力](https://www.javadrive.jp/servlet/jsp_scripting/index2.html)