Stay hungry, Stay foolish

0%

使用Feign实现Form表单数据提交

有个合作方的接口要求是通过form表单(application/x-www-form-urlencoded)的形式提交

1
2
3
4
5
6
@FeignClient(name = "partner", url = "${partner.url}")
public interface PartnerClient {

@RequestMapping(value="/comment/submit", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED)
Map<String,Object> submitComment(@RequestBody CommentSubmitParam param);
}

本以为只要加个相应的ContentType就能解决,没想到还是too young too simple

1
feign.codec.EncodeException: Could not write request: no suitable HttpMessageConverter found for request type [com.demon.com.partner.entity.param.CommentSubmitParam] and content type [application/x-www-form-urlencoded]

查了下资料,需要添加FormEncoder

1
2
3
4
5
6
7
8
9
10
11
12
public class FeignEncoderConfig {

@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;

@Bean
@Primary
@Scope(SCOPE_PROTOTYPE)
Encoder feignFormEncoder() {
return new FormEncoder(new SpringEncoder(this.messageConverters));
}
}

如果全局使用加个@Configurable的注解即可;而我的需求是只针对部分Client,所以还要在FeignClient上指定配置:

1
@FeignClient(name = "partner", url = "${partner.url}", configuration = FeignEncoderConfig.class)

发起请求的时候又碰到了参数缺失的问题:

只好进到FormEncoder里跟一下,在FormEncode的encode里使用的是PojoUtil的toMap方法

1
data = PojoUtil.toMap(object);

toMap的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
val type = object.getClass();
for (val field : type.getDeclaredFields()) {
val fieldValue = field.get(object);
if (fieldValue == null) {
continue;
}

val propertyKey = field.isAnnotationPresent(FormProperty.class)
? field.getAnnotation(FormProperty.class).value()
: field.getName();

result.put(propertyKey, fieldValue);
}

可以看到PojoUtil使用的获取对象属性用的是object.getClass().getDeclaredFields()————这个方法只会获取当前类里定义的属性,而不会获取父类里的属性!

而请求里丢失的参数正好都是父类的!

看来,要么自己写一个FormEncoder,要么就只使用非继承的POJO,而我选择后者!^_^

据说打赏我的人,代码没有BUG