データの登録をAPI経由で行うとき、作成日時や更新日時を対向APIやDBに連携する場面がある。

複数APIが同じように日時を取り扱いたい場合、それぞれのAPIで日時オブジェクトを生成するのは冗長である。

そのため、日時オブジェクトの生成を共通処理化してコントローラの引数としてバインドできるようにしてみた。

環境

  • Java 11
  • Spring Boot 2.4.3

実装

Spring Frameworkでは、HandlerMethodArgumentResolverインタフェースを利用することで、任意のオブジェクトをバインドしてコントローラの引数として受け取ることができる。

HandlerMethodArgumentResolverインタフェースの実装クラスを作成

supportsParameterメソッドは、コントローラのメソッドに指定した引数のオブジェクトがこのリゾルバで提供する型と同型であるか検証する。

resolveArgumentメソッドは、リゾルバで提供するオブジェクトを返却する。

RequestDateTimeHandlerMethodArgumentResolver.java@Component
public class RequestDateTimeHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    private final Clock clock;

    public RequestDateTimeHandlerMethodArgumentResolver(Clock clock) {
        this.clock = clock;
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().isAssignableFrom(RequestDateTime.class);
    }

    @Override
    public RequestDateTime resolveArgument(
            MethodParameter parameter,
            ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) {
        return RequestDateTime.now(clock);
    }
}
RequestDateTime.javapublic class RequestDateTime {

    private final LocalDateTime value;

    public static RequestDateTime now(Clock clock) {
        return new RequestDateTime(LocalDateTime.now(clock));
    }

    public String format() {
        return value.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }

}

WebMvcConfigurerインタフェースの実装クラスを作成

作成したリゾルバはそのままでは利用することができないので次のように設定する。

addArgumentResolversメソッドは、リゾルバを適用するための設定を行う。

HandlerMethodArgumentResolverのリストを引数に取りうるので、DIしたリゾルバをリストの要素に追加してやれば良い。

WebMvcConfigurerImpl.java@Configuration
public class WebMvcConfigurerImpl implements WebMvcConfigurer {

    private final RequestDateTimeHandlerMethodArgumentResolver requestDateTimeHandlerMethodArgumentResolver;
    
    public WebMvcConfigurerImpl(RequestDateTimeHandlerMethodArgumentResolver requestDateTimeHandlerMethodArgumentResolver) {
        this.requestDateTimeHandlerMethodArgumentResolver = requestDateTimeHandlerMethodArgumentResolver;
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolverList) {
        resolverList.add(requestDateTimeHandlerMethodArgumentResolver);
    }
}

コントローラのメソッドの引数として利用

RequestDateTimeを引数として受け取るためには次のように記載すれば良い。

PostController.javapublic ResponseEntity<RegisterPostResponse> registerPost(
        @RequestBody RegisterPostRequest requestBody,
        @Parameter(hidden = true) RequestDateTime requestDateTime) {
        
        System.out.println(requestDateTime.format()); // 20211021221245
       
       // 後続の処理は省略
}