JSON レスポンスアドバイス
REST コントローラーのオブジェクトバインディングや、エラーハンドリングに特化したアドバイスを作成するには、通常のコントローラー同様、@ControllerAdvice
を使用しますが、org.springframework.web.servlet.mvc.method.annotation.AbstractMappingJacksonResponseBodyAdvice
を継承する点が異なります。
これがどのように動作するのか確認するため、ここまでに作成したコントローラーに、呼びだされた時間を付与するコントローラーアドバイスを、以下を参考に作成します。
// src/main/java/io/github/yo1000/sss/aspect/AppendTimeJacksonControllerAdvice.java
package io.github.yo1000.sss.aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.AbstractMappingJacksonResponseBodyAdvice;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class AppendTimeJacksonControllerAdvice extends AbstractMappingJacksonResponseBodyAdvice {
private static final Logger LOGGER = LoggerFactory.getLogger(AppendTimeJacksonControllerAdvice.class);
@Override
protected void beforeBodyWriteInternal(MappingJacksonValue mappingJacksonValue, MediaType mediaType,
MethodParameter methodParameter, ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {}
@Override
protected MappingJacksonValue getOrCreateContainer(Object body) {
MappingJacksonValue jacksonValue = super.getOrCreateContainer(body);
Object bodyValue = jacksonValue.getValue();
LOGGER.info("{}", bodyValue);
Map<String, Object> wrappedMap = new HashMap<>();
wrappedMap.put("body", bodyValue);
wrappedMap.put("time", System.currentTimeMillis());
jacksonValue.setValue(wrappedMap);
return jacksonValue;
}
}
アプリケーションを再起動して、cURL で、http://localhost:8080/api/v1/memo をリクエストしてみます。
$ curl -v -X GET http://localhost:8080/api/v1/memo
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /api/v1/memo HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 20 Jul 2016 04:42:06 GMT
<
* Connection #0 to host localhost left intact
{"time":1468989726732,"body":[{"memo":"Springを学ぶ","author":"金次郎","created":null},{"memo":"Thymeleafを学ぶ","author":"金次郎","created":null},{"memo":"Flywayを学ぶ","author":"金次郎","created":null},{"memo":"AspectJを生麩","author":"金字塔","created":null},{"memo":"REST対応する","author":"銀河万丈","created":null}]}
コントローラーアドバイスで設定したように、"time":1468989726732
がレスポンスに含まれるようになったことを確認できました。
このように、REST コントローラーに対するアドバイスについては、@ControllerAdvice
だけでなく、AbstractMappingJacksonResponseBodyAdvice
クラスの継承も必要になってきます。
この他にもレスポンスの内容に応じて、いくつかの抽象クラスが org.springframework.web.servlet.mvc.method.annotation
パッケージ配下に用意されているので、必要に応じてリファレンスを確認してみると良いでしょう。
サンプル
ここまでのコードサンプルは、以下より入手できます。
$ git clone -b appendix/2 https://github.com/yo1000/self-study-spring.git