読者です 読者をやめる 読者になる 読者になる

かんがるーさんの日記

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

Git のコメントを "#" で始められるようにする

Git のコミットを GitHub の Issue に紐付けるために、コメントを “#128 …” のように “#” + Issue番号 から始めるようにしているのですが、Git for Windows の 2.11.0 の頃から git rebase -i で rebase しようとすると Aborting commit due to empty commit message. というメッセージが表示されて rebase できなくなっていました。

f:id:ksby:20170422104241p:plain

何か対応方法があるのか stackoverflow を見ていたところ、以下の QA が見つかりました。

Start a git commit message with a hashmark (#)
http://stackoverflow.com/questions/2788092/start-a-git-commit-message-with-a-hashmark

この QA を見ると、Git のデフォルトのコメント開始の文字は “#” になっているので、 git config core.commentChar ";" で別の文字に変更すればよいとのこと。

git config core.commentChar ";" でコメント開始の文字を “;” に変更してから git rebase -i を実行してみると、起動したエディタの下に表示されるコメントの一番左側の文字が “#” から “;” に変わっています。

f:id:ksby:20170422105051p:plain

このまま rebase の操作を続けると、問題なく rebase することができました。

f:id:ksby:20170422105313p:plain

この後いろいろ試してみたのですが、git config core.commentChar auto と実行するとコメント開始の文字を “#” にしたまま git rebase -i が成功するようになりました。

git config core.commentChar auto を実行してから git rebase -i を実行すると、起動したエディタのコメントは “#” から始まっています。

f:id:ksby:20170422105836p:plain

このまま rebase の操作を続けると、問題なく rebase することができました。

f:id:ksby:20170422110011p:plain

初めから auto で設定しておいてもらえればよさそうに思えるのですが、何か問題があるのかな。。。

また git config core.commentChar auto のコマンドを実行しても .gitconfig には core.commentChar の設定は保存されないんですよね。どこに保存されるのかも疑問です。。。

Java SE を 8u121 → 8u131 へ、IntelliJ IDEA を 2017.1 → 2017.1.1 へ、Git for Windows を 2.12.2 → 2.12.2(2) へバージョンアップ

※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。

Java SE を 8u121 → 8u131 へバージョンアップする

  1. OracleJava SE Downloads を見ると 8u131 がダウンロードできるようになっていました。以下のページに説明があります。

    8u131 へバージョンアップします。

  2. jdk-8u131-windows-i586.exe をダウンロードして C:\Java\jdk1.8.0_131 へインストールした後、環境変数 JAVA_HOME のパスを C:\Java\jdk1.8.0_131 へ変更します。

    コマンドプロンプトから java -version を実行し、1.8.0_131 に変更されていることを確認します。

    f:id:ksby:20170422080335p:plain

  3. IntelliJ IDEA を再起動した後、プロジェクトで使用する Java SE を 8u131 へ変更します。

  4. 開いているプロジェクトを閉じて「Welcome to IntelliJ IDEA」ダイアログを表示します。

  5. ダイアログ下部の「Configure」-「Project Defaults」-「Project Structure」を選択します。

    f:id:ksby:20170422082029p:plain

  6. 「Default Project Structure」ダイアログが表示されます。画面左側で「Project Settings」-「Project」を選択後、画面右側の「Project SDK」の「New…」ボタンをクリックし、表示されるメニューから「JDK」を選択します。

    f:id:ksby:20170422082256p:plain

  7. 「Select Home Directory for JDK」ダイアログが表示されます。今回は環境変数 JAVA_HOME のディレクトリが選択された状態で表示されませんでした。。。? C:\Java\jdk1.8.0_131 を選択した後、「OK」ボタンをクリックします。

    f:id:ksby:20170422082629p:plain

  8. 「Default Project Structure」ダイアログに戻るので、今度は「Project SDK」の「Edit」ボタンをクリックします。

    f:id:ksby:20170422082928p:plain

  9. 画面左側で「Platform Settings」-「SDKs」が選択された状態になるので、画面右上の入力フィールドで “1.8” → “1.8.0_131” へ変更します。

    f:id:ksby:20170422083221p:plain

  10. 次に中央のリストから「1.8.0_121」を選択した後、リストの上の「-」ボタンをクリックして削除します。

    f:id:ksby:20170422083453p:plain

  11. 「OK」ボタンをクリックして「Default Project Structure」ダイアログを閉じます。

  12. 「Welcome to IntelliJ IDEA」ダイアログに戻ったら、ksbysample-webapp-lending プロジェクトを開きます。

  13. IntelliJ IDEA のメイン画面が開いたら、メニューから「File」-「Project Structure…」を選択します。

  14. 「Project Structure」ダイアログが表示されます。以下の画像の状態になっているので、

    f:id:ksby:20170422084045p:plain

    「Project SDK」と「Project language level」を選択し直します。

    f:id:ksby:20170422084542p:plain

  15. 「OK」ボタンをクリックして「Project Structure」ダイアログを閉じます。

  16. メイン画面に戻ると画面右下に「Indexing…」の表示が出るので、終了するまで待ちます。

    f:id:ksby:20170422084712p:plain

  17. Build 及びテストで問題がないか確認します。Gradle projects View から clean タスクの実行→「Rebuild Project」メニューの実行→build タスクの実行を行い、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。

    f:id:ksby:20170422085247p:plain

  18. Project Tool Window で src/test を選択した後、コンテキストメニューを表示して「Run ‘All Tests’ with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20170422085750p:plain

  19. 特に問題は発生しませんでした。8u131 で開発を進めます。

IntelliJ IDEA を 2017.1 → 2017.1.1 へバージョンアップする

IntelliJ IDEA の 2017.1.1 がリリースされたのでバージョンアップします。

※上の Java SE のバージョンアップからの続きで ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。

  1. IntelliJ IDEA のメインメニューから「Help」-「Check for Updates…」を選択します。

  2. 「Platform and Plugin Updates」ダイアログが表示されます。左下に「Update and Restart」ボタンが表示されていますので、「Update and Restart」ボタンをクリックします。

    f:id:ksby:20170422090516p:plain

  3. Plugin の update も表示されたので、チェックしたまま「Update and Restart」ボタンをクリックします。

    f:id:ksby:20170422090637p:plain

  4. Patch がダウンロードされて IntelliJ IDEA が再起動します。

  5. メイン画面が表示されます。今回は画面下部に「Indexing…」のメッセージが表示されませんでした。。。?

  6. 処理が終了しても Gradle Tool Window のツリーの表示は other グループしかない初期の状態に戻らず、build グループ等が表示された状態でした。これまでバージョンアップする度に更新しないといけないのは手間だったので、これは嬉しいですね。

    f:id:ksby:20170422091957p:plain

  7. clean タスク実行 → Rebuild Project 実行をした後、build タスクを実行して “BUILD SUCCESSFUL” のメッセージが表示されることを確認します。

    f:id:ksby:20170422092641p:plain

  8. Project Tool Window で src/test を選択した後、コンテキストメニューを表示して「Run ‘All Tests’ with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20170422093012p:plain

Git for Windows を 2.12.2 → 2.12.2(2) へバージョンアップする

Git for Windows の 2.12.2(2) がリリースされていたのでバージョンアップします。

  1. https://git-for-windows.github.io/ の「Download」ボタンをクリックして Git-2.12.2.2-64-bit.exe をダウンロードします。

  2. Git-2.12.2.2-64-bit.exe を実行します。

  3. 「Git 2.12.2.2 Setup」ダイアログが表示されます。[Next >]ボタンをクリックします。

  4. 「Select Components」画面が表示されます。「Git LFS(Large File Support)」のチェックボックスが追加されたようで、チェックされた状態で表示されました。この項目だけチェックした状態で [Next >]ボタンをクリックします。

    f:id:ksby:20170422095814p:plain

  5. 「Adjusting your PATH environment」画面が表示されます。中央の「Use Git from the Windows Command Prompt」が選択されていることを確認後、[Next >]ボタンをクリックします。

  6. 「Choosing HTTPS transport backend」画面が表示されます。「Use the OpenSSL library」が選択されていることを確認後、[Next >]ボタンをクリックします。

  7. 「Configuring the line ending conversions」画面が表示されます。「Checkout Windows-style, commit Unix-style line endings」が選択されていることを確認した後、[Next >]ボタンをクリックします。

  8. 「Configuring the terminal emulator to use with Git Bash」画面が表示されます。「Use Windows'default console window」が選択されていることを確認した後、[Next >]ボタンをクリックします。

  9. 「Configuring extra options」画面が表示されます。「Enable file system caching」だけがチェックされていることを確認した後、[Install]ボタンをクリックします。

  10. インストールが完了すると「Completing the Git Setup Wizard」のメッセージが表示された画面が表示されます。中央の「View ReleaseNotes.html」のチェックを外した後、「Finish」ボタンをクリックしてインストーラーを終了します。

  11. コマンドプロンプトを起動して git のバージョンが git version 2.12.2.windows.2 になっていることを確認します。

    f:id:ksby:20170422100158p:plain

  12. git-cmd.exe を起動して日本語の表示・入力が問題ないかを確認します。

    f:id:ksby:20170422100326p:plain

  13. 特に問題はないようですので、2.12.2(2) で作業を進めたいと思います。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その22 )( application.properties に記述する `spring.datasource.tomcat.~` の設定を見直す )

