使用Feign調(diào)用注解組件(實(shí)現(xiàn)字段賦值功能)
使用注解的形式,裝配在id字段,自動(dòng)調(diào)用fegin賦值給目標(biāo)字段。
使用效果
1.先給vo類中字段添加注解

2.調(diào)用feignDataSetUtils.setData 方法 將vo類放入 比如我的
feignDataSetUtils.setData(Stream.of(vo).collect(Collectors.toList()));
調(diào)用前

調(diào)用后 產(chǎn)生賦值。

利用類字段注解的形式配置好對(duì)應(yīng)的fegin關(guān)系,達(dá)到自動(dòng)調(diào)用fegin的效果。
優(yōu)點(diǎn)
1.省略大部分代碼,只需配置注解,和編寫fegin所需方法。
2.無(wú)其他重依賴,適應(yīng)性強(qiáng)。
3.隨意裝配,不需要vo類或者fegin類繼承任何接口。
如何裝配
加入所有工具類后,只需兩步。
先加入 以下類
ApplicationContextProvider:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @Version 1.0
* @Author:yanch
* @Date:2021-9-28
* @Content:
*/
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContextSpring;
@Override
public synchronized void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
applicationContextSpring = applicationContext;
}
/**
* 通過(guò)class 獲取Bean
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContextSpring.getBean(clazz);
}
}FeignColum:
import java.lang.annotation.*;
/**
* @Version 1.0
* @Author:yanch
* @Date:2021-9-27
* @Content:
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignColum {
/**
* 目標(biāo)字段 當(dāng)前vo類的想要賦值的字段名稱
*
*/
String targetFieldName();
/**
* 當(dāng)前字段如果是string類型且是用“,”分割的話就可以使用這個(gè)屬性 可以設(shè)置為“,”,該字段將會(huì)被“,”分割
*
*/
String split() default "";
/**
* 使用的feignType枚舉類型
*
*/
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;
/**
* @Version 1.0
* @Author:yanch
* @Date:2021-9-28
* @Content:
*/
@Component
public class FeignDataSetUtils {
// @Value("${appId}")
private String appId;
/**
* 補(bǔ)充User數(shù)據(jù)
*
* @param voList
* @return
*/
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<FeignType, List<Field>> feignFieldsMap = getFieldsAnnotationMap(objectClass);
// 獲得數(shù)據(jù)dataMap 后面用來(lái)發(fā)送給feign
Map<FeignType, List<Object>> idDataMap = buildDataMap(feignFieldsMap.keySet());
// 遍歷所有注解
// 遍歷所有攜帶注解的字段-獲得id集合
putIdDataMap(feignFieldsMap, voList, idDataMap);
// Feign返回結(jié)果集合
Map<FeignType, Map<Object, Object>> feignResultMap = getFeignResultMap(idDataMap);
// 遍歷所有
// 遍歷所有攜帶注解的字段-添加集合
putDataMap(feignFieldsMap, objectClass, voList, feignResultMap);
return voList;
}
/**
* 添加Feign的Result數(shù)據(jù)
* @return
*/
private Map<FeignType, Map<Object, Object>> getFeignResultMap(Map<FeignType, List<Object>> idDataMap) {
// 初始化Feign返回結(jié)果集合
Map<FeignType, Map<Object, Object>> feignResultMap = new HashMap();
Map<FeignType, IFeignFunction> 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<String, Object> 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;
}
/**
* 遍歷所有攜帶注解的字段-獲得id集合
*
* @return
*/
private void putIdDataMap(Map<FeignType, List<Field>> feignFieldsMap, List voList, Map<FeignType, List<Object>> idDataMap) {
//遍歷所有數(shù)據(jù)
voList.stream().forEach(entry -> {
feignFieldsMap.keySet().stream().forEach(feignClass -> {
feignFieldsMap.get(feignClass).stream().forEach(field -> {
FeignColum colum = field.getAnnotation(FeignColum.class);
field.setAccessible(true);
// 開(kāi)始添加id數(shù)據(jù)
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();
}
});
});
});
// 刪除沒(méi)有的數(shù)據(jù)
idDataMap.values().removeIf(value -> CollectionUtils.isEmpty(value));
}
/**
* 遍歷所有攜帶注解的字段-添加集合
*
* @return
*/
private void putDataMap(Map<FeignType, List<Field>> feignFieldsMap, Class objectClass, List voList, Map<FeignType, Map<Object, Object>> resultMap) {
if (CollectionUtils.isEmpty(feignFieldsMap) || CollectionUtils.isEmpty(resultMap)) {
return;
}
voList.stream().forEach(entry -> {
feignFieldsMap.keySet().stream().forEach(feignType -> {
Map<Object, Object> voMap = resultMap.get(feignType);
feignFieldsMap.get(feignType).stream().forEach(field -> {
try {
FeignColum colum = field.getAnnotation(FeignColum.class);
String targetFieldName = colum.targetFieldName();
// 目標(biāo)字段
Field targetField = objectClass.getDeclaredField(targetFieldName);
targetField.setAccessible(true);
// 開(kāi)始添加用戶數(shù)據(jù)
if (StringUtils.isEmpty(colum.split())) {
Optional.ofNullable(field.get(entry)).filter(f -> !ObjectUtils.isEmpty(f)).ifPresent(
fieldValue -> {
Object object = voMap.get(fieldValue);
try {
targetField.set(entry, object);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
} else {
Optional.ofNullable(field.get(entry)).map(m -> (String) m).filter(f -> StringUtils.isNotEmpty(f)).ifPresent(
fieldValue -> {
try {
Object object = Arrays.stream(fieldValue.split(colum.split())).map(m -> {
return voMap.get(m);
}).collect(Collectors.toList());
targetField.set(entry, object);
} catch (Exception e) {
e.printStackTrace();
}
});
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
});
});
});
}
/**
* 獲得需要的注解字段
*
* @param cls
* @return
*/
private Map<FeignType, List<Field>> getFieldsAnnotationMap(Class cls) {
// 注解集合對(duì)象
Map<FeignType, List<Field>> feignMap = buildAnnotationMap();
// 字段遍歷
Arrays.stream(cls.getDeclaredFields()).forEach(field -> {
feignMap.keySet().stream().forEach(feignClass -> {
if (field.isAnnotationPresent(FeignColum.class)) {
FeignColum colum = field.getAnnotation(FeignColum.class);
if(colum.feignType()!=feignClass){
return;
}
feignMap.get(colum.feignType()).add(field);
}
});
});
// 刪除沒(méi)有的字段注解
feignMap.values().removeIf(value -> CollectionUtils.isEmpty(value));
return feignMap;
}
/**
* 初始化注解map
*
* @return
*/
private Map<FeignType, List<Field>> buildAnnotationMap() {
return Arrays.stream(FeignType.values()).collect(Collectors.toMap(my -> my, my -> new ArrayList()));
}
/**
* 初始化字段數(shù)據(jù)map
*
* @return
*/
private Map<FeignType, List<Object>> buildDataMap(Collection<FeignType> collection) {
return collection.stream().collect(Collectors.toMap(my -> my, my -> new ArrayList()));
}
}IFeignFunction:
import lombok.Data;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* @Version 1.0
* @Author:yanch
* @Date:2021-9-28
* @Content:
*/
@Data
public abstract class IFeignFunction<T,E> {
Class<T> clazz;
T feign;
String appId;
public IFeignFunction(){
doGetClass();
}
public abstract Map<E, Object> getBatch(List<E> idList);
public void doGetClass() {
Type genType = this.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
this.clazz = (Class<T>) params[0];
}
}剩下的兩塊代碼需要自己加?xùn)|西
FeignType:這個(gè)是用來(lái)給注解配置Feign的枚舉選項(xiàng),也就是你想要什么Feign就需要在FeignType中添加一次。

例如我的:
/**
* @Version 1.0
* @Author:yanch
* @Date:2021-9-27
* @Content:
*/
public enum FeignType {
/**
*手工配置1 UserInfoFeign 是選項(xiàng)名稱 用來(lái)給注解配置使用
*/
UserInfoFeign(),
/**
*手工配置2 UserInfoFeign2 是選項(xiàng)名稱 用來(lái)給注解配置使用
*/
UserInfoFeign2();
}FeignFunctionMap:它的作用是用來(lái)綁定FeignType和IFeignFunction(Feign的方法)的關(guān)系。- 具體可以查看代碼理解。比如代碼里面的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;
/**
* @Version 1.0
* @Author:yanch
* @Date:2021-9-28
* @Content:
*/
public class FeignFunctionMap {
private static Map<FeignType, IFeignFunction> feignFunctionMap = new HashMap();
static {
/**
* 用來(lái)綁定FeignType.UserInfoFeign 和Feign方法的關(guān)系(IFeignFunction)
*手工配置1
* IFeignFunction的第一個(gè)泛型是Feign的類,第二個(gè)是字段參數(shù)類型。 比如我用的是String 存儲(chǔ)的id,這里就用String
*/
// 用戶Feign
put(FeignType.UserInfoFeign,new IFeignFunction<UserInfoFeign,String>() {
@Override
public Map<String, Object> getBatch(List<String> idList) {
// feign對(duì)象相當(dāng)于UserInfoFeign的實(shí)例化對(duì)象,appid你們可以不用管,這個(gè)是我的feign必須要攜帶的一個(gè)常量。
// 為什么要返回一個(gè)Map<String, Object> ? 因?yàn)檫@將要用來(lái)做成字典,key是id,value是這個(gè)feign根據(jù)這個(gè)id調(diào)用來(lái)的值
return feign.getBatch(idList, appId).stream().collect(Collectors.toMap(UserVo::getId, my -> (Object) my));
}
});
/**
* 用來(lái)綁定FeignType.UserInfoFeign2 和Feign方法的關(guān)系(IFeignFunction)
*手工配置2
* IFeignFunction的第一個(gè)泛型是Feign的類,第二個(gè)是字段參數(shù)類型。 比如我用的是Long 存儲(chǔ)的id,這里就用Long
*/
put(FeignType.UserInfoFeign2,new IFeignFunction<UserInfoFeign,Long>() {
@Override
public Map<Long, Object> getBatch(List<Long> 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));
}
});
}
/**
*--------------------------以下無(wú)需配置
*/
/**
*@param feignType FeignType名稱
*@param iFeignFunction feign方法實(shí)現(xiàn)方式
*/
public static void put(FeignType feignType,IFeignFunction iFeignFunction){
feignFunctionMap.put(feignType,iFeignFunction);
}
public static Map<FeignType, IFeignFunction> getFeignFunctionMap() {
return feignFunctionMap;
}
}如果把自己的FeignType和FeignFunctionMap配置完成后就可以在自己的類中加入注解了。
比如下面是我的vo類。

之后放入feignDataSetUtils.setData(Stream.of(vo).collect(Collectors.toList()))當(dāng)中就能夠賦值了。

上面的代碼沒(méi)有必要放出來(lái)所以我就已圖片的形式展示出來(lái)了。
FeignColum注解類的三個(gè)屬性用意:
targetFieldName:用來(lái)記錄目標(biāo)賦值的字段名稱split:用來(lái)切割字符串的分割符號(hào),比如我的 字段是allUserId的值是 "1;2" 那我就需要配置 split = ";",且目標(biāo)字段也必須是List接收。feignType:用來(lái)綁定使用的feginType的枚舉類型。
特殊需求
1.假如我的feign的方法每次請(qǐng)求除了攜帶id還需要攜帶一個(gè)常量參數(shù)訪問(wèn)該怎么辦?
這個(gè)可以是用全局搜索參看 appId的使用方式。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java9新特性Reactive?Stream響應(yīng)式編程?API
這篇文章主要為大家介紹了java9新特性響應(yīng)式編程API的特點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
Executor攔截器高級(jí)教程QueryInterceptor的規(guī)范
今天小編就為大家分享一篇關(guān)于Executor攔截器高級(jí)教程QueryInterceptor的規(guī)范,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
zuul轉(zhuǎn)發(fā)后服務(wù)取不到請(qǐng)求路徑的解決
這篇文章主要介紹了zuul轉(zhuǎn)發(fā)后服務(wù)取不到請(qǐng)求路徑的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
使用JSON.toJSONString格式化成json字符串時(shí)保留null屬性
這篇文章主要介紹了使用JSON.toJSONString格式化成json字符串時(shí)保留null屬性,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
SpringBoot2整合Ehcache組件實(shí)現(xiàn)輕量級(jí)緩存管理
EhCache是一個(gè)純Java的進(jìn)程內(nèi)緩存框架,具有快速、上手簡(jiǎn)單等特點(diǎn),是Hibernate中默認(rèn)的緩存提供方。本文講述下SpringBoot2 整合Ehcache組件的步驟2021-06-06
java實(shí)現(xiàn)坦克大戰(zhàn)小游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)坦克大戰(zhàn)小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01
java使用wait()和notify()線程間通訊的實(shí)現(xiàn)
Java 線程通信是將多個(gè)獨(dú)立的線程個(gè)體進(jìn)行關(guān)聯(lián)處理,使得線程與線程之間能進(jìn)行相互通信,本文就介紹了java使用wait()和notify()線程間通訊的實(shí)現(xiàn),感興趣的可以了解一下2023-09-09

