feign 自定义编码器

4,088 阅读2分钟

feign 自定义编码器

1、实现的目的

当某接口定义仅支持form 形式进行参数传递而入参又特别多的时候,定义feign 接口则需要对应上那一大坨的参数,为了简化这些操作而自定义了编码器。

2、实现方式

1、首先在定义一个Feign Client的时候,指定一个额外的配置类

可参考openfeign 官网文档

@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());
    }
}