Spring Boot でメール送信する Web アプリケーションを作る ( その21 )( 気になった点を修正2 )
概要
Spring Boot でメール送信する Web アプリケーションを作る ( その20 )( 気になった点を修正 ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
ソフトウェア一覧
参考にしたサイト
手順
Thymeleaf テンプレートファイルの共通部分を読み込むタグを修正する
Thymeleaf テンプレートファイル内で共通の css, js ファイルを読み込む部分を meta タグで書いていたのですが、さすがに meta タグはないなと思ったので 読み込むファイルの中で一番記述されているタグに合わせて link, script タグへ修正します。
IntelliJ IDEA で 1.0.x-replace-htmltag ブランチを作成します。
src/main/resources/templates/mailsend の下の mailsend.html を リンク先のその1の内容 に変更します。
src/main/resources/templates/mailsearch の下の mailsearch.html を リンク先のその1の内容 に変更します。
画面が表示されるか確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。
ブラウザを起動し http://localhost:8080/mailsearch へアクセスします。画面が表示され、カーソルも「To」の項目にセットされることを確認します。
ブラウザを起動し http://localhost:8080/mailsend へアクセスします。画面が表示され、カーソルも「From」の項目にセットされることを確認します。
Ctrl+F2 を押して Tomcat を停止します。
commit、GitHub へ Push、1.0.x-replace-htmltag -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-replace-htmltag ブランチを削除、をします。
Pagable を元に SelectOptions のインスタンスを生成するための util クラスを作成する
IntelliJ IDEA で 1.0.x-selectoptions-helper ブランチを作成します。
src/main/java/ksbysample/webapp/email/util の下に SelectOptionsUtils.java を新規作成します。作成後、リンク先の内容 に変更します。
src/main/java/ksbysample/webapp/email/web/mailsearch の下の MailsearchService.java を リンク先の内容 に変更します。
Gradle projects View から bootRun タスクを実行して Tomcat を起動し、ページングが正常に動作するか確認します。確認後、Ctrl+F2 を押して Tomcat を停止します。
commit、GitHub へ Push、1.0.x-selectoptions-helper -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-selectoptions-helper ブランチを削除、をします。
値とテキストの定義を YAML ファイル+Constant クラス → enum へ変更する
値とテキストの組み合わせを定義するのに YAML ファイル+Constant.java で実装していますが、この方法だと FormValidator クラスで Form クラスの値をチェックする時等に利用しにくく "1"
のように実際の値を書いていたので、enum で定義するよう変更して Java のソースファイルや Thymeleaf テンプレートファイル内では作成した enum を参照するようにしてみます。
今回は Constant.java 内の TYPE_MAP のみ enum へ変更します。それ以外は今のままです。
また Doma のドメインクラスにすることも考えたのですが、DomaGen で自動生成された Entity クラスを変更するのがちょっと手間だったので、やめました。
src/main/java/ksbysample/webapp/email の下に domain パッケージを作成します。
src/main/java/ksbysample/webapp/email/domain の下に InquiryType.java を新規作成します。作成後、リンク先の内容 に変更します。
src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendFormValidator.java を リンク先の内容 に変更します。
src/main/resources/templates/mailsend の下の mailsend.html を リンク先のその2の内容 に変更します。
src/main/resources/templates/mailsearch の下の mailsearch.html を リンク先のその2の内容 に変更します。
src/main/java/ksbysample/webapp/email/helper/mail の下の MAIL001MailHelper.java を リンク先の内容 に変更します。
src/test/java/ksbysample/webapp/email/helper/mail の下の MAIL001MailHelperTest.java を リンク先の内容 に変更します。
src/test/java/ksbysample/webapp/email/web/mailsend の下の MailsendServiceTest.java を リンク先の内容 に変更します。
src/main/resources の下の constant.yml を リンク先の内容 に変更します。
src/test/java/ksbysample/webapp/email/config の下の Constant.java を リンク先の内容 に変更します。
Project View のルートでコンテキストメニューを表示して「Run 'Tests in 'ksbysample...' with Coverage」を選択し、テストが全て成功することを確認します。
Gradle projects View から build タスクを実行し、"BUILD SUCCESSFUL" が出力されることを確認します。
Gradle projects View から bootRun タスクを実行して Tomcat を起動し、以下の点を確認します。確認後、Ctrl+F2 を押して Tomcat を停止します。
- メール送信画面(http://localhost:8080/mailsend)の「項目」のドロップダウンリストにテキストが正常に表示される。
- メール送信画面から「送信」ボタンをクリックしてテキストメールを送信した時に、テキストメール内の「項目」にテキストが正常に表示される。
- メール送信画面から「HTMLメール送信」ボタンをクリックしてHTMLメールを送信した時に、HTMLメール内の「項目」にテキストが正常に表示される。
- 送信済メール検索画面(http://localhost:8080/mailsearch)の検索条件の「項目」、一覧の「項目」にテキストが正常に表示される。
commit、GitHub へ Push、1.0.x-constant-enum -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-constant-enum ブランチを削除、をします。
最後に感想です。
ソースコード
mailsend.html
■その1
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>ksbysample-webapp-email</title> <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'/> <link th:replace="common/head-cssjs"/> <style> <!-- .checkbox label, .radio label { padding-right: 10px; } .form-control-static { padding-top: 0px; padding-bottom: 0px; } .has-error .form-control { background-color: #fff5ee; } --> </style> </head> <body class="skin-blue"> <div class="wrapper"> <!-- Main Header --> <div th:replace="common/mainparts :: main-header"></div> <!-- Left side column. contains the logo and sidebar --> <div th:replace="common/mainparts :: main-sidebar (active='mailsend')"></div> <!-- 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"> <form id="mailsendForm" method="post" action="/mailsend/send" th:action="@{/mailsend/send}" th:object="${mailsendForm}" class="form-horizontal"> <div class="callout callout-danger" th:if="${#fields.hasGlobalErrors()}"> <p th:each="err : ${#fields.globalErrors()}" th:text="${err}">共通エラーメッセージ表示エリア</p> </div> <div class="box box-primary"> <div class="box-body"> <div class="form-group" th:classappend="${#fields.hasErrors('*{fromAddr}')} ? 'has-error' : ''"> <label for="fromAddr" class="control-label col-sm-2">From</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"><div class="input-group"><span class="input-group-addon"><i class="fa fa-envelope"></i></span><input type="text" name="fromAddr" id="fromAddr" class="form-control input-sm" value="" placeholder="Fromアドレスを入力して下さい" th:field="*{fromAddr}"/></div></div></div> <div class="row" th:if="${#fields.hasErrors('*{fromAddr}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{fromAddr}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{toAddr}')} ? 'has-error' : ''"> <label for="toAddr" class="control-label col-sm-2">To</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"><div class="input-group"><span class="input-group-addon"><i class="fa fa-envelope"></i></span><input type="text" name="toAddr" id="toAddr" class="form-control input-sm" value="" placeholder="Toアドレスを入力して下さい" th:field="*{toAddr}"/></div></div></div> <div class="row" th:if="${#fields.hasErrors('*{toAddr}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{toAddr}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{subject}')} ? 'has-error' : ''"> <label for="subject" class="control-label col-sm-2">Subject</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"><input type="text" name="subject" id="subject" class="form-control input-sm" value="" placeholder="件名を入力して下さい" th:field="*{subject}"/></div></div> <div class="row" th:if="${#fields.hasErrors('*{subject}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{subject}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{name}')} ? 'has-error' : ''"> <label for="name" class="control-label col-sm-2">氏名</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"><input type="text" name="name" id="name" class="form-control input-sm" value="" placeholder="(例) 田中 太郎" th:field="*{name}"/></div></div> <div class="row" th:if="${#fields.hasErrors('*{name}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{name}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{sex}')} ? 'has-error' : ''"> <label class="control-label col-sm-2">性別</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"> <div class="radio"> <label th:each="sex : ${T(ksbysample.webapp.email.config.Constant).getInstance().SEX_MAP.entrySet()}"> <input type="radio" name="sex" th:value="${sex.getKey()}" th:text="${sex.getValue()}" th:field="*{sex}"/> </label> </div> </div></div> <div class="row" th:if="${#fields.hasErrors('*{sex}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{sex}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{type}')} ? 'has-error' : ''"> <label class="control-label col-sm-2">項目</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"> <select name="type" id="type" class="form-control input-sm" th:field="*{type}"> <option th:each="type : ${T(ksbysample.webapp.email.config.Constant).getInstance().TYPE_MAP.entrySet()}" th:value="${type.getKey()}" th:text="${type.getValue()}">sex</option> </select> </div></div> <div class="row" th:if="${#fields.hasErrors('*{type}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{type}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{item}')} ? 'has-error' : ''"> <label class="control-label col-sm-2">商品</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"> <div class="checkbox"> <label th:each="item : ${T(ksbysample.webapp.email.config.Constant).getInstance().ITEM_MAP.entrySet()}"> <input type="checkbox" name="item" th:value="${item.getKey()}" th:text="${item.getValue()}" th:field="*{item}"/> </label> </div> </div></div> <div class="row" th:if="${#fields.hasErrors('*{item}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{item}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{naiyo}')} ? 'has-error' : ''"> <label for="naiyo" class="control-label col-sm-2">内容</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"><textarea rows="5" name="naiyo" id="naiyo" class="form-control input-sm" placeholder="お問い合わせ内容を入力して下さい" th:field="*{naiyo}"></textarea></div></div> <div class="row" th:if="${#fields.hasErrors('*{naiyo}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{naiyo}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="form-group" th:classappend="${#fields.hasErrors('*{attachedFile}')} ? 'has-error' : ''"> <label class="control-label col-sm-2">添付</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"> <div class="checkbox"> <label> <input type="checkbox" name="attachedFile" th:value="1" th:text="ファイルを添付する" th:field="*{attachedFile}"/> </label> </div> </div></div> <div class="row" th:if="${#fields.hasErrors('*{item}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{item}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div> </div> <div class="box-footer"> <div class="text-center"> <button type="button" id="send" value="send" class="btn btn-primary">送信</button> <button type="button" id="sendhtml" value="sendhtml" class="btn btn-default">HTMLメール送信</button> </div> </div> </div> </form> </div> </div> </section> <!-- /.content --> </div> <!-- /.content-wrapper --> </div> <!-- ./wrapper --> <!-- REQUIRED JS SCRIPTS --> <script th:replace="common/bottom-js"/> <script type="text/javascript"> <!-- $(document).ready(function() { $('#fromAddr').focus(); $('#send').bind('click', function(){ $('#mailsendForm').submit(); }); $('#sendhtml').bind('click', function(){ $('#mailsendForm').attr('action', '/mailsend/sendhtml'); $('#mailsendForm').submit(); }); }); --> </script> </body> </html>
<meta th:replace="common/head-cssjs"/>
→<link th:replace="common/head-cssjs"/>
へ変更します。<div th:replace="common/bottom-js"></div>
→<script th:replace="common/bottom-js"/>
へ変更します。
■その2
<div class="form-group" th:classappend="${#fields.hasErrors('*{type}')} ? 'has-error' : ''"> <label class="control-label col-sm-2">項目</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"> <select name="type" id="type" class="form-control input-sm" th:field="*{type}"> <option th:each="type : ${T(ksbysample.webapp.email.domain.InquiryType).values()}" th:value="${type.getValue()}" th:text="${type.getText()}">sex</option> </select> </div></div> <div class="row" th:if="${#fields.hasErrors('*{type}')}"><div class="col-sm-10"><p class="form-control-static text-danger"><small th:errors="*{type}">ここにエラーメッセージを表示します</small></p></div></div> </div> </div>
<option th:each="type : ${T(ksbysample.webapp.email.config.Constant).getInstance().TYPE_MAP.entrySet()}
→<option th:each="type : ${T(ksbysample.webapp.email.domain.InquiryType).values()}"
へ変更します。それに伴い th:value, th:text に記述する部分で呼び出すメソッドも変更します。
mailsearch.html
■その1
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>ksbysample-webapp-email</title> <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'/> <link th:replace="common/head-cssjs"/> <style> <!-- .form-group { margin-bottom: 5px; } .table { margin-top: 10px; margin-bottom: 0px; } .table>tbody>tr>td , .table>tbody>tr>th , .table>tfoot>tr>td , .table>tfoot>tr>th , .table>thead>tr>td , .table>thead>tr>th { padding: 5px; } .checkbox label, .radio label { padding-right: 10px; } .pagination > .disabled > a , .pagination > .disabled > a:focus , .pagination > .disabled > a:hover , .pagination > .disabled > span , .pagination > .disabled > span:focus , .pagination > .disabled > span:hover { color: #eee; cursor: not-allowed; background-color: #fff; border-color: #ddd; } --> </style> </head> <body class="skin-blue"> <div class="wrapper"> <!-- Main Header --> <div th:replace="common/mainparts :: main-header"></div> <!-- Left side column. contains the logo and sidebar --> <div th:replace="common/mainparts :: main-sidebar (active='mailsearch')"></div> <!-- 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"> <div class="box"> <div class="box-header with-border bg-purple-gradient"> <div class="row"> <div class="col-xs-12"> <form id="mailSearchForm" method="post" action="/mailsearch" th:action="@{/mailsearch}" th:object="${mailsearchForm}" class="form-horizontal"> <div class="form-group"> <label for="toAddr" class="control-label col-sm-2">To</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"><div class="input-group"><span class="input-group-addon"><i class="fa fa-envelope"></i></span><input type="text" name="toAddr" id="toAddr" class="form-control input-sm" value="" placeholder="" th:field="*{toAddr}"/></div></div></div> </div> </div> <div class="form-group"> <label for="subject" class="control-label col-sm-2">Subject</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"><input type="text" name="subject" id="subject" class="form-control input-sm" value="" placeholder="" th:field="*{subject}"/></div></div> </div> </div> <div class="form-group"> <label for="name" class="control-label col-sm-2">氏名</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"><input type="text" name="name" id="name" class="form-control input-sm" value="" placeholder="" th:field="*{name}"/></div></div> </div> </div> <div class="form-group"> <label class="control-label col-sm-2">項目</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"> <div class="checkbox"> <label th:each="type : ${T(ksbysample.webapp.email.config.Constant).getInstance().TYPE_MAP.entrySet()}"> <input type="checkbox" name="type" th:value="${type.getKey()}" th:text="${type.getValue()}" th:field="*{type}"/> </label> </div> </div></div> </div> </div> <div class="text-center"> <button type="button" id="search" value="search" class="btn btn-primary bg-gray">検索</button> </div> </form> </div> </div> </div> <div class="box-body"> <div id="maillist_wrapper" class="dataTables_wrapper form-inline" role="grid"> <table id="maillist" class="table table-bordered table-hover dataTable" aria-describedby="maillist_info"> <thead class="bg-purple"> <tr role="row"> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">To</th> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">Subject</th> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">氏名</th> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">項目</th> </tr> </thead> <tbody role="alert" aria-live="polite" aria-relevant="all"> <tr th:each="email : ${page.content}"> <td th:text="${email.toAddr}">test@sample.com</td> <td th:text="${email.subject}">件名1</td> <td th:text="${email.name}">田中 太郎</td> <td th:text="${T(ksbysample.webapp.email.config.Constant).getInstance().TYPE_MAP.get(email.type)}">資料請求</td> </tr> </tbody> </table> <div id="pagenation" th:include="common/pagenation :: pagenation (url='/mailsearch', page=${page}, ph=${ph})"></div> <form id="pagenationForm" method="post" action="#" th:action="@{#}" th:object="${mailsearchForm}"> <input type="hidden" name="toAddr" id="toAddr" th:value="*{toAddr}"/> <input type="hidden" name="subject" id="subject" th:value="*{subject}"/> <input type="hidden" name="name" id="name" th:value="*{name}"/> <input type="hidden" name="type" id="type" th:each="typeItem : *{type}" th:value="${typeItem}"/> </form> </div> </div> </div> </div> </div> </section> <!-- /.content --> </div> <!-- /.content-wrapper --> </div> <!-- ./wrapper --> <!-- REQUIRED JS SCRIPTS --> <script th:replace="common/bottom-js"/> <script type="text/javascript"> <!-- $(document).ready(function() { $('#toAddr').focus(); $('#search').bind('click', function(){ $('#mailSearchForm').submit(); }); $('.js-pagenation').each(function(){ $(this).click(function(){ $('#pagenationForm').attr('action', $(this).attr('href')); $(this).attr('href', '#'); $('#pagenationForm').submit(); }); }); }); --> </script> </body> </html>
<meta th:replace="common/head-cssjs"/>
→<link th:replace="common/head-cssjs"/>
へ変更します。<div th:replace="common/bottom-js"></div>
→<script th:replace="common/bottom-js"/>
へ変更します。
■その2
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>ksbysample-webapp-email</title> <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'/> <link th:replace="common/head-cssjs"/> <style> <!-- .form-group { margin-bottom: 5px; } .table { margin-top: 10px; margin-bottom: 0px; } .table>tbody>tr>td , .table>tbody>tr>th , .table>tfoot>tr>td , .table>tfoot>tr>th , .table>thead>tr>td , .table>thead>tr>th { padding: 5px; } .checkbox label, .radio label { padding-right: 10px; } .pagination > .disabled > a , .pagination > .disabled > a:focus , .pagination > .disabled > a:hover , .pagination > .disabled > span , .pagination > .disabled > span:focus , .pagination > .disabled > span:hover { color: #eee; cursor: not-allowed; background-color: #fff; border-color: #ddd; } --> </style> </head> <body class="skin-blue"> <div class="wrapper"> <!-- Main Header --> <div th:replace="common/mainparts :: main-header"></div> <!-- Left side column. contains the logo and sidebar --> <div th:replace="common/mainparts :: main-sidebar (active='mailsearch')"></div> <!-- 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"> <div class="box"> <div class="box-header with-border bg-purple-gradient"> <div class="row"> <div class="col-xs-12"> <form id="mailSearchForm" method="post" action="/mailsearch" th:action="@{/mailsearch}" th:object="${mailsearchForm}" class="form-horizontal"> <div class="form-group"> <label for="toAddr" class="control-label col-sm-2">To</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"><div class="input-group"><span class="input-group-addon"><i class="fa fa-envelope"></i></span><input type="text" name="toAddr" id="toAddr" class="form-control input-sm" value="" placeholder="" th:field="*{toAddr}"/></div></div></div> </div> </div> <div class="form-group"> <label for="subject" class="control-label col-sm-2">Subject</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"><input type="text" name="subject" id="subject" class="form-control input-sm" value="" placeholder="" th:field="*{subject}"/></div></div> </div> </div> <div class="form-group"> <label for="name" class="control-label col-sm-2">氏名</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-8"><input type="text" name="name" id="name" class="form-control input-sm" value="" placeholder="" th:field="*{name}"/></div></div> </div> </div> <div class="form-group"> <label class="control-label col-sm-2">項目</label> <div class="col-sm-10"> <div class="row"><div class="col-sm-12"> <div class="checkbox"> <label th:each="type : ${T(ksbysample.webapp.email.domain.InquiryType).values()}"> <input type="checkbox" name="type" th:value="${type.getValue()}" th:text="${type.getText()}" th:field="*{type}"/> </label> </div> </div></div> </div> </div> <div class="text-center"> <button type="button" id="search" value="search" class="btn btn-primary bg-gray">検索</button> </div> </form> </div> </div> </div> <div class="box-body"> <div id="maillist_wrapper" class="dataTables_wrapper form-inline" role="grid"> <table id="maillist" class="table table-bordered table-hover dataTable" aria-describedby="maillist_info"> <thead class="bg-purple"> <tr role="row"> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">To</th> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">Subject</th> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">氏名</th> <th role="columnheader" tabindex="0" aria-controls="maillist" rowspan="1" colspan="1">項目</th> </tr> </thead> <tbody role="alert" aria-live="polite" aria-relevant="all"> <tr th:each="email : ${page.content}"> <td th:text="${email.toAddr}">test@sample.com</td> <td th:text="${email.subject}">件名1</td> <td th:text="${email.name}">田中 太郎</td> <td th:text="${T(ksbysample.webapp.email.domain.InquiryType).getText(email.type)}">資料請求</td> </tr> </tbody> </table> <div id="pagenation" th:include="common/pagenation :: pagenation (url='/mailsearch', page=${page}, ph=${ph})"></div> <form id="pagenationForm" method="post" action="#" th:action="@{#}" th:object="${mailsearchForm}"> <input type="hidden" name="toAddr" id="toAddr" th:value="*{toAddr}"/> <input type="hidden" name="subject" id="subject" th:value="*{subject}"/> <input type="hidden" name="name" id="name" th:value="*{name}"/> <input type="hidden" name="type" id="type" th:each="typeItem : *{type}" th:value="${typeItem}"/> </form> </div> </div> </div> </div> </div> </section> <!-- /.content --> </div> <!-- /.content-wrapper --> </div> <!-- ./wrapper --> <!-- REQUIRED JS SCRIPTS --> <script th:replace="common/bottom-js"/> <script type="text/javascript"> <!-- $(document).ready(function() { $('#toAddr').focus(); $('#search').bind('click', function(){ $('#mailSearchForm').submit(); }); $('.js-pagenation').each(function(){ $(this).click(function(){ $('#pagenationForm').attr('action', $(this).attr('href')); $(this).attr('href', '#'); $('#pagenationForm').submit(); }); }); }); --> </script> </body> </html>
- 検索条件入力部の以下の点を変更します。
<label th:each="type : ${T(ksbysample.webapp.email.config.Constant).getInstance().TYPE_MAP.entrySet()}">
→<label th:each="type : ${T(ksbysample.webapp.email.domain.InquiryType).values()}">
へ変更します。<input type="checkbox" name="type" th:value="${type.getKey()}" th:text="${type.getValue()}" th:field="*{type}"/>
→<input type="checkbox" name="type" th:value="${type.getValue()}" th:text="${type.getText()}" th:field="*{type}"/>
へ変更します。
- 一覧表示部の以下の点を変更します。
<td th:text="${T(ksbysample.webapp.email.config.Constant).getInstance().TYPE_MAP.get(email.type)}">資料請求</td>
→<td th:text="${T(ksbysample.webapp.email.domain.InquiryType).getText(email.type)}">資料請求</td>
へ変更します。
SelectOptionsUtils.java
package ksbysample.webapp.email.util; import org.seasar.doma.jdbc.SelectOptions; import org.springframework.data.domain.Pageable; public class SelectOptionsUtils { public static SelectOptions get(Pageable pageable, boolean countFlg) { int offset = pageable.getPageNumber() * pageable.getPageSize(); int limit = pageable.getPageSize(); SelectOptions selectOptions = null; if (countFlg) { selectOptions = SelectOptions.get().offset(offset).limit(limit).count(); } else { selectOptions = SelectOptions.get().offset(offset).limit(limit); } return selectOptions; } }
MailsearchService.java
package ksbysample.webapp.email.web.mailsearch; import ksbysample.webapp.email.entity.Email; import ksbysample.webapp.email.util.SelectOptionsUtils; import org.seasar.doma.jdbc.SelectOptions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; @Service public class MailsearchService { @Autowired private MailsearchDao mailsearchDao; public Page<Email> searchEmail(MailsearchForm mailsearchForm, Pageable pageable) { SelectOptions options = SelectOptionsUtils.get(pageable, true); List<Email> emailList = mailsearchDao.selectCondition(mailsearchForm, options); long count = options.getCount(); Page<Email> page = new PageImpl<Email>(emailList, pageable, count); return page; } }
- SelectOptions のインスタンスを取得する方法を
SelectOptionsUtils.get(pageable, true);
に変更します。
InquiryType.java
package ksbysample.webapp.email.domain; import lombok.Getter; import org.apache.commons.lang3.StringUtils; @Getter public enum InquiryType { SHIRYO_SEIKYU("1", "資料請求") , SHOHIN_NI_KANSURU_KUJO("2", "商品に関する苦情") , SONOTA("3", "その他"); private final String value; private final String text; private InquiryType(String value, String text) { this.value = value; this.text = text; } public static String getText(String value) { String result = ""; for (InquiryType inquiryType : InquiryType.values()) { if (StringUtils.equals(inquiryType.getValue(), value)) { result = inquiryType.getText(); } } return result; } }
MailsendFormValidator.java
package ksbysample.webapp.email.web.mailsend; import ksbysample.webapp.email.config.Constant; import ksbysample.webapp.email.domain.InquiryType; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; @Component public class MailsendFormValidator implements Validator { @Override public boolean supports(Class<?> clazz) { return clazz.equals(MailsendForm.class); } @Override public void validate(Object target, Errors errors) { MailsendForm mailsendForm = (MailsendForm)target; Constant constant = Constant.getInstance(); // 「項目」が「資料請求」「商品に関する苦情」の場合には「商品」が何も選択されていない場合にはエラー if (StringUtils.equals(mailsendForm.getType(), InquiryType.SHIRYO_SEIKYU.getValue()) || StringUtils.equals(mailsendForm.getType(), InquiryType.SHOHIN_NI_KANSURU_KUJO.getValue())) { if ((mailsendForm.getItem() == null) || (mailsendForm.getItem().size() == 0)) { errors.reject("mailsendForm.item.noSelect"); } } // 「項目」が「その他」の場合には「内容」に何も入力されていない場合にはエラー if (StringUtils.equals(mailsendForm.getType(), InquiryType.SONOTA.getValue())) { if (mailsendForm.getNaiyo().length() == 0) { errors.reject("mailsendForm.naiyo.noText"); } } } }
- mailsendForm.getType() と値を比較していた部分に具体的な値を記述していたのを InquiryType で記述するよう変更します。
StringUtils.equals(mailsendForm.getType(), "1")
→StringUtils.equals(mailsendForm.getType(), InquiryType.SHIRYO_SEIKYU.getValue())
のようになります。
MAIL001MailHelper.java
private String generateTextUsingVelocity(MailsendForm mailsendForm) { Constant constant = Constant.getInstance(); Map<String, Object> model = new HashMap<>(); model.put("name", mailsendForm.getName()); model.put("sex", constant.SEX_MAP.get(mailsendForm.getSex())); model.put("type", InquiryType.getText(mailsendForm.getType())); String itemList = null; if (mailsendForm.getItem() != null) { itemList = mailsendForm.getItem().stream() .map(constant.ITEM_MAP::get) .collect(Collectors.joining(", ")); } model.put("item", itemList); model.put("naiyo", mailsendForm.getNaiyo()); return velocityUtils.merge(this.TEMPLATE_LOCATION_TEXTMAIL, model); } private String generateTextUsingThymeleaf(MailsendForm mailsendForm) { Constant constant = Constant.getInstance(); Context ctx = new Context(LocaleContextHolder.getLocale()); ctx.setVariable("name", mailsendForm.getName()); ctx.setVariable("sex", constant.SEX_MAP.get(mailsendForm.getSex())); ctx.setVariable("type", InquiryType.getText(mailsendForm.getType())); String itemList = null; if (mailsendForm.getItem() != null) { itemList = mailsendForm.getItem().stream() .map(constant.ITEM_MAP::get) .collect(Collectors.joining(", ")); } ctx.setVariable("item", itemList); ctx.setVariable("naiyo", mailsendForm.getNaiyo()); return this.templateEngine.process(this.TEMPLATE_LOCATION_HTMLMAIL, ctx); }
- generateTextUsingVelocity, generateTextUsingThymeleaf メソッド内の
constant.TYPE_MAP.get(mailsendForm.getType())
→InquiryType.getText(mailsendForm.getType())
へ変更します。
MAIL001MailHelperTest.java
@Test public void MailsendFormの全てに値がセットされている場合() throws Exception { MimeMessage message = mail001MailHelper.createHtmlMessage(mailsendFormSimple); // from, Subject InternetAddress address = (InternetAddress) message.getFrom()[0]; assertThat(address.getAddress(), is(mailsendFormSimple.getFromAddr())); assertThat(message.getSubject(), is(mailsendFormSimple.getSubject())); // メール本文 Document document = DocumentBuilderFactory .newInstance() .newDocumentBuilder() .parse(new InputSource(new StringReader((String) message.getContent()))); Constant constant = Constant.getInstance(); assertThat(document, hasXPath("//*[@id=\"name\"]", equalTo(mailsendFormSimple.getName()))); assertThat(document, hasXPath("//*[@id=\"sex\"]", equalTo(constant.SEX_MAP.get(mailsendFormSimple.getSex())))); assertThat(document, hasXPath("//*[@id=\"type\"]", equalTo(InquiryType.getText(mailsendFormSimple.getType())))); assertThat(document, hasXPath("//*[@id=\"item\"]" , equalTo( mailsendFormSimple.getItem().stream() .map(constant.ITEM_MAP::get) .collect(Collectors.joining(", "))))); assertThat(document, hasXPath("//*[@id=\"naiyo\"]", equalTo(mailsendFormSimple.getNaiyo()))); }
- 「MailsendFormの全てに値がセットされている場合」テストメソッド内の
constant.TYPE_MAP.get(mailsendForm.getType())
→InquiryType.getText(mailsendForm.getType())
へ変更します。
MailsendServiceTest.java
@Test public void mailsendFormSimpleでHTMLメールを送信する場合() throws Exception { mailsendService.saveAndSendHtmlEmail(mailsendFormSimple); // email, email_item テーブルに保存されているか確認する IDataSet dataSet = new CsvDataSet(new File("src/test/resources/ksbysample/webapp/email/web/mailsend/testdata/simple")); TableDataAssert tableDataAssert = new TableDataAssert(dataSet, dataSource); tableDataAssert.assertEquals("email", new String[]{"email_id"}); tableDataAssert.assertEquals("email_item", new String[]{"email_item_id", "email_id"}); // メールが送信されているか確認する assertThat(mailServer.getMessagesCount(), is(1)); MimeMessage receiveMessage = mailServer.getFirstMessage(); assertThat(receiveMessage.getFrom()[0], is(new InternetAddress("test@sample.com"))); assertThat(receiveMessage.getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz"))); assertThat(receiveMessage.getSubject(), is("テスト")); // メール本文 Document document = DocumentBuilderFactory .newInstance() .newDocumentBuilder() .parse(new InputSource(new StringReader((String) receiveMessage.getContent()))); Constant constant = Constant.getInstance(); assertThat(document, hasXPath("//*[@id=\"name\"]", equalTo(mailsendFormSimple.getName()))); assertThat(document, hasXPath("//*[@id=\"sex\"]", equalTo(constant.SEX_MAP.get(mailsendFormSimple.getSex())))); assertThat(document, hasXPath("//*[@id=\"type\"]", equalTo(InquiryType.getText(mailsendFormSimple.getType())))); assertThat(document, hasXPath("//*[@id=\"item\"]" , equalTo( mailsendFormSimple.getItem().stream() .map(constant.ITEM_MAP::get) .collect(Collectors.joining(", "))))); assertThat(document, hasXPath("//*[@id=\"naiyo\"]", equalTo(mailsendFormSimple.getNaiyo()))); }
- 「mailsendFormSimpleでHTMLメールを送信する場合」テストメソッド内の
constant.TYPE_MAP.get(mailsendForm.getType())
→InquiryType.getText(mailsendForm.getType())
へ変更します。
constant.yml
!!ksbysample.webapp.email.config.Constant SEX_MAP: 1: 男性 2: 女性 ITEM_MAP: 101: 商品1 102: 商品2 103: 商品3
- TYPE_MAP の定義を削除します。
Constant.java
package ksbysample.webapp.email.config; import org.springframework.stereotype.Component; import org.yaml.snakeyaml.Yaml; import java.util.Map; @Component public class Constant { private static final Constant instance = (Constant) new Yaml().load(Constant.class.getResourceAsStream("/constant.yml")); public static Constant getInstance() { return instance; } // 性別 public Map<String, String> SEX_MAP; // 商品 public Map<String, String> ITEM_MAP; }
public Map<String, String> TYPE_MAP;
を削除します。
履歴
2015/06/21
初版発行。