Spring Boot でメール送信する Web アプリケーションを作る ( その9 )( メール送信画面の作成4 )
概要
Spring Boot でメール送信する Web アプリケーションを作る ( その8 )( メール送信画面の作成3 ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- メール送信画面の作成
- 以下の点を調査・修正します。
- create table 文のテーブル名/カラム名は英大文字で記述したのですが、Doma-Gen で生成された Entity クラスの中のテーブル名/カラム名や、pgAdmin Ⅲ 上に表示されるテーブル名/カラム名は英小文字で表示されていることに気づきました。PostgreSQL でのテーブル名/カラム名の命名ルールを確認してみます。
- 現在 Service クラスのメソッドに @Transactional アノテーションを付加してトランザクションを開始していますが、XMLファイルから AOP でトランザクションが設定されるようにします。
- dataSource と transactionManager を利用したいだけならば spring-boot-starter-data-jpa ではなく spring-boot-starter-jdbc でもよいような気がするので試してみます。
- 性別(sex)と項目(type)が保存されない問題を解消します。
- email_item テーブルにデータを保存する処理で毎回インスタンスを生成するように実装しましたが、emailItemId をクリアすればよいだけのような気もするので試してみます。
- 画面の初期表示時に From の入力フィールドにカーソルが移動するようにします。
ソフトウェア一覧
参考にしたサイト
PostgreSQLでは識別子に大文字を使ってはいけない
http://doma.readthedocs.org/ja/stable/Postgresqlのテーブル名が大文字だとややこしい件
http://suguru1989-programming.hatenablog.com/entry/2014/07/10/001357PostgreSQLで大文字のテーブル名やフィールド名を扱う
http://cadweb.jp/blog/2006/09/postgresql.html
手順
PostgreSQL のテーブル名/カラム名は必ず小文字?
「参考にしたサイト」に上げたサイトの内容を読んだ結論は、PostgreSQL では SQL 文内のダブルクォーテーションで囲まれていないテーブル名/カラム名は英小文字に変換される、ということでした。まさかそんな仕様があるとは。。。 PostgreSQL を使用する時は英大文字は使わないという対応が無難ですね。
SQL ファイル、Java のソース内のコメントのテーブル名/カラム名を英小文字に変更します。IntelliJ IDEA では変換したい文字にカーソルを移動して ( 変換したい文字列を選択状態にする必要はありません ) Ctrl+SHIFT+U を押せば英大文字←→英小文字に変換することが出来ます。
IntelliJ IDEA で 1.0.x-lower-tablename ブランチを作成します。
/sql の下の create_table.sql を リンク先のその1の内容 に変更します。
src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendService.java を リンク先のその1の内容 に変更します。
commit、GitHub へ Push、1.0.x-lower-tablename -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-lower-tablename ブランチを削除、をします。
@Transactional アノテーションではなく applicationContext.xml でトランザクションを設定する
IntelliJ IDEA で 1.0.x-transactionwithconf ブランチを作成します。
@Transactional アノテーションを削除します。src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendService.java を リンク先のその2の内容 に変更します。
ksbysample.webapp.email の下 ( サブパッケージを含む ) にある末尾が "Service" で終わるクラスのメソッド全てに txAdvice の設定を反映します。src/main/resources の下の applicationContext.xml を リンク先の内容 に変更します。
動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。
ブラウザを起動し http://localhost:8080/mailsend へアクセスします。以下の画像の値を入力後、「送信」ボタンをクリックします。
エラーは発生せず、メールも送信され email, email_item どちらのテーブルにもデータが保存されていました。
Run View で Ctrl+F2 を押して Tomcat を停止します。
commit、GitHub へ Push、1.0.x-transactionwithconf -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-transactionwithconf ブランチを削除、をします。
spring-boot-starter-data-jpa ではなく spring-boot-starter-jdbc でも dataSource, transactionManager は利用可能か?
dataSource の生成の仕組みと自動生成される transactionManager Bean を利用したいだけで、Doma 2 を使用する場合には Spring Data JPA を利用することはないので、spring-boot-starter-data-jpa ではなく spring-boot-starter-jdbc でも大丈夫なのか確認します。
IntelliJ IDEA で 1.0.x-starter-jpa2jdbc ブランチを作成します。
build.gradle を リンク先の内容 に変更します。
Gradle projects View の左上にある「Refresh all Gradle projects」アイコンをクリックして、変更した build.gradle の内容を反映します。
Gradle projects View から clean タスク、build タスクを実行します。
Gradle projects View から bootRun タスクを実行して Tomcat を起動しようとしたところ
java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutExpression
というエラーログが出力されて起動できませんでした。AspectJ のライブラリが足りないようです。単純に spring-boot-starter-data-jpa → spring-boot-starter-jdbc に変更しても動作するのかを確認したいだけでしたので、この件の調査はこれで中止とします。
※逆にこのエラーで気づきましたが、spring-boot-starter-data-jpa を入れると Spring AOP に必要なライブラリも読み込まれて AOP が使用できるようになるようです。
変更を全て元に戻します。
C:\project-springboot\ksbysample-webapp-email>git reset --hard
ブランチを 1.0.x に変更し、1.0.x-starter-jpa2jdbc ブランチを削除します。
Gradle projects View の左上にある「Refresh all Gradle projects」アイコンをクリックして、変更した build.gradle の内容を反映します。
Gradle projects View から clean タスク、build タスクを実行します。
Gradle projects View から bootRun タスクを実行して Tomcat が起動することを確認した後、Run View で Ctrl+F2 を押して Tomcat を停止します。
性別(sex)と項目(type)を保存する
email テーブルの sex, type、email_item テーブルの item を Form クラスに合わせて smallint → varchar へ変更します。
IntelliJ IDEA で 1.0.x-change-columntype ブランチを作成します。
/sql の下の create_table.sql を リンク先のその2の内容 に変更します。
テーブルを作成し直します。
C:\project-springboot\ksbysample-webapp-email>psql -U ksbyemail_user ksbyemail ユーザ ksbyemail_user のパスワード: psql (9.4.1) "help" でヘルプを表示します. ksbyemail=> drop table email_item; DROP TABLE ksbyemail=> drop table email; DROP TABLE ksbyemail=> CREATE TABLE email ksbyemail-> ( ksbyemail(> email_id bigserial primary key ksbyemail(> , from_addr varchar(65) not null ksbyemail(> , to_addr varchar(65) not null ksbyemail(> , subject varchar(128) not null ksbyemail(> , name varchar(32) ksbyemail(> , sex varchar(1) ksbyemail(> , type varchar(1) ksbyemail(> , naiyo text ksbyemail(> ); CREATE TABLE ksbyemail=> CREATE TABLE email_item ksbyemail-> ( ksbyemail(> email_item_id bigserial primary key ksbyemail(> , email_id bigint not null references EMAIL(email_id) on delete cascade ksbyemail(> , item varchar(3) ksbyemail(> ); CREATE TABLE ksbyemail=> \d リレーションの一覧 スキーマ | 名前 | 型 | 所有者 ----------+------------------------------+------------+---------------- public | email | テーブル | ksbyemail_user public | email_email_id_seq | シーケンス | ksbyemail_user public | email_item | テーブル | ksbyemail_user public | email_item_email_item_id_seq | シーケンス | ksbyemail_user (4 行) ksbyemail=> \q C:\project-springboot\ksbysample-webapp-email>
※drop table すると id 自動発行用のシーケンスも作成し直されて、発行される値が 1 に戻ります。
Gradle projects View から gen タスクを実行して Entity クラスを作成し直します。以下メモ書きです。
src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendService.java を リンク先のその3の内容 に変更します。
動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。
ブラウザを起動し http://localhost:8080/mailsend へアクセスします。以下の画像の値を入力後、「送信」ボタンをクリックします。
エラーは発生せず、メールも送信されました。email, email_item どちらのテーブルにもデータが保存されており、かつ性別(sex)と項目(type)にも値がセットされています。
Run View で Ctrl+F2 を押して Tomcat を停止します。
commit、GitHub へ Push、1.0.x-transactionwithconf -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-transactionwithconf ブランチを削除、をします。
email_item テーブルのデータ保存処理で毎回インスタンスを生成しなくてもよいか?
IntelliJ IDEA で 1.0.x-necessary-new-emailitem ブランチを作成します。
src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendService.java を リンク先のその4の内容 に変更します。
動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。email, email_item テーブルにデータが登録されている場合には全て削除しておきます。
ブラウザを起動し http://localhost:8080/mailsend へアクセスします。以下の画像の値を入力後、「送信」ボタンをクリックします。
エラーは発生せず、メールも送信されました。email_item テーブルにもデータが保存されています。
問題なさそうですので、このまま進めます。Run View で Ctrl+F2 を押して Tomcat を停止します。
commit、GitHub へ Push、1.0.x-necessary-new-emailitem -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-necessary-new-emailitem ブランチを削除、をします。
画面の初期表示時に From の入力フィールドにカーソルを移動する
ID を from → fromAddr に変更した際に Javascript 内の ID を変更するのを忘れていました。修正します。
IntelliJ IDEA で 1.0.x-setcursor-fromfield ブランチを作成します。
src/main/resources/templates/mailsend の下の mailsend.html を リンク先の内容 に変更します。
動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。
ブラウザを起動し http://localhost:8080/mailsend へアクセスし、From フィールドにカーソルが移動することを確認します。
Run View で Ctrl+F2 を押して Tomcat を停止します。
commit、GitHub へ Push、1.0.x-necessary-new-emailitem -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-necessary-new-emailitem ブランチを削除、をします。
ソースコード
create_table.sql
■その1
CREATE TABLE email ( email_id bigserial primary key , from_addr varchar(65) not null , to_addr varchar(65) not null , subject varchar(128) not null , name varchar(32) , sex smallint , type smallint , naiyo text ); CREATE TABLE email_item ( email_item_id bigserial primary key , email_id bigint not null references EMAIL(email_id) on delete cascade , item smallint );
- テーブル名/カラム名を英大文字→英小文字に変更します。
■その2
CREATE TABLE email ( email_id bigserial primary key , from_addr varchar(65) not null , to_addr varchar(65) not null , subject varchar(128) not null , name varchar(32) , sex varchar(1) , type varchar(1) , naiyo text ); CREATE TABLE email_item ( email_item_id bigserial primary key , email_id bigint not null references EMAIL(email_id) on delete cascade , item varchar(3) );
- email テーブルの sex, type の型を smallint → varchar(1) へ変更します。
- email_item テーブルの item の型を smallint → varchar(3) へ変更します。
MailsendService.java
■その1
@Transactional(rollbackFor = Exception.class) public void saveAndSendEmail(MailsendForm mailsendForm) { // 入力されたデータを email, email_item テーブルに保存する saveEmail(mailsendForm); // メールを送信する sendEmail(mailsendForm); } public void saveEmail(MailsendForm mailsendForm) { // email テーブルに保存する Email email = new Email(); BeanUtils.copyProperties(mailsendForm, email); emailDao.insert(email); // email_item テーブルに保存する for (String item : mailsendForm.getItem()) { EmailItem emailItem = new EmailItem(); emailItem.setEmailId(email.getEmailId()); emailItem.setItem(Short.parseShort(item)); emailItemDao.insert(emailItem); } }
■その2
@Autowired private EmailService emailService; public void saveAndSendEmail(MailsendForm mailsendForm) { // 入力されたデータを email, email_item テーブルに保存する saveEmail(mailsendForm); // メールを送信する sendEmail(mailsendForm); }
- saveAndSendEmail メソッドに付加していた
@Transactional(rollbackFor = Exception.class)
を削除します。
■その3
public void saveEmail(MailsendForm mailsendForm) { // email テーブルに保存する Email email = new Email(); BeanUtils.copyProperties(mailsendForm, email); emailDao.insert(email); // email_item テーブルに保存する for (String item : mailsendForm.getItem()) { EmailItem emailItem = new EmailItem(); emailItem.setEmailId(email.getEmailId()); emailItem.setItem(item); emailItemDao.insert(emailItem); } }
emailItem.setItem(Short.parseShort(item));
→emailItem.setItem(item);
に変更します。
■その4
public void saveEmail(MailsendForm mailsendForm) { // email テーブルに保存する Email email = new Email(); BeanUtils.copyProperties(mailsendForm, email); emailDao.insert(email); // email_item テーブルに保存する EmailItem emailItem = new EmailItem(); for (String item : mailsendForm.getItem()) { emailItem.setEmailItemId(null); emailItem.setEmailId(email.getEmailId()); emailItem.setItem(item); emailItemDao.insert(emailItem); } }
- for 文の前で
EmailItem emailItem = new EmailItem();
を実行するよう変更します。 - for 文の中では
emailItem.setEmailItemId(null);
を実行して emailItemId をクリアします。
applicationContext.xml
<aop:config> <aop:pointcut id="pointcutService" expression="execution(* ksbysample.webapp.email..*Service.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcutService"/> </aop:config>
ksbysample.webapp.email.service..*Service.*(..))
→ksbysample.webapp.email..*Service.*(..))
へ変更します。
build.gradle
dependencies { def jdbcDriver = "org.postgresql:postgresql:9.4-1201-jdbc41" // spring-boot-gradle-plugin によりバージョン番号が自動で設定されるもの // Appendix E. Dependency versions ( http://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html ) 参照 compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-thymeleaf") compile("org.springframework.boot:spring-boot-starter-jdbc") compile("org.springframework.boot:spring-boot-starter-velocity") compile("org.springframework.boot:spring-boot-starter-mail") compile("org.codehaus.janino:janino") testCompile("org.springframework.boot:spring-boot-starter-test") testCompile("org.yaml:snakeyaml") // spring-boot-gradle-plugin によりバージョン番号が自動で設定されないもの compile("${jdbcDriver}") compile("org.seasar.doma:doma:2.2.0") compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16") compile("org.apache.commons:commons-lang3:3.4") compile("org.projectlombok:lombok:1.16.2") testCompile("org.dbunit:dbunit:2.5.0") // for Doma-Gen domaGenRuntime("org.seasar.doma:doma-gen:2.2.0") domaGenRuntime("${jdbcDriver}") }
compile("org.springframework.boot:spring-boot-starter-data-jpa")
→compile("org.springframework.boot:spring-boot-starter-jdbc")
へ変更します。
mailsend.html
<div th:replace="common/bottom-js"></div> <script type="text/javascript"> <!-- $(document).ready(function() { $('#fromAddr').focus(); $('#send').bind('click', function(){ $('#mailsendForm').submit(); }); }); --> </script> </body> </html>
$('#from').focus();
→$('#fromAddr').focus();
へ変更します。
履歴
2015/05/08
初版発行。