概要

記事一覧はこちらです。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その21 )( Log4jdbc Spring Boot Starter を入れてみる ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Tomcat JDBC Connection Pool の設定項目である spring.datasource.tomcat.~ について、現在 url, username, password, driverClassName しか設定していないので、他に設定すべき項目を確認して設定します。

参照したサイト・書籍

  1. The Tomcat JDBC Connection Pool
    https://tomcat.apache.org/tomcat-8.5-doc/jdbc-pool.html

  2. Tomcat JDBC Connection Poolの存在を忘れてました
    http://qiita.com/uzresk/items/d9e1b46014809094b10d

  3. Tomcat JDBC Connection Pool configuration for production and development
    http://www.codingpedia.org/ama/tomcat-jdbc-connection-pool-configuration-for-production-and-development/

  4. Commons DBCPを超えるTomcat JDBC Poolとは
    http://www.atmarkit.co.jp/ait/articles/1111/07/news212.html

目次

  1. jconsole で Tomcat JDBC Connection Pool の状況を確認する
  2. initialSize, maxActive, maxIdle, minIdle
  3. testOnBorrow, validationQuery, validationQueryTimeout
  4. removeAbandoned, removeAbandonedTimeout
  5. ここまでの設定が反映されているか jconsole で確認する
  6. SlowQueryReport を使用してスロークエリーをログに出力する
  7. 次回は。。。

手順

jconsole で Tomcat JDBC Connection Pool の状況を確認する

今の設定での Tomcat JDBC Connection Pool の他の設定項目の値を確認するために jconsole で MBean の値を見ようとしたのですが、以外に時間がかかりました。結論としては、

  • application.properties に設定する spring.datasource.jmx-enabled はデフォルト値が false なので true にする必要があります。またこの設定は spring.datasource.tomcat.jmx-enabled という名前にしてはいけません。IntelliJ IDEA で補完表示されるのですが設定しても全く意味がありません。
  • Log4jdbc Spring Boot Starter の AutoConfiguration が有効な場合、Tomcat JDBC Connection Pool の MBean インターフェースが登録されず、jconsole に表示されません。

まず Spring Boot Reference Guide の Appendix A. Common application properties を見ると spring.datasource.jmx-enabled=false と記述されています。デフォルト値が false なので true にします。

src/main/resources/application.properties に設定を追加します。spring.datasource.~ の設定は spring.datasource.tomcat.~ に変更していたので、最初 spring.datasource.tomcat.jmx-enabled=true と書きました。IntelliJ IDEA でも以下のように補完表示されます。

f:id:ksby:20170415211303p:plain

しかし、この設定だけ書いた状態では jconsole に Tomcat JDBC Connection Pool らしき情報が表示されません。

コマンドプロンプトを起動後、jconsole コマンドを実行します ( jconsole は C:\Java\jdk1.8.0_121\bin の下にあります )。

f:id:ksby:20170415220116p:plain

ローカル・プロセス一覧から ksbysample-webapp-lending を選択します。

f:id:ksby:20170415220257p:plain

メイン画面が表示されたら「MBeans」タブをクリックし MBean 一覧を表示しますが、画面左側のツリーに Tomcat JDBC Connection Pool らしき情報が表示されません。

f:id:ksby:20170415220444p:plain

MBean インターフェイスを登録している場所を探したら org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration の中の TomcatDataSourceJmxConfiguration#dataSourceMBean でした。以下のようにブレークポイントを設定して IntelliJ IDEA から debug 実行したところ、ブレークポイントで停止しませんでした。。。

f:id:ksby:20170415210257p:plain

f:id:ksby:20170415211916p:plain

TomcatDataSourceJmxConfiguration クラスに付いているアノテーションを見ると @ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled") と書かれていました。ここで jmx-enabled は spring.datasource.jmx-enabled=true と記述しないといけないことに気づきます。

src/main/resources/application.properties に記述する設定を spring.datasource.jmx-enabled=true に変更したのですが、やはり jconsole に表示されません。今度は debug 実行すると上で設定した TomcatDataSourceJmxConfiguration#dataSourceMBean のブレークポイントで止まるのですが、if (dataSource instanceof DataSourceProxy) の条件を満たしていないのか if 文の中の処理が実行されません。

再度 debug 実行して dataSource がどうなっているのか見てみたところ、DataSourceProxy クラスのインスタンスではなく log4jdbc が提供する DataSourceSpy クラスのインスタンスになっていました。if 文の中の処理が実行されないはずです。

f:id:ksby:20170415222433p:plain

Log4jdbc Spring Boot Starter を無効にするために src/main/resources/application.properties に spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を書いて debug 実行したところ、今度は TomcatDataSourceJmxConfiguration#dataSourceMBean の if 文の中の処理が実行されました。

f:id:ksby:20170415223106p:plain

jconsole にも org.apache.tomcat.jdbc.pool.jmx という名前で Tomcat JDBC Connection Pool の情報が表示されました。これで現在の設定値が確認できます。

f:id:ksby:20170416003124p:plain f:id:ksby:20170416003213p:plain

デフォルトの設定が書かれているクラスがどれか確認してみたところ org.apache.tomcat.jdbc.pool.PoolProperties でした。これを探すのに IntelliJ IDEA 2017.1 から新しくなった Find in Path を使いましたが、以前のツリー表示と違い1画面内でヒットしたソースが確認できてレスポンスもよく、使い勝手が非常に良くなっています。

f:id:ksby:20170415230024p:plain

initialSize, maxActive, maxIdle, minIdle

DB とのコネクション数を設定します。以下の方針で設定します。

  • initialSize, minIdle のデフォルト値は 10 ですが、product プロファイル以外では 1 にします。product プロファイルではデフォルト値の 10 にします。
  • maxActive, maxIdle はデフォルト値の 100 のままにします。
  • initialSize, maxActive, maxIdle, minIdle は application.properties, application-product.properties に明記することにします。

■application.properties

spring.datasource.tomcat.initialSize=1
spring.datasource.tomcat.maxActive=100
spring.datasource.tomcat.maxIdle=100
spring.datasource.tomcat.minIdle=1

■application-product.properties

spring.datasource.tomcat.initialSize=10
spring.datasource.tomcat.maxActive=100
spring.datasource.tomcat.maxIdle=100
spring.datasource.tomcat.minIdle=10

testOnBorrow, validationQuery, validationQueryTimeout

プールからコネクションを取得する時に有効性が検証されるようにします。この設定は application.properties にのみ設定します。

■application.properties

spring.datasource.tomcat.testOnBorrow=true
spring.datasource.tomcat.validationQuery=select 1
spring.datasource.tomcat.validationQueryTimeout=5

removeAbandoned, removeAbandonedTimeout

クローズ漏れのコネクションが自動検知されるようにします。

  • application.properties にのみ設定します。
  • removeAbandonedTimeout のデフォルト値は 60秒ですが、30秒にします。

■application.properties

spring.datasource.tomcat.removeAbandoned=true
spring.datasource.tomcat.removeAbandonedTimeout=30

ここまでの設定が反映されているか jconsole で確認する

application.properties に spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を追加してから develop プロファイルで Tomcat を起動した後、jconsole で確認します。

全ての設定が反映されていることが確認できます。

f:id:ksby:20170416012752p:plain f:id:ksby:20170416012855p:plain

SlowQueryReport を使用してスロークエリーをログに出力する

Tomcat JDBC Connection Pool にはスロークエリーを検知する仕組みがあるようなので試してみます。スロークエリーを検知したら専用のログファイルに出力させてみます。

  1. src/main/resources の下の application.properties を リンク先のその1の内容 に変更します。

  2. src/main/resources の下の application-product.properties を リンク先のその1の内容 に変更します。

  3. src/main/resources の下の logback-spring.xmlリンク先の内容 に変更します。

  4. src/main/resources の下の logback-product.xmlリンク先の内容 に変更します。

  5. clean タスク → Rebuild Project → build タスクを実行して ksbysample-webapp-lending-1.4.5-RELEASE.jar を作成します。

    f:id:ksby:20170418233200p:plain

  6. C:\project-springboot\ksbysample-webapp-lending\build\libs\ksbysample-webapp-lending-1.4.5-RELEASE.jar を C:\webapps\ksbysample-webapp-lending\lib の下へコピーします。

  7. C:\webapps\ksbysample-webapp-lending\bat\webapp_startup.bat の中の set WEBAPP_JAR=ksbysample-webapp-lending-1.4.5-RELEASE.jar に変更します。

  8. webapp_startup.bat を実行します。

    f:id:ksby:20170419000837p:plain

    slow-query.log が作成されます。

    f:id:ksby:20170419001119p:plain

  9. ログインして検索対象図書館登録画面から図書館を登録すると、slow-query.log に以下のように出力されました。

    f:id:ksby:20170419002654p:plain

    • SQL の末尾に time=1 ms; のように実行時間が出力されます。
    • ログは WARN レベルで出力されます。
    • SQL のパラメータの部分は “?” のまま出力されます。
  10. Ctrl+C を押して webapp_startup.bat を停止します。

  11. スロークエリーに出力される条件は 5秒に変更しておきます。src/main/resources の下の application.properties を リンク先のその2の内容 に変更します。

次回は。。。

application.properties の最終形、application-product.properties の最終形を記載します。

次回は、

  • ログイン画面で何も入力せずに「ログイン」ボタンをクリックすると “500 Internal Server Error” になることに気付いたので、修正します。
  • Spring Security 関連で修正した方がよい箇所があれば見直します。
  • その後で jar ファイルを作成して動作確認して終わりに向かう予定です。

ソースコード

application.properties

■その1

spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=0)
  • spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=0) を追加します。まずは全てのクエリーをログに出力したいので、スロークエリーの基準は 0 ミリ秒 ( threshold=0 ) にします。

