requestbody mvc mapperfeature jsonview example default_view_inclusion spring-mvc json-view

spring-mvc - mapperfeature - spring mvc jackson example



Selección dinámica de JsonView en Spring MVC Controller (2)

Soy consciente de que es posible anotar los métodos del controlador con @JsonView(...) para definir estáticamente una clase de vista única en Spring MVC. Desafortunadamente, esto significa que necesito un punto final diferente para cada tipo de vista que pueda tener.

Veo que otras personas han preguntado esto before . Si bien este enfoque puede funcionar, Spring a menudo tiene muchas formas de hacer lo mismo. A veces, la solución puede ser mucho más simple de lo que parece al principio si solo tiene un poco de conocimiento acerca de algunos de los aspectos internos.

Me gustaría tener un único punto final de controlador que pueda seleccionar dinámicamente la vista apropiada según el principal actual. ¿Es posible que devuelva un Model con un atributo que contenga la clase de vista apropiada o tal vez una instancia de MappingJacksonValue directamente?

Veo en org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal hay un fragmento de código que determina qué vista usar:

if (value instanceof MappingJacksonValue) { MappingJacksonValue container = (MappingJacksonValue) object; value = container.getValue(); serializationView = container.getSerializationView(); }

Lo que parece provenir de org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice#beforeBodyWriteInternal pero tengo problemas para resolver si hay una manera de evitarlo simplemente devolviendo un valor particular que contenga lo necesario información para el Jackson2HttpMessageConverter para elegir la vista correcta.

Cualquier ayuda muy apreciada.


Aquí hay una variación de la respuesta anterior que me ayudó. Encontré problemas al devolver MappingJacksonValue directamente al usar las cargas útiles Spring HATEOAS. Si lo devuelvo directamente desde el controlador del controlador, por alguna razón, los mixins Resources y ResourceSupport no se aplican correctamente y los enlaces JSON HAL se representan como enlaces. Además, Spring ResponseEntity no se procesa, ya que debería mostrar los objetos de body y status en la carga útil.

Usar ControllerAdvice para lograr lo mismo ayudó a eso y ahora mis cargas útiles se representan correctamente y las vistas se aplican según sea necesario

@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); } } }


En caso de que alguien más quiera lograr lo mismo, en realidad es muy simple.

Puede devolver directamente una instancia org.springframework.http.converter.json.MappingJacksonValue desde su controlador que contiene tanto el objeto que desea serializar como la clase de vista.

Esto será recogido por el método org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal y se org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal la vista correspondiente.

Funciona algo como esto:

@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; }