使用Feign调用注解组件(实现字段赋值功能)

网友投稿 298 2022-08-21


使用Feign调用注解组件(实现字段赋值功能)

目录使用效果优点如何装配特殊需求

使用注解的形式,装配在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 getBean(Class 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 Strhttp://ing 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> 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;

}

/**

* 添加Feign的Result数据

* @return

*/

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;

}

/**

* 遍历所有携带注解的字段-获得id集合

*

* @return

*/

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));

}

/**

* 遍历所有携带注解的字段-添加集合

*

* @return

*/

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 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> getFieldsAnnotationMap(Class cls) {

// 注解集合对象

Map> 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> buildAnnotationMap() {

return Arrays.stream(FeignType.values()).collect(Collectors.toMap(my -> my, my -> new ArrayList()));

}

/**

* 初始化字段数据map

*

* @return

*/

private Map> buildDataMap(Collection 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 {

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:这个是用来给注解配置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 feignFunctionMap = new HashMap();

static {

/**

* 用来绑定FeignType.UserInfoFeign 和Feign方法的关系(IFeignFunction)

*手工配置1

* IFeignFunction的第一个泛型是Feign的类,第二个是字段参数类型。 比如我用的是String 存储的id,这里就用String

*/

// 用户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));

}

});

/**

* 用来绑定FeignType.UserInfoFeign2 和Feign方法的关系(IFeignFunction)

*手工配置2

* IFeignFunction的第一个泛型是Feign的类,第二个是字段参数类型。 比如我用的是Long 存储的id,这里就用Long

*/

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));

}

});

}

/**

*--------------------------以下无需配置

*/

/**

*@param feignType FeignType名称

*@param iFeignFunction feign方法实现方式

*/

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的使用方式。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:JAVA偏向锁的原理与实战
下一篇:Java十分钟掌握选择与循环结构
相关文章

 发表评论

暂时没有评论,来抢沙发吧~