将 Map<String,String> 传递给 springMVC 控制器

Posted

技术标签:

【中文标题】将 Map<String,String> 传递给 springMVC 控制器【英文标题】:Passing a Map<String,String> to a springMVC controller 【发布时间】:2013-08-19 06:40:22 【问题描述】:

我正在尝试将 HashMap 或任何其他 Map 实现从 ajax 发送到 Spring MVC 控制器

这里是我如何做的细节:

Ajax 调用如下

var tags = ;
tags["foo"] = "bar";
tags["whee"] = "whizzz";


$.post("doTestMap.do",   "tags" : tags , function(data, textStatus, jqXHR) 
if (textStatus == 'success') 
    //handle success
    console.log("doTest returned " + data);
 else 
    console.err("doTest returned " + data);

); 

然后在控制器端我有:

@RequestMapping(value="/publisher/doTestMap.do", method=RequestMethod.POST)
public @ResponseBody String doTestMap(@RequestParam(value = "tags", defaultValue = "") HashMap<String,String> tags, HttpServletRequest request)   //

    System.out.println(tags);

    return "cool";
 

不幸的是我系统地得到了

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

我做错了什么?

谢谢。

【问题讨论】:

看起来 spring 将“tags”参数读取为字符串,而不是映射。这意味着 spring 没有默认的消息转换器,它将字符串转换为映射。所以需要编写自定义MessageConverter并在应用中注册 认真的吗? spring 不支持映射到开箱即用的 Map 吗? tags 怎么连 jquery post 序列化?它看起来像json。也许你正在寻找@RequestBody javascript 端的tags 是什么类型?生成的地图会将什么映射到什么? 【参考方案1】:

在 Spring 控制器中绑定地图的方式与绑定数组的方式相同。无需特殊转换器!

但有一点要记住:

Spring 使用 command 对象作为***值持有者。命令对象可以是任何类。

因此,您只需要一个包装类 (TagsWrapper),其中包含一个名为标签的 Map&lt;String, String&gt; 类型的字段。 与绑定数组相同的方法。

这在文档中得到了很好的解释,但我偶尔会忘记包装对象的需要;)

您需要更改的第二件事是提交标签值的方式:

每个映射键使用一个表单参数,而不是完整映射的完整字符串表示。

一个输入值应如下所示:

  <input type="text" name="tags[key]" value="something">

如果标签是包装器中的地图,则可以开箱即用地提交表单。

【讨论】:

是的,就是这样!如果将 Map 包装在任何类的 @ModelAttribute 注释参数中,它就可以工作。这很疯狂,因为如果您只是将地图作为控制器方法的参数,它不会正确绑定并创建一个空的 BindingAwareModelMap。 + 注意关于表单参数的评论是真的。非常感谢!【参考方案2】:

这可能会延迟响应。但是,它可能会帮助某人。 我有一个类似的问题,这就是我解决它的方法。 在 JS 上: 我的地图看起来像,

var values = ;
values[element.id] = element.value;

阿贾克斯:

        $.ajax(
            type : 'POST',
            url : 'xxx.mvc',
            data : JSON.stringify(values),              
            error : function(response) 
                alert("Operation failed.");
            ,
            success : function(response) 
                alert("Success");
            ,
            contentType : "application/json",
            dataType : "json"
        );

控制器:

@RequestMapping(value = "/xxx.mvc", method=RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getValues(@RequestBody Map<String, Object> pvmValues, final HttpServletRequest request, final HttpServletResponse response) 
System.out.println(pvmValues.get("key"));

【讨论】:

在 Javascript 上,使用类似这样的东西;变量值 = ; values.elementid=元素值;而不是 values[elementid]=elementvalue; 我们使用的是spring security,上面的代码给出了403异常。所以我们必须遵循这个答案以及上述更改。***.com/questions/19091206/…【参考方案3】:

这是我根据 Martin Frey 的帮助用代码完成的答案:

javascript 方面(注意标签值是如何填充的):

var data = 
   "tags[foo]" : "foovalue", 
   "tags[whizz]" : "whizzvalue" 


$.post("doTestMap.do",   data , function(data, textStatus, jqXHR) 
    ...
); 

然后在控制器端:

@RequestMapping(value="/publisher/doTestMap.do", method=RequestMethod.POST)
public @ResponseBody String doTestMap(@ModelAttribute MyWrapper wrapper, HttpServletRequest request) 
 

并在其中创建包含 Map 的包装类:

class MyWrapper 

    Map<String,String> tags;

   +getters and setters


然后你会得到适当的填充你的地图......

【讨论】:

【参考方案4】:

最好的方法是使用 JSON 对对象进行编码并对其进行解码。

您需要两个库。在客户端,您需要json2.js。一些浏览器现在似乎原生地做到了这一点。但这样做是更安全的方式。

在你需要的服务器上jackson。

在客户端上,您对地图进行编码并将其作为参数传递:

var myEncodedObject = JSON.stringify(tags);

在服务器上,您将参数作为字符串接收并对其进行解码:

ObjectMapper myMapper = new ObjectMapper();
Map<String, Object> myMap = myMapper.readValue(tags, new TypeReference<Map<String, Object>>);

Spring 中可能有一些方法可以让它自动转换,但这就是它的要点。

【讨论】:

【参考方案5】:

您正在发送一个 JavaScript 数组 tags,默认情况下,jQuery 会将其 url 编码为一系列名为 tags[] 的参数。不确定这是否是您想要的。

你得到一个错误,因为spring没有从多个同名参数到HashMap的默认转换策略。但是,它可以轻松地将它们转换为List、数组或Set

所以试试这个:

@RequestMapping(value="/publisher/doTestMap.do", method=RequestMethod.POST)
public @ResponseBody String doTestMap(@RequestParam(value = "tags[]") Set<String> tags, HttpServletRequest request)   //

    System.out.println(tags); //this probably won't print what you want

    return "cool";
 

【讨论】:

以上是关于将 Map<String,String> 传递给 springMVC 控制器的主要内容,如果未能解决你的问题,请参考以下文章

Java 8:将 Map<String, List<String>> 转换为 Map<String, String[]> [重复]

如何将map<string list<>>转换成城map<string,object>

Java 将 Map<String,Set<String>> 转换为 Map<String,Set<Object1>> [关闭]

将Map<String,Object>格式转换成Map<String ,String[]>格式

将 Map<String, String> 转换为 POJO

如何将mapobject转换成string