Spring MVCで単一のビュークラスを静的に定義するために@JsonView(...)
でコントローラーメソッドに注釈を付けることが可能であることを知っています。残念ながら、これは私が持つ可能性のあるすべてのタイプのビューに対して異なるエンドポイントが必要であることを意味します。
他の人がこれを尋ねたのを見る before 。このアプローチは機能する可能性がありますが、Springには多くの場合、同じことを行う多くの方法があります。いくつかの内部について少し知識がある場合、ソリューションは最初に表示されるよりもはるかに単純になることがあります。
現在のプリンシパルに基づいて適切なビューを動的に選択できる単一のコントローラーエンドポイントが欲しいのですが。適切なビュークラスまたはModel
インスタンスを直接含む属性を持つMappingJacksonValue
を直接返すことは可能ですか?
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal
には、使用するビューを決定するコードスニペットがあります。
if (value instanceof MappingJacksonValue) {
MappingJacksonValue container = (MappingJacksonValue) object;
value = container.getValue();
serializationView = container.getSerializationView();
}
これはorg.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice#beforeBodyWriteInternal
からのようですが、Jackson2HttpMessageConverter
が適切な情報を取得するために必要な情報を含む特定の値を返すだけでこれを回避できる方法がある場合、問題が発生します見る。
どんな助けも大歓迎です。
他の誰かが同じことを達成したいと思った場合、それは実際には非常に簡単です。
シリアル化するオブジェクトとビュークラスの両方を含むコントローラーからaorg.springframework.http.converter.json.MappingJacksonValue
インスタンスを直接返すことができます。
これはorg.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal
メソッドによって取得され、適切なビューが使用されます。
これは次のように機能します。
@RequestMapping(value = "/accounts/{id}", method = GET, produces = APPLICATION_JSON_VALUE)
public MappingJacksonValue getAccount(@PathVariable("id") String accountId, @AuthenticationPrincipal User user) {
final Account account = accountService.get(accountId);
final MappingJacksonValue result = new MappingJacksonValue(account);
final Class<? extends View> view = accountPermissionsService.getViewForUser(user);
result.setSerializationView(view);
return result;
}
ここに私を助けた上記の答えのバリエーションがあります。 Spring HATEOASペイロードの使用中にMappingJacksonValue
を直接返す問題を発見しました。コントローラーのハンドラーから直接返すと、何らかの理由でResources
とResourceSupport
のミックスインが正しく適用されず、JSON HAL _linksがリンクとしてレンダリングされます。また、Spring ResponseEntity
は、ペイロードにbody
およびstatus
オブジェクトを表示する必要があるため、レンダリングされません。
ControllerAdvice
を使用して同じことを実現すると、ペイロードが正しくレンダリングされ、必要に応じてビューが適用されます
@ControllerAdvice(assignableTypes = MyController.class)
public class MyControllerAdvice extends AbstractMappingJacksonResponseBodyAdvice {
@Override
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType, MethodParameter returnType,
ServerHttpRequest req, ServerHttpResponse res) {
ServletServerHttpRequest request = (ServletServerHttpRequest)req;
String view = request.getServletRequest().getParameter("view");
if ("hello".equals(view)) {
bodyContainer.setSerializationView(HelloView.class);
}
}
}