使用Feign调用注解组件(实现字段赋值功能)
作者:qq_42152947 发布时间:2023-01-06 15:19:59
使用注解的形式,装配在id字段,自动调用fegin赋值给目标字段。
使用效果
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;
/**
* @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数据
*
* @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:
*/
@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的方法)的关系。具体可以查看代码理解。比如代码里面的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的使用方式。
来源:https://blog.csdn.net/qq_42152947/article/details/120601199


猜你喜欢
- 1.一维数组名作为函数参数传递一位数组名,就相当于该数组的首个元素的地址;int a[10];int *p;p=a;//p=a与p=&
- Android里有两个类android.view.GestureDetectorandroid.view.GestureDetector.S
- 像ipconfig /all 这样的CMD命令想必大家都知道,但是很多童鞋可能不知道怎么写这样的控制台带参数的程序,其实很简单,我们先看建立
- 前言在项目开发中经常会用到配置文件,配置文件的存在解决了很大一份重复的工作。今天就分享四种在Springboot中获取配置文件的方式。注:前
- 生成excel并导出到对应位置package tech.BurtonPratice; import org.apache.poi.hssf.
- 本篇文章主要介绍了java自动生成编号的实现,分享给大家,具体如下/** * 自动生成编号格式:yyMM+四位流水号 */ @Reques
- 概述 ScrollView也是一个容器,它是FrameLayout的子类,它的主要作用就是将超出物理屏幕的内容显示
- 具体代码如下所示:import java.io.File;public class Scan { public static v
- 目录类划分时关于内聚性的问题静态类的设计高内聚类的设计附:面向过程编程中模块的内聚性偶然内聚或巧合内聚(Coincidental)逻辑内聚(
- Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。B
- 本文实例讲述了java swing实现的扫雷游戏及改进版。分享给大家供大家参考,具体如下:版本1:package awtDemo;impor
- 前言MyBatis中也提供了注解式开发⽅式,采⽤注解可以减少Sql映射⽂件的配置。 当然,使⽤注解式开发的话,sql语句是写在java程序中
- 1. Dozer 介绍Dozer 是一个 Java Bean 到 Java Bean 的映射器,它递归地将数据从一个对象复制到另一个对象。D
- 一、读取系统配置文件application.yaml1、application.yaml配置文件中增加一下测试配置testdata: &nb
- Kotlin 封装万能SharedPreferences存取任何类型详解/** * author: smart * time: 2016/1
- 前言前不久遇到一个问题,是公司早期的基础库遇到的,其实很低级,但是还是记录下来。出错点是一个 IO 流的写入bug,我们项目会有一种专有的数
- 实现Android studio设置自动导包及自动导包快捷键方式一:Android studio只有导单个包的快捷键:Alt+Enter。方
- 负载均衡使用微服务后,为了能够承担高并发的压力,同一个服务可能会启动多个实例。这时候消费者就需要负载均衡,把请求分散到各个实例。负载均衡主要
- 了解JVM内存结构的目的在Java的开发过程中,因为有JVM自动内存管理机制,不再需要像在C、C++开发那样手动释放对象的内存空间,不容易出
- 属性CascadeType.REFRESH:级联刷新,当多个用户同时作操作一个实体,为了用户取到的数据是实时的,在用实体中的数据之前就可以调