Java SpringMVC4.0中JSON表单参数的自动转换
我正在尝试构建一个SpringMVC控制器,它将接收一个带有JSON格式参数的发布表单,并让Spring自动将其转换为Java对象Java SpringMVC4.0中JSON表单参数的自动转换,java,json,spring,spring-mvc,jackson,Java,Json,Spring,Spring Mvc,Jackson,我正在尝试构建一个SpringMVC控制器,它将接收一个带有JSON格式参数的发布表单,并让Spring自动将其转换为Java对象 请求内容类型为application/x-www-form-urlencoded 包含JSON字符串的参数名为data.JSON 这是控制器: @Controller public class MyController { @RequestMapping(value = "/formHandler", method = RequestMethod.POS
- 请求内容类型为
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,但以下情况除外:
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
如果我读对了,Jackson-JSON转换是由Content-Typeapplication/JSON
触发的,我显然不能使用它,因为这是一个表单POST(我不控制POST部分)
是否可以让Spring将JSON字符串转换为MyMessage的实例,或者我应该放弃,将其作为字符串读取并自己执行转换?Spring通过反射调用您的
@RequestMapping
方法。要解析要传递给调用的每个参数,它使用HandlerMethodArgumentResolver
的实现。对于带注释的参数@RequestParam
,它使用requestparamethodargumentresolver
。此实现将请求参数绑定到单个对象,通常是字符串
或一些数字
类型
然而,您的用例更为罕见。您很少会收到json
作为请求参数,这就是为什么我认为您应该重新考虑您的设计,但是如果您没有其他选择,您需要注册一个自定义属性编辑器
,该编辑器将负责将请求参数的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
,这是PropertyEditor
的一个有用的默认实现。我们只需使用我们想要的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)
我不控制客户端应该遵循服务器规范的发布部分,而不是相反。客户端是我无法控制的第三方webhook机制。但您的陈述让我好奇,HTTP规范中是否有禁止使用表单字段/post参数发送JSON数据的内容?不,没有,但对于REST,将其放在正文中已成为惯例。“我的建议是永远不要将JSON作为请求参数发送”。我同意,但我并没有控制发送端,我只是为第三方webhook实现了一个接收器。它是为Mandrill实现的吗?我猜他们的客户端只能接收表单参数而不能接收内容体。@NickSpacek不,这是一种接收调用的机制。您并不总是可以控制浏览器代码,例如ExtJS数据存储小部件将JSON编码的字符串作为请求参数发送以支持筛选,因此,在服务器端确实需要类似于此的解决方案。FWIW-Slack对操作回调做了类似的事情,基本上主体是:
payload=
不幸的是,@RequestPart
注释不能与内容类型应用程序/x-www-form-urlencoded
一起使用。