动态修改feignclient注解值,feignclient注解作用
目录
使用效果优点如何装配特殊需求使用注解的形式,装配在编号字段,自动调用费金赋值给目标字段。
使用效果
1.先给签证官类中字段添加注解
2.调用feignDataSetUtils.setData方法将签证官类放入比如我的
feigndatasetutils。setdata(流。(VO)的.收藏(收藏者。to list());调用前
调用后产生赋值。
利用类字段注解的形式配置好对应的费金关系,达到自动调用费金的效果。
优点
1.省略大部分代码,只需配置注解,和编写费金所需方法。
2.无其他重依赖,适应性强。
3.随意装配,不需要签证官类或者费金类继承任何接口。
如何装配
加入所有工具类后,只需两步。
先加入以下类
应用上下文提供者:
导入org。spring框架。豆子。beans异常;导入org。spring框架。语境。应用程序上下文;导入组织。spring框架。语境。applicationcontextaware导入org。spring框架。刻板印象。组件;/* * * * @ 1.0版* @ author : yanch * @ date :2021-9-28 * @ content : */@ component公共类应用上下文提供者实现ApplicationContextAware {私有静态应用程序上下文applicationContextSpring@覆盖公共同步void setApplicationContext(应用程序上下文应用程序上下文)抛出beans异常{ applicationContextSpring=应用程序上下文;} /** * 通过班级获取bean */public static T T get bean(clazz){ return application context spring。get bean(clazz);}}FeignColum:
导入Java。郎。注释。*;/* * * * @ 1.0版* @ author : yanch * @ date :2021-9-27 * @ content : */@ Target({ element type .FIELD })@ Retention(保留策略.运行时)@ documented public @ interface FeignColum {/* * *目标字段当前签证官类的想要赋值的字段名称* */String目标字段名称();/** * 当前字段如果是线类型且是用","分割的话就可以使用这个属性可以设置为",",该字段将会被","分割* */字符串拆分()默认"";/** * 使用的费根类型枚举类型* */FeignType FeignType();}FeignDataSetUtils:
导入org。阿帕奇。公地。郎。字符串实用程序;导入org。spring框架。豆子。工厂。注释。价值;导入org。spring框架。刻板印象。组件;导入org。spring框架。util。收藏u
tils;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: */@Componentpublic class FeignDataSetUtils { // @Value("${appId}") private String appId; /** * 补充User数据 * * @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); // 获得数据dataMap 后面用来发送给feign Map<FeignType, List<Object>> idDataMap = buildDataMap(feignFieldsMap.keySet()); // 遍历所有注解 // 遍历所有携带注解的字段-获得id集合 putIdDataMap(feignFieldsMap, voList, idDataMap); // Feign返回结果集合 Map<FeignType, Map<Object, Object>> feignResultMap = getFeignResultMap(idDataMap); // 遍历所有 // 遍历所有携带注解的字段-添加集合 putDataMap(feignFieldsMap, objectClass, voList, feignResultMap); return voList; } /** * 添加Feign的Result数据 * @return */ private Map<FeignType, Map<Object, Object>> getFeignResultMap(Map<FeignType, List<Object>> idDataMap) { // 初始化Feign返回结果集合 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) { //遍历所有数据 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)); } /** * 遍历所有携带注解的字段-添加集合 * * @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); // 开始添加用户数据 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())); } /** * 初始化字段数据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: */@Datapublic 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的方法)的关系。具体可以查看代码理解。比如代码里面的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方法的关系(IFeignFunction) *手工配置1 * IFeignFunction的第一个泛型是Feign的类,第二个是字段参数类型。 比如我用的是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根据这个id调用来的值 return feign.getBatch(idList, appId).stream().collect(Collectors.toMap(UserVo::getId, my -> (Object) my)); } }); /** * 用来绑定FeignType.UserInfoFeign2 和Feign方法的关系(IFeignFunction) *手工配置2 * IFeignFunction的第一个泛型是Feign的类,第二个是字段参数类型。 比如我用的是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方法实现方式 */ 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还需要携带一个常量参数访问该怎么办?
这个可以是用全局搜索参看appId的使用方式。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持盛行IT。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。