Динамический выбор 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 во время выполнения