ユニーク制約の一部にNullableなカラムを含めたいが、それではユニークにならないので回避したい。
(a, b, c) という複数カラムのユニーク制約を定義したい場合に、この中にNULLを許可するカラムがありNULLが入ってきてしまうと、MySQLなどではユニーク性が担保されない。
これを回避するために NULL の代わりに 0 を使ってみたら良さそうだが、Springではどうやればいいのか?
ユニーク制約の一部にNullableなカラムを含めたいが、それではユニークにならないので回避したい。
(a, b, c) という複数カラムのユニーク制約を定義したい場合に、この中にNULLを許可するカラムがありNULLが入ってきてしまうと、MySQLなどではユニーク性が担保されない。
これを回避するために NULL の代わりに 0 を使ってみたら良さそうだが、Springではどうやればいいのか?
Spring BootでJDBCを使っていてSQLExceptionが発生した場合に、HibernateのSqlExceptionHelperが以下のようにERRORログを出力してしまう。
2016-10-30 13:56:45.772 WARN 40153 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23502, SQLState: 23502
2016-10-30 13:56:45.772 ERROR 40153 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper : 列 "TEAM_ID" にはnull値が許されていません
NULL not allowed for column "TEAM_ID"; SQL statement:
insert into tag (id, created_at, updated_at, account_id, name, team_id) values (null, ?, ?, ?, ?, ?) [23502-190]
未知の例外に対してはこの挙動でも問題ないように思うが、例えばデッドロックが発生した時にはリトライしたいとか、自分でハンドリングしたいケースがあった場合には、本当に問題といえる状態だと判断ができるレイヤでERRORログを出力するように制御したい。
…ということで、このログ出力を回避して自分でハンドリングする方法について。
以前のエントリ
Spring BootでJavaScript/CSSライブラリにフィンガープリントをつける
Spring BootでJavaScript/CSSライブラリにフィンガープリントをつける (2)
の方法だけだと、フィンガープリントを付けることはできてもSpring Securityによりキャッシュ無効化のヘッダが付いてしまうためキャッシュされない。
そこで静的リソースについてはキャッシュヘッダを無効化してみて、一見 Cache-Control: no-cache
のようなヘッダはなくなったかのように見えたが、Font Awesomeのアイコンがどうもちらつくな…と思って調べた。
すると、静的リソースについては全体的にキャッシュ系のヘッダを無効化していたものの、Expiresヘッダだけはついてしまっていた。
※Spring Boot 1.3.2 (Spring Security 4.0.3) を使用。
基本的な部分かもしれないが、Thymeleaf、JPAでの型変換を行う方法について。
Thymeleafでは、SpringのConverterが定義されていれば${{variable}}
の形式で書くことでConverterで変換した結果を出力してくれる。
なので、HTML上で分岐を書いたり独自の変換用のBeanを定義するよりはこの仕組みを使ったほうがいい。
例えば以下のような列挙型を定義していたとする。
Bean ValidationのエラーメッセージはValidationMessages.propertiesもしくはValidationMessages_ja.propertiesに書かなければならないと思っていたが、そうではなかった。
以下のようにMessageSourceで読み込んだ内容をLocalValidatorFactoryBeanに渡せば良い。
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Autowired
private MessageSource messageSource;
@Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setValidationMessageSource(messageSource);
return localValidatorFactoryBean;
}
@Override
public Validator getValidator() {
return validator();
}
}
messages.propertiesはnative2asciiで変換せず直接マルチバイトのメッセージを書いていても動作するので、この方法の方がいいかもしれない。
(コードレビューでも直接日本語のメッセージが読めるし)
APIだとAOPでロギングするのは割と簡単だが、画面の場合にうまいやり方が見つからず試行錯誤したのでメモ。
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
などを使えばリクエストの前後に処理を挟むことは簡単。
APIの場合は、バリデーションエラーや例外に対して共通的な処理を入れることは容易いが、画面の場合、バリデーションエラーが発生したら共通エラー画面ではなく元の画面を表示したいし、例外に対しても同じ。
例外に関しては個別のControllerのメソッド内でtry-catchを入れてログ出力すればいいが、バリデーションエラーは画面に表示されるだけでログに出力する方法がわかっていなかった。
Spring BootでControllerを含めたテストをする場合に、
MockMvcBuilders.webAppContextSetup()
でセットアップして @WebIntegrationTests
にすると通常のアプリケーションとしてテストできるが、数が多くなってくると重い。
いくつか改善できそうなポイントを調べたので記録しておく。
なお、極力Springを使わないのがベストだが、今回はそれができないケースを想定しているので除外。
以前、JavaとNode.jsでSpringアプリを動かしたが、自作の gradle-web-resource-plugin を使えば既にJava/Gradleだけで済むようになっていることもあり、Heroku の Gradle ビルドパックに切り替えてみた。
網羅的な手順ではなく、上記アプリのビルドパックを切り替える場合の記録なので注意。