????對于線上已經(jīng)在用的接口搁料,要動態(tài)的擴展返回數(shù)據(jù)的字段肛炮,并且不同的調(diào)用商需要的字段不一樣婴谱,為了A客戶增加了一個字段瞬逊,不能把字段返回給B送爸,防止B客戶那邊也要升級接口朝聋。對于開始加一兩個字段我還可以接受:每次返回不同的實例火诸,漸漸的我覺得力不從心了该窗,代碼重復太多了酌心,就想到了能不能動態(tài)的添加字段呢拌消?
首先引入maven依賴:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
代碼中使用:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
import org.apache.commons.beanutils.PropertyUtilsBean;
import java.beans.PropertyDescriptor;
import java.util.Map;
/**
* @author: jack
* @Date: 2019/5/15 21:30
* @Description: 動態(tài)添加類的屬性
*/
public class ReflectUtil {
public static Object getTarget(Object dest, Map<String, Object> addProperties) {
PropertyUtilsBean propertyUtilsBean =new PropertyUtilsBean();
PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);
Map<String, Class> propertyMap = Maps.newHashMap();
for(PropertyDescriptor d : descriptors) {
if(!"class".equalsIgnoreCase(d.getName())) {
propertyMap.put(d.getName(), d.getPropertyType());
}
}
// add extra properties
addProperties.forEach((k, v) -> propertyMap.put(k, v.getClass()));
// new dynamic bean
DynamicBean dynamicBean =new DynamicBean(dest.getClass(), propertyMap);
// add old value
propertyMap.forEach((k, v) -> {
try{
// filter extra properties
if(!addProperties.containsKey(k)) {
dynamicBean.setValue(k, propertyUtilsBean.getNestedProperty(dest, k));
}
}catch (Exception e) {
e.printStackTrace();
}
});
// add extra value
addProperties.forEach((k, v) -> {
try{
dynamicBean.setValue(k, v);
}catch (Exception e) {
e.printStackTrace();
}
});
Object target = dynamicBean.getTarget();
return target;
}
public static class DynamicBean {
/**
* 目標對象
*/
private Object target;
/**
* 屬性集合
*/
private BeanMap beanMap;
public DynamicBean(Class superclass, Map<String, Class> propertyMap) {
this.target = generateBean(superclass, propertyMap);
this.beanMap = BeanMap.create(this.target);
}
/**
* bean 添加屬性和值
*
* @param property
* @param value
*/
public void setValue(String property, Object value) {
beanMap.put(property, value);
}
/**
* 獲取屬性值
*
* @param property
* @return
*/
public Object getValue(String property) {
return beanMap.get(property);
}
/**
* 獲取對象
*
* @return
*/
public Object getTarget() {
return this.target;
}
/**
* 根據(jù)屬性生成對象
*
* @param superclass
* @param propertyMap
* @return
*/
private Object generateBean(Class superclass, Map<String, Class> propertyMap) {
BeanGenerator generator =new BeanGenerator();
if(null != superclass) {
generator.setSuperclass(superclass);
}
BeanGenerator.addProperties(generator, propertyMap);
return generator.create();
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class Student {
private String name;
private String email;
}
public static void main(String[] args) throws Exception{
Student student = Student.builder().name("jack").email("xy123zk@163.com").build();
System.out.println(student.toString());
Map<String,Object> properties = Maps.newHashMap();
properties.put("address","浙江杭州");
properties.put("age",26);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(getTarget(student,properties));
System.out.println(json);
}
}
結果:
image.png
在spring集成的web項目可以直接使用spring提供的類,可以把依賴的
net.sf.cglib.beans.BeanGenerator
和net.sf.cglib.beans.BeanMap
直接換成org.springframework.cglib.beans.BeanGenerator
和org.springframework.cglib.beans.BeanMap