Spring MVC Vistas JSON

Para generar vistas en formato JSON (JavaScript Object Notation) el Framework Spring MVC soporta el uso de la librería externa Jackson 2, para utilizarla solo debemos agregarlas al classpath, usando la configuración con la anotación @EnableWebMvc se configurarán todos los componentes necesarios.

Agregamos la librería Jackson a las dependencias del POM.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.8</version>
</dependency>

Para nuestro ejemplo utilizaremos las siguientes clases:

package carmelo.spring.model;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Customer {
    private Long id;
    private String firstName;
    private String lastName;
    private String street;
    private String city;
}

Los objetos de esta clase serán convertidos a formato JSON, los correspondientes métodos: getter, setter, el constructor, son generados usando lombok.

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {
    "carmelo.spring.controller",
    "carmelo.spring.service"})
public class WebAppConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/views/", ".jsp");
    }
}

Esta configuración registra un ViewResolver para las vistas JSP, este nos es necesario para manejar datos JSON, solo lo tenemos para manejar ambos tipos de vistas.

Para que nuestro controlador genere la salida en formato JSON se deben cumplir estas condiciones, primero que la biblioteca Jackson este en el classpath, segundo que la configuración utilice la anotación @EnableWebMvc o su equivalente XML <mvc:annotation-driven /> y que el método correspondiente este anotado con @ResponseBody.

@Controller
public class CustomerController {

    @Autowired
    private CustomerService cs;

    @RequestMapping(value = {"/", "/index"})
    public String customerJsp(Model model) {
        model.addAttribute("customerList", cs.findAll());
        return "customer";
    }

    @ResponseBody
    @RequestMapping("/data")
    public List<Customer> customerJson() {
        return cs.findAll();
    }
}

El primer método maneja la vista JSP de los datos, una lista de objetos Customer, el resultado de esta vista es el siguiente:

Spring MVC Vistas JSP

Si accedemos a la URL localhost:8084/customer/data veremos los datos en formato JSON.

Spring MVC Generar vistas en formato JSON

Podemos hacerlo de otra forma, sin utilizar la anotación @ResponseBody, de esta forma se hacia en versiones anteriores de Spring MVC,  esta forma es muy similar a como lo hacemos con las vistas JSP, ejemplo, agregamos el siguiente método a nuestro controlador:

@RequestMapping(name = "/list")
public String customerJsonList(Model model) {
    model.addAttribute(cs.findAll());
    return "jsonView";
}

El texto de retorno de este método es el nombre de la vista, por ello debemos crear un bean de tipo View, lo haremos con la clase MappingJackson2JsonView encargada de hacer el mapeo de un objeto a formato JSON, también debemos agregar un BeanNameViewResolver este usará el bean cuyo nombre concuerde con la vista.

Nuestra configuración ahora queda del siguiente modo:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {
    "carmelo.spring.controller",
    "carmelo.spring.service"})
public class WebAppConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/views/", ".jsp");
    }

    @Bean
    public ViewResolver viewResolver() {
      BeanNameViewResolver resolver = new BeanNameViewResolver();
      resolver.setOrder(1);
      return resolver;
    }

    @Bean
    public View jsonView() {
        MappingJackson2JsonView view = new MappingJackson2JsonView();
        view.setPrettyPrint(true);
        return view;
    }
}

Habilitamos el PrittyPrint para obtener una salida más legible.

Usando la vista MappingJackson2JsonView en Spring MVC

Si deseamos personalizar la salida JSON, por ejemplo, deseamos excluir alguna propiedad, como el ID para nuestro caso, podemos usar la anotación @JsonIgnore sobre el campo que deseemos ignorar o excluir de la salida.

@Data
@AllArgsConstructor
public class Customer {
    
    @JsonIgnore private Long id;

    private String firstName;
    private String lastName;   
    private String street;
    private String city;
}

Otra posibilidad es utilizar @JsonView para definir cuales de las propiedades del objeto JavaBean aparecerán en la salida JSON, para usar esta anotación debemos crear una interface que representa la vista, podemos tener uno o más de ellas, ejemplo:

@Data
@AllArgsConstructor
public class Customer {
    
    public interface FullNameView { };
    public interface FullNameAndDirectionView extends FullNameView { };
    
    private Long id;
    
    @JsonView(FullNameView.class)
    private String firstName;
    
    @JsonView(FullNameView.class)
    private String lastName;
    
    @JsonView(FullNameAndDirectionView.class)
    private String street;
    
    private String city;
}

Definimos dos vistas FullNameView y FullNameAndDirectionView que extiende la primera, usando la anotación @JsonView(view.class) indicamos cuales son las propiedades que pertenecen a una vista, la segunda vista extiende la primera, esto quiere decir que incluirán en ella los elementos que pertenezcan a la primera vista.

@RequestMapping(name = "/list")
public String customerJsonList(Model model) {
    model.addAttribute(cs.findAll());
    model.addAttribute(JsonView.class.getName(), Customer.FullNameAndDirectionView.class);
    return "jsonView";
}

Para usar una vista debemos agregar el atributo al modelo, el nombre será el de la anotación JsonView y su valor debe ser el class de la vista que deseamos utilizar.

Usando la anotación @JsonView en Spring MVC

Debemos mencionar que una propiedad puede pertenecer a más de una vista, la anotación @JsonView nos permite establecer más de una vista, por ejemplo:

@JsonView(value = {FullNameView.class, TestView.class})
private String firstName;

De este modo el campo pertenece dos vistas.

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

tkinter Canvas

Controles y Contenedores JavaFX 8 - I

Conectar SQL Server con Java