Spring MVC控制器中JsonView的动态选择

Dav*_*vid 25 spring-mvc json-view

我知道可以使用@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();
        }
Run Code Online (Sandbox Code Playgroud)

这似乎来自org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice#beforeBodyWriteInternal但我无法解决,如果有一种方法可以绕过这只是简单地返回一个包含必要信息的特定值Jackson2HttpMessageConverter来选择正确的视图.

任何帮助非常感谢.

Dav*_*vid 39

关于其他人想要实现同样的事情的机会,它实际上非常简单.

您可以直接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;
}
Run Code Online (Sandbox Code Playgroud)

  • 作为旁注,我已经决定在某些情况下这样做可能是一个坏主意或指示或一些糟糕的设计。考虑到端点在某些情况下可能会生成缓存控制标头,或者如果您想记录 API 响应并且某些 JSON 属性以正在使用的视图为条件,则可能会使事情变得更加复杂,甚至可能会暴露不应该出现的细节(例如在缓存控制处理不当的情况下)。我现在的观点是,作为单独的 URI 或调用者使用 `Accept` 标头的不同内容类型,这些可能会更好。 (2认同)

Paw*_*ski 10

以上是上述答案的变体,对我有所帮助.我发现MappingJacksonValue在使用Spring HATEOAS有效负载时直接返回问题.如果我直接从控制器的处理程序返回它,由于某种原因,ResourcesResourceSupportmixin没有得到正确应用,JSON HAL _links被渲染为链接.此外春天ResponseEntity不会被渲染,因为它应该显示bodystatus有效载荷中的对象.

使用它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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)