using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Text.Json; using System.Collections.Generic; using medical.transfomer.entity; using Newtonsoft.Json.Linq; using Polly; using Polly.Retry; using Polly.CircuitBreaker; using Microsoft.Extensions.Logging; using SqlSugar; using ReZero.DependencyInjection; using System.Reflection; using System.Linq; using Polly.Timeout; using System.Threading; namespace medical.transfomer.business { /// /// 医保转换工厂,负责动态转换和HTTP请求处理 /// public class TransformerFactory : IScopeContract { private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; private readonly ISqlSugarClient _db; private readonly ResiliencePipeline _resiliencePipeline; public TransformerFactory(IHttpClientFactory httpClientFactory, ILogger logger, ISqlSugarClient db) { _httpClientFactory = httpClientFactory; _logger = logger; _db = db; // 在Polly 8.x中,我们使用ResiliencePipelineBuilder来创建弹性管道 var pipelineBuilder = new ResiliencePipelineBuilder(); // 添加重试策略 pipelineBuilder.AddRetry(new RetryStrategyOptions { ShouldHandle = new PredicateBuilder() .Handle() .HandleResult(r => !r.IsSuccessStatusCode), MaxRetryAttempts = 3, Delay = TimeSpan.FromSeconds(1), BackoffType = DelayBackoffType.Exponential, OnRetry = args => { _logger.LogWarning($"重试第 {args.AttemptNumber} 次,等待 {args.RetryDelay.TotalSeconds} 秒"); return ValueTask.CompletedTask; } }); // 添加断路器策略 pipelineBuilder.AddCircuitBreaker(new CircuitBreakerStrategyOptions { ShouldHandle = new PredicateBuilder() .Handle() .HandleResult(r => !r.IsSuccessStatusCode), FailureRatio = 0.5, // 50%失败率 MinimumThroughput = 10, // 最小样本数 SamplingDuration = TimeSpan.FromSeconds(30), // 采样时间窗口 BreakDuration = TimeSpan.FromMinutes(1), // 断路时间 OnOpened = args => { _logger.LogError($"断路器已断开,将在 {args.BreakDuration.TotalSeconds} 秒后尝试恢复"); return ValueTask.CompletedTask; }, OnClosed = _ => { _logger.LogInformation("断路器已关闭,恢复正常操作"); return ValueTask.CompletedTask; } }); // 添加超时策略 pipelineBuilder.AddTimeout(TimeSpan.FromSeconds(30)); // 构建弹性管道 _resiliencePipeline = pipelineBuilder.Build(); } /// /// 根据方法名执行医保交易 /// /// 方法名称 /// 输入数据 /// 处理结果 public async Task ExecuteMethod(string methodName, JObject inputData) { try { // 1. 获取方法配置 var methodConfig = await _db.Queryable() .FirstAsync(m => m.BIND_SYS_CODE == methodName); if (methodConfig == null) { _logger.LogError($"未找到方法配置: {methodName}"); return new { code = -1, msg = $"未找到方法配置: {methodName}" }; } // 2. 获取输入对象的映射配置 var inputAssembly = await _db.Queryable() .Where(a => a.METHOD_REF == methodConfig.METHOD_ID && a.PARAMETR_TYPE == 1) .ToListAsync(); // 3. 转换输入数据 var convertedInputData = ConvertToMedicalInsuranceObject(inputData, inputAssembly); // 4. 调用医保接口 var responseData = await CallMedicalInsuranceService(methodConfig.METHOD_VALUE, convertedInputData); // 5. 获取输出对象的映射配置 var outputAssembly = await _db.Queryable() .Where(a => a.METHOD_REF == methodConfig.METHOD_ID && a.PARAMETR_TYPE == 2) .ToListAsync(); // 6. 转换输出数据 var convertedOutputData = ConvertToSystemObject(responseData, outputAssembly); // 7. 保存交易记录 if (methodConfig.SAVE_INPUT == 1 || methodConfig.SAVE_OUTPUT == 1) { await SaveTransactionLog(methodConfig, inputData, responseData); } return new { code = 0, msg = "处理成功", data = convertedOutputData }; } catch (Exception ex) { _logger.LogError(ex, $"执行方法 {methodName} 异常"); return new { code = -1, msg = $"执行异常: {ex.Message}" }; } } /// /// 将系统对象转换为医保对象 /// private JObject ConvertToMedicalInsuranceObject(JObject systemObject, List assemblies) { JObject medicalObject = new JObject(); foreach (var assembly in assemblies) { // 获取映射字段 var mappings = _db.Queryable() .Where(m => m.SYSTEM_TABLE_NAME == assembly.MAPPING_TABLE) .ToList(); if (assembly.OBJECT_TYPE == 1) // 单个对象 { JObject targetObject = new JObject(); foreach (var mapping in mappings) { if (mapping.SYSTEM_FIELD != null && mapping.INTERFACE_FIELD != null && !string.IsNullOrEmpty(mapping.SYSTEM_FIELD) && !string.IsNullOrEmpty(mapping.INTERFACE_FIELD)) { // 从系统对象中提取值 var paths = assembly.OBJECT_PATH.Split('.'); JToken currentToken = systemObject; foreach (var path in paths) { if (currentToken != null && currentToken[path] != null) { currentToken = currentToken[path]; } else { currentToken = null; break; } } if (currentToken != null && currentToken[mapping.SYSTEM_FIELD] != null) { targetObject[mapping.INTERFACE_FIELD] = currentToken[mapping.SYSTEM_FIELD]; } } } // 设置到医保对象中 var objectPath = assembly.OBJECT_PATH; if (objectPath.Contains('.')) { var paths = objectPath.Split('.'); JObject current = medicalObject; for (int i = 0; i < paths.Length - 1; i++) { var path = paths[i]; if (current[path] == null || !(current[path] is JObject)) { current[path] = new JObject(); } current = (JObject)current[path]; } current[paths[paths.Length - 1]] = targetObject; } else { medicalObject[objectPath] = targetObject; } } else if (assembly.OBJECT_TYPE == 2) // 列表对象 { JArray targetArray = new JArray(); // 从系统对象中提取列表 var paths = assembly.OBJECT_PATH.Split('.'); JToken currentToken = systemObject; foreach (var path in paths) { if (currentToken != null && currentToken[path] != null) { currentToken = currentToken[path]; } else { currentToken = null; break; } } if (currentToken != null) { JArray sourceArray; // 处理不同类型的JToken if (currentToken is JArray jArray) { sourceArray = jArray; } else if (currentToken is JObject jObject) { // 如果是JObject,将其作为单个元素的数组处理 sourceArray = new JArray { jObject }; } else { // 创建包含当前Token的数组 sourceArray = new JArray { currentToken }; } foreach (JToken sourceItem in sourceArray) { if (sourceItem is JObject sourceObject) { JObject targetItem = new JObject(); foreach (var mapping in mappings) { if (mapping.SYSTEM_FIELD != null && mapping.INTERFACE_FIELD != null && !string.IsNullOrEmpty(mapping.SYSTEM_FIELD) && !string.IsNullOrEmpty(mapping.INTERFACE_FIELD)) { if (sourceObject[mapping.SYSTEM_FIELD] != null) { targetItem[mapping.INTERFACE_FIELD] = sourceObject[mapping.SYSTEM_FIELD]; } } } targetArray.Add(targetItem); } } } // 设置到医保对象中 var objectPath = assembly.OBJECT_PATH; if (objectPath.Contains('.')) { var paths2 = objectPath.Split('.'); JObject current = medicalObject; for (int i = 0; i < paths2.Length - 1; i++) { var path = paths2[i]; if (current[path] == null || !(current[path] is JObject)) { current[path] = new JObject(); } current = (JObject)current[path]; } current[paths2[paths2.Length - 1]] = targetArray; } else { medicalObject[objectPath] = targetArray; } } } return medicalObject; } /// /// 将医保对象转换为系统对象 /// private JObject ConvertToSystemObject(JObject medicalObject, List assemblies) { JObject systemObject = new JObject(); foreach (var assembly in assemblies) { // 获取映射字段 var mappings = _db.Queryable() .Where(m => m.OBJECT_TABLE_NAME == assembly.MAPPING_TABLE) .ToList(); if (assembly.OBJECT_TYPE == 1) // 单个对象 { JObject targetObject = new JObject(); // 从医保对象中提取值 var paths = assembly.OBJECT_PATH.Split('.'); JToken currentToken = medicalObject; foreach (var path in paths) { if (currentToken != null && currentToken[path] != null) { currentToken = currentToken[path]; } else { currentToken = null; break; } } if (currentToken != null && currentToken is JObject sourceObject) { foreach (var mapping in mappings) { if (mapping.INTERFACE_FIELD != null && mapping.SYSTEM_FIELD != null && !string.IsNullOrEmpty(mapping.INTERFACE_FIELD) && !string.IsNullOrEmpty(mapping.SYSTEM_FIELD)) { if (sourceObject[mapping.INTERFACE_FIELD] != null) { targetObject[mapping.SYSTEM_FIELD] = sourceObject[mapping.INTERFACE_FIELD]; } } } } // 设置到系统对象中 systemObject[assembly.MAPPING_TABLE] = targetObject; } else if (assembly.OBJECT_TYPE == 2) // 列表对象 { JArray targetArray = new JArray(); // 从医保对象中提取列表 var paths = assembly.OBJECT_PATH.Split('.'); JToken currentToken = medicalObject; foreach (var path in paths) { if (currentToken != null && currentToken[path] != null) { currentToken = currentToken[path]; } else { currentToken = null; break; } } if (currentToken != null) { JArray sourceArray; // 处理不同类型的JToken if (currentToken is JArray jArray) { sourceArray = jArray; } else if (currentToken is JObject jObject) { // 如果是JObject,将其作为单个元素的数组处理 sourceArray = new JArray { jObject }; } else { // 创建包含当前Token的数组 sourceArray = new JArray { currentToken }; } foreach (JToken sourceItem in sourceArray) { if (sourceItem is JObject sourceObject) { JObject targetItem = new JObject(); foreach (var mapping in mappings) { if (mapping.INTERFACE_FIELD != null && mapping.SYSTEM_FIELD != null && !string.IsNullOrEmpty(mapping.INTERFACE_FIELD) && !string.IsNullOrEmpty(mapping.SYSTEM_FIELD)) { if (sourceObject[mapping.INTERFACE_FIELD] != null) { targetItem[mapping.SYSTEM_FIELD] = sourceObject[mapping.INTERFACE_FIELD]; } } } targetArray.Add(targetItem); } } } // 设置到系统对象中 systemObject[assembly.MAPPING_TABLE] = targetArray; } } return systemObject; } /// /// 调用医保服务接口 /// private async Task CallMedicalInsuranceService(string endpoint, JObject requestData) { var httpClient = _httpClientFactory.CreateClient("MedicalInsurance"); var content = new StringContent( requestData.ToString(), Encoding.UTF8, "application/json"); try { // 使用弹性管道执行HTTP请求 var response = await _resiliencePipeline.ExecuteAsync(async cancellationToken => { return await httpClient.PostAsync(endpoint, content, cancellationToken); }, CancellationToken.None); if (response.IsSuccessStatusCode) { var responseString = await response.Content.ReadAsStringAsync(); return JObject.Parse(responseString); } else { _logger.LogError($"医保接口调用失败: {response.StatusCode}, {await response.Content.ReadAsStringAsync()}"); throw new Exception($"医保接口调用失败: {response.StatusCode}"); } } catch (Exception ex) { _logger.LogError(ex, "调用医保服务异常"); throw; } } /// /// 保存交易日志 /// private async Task SaveTransactionLog(STD_METHOD_CONFIG methodConfig, JObject inputData, JObject outputData) { try { // 创建日志对象 var transLog = new { MethodId = methodConfig.METHOD_ID, MethodName = methodConfig.METHOD_NAME, RequestTime = DateTime.Now, RequestData = methodConfig.SAVE_INPUT == 1 ? inputData.ToString() : null, ResponseTime = DateTime.Now, ResponseData = methodConfig.SAVE_OUTPUT == 1 ? outputData.ToString() : null, Status = 1, // 成功 ErrorMessage = "" }; // 保存到数据库 // TODO: 实际实现中需要定义日志表并保存数据 _logger.LogInformation($"保存交易日志: {JsonSerializer.Serialize(transLog)}"); } catch (Exception ex) { _logger.LogError(ex, "保存交易日志异常"); } } } }