■その2

spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=5000)

■最終形

doma.dialect=org.seasar.doma.jdbc.dialect.PostgresDialect

spring.datasource.tomcat.url=jdbc:postgresql://localhost/ksbylending
spring.datasource.tomcat.username=ksbylending_user
spring.datasource.tomcat.password=xxxxxxxx
spring.datasource.tomcat.driverClassName=org.postgresql.Driver
spring.datasource.tomcat.initialSize=1
spring.datasource.tomcat.maxActive=100
spring.datasource.tomcat.maxIdle=100
spring.datasource.tomcat.minIdle=1
spring.datasource.tomcat.testOnBorrow=true
spring.datasource.tomcat.validationQuery=select 1
spring.datasource.tomcat.validationQueryTimeout=5
spring.datasource.tomcat.removeAbandoned=true
spring.datasource.tomcat.removeAbandonedTimeout=30
spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=5000)
# spring.datasource.jmx-enabled は spring.datasource.tomcat.jmx-enabled と書かないこと。
# spring.datasource.tomcat.jmx-enabled だと機能しない。
spring.datasource.jmx-enabled=true

spring.session.store-type=redis

spring.freemarker.cache=true
spring.freemarker.charset=UTF-8
spring.freemarker.enabled=false
spring.freemarker.prefer-file-system-access=false

application-product.properties

■その1

server.tomcat.basedir=C:/webapps/ksbysample-webapp-lending
logging.file=${server.tomcat.basedir}/logs/ksbysample-webapp-lending.log
slowquery.logging.file=${server.tomcat.basedir}/logs/slow-query.log
  • slowquery.logging.file=${server.tomcat.basedir}/logs/slow-query.log を追加します。

■最終形

