关于Feign在微服务间调用引用参数传递的问题

Feign默认不支持GET方式传递POJO,也不支持传递多个引用类型的参数!本文就是解决这两个问题!

 

解决思路:

在微服务A端:将要传递的引用类型参数要么以body方式传递,要么以json串方式传递,在拦截器里解析json串拆分为更为详细的参数。

在微服务B端:按照SpringMVC支持写法去写,A端传来的请求参数自动映射到B端实体属性上!

 

解决问题的关键:是自定义Feign请求拦截器的实现

 

关键代码如下:

/**
 * 处理Feign请求不支持Pojo的问题,以及参数为json串的转换处理!
 */
@AllArgsConstructor
@Configuration
public class FeignRequestInterceptor implements RequestInterceptor {
    private ObjectMapper objectMapper;

    @Override
    public void apply(RequestTemplate template) {

        if (template.method().equals("GET")) {
            try {
                Map<String, Collection<String>> queries = new HashMap<>();
                // 处理不带注解的参数解析
                // feign 不支持 GET 方法传 POJO, json body转query
                if (template.requestBody().asBytes() != null) {
                    JsonNode jsonNode = objectMapper.readTree(template.requestBody().asBytes());
                    buildQuery(jsonNode, "", queries);
                }

                // 处理带有@RequestParam前缀注解的参数解析,如果是json串则拆分处理
                Map<String, Collection<String>> entityParams = template.queries();
                if (entityParams.size() > 0) {
                    for (Map.Entry<String, Collection<String>> entry : entityParams.entrySet()) {
                        List<String> value = (List<String>) entry.getValue();
                        String strVal = value.get(0);
                        // 判断是否是引用对象的的参数,例如:%7B%22code%22:%2218041CAB070-018%22%7D
//                        if (strVal.contains("%22") && strVal.contains("%7B") && strVal.contains("%7D")) { // 则认为是引用类型
                        JsonNode tmpJsonNode = objectMapper.readTree(URLDecoder.decode(strVal, "UTF-8"));
                        buildQuery(tmpJsonNode, "", queries);
//                        }
                    }
                }

                template.queries(queries);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    ...省略其他的代码....    
}  

 

解决不能传递POJO的问题:

下面这段代码处理:支持有一个参数不写@RequestParam,这样这个引用参数自动映射为body:即支持get传递POJO对象,例如分页对象,拦截器拦截处理!

 Map<String, Collection<String>> queries = new HashMap<>();
                // 处理不带注解的参数解析
                // feign 不支持 GET 方法传 POJO, json body转query
                if (template.requestBody().asBytes() != null) {
                    JsonNode jsonNode = objectMapper.readTree(template.requestBody().asBytes());
                    buildQuery(jsonNode, "", queries);
                }

例如,下面为feign接口中定义的样例:

  @GetMapping("/warninginfo/page")
 R getWarningInfoPage(Page page, @RequestParam("warningInfo") String warningInfoJsonString, @RequestHeader(SecurityConstants.FROM) String from);

此处的Page就会被拦截器处理,以便支持传递到B端!

 

解决传递多个引用对象参数到B端的问题:

下面的这段代码处理带有@RequestParam前缀注解的参数解析,如果是json串则拆分处理:

 // 处理带有@RequestParam前缀注解的参数解析,如果是json串则拆分处理
                Map<String, Collection<String>> entityParams = template.queries();
                if (entityParams.size() > 0) {
                    for (Map.Entry<String, Collection<String>> entry : entityParams.entrySet()) {
                        List<String> value = (List<String>) entry.getValue();
                        String strVal = value.get(0);
                        // 判断是否是引用对象的的参数,例如:%7B%22code%22:%2218041CAB070-018%22%7D
//                        if (strVal.contains("%22") && strVal.contains("%7B") && strVal.contains("%7D")) { // 则认为是引用类型
                        JsonNode tmpJsonNode = objectMapper.readTree(URLDecoder.decode(strVal, "UTF-8"));
                        buildQuery(tmpJsonNode, "", queries);
//                        }
                    }
                }

在A端传递多个引用类型对象的json串,这样就支持传递多个引用对象作为参数了,拦截器会解析json串并拆分为请求参数;

下面为feign接口中定义的样例,

@GetMapping("/warninginfo/page") 
R getWarningInfoPage(@RequestParam("page") String pageJsonString, @RequestParam("warningInfo") String warningInfoJsonString, @RequestHeader(SecurityConstants.FROM) String from)

 

 

B端按照SpringMVC支持的方式书写即可:例如

@GetMapping("/page")
@Inner
public R getWarningInfoPage(Page page, WarningInfo warningInfo) {
    return super.getByPage(page, warningInfo);
}

 

拦截器代码参见有道云笔记地址:http://note.youdao.com/noteshare?id=576a6c4f11b25758a44fb09cb0632151

 

参考:

https://www.jianshu.com/p/085c11e5722f

https://github.com/spring-cloud/spring-cloud-netflix/issues/1253

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章