package com.fxiaoke.open.proxy.groovy; import cn.hutool.core.util.ObjectUtil; import com.fxiaoke.open.proxy.SAPMetaDetailResult; import com.fxiaoke.open.proxy.SapFunctionParamsArg; import com.fxiaoke.open.proxy.SapPropertiesArg; import com.fxiaoke.open.proxy.result.SapMetaDataResult; import com.fxiaoke.open.proxy.result.SapResult; import com.fxiaoke.open.proxy.service.SapGroovyService; import com.fxiaoke.open.proxy.util.XmlToMapUtil; import com.fxiaoke.open.proxy.constants.ResultEnum; import com.fxiaoke.open.proxy.result.Result; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.sap.conn.jco.*; import com.sap.conn.jco.ext.DestinationDataProvider; import org.apache.commons.collections4.MapUtils; import org.dom4j.DocumentException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.io.File; import java.io.FileOutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.stream.Collectors; /** * @author keny8354 * @create 2024/8/15 11:39 * @desc */ @Component class SapGroovyServiceImpl implements SapGroovyService{ private static final String ABAP_AS_POOLED = "ABAP_AS_WITH_POOL"; private JCoDestination jCoDestination; Logger log = LoggerFactory.getLogger("GroovyLogger"); @Override public Result executeRfcMethod(SapFunctionParamsArg sapFunctionParamsArg, SapPropertiesArg sapPropertiesArg) { initializeConnectionIfNeeded(sapPropertiesArg); return execute(sapFunctionParamsArg,jCoDestination); } private synchronized void initializeConnectionIfNeeded(SapPropertiesArg sapPropertiesArg) { if(ObjectUtil.isEmpty(jCoDestination)){ jCoDestination=connect(sapPropertiesArg); } } @Override public Result executeMeta(String functionName, SapPropertiesArg sapPropertiesArg) { try { initializeConnectionIfNeeded(sapPropertiesArg); // SapMetaDataResult sapMetaDataResult=new SapMetaDataResult(); // Step 2: 获取函数 JCoFunction function = jCoDestination.getRepository().getFunction(functionName); if (function == null) { throw new RuntimeException("BAPI_MATERIAL_SAVEDATA not found in SAP."); } // 获取函数的元数据 JCoParameterList importParams = function.getImportParameterList(); JCoParameterList exportParams = function.getExportParameterList(); JCoParameterList tableParams = function.getTableParameterList(); List sapImportDatas = printParameterList(importParams); sapMetaDataResult.setImportParams(sapImportDatas); List sapExportParams = printParameterList(exportParams); sapMetaDataResult.setExportParams(sapExportParams); List sapTableParams = printParameterList(tableParams); sapMetaDataResult.setTableParams(sapTableParams); return Result.newSuccess(sapMetaDataResult); } catch (JCoException e) { e.printStackTrace(); } return Result.newSuccess(); } @Override public Result connectSap(SapPropertiesArg sapPropertiesArg) { log.warn("sapManager function output data is null :{}",sapPropertiesArg); this.initializeConnectionIfNeeded(sapPropertiesArg); return Result.newSuccess(); } // 打印参数列表 private static List printParameterList(JCoParameterList paramList) { List paramsList= Lists.newArrayList(); if (paramList != null) { for (int i = 0; i < paramList.getFieldCount(); i++) { SAPMetaDetailResult sapMetaDetailResult=new SAPMetaDetailResult(); String paramName = paramList.getMetaData().getName(i); JCoMetaData metaData = paramList.getMetaData(); String paramType = metaData.getTypeAsString(i); String description = metaData.getDescription(i); sapMetaDetailResult.setParameterName(paramName); sapMetaDetailResult.setParameterType(paramType); sapMetaDetailResult.setParameterDesc(description); // 如果是表或结构,进一步获取其字段描述 if (metaData.isStructure(i)) { JCoStructure structure = paramList.getStructure(paramName); List sapMetaDetailResults = printStructureMetaData(structure.getMetaData()); sapMetaDetailResult.setParameterItems(sapMetaDetailResults); } else if (metaData.isTable(i)) { JCoTable table = paramList.getTable(paramName); List sapMetaDetailResults = printTableMetaData(table.getMetaData()); sapMetaDetailResult.setParameterItems(sapMetaDetailResults); } paramsList.add(sapMetaDetailResult); } } return paramsList; } // 打印表的元数据 private static List printTableMetaData(JCoMetaData metaData) { List sapMetaDetailResults=Lists.newArrayList(); for (int i = 0; i < metaData.getFieldCount(); i++) { SAPMetaDetailResult sapMetaDetailResult=new SAPMetaDetailResult(); String fieldName = metaData.getName(i); String fieldType = metaData.getTypeAsString(i); String fieldDescription = metaData.getDescription(i); sapMetaDetailResult.setParameterName(fieldName); sapMetaDetailResult.setParameterDesc(fieldDescription); sapMetaDetailResult.setParameterType(fieldType); sapMetaDetailResults.add(sapMetaDetailResult); } return sapMetaDetailResults; } // 打印结构的元数据 private static List printStructureMetaData(JCoMetaData metaData) { List sapMetaDetailResults=Lists.newArrayList(); for (int i = 0; i < metaData.getFieldCount(); i++) { SAPMetaDetailResult sapMetaDetailResult=new SAPMetaDetailResult(); String fieldName = metaData.getName(i); String fieldType = metaData.getTypeAsString(i); String fieldDescription = metaData.getDescription(i); sapMetaDetailResult.setParameterName(fieldName); sapMetaDetailResult.setParameterDesc(fieldDescription); sapMetaDetailResult.setParameterType(fieldType); sapMetaDetailResults.add(sapMetaDetailResult); } return sapMetaDetailResults; } private Result execute(SapFunctionParamsArg sapFunctionParamsArg,JCoDestination destination){ SapResult sapResult=new SapResult(); // 创建一个与SAP系统的连接 if(ObjectUtil.isEmpty(sapFunctionParamsArg.getFunctionName())){ return Result.newError(ResultEnum.SAP_RFC_FUNCTION_NAME_IS_NULL); } String functionName= sapFunctionParamsArg.getFunctionName(); try { // 调用函数 JCoFunction function = destination.getRepository().getFunction(functionName); if(null == function) { return Result.newError(ResultEnum.SAP_RFC_FUNCTION_IS_ERROR); } if(ObjectUtil.isNotEmpty(sapFunctionParamsArg.getImportParamsValues())){ Map importParamsValues = sapFunctionParamsArg.getImportParamsValues(); //入参结构 JCoParameterList importParameterList = function.getImportParameterList(); if (importParameterList != null) { // 遍历参数列表,判断每个参数的类型 for (JCoField field : importParameterList) { String paramName = field.getName(); if (field.isStructure()) { log.info("Parameter " + paramName + " is a structure."); JCoStructure structure = importParameterList.getStructure(paramName); // 处理结构参数 Map structMap = (Map) importParamsValues.get(paramName); handleStructure(structure,structMap); } else if (field.isTable()) { log.error("Parameter " + paramName + " is a table."); throw new RuntimeException("sapconnect input params is table ,please setting tableparams:设置参数是表参数,请设置在tableparams{}"+paramName); } else { log.info("Parameter " + paramName + " is a scalar (simple field)."); Object scalarValue = importParamsValues.get(paramName); // 处理标量参数 field.setValue(scalarValue); } } } } if(ObjectUtil.isNotEmpty(sapFunctionParamsArg.getTableParams())){ Map> tableParams = sapFunctionParamsArg.getTableParams(); JCoParameterList tableParameterList = function.getTableParameterList(); if (MapUtils.isNotEmpty(tableParams) && tableParameterList != null) { tableParams.forEach((tableName, tableDatas) -> { // 设置输入参数为表的数据 JCoTable importTable = tableParameterList.getTable(tableName); for (Object tableData : tableDatas) { // 设置第一行数据 importTable.appendRow(); Map ObjectDataMap= (Map) tableData; ObjectDataMap.forEach((k, v) -> { importTable.setValue(k, v); }); } }); } } function.execute(destination); if(ObjectUtil.isNotEmpty(sapFunctionParamsArg.getOutTablesNames())){ Map dataMap= Maps.newHashMap(); List outTablesNames = sapFunctionParamsArg.getOutTablesNames(); for (String outTablesName : outTablesNames) { JCoParameterList tableParameterList = function.getTableParameterList(); if(ObjectUtil.isEmpty(tableParameterList)){ log.warn("sapManager function output tableParameterList is null :{}",function); continue; } JCoTable output = function.getTableParameterList().getTable(outTablesName); if(ObjectUtil.isEmpty(output)){ log.warn("sapManager function output data is null :{}",outTablesName); continue; } String xmlMsg = output.toXML(); //xml转map Map dataXml = XmlToMapUtil.xml2map(xmlMsg,false); dataMap.put(outTablesName,dataXml); } sapResult.setTableData(dataMap); } if(ObjectUtil.isNotEmpty(sapFunctionParamsArg.getReturnParamsField())){ List returnParamsField = sapFunctionParamsArg.getReturnParamsField(); JCoParameterList exportParameterList = function.getExportParameterList(); Map data = new HashMap(); returnParamsField.forEach(item -> { String dataXml = exportParameterList.getStructure(item).toXML(); log.info("return parames field data:{}",dataXml); if(ObjectUtil.isNotEmpty(dataXml)){ Map dataMap = null; try { dataMap = XmlToMapUtil.xml2map(dataXml, false); } catch (DocumentException e) { log.error("sapManager execute xml2map message:{}", e); } data.put(item, dataMap); } }); sapResult.setExportParamsData(data); } //主从数据,大量数据需要做分页返回。内存做一下缓存,避免多次访问 if(ObjectUtil.isNotEmpty(sapFunctionParamsArg.getBatchQueryArg())){ String masterApiName = sapFunctionParamsArg.getBatchQueryArg().getMasterApiName(); Map>> masterDataMap= ( Map>>) sapResult.getTableData().get(masterApiName); String masterFieldName=sapFunctionParamsArg.getBatchQueryArg().getMasterFieldName(); Map>> idMasterDataMap = masterDataMap.get("item").stream().collect(Collectors.groupingBy(entity -> entity.get(masterFieldName))); SapResult.StandardObjectData standardObjectData=new SapResult.StandardObjectData(); standardObjectData.setObjAPIName(masterApiName); List standardObjectDatas=Lists.newArrayList(); for (String detailApiName : sapFunctionParamsArg.getBatchQueryArg().getDetailApiNames()) { Map>> detailObjDataMap= ( Map>>) sapResult.getTableData().get(detailApiName); Map>> detailObjDataByMasterId = detailObjDataMap.get("item").stream().collect(Collectors.groupingBy(entity -> String.valueOf(entity.get(detailApiName)))); Map>> detailObjData=Maps.newHashMap(); for (String masterDetailId : detailObjDataByMasterId.keySet()) { List> masterObj = idMasterDataMap.get(masterDetailId); List> detailObj = detailObjDataByMasterId.get(masterDetailId);//从对象 SapResult.StandardObjectData objectData= new SapResult.StandardObjectData(); objectData.setMasterFieldVal(masterObj.get(0)); detailObjData.put(detailApiName,detailObj); objectData.setDetailFieldVals(detailObjData); standardObjectDatas.add(objectData); } } } } catch (Exception e) { log.error("sapManager execute error message:{}",e.getMessage()); return Result.newError(ResultEnum.SYSTEM_ERROR.getErrorCode(),e.getMessage()); } return Result.newSuccess(sapResult); } /** * 创建sap接口属性文件 * @param name * @param suffix * @param properties */ private static void createDataFile(String name, String suffix, Properties properties) { File cfg = new File(name + "." + suffix); if (cfg.exists()) { //删除旧文件,避免配置没有更新 cfg.deleteOnExit(); } try { FileOutputStream fos = new FileOutputStream(cfg, false); properties.store(fos, "for tests only !"); fos.close(); } catch (Exception e) { System.out.println("Create Data file fault, error msg: " + e.toString()); throw new RuntimeException("Unable to create the destination file 创建文件失败 " + cfg.getName(), e); } } /** * 获取sap连接 * @return */ public JCoDestination connect(SapPropertiesArg sapPropertiesArg) { //判断参数 sapPropertiesArg.validParams(); Properties connectProperties = new Properties(); connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, sapPropertiesArg.getJCO_ASHOST()); connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, sapPropertiesArg.getJCO_SYSNR()); connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, sapPropertiesArg.getJCO_CLIENT()); connectProperties.setProperty(DestinationDataProvider.JCO_USER, sapPropertiesArg.getJCO_USER()); connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, sapPropertiesArg.getJCO_PASSWD()); connectProperties.setProperty(DestinationDataProvider.JCO_LANG, sapPropertiesArg.getJCO_LANG()); connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, sapPropertiesArg.getJCO_POOL_CAPACITY()); connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, sapPropertiesArg.getJCO_PEAK_LIMIT()); createDataFile(ABAP_AS_POOLED, "jcoDestination", connectProperties); JCoDestination destination = null; try { destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED); } catch (JCoException e) { log.error("Connect SAP fault, error msg: " + e.toString()); throw new RuntimeException("连接sap失败 " + e); } return destination; } private static void handleStructure(JCoStructure structure, Map structMap) { if(ObjectUtil.isEmpty(structMap)){ return; } // 处理结构参数的代码 for (Map.Entry entry : structMap.entrySet()) { structure.setValue(entry.getKey(),entry.getValue()); } } private static void handleTable(JCoTable table) { // 处理表参数的代码 for (int i = 0; i < table.getNumRows(); i++) { table.setRow(i); System.out.println(" Table Row " + i); for (JCoField field : table) { String fieldName = field.getName(); Object value = field.getValue(); System.out.println(" Table Field: " + fieldName + " = " + value); } } } private static void handleScalar(String paramName, Object value) { // 处理标量参数的代码 } }