server.tomcat.basedir=C:/webapps/ksbysample-webapp-lending
logging.file=${server.tomcat.basedir}/logs/ksbysample-webapp-lending.log
slowquery.logging.file=${server.tomcat.basedir}/logs/slow-query.log

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
spring.datasource.tomcat.initialSize=10
spring.datasource.tomcat.maxActive=100
spring.datasource.tomcat.maxIdle=100
spring.datasource.tomcat.minIdle=10

spring.mail.host=localhost
spring.mail.port=25

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672

spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=localhost:6381,localhost:6382,localhost:6383

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <if condition='"${spring.profiles.active}" == "product"'>
        <then>
            <property name="LOG_FILE" value="${LOG_FILE}"/>
            <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <encoder>
                    <pattern>${FILE_LOG_PATTERN}</pattern>
                </encoder>
                <file>${LOG_FILE}</file>
                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                    <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</fileNamePattern>
                    <maxHistory>30</maxHistory>
                </rollingPolicy>
            </appender>
        </then>
    </if>

    <!-- SlowQueryReport用ログファイル -->
    <if condition='"${spring.profiles.active}" == "product" &amp;&amp; "${slowquery.logging.file}" != ""'>
        <then>
            <springProperty scope="context" name="slowQueryLogFile" source="slowquery.logging.file"/>
            <appender name="SLOWQUERY_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <encoder>
                    <pattern>${FILE_LOG_PATTERN}</pattern>
                </encoder>
                <file>${slowQueryLogFile}</file>
                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                    <fileNamePattern>${slowQueryLogFile}.%d{yyyy-MM-dd}</fileNamePattern>
                    <maxHistory>30</maxHistory>
                </rollingPolicy>
            </appender>
        </then>
    </if>

    <if condition='"${spring.profiles.active}" == "develop"'>
        <then>
            <include resource="logback-develop.xml"/>
        </then>
    </if>
    <if condition='"${spring.profiles.active}" == "unittest"'>
        <then>
            <include resource="logback-unittest.xml"/>
        </then>
    </if>
    <if condition='"${spring.profiles.active}" == "product"'>
        <then>
            <include resource="logback-product.xml"/>
        </then>
    </if>
</configuration>
  • <!-- SlowQueryReport用ログファイル --><if condition=...> ... </if> を追加します。
  • <if condition='...'> の中で AND 条件を記述する場合には &amp;&amp; と書きます。

logback-product.xml

<?xml version="1.0" encoding="UTF-8"?>
<included>
    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>

    <!-- Doma 2 -->
    <logger name="org.seasar.doma" level="ERROR"/>

    <!-- Tomcat JDBC Connection Pool SlowQueryReport interceptor -->
    <if condition='"${slowquery.logging.file}" != ""'>
        <then>
            <logger name="org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport" level="INFO">
                <appender-ref ref="SLOWQUERY_LOG_FILE"/>
            </logger>
        </then>
    </if>
</included>
  • <!-- Tomcat JDBC Connection Pool SlowQueryReport interceptor --><if condition=...> ... </if> を追加します。

履歴

2017/04/20
初版発行。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その21 )( Log4jdbc Spring Boot Starter を入れてみる )

概要

