かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その58 )( 確認画面を作成する )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その57 )( build.gradle に記述する BOM を Spring IO Platform のものから Spring Boot のものに変更する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • 確認画面の作成
    • 今回は入力されたデータを画面に表示する処理を作成します。保存された入力値を画面に表示する文字列に変換する処理を ModelMapper のデータ変換用クラス内で行います。

参照したサイト・書籍

目次

  1. Form クラスを作成する
  2. ModelMapper で使用するデータ変換用クラスを作成する
  3. InquiryConfirmController クラスを変更する
  4. confirm.html を変更する
  5. 動作確認
  6. 次は。。。

手順

Form クラスを作成する

src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form の下に ConfirmForm.java を新規作成し、以下の内容を記述します。

package ksbysample.webapp.bootnpmgeb.web.inquiry.form;

import lombok.Data;

/**
 * 確認画面用 Form クラス
 */
@Data
public class ConfirmForm {

    /************************
     * 入力画面1の入力項目用
     ************************/
    private String name;

    private String kana;

    private String sex;

    private String age;

    private String job;

    /************************
     * 入力画面2の入力項目用
     ************************/
    private String zipcode;

    private String address;

    private String tel;

    private String email;

    /************************
     * 入力画面3の入力項目用
     ************************/
    private String type1;

    private String type2;

    private String inquiry;

    private List<String> survey;

}

ModelMapper で使用するデータ変換用クラスを作成する

データ変換のルールを定義するクラスを配置するパッケージを作成します。src/main/java/ksbysample/webapp/bootnpmgeb の下に mapper パッケージを作成します。

src/main/java/ksbysample/webapp/bootnpmgeb/mapper の下に SessionData2ConfirmFormTypeMap.java を新規作成し、以下の内容を記述します。

package ksbysample.webapp.bootnpmgeb.mapper;

import com.github.rozidan.springboot.modelmapper.TypeMapConfigurer;
import ksbysample.webapp.bootnpmgeb.helper.db.SurveyOptionsHelper;
import ksbysample.webapp.bootnpmgeb.session.SessionData;
import ksbysample.webapp.bootnpmgeb.values.*;
import ksbysample.webapp.bootnpmgeb.web.inquiry.form.ConfirmForm;
import ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput01Form;
import ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput02Form;
import ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput03Form;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.TypeMap;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * SessionData --> ConfirmForm データ変換用クラス
 */
@Component
public class SessionData2ConfirmFormTypeMap extends TypeMapConfigurer<SessionData, ConfirmForm> {

    private final ValuesHelper vh;

    private final SurveyOptionsHelper soh;

    /**
     * コンストラクタ
     *
     * @param vh  {@ValuesHelper} オブジェクト
     * @param soh {@SurveyOptionsHelper} オブジェクト
     */
    public SessionData2ConfirmFormTypeMap(ValuesHelper vh
            , SurveyOptionsHelper soh) {
        super();
        this.vh = vh;
        this.soh = soh;
    }

    @Override
    public void configure(TypeMap<SessionData, ConfirmForm> typeMap) {
        typeMap.setPreConverter(context -> {
            SessionData sessionData = context.getSource();
            InquiryInput01Form inquiryInput01Form = sessionData.getInquiryInput01Form();
            InquiryInput02Form inquiryInput02Form = sessionData.getInquiryInput02Form();
            InquiryInput03Form inquiryInput03Form = sessionData.getInquiryInput03Form();
            ConfirmForm confirmForm = context.getDestination();

            /************************
             * 入力画面1の入力項目用
             ************************/
            confirmForm.setName(join(" "
                    , inquiryInput01Form.getLastname()
                    , inquiryInput01Form.getFirstname()));
            confirmForm.setKana(join(" "
                    , inquiryInput01Form.getLastkana()
                    , inquiryInput01Form.getFirstkana()));
            confirmForm.setSex(vh.getText(SexValues.class, inquiryInput01Form.getSex()));
            confirmForm.setAge(inquiryInput01Form.getAge());
            confirmForm.setJob(vh.getText(JobValues.class, inquiryInput01Form.getJob()));

            /************************
             * 入力画面2の入力項目用
             ************************/
            confirmForm.setZipcode(join("-"
                    , inquiryInput02Form.getZipcode1()
                    , inquiryInput02Form.getZipcode2()));
            confirmForm.setAddress(inquiryInput02Form.getAddress());
            confirmForm.setTel(join("-"
                    , inquiryInput02Form.getTel1()
                    , inquiryInput02Form.getTel2()
                    , inquiryInput02Form.getTel3()));
            confirmForm.setEmail(inquiryInput02Form.getEmail());

            /************************
             * 入力画面3の入力項目用
             ************************/
            confirmForm.setType1(vh.getText(Type1Values.class, inquiryInput03Form.getType1()));
            confirmForm.setType2(inquiryInput03Form.getType2().stream()
                    .map(type2 -> vh.getText(Type2Values.class, type2))
                    .collect(Collectors.joining("、")));
            confirmForm.setInquiry(inquiryInput03Form.getInquiry());
            Map<String, String> surveyOptionsMap = this.soh.selectItemList("survey").stream()
                    .collect(Collectors.toMap(s -> s.getItemValue(), s -> s.getItemName()));
            confirmForm.setSurvey(inquiryInput03Form.getSurvey().stream()
                    .map(survey -> surveyOptionsMap.get(survey))
                    .collect(Collectors.toList()));

            return context.getDestination();
        });

        typeMap.addMappings(mapping -> mapping.skip(ConfirmForm::setName))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setKana))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setSex))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setAge))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setJob))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setZipcode))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setAddress))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setTel))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setEmail))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setType1))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setType2))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setInquiry))
                .addMappings(mapping -> mapping.skip(ConfirmForm::setSurvey));
    }

    /**
     * 文字列を指定された区切り文字で結合する。文字列が全て空の場合には空文字列を返す。
     *
     * @param delimiter 区切り文字
     * @param arg       結合する文字列の配列
     * @return 結合した文字列
     */
    private String join(String delimiter, String... arg) {
        boolean isAllEmpty = arg == null
                || Arrays.asList(arg).stream().allMatch(str -> StringUtils.isEmpty(str));
        return isAllEmpty
                ? StringUtils.EMPTY
                : Arrays.asList(arg).stream().collect(Collectors.joining(delimiter));
    }

}

