feign 自定义编码器
1、实现的目的
当某接口定义仅支持form 形式进行参数传递而入参又特别多的时候,定义feign 接口则需要对应上那一大坨的参数,为了简化这些操作而自定义了编码器。
2、实现方式
1、首先在定义一个Feign Client的时候,指定一个额外的配置类
@FeignClient(configuration = FormConfig.class)
FormConfig 代码如下:
//不需要用注释@Configuration。但是如果使用了@Configuration的话它将成为默认的编码器
public class FormConfig {
@Bean
public Encoder encoder(){
return new FormEncoder();
}
}
2、定义编码器类将传入的对象拆分为form 表单形式参数传递
主要实现了Encoder 的 encode 方法
package com.yiyu.feign.code;
import com.alibaba.fastjson.JSONObject;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @description: feign 参数编码器
* @date: 2020/7/31 0031 15:58
* @author: xpy
*/
@Configuration
public class FormEncoder implements Encoder {
/**
* @description: 覆写编码实现
* @date: 2020/8/13 0013 22:04
* @author: xpy
*/
@Override
public void encode(Object o, Type type, RequestTemplate rt) throws EncodeException {
try {
if(RequestMethod.GET.name().equals(rt.method())){
doGetEncode(o, type, rt);
}else {
doPostEncode(o, type, rt);
}
}catch (Exception e){
throw new EncodeException(e.getMessage());
}
}
/**
* @description: 请求接口为get请求时
* @date: 2020/8/13 0013 22:04
* @author: xpy
*/
public void doGetEncode(Object o, Type type, RequestTemplate rt) throws Exception {
Map<String, String> map = this.parserParamMap(o, type, rt);
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
rt.query(entry.getKey(),entry.getValue());
}
rt.header("Content-Type", "application/x-www-form-urlencoded");
}
/**
* @description: 请求接口为post请求时
* @date: 2020/8/13 0013 22:04
* @author: xpy
*/
public void doPostEncode(Object o, Type type, RequestTemplate rt) throws Exception {
Map<String, String> map = this.parserParamMap(o, type, rt);
Set<Map.Entry<String, String>> entries = map.entrySet();
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : entries) {
stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
rt.header("Content-Type", "application/x-www-form-urlencoded");
rt.body(stringBuilder.toString());
}
/**
* @description: 参数转换
* @date: 2020/8/4 0004 17:20
* @author: xpy
*/
public Map<String,String> parserParamMap(Object o, Type type, RequestTemplate rt) throws Exception {
Map<String,String> requestParamMap = new HashMap<>();
Class clazz = Thread.currentThread().getContextClassLoader().loadClass(type.getTypeName());
Field[] fields = clazz.getDeclaredFields();
String oStr = JSONObject.toJSONString(o);
for(Field field : fields){
field.setAccessible(true);
Object fieldValue = field.get(JSONObject.parseObject(oStr,clazz));
if(fieldValue == null){
continue;
}
//判断对象是否为基本类型
if(isPrimitive(fieldValue)){
requestParamMap.put(URLEncoder.encode(field.getName(),"UTF-8"),URLEncoder.encode(fieldValue.toString(),"UTF-8"));
}
//判断对象是集合
else if(fieldValue instanceof Iterable){
Iterable iterable = (Iterable)fieldValue;
//获取迭代器
Iterator iterator = iterable.iterator();
int index = 0;
while (true){
Object value = iterator.next();
//判断是否为基本类型非基本类型抛出异常
if(!isPrimitive(value)){
throw new EncodeException(field.getName()+":Types that cannot be converted");
}
requestParamMap.put(URLEncoder.encode(field.getName()+"["+index+"]","UTF-8"),URLEncoder.encode(value.toString(),"UTF-8"));
boolean flag = iterator.hasNext();
if(!flag){
break;
}
index++;
}
}else {
throw new EncodeException(field.getName()+":Types that cannot be converted");
}
}
return requestParamMap;
}
/**
* @description: 判断对象是否为基本类型
* @date: 2020/8/4 0004 16:23
* @author: xpy
*/
public boolean isPrimitive(Object object){
return ClassUtils.isPrimitiveOrWrapper(object.getClass())
|| String.class.isAssignableFrom(object.getClass())
|| Number.class.isAssignableFrom(object.getClass());
}
}