Parámetro JSON en el controlador MVC de spring

yo tengo

@RequestMapping(method = RequestMethod.GET) @ResponseBody SessionInfo register(UserProfile profileJson){ ... } 

Paso el perfilJson de esta manera:

 http://server/url?profileJson={"email": "mymail@gmail.com"} 

pero mi objeto profileJson tiene todos los campos nulos. ¿Qué debo hacer para que la spring analice mi json?

Esto podría hacerse con un editor personalizado, que convierta el JSON en un objeto UserProfile:

 public class UserProfileEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { ObjectMapper mapper = new ObjectMapper(); UserProfile value = null; try { value = new UserProfile(); JsonNode root = mapper.readTree(text); value.setEmail(root.path("email").asText()); } catch (IOException e) { // handle error } setValue(value); } } 

Esto es para registrar el editor en la clase de controlador:

 @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(UserProfile.class, new UserProfileEditor()); } 

Y esta es la forma de usar el editor, para deshacer el parámetro JSONP:

 @RequestMapping(value = "/jsonp", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE}) @ResponseBody SessionInfo register(@RequestParam("profileJson") UserProfile profileJson){ ... } 

La solución a esto es tan fácil y simple que prácticamente te hará reír, pero antes de siquiera llegar a ella, permítanme enfatizar que ningún desarrollador de Java respetuoso lo hará nunca, y me refiero a que NUNCA trabaje con JSON sin utilizar el alto de Jackson. de rendimiento JSON biblioteca.

Jackson no es solo una fuente de trabajo y una biblioteca de JSON de facto para desarrolladores de Java, sino que también proporciona un conjunto completo de llamadas API que hace que la integración de JSON con Java sea pan comido (puede descargar Jackson en http: //jackson.codehaus. org / ).

Ahora la respuesta. Suponiendo que tienes un pojo UserProfile que se parece a esto:

 public class UserProfile { private String email; // etc... public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } // more getters and setters... } 

… entonces su método Spring MVC para convertir un nombre de parámetro GET “profileJson” con el valor JSON de {“email”: “mymail@gmail.com”} se vería así en su controlador:

 import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; // this is your lifesaver right here //.. your controller class, blah blah blah @RequestMapping(value="/register", method = RequestMethod.GET) public SessionInfo register(@RequestParam("profileJson") String profileJson) throws JsonMappingException, JsonParseException, IOException { // now simply convert your JSON string into your UserProfile POJO // using Jackson's ObjectMapper.readValue() method, whose first // parameter your JSON parameter as String, and the second // parameter is the POJO class. UserProfile profile = new ObjectMapper().readValue(profileJson, UserProfile.class); System.out.println(profile.getEmail()); // rest of your code goes here. } 

Bam! Ya terminaste Le animo a que revise la mayor parte de la API de Jackson porque, como dije, es un salvavidas. Por ejemplo, ¿estás devolviendo JSON desde tu controlador? Si es así, todo lo que necesita hacer es incluir JSON en su lib y devolver su POJO y Jackson lo convertirá automáticamente en JSON. No puedes ser mucho más fácil que eso. ¡Aclamaciones! 🙂

Esto resuelve mi problema inmediato, pero todavía tengo curiosidad sobre cómo se puede pasar en múltiples objetos JSON a través de una llamada AJAX.

La mejor manera de hacerlo es tener un objeto contenedor que contenga los dos (o múltiples) objetos que desea pasar. A continuación, construye su objeto JSON como una matriz de los dos objetos, es decir,

 [ { "name" : "object1", "prop1" : "foo", "prop2" : "bar" }, { "name" : "object2", "prop1" : "hello", "prop2" : "world" } ] 

Luego, en su método de controlador, recibe el cuerpo de la solicitud como un solo objeto y extrae los dos objetos contenidos. es decir:

 @RequestMapping(value="/handlePost", method = RequestMethod.POST, consumes = { "application/json" }) public void doPost(@RequestBody WrapperObject wrapperObj) { Object obj1 = wrapperObj.getObj1; Object obj2 = wrapperObj.getObj2; //Do what you want with the objects... } 

El objeto envoltorio sería algo así como …

 public class WrapperObject { private Object obj1; private Object obj2; public Object getObj1() { return obj1; } public void setObj1(Object obj1) { this.obj1 = obj1; } public Object getObj2() { return obj2; } public void setObj2(Object obj2) { this.obj2 = obj2; } } 

Puede crear su propio Converter y dejar que Spring lo use automáticamente cuando corresponda:

 import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @Component class JsonToUserProfileConverter implements Converter { private final ObjectMapper jsonMapper = new ObjectMapper(); public UserProfile convert(String source) { return jsonMapper.readValue(source, UserProfile.class); } } 

Como puede ver en el siguiente método de control, no se necesita nada especial:

 @GetMapping @ResponseBody public SessionInfo register(@RequestParam UserProfile userProfile) { ... } 

Spring recupera el convertidor automáticamente si utiliza el componente de escaneo y anota la clase de convertidor con @Component .

Obtenga más información sobre Spring Converter y las conversiones de tipo en Spring MVC .

Solo agrega la anotación @RequestBody antes de este param