在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)