記事一覧はこちらです。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その20 )( 気になった点を修正する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • log4jdbc を適用するのに Log4jdbc Spring Boot Starter というライブラリが出ていたので、それに乗り換えてみます。

参照したサイト・書籍

  1. Log4jdbc Spring Boot Starter
    https://github.com/candrews/log4jdbc-spring-boot-starter

  2. How to exclude *AutoConfiguration classes in Spring Boot JUnit tests?
    http://stackoverflow.com/questions/26698071/how-to-exclude-autoconfiguration-classes-in-spring-boot-junit-tests

目次

  1. これまでの log4jdbc を適用する手順とは
  2. Log4jdbc Spring Boot Starter の場合にはどう変わるのか
  3. 実際に適用してみる
  4. develop プロファイルで起動してログが出力されることを確認する
  5. spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を設定すればログが出力されないことを確認する
  6. 感想

手順

これまでの log4jdbc を適用する手順とは

これまで Project に log4jdbc を適用するには、以下の手順で設定していました。

  1. build.gradle に compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16") を記述する。
  2. src/main/resources の下に log4jdbc.log4j2.properties を作成する。
  3. src/main/resources の下の application-develop.properties の spring.datasource.url に記述する URL に :log4jdbc を追加し、spring.datasource.tomcat.driverClassName には net.sf.log4jdbc.sql.jdbcapi.DriverSpy を記述する。
  4. src/main/resources の下の logback-develop.xml<logger name="jdbc.~" level="..."/> を記述する。

Log4jdbc Spring Boot Starter の場合にはどう変わるのか

これが Log4jdbc Spring Boot Starter を適用する場合には、以下の手順で設定すればよいだけになります。

  1. build.gradle に compile("com.integralblue:log4jdbc-spring-boot-starter:1.0.0") を記述する。
  2. src/main/resources の下の logback-develop.xml<logger name="jdbc.~" level="..."/> を記述する。
  3. log4jdbc を適用したくない profile がある場合には、src/main/resources の下の application-[profile名].properties に spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を記述する。

実際に適用してみる

  1. build.gradle を リンク先の内容 に変更します。

  2. 変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

    Project Tool Window を見ると適用される log4jdbc のライブラリは以前と同じ org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16 のようです。

    f:id:ksby:20170415083650p:plain

  3. src/main/resources/log4jdbc.log4j2.properties を削除します。

  4. src/main/resources の下の application.properties を リンク先の内容 に変更します。

  5. src/main/resources の下の application-develop.properties, application-product.properties, application-unittest.properties を リンク先の内容 に変更します。

  6. clean タスク → Rebuild Project → build タスクを実行して “BUILD SUCCESSFUL” が表示されることを確認します。

    f:id:ksby:20170415143716p:plain

  7. Project Tool Window の src/test から「Run ‘All Tests’ with Coverage」を実行してテストが全て成功することを確認します。

    f:id:ksby:20170415144105p:plain

develop プロファイルで起動してログが出力されることを確認する

bootRun で起動して、ログイン画面から tanaka.taro@sample.com でログインした後、検索対象図書館登録画面からアジア・アフリカ図書館を選択してみます。

f:id:ksby:20170415145322p:plain

Log4jdbc Spring Boot Starter に入れ替える前と同様に JDBC のログが出力されていることが確認できます。

f:id:ksby:20170415145628p:plain

Ctrl+F2 を押して Tomcat を停止します。

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を設定すればログが出力されないことを確認する

application-develop.properties に spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を追加します。

spring.mail.host=localhost
spring.mail.port=25

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672

spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=localhost:6381,localhost:6382,localhost:6383

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration

再度 bootRun で起動して、ログイン画面から tanaka.taro@sample.com でログインした後、検索対象図書館登録画面から米国大使館レファレンス資料室を選択してみます。

f:id:ksby:20170415152958p:plain

今度は JDBC のログは出力されませんでした。

f:id:ksby:20170415153304p:plain

Ctrl+F2 を押して Tomcat を停止します。application-develop.properties も元に戻します。

感想

これまで log4jdbc を適用するにはいろんな箇所を設定しないといけなかったのが省略されるので、楽ですね。今後はこれを使っていきたいと思います。

ソースコード

build.gradle

dependencies {
    ..........

    // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの
    runtime("${jdbcDriver}")
    compile("com.integralblue:log4jdbc-spring-boot-starter:1.0.0")
    compile("org.simpleframework:simple-xml:2.7.1")
  • compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16") を削除します。
  • compile("com.integralblue:log4jdbc-spring-boot-starter:1.0.0") を追加します。

application.properties

doma.dialect=org.seasar.doma.jdbc.dialect.PostgresDialect

spring.datasource.tomcat.url=jdbc:postgresql://localhost/ksbylending
spring.datasource.tomcat.username=ksbylending_user
spring.datasource.tomcat.password=xxxxxxxx
spring.datasource.tomcat.driverClassName=org.postgresql.Driver

spring.session.store-type=redis

spring.freemarker.cache=true
spring.freemarker.charset=UTF-8
spring.freemarker.enabled=false
spring.freemarker.prefer-file-system-access=false
  • application-product.properties に記載してある以下の設定をコピーします。
    • spring.datasource.tomcat.url=jdbc:postgresql://localhost/ksbylending
    • spring.datasource.tomcat.username=ksbylending_user
    • spring.datasource.tomcat.password=xxxxxxxx
    • spring.datasource.tomcat.driverClassName=org.postgresql.Driver

application-develop.properties, application-product.properties, application-unittest.properties

■application-develop.properties

spring.mail.host=localhost
spring.mail.port=25

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672

spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=localhost:6381,localhost:6382,localhost:6383
  • spring.datasource.tomcat.url, spring.datasource.tomcat.username, spring.datasource.tomcat.password, spring.datasource.tomcat.driverClassName の設定を削除します。

■application-product.properties

server.tomcat.basedir=C:/webapps/ksbysample-webapp-lending
logging.file=${server.tomcat.basedir}/logs/ksbysample-webapp-lending.log

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration

spring.mail.host=localhost
spring.mail.port=25

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672

spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=localhost:6381,localhost:6382,localhost:6383
  • spring.datasource.tomcat.url, spring.datasource.tomcat.username, spring.datasource.tomcat.password, spring.datasource.tomcat.driverClassName の設定を削除します。
  • spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を追加します。

■application-unittest.properties

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration

spring.mail.host=localhost
spring.mail.port=25

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672

spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=localhost:6381,localhost:6382,localhost:6383
  • spring.datasource.tomcat.url, spring.datasource.tomcat.username, spring.datasource.tomcat.password, spring.datasource.tomcat.driverClassName の設定を削除します。
  • spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を追加します。

履歴

2017/04/15
初版発行。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その20 )( 気になった点を修正する )

概要

記事一覧はこちらです。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その19 )( Spring Boot を 1.4.4 → 1.4.5 にバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • 1.4 系へのバージョンアップとは直接関係ありませんが、修正した方がよさそうな点を修正します。

参照したサイト・書籍

  1. Spring Bootでバリデーションエラー時のメッセージリソースをValidationMessages.propertiesからmessages.propertiesにする
    http://qiita.com/NagaokaKenichi/items/65d0e07151292968d67f

目次

  1. application.properties から hibernate.dialect, spring.jpa.~ を削除する
  2. hibernate.properties を削除する
  3. ValuesEnumValidatorTest.java 内で定義しているクラスに static を追加する
  4. FreeMarkerUtils → FreeMarkerHelper へ変更する
  5. ValidationMessages_ja_JP.properties をやめて messages.properties に1本化する& IDEA の Transparent native-to-ascii conversion のチェックを外して UTF-8 の文字列のまま保存する
  6. clean タスク → Rebuild Project → build タスクを実行する

手順

application.properties から hibernate.dialect, spring.jpa.~ を削除する

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その35 )( 貸出申請画面の作成6 )@SpringBootApplication アノテーションexclude = {JpaRepositoriesAutoConfiguration.class, HibernateJpaAutoConfiguration.class} を追加して JPA を無効にしましたが、不要になった設定を残したままにしていたので削除します。

  1. src/main/resources/application.properties を リンク先の内容 に変更します。

hibernate.properties を削除する

上で書いたように HibernateJpaAutoConfiguration.class は無効にしたので、関連する設定ファイルである hibernate.properties を削除します。

  1. src/main/resources/hibernate.properties を削除します。

ValuesEnumValidatorTest.java 内で定義しているクラスに static を追加する

Error Prone のバージョンアップの検証をしている時に static が付いていないという警告が出たので、付けることにします。

  1. src/test/java/ksbysample/webapp/lending/values/validation/ValuesEnumValidatorTest.javaリンク先の内容 に変更します。

FreeMarkerUtils → FreeMarkerHelper へ変更する

FreeMarkerUtils クラスは static メソッドを持っておらず、クラスに @Component アノテーションを付加しているので、Utils ではなく Helper クラスに変更します。

  1. Project Tool Window で ksbysample.webapp.lending.util パッケージの下の freemarker を ksbysample.webapp.lending.helper パッケージの下へ移動します。

    「Select Refactoring」ダイアログが表示されますので、そのまま「OK」ボタンをクリックします。

    f:id:ksby:20170408192611p:plain

    「Warning」ダイアログが表示されますが、これも「Yes」ボタンをクリックします。

    f:id:ksby:20170408192821p:plain

    「Move」ダイアログが表示されますので、そのまま「Refactor」ボタンをクリックします。

    f:id:ksby:20170408193033p:plain

  2. src/main/java/ksbysample/webapp/lending/helper/freemarker の下の FreeMarkerUtils クラスのクラス名を FreeMarkerHelper へ変更します。

    IntelliJ IDEA 2017.1 からなのか、クラスを選択して Shift+F6 を押しても「Rename」ダイアログが表示されませんでした。今回は修正箇所を1つずつ修正しています。バグ?

  3. src/test/groovy/ksbysample/webapp/lending/helper/freemarker の下の FreeMarkerUtilsTest クラスのクラス名を FreeMarkerHelperTest へ変更します。

  4. 以下のソースに記述されている FreeMarkerUtils freeMarkerUtilsFreeMarkerHelper freeMarkerHelper へ変更します。

    • src/main/java/ksbysample/webapp/lending/helper/mail/Mail001Helper.java
    • src/main/java/ksbysample/webapp/lending/helper/mail/Mail002Helper.java
    • src/main/java/ksbysample/webapp/lending/helper/mail/Mail003Helper.java
    • src/test/groovy/ksbysample/webapp/lending/helper/freemarker/FreeMarkerHelperTest.groovy

ValidationMessages_ja_JP.properties をやめて messages.properties に1本化する& IDEA の Transparent native-to-ascii conversion のチェックを外して UTF-8 の文字列のまま保存する

