--- title: Spring MVCの@DateTimeFormatで和暦パターンを扱う方法 tags: ["Spring MVC", "Java"] categories: ["Programming", "Java", "org", "springframework", "web"] date: 2016-03-03T04:38:19Z updated: 2016-03-03T04:38:19Z --- Spring MVCでリクエストパラメータをバインドする場合は`@DateTimeFormat`でパターンを指定しますが、 和暦フォーマット(`GGGGyy.MM.dd`など)を指定するとパースエラーが発生します。 和暦を扱う場合はパーサーに`Locale`や`Chronology`を指定する必要があるのですが、 当然ながら日本用のものは指定されていないため、パースエラーとなります。 実はパーサーが使う`Locale`や`Chronology`は、`org.springframework.context.i18n.LocaleContextHolder`や`org.springframework.format.datetime.standard.DateTimeContextHolder`を使ってスレッドローカルに保存できます。 なのでFilterやInterceptorでこれを指定してやればOKです。 `HandlerInterceptorAdapter`を使う例を以下に示します。 ``` java package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.datetime.standard.DateTimeContext; import org.springframework.format.datetime.standard.DateTimeContextHolder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.time.LocalDate; import java.time.chrono.JapaneseChronology; import java.util.Date; import java.util.Locale; @SpringBootApplication @RestController public class DemoWarekiApplication extends WebMvcConfigurerAdapter { public static void main(String[] args) { SpringApplication.run(DemoWarekiApplication.class, args); } @Override public void addInterceptors(InterceptorRegistry registry) { DateTimeContext context = new DateTimeContext(); context.setChronology(JapaneseChronology.INSTANCE); Locale japan = new Locale("ja", "JP", "JP"); registry.addInterceptor(new HandlerInterceptorAdapter() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { DateTimeContextHolder.setDateTimeContext(context); // for java.time.LocalDate LocaleContextHolder.setLocale(japan); // for java.util.Date return true; } }); } @RequestMapping(path = "/jud") Object jud(@DateTimeFormat(pattern = "GGGGyy.MM.dd") @RequestParam(name = "date") Date date) { return date.toString(); } @RequestMapping(path = "/jtl") Object jtl(@DateTimeFormat(pattern = "GGGGyy.MM.dd") @RequestParam(name = "date") LocalDate date) { return date.toString(); } } ``` アクセス例 ``` console $ curl "localhost:8080/jud?date=平成28.03.03" Thu Mar 03 00:00:00 JST 2016 $ curl "localhost:8080/jtl?date=平成28.03.03" 2016-03-03 ``` https://jira.spring.io/browse/SPR-13568