Feign的Get请求支持对象,解决数组不能查询的问题

随着Spring全家桶的流行.越来越多的小伙伴使用了Feign去做RPC的调用,最近我在编写feign的客户端给别的小伙伴调用的时候发现一个非常坑的地方,那就是Feign里面Get请求不支持一个对象属性,只能是一个属性字段一个属性字段的写,如下

@GetMapping
HttpMessageResult<CouponVO> getOne(@RequestParam("userId") Long userId, @RequestParam("couponId") Long couponId);

当查询请求的参数比较少的时候还能写,如果参数很多,那不是凉了 ,如果要能支持对象查询,如下,该多好

@GetMapping
HttpMessageResult<CouponVO> getOne(@RequestParam CouponQO qo);

后来仔细查看了下源码,其实不是不支持,只是换了一种情形而已.

经改造,feign接口如下,里面的对象换成一个Map.

@GetMapping
HttpMessageResult<List<CouponVO>> queryList(@RequestParam Map<String, Object> queries);

很多小伙可能说,Map很不方便.不可能要消费方去往Map里面赋值,而且就算消费方同意,由于消费方不了解我们的业务逻辑,很可能导致往Map里面赋值的时候key写错了,这种情况确实要避免.所以, 这里面我还是可以封装一个对象.然后把对象转化成Map,这样消费方还是构建我们的查询对象,比如

 
@Getter
@Setter
@ToString(callSuper = true)
public class CouponQO implements IQuery {

/**
* 主键id
*/
private Long couponId;

/**
* 用户id
*/
private Long userId;

@Override
public Map<String, Object> toQueryMap() {
Map<String, Object> query = Maps.newHashMap();
if (userId != null) {
query.put("userId", userId);
}
if (couponInfoId != null) {
query.put("couponId", couponInfoId);
}
return query;
}
}

如果这样写的话,对于消费方就很方便了,他们只需要构建查询的请求对象,构建好了之后在用这个查询请求对象的toQueryMap方法,即可返回整个对象的Map,

其中IQuery的接口只定义了一个接口

public interface IQuery {

Map<String, Object> toQueryMap();
}

是不是非常的方便呢

随着业务的查询条件逐渐增加,我们会往查询的对象QO里面塞越来越多的值,笔者在添加查询属性的时候,有一个字段是数组对象,如下

protected CouponInfoTermQO[] terms;

这个对象在转化成map的时候,一开始的写法是,发现消费方请求的时候直接报500的错误,

 if (terms != null) {
query.put("terms", terms);
}

整理之后发现是这种写法有问题.

经过改造写成如下写法,轻松解决feign的Get里面数组不支持的小问题,具体原因,大家可以看下HTTP请求的参数格式解析的相关原理

if (terms != null) {
for (int i = 0; i < terms.length; i++) {
CouponInfoTermQO term = terms[i];
if (term == null) {
continue;
}
query.put("terms[" + i + "].typeId", term.getTypeId());
query.put("terms[" + i + "].unionId", term.getUnionId());
}
}