using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PTMedicalInsurance.Common; using PTMedicalInsurance.Variables; using System; using System.Collections.Generic; using System.IO; using System.Reflection; namespace PTMedicalInsurance.Helper { /// /// 将json转换为实体对象 /// public class JsonMapper { const string ArrayPattern = "[]"; private string jsonConfig; private string configFile; private JsonMappingSetting setting; public JsonMapper(string name) { configFile = Global.curEvt.path + "/config/" + name + ".json"; reload(); } public void reload() { try { // 加载字段映射配置 if (File.Exists(configFile)) { jsonConfig = File.ReadAllText(configFile); setting = JsonHelper.toObject(JObject.Parse(jsonConfig)); } else { setting = new JsonMappingSetting(); } } catch (Exception ex) { throw new Exception("配置文件异常:"+ex.Message); } } /// /// 获取入参映射 /// /// public List GetInputMapping() { return setting.Input??new List(); } /// /// 设置入参 /// /// public void SetInputMapping(List value) { setting.Input = value; } /// /// 获取出参映射 /// /// public List GetOutputMapping() { return setting.Output ?? new List(); } /// /// 设置出参 /// /// public void SetOutputMapping(List value) { setting.Output = value; } /// /// 获取转换类 /// /// private ConvertMapping GetConverter() { return setting.Convert??new ConvertMapping(); } /// /// 根据实体类获取Json /// /// /// private string GetConvertJson(string typeName) { if (!string.IsNullOrEmpty(typeName)) { if (typeName.IndexOf(".")<1) { typeName = "PTMedicalInsurance.Entity.Local." + typeName; } Type type = Type.GetType(typeName); if (type != null) { Object obj = Activator.CreateInstance(type); return JsonHelper.toJsonString(obj, false); } } return string.Empty; } /// /// 将参数方向对调 /// public void ChangeDirection(List mappings) { mappings.ForEach((map) => { if (!string.IsNullOrEmpty(map.Source) && !string.IsNullOrEmpty(map.Target)) { string orgin = map.Target; map.Target = map.Source; map.Source = orgin; } }); } /// /// 入参实例JSON /// /// public string GetInputJson() { return GetConvertJson(GetConverter()?.Input); } /// /// 出参实例JSON /// /// public string GetOutputJson() { return GetConvertJson(GetConverter()?.Output); } /// /// Json字段映射 /// /// /// private JObject MapJson(string key,JObject jSource) { JObject jObject = new JObject(); if(string.IsNullOrEmpty(jsonConfig) || string.IsNullOrEmpty(key)) { return jSource; } List fieldMappings = "input".Equals(key) ? GetInputMapping() : GetOutputMapping() ; if (fieldMappings != null) { // 对于每一个字段映射信息 foreach (var fieldMapping in fieldMappings) { if (!string.IsNullOrEmpty(fieldMapping.Target)) { // 单一映射或一对多统一处理 string[] targets = fieldMapping.Target.Split(",".ToCharArray()); List fields = new List(); foreach (var t in targets) { fields.Add(new FieldMapping() { Source = fieldMapping.Source, Expression = fieldMapping.Expression, Target = t, Value = fieldMapping.Value, Child = fieldMapping.Child }) ; } fields.ForEach((f) => { MapItem(f,jSource,jObject); }); } else { MapItem(fieldMapping, jSource, jObject); } } } return jObject; } private void MapItem(FieldMapping fieldMapping, JObject jSource, JObject jObject) { // 使用JToken.SelectToken来获取源路径对应的值 dynamic value = new JValue(""); string nameKey = fieldMapping.Source; string expression = fieldMapping.Expression; if (!string.IsNullOrEmpty(nameKey) && string.IsNullOrEmpty(fieldMapping.Value)) { nameKey = nameKey.Split(",".ToCharArray())[0]; //多对一忽略后面的 //TODO: 多对一时支持按指定连接符进行连接 if (fieldMapping.Child != null) { //数组映射 nameKey = nameKey.Replace(ArrayPattern, ""); } else { if (nameKey.Contains(ArrayPattern)) { //数组映射对象时,取第一个 nameKey = nameKey.Replace(ArrayPattern, "[0]"); } } value = jSource.SelectToken(nameKey); } else if (fieldMapping.Value != null) { // 支持固定值 value = new JValue(fieldMapping.Value); } // 表达式(全局变量) if ((expression ?? "").Equals("GlobaVariables")) { value = GetExpressionValue(expression, fieldMapping.Source); expression = null; } // 表达式(扩展字段) if ((expression ?? "").Equals("SaveToExpand")) { SetExpression(expression, fieldMapping.Source, value); return; } string converter = "ShortDate,NoSplitDate,ConvertToString"; if (expression!=null && converter.IndexOf(expression)!=-1) { value = GetExpressionValue(expression, value); expression = null; } // 普通转换 if (value != null) { if (fieldMapping.Child != null) { Type type = value.GetType(); var items = new JArray(); //如果为JValue,则为一对多(忽略此时的name) if (type == typeof(JValue)) { JObject sub = new JObject(); // 此时只返回一条数据的集合 fieldMapping.Child.ForEach((c) => { MapItem(c, jSource, sub); }); items.Add(sub); } else if (type == typeof(JArray)) { //数组映射,此时的value为array foreach (var item in (JArray)value) { var child = MapChildItem((JObject)item, fieldMapping.Child); items.Add(child); } } CreateJObjectFromString(jObject, fieldMapping.Target.Replace(ArrayPattern, ""), items, 0); } else { ParseAndMap(value, jObject, nameKey, fieldMapping.Target, expression); } } } /// /// 映射子对象 /// /// /// /// private JObject MapChildItem(JObject itemObject, List childs) { JObject newItem = new JObject(); foreach (FieldMapping subMapping in childs) { if (subMapping.Value != null) { newItem[subMapping.Target] = subMapping.Value; } else { newItem[subMapping.Target] = itemObject[subMapping.Source]; } } return newItem; } /// /// 映射实体 /// /// 源对象 /// 目标对象 /// 名称 /// 源数据 /// public TTarget Map(string key, TSource sourceItem) { var json = JsonConvert.SerializeObject(sourceItem); var jObject = JObject.Parse(json); // 映射 JObject jRet = MapJson(key,jObject); // 然后将修改后的JObject再转化到目标类型的对象 var targetItem = jRet.ToObject(); return targetItem; } /// /// 解析对象后转换为JObject /// /// /// /// /// //[Obsolete("建议使用Map方法")] private JObject MapObject(string key,TSource sourceItem) { TTarget target = Map(key,sourceItem); var json = JsonConvert.SerializeObject(target); return JObject.Parse(json); } /// /// 入参映射 /// /// /// /// /// public JObject MapRequest(TSource sourceItem) { TTarget target = Map("input",sourceItem); var json = JsonConvert.SerializeObject(target); return JObject.Parse(json); } /// /// 出参映射 /// /// /// /// /// public JObject MapResponse(TSource sourceItem) { TTarget target = Map("output", sourceItem); var json = JsonConvert.SerializeObject(target); return JObject.Parse(json); } /// /// 解析并映射字段 /// /// /// /// /// private void ParseAndMap(JToken sourceToken, JObject targetObject, string sourcePath, string targetPath, string expression = "") { // 支持映射多个字段 var targetFields = targetPath.Split(','); foreach (var targetField in targetFields) { //if (!sourceToken.HasValues && string.IsNullOrEmpty(sourceToken.Value())) continue; ParseAndMapField(sourceToken, targetObject, sourcePath, targetField, expression); } } /// /// 解析并映射单个字段 /// /// /// /// /// private void ParseAndMapField(JToken value, JObject targetObject, string sourcePath, string targetPath, string expression = "") { if (string.IsNullOrEmpty(targetPath)) return; if (sourcePath !=null && sourcePath.StartsWith(".")) { sourcePath = sourcePath.Substring(1); } if (targetPath.StartsWith(".")) { targetPath = targetPath.Substring(1); } var targetTokens = targetPath.Split('.'); var remainingTargetPath = string.Join(".", targetTokens, 0, targetTokens.Length - 1); var isArray = remainingTargetPath.Contains(ArrayPattern); var remainingTargetTokens = remainingTargetPath.Split(ArrayPattern.ToCharArray()); //var value = sourceToken.SelectToken(sourcePath); // 抵达路径顶点 if (targetTokens.Length == 1) { targetObject.Add(targetTokens[0], value); return; } // 处理数组类型的映射 if (isArray) { if (value is JValue) { // 将固定数据给数组中的第一个对象 var newItem = (targetObject[targetTokens[0]] ?? new JObject()) as JObject; CreateJObjectFromString(newItem, targetPath, (JValue)value,1,expression); targetObject[targetTokens[0]] = newItem; } //if (value is JArray) //{ // string[] childPath = sourcePath.Split(ArrayPattern.ToCharArray()); // string[] destPath = targetPath.Split(ArrayPattern.ToCharArray()); // string arrayKey = targetTokens[0].Split(ArrayPattern.ToCharArray())[0]; // var newItem = (targetObject[arrayKey] ?? new JArray()) as JArray; // //CreateJObjectFromString(newItem, targetPath, null,0); // foreach (var item in ((JArray)value).Children()) // { // var childItem = new JObject(); // ParseAndMapField(item.SelectToken(childPath[2].Substring(1)), childItem, childPath[2], destPath[2]); // 递归处理嵌套路径 // newItem.Add(childItem); // } // targetObject[arrayKey] = newItem; //} } else if (targetTokens.Length > 1) { // 对象层级 string nameKey = targetTokens[0]; int index = 1; //不包含根节点 if (nameKey.Contains("[]")) { nameKey = nameKey.Substring(0, nameKey.Length - 2); index = 0; } var newItem = (targetObject[nameKey] ?? new JObject()) as JObject; CreateJObjectFromString(newItem,targetPath,(JValue)value, index, expression); targetObject[nameKey] = newItem; } else // 普通嵌套映射 { var newItem = new JObject(); ParseAndMapField(value, newItem, sourcePath, remainingTargetPath); // 递归处理嵌套路径 targetObject.Add(targetTokens[0], newItem); } targetObject.Remove(sourcePath); } /// /// 根据层级创建对象 /// /// /// /// /// private JObject CreateJObjectFromString(JObject current, string input,JToken value,int index = 1,string expression = "") { var keys = input.Split('.'); JObject root = current; for (int i = index; i < keys.Length - 1; i++) { if (keys[i].EndsWith("[]")) { string actualKey = keys[i].Substring(0, keys[i].Length - 2); if (current[actualKey] == null) { current[actualKey] = new JArray { new JObject() }; } // 数组的某一条 current = (JObject)((JArray)current[actualKey]).Last; ; } else { if (current[keys[i]] == null) { current[keys[i]] = new JObject(); } current = (JObject)current[keys[i]]; } } if (!string.IsNullOrEmpty(expression)) { value = GetExpressionValue(expression, value); } current[keys[keys.Length - 1]] = value; return root; } private void SetExpression(string method, string key,object value) { try { Type type = typeof(ExpressionEvaluator); MethodInfo mi = type.GetMethod(method); if (mi != null) { mi.Invoke(null, new object[] {key,value }); } } catch (Exception e) { } } private string GetExpressionValue(string method,object value) { object objRtn = null; try { Type type = typeof(ExpressionEvaluator); MethodInfo mi = type.GetMethod(method); if (mi != null) { objRtn = mi.Invoke(null, new object[] { value }); } } catch (Exception e) { } return objRtn?.ToString(); } /// /// 保存配置 /// public void Save() { jsonConfig = JsonHelper.toJsonString(this.setting); if(!string.IsNullOrEmpty(jsonConfig) && !string.IsNullOrEmpty(configFile)) { File.WriteAllText(configFile,jsonConfig); } } } public class JsonMappingSetting { public List Input { set; get; } public List Output { set; get; } public ConvertMapping Convert { set; get; } } public class FieldMapping { public string Source { get; set; } public string Target { get; set; } public string Value { get; set; } public string Expression { set; get; } public string Name { get; set; } public List Child { get; set; } public FieldMapping() { } } public class ConvertMapping { public string Input { set; get; } public string Output { set; get; } } }