1.先给vo类中字段添加注解
2.调用feignDataSetUtils.setData 方法 将vo类放入 比如我的
feignDataSetUtils.setData(Stream.of(vo).collect(Collectors.toList()));
调用前
调用后 产生赋值。
利用类字段注解的形式配置好对应的fegin关系,达到自动调用fegin的效果。
二.优点1.省略大部分代码,只需配置注解,和编写fegin所需方法。
2.无其他重依赖,适应性强。
3.随意装配,不需要vo类或者fegin类继承任何接口。
三.如何装配加入所有工具类后,只需两步。
先加入 以下类
ApplicationContextProvider:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContextSpring;
@Override
public synchronized void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
applicationContextSpring = applicationContext;
}
public static T getBean(Class clazz) {
return applicationContextSpring.getBean(clazz);
}
}
FeignColum:
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface FeignColum {
String targetFieldName();
String split() default "";
FeignType feignType();
}
FeignDataSetUtils:
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
@Component
public class FeignDataSetUtils {
// @Value("${appId}")
private String appId;
public List setData(List voList) {
if (CollectionUtils.isEmpty(voList)) {
return voList;
}
Object object = voList.get(0);
Class objectClass = object.getClass();
// 获得feign的class为key Field集合为value的map
Map> feignFieldsMap = getFieldsAnnotationMap(objectClass);
// 获得数据dataMap 后面用来发送给feign
Map> idDataMap = buildDataMap(feignFieldsMap.keySet());
// 遍历所有注解
// 遍历所有携带注解的字段-获得id集合
putIdDataMap(feignFieldsMap, voList, idDataMap);
// Feign返回结果集合
Map> feignResultMap = getFeignResultMap(idDataMap);
// 遍历所有
// 遍历所有携带注解的字段-添加集合
putDataMap(feignFieldsMap, objectClass, voList, feignResultMap);
return voList;
}
private Map> getFeignResultMap(Map> idDataMap) {
// 初始化Feign返回结果集合
Map> feignResultMap = new HashMap();
Map feignFunctionMap = FeignFunctionMap.getFeignFunctionMap();
idDataMap.keySet().forEach(feignType -> {
IFeignFunction feignFunction = feignFunctionMap.get(feignType);
Optional.ofNullable(feignFunction).ifPresent(m -> {
m.setAppId(appId);
m.setFeign(ApplicationContextProvider.getBean(feignType.getFeignClass()));
Optional.ofNullable(idDataMap.get(feignType)).ifPresent(idList ->
feignResultMap.put(feignType, m.getBatch(idList))
);
});
});
// // 获得用户集合
// Map userVoMap= Optional.ofNullable(idDataMap.get(FeignType.UserInfoFeign.getFeignClass())).map(m->userInfoFeign.getBatch(m,appId).stream().collect(Collectors.toMap(UserVo::getId, my->(Object)my))).orElse(null) ;
// Optional.ofNullable(userVoMap).ifPresent(p->
// feignResultMap.put(FeignType.UserInfoFeign.getFeignClass(),p)
// );
return feignResultMap;
}
private void putIdDataMap(Map> feignFieldsMap, List voList, Map> idDataMap) {
//遍历所有数据
voList.stream().forEach(entry -> {
feignFieldsMap.keySet().stream().forEach(feignClass -> {
feignFieldsMap.get(feignClass).stream().forEach(field -> {
FeignColum colum = field.getAnnotation(FeignColum.class);
field.setAccessible(true);
// 开始添加id数据
try {
if (StringUtils.isEmpty(colum.split())) {
Optional.ofNullable(field.get(entry)).filter(f -> !ObjectUtils.isEmpty(f)).ifPresent(
fieldValue -> idDataMap.get(colum.feignType()).add(fieldValue));
} else {
Optional.ofNullable(field.get(entry)).map(m -> (String) m).filter(f -> StringUtils.isNotEmpty(f)).ifPresent(
fieldValue -> idDataMap.get(colum.feignType()).addAll(Arrays.stream(fieldValue.split(colum.split())).collect(Collectors.toList())));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
});
});
// 删除没有的数据
idDataMap.values().removeIf(value -> CollectionUtils.isEmpty(value));
}
private void putDataMap(Map> feignFieldsMap, Class objectClass, List voList, Map> resultMap) {
if (CollectionUtils.isEmpty(feignFieldsMap) || CollectionUtils.isEmpty(resultMap)) {
return;
}
voList.stream().forEach(entry -> {
feignFieldsMap.keySet().stream().forEach(feignType -> {
Map
IFeignFunction:
import lombok.Data; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; @Data public abstract class IFeignFunction{ Class clazz; T feign; String appId; public IFeignFunction(){ doGetClass(); } public abstract Map getBatch(List idList); public void doGetClass() { Type genType = this.getClass().getGenericSuperclass(); Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); this.clazz = (Class ) params[0]; } }
剩下的两块代码需要自己加东西
FeignType:
FeignType:这个是用来给注解配置Feign的枚举选项,也就是你想要什么Feign就需要在FeignType中添加一次。
例如我的:
public enum FeignType {
UserInfoFeign(),
UserInfoFeign2();
}
FeignFunctionMap:
它的作用是用来绑定FeignType和IFeignFunction(Feign的方法)的关系。具体可以查看代码理解。比如代码里面的put(FeignType.UserInfoFeign 。。。。 和put(FeignType.UserInfoFeign2.。。。。
import com.xxx.xxx.sdk.feign.UserInfoFeign;
import com.xxx.xxx.sdk.vo.UserVo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class FeignFunctionMap {
private static Map feignFunctionMap = new HashMap();
static {
// 用户Feign
put(FeignType.UserInfoFeign,new IFeignFunction() {
@Override
public Map getBatch(List idList) {
// feign对象相当于UserInfoFeign的实例化对象,appid你们可以不用管,这个是我的feign必须要携带的一个常量。
// 为什么要返回一个Map ? 因为这将要用来做成字典,key是id,value是这个feign根据这个id调用来的值
return feign.getBatch(idList, appId).stream().collect(Collectors.toMap(UserVo::getId, my -> (Object) my));
}
});
put(FeignType.UserInfoFeign2,new IFeignFunction() {
@Override
public Map getBatch(List idList) {
return feign.getBatch(idList.stream().map(m->String.valueOf(m)).collect(Collectors.toList()), appId).stream().collect(Collectors.toMap( my ->Long.valueOf(my.getId()), my -> (Object) my));
}
});
}
public static void put(FeignType feignType,IFeignFunction iFeignFunction){
feignFunctionMap.put(feignType,iFeignFunction);
}
public static Map getFeignFunctionMap() {
return feignFunctionMap;
}
}
如果把自己的FeignType和FeignFunctionMap配置完成后就可以在自己的类中加入注解了。
比如下面是我的vo类。
之后放入feignDataSetUtils.setData(Stream.of(vo).collect(Collectors.toList()))当中就能够赋值了。
上面的代码没有必要放出来所以我就已图片的形式展示出来了。
FeignColum注解类的三个属性用意:
targetFieldName:用来记录目标赋值的字段名称 split:用来切割字符串的分割符号,比如我的 字段是allUserId的值是 "1;2" 那我就需要配置 split = ";",且目标字段也必须是List接收。 feignType:用来绑定使用的feginType的枚举类型。
四.特殊需求
1.假如我的feign的方法每次请求除了携带id还需要携带一个常量参数访问该怎么办?
这个可以是用全局搜索参看 appId的使用方式。