Bean Validation に Hibernate Validator を利用している場合、メッセージは ValidationMessages.properties に記述し、日本語が含まれるなら native-to-ascii で変換する必要がありますが、Spring Bootでバリデーションエラー時のメッセージリソースをValidationMessages.propertiesからmessages.propertiesにする の記事にメッセージを messages.properties に一本化する方法が記載されているのを見かけたので、メッセージは messages.properties に一本化し、かつ native-to-ascii を止めて UTF-8 のままで保存するようにします。

  1. src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.javaリンク先の内容 に変更します。

  2. src/main/java/ksbysample/webapp/lending/config の下に WebMvcConfig.java を新規作成し、リンク先の内容 の内容を記述します。

  3. ValidationMessages_ja_JP.properties に定義されたメッセージを messages_ja_JP.properties へ移動します。また使用されていないメッセージを削除します。src/main/resources/messages_ja_JP.properties を リンク先の内容 に変更します。

  4. src/main/resources/ValidationMessages_ja_JP.properties を削除します。

  5. native-to-ascii の設定を解除します。まず src/main/resources/messages_ja_JP.properties のファイルの内容を IntelliJ IDEA とは別のテキストエディタ(メモ帳やサクラエディタ等)にコピーします。

  6. IntelliJ IDEA のメインメニューから「File」-「Settings…」を選択して「Settings」ダイアログを表示した後、以下の画面の「Transparent native-to-ascii conversion」のチェックを外します。

    f:id:ksby:20170408230832p:plain

  7. チェックを外した後に src/main/resources/messages_ja_JP.properties を開くとメッセージが AbstractUserDetailsAuthenticationProvider.locked=\u5165\u529B\u3055\u308C\u305F ID \u306F\u30ED\u30C3\u30AF\u3055\u308C\u3066\u3044\u307E\u3059 のように表示されるので、テキストエディタにコピーしておいたメッセージを戻します。

clean タスク → Rebuild Project → build タスクを実行する

最後に build, テストが正常に終了することを確認します。

  1. clean タスク → Rebuild Project → build タスクを実行して “BUILD SUCCESSFUL” が表示されることが確認できました。

    f:id:ksby:20170408235229p:plain

  2. Project Tool Window の src/test から「Run ‘All Tests’ with Coverage」を実行してテストが全て成功しました。

    f:id:ksby:20170409000955p:plain

ソースコード

application.properties

doma.dialect=org.seasar.doma.jdbc.dialect.PostgresDialect

spring.session.store-type=redis

spring.freemarker.cache=true
spring.freemarker.charset=UTF-8
spring.freemarker.enabled=false
spring.freemarker.prefer-file-system-access=false
  • 以下の設定を削除します。
    • hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
    • spring.jpa.hibernate.ddl-auto=none
    • spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy

ValuesEnumValidatorTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class ValuesEnumValidatorTest {

    ..........

    // テスト用 POJO クラス
    @Data
    private static class NotAllowEmptyTestClass {
        @ValuesEnum(enumClass = TestValues.class)
        private String testStr;
    }

    // テスト用 POJO クラス
    @Data
    private static class AllowEmptyTestClass {
        @ValuesEnum(enumClass = TestValues.class, allowEmpty = true)
        private String testStr;
    }

    private Validator validator;

    ..........
  • NotAllowEmptyTestClass と AllowEmptyTestClass クラスの定義に static を追加します。

ApplicationConfig.java

@Configuration
public class ApplicationConfig {

    ..........

    private final MessageSource messageSource;

    /**
     * @param connectionFactory {@link ConnectionFactory} bean
     * @param messageSource     {@link MessageSource} bean
     */
    public ApplicationConfig(ConnectionFactory connectionFactory
            , MessageSource messageSource) {
        this.connectionFactory = connectionFactory;
        this.messageSource = messageSource;
    }

    ..........

    /**
     * Controller クラスで直接 {@link Validator} を呼び出すために Bean として定義している
     * また Hibernate Validator のメッセージを ValidationMessages.properties ではなく
     * messages.properties に記述できるようにするためにも使用している
     *
     * @return new {@link LocalValidatorFactoryBean}
     */
    @Bean
    public Validator validator() {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(this.messageSource);
        return localValidatorFactoryBean;
    }

    ..........
  • フィールド変数 private final MessageSource messageSource; を追加し、コンストラクタインジェクションを追加します。
  • validator メソッドの処理を上記のように変更します。localValidatorFactoryBean.setValidationMessageSource(this.messageSource); を呼び出すようにします。

WebMvcConfig.java

package ksbysample.webapp.lending.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.validation.Validator;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    private final Validator validator;

    /**
     * @param validator {@link Validator} bean
     */
    public WebMvcConfig(Validator validator) {
        this.validator = validator;
    }

    /**
     * Hibernate Validator のメッセージを ValidationMessages.properties ではなく
     * messages.properties に記述するために Override して {@link Validator} bean を返している
     *
     * @return {@link Validator} bean
     */
    @Override
    public Validator getValidator() {
        return validator;
    }

}

messages_ja_JP.properties

AbstractUserDetailsAuthenticationProvider.locked=入力された ID はロックされています
AbstractUserDetailsAuthenticationProvider.disabled=入力された ID は使用できません
AbstractUserDetailsAuthenticationProvider.expired=入力された ID の有効期限が切れています
AbstractUserDetailsAuthenticationProvider.credentialsExpired=入力された ID のパスワードの有効期限が切れています
AbstractUserDetailsAuthenticationProvider.badCredentials=入力された ID あるいはパスワードが正しくありません
UserInfoUserDetailsService.usernameNotFound=入力された ID あるいはパスワードが正しくありません

# Bean Validation 用メッセージ
error.size.max = {max}文字以内で入力して下さい。
javax.validation.constraints.NotNull.message=必須の入力項目です。
org.hibernate.validator.constraints.Email.message=メールアドレスを入力して下さい。
org.hibernate.validator.constraints.NotBlank.message=必須の入力項目です。
typeMismatch.java.lang.Long=数値を入力して下さい。

Global.optimisticLockException=既にデータが更新されているため更新できませんでした。データを読み込み直してください。

..........
  • 以下のメッセージを追加します。
    • error.size.max = {max}文字以内で入力して下さい。
    • javax.validation.constraints.NotNull.message=必須の入力項目です。
    • org.hibernate.validator.constraints.Email.message=メールアドレスを入力して下さい。
    • org.hibernate.validator.constraints.NotBlank.message=必須の入力項目です。
  • 以下のメッセージを削除します。
    • typeMismatch.java.math.BigDecimal=数値を入力して下さい。
  • 以下のメッセージは ValidationMessages_ja_JP.properties から移動せず削除します。
    • error.digits.integerandfraction = 数値を整数{integer}桁以内、小数{fraction}桁以内で入力して下さい。
    • error.digits.integeronly = 数値を整数{integer}桁以内で入力して下さい。

履歴

2017/04/09
初版発行。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その19 )( Spring Boot を 1.4.4 → 1.4.5 にバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その18 )( Gradle のバージョンを 2.13 → 3.x へバージョンアップ。。。しようと思いましたが止めました ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • 記事を書き始めた時の Spring Boot のバージョンは 1.4.4 でしたが、1.4.5 が出ているのでバージョンアップします。
    • Error Prone 以外のライブラリも最新バージョンにバージョンアップします。
    • build.gradle の書き方で、最近は jar { ... } は書かずに group, version を一番上に書くようにしているので、そのように変更します。また Error Prone の compileJava.options.compilerArgs += ['-Xep:RemoveUnusedImports:WARN'] の設定を追加して不要な import 文が検出されるようにします。

参照したサイト・書籍

目次

  1. build.gradle を変更する
  2. clean タスク → Rebuild Project → build タスクを実行する
  3. メモ書き

手順

build.gradle を変更する

  1. build.gradle を リンク先の内容 に変更します。

  2. 変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

clean タスク → Rebuild Project → build タスクを実行する

  1. clean タスク → Rebuild Project → build タスクを実行します。

    f:id:ksby:20170408013157p:plain f:id:ksby:20170408013605p:plain

    build.gradle に追加した compileJava.options.compilerArgs += ['-Xep:RemoveUnusedImports:WARN'] により、使用されていない import 文が入っているソースがログに出力されていました。以下の2ファイルです。不要な import 文を削除します。

    • src/main/java/ksbysample/webapp/lending/Application.java
    • src/main/java/ksbysample/webapp/lending/helper/url/UrlAfterLoginHelper.java

    他は問題ないようで無事 “BUILD SUCCESSFUL” のメッセージが表示されています。

  2. Project Tool Window の src/test から「Run ‘All Tests’ with Coverage」を実行すると、こちらも全てのテストが成功しました。

    f:id:ksby:20170408075659p:plain

メモ書き

  • Lombok の 1.16.16 が出ていたので Lombok Changelog を見てみたのですが、JDK9 now supported と記述されていました。これでいよいよ Error Prone のバージョンアップが出来るかも!?

ソースコード

build.gradle

group 'ksbysample'
version '1.4.5-RELEASE'

buildscript {
    ext {
        springBootVersion = '1.4.5.RELEASE'
    }
    repositories {
        jcenter()
        maven { url "http://repo.spring.io/repo/" }
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        // for Error Prone ( http://errorprone.info/ )
        classpath("net.ltgt.gradle:gradle-errorprone-plugin:0.0.9")
        // for Grgit
        classpath("org.ajoberstar:grgit:1.9.0")
        // Gradle Download Task
        classpath("de.undercouch:gradle-download-task:3.2.0")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'de.undercouch.download'
apply plugin: 'groovy'
apply plugin: 'net.ltgt.errorprone'
apply plugin: 'checkstyle'
apply plugin: 'findbugs'

sourceCompatibility = 1.8
targetCompatibility = 1.8

task wrapper(type: Wrapper) {
    gradleVersion = '2.13'
}

[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ['-Xlint:all,-options,-processing,-path']
compileJava.options.compilerArgs += ['-Xep:RemoveUnusedImports:WARN']

// for Doma 2
// JavaクラスとSQLファイルの出力先ディレクトリを同じにする
processResources.destinationDir = compileJava.destinationDir
// コンパイルより前にSQLファイルを出力先ディレクトリにコピーするために依存関係を逆転する
compileJava.dependsOn processResources

idea {
    module {
        inheritOutputDirs = false
        outputDir = file("$buildDir/classes/main/")
    }
}

configurations {
    // for Doma 2
    domaGenRuntime
}

checkstyle {
    configFile = file("${rootProject.projectDir}/config/checkstyle/google_checks.xml")
    toolVersion = '7.6.1'
    sourceSets = [project.sourceSets.main]
}

findbugs {
    toolVersion = '3.0.1'
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    effort = "max"
    excludeFilter = file("${rootProject.projectDir}/config/findbugs/findbugs-exclude.xml")
}

tasks.withType(FindBugs) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}

repositories {
    jcenter()
}

dependencyManagement {
    imports {
        mavenBom("io.spring.platform:platform-bom:Athens-SR4") {
            bomProperty 'commons-lang3.version', '3.5'
            bomProperty 'guava.version', '21.0'
        }
    }
}

bootRepackage {
    mainClass = 'ksbysample.webapp.lending.Application'
    excludeDevtools = true
}

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:9.4.1212"
    def spockVersion = "1.1-groovy-2.4-rc-4"
    def domaVersion = "2.16.0"
    def lombokVersion = "1.16.16"
    def errorproneVersion = "2.0.15"

    // dependency-management-plugin によりバージョン番号が自動で設定されるもの
    // Appendix A. Dependency versions ( http://docs.spring.io/platform/docs/current/reference/htmlsingle/#appendix-dependency-versions ) 参照
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.thymeleaf.extras:thymeleaf-extras-springsecurity4")
    compile("org.thymeleaf.extras:thymeleaf-extras-java8time")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-freemarker")
    compile("org.springframework.boot:spring-boot-starter-mail")
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-data-redis")
    compile("org.springframework.boot:spring-boot-starter-amqp")
    compile("org.springframework.boot:spring-boot-devtools")
    compile("org.springframework.session:spring-session")
    compile("org.springframework.retry:spring-retry")
    compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
    compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
    compile("com.google.guava:guava")
    compile("org.apache.commons:commons-lang3")
    compile("org.codehaus.janino:janino")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("org.springframework.security:spring-security-test")
    testCompile("org.yaml:snakeyaml")
    testCompile("org.mockito:mockito-core")

    // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの
    runtime("${jdbcDriver}")
    compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16")
    compile("org.simpleframework:simple-xml:2.7.1")
    compile("com.univocity:univocity-parsers:2.3.1")
    testCompile("org.dbunit:dbunit:2.5.3")
    testCompile("com.icegreen:greenmail:1.5.3")
    testCompile("org.assertj:assertj-core:3.6.2")
    testCompile("com.jayway.jsonpath:json-path:2.2.0")
    testCompile("org.spockframework:spock-core:${spockVersion}") {
        exclude module: "groovy-all"
    }
    testCompile("org.spockframework:spock-spring:${spockVersion}") {
        exclude module: "groovy-all"
    }
    testCompile("com.google.code.findbugs:jsr305:3.0.2")

    // for lombok
    compileOnly("org.projectlombok:lombok:${lombokVersion}")
    testCompileOnly("org.projectlombok:lombok:${lombokVersion}")

    // for Doma
    compile("org.seasar.doma:doma:${domaVersion}")
    domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}")
    domaGenRuntime("${jdbcDriver}")

    // for Error Prone ( http://errorprone.info/ )
    errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}")
    compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}")
}

