通过Java反射来实现接口字段的可配置化

项目中与外部系统的数据交互肯定少不了,大部分项目的对外接口其实可以固定,基本是万年不变。但是现在在做的百度CMS系统由于对接了太多的业务线,各个业务线推送合同的字段不一样,并且由于安全的考虑,并不会放开所有字段推送给外部系统。这就造成一个问题,随着各业务线的业务需要,可能会时不时的改动数据传输的接口,这就增加了开发的工作量,由于基本都是后台定时任务,QA测试也并不是很方便,因此就想搞一个前台可配置的定时任务,可以让PM通过配置需要传输的字段,而不是代码字段的修改,实现业务上的满足。

传输对象类

定一个需要传输的对象,我们定义一个User类,设置几个属性,并生成一下getter和setter。

public class User implements Serializable {

    private String name;
    private String addr;
    private int age;
    private User leader;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public User getLeader() {
        return leader;
    }

    public void setLeader(User leader) {
        this.leader = leader;
    }
}
public class Field implements Serializable {
	private String code;
    private String fieldName;
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }
}

自动任务对象

定义一个简单的自动任务类,里面包含需要传输的字段,cron表达式,执行时间等字段。

public class TransimissionJob {
    // 自动任务名称
    private String jobName;
    // 自动任务表达式
    private String cronExp;
    // 上次执行时间
    private Date lastExecTime;
    // 下次执行时间
    private Date nextExecTime;
    // 传输地址
    private String url;
    // 传输字段
    private List<MyField> info = new ArrayList<MyField>(0);

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getCronExp() {
        return cronExp;
    }

    public void setCronExp(String cronExp) {
        this.cronExp = cronExp;
    }

    public Date getLastExecTime() {
        return lastExecTime;
    }

    public void setLastExecTime(Date lastExecTime) {
        this.lastExecTime = lastExecTime;
    }

    public Date getNextExecTime() {
        return nextExecTime;
    }

    public void setNextExecTime(Date nextExecTime) {
        this.nextExecTime = nextExecTime;
    }
    
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public List<MyField> getBasicInfo() {
        return basicInfo;
    }

    public void setBasicInfo(List<MyField> basicInfo) {
        this.basicInfo = basicInfo;
    }
}

这些基本的对象都有了,但还差一点东西,既然要满足前台配置,而且是通过反射进行对象属性的封装,那么就得要有一个映射关系:
人员名—name;
人员地址—addr;
人员年龄—age;
上级人员名—leader.name;
比如说,要勾选人员名、地址、年龄、上级名这四个字段进行数据传输,TransimissionJob.info那个列表,就应该是四个对象,Field.code属性分别是name、addr、age、leader.name。

具体的处理

TransimissionJob job = // 从数据库拿出某条任务对象
// 定义一个Set集合,将TransimissionJob.info对象的code装进去
Set<String> properties = new HashSet<String>();
if (CollectionUtils.isNotEmpty(job.getInfo())) {
      for (Field field : job.getInfo()) {
         if (StringUtils.isNotBlank(field.getCode())) {
              properties.add(field.getCode());
            }
      }
}
// 获取一级属性
Set<String> simpleProperties = getSimpleProperties(properties);
List<User> data = // 从数据库拿出用户对象
// 存放组织的数据
List<Map<String, Object> > targets = new ArrayList<Map<String, Object>>();
for (User user : datas) {
	// 每一条数据的kv键值对
	Map<String, Object> target = getData(user, user.class, simpleProperties);
    targets.add(target);
}
// 转换得到的Json串
String jsonData = JSON.toJSONString(result);
// 具体调外部系统接收数据api
......

/** 
 * 获取一级属性,通过.来分割
*/
public static Set<String> getSimpleProperties(Set<String> properties) {
        Set<String> simpleProperties = new HashSet<String>();
        for (String property : properties) {
            if (property.contains(".")) {
                int suffixIx = property.indexOf(".");
                if (suffixIx > 0) {
                    String simpleProperty = property.substring(0, suffixIx);
                    simpleProperties.add(simpleProperty);
                }
            } else {
                simpleProperties.add(property);
            }
        }
        return simpleProperties;
}
/** 
 * 获取properties中parent下面的子字段名列表
*/
public static Set<String> getChildProperties(Set<String> properties, String parent) {
        Set<String> result = new HashSet<String>();
        for (String property : properties) {
            if (property.startsWith(parent + ".")) {
                int suffixIx = property.indexOf(".");
                if (suffixIx > 0) {
                    String simpleProperty = property.substring(suffixIx + 1);
                    result.add(simpleProperty);
                }
            }
        }
        return result;
    }
/**
     * 根据实体entity和字段属性名得到需要的字段
     * @param entity
     * @param clazz
     * @param needProperties
     * @return
     * @throws Exception
     */
    public static Map<String, Object> getData(Object entity, Class<?> clazz,
            Set<String> needProperties) throws Exception {
        Set<String> simpleProperties = getSimpleProperties(needProperties);
        Set<String> properties = getPropertyNames(clazz, simpleProperties);
        Map<String, Object> data = new HashMap<String, Object>();
        for (String property : properties) {
            if (!simpleProperties.contains(property)) {
                continue;
            }
            try {
                Set<String> childrenProperties = getChildProperties(needProperties, property);
                Method gMethod = clazz.getMethod("get".concat(StringUtils.capitalize(property)));
                Object value = gMethod.invoke(entity);
                if (value == null) {
                    continue;
                } else if (CollectionUtils.isEmpty(childrenProperties)) {
                    if (value instanceof java.sql.Date) {
                        value = new java.util.Date(((java.sql.Date) value).getTime());
                    }
                    // 如果没有子属性,就把他当做整体输出
                    data.put(property, value);
                    continue;
                }
                if (value instanceof Collection) {
                    // 集合类对象全部以list形式输出
                    Collection c = (Collection) value;
                    List list = new ArrayList();
                    for (Object o : c) {
                        Map<String, Object> element = getData(o, o.getClass(), childrenProperties);
                        list.add(element);
                    }
                    data.put(property, list);
                } else {
                    // 一对一级联对象
                    data.put(property, getData(value, value.getClass(), childrenProperties));
                }
            } catch (Exception e) {
                logger.error("transfer error", e);
            }
        }

        return data;
    }

    /**
     * 根据需要的字段属性名获取对象中的字段属性名
     * 只取对象中有的属性,忽略needProperties中多余的属性,保证程序不报错
     * @param clazz
     * @return
     */
    public static Set<String> getPropertyNames(Class<?> clazz, Set<String> needProperties) {
        final BeanWrapper src = new BeanWrapperImpl(clazz);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> properties = new HashSet<String>();
        for (java.beans.PropertyDescriptor pd : pds) {
            if (!"class".equals(pd.getName()) && needProperties.contains(pd.getName())) { // 排除掉getClass方法
                properties.add(pd.getName());
            }
        }
        return properties;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值