1、pom里引入net.sf.json
<dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <classifier>jdk15</classifier> <version>2.2.3</version> </dependency>
2、外部导入数据,配置映射关系,转为我们需要的实体
2.1 读取json文件得到字符串
public static String readFile(String srcPath) { InputStream input = null; StringBuilder out = null; try { input = TestUtil.class.getResource(srcPath).openStream(); out = new StringBuilder(); byte[] b = new byte[4096]; for (int n; (n = input.read(b)) != -1; ) { out.append(new String(b, 0, n)); } } catch (Exception e) { } finally { try { if (null != input) { input.close(); } } catch (Exception e) { } } if (null != out && out.length() > 0) { return out.toString(); } return ""; }
完整类
import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.springframework.http.MediaType; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.nio.charset.Charset; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; /** * Utility class for testing REST controllers. */ public class TestUtil { public static final MediaType APPLICATION_JSON_UTF8 = new MediaType( MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); private TestUtil() { } /** * Convert an object to JSON byte array. * * @param object * the object to convert * @return the JSON byte array * @throws IOException */ public static byte[] convertObjectToJsonBytes(Object object) throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); JavaTimeModule module = new JavaTimeModule(); mapper.registerModule(module); return mapper.writeValueAsBytes(object); } /** * Create a byte array with a specific size filled with specified data. * * @param size the size of the byte array * @param data the data to put in the byte array * @return the JSON byte array */ public static byte[] createByteArray(int size, String data) { byte[] byteArray = new byte[size]; for (int i = 0; i < size; i++) { byteArray[i] = Byte.parseByte(data, 2); } return byteArray; } /** * A matcher that tests that the examined string represents the same instant as the reference datetime. */ public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher<String> { private final ZonedDateTime date; public ZonedDateTimeMatcher(ZonedDateTime date) { this.date = date; } @Override protected boolean matchesSafely(String item, Description mismatchDescription) { try { if (!date.isEqual(ZonedDateTime.parse(item))) { mismatchDescription.appendText("was ").appendValue(item); return false; } return true; } catch (DateTimeParseException e) { mismatchDescription.appendText("was ").appendValue(item) .appendText(", which could not be parsed as a ZonedDateTime"); return false; } } @Override public void describeTo(Description description) { description.appendText("a String representing the same Instant as ").appendValue(date); } } /** * Creates a matcher that matches when the examined string reprensents the same instant as the reference datetime * * @param date the reference datetime against which the examined string is checked */ public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { return new ZonedDateTimeMatcher(date); } /** * Verifies the equals/hashcode contract on the domain object. */ @SuppressWarnings("unchecked") public static void equalsVerifier(Class clazz) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Object domainObject1 = clazz.getConstructor().newInstance(); assertThat(domainObject1.toString()).isNotNull(); assertThat(domainObject1).isEqualTo(domainObject1); assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()); // Test with an instance of another class Object testOtherObject = new Object(); assertThat(domainObject1).isNotEqualTo(testOtherObject); // Test with an instance of the same class Object domainObject2 = clazz.getConstructor().newInstance(); assertThat(domainObject1).isNotEqualTo(domainObject2); // HashCodes are equals because the objects are not persisted yet assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()); } public static <T> T parseFile(String srcPath, Class<T> clazz) throws IOException { InputStream is = TestUtil.class.getResource(srcPath).openStream(); T result = JSONObject.parseObject(is, clazz); is.close(); return result; } public static <T> List<T> readList(String srcPath, Class<T> clazz) throws IOException, ClassNotFoundException { String text = readFile(srcPath); return JSONConvertUtil.toJavaArray(text, "_class"); } public static String readFile(String srcPath) { InputStream input = null; StringBuilder out = null; try { input = TestUtil.class.getResource(srcPath).openStream(); out = new StringBuilder(); byte[] b = new byte[4096]; for (int n; (n = input.read(b)) != -1; ) { out.append(new String(b, 0, n)); } } catch (Exception e) { } finally { try { if (null != input) { input.close(); } } catch (Exception e) { } } if (null != out && out.length() > 0) { return out.toString(); } return ""; } }
测试
String jsonString = TestUtil.readFile("/test_data/member.json");
2.2 转换
1、实体
public class DataAttribute { /** * 原来的属性 */ private String sourceName; /** 我们需要的属性 */ private String fieldName; /** 数据的类型 */ private AttributeDataType dataType; /** 默认值 */ private String defaultValue;
public class DataStrategy { private String id; /** * 是否有转换 true false 留作判断是否需要转换 */ private boolean mapping; private List<DataAttribute> attributes;
枚举
public enum AttributeDataType { STRING, INTEGER, LONG, DATE, BOOLEAN,; }
转换工具类
package com.datatrategy; import java.lang.reflect.ParameterizedType; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.alibaba.fastjson.JSONObject; public class DataConvertor<T> { private Class<T> tClass; /** * 转换成内部数据结构 * @param tenant 租户ID * @param strategy 转换策略 * @param jsonData 源数据 * @return 目标对象 */ public T toInternal(DataStrategy strategy, String jsonData) { List<DataAttribute> attributes = strategy.getAttributes(); JSONObject json = JSONObject.parseObject(jsonData); JSONObject result = new JSONObject(); for (DataAttribute attribute : attributes) { result.put(attribute.getFieldName(), mappingInternal(json, attribute)); } Map<String, Object> itemMap = JSONObject.toJavaObject(json, Map.class); Map extension = new HashMap<>(); Set<String> keySet = itemMap.keySet(); for (String key : keySet) { boolean flag = false; for (DataAttribute attribute : attributes) { if(key.equals(attribute.getSourceName())){ flag = true; break; } } if(!flag){ extension.put(key, itemMap.get(key)); } } result.put("extension",extension); return result.toJavaObject(result, getTClass()); // return result.toJavaObject(getTClass()); } /** * 有映射规则的字段 * @param json * @param attribute * @return */ private Object mappingInternal(JSONObject json, DataAttribute attribute){ // TODO 实现逻辑 Object result =""; switch (attribute.getDataType()) { case STRING: result = json.getString(attribute.getSourceName()); break; case INTEGER: result = json.getInteger(attribute.getSourceName()); break; case LONG: result = json.getLong(attribute.getSourceName()); break; case BOOLEAN: result = json.getBoolean(attribute.getSourceName()); break; case DATE: // TODO 考虑日期格式 result = json.getDate(attribute.getSourceName()); break; default: result = json.get(attribute.getSourceName()); break; } return result; } private Class<T> getTClass() { if(tClass == null){ tClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } return tClass; } }
extend是
Json转Map 这样就知道所有的key了 ,然后定义的规则没有的字段放入Map里
测试
接受实体
public class Member { private String memberId; /** 存放对方给了 但是我们没有的字段*/ private Map extension; private String name; private String gender;
转换工具类
public class MemberConvertor extends DataConvertor<Member>{ }
补充转List
public List<T> toInternals(String tenant, DataStrategy strategy, String jsonData) { JSONArray jsonArray = JSON.parseArray(jsonData); List<T> result = new ArrayList<>(); for (int i = 0; i < jsonArray.size(); i++){ JSONObject jsonObject = jsonArray.getJSONObject(i); result.add(toInternal(tenant,strategy,JSONObject.toJSONString(jsonObject))); } return result; }
Json数组 循环
外部实体对象
public class SourMember { private String id; private String name; private String gender; private int age;
分析
age 字段我们没有,按照我们设想应该是进入map里
id的值转换到memberI里
测试
public static void main(String[] args) { SourMember attr = new SourMember(); attr.setGender("man"); attr.setId("001"); attr.setName("kebi"); attr.setAge(123); String jsonData = JSONObject.toJSONString(attr); DataStrategy strategy = new DataStrategy(); strategy.setMapping(true); List<DataAttribute> attributes = new ArrayList<>(); attributes.add(createDataAttribute(AttributeDataType.STRING, "memberId", "id")); attributes.add(createDataAttribute(AttributeDataType.STRING, "name", "name")); attributes.add(createDataAttribute(AttributeDataType.STRING, "gender", "gender")); strategy.setAttributes(attributes); MemberConvertor conv = new MemberConvertor(); Member member = conv.toInternal(strategy, jsonData); System.out.println(member); }
结果
Member [memberId=001, extension={age=123}, name=kebi, gender=man]
策略 存储到数据库里
DataStrategy
考虑 根据id查询策略的时候,如果数据很多,每一次查询数据库显得太频繁,使用redis 做缓存
2、属性里包含对象或者集合处理办法
添加枚举类型
public enum AttributeDataType { STRING, INTEGER, LONG, DATE, BOOLEAN,CLAZZ,LISTCLAZZ; }
case CLAZZ: result = JSONObject.parseObject(json.getString(attribute.getSourceName())); break; case LISTCLAZZ: result = JSON.parseArray(json.getString(attribute.getSourceName())); break; default:
测试
public class SourMember { private String id; private String name; private String gender; private String birday; private List<Friend> friendList; private Car car;
属性里面新增了Car 和List
引用
DataAttribute carDataAttr = createDataAttribute(AttributeDataType.CLAZZ, "car", "car"); DataAttribute friendDataAttr = createDataAttribute(AttributeDataType.CLAZZ, "friendList", "friendList");