InquiryConfirmController クラスを変更する

src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryConfirmController.java の以下の点を変更します。

@Controller
@RequestMapping("/inquiry/confirm")
@SessionAttributes("sessionData")
public class InquiryConfirmController {

    private static final String TEMPLATE_BASE = "web/inquiry";
    private static final String TEMPLATE_CONFIRM = TEMPLATE_BASE + "/confirm";

    private final ModelMapper modelMapper;

    /**
     * コンストラクタ
     *
     * @param modelMapper {@ModelMapper} オブジェクト
     */
    public InquiryConfirmController(ModelMapper modelMapper) {
        this.modelMapper = modelMapper;
    }

    /**
     * 確認画面 初期表示処理
     *
     * @param confirmForm {@ConfirmForm} オブジェクト
     * @param sessionData {@SessionData} オブジェクト
     * @return 確認画面の Thymeleaf テンプレートファイルのパス
     */
    @GetMapping
    public String index(ConfirmForm confirmForm
            , SessionData sessionData) {
        modelMapper.map(sessionData, confirmForm);
        return TEMPLATE_CONFIRM;
    }

    ..........

}
  • private final ModelMapper modelMapper; を追加します。
  • コンストラクタを追加します。
  • index メソッドに ConfirmForm confirmForm, SessionData sessionData の引数を追加し、modelMapper.map(sessionData, confirmForm); を追加します。

confirm.html を変更する

src/main/resources/templates/web/inquiry/confirm.html の以下の点を変更します。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{web/common/fragments :: common_header(~{::title}, ~{::link}, ~{::style})}">
  <title>入力フォーム - 確認画面</title>

  <style>
    /* セルの上部の罫線を表示しないようようにし、セル内の余白を詰める */
    .table > tbody > tr > th,
    .table > tbody > tr > td {
      border-top: none;
      padding: 5px;
    }
  </style>
</head>