..........
  • group 'ksbysample' を追加します。
  • version '1.4.5-RELEASE' を追加します。バージョン番号は Spring Boot のバージョンに合わせます。
  • buildscript の以下の点を変更します。
    • springBootVersion = '1.4.4.RELEASE'springBootVersion = '1.4.5.RELEASE' に変更します。
    • classpath("org.ajoberstar:grgit:1.8.0")classpath("org.ajoberstar:grgit:1.9.0") に変更します。
  • compileJava.options.compilerArgs += ['-Xep:RemoveUnusedImports:WARN'] を追加します。
  • jar { ... } を削除します。
  • checkstyle の以下の点を変更します。
    • toolVersion = '7.5.1'toolVersion = '7.6.1' に変更します。
  • dependencyManagement の以下の点を変更します。
    • mavenBom("io.spring.platform:platform-bom:Athens-SR3")mavenBom("io.spring.platform:platform-bom:Athens-SR4") に変更します。
  • dependencies の以下の点を変更します。
    • def jdbcDriver = "org.postgresql:postgresql:9.4.1212"def jdbcDriver = "org.postgresql:postgresql:42.0.0" に変更します。
    • def spockVersion = "1.1-groovy-2.4-rc-3"def spockVersion = "1.1-groovy-2.4-rc-4" に変更します。
    • def domaVersion = "2.15.0"def domaVersion = "2.16.0" に変更します。
    • def lombokVersion = "1.16.12"def lombokVersion = "1.16.16" に変更します。
    • compile("com.univocity:univocity-parsers:2.3.1")compile("com.univocity:univocity-parsers:2.4.1") に変更します。
    • testCompile("com.google.code.findbugs:jsr305:3.0.1")testCompile("com.google.code.findbugs:jsr305:3.0.2") に変更します。
    • // for Doma Gen// for Doma へコメントを変更し、compile("org.seasar.doma:doma:${domaVersion}") をこのコメントの下に移動します。Doma の記述は1つにまとめることにします。

履歴

2017/04/08
初版発行。

Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( 番外編 )( Optional をもう少しまともに使ってみる )

概要

記事一覧はこちらです。

src/main/java/ksbysample/webapp/lending/util/cookie/CookieUtils.java のソースに書いた Optional の使い方を見つけて、以前は全然使い方を理解できていなかったんだな。。。と思ったので、修正します。

Optional らしく書き直してみる

src/main/java/ksbysample/webapp/lending/util/cookie/CookieUtils.java で Optional を以下のように使っていたのですが、

    public static String getCookieValue(String cookieName, HttpServletRequest request) {
        Optional<String> result = Optional.empty();
        if (request != null) {
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                result = Arrays.asList(cookies).stream()
                        .filter(cookie -> StringUtils.equals(cookie.getName(), cookieName))
                        .map(cookie -> cookie.getValue())
                        .findFirst();
            }
        }
        return result.orElse(null);
    }

上の内容なら if 文を使わずに、もう少しすっきりしたソースにできそうです。戻り値も StringOptional<String> に変更して書き直してみます。

    public static Optional<String> getCookieValue(String cookieName, HttpServletRequest request) {
        return Optional.ofNullable(request)
                .flatMap(req -> Optional.ofNullable(req.getCookies()))
                .flatMap(cookies -> Arrays.stream(cookies)
                            .filter(cookie -> StringUtils.equals(cookie.getName(), cookieName))
                            .map(Cookie::getValue)
                            .findFirst());
    }

CookieUtils#getCookieValue を呼び出している箇所も修正します。

src/main/java/ksbysample/webapp/lending/helper/url/UrlAfterLoginHelper.java は以下のように実装されているのを、

    public static String getUrlAfterLogin(Authentication authentication, HttpServletRequest request) {
        String targetUrl = WebSecurityConfig.DEFAULT_SUCCESS_URL;

        // 特定の権限を持っている場合には対応するURLへリダイレクトする
        GrantedAuthority roleAdmin = new SimpleGrantedAuthority("ROLE_ADMIN");
        if (authentication.getAuthorities().contains(roleAdmin)) {
            // 管理権限 ( ROLE_ADMIN ) を持っている場合には検索対象図書館登録画面へ遷移させる
            targetUrl = Constant.URL_AFTER_LOGIN_FOR_ROLE_ADMIN;
        }

        // LastLendingAppId Cookie に貸出申請ID をセットされている場合には貸出申請画面へリダイレクトさせる
        String cookieLastLendingAppId = CookieUtils.getCookieValue(CookieLastLendingAppId.COOKIE_NAME, request);
        if (StringUtils.isNotBlank(cookieLastLendingAppId)) {
            targetUrl = String.format("%s?lendingAppId=%s", Constant.URL_LENDINGAPP, cookieLastLendingAppId);
        }

        return targetUrl;
    }

以下のように修正します。

    public static String getUrlAfterLogin(Authentication authentication, HttpServletRequest request) {
        String targetUrl = WebSecurityConfig.DEFAULT_SUCCESS_URL;

        // 特定の権限を持っている場合には対応するURLへリダイレクトする
        GrantedAuthority roleAdmin = new SimpleGrantedAuthority("ROLE_ADMIN");
        if (authentication.getAuthorities().contains(roleAdmin)) {
            // 管理権限 ( ROLE_ADMIN ) を持っている場合には検索対象図書館登録画面へ遷移させる
            targetUrl = Constant.URL_AFTER_LOGIN_FOR_ROLE_ADMIN;
        }

        // LastLendingAppId Cookie に貸出申請ID をセットされている場合には貸出申請画面へリダイレクトさせる
        targetUrl = CookieUtils.getCookieValue(CookieLastLendingAppId.COOKIE_NAME, request)
                .map(cookieLastLendingAppId ->
                        String.format("%s?lendingAppId=%s", Constant.URL_LENDINGAPP, cookieLastLendingAppId))
                .orElse(targetUrl);

        return targetUrl;
    }

src/test/groovy/ksbysample/webapp/lending/util/cookie/CookieUtilsTest.groovy は以下のように実装されているのを、

    def "GetCookieValueのテスト"() {
        setup:
        def request = new MockHttpServletRequest()
        
        expect:
        Cookie cookieTest = new Cookie(CookieTest.COOKIE_NAME, "テスト")
        Cookie cookieSample = new Cookie(CookieSample.COOKIE_NAME, "サンプル")
        request.setCookies(cookieTest, cookieSample)
        CookieUtils.getCookieValue(CookieTest.COOKIE_NAME, request) == "テスト"
        CookieUtils.getCookieValue(CookieSample.COOKIE_NAME, request) == "サンプル"
    }

以下のように修正します。

    def "GetCookieValueのテスト"() {
        setup:
        def request = new MockHttpServletRequest()

        expect:
        Cookie cookieTest = new Cookie(CookieTest.COOKIE_NAME, "テスト")
        Cookie cookieSample = new Cookie(CookieSample.COOKIE_NAME, "サンプル")
        request.setCookies(cookieTest, cookieSample)
        CookieUtils.getCookieValue(CookieTest.COOKIE_NAME, request).get() == "テスト"
        CookieUtils.getCookieValue(CookieSample.COOKIE_NAME, request).get() == "サンプル"
        CookieUtils.getCookieValue(CookieTest.COOKIE_NAME, null) == Optional.empty()
        CookieUtils.getCookieValue("NotExistsCookie", request) == Optional.empty()
    }

最後にテストが通しで全て成功することを確認します。

f:id:ksby:20170407020451p:plain

履歴

2017/04/07
初版発行。