You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中将POJO转换为application/x-www-form-urlencoded表单数据

把BaseRequest转成form-urlencoded格式调用服务的解决方案

刚好碰到过类似的场景,给你两种实用的实现方式,都是适配Spring RestTemplate的:

方式一:手动构建表单键值对

这种方式最直观,完全可控,适合对参数格式有明确要求的场景:

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

    // 用LinkedMultiValueMap来存表单数据,它是Spring专门用于form请求的容器
    MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();

    // 添加type字段
    if (req.getType() != null) {
        formData.add("type", req.getType());
    }

    // 遍历details里的所有键值对,转成表单参数
    if (req.getDetails() != null) {
        req.getDetails().forEach((key, value) -> {
            // 这里用details[key]的命名是为了让服务端能识别属于details的参数,可按需调整
            formData.add("details[" + key + "]", value != null ? value.toString() : "");
        });
    }

    // 同样处理signature字段
    if (req.getSignature() != null) {
        req.getSignature().forEach((key, value) -> {
            formData.add("signature[" + key + "]", value != null ? value.toString() : "");
        });
    }

    // 组装请求实体
    HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);

    // 调用服务并返回结果
    return restTemplate.postForObject(url, requestEntity, String.class);
}

方式二:借助Spring工具类自动转换

如果不想手动逐个处理字段,可以用Spring的BeanUtils来自动遍历并扁平化对象,代码更简洁:

import org.springframework.beans.BeanUtils;
import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.PropertyAccessorFactory;

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

    MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
    PropertyAccessor accessor = PropertyAccessorFactory.forBeanPropertyAccess(req);

    // 遍历BaseRequest的所有字段
    BeanUtils.getPropertyDescriptors(BaseRequest.class).forEach(descriptor -> {
        String propertyName = descriptor.getName();
        // 跳过class字段
        if (!"class".equals(propertyName)) {
            try {
                Object value = accessor.getPropertyValue(propertyName);
                if (value != null) {
                    if (value instanceof Map) {
                        // 处理Map类型字段,拆成单个键值对
                        ((Map<?, ?>) value).forEach((k, v) -> {
                            formData.add(propertyName + "[" + k + "]", v != null ? v.toString() : "");
                        });
                    } else {
                        // 普通字段直接添加
                        formData.add(propertyName, value.toString());
                    }
                }
            } catch (Exception e) {
                // 这里可以根据业务做异常处理,比如打日志或者抛出自定义异常
                e.printStackTrace();
            }
        }
    });

    HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
    return restTemplate.postForObject(url, requestEntity, String.class);
}

几个要注意的点

  • 所有Object类型的值都要转成String,如果有复杂自定义对象,得提前序列化(比如转成JSON字符串)再存到表单里。
  • 参数命名格式(比如details[key])可以根据服务端的接收要求调整,比如服务端直接要键名的话,就把details[" + key + "]改成key就行。
  • 如果项目里有很多这类场景,也可以自定义一个HttpMessageConverter来自动处理POJO到form数据的转换,但上面两种方式更轻量,适合快速落地。

内容的提问来源于stack exchange,提问作者Qawls

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:18:15