ControllerでHttpServletRequest
を引数に設定するとなんでもできますが、同じようなことをいろんなContorllerでやっていたらコードが重複して無駄ですよね…
例えばこんな感じ(このレベルだと@RequestHeader
使おうで済むんですけどねw)
@GetMapping("/sample/plain")
public String plain(HttpServletRequest request) {
return request.getHeader("key");
}
この記事では、HandlerMethodArgumentResolver
を使用して、Controllerの引数で任意のクラスを受け取ることで解決する方法を紹介します!
任意クラスの作成
まずは、Controllerの引数で受けとるクラスを作成します。
@Value
public class SampleModel {
private String key;
}
【本題】HandlerMethodArgumentResolver
本題の任意のクラスに値をバインドするクラスです。
public class SampleArgumentResolver implements HandlerMethodArgumentResolver {
// Controller(RestController)の引数ごとに実行される
// このメソッドの戻り値がtrueの場合だけ、resolveArgumentが実行される
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(SampleModel.class);
}
// 引数を解決するメインメソッド
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory
) throws Exception {
var name = webRequest.getHeader("key");
// 引数で受け取りたいクラスを返す
return new SampleModel(name);
}
}
メソッドごとにもう少し解説します。
supportsParameter
このメソッドは、Controllerの実行ごとControllerの引数ごとに実行されます。
このメソッドがtrueを返す場合にのみresolveArgument
が実行されます。
一番メジャーな使い方としては、引数のクラスに応じてtrue / falseを返却することです。
もう少し細かくやろうとしたら
・引数の名前:parameter.getParameter().getName()
・アノテーション:parameter.getParameterAnnotation(<クラス>.class)
とかが使えそうです!
resolveArgument
このクラスで引数に受け取りたいクラスを返すように実装します。
HttpServletRequest
に対応するクラスがNativeWebRequest
で、headerやパラメータ等HTTPリクエストに関する情報を取得できます。
WebMvcConfigurer
先ほど作成したHandlerMethodArgumentResolver
ですが、クラスを作成しただけではSpringに認識をしてもらえないので、WebMvcConfigurer
を実装したクラスで存在を教えてあげる必要があります。
@Configuration
public class HandlerMethodArgumentResolverConfiguration implements WebMvcConfigurer {
// 実装したresolverを登録する
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new SampleArgumentResolver());
}
}
動かしてみる
これで、任意のクラス(ここではSampleModel
)を受け取る準備ができたので、動かしてみましょう!
@RestController
public class SampleController {
@GetMapping("/sample")
public String resolver(
SampleModel sampleModel
) {
return sampleModel.getKey();
}
}
$ curl -H 'key: value' 'localhost:8080/sample/resolver'
value
🎉🎉🎉🎉