35

@JsonView(...)Spring MVC で単一のビュー クラスを静的に定義するために、コントローラー メソッドにアノテーションを付けることが可能であることを認識しています。残念ながら、これは、可能性のあるビューの種類ごとに異なるエンドポイントが必要であることを意味します。

私は他の人が以前にこれを尋ねたのを見ます。このアプローチはうまくいくかもしれませんが、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

どんな助けでも大歓迎です。

4

2 に答える 2

46

偶然にも、誰かが同じことを達成したいと思ったとしても、実際には非常に簡単です。

org.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;
}
于 2015-03-17T15:41:01.860 に答える
17

これは私を助けた上記の答えのバリエーションです。MappingJacksonValueSpring HATEOAS ペイロードの使用中に直接返される問題を発見しました。コントローラーのハンドラーから直接返すと、何らかの理由でResourcesResourceSupportmixin が正しく適用されず、JSON HAL _links がリンクとしてレンダリングされます。また、SpringResponseEntityはレンダリングされず、ペイロード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);
    }
  }
}
于 2016-10-31T17:42:07.550 に答える