<body class="skin-blue layout-top-nav">
<div class="wrapper">

  <!-- Content Wrapper. Contains page content -->
  <div class="content-wrapper">
    <!-- Content Header (Page header) -->
    <section class="content-header">
      <h1>
        確認画面
      </h1>
    </section>

    <!-- Main content -->
    <section class="content">
      <div class="row">
        <div class="col-xs-12">
          <!--/*@thymesVar id="confirmForm" type="ksbysample.webapp.bootnpmgeb.web.inquiry.form.ConfirmForm"*/-->
          <form id="confirmForm" method="post" action=""
                th:action="@{/inquiry/confirm/}"
                th:object="${confirmForm}">
            <table class="table">
              <colgroup>
                <col width="15%"/>
                <col width="85%"/>
              </colgroup>

              <!-- 入力画面1の項目 -->
              <tr>
                <th nowrap>お名前(漢字)</th>
                <td th:text="*{name}">田中 太郎</td>
              </tr>
              <tr>
                <th nowrap>お名前(かな)</th>
                <td th:text="*{kana}">たなか たろう</td>
              </tr>
              <tr>
                <th nowrap>性別</th>
                <td th:text="*{sex}">男性</td>
              </tr>
              <tr>
                <th nowrap>年齢</th>
                <td>
                  <th:block th:text="*{age}">30</th:block></td>
              </tr>
              <tr>
                <th nowrap>職業</th>
                <td th:text="*{job}">会社員</td>
              </tr>
              <tr>
                <td colspan="2">
                  <button class="btn bg-blue js-btn-input01"><i class="fa fa-arrow-left"></i> 修正する</button>
                </td>
              </tr>

              <!-- 入力画面2の項目 -->
              <tr>
                <th nowrap>郵便番号</th>
                <td><th:block th:text="*{zipcode}">102-0072</th:block>
                </td>
              </tr>
              <tr>
                <th nowrap>住所</th>
                <td th:text="*{address}">東京都千代田区飯田橋1-1</td>
              </tr>
              <tr>
                <th nowrap>電話番号</th>
                <td th:text="*{tel}">03-1234-5678</td>
              </tr>
              <tr>
                <th nowrap>メールアドレス</th>
                <td th:text="*{email}">taro.tanaka@sample.co.jp</td>
              </tr>
              <tr>
                <td colspan="2">
                  <button class="btn bg-blue js-btn-input02"><i class="fa fa-arrow-left"></i> 修正する</button>
                </td>
              </tr>

              <!-- 入力画面3の項目 -->
              <tr>
                <th nowrap>お問い合わせの種類1</th>
                <td th:text="*{type1}">製品に関するお問い合わせ</td>
              </tr>
              <tr>
                <th nowrap>お問い合わせの種類2</th>
                <td th:text="*{type2}">見積が欲しい</td>
              </tr>
              <tr>
                <th nowrap>お問い合わせの内容</th>
                <td th:utext="*{inquiry} ? ${#strings.replace(#strings.escapeXml(confirmForm.inquiry), T(java.lang.System).getProperty('line.separator'), '&lt;br /&gt;')} : ''">
                  ここに、<br/>
                  入力されたお問い合わせの内容が表示されます。
                </td>
              </tr>
              <tr>
                <th nowrap>アンケート</th>
                <td>
                  <ul style="padding-left: 20px"
                      th:each="sv : *{survey}">
                    <li th:text="${sv}">選択肢1だけ長くしてみる</li>
                  </ul>
                </td>
              </tr>
              <tr>
                <td colspan="2">
                  <button class="btn bg-blue js-btn-input03"><i class="fa fa-arrow-left"></i> 修正する</button>
                </td>
              </tr>
            </table>

            <div class="text-center">
              <button class="btn bg-green js-btn-send"><i class="fa fa-arrow-right"></i> 送信する</button>
            </div>
          </form>
        </div>
      </div>
    </section>
    <!-- /.content -->
  </div>
  <!-- /.content-wrapper -->
</div>
<!-- ./wrapper -->

<!-- REQUIRED JS SCRIPTS -->
<script src="/js/inquiry/confirm.js"></script>

</body>
</html>
  • form タグの上に <!--/*@thymesVar id="confirmForm" type="ksbysample.webapp.bootnpmgeb.web.inquiry.form.ConfirmForm"*/--> を追加します。
  • form タグの末尾に th:object="${confirmForm}" を追加します。
  • 各表示項目を以下のように変更します。
    • 基本的には td タグに th:text="*{...}"(... には入力項目に対応した変数を記述) を追加します。
    • textarea の入力項目である「お問い合わせの内容」には th:utext="*{inquiry} ? ${#strings.replace(#strings.escapeXml(confirmForm.inquiry), T(java.lang.System).getProperty('line.separator'), '&lt;br /&gt;')} : ''" を追加します。改行は <br/> に変換して出力します。
    • 「アンケート」はリストを出力するので ul タグに th:each="sv : *{survey}" を、li タグに th:text="${sv}" を追加します。

動作確認

動作確認します。npm run springboot コマンドを実行し Tomcat を起動した後、ブラウザで http://localhost:9080/inquiry/input/01/ にアクセスします。

入力画面1~3に以下の画像のデータを入力します。

f:id:ksby:20180613211511p:plain f:id:ksby:20180613211616p:plain f:id:ksby:20180613211723p:plain

確認画面を表示すると入力したデータが表示されます。

f:id:ksby:20180613211957p:plain f:id:ksby:20180613212129p:plain

  • ラジオボタンやドロップダウンリストで選択する項目は、選択された文字列が表示されています。
  • 「郵便番号」や「電話番号」は入力した値が "-" で結合して表示されています。
  • 「お問い合わせの種類2」は選択した項目が "、" で結合して表示されています。
  • 「お問い合わせの内容」は改行した箇所は改行されて表示されています。
  • 「アンケート」は選択した項目が列挙されています。

「職業」や「アンケート」を選択しなかったり、「電話番号」を入力しないと、

f:id:ksby:20180613232244p:plain f:id:ksby:20180613232332p:plain f:id:ksby:20180613232429p:plain

確認画面の「職業」「電話番号」「アンケート」には何も表示されません。

f:id:ksby:20180613232624p:plain

次は。。。

「修正する」ボタンの処理→「送信する」ボタンの処理の順に実装します。

履歴

2018/06/13
初版発行。