解决 feign不支持GET方法传递POJO 的问题
diff --git a/leaveschool/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java b/leaveschool/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java
index 58b71fe..181f6a5 100644
--- a/leaveschool/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java
+++ b/leaveschool/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java
@@ -11,6 +11,7 @@
 import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
 import com.supwisdom.infras.security.configure.api.EnableInfrasApiSecurity;
 import com.supwisdom.infras.security.configure.oauth2.EnableInfrasOAuth2;
+import com.supwisdom.leaveschool.feign.CharlesRequestInterceptor;
 
 @SpringBootApplication
 @EnableCircuitBreaker
@@ -24,6 +25,12 @@
     SpringApplication.run(ClientApplication.class, args);
   }
   
+
+  @Bean
+  public CharlesRequestInterceptor charlesRequestInterceptor(){
+    return new CharlesRequestInterceptor();
+  }
+  
   
   @Bean
   public ServletRegistrationBean<HystrixMetricsStreamServlet> hystrixMetricsStreamServlet() {
diff --git a/leaveschool/client/src/main/java/com/supwisdom/leaveschool/feign/CharlesRequestInterceptor.java b/leaveschool/client/src/main/java/com/supwisdom/leaveschool/feign/CharlesRequestInterceptor.java
new file mode 100644
index 0000000..181c396
--- /dev/null
+++ b/leaveschool/client/src/main/java/com/supwisdom/leaveschool/feign/CharlesRequestInterceptor.java
@@ -0,0 +1,74 @@
+package com.supwisdom.leaveschool.feign;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+
+public class CharlesRequestInterceptor implements RequestInterceptor {
+
+  @Autowired
+  private ObjectMapper objectMapper;
+
+  @Override
+  public void apply(RequestTemplate template) {
+    // feign 不支持 GET 方法传 POJO, json body转query
+    if (template.method().equals("GET") && template.body() != null) {
+      try {
+        JsonNode jsonNode = objectMapper.readTree(template.body());
+        template.body(null);
+        Map<String, Collection<String>> queries = new HashMap<>();
+        buildQuery(jsonNode, "", queries);
+        template.queries(queries);
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
+    if (!jsonNode.isContainerNode()) {
+      // 叶子节点
+      if (jsonNode.isNull()) {
+        return;
+      }
+      Collection<String> values = queries.get(path);
+      if (null == values) {
+        values = new ArrayList<>();
+        queries.put(path, values);
+      }
+      values.add(jsonNode.asText());
+      return;
+    }
+    if (jsonNode.isArray()) { // 数组节点
+      Iterator<JsonNode> it = jsonNode.elements();
+      while (it.hasNext()) {
+        buildQuery(it.next(), path, queries);
+      }
+    } else {
+      Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
+      while (it.hasNext()) {
+        Map.Entry<String, JsonNode> entry = it.next();
+        if (StringUtils.hasText(path)) {
+          buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
+        } else {
+          // 根节点
+          buildQuery(entry.getValue(), entry.getKey(), queries);
+        }
+      }
+    }
+
+  }
+
+}
diff --git a/samples/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java b/samples/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java
index ff95ef5..1de9e95 100644
--- a/samples/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java
+++ b/samples/client/src/main/java/com/supwisdom/leaveschool/client/ClientApplication.java
@@ -15,6 +15,7 @@
 import com.supwisdom.infras.security.configure.api.EnableInfrasApiSecurity;
 import com.supwisdom.infras.security.configure.oauth2.EnableInfrasOAuth2;
 import com.supwisdom.infras.security.configure.web.EnableInfrasWebSecurity;
+import com.supwisdom.leaveschool.feign.CharlesRequestInterceptor;
 
 @SpringBootApplication
 @EnableCircuitBreaker
@@ -29,6 +30,10 @@
     SpringApplication.run(ClientApplication.class, args);
   }
   
+  @Bean
+  public CharlesRequestInterceptor charlesRequestInterceptor(){
+      return new CharlesRequestInterceptor();
+  }
   
   @Bean
   public ServletRegistrationBean<HystrixMetricsStreamServlet> hystrixMetricsStreamServlet() {
diff --git a/samples/client/src/main/java/com/supwisdom/leaveschool/feign/CharlesRequestInterceptor.java b/samples/client/src/main/java/com/supwisdom/leaveschool/feign/CharlesRequestInterceptor.java
new file mode 100644
index 0000000..181c396
--- /dev/null
+++ b/samples/client/src/main/java/com/supwisdom/leaveschool/feign/CharlesRequestInterceptor.java
@@ -0,0 +1,74 @@
+package com.supwisdom.leaveschool.feign;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+
+public class CharlesRequestInterceptor implements RequestInterceptor {
+
+  @Autowired
+  private ObjectMapper objectMapper;
+
+  @Override
+  public void apply(RequestTemplate template) {
+    // feign 不支持 GET 方法传 POJO, json body转query
+    if (template.method().equals("GET") && template.body() != null) {
+      try {
+        JsonNode jsonNode = objectMapper.readTree(template.body());
+        template.body(null);
+        Map<String, Collection<String>> queries = new HashMap<>();
+        buildQuery(jsonNode, "", queries);
+        template.queries(queries);
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
+    if (!jsonNode.isContainerNode()) {
+      // 叶子节点
+      if (jsonNode.isNull()) {
+        return;
+      }
+      Collection<String> values = queries.get(path);
+      if (null == values) {
+        values = new ArrayList<>();
+        queries.put(path, values);
+      }
+      values.add(jsonNode.asText());
+      return;
+    }
+    if (jsonNode.isArray()) { // 数组节点
+      Iterator<JsonNode> it = jsonNode.elements();
+      while (it.hasNext()) {
+        buildQuery(it.next(), path, queries);
+      }
+    } else {
+      Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
+      while (it.hasNext()) {
+        Map.Entry<String, JsonNode> entry = it.next();
+        if (StringUtils.hasText(path)) {
+          buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
+        } else {
+          // 根节点
+          buildQuery(entry.getValue(), entry.getKey(), queries);
+        }
+      }
+    }
+
+  }
+
+}