在 Java 中将 POJO 转换为表单数据

Posted

技术标签:

【中文标题】在 Java 中将 POJO 转换为表单数据【英文标题】:Converting a POJO to Form Data in Java 【发布时间】:2018-09-27 07:17:51 【问题描述】:

我有一个 POJO 的形式:

@Data
public class BaseRequest 
    private String type;
    private Map<String, Object> details;
    private Map<String, Object> signature;

我有一个服务正在运行,它只接受内容类型:“application/x-www-form-urlencoded”。

我用 Java 编写了一个客户端,它使用 Spring 的 RestTemplate 进行调用。

public String getInvoice(BaseRequest req, String url) 
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

    HttpEntity<BaseRequest> httpEntity = new HttpEntity<BaseRequest>(req, headers);
    String response = this.restTemplate.postForObject(url, httpEntity, String.class);
    return response;

但是,它会引发错误:

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [com.x.y.z.BaseRequest] and content type [application/x-www-form-urlencoded]

如果我将内容类型设置为 JSON,它会起作用:

headers.setContentType(MediaType.APPLICATION_JSON);

我知道它适用于 JSON,因为我已经使用 JacksonHTTPMessageConverter 配置了我的 RestTemplate Bean。所以我可以轻松地将 POJO 转换为 application/json。但是,我无法弄清楚如何使用 application/x-www-form-urlencoded 来做到这一点。

我已经搜索了一段时间了,我找到的唯一解决方案是编写自己的转换器,将我的 BaseRequest 类转换为 Spring 的 MultiValueMap,然后 Spring 的 FormHttpMessageConverter 会自动处理它。但我想避免这样做。有没有其他办法解决这个问题?

任何线索将不胜感激。谢谢!

编辑: 我的问题与@JsonProperty not working for Content-Type : application/x-www-form-urlencoded 不同。那里发生的转换是关于接受 application/x-www-form-urlencoded 中的数据并将其转换为 POJO。我的问题是关于在使用 Spring 的 resttemplate 进行调用时将 POJO 转换为 application/x-www-form-urlencoded。就像我提到的那样,我知道我可以通过编写自己的转换器将我的 POJO 转换为 Spring 的 MultiValueMap 来实现这一点。但是,我想知道我是否可以避免这样做。

编辑:

Dump of $_POST on the API when I send my data as MultiValueMap<String, Object>:

"array(0) 
"

Dump of $_POST on the API when I send my data through Postman in the correct format:

"array(2) 
  ["type"]=>
  string(16) "abcd"
  ["details"]=>
  array(1) 
  ["template_file"]=>
  string(16) "x.html"
  
"

【问题讨论】:

所以你已经用“produces(application/x-www-form-urlencoded)”注释了你的控制器方法? @dainu 控制器方法的代码在不同的服务上,我无法在那里进行更改。该服务是用 php 编写的。我只是从我的服务(用 Java 编写)对该服务进行 API 调用。 【参考方案1】:

尝试将请求负载中的嵌套对象转换为org.springframework.util.MultiValueMap。在你的 POJO 中添加和实现转换器方法

public class BaseRequest 
    // ...

    public MultiValueMap<String, Object> toMap() 
        MultiValueMap<String, Object> result = new LinkedMultiValueMap<>();
        result.add("type", type);
        result.put("details", details);
        result.put("signature", signature);
        return result;
    

现在在创建请求时使用它

HttpEntity<BaseRequest> httpEntity = new HttpEntity<BaseRequest>(req.toMap(), headers);

这是因为 FormHttpMessageConverter 内部执行实际转换方法 canRead(Class&lt;?&gt;, MediaType) 检查 MultiValueMap.class.isAssignableFrom(clazz) 是否是您的有效负载对象。在你的情况下它失败了,所以 FormHttpMessageConverter 跳过了。

希望对你有帮助!

【讨论】:

您好,感谢您的回复。就像我在问题中提到的那样,我想避免编写自己的转换器来将我的 POJO 转换为 MultiValueMap。我这样说是因为在 MultiValueMap 中,如果我插入详细信息(属于 Map 类型),它不会正确格式化到服务器,因此服务器无法解析它.我将 $_REQUEST 的输出添加到在 EDIT 中进行此调用的服务器上。 您可以将MultiValueMap&lt;String, Object&gt;的签名更改为MultiValueMap&lt;String, String&gt;并根据您的需要手动格式化您的对象。 是的,但我想避免这样做,因为编写该转换器会很丑陋。难道没有像杰克逊这样的图书馆可以为我处理这种转换吗?还是我面临的问题太少见了? @Qawls,Spring 已经为您完成了,它从对象中获取您的请求并执行所有转换/处理/处理回调。如果您的服务器无法以其他方式处理数据,则编写数据的特定表示并不难看。 @Qawls,如果你想要好的漂亮的解决方法,你需要修复你的 PHP 代码,这是不可能的,所以我建议你坚持工作解决方案而不是追逐“最佳”。

以上是关于在 Java 中将 POJO 转换为表单数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Java Stream 中将 POJO 的列表转换为 Map<String,List>?

struts2+ 将表单值设置为 POJO 并将 POJO 值设置为表单

在javascript中将表单数据保存为xml时防止跨站点(XSS)

在Jquery中将表单转换为关联数组[重复]

如何在 Xamarin 表单中将边距、填充、宽度和高度值转换为像素(px)?

如何在 Javascript 中将表单数组转换为 JSON? (对象数组)?