📝 BLOG.IK.AM

@making's memo
(🗃 Categories 🏷 Tags)

Spring MVCの@DateTimeFormatで和暦パターンを扱う方法

🗃 {Programming/Java/org/springframework/web}

🏷 Java 🏷 Spring MVC

🗓 Updated at 2016-03-03T04:38:19+09:00 by making  🗓 Created at 2016-03-03T04:38:19+09:00 by making  {✒️️ Edit  ⏰ History}


🚨 Warning: This content is old. Please don't trust too much.

Spring MVCでリクエストパラメータをバインドする場合は@DateTimeFormatでパターンを指定しますが、
和暦フォーマット(GGGGyy.MM.ddなど)を指定するとパースエラーが発生します。

和暦を扱う場合はパーサーにLocaleChronologyを指定する必要があるのですが、
当然ながら日本用のものは指定されていないため、パースエラーとなります。

実はパーサーが使うLocaleChronologyは、org.springframework.context.i18n.LocaleContextHolderorg.springframework.format.datetime.standard.DateTimeContextHolderを使ってスレッドローカルに保存できます。
なのでFilterやInterceptorでこれを指定してやればOKです。

HandlerInterceptorAdapterを使う例を以下に示します。

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();
    }
}

アクセス例

$ 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