【原】基于Feign 重写自定义编码器
背景:
有个spring cloud 项目需要调用php小组的接口,但是php提供的接口入参大部分是下划线命名,而Java这边是会按照驼峰编写,如果使用Fegin调用会导致php无法接收参数,所以针对这个问题进行了如下处理,主要是通过重写fegin的默认编码器实现
原理
Spring Cloud Feign 的编码器、解码器和客户端都是支持自定义扩展,可以对请求以及结果和发起请求的过程进行自定义实现,Feign 默认encoder实现是SpringEncoder,默认decocer实现是ResponseEntityDecoder,另外还有一些其它的编解码器。
| Encoder/ Decoder 实现 | 说明 |
|---|---|
| JacksonEncoder,JacksonDecoder | 基于 Jackson 格式的持久化转换协议 |
| GsonEncoder,GsonDecoder | 基于Google GSON 格式的持久化转换协议 |
| SaxEncoder,SaxDecoder | 基于XML 格式的Sax 库持久化转换协议 |
| JAXBEncoder,JAXBDecoder | 基于XML 格式的JAXB 库持久化转换协议 |
| ResponseEntityEncoder,ResponseEntityDecoder | Spring MVC 基于 ResponseEntity< T > 返回格式的转换协议 |
| SpringEncoder,SpringDecoder | 基于Spring MVC HttpMessageConverters 一套机制实现的转换协议 ,应用于Spring Cloud 体系中 |
实现方案
**
* 由于下游接口php是下划线命名,java是驼峰,通过fegin调用会导致下游php接收不到,所以需要针对这种问题特殊处理
*/
public class FeignClientEncoder extends SpringEncoder {
public static final char UNDERLINE = '_';
public FeignClientEncoder(ObjectFactory messageConverters) {
super(messageConverters);
}
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
try {
super.encode(object, bodyType, template);
if(ObjectUtils.isNotEmpty(AnnotationUtils.getAnnotation(object.getClass(), FeginCamelCase.class))){
final String s = JSON.toJSONString(object);
final Object jsonObject = JSON.parse(s);
Class clazz = Class.forName(bodyType.getTypeName());
convertToCamelCase(jsonObject,clazz);
template.body(JSON.toJSONString(jsonObject));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public final static void convertToCamelCase(Object json,Class clazz) throws NoSuchFieldException {
if (json instanceof JSONArray) {
JSONArray arr = (JSONArray) json;
for (Object obj : arr) {
convertToCamelCase(obj,clazz);
}
} else if (json instanceof JSONObject) {
JSONObject jo = (JSONObject) json;
Set keys = jo.keySet();
String[] array = keys.toArray(new String[keys.size()]);
for (String key : array) {
Field field = clazz.getField(key);
//由于有些字段因为特殊原因,不想处理成下划线形式,这时候就可以通过注解的方式进行标记不进行处理
if(ObjectUtils.isEmpty(AnnotationUtils.getAnnotation(field,IgnoreFeginCamelCase.class))){
Object value = jo.get(key);
final String underLineKey = camelToUnderline(key,1);
jo.remove(key);
jo.put(underLineKey, value);
convertToCamelCase(value,clazz);
}
}
}
}
//驼峰转下划线
public static String camelToUnderline(String param, Integer charType) {
if (param == null || "".equals(param.trim())) {
return "";
}
int len = param.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c = param.charAt(i);
if (Character.isUpperCase(c)) {
sb.append(UNDERLINE);
}
if (charType == 2) {
sb.append(Character.toUpperCase(c)); //统一都转大写
} else {
sb.append(Character.toLowerCase(c)); //统一都转小写
}
}
return sb.toString();
}
启动类指定编码器
@EnableFeignClients(defaultConfiguration = FeignClientEncoder.class)