Spring Boot でメール送信する Web アプリケーションを作る ( その8 )( メール送信画面の作成3 )
概要
Spring Boot でメール送信する Web アプリケーションを作る ( その7 )( メール送信画面の作成2 ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- メール送信画面の作成
- 今回は Doma 2 を使用したメール保存処理を実装します。
- Doma 2 は使い方を調査するのに苦労しましたが、コードジェネレータがあるのと、SQL ファイルが使えるのが魅力ですね。
ソフトウェア一覧
参考にしたサイト
Welcome to Doma
http://doma.readthedocs.org/ja/stable/Spring @Component vs @Configuration for basic configuration class
http://stackoverflow.com/questions/18976634/spring-component-vs-configuration-for-basic-configuration-class- Doma 2 の Config インターフェースの実装クラスを Spring の DI コンテナにシングルトンで生成・管理してもらおうと思ったのですが、実装時に @Component と @Configuration のどちらのアノテーションを付与するのが良いのか迷ったので、その調査をした時に参照しました。
- ComponentScan の対象にして他のクラスに @Autowired で DI するものは @Component を、@Bean を定義したり XMLベースの設定と同じことをする場合には @Configuration を、という感じでしょうか?
- Doma 2 の Config インターフェースの実装クラスは Dao インターフェースの実装クラスに DI されるので、@Component アノテーションを使用することにします。
IntelliJ Doma support plugin の GitHub サイト
https://github.com/siosio/DomaSupportIntelliJ IDEA Plugins - Doma Support -> 0.3
https://plugins.jetbrains.com/update/index?pr=idea&updateId=19563Welcome to Doma-Gen
http://doma-gen.readthedocs.org/ja/stable/@AnnotateWithをメタアノテーションとして使用可能に
http://d.hatena.ne.jp/taedium/20100130/p1- @AnnotateWith アノテーションの説明が記載されています。
SpringBootとDomaを連携する
http://shinsuke789.hatenablog.jp/entry/2014/07/31/123800- Dao インターフェースの実装クラスを Spring の DI コンテナで管理させるための実装方法を参考にしました。
SpringBoot+Doma2+Gradleを試してみた。
http://qiita.com/nyasba/items/1e22c2401f3849f9071d- dataSource を Spring の管理するトランザクションに参加させる方法を参考にしました。
手順
1.0.x-make-mailsendform-saveemail ブランチの作成
- IntelliJ IDEA で 1.0.x-make-mailsendform-saveemail ブランチを作成します。
Doma 2 の Config インターフェースの実装クラスの作成
以下のドキュメントを参考にして、Doma 2 の Config インターフェースを実装します。
src/main/resources の下の application.properties を リンク先の内容 に変更します。
src/main/java/ksbysample/webapp/email/config の下に DomaBeanConfig.java を作成します。作成後、リンク先の内容 に変更します。
src/main/java/ksbysample/webapp/email/config の下に DomaConfig.java を作成します。作成後、リンク先のその1の内容 に変更します。
Community Edition に IntelliJ Doma support plugin はインストールできませんでした
Doma の開発に便利な IntelliJ IDEA 用のプラグインがあると書かれていたのでインストールしようと思いましたが、IntelliJ IDEA Plugins のプラグインのページ を見てみると、Community Edition は動作対象外でした。残念です。。。
Entity クラス、Dao インターフェース、SQL ファイルの作成
Doma には Doma-Gen というコードジェネレータが提供されていますので、それを利用して Entity クラス、Dao インターフェース、SQL ファイルを自動生成します。
build.gradle を リンク先の内容 に変更します。
Gradle projects View の左上にある「Refresh all Gradle projects」アイコンをクリックして、変更した build.gradle の内容を反映します。
Gradle projects View から以下の場所にある gen タスクを実行します。
- 一番最初の実行時はライブラリのダウンロードが行われます。上のキャプチャは何度か実行した後のもので、ライブラリのダウンロード時の様子はキャプチャするのを忘れていました。
gen タスクが正常に終了すると、以下の画像の Entity クラス、Dao インターフェース、SQL ファイルが作成されます。
Dao インターフェースはこの後作成する Service クラスに @Autowired アノテーションで DI したいので、@Component アノテーションを付加しておきます。
src/main/java/ksbysample/webapp/email/dao の下の EmailDao.java を リンク先のその1の内容 に変更します。
src/main/java/ksbysample/webapp/email/dao の下の EmailItemDao.java を リンク先のその1の内容 に変更します。
Doma-Gen で自動生成されたファイルは Git のバージョン管理対象として登録されていないので登録します。Project View でルートディレクトリを選択後、コンテキストメニューを表示して「Git」-「Add」を選択し、ファイルを追加します。
Service クラスの作成、Controller クラスの変更
src/main/java/ksbysample/webapp/email/web/mailsend の下に MailsendService.java を作成します。作成後、リンク先のその1の内容 に変更します。
src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendController.java を リンク先の内容 に変更します。
動作確認 ( その1 )
動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動しようとしますが、
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mailsendController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ksbysample.webapp.email.web.mailsend.MailsendService ksbysample.webapp.email.web.mailsend.MailsendController.mailsendService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mailsendService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ksbysample.webapp.email.dao.EmailDao ksbysample.webapp.email.web.mailsend.MailsendService.emailDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [ksbysample.webapp.email.dao.EmailDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
というエラーメッセージが出力されて起動しませんでした。どうも EmailDao を MailsendService クラスに DI できていないようです。原因を調査します。調査した結果は以下の通りでした。
- Doma 2 では build 時に apt により Dao インターフェースから実装クラス ( ~DaoImpl クラス ) が生成されます。apt については、apt(アプト)とは何ですか? に説明がありました。
- 生成された実装クラスがどこにあるか確認したところ、build\classes\main\generated\ksbysample\webapp\email\dao の下に作成されていました。
- Dao インターフェースに @Component アノテーションを付加しても実装クラスには @Component アノテーションは付加されていませんでした。
- Doma 2 の User Documentation - 設定 - アドバンスド を見ると、Dao インターフェースに @AnnotateWith アノテーションを付加すれば、実装クラスに付加するアノテーションを指定できるようです。
- @AnnotateWith アノテーションで以下2点を実現できればよさそうです。
- @AnnotateWith アノテーションによる記述は長いのですが、別のアノテーションを定義しておいて、それを Dao インターフェースに付加すれば短く記述できるようです。
以下の実装に変更します。
src/main/java/ksbysample/webapp/email の下に annotation.dao パッケージを作成します。
src/main/java/ksbysample/webapp/email/annotation/dao の下に ComponentAndAutowiredDomaConfig.java を作成します。作成後、リンク先の内容 に変更します。
src/main/java/ksbysample/webapp/email/dao の下の EmailDao.java を リンク先のその2の内容 に変更します。
src/main/java/ksbysample/webapp/email/dao の下の EmailItemDao.java を リンク先のその2の内容 に変更します。
Ctrl+F9 を押して build します。build\classes\main\generated\ksbysample\webapp\email\dao の下の EmailDaoImpl.java を見ると リンク先の内容 になっており、クラスに @Component アノテーションが、コンストラクタに @Autowired アノテーションが付加されていました。
再度 Gradle projects View から bootRun タスクを実行したところ、今度は Tomcat が正常に起動しました。動作確認を続けます。
動作確認 ( その2 )
ブラウザを起動し http://localhost:8080/mailsend へアクセスします。以下の画像の値を入力後、「送信」ボタンをクリックします。
「送信」ボタンをクリックすると以下の画像のエラーが発生しました。原因を調査します。
調査した結果は以下の通りでした。
- log4jdbc で出力された SQL を見てみると、以下の処理が実行されていました。
- Connection.setAutoCommit(false)
- Connection.prepareStatement(insert into email .....
- org.seasar.doma.jdbc.command.ModifyCommand.executeUpdate で PreparedStatement.executeUpdate() を呼び出して insert 文を実行
- Connection.prepareStatement(select currval('email_email_id_seq'))
- org.seasar.doma.jdbc.id.AbstractIdGenerator.getGeneratedValue で PreparedStatement.executeQuery() を呼び出して select currval('email_email_id_seq') を実行
-
org.postgresql.util.PSQLException: ERROR: 本セッションでシーケンス"email_email_id_seq"のcurrvalはまだ定義されていません
のエラーが発生
- Google でエラーメッセージを検索してみると以下の記事がヒットしました。内容を見てみると、どうも SQL 発行と同時にコミットされてしまっているためらしいです。
- DB の EMAIL テーブルを見るとデータが insert されていました。@Transactional アノテーションを付加しているのに効いていませんね。。。
※実際には何度か実行していたので、email_id は 1 ではなく 13 まで進んでいます。
- トランザクションが効いていないだけのように見えたので SpringBoot+Doma2+Gradleを試してみた。 の記事を参考に
DataSourceBuilder.create().build()
→new TransactionAwareDataSourceProxy(DataSourceBuilder.create().build())
と変更してみたのですが、Tomcat を再起動するとjava.sql.SQLException: The url cannot be null
というエラーログが出力されて Tomcat が起動しませんでした。 - 確かに dataSource Bean の中で
DataSourceBuilder.create().build()
で生成した dataSource を org.apache.tomcat.jdbc.pool.DataSource でキャストした後、設定されている値をSystem.out.println(dataSource.getUrl());
で出力してみたのですが、null でした。DataSourceBuilder.create().build()
で生成した時に application.properties の設定が反映されていると思っていましたが、どうもそうではないようです。Service クラスに dataSource を @Autowired で DI してSystem.out.println(dataSource.getUrl());
で出力してみるとセットされているのですが。 - dataSource への application.properties の設定の反映は dataSource Bean に AOP で処理を追加して行われているような気がするのですが、具体的な仕組みが分からないですね。。。 そのうち調べてみましょう。
- まとめると、おそらく以下の仕組みになっていると思われます。
- dataSource Bean 生成時点では Spring 管理のトランザクションに参加していません。よって、Doma 2 の Config インターフェースの実装クラスで dataSource をそのまま使用してもトランザクションが有効になりません。
- 生成された dataSource に設定が反映されていれば
new TransactionAwareDataSourceProxy(...)
はエラーになりません。 - dataSource Bean の生成時点では application.properties の設定は反映されていませんが、それ以外の場所で使用する場合には設定が反映されています。
- DomaConfig クラスのフィールド dataSource にはセッターインジェクションで DI するように変更し、セッター内で
new TransactionAwareDataSourceProxy(...)
を呼び出して Spring 管理のトランザクションに参加させるようにしてみます。
- log4jdbc で出力された SQL を見てみると、以下の処理が実行されていました。
src/main/java/ksbysample/webapp/email/config の下の DomaConfig.java を リンク先のその2の内容 に変更します。
確認します。Run View で Ctrl+F5 を押して Tomcat を再起動します。
ブラウザで http://localhost:8080/mailsend へアクセスします。以下の画像の値を入力後、「送信」ボタンをクリックします。
今度はエラーは発生せず、メールも送信されました。
DB にも保存されていました。
※性別(sex)と項目(type)が保存されていないのは Form クラスと Entity クラスの型が違うためです。今回は Doma 2 を利用できるようにするための調査で時間がかかりすぎたので、次回に解決します。エラー発生時にロールバックされるかも確認します。最初に email, email_item テーブルからデータを削除します。
Service クラス内で RuntimeException が発生するようにします。src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendService.java を リンク先のその2の内容 に変更します。
Ctrl+F9 を押して build します。
ブラウザで http://localhost:8080/mailsend へアクセスします。先程と同じデータを入力後、「送信」ボタンをクリックします。
予定通りエラーにはなったのですが、メールが送信されませんでした。Spring Loaded により Tomcat を再起動することなく反映されると思ったのですが、どうも反映されていないようです。
Run View で Ctrl+F5 を押して Tomcat を再起動します。
再度ブラウザで http://localhost:8080/mailsend へアクセスします。先程と同じデータを入力後、「送信」ボタンをクリックします。
今度は予定通りエラーになり、メールは送信されました。また DB を確認したところ、email, email_item どちらのテーブルにもデータは保存されていませんでした。
ログにも rollback が出力されていました。
src/main/java/ksbysample/webapp/email/web/mailsend の下の MailsendService.java の実装を元に戻します。
Run View で Ctrl+F2 を押して Tomcat を停止します。
commit、Push、Pull Request、マージ
commit します。commit 時に Code Analysis のダイアログが表示されますが、Unused property の Warning だけなので「Commit」ボタンをクリックします。
GitHub へ Push、1.0.x-make-mailsendform-saveemail -> 1.0.x へ Pull Request、1.0.x でマージ、1.0.x-make-mailsendform-saveemail ブランチを削除、をします。
Spring Boot で Doma 2 を使うためのメモ
- Doma 2 を使用するための設定 ( build 時の SQL ファイルの出力先ディレクトリ等 ) を build.gradle に記述します。
- dataSource は spring-boot-starter-data-jpa を build.gradle に記述した後、Java Configuration のクラスに dataSource Bean を実装したものを使用します。
- Doma 2 の Config インターフェースの実装クラスを実装します。Spring の DI コンテナにシングルトンで生成・管理してもらうため、クラスには @Component アノテーションを付加します。また dataSource は dataSource Bean として実装したものをセッターインジェクションで DI します。インジェクション時には
new TransactionAwareDataSourceProxy(...)
を呼び出して dataSource を Spring 管理のトランザクションに参加させます。 - コードジェネレータ Doma-Gen を利用して Entity クラス、Dao インターフェース、SQL ファイルを生成します。
- Doma-Gen を利用するための設定 ( クラスの生成先のパッケージ、DB の設定 ) を build.gradle に記述します。
- Doma 2 が apt で自動生成する Dao インターフェースの実装クラスを Spring の DI コンテナに生成・管理してもらうために、@AnnotateWith アノテーションで実装クラスに付加するアノテーションを指定します。最初に @AnnotateWith アノテーションを記述したアノテーションを作成しておき、各 Dao インターフェースには作成したアノテーションをクラスに付加します。
- あとは Dao インターフェースを Service クラス等に @Autowired アノテーションで DI して使用します。
- IntelliJ Doma support plugin は IntelliJ IDEA の Community Edition では使えません。。。
その他のメモ書き
次回は。。。
以下の点を調査・修正します。テストを書くのはその後の予定です。
- create table 文のテーブル名/カラム名は英大文字で記述したのですが、Doma-Gen で生成された Entity クラスの中のテーブル名/カラム名や、pgAdmin Ⅲ 上に表示されるテーブル名/カラム名は英小文字で表示されていることに気づきました。PostgreSQL でのテーブル名/カラム名の命名ルールを確認してみます。
- 現在 Service クラスのメソッドに @Transactional アノテーションを付加してトランザクションを開始していますが、AOP でトランザクションが設定されるようにします。
- dataSource と transactionManager を利用したいだけならば spring-boot-starter-data-jpa ではなく spring-boot-starter-data-jdbc でもよいような気がするので試してみます。
- 性別(sex)と項目(type)が保存されない問題を解消します。
- EMAIL_ITEM テーブルにデータを保存する処理で毎回インスタンスを生成するように実装しましたが、emailItemId をクリアすればよいだけのような気もするので試してみます。
ソースコード
application.properties
hibernate.dialect = org.hibernate.dialect.PostgreSQL9Dialect doma.dialect = org.seasar.doma.jdbc.dialect.PostgresDialect spring.jpa.hibernate.ddl-auto = none spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.ImprovedNamingStrategy spring.velocity.enabled = false spring.velocity.charset = UTF-8
doma.dialect
を追加します。
DomaBeanConfig.java
package ksbysample.webapp.email.config; import org.seasar.doma.jdbc.dialect.Dialect; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class DomaBeanConfig { @Value("${doma.dialect}") private String domaDialect; @Bean public Dialect dialect() throws ClassNotFoundException, IllegalAccessException, InstantiationException { return (Dialect)Class.forName(domaDialect).newInstance(); } }
DomaConfig.java
■その1
package ksbysample.webapp.email.config; import org.seasar.doma.jdbc.Config; import org.seasar.doma.jdbc.dialect.Dialect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.sql.DataSource; @Component public class DomaConfig implements Config { @Autowired private DataSource dataSource; @Autowired private Dialect dialect; @Override public DataSource getDataSource() { return dataSource; } @Override public Dialect getDialect() { return dialect; } }
■その2
package ksbysample.webapp.email.config; import org.seasar.doma.jdbc.Config; import org.seasar.doma.jdbc.dialect.Dialect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; import javax.sql.DataSource; @Component public class DomaConfig implements Config { private DataSource dataSource; @Autowired private Dialect dialect; @Autowired public void setDataSource(DataSource dataSource) { this.dataSource = new TransactionAwareDataSourceProxy(dataSource); } @Override public DataSource getDataSource() { return this.dataSource; } @Override public Dialect getDialect() { return this.dialect; } }
private DataSource dataSource;
に付加していた @Autowired アノテーションを削除します。- セッターインジェクションするために @Autowired アノテーションを付加した setDataSource メソッドを追加します。セッター内でフィールド dataSource にセットする際に
new TransactionAwareDataSourceProxy(...)
を呼び出して dataSource を Spring 管理のトランザクションに参加させます。
build.gradle
buildscript { repositories { jcenter() // for org.springframework:springloaded maven { url "http://repo.spring.io/repo/" } } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.3.RELEASE") classpath("org.springframework:springloaded:1.2.3.RELEASE") } } apply plugin: 'java' apply plugin: 'spring-boot' apply plugin: 'idea' // for Doma 2 // JavaクラスとSQLファイルの出力先ディレクトリを同じにする processResources.destinationDir = compileJava.destinationDir // コンパイルより前にSQLファイルを出力先ディレクトリにコピーするために依存関係を逆転する compileJava.dependsOn processResources jar { baseName = 'ksbysample-webapp-email' version = '0.0.1-SNAPSHOT' } idea { module { inheritOutputDirs = false outputDir = file("$buildDir/classes/main/") } } configurations { domaGenRuntime } repositories { jcenter() // for org.seasar.doma:doma maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } 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-data-jpa") 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}") } bootRun { jvmArgs = ['-Dspring.profiles.active=develop'] } test { jvmArgs = ['-Dspring.profiles.active=unittest'] } // for Doma-Gen task gen << { def rootPackageName = 'ksbysample.webapp.email' ant.taskdef(resource: 'domagentask.properties', classpath: configurations.domaGenRuntime.asPath) ant.gen(url: 'jdbc:postgresql://localhost/ksbyemail', user: 'ksbyemail_user', password: 'xxxxxxxx') { entityConfig(packageName: "${rootPackageName}.entity", useListener: false) daoConfig(packageName: "${rootPackageName}.dao") sqlConfig() } }
configurations { ... }
を追加します。- dependencies の以下の点を変更します。
def jdbcDriver = "org.postgresql:postgresql:9.4-1201-jdbc41"
を追加します。compile("org.postgresql:postgresql:9.4-1201-jdbc41")
→compile("${jdbcDriver}")
へ変更します。domaGenRuntime("org.seasar.doma:doma-gen:2.2.0")
,domaGenRuntime("${jdbcDriver}")
を追加します。
task gen << { ... }
を追加します。
EmailDao.java
■その1
@Dao @Component public interface EmailDao {
- クラスに
@Component
アノテーションを付加します。
■その2
@Dao @ComponentAndAutowiredDomaConfig public interface EmailDao {
@Component
→@ComponentAndAutowiredDomaConfig
に変更します。
EmailItemDao.java
■その1
@Dao @Component public interface EmailItemDao {
- クラスに
@Component
アノテーションを付加します。
■その2
@Dao @ComponentAndAutowiredDomaConfig public interface EmailItemDao {
@Component
→@ComponentAndAutowiredDomaConfig
に変更します。
MailsendService.java
■その1
package ksbysample.webapp.email.web.mailsend; import ksbysample.webapp.email.dao.EmailDao; import ksbysample.webapp.email.dao.EmailItemDao; import ksbysample.webapp.email.entity.Email; import ksbysample.webapp.email.entity.EmailItem; import ksbysample.webapp.email.service.EmailService; import ksbysample.webapp.email.util.VelocityUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.SimpleMailMessage; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class MailsendService { @Autowired private EmailDao emailDao; @Autowired private EmailItemDao emailItemDao; @Autowired private VelocityUtils velocityUtils; @Autowired private EmailService emailService; @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); } } public void sendEmail(MailsendForm mailsendForm) { SimpleMailMessage mailMessage = MAIL001MailBuilder.build() .setForm(mailsendForm) .setVelocityUtils(velocityUtils) .setTemplateLocation("mail/MAIL001/MAIL001-body.vm") .create(); emailService.sendSimpleMail(mailMessage); } }
■その2
@Transactional(rollbackFor = Exception.class) public void saveAndSendEmail(MailsendForm mailsendForm) { // 入力されたデータを EMAIL, EMAIL_ITEM テーブルに保存する saveEmail(mailsendForm); // メールを送信する sendEmail(mailsendForm); throw new RuntimeException("メールは送信されるがDBには保存されないはず"); }
- saveAndSendEmail メソッドの最後に RuntimeException を throw します。
MailsendController.java
package ksbysample.webapp.email.web.mailsend; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/mailsend") public class MailsendController { @Autowired private MailsendService mailsendService; @Autowired private MailsendFormValidator mailsendFormValidator; @InitBinder public void initBinder(WebDataBinder binder) { binder.addValidators(mailsendFormValidator); } @RequestMapping public String index(MailsendForm mailsendForm , Model model) { return "mailsend/mailsend"; } @RequestMapping("/send") public String send(@Validated MailsendForm mailsendForm , BindingResult bindingResult , Model model) { if (bindingResult.hasErrors()) { return "mailsend/mailsend"; } // 入力されたデータをDBに保存した後、メールを送信する mailsendService.saveAndSendEmail(mailsendForm); return "redirect:/mailsend"; } }
- @Autowired アノテーションを付加して DI していた以下のフィールドは MailsendService クラスへ移動します。
private VelocityUtils velocityUtils;
private EmailService emailService;
- send メソッド内に記述していたメール送信処理を MailsendService クラスへ移動し、send メソッドからは
mailsendService.saveAndSendEmail(mailsendForm);
を呼び出すように変更します。
ComponentAndAutowiredDomaConfig.java
package ksbysample.webapp.email.annotation.dao; import org.seasar.doma.AnnotateWith; import org.seasar.doma.Annotation; import org.seasar.doma.AnnotationTarget; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @AnnotateWith(annotations = { @Annotation(target = AnnotationTarget.CLASS, type = Component.class), @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Autowired.class) }) public @interface ComponentAndAutowiredDomaConfig { }
EmailDaoImpl.java
package ksbysample.webapp.email.dao; /** */ @org.springframework.stereotype.Component() @javax.annotation.Generated(value = { "Doma", "2.2.0" }, date = "2015-05-05T04:01:34.940+0900") public class EmailDaoImpl extends org.seasar.doma.internal.jdbc.dao.AbstractDao implements ksbysample.webapp.email.dao.EmailDao { static { org.seasar.doma.internal.Artifact.validateVersion("2.2.0"); } private static final java.lang.reflect.Method __method0 = org.seasar.doma.internal.jdbc.dao.AbstractDao.getDeclaredMethod(ksbysample.webapp.email.dao.EmailDao.class, "selectById", java.lang.Long.class); private static final java.lang.reflect.Method __method1 = org.seasar.doma.internal.jdbc.dao.AbstractDao.getDeclaredMethod(ksbysample.webapp.email.dao.EmailDao.class, "insert", ksbysample.webapp.email.entity.Email.class); private static final java.lang.reflect.Method __method2 = org.seasar.doma.internal.jdbc.dao.AbstractDao.getDeclaredMethod(ksbysample.webapp.email.dao.EmailDao.class, "update", ksbysample.webapp.email.entity.Email.class); private static final java.lang.reflect.Method __method3 = org.seasar.doma.internal.jdbc.dao.AbstractDao.getDeclaredMethod(ksbysample.webapp.email.dao.EmailDao.class, "delete", ksbysample.webapp.email.entity.Email.class); /** * @param config the config */ @org.springframework.beans.factory.annotation.Autowired() public EmailDaoImpl(org.seasar.doma.jdbc.Config config) { super(config); }
- クラスに
@org.springframework.stereotype.Component()
が、コンストラクタに@org.springframework.beans.factory.annotation.Autowired()
が付加されていることが確認できます。
履歴
2015/05/05
初版発行。