现在在Spring-Boot提供了Map<String,?> map的格式来提交form表单参数,但是Map<String,?> map不能体现request的含义,而且还多了object转换map的流程,期望能够在FeignClient中直接提交object为form表单参数
现在FeignClient支持的form表单参数提交的格式
@FeignClient(name = "jddefray", url = "${jd.defrayPay.url}")
public interface JdDefrayPayClient {
@PostMapping(value = "/npp10/defray_pay" ,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
String defrayPay(Map<String,?> entityBody);
}
在@FeignClient中是使用FormEncoder进行提交的, 观察FormEncoder#encode中的源码实现,可以看到Map<String,?>对应的Type是Type MAP_STRING_WILDCARD = Util.MAP_STRING_WILDCARD;, 那么对于自定义的PoJo那么是不是只要在自定义的Encoder中将其转换成Map, 然后委托给FormEncoder就可以实现想要的效果了.
@Override@SuppressWarnings("unchecked")
public void encode (Object object, Type bodyType, RequestTemplate template)
throws EncodeException {
String contentTypeValue = getContentTypeValue(template.headers());
val contentType = ContentType.of(contentTypeValue);
if (!processors.containsKey(contentType)) {
delegate.encode(object, bodyType, template);
return;
}
Map<String, Object> data;
if (MAP_STRING_WILDCARD.equals(bodyType)) {
data = (Map<String, Object>) object;
} else if (isUserPojo(bodyType)) {
data = toMap(object);
} else {
delegate.encode(object, bodyType, template);
return;
}
val charset = getCharset(contentTypeValue);
processors.get(contentType).process(template, charset, data);
}
下面是自定义的ObjectFormEncoder,将object转换为Map<String,?>交给FormEncoder以form表单格式提交
/** * 这里将object转换为@Feignclient中支持的 Map<String,?> 提交的表单格式 */
@Slf4j
class ObjectFormEncoder implements Encoder {
private final Encoder delegate;
public ObjectFormEncoder(Encoder delegate) {
this.delegate = delegate;
}
@Override
public void encode(Object object, Type bodyType, RequestTemplate template)
throws EncodeException {
// object -> Map<String,?> map
Map<String, ?> map = new ObjectMapper().convertValue(object, new TypeReference<Map<String, ?>>() { });
log.info("request:{}" ,map );
delegate.encode(map, MAP_STRING_WILDCARD, template);
return;
}
}
然后在@FeignClient中换上自定义的feignEncoder即可
class JdAgreeConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Encoder feignEncoder() {
return new ObjectFormEncoder(new FormEncoder(new SpringEncoder(messageConverters)));
}
}
经过测试,这样是可以实现以form表单格式提交object(自定义PoJo)的。
Question: 在观察FormEncoder#encode中的源码的时候,发现有判断isUserPojo(bodyType),然后转换为map的动作, 按说是应该是实现了上面所说的功能, 是需要哪里配置什么么?