Динамический выбор JsonView в Spring MVC-контроллере

Я знаю, что можно комментировать методы контроллера с помощью @JsonView(...), чтобы статически определить один класс представления в Spring MVC. К сожалению, это означает, что мне нужен другой конечный пункт для каждого типа просмотра, которое я мог бы иметь.

Я вижу, что другие люди задавали этот до. Хотя этот подход может работать, Spring часто имеет много способов сделать то же самое. Иногда решение может быть намного проще, чем вначале, если у вас есть немного знаний о некоторых внутренних компонентах.

Я хотел бы иметь единственную конечную точку контроллера, которая может динамически выбирать соответствующее представление на основе текущего принципала. Возможно ли мне вернуть a 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, чтобы выбрать правильный вид,

Любая помощь очень ценится.

Ответ 1

В ситуации, когда кто-то хочет достичь того же, на самом деле это очень просто.

Вы можете напрямую вернуть экземпляр 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;
}

Ответ 2

Вот вариант ответа, который мне помог. Я обнаружил, что проблемы возвращают MappingJacksonValue непосредственно при использовании полезных данных Spring HATEOAS. Если я верну его непосредственно из обработчика контроллера, по какой-то причине mixings Resources и ResourceSupport не будут корректно применяться, а ссылки JSON HAL будут отображаться как ссылки. Также 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);
    }
  }
}

Ответ 3

Пожалуйста, проверьте https://github.com/monitorjbl/json-view/, используя это, мы решили проблему динамического выбора полей JSON во время выполнения