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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20622359/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 03:10:43  来源:igfitidea点击:

Automatic conversion of JSON form parameter in Spring MVC 4.0

javajsonspringspring-mvcHymanson

提问by Jon Ekdahl

I am trying to build a Spring MVC controller which will receive a POSTed form with a parameter in JSON format, and have Spring automatically convert it to a Java object.

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

  • Request content type is application/x-www-form-urlencoded
  • The name of the parameter that contains a JSON string is data.json
  • 请求内容类型为 application/x-www-form-urlencoded
  • 包含 JSON 字符串的参数名称为 data.json

This is the controller:

这是控制器:

@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";
    }
}

And this is what the MyMessage object looks like:

这就是 MyMessage 对象的样子:

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

Perhaps not surprisingly, posting a form with parameter data.json={"id":"Hello"} results in HTTP error 500 with this exception:

也许并不奇怪,发布带有参数 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

If I read the MappingHymanson2HttpMessageConverter docscorrectly, Hymanson JSON conversion is triggered by Content-Type application/json, which I obviously cannot use since this is a form POST (and I don't control the POSTing part).

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

Is it possible to get Spring to convert the JSON string into an instance of MyMessage, or should I just give up, read it as a String and perform the conversion myself?

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

采纳答案by Sotirios Delimanolis

Spring invokes your @RequestMappingmethods with reflection. To resolve each argument it's going to pass to the invocation, it uses implementations of HandlerMethodArgumentResolver. For @RequestParamannotated parameters, it uses RequestParamMethodArgumentResolver. This implementation binds a request parameter to a single object, typically a Stringor some Numbertype.

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

However, your use case is a little more rare. You rarely receive jsonas a request parameter, which is why I think you should re-think your design, but if you have no other choice, you need to register a custom PropertyEditorthat will take care of converting the request parameter's jsonvalue into your custom type.

但是,您的用例比较少见。您很少收到json请求参数,这就是为什么我认为您应该重新考虑您的设计,但是如果您别无选择,您需要注册一个自定义PropertyEditor,它将负责将请求参数的json值转换为您的自定义类型。

Registration is simple in an @InitBinderannotated method in your @Controllerclass

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

@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);
        }
    });
}

In this particular case, we don't need all the methods of the PropertyEditorinterface, so we can use PropertyEditorSupportwhich is a helpful default implementation of PropertyEditor. We simply implement the two methods we care about using whichever flavor of JSON parser we want. I used Gsonbecause it was available.

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

When Spring sees that it has a request parameter that you requested, it will check the parameter type, find the type MyMessageand look for a registered PropertyEditorfor that type. It will find it because we registered it and it it will then use it to convert the value.

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

You might need to implement other methods of PropertyEditordepending on what you do next.

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

My recommendation is to never send JSON as a request parameter. Set your request content type to application/jsonand send the jsonas the body of the request. Then use @RequestBodyto parse it.

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

回答by feht

You can also use @RequestPartlike this:

你也可以@RequestPart这样使用:

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