使用Feign調(diào)用注解組件(實現(xiàn)字段賦值功能)
使用注解的形式,裝配在id字段,自動調(diào)用fegin賦值給目標字段。
使用效果
1.先給vo類中字段添加注解
2.調(diào)用feignDataSetUtils.setData 方法 將vo類放入 比如我的
feignDataSetUtils.setData(Stream.of(vo).collect(Collectors.toList()));
調(diào)用前
調(diào)用后 產(chǎn)生賦值。
利用類字段注解的形式配置好對應的fegin關(guān)系,達到自動調(diào)用fegin的效果。
優(yōu)點
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; /** * @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; } /** * 通過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 { /** * 目標字段 當前vo類的想要賦值的字段名稱 * */ String targetFieldName(); /** * 當前字段如果是string類型且是用“,”分割的話就可以使用這個屬性 可以設置為“,”,該字段將會被“,”分割 * */ 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; /** * 補充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 后面用來發(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); // 開始添加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(); } }); }); }); // 刪除沒有的數(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(); // 目標字段 Field targetField = objectClass.getDeclaredField(targetFieldName); targetField.setAccessible(true); // 開始添加用戶數(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) { // 注解集合對象 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); } }); }); // 刪除沒有的字段注解 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]; } }
剩下的兩塊代碼需要自己加東西
FeignType
:這個是用來給注解配置Feign的枚舉選項,也就是你想要什么Feign就需要在FeignType中添加一次。
例如我的:
/** * @Version 1.0 * @Author:yanch * @Date:2021-9-27 * @Content: */ public enum FeignType { /** *手工配置1 UserInfoFeign 是選項名稱 用來給注解配置使用 */ UserInfoFeign(), /** *手工配置2 UserInfoFeign2 是選項名稱 用來給注解配置使用 */ UserInfoFeign2(); }
FeignFunctionMap
:它的作用是用來綁定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 { /** * 用來綁定FeignType.UserInfoFeign 和Feign方法的關(guān)系(IFeignFunction) *手工配置1 * IFeignFunction的第一個泛型是Feign的類,第二個是字段參數(shù)類型。 比如我用的是String 存儲的id,這里就用String */ // 用戶Feign put(FeignType.UserInfoFeign,new IFeignFunction<UserInfoFeign,String>() { @Override public Map<String, Object> getBatch(List<String> idList) { // feign對象相當于UserInfoFeign的實例化對象,appid你們可以不用管,這個是我的feign必須要攜帶的一個常量。 // 為什么要返回一個Map<String, Object> ? 因為這將要用來做成字典,key是id,value是這個feign根據(jù)這個id調(diào)用來的值 return feign.getBatch(idList, appId).stream().collect(Collectors.toMap(UserVo::getId, my -> (Object) my)); } }); /** * 用來綁定FeignType.UserInfoFeign2 和Feign方法的關(guān)系(IFeignFunction) *手工配置2 * IFeignFunction的第一個泛型是Feign的類,第二個是字段參數(shù)類型。 比如我用的是Long 存儲的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)); } }); } /** *--------------------------以下無需配置 */ /** *@param feignType FeignType名稱 *@param iFeignFunction feign方法實現(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()))當中就能夠賦值了。
上面的代碼沒有必要放出來所以我就已圖片的形式展示出來了。
FeignColum注解類的三個屬性用意:
targetFieldName
:用來記錄目標賦值的字段名稱split
:用來切割字符串的分割符號,比如我的 字段是allUserId的值是 "1;2" 那我就需要配置 split = ";",且目標字段也必須是List接收。feignType
:用來綁定使用的feginType的枚舉類型。
特殊需求
1.假如我的feign的方法每次請求除了攜帶id還需要攜帶一個常量參數(shù)訪問該怎么辦?
這個可以是用全局搜索參看 appId的使用方式。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java9新特性Reactive?Stream響應式編程?API
這篇文章主要為大家介紹了java9新特性響應式編程API的特點詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03Executor攔截器高級教程QueryInterceptor的規(guī)范
今天小編就為大家分享一篇關(guān)于Executor攔截器高級教程QueryInterceptor的規(guī)范,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12zuul轉(zhuǎn)發(fā)后服務取不到請求路徑的解決
這篇文章主要介紹了zuul轉(zhuǎn)發(fā)后服務取不到請求路徑的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07使用JSON.toJSONString格式化成json字符串時保留null屬性
這篇文章主要介紹了使用JSON.toJSONString格式化成json字符串時保留null屬性,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06SpringBoot2整合Ehcache組件實現(xiàn)輕量級緩存管理
EhCache是一個純Java的進程內(nèi)緩存框架,具有快速、上手簡單等特點,是Hibernate中默認的緩存提供方。本文講述下SpringBoot2 整合Ehcache組件的步驟2021-06-06

java使用wait()和notify()線程間通訊的實現(xiàn)