在Spring MVC 4.0中自动转换JSON表单参数

我正在尝试构建一个Spring MVC控制器,它将接收带有JSON格式参数的POSTed表单,并让Spring自动将其转换为Java对象。

  • 请求内容类型是application/x-www-form-urlencoded
  • 包含JSON字符串的参数的名称是data.json

这是控制器:

 @Controller public class MyController { @RequestMapping(value = "/formHandler", method = RequestMethod.POST) public @ResponseBody String handleSubscription( @RequestParam("data.json") MyMessage msg) { logger.debug("id: " + msg.getId()); return "OK"; } } 

这就是MyMessage对象的样子:

 public class MyMessage { private String id; // Getter/setter omitted for brevity } 

也许并不奇怪,发布带有参数data.json = {“id”:“Hello”}的表单会导致HTTP错误500,并出现此exception:

 org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'MyMessage' nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [MyMessage]: no matching editors or conversion strategy found 

如果我正确读取MappingJackson2HttpMessageConverter文档 ,那么Jackson JSON转换是由Content-Type application/json触发的,我显然不能使用它,因为这是一个表单POST(我不控制POSTing部分)。

是否有可能让Spring将JSON字符串转换为MyMessage的实例,或者我应该放弃,将其作为String读取并自己执行转换?

Spring使用reflection调用您的@RequestMapping方法。 要解析它将传递给调用的每个参数,它使用HandlerMethodArgumentResolver实现。 对于@RequestParam注释的参数,它使用RequestParamMethodArgumentResolver 。 此实现将请求参数绑定到单个对象,通常是String或某种Number类型。

但是,您的用例更为罕见。 您很少收到json作为请求参数, 这就是为什么我认为您应该重新考虑您的设计 ,但如果您没有其他选择,则需要注册一个自定义PropertyEditor ,它将把请求参数的json值转换为您的自定义类型。

@Controller类的@InitBinder注释方法中注册很简单

 @InitBinder public void initBinder(WebDataBinder dataBinder) { dataBinder.registerCustomEditor(MyMessage.class, new PropertyEditorSupport() { Object value; @Override public Object getValue() { return value; } @Override public void setAsText(String text) throws IllegalArgumentException { value = new Gson().fromJson((String) text, MyMessage.class); } }); } 

在这种特殊情况下,我们不需要PropertyEditor接口的所有方法,因此我们可以使用PropertyEditorSupport ,它是PropertyEditorSupport的一个有用的默认实现。 我们只是实现了我们关心的两种方法,即使用我们想要的任何JSON解析器。 我使用Gson因为它可用。

当Spring看到它有你请求的请求参数时,它将检查参数类型,找到类型MyMessage并查找该类型的已注册PropertyEditor 。 它会找到它,因为我们注册了它然后它将使用它来转换值。

您可能需要实现PropertyEditor其他方法,具体取决于您接下来要做什么。

我的建议是永远不要将JSON作为请求参数发送。 将您的请求内容类型设置为application/json ,并将json作为请求的主体发送。 然后使用@RequestBody来解析它。

您也可以像这样使用@RequestPart

 @RequestMapping(value = "/issues", method = RequestMethod.POST, headers = "Content-Type=multipart/form-data") public String uploadIssue(@RequestParam("image") MultipartFile file, @RequestPart("issue") MyMessage issue)