get요청 db 저장기능
This commit is contained in:
@@ -271,6 +271,14 @@ export class ImprovedButtonActionExecutor {
|
||||
// 2. 관계 타입에 따른 실행
|
||||
const relationships = relationshipData.relationships;
|
||||
const connectionType = relationships.connectionType;
|
||||
|
||||
console.log(`🔍 관계 상세 정보:`, {
|
||||
connectionType,
|
||||
hasExternalCallConfig: !!relationships.externalCallConfig,
|
||||
externalCallConfig: relationships.externalCallConfig,
|
||||
hasDataSaveConfig: !!relationships.dataSaveConfig,
|
||||
dataSaveConfig: relationships.dataSaveConfig,
|
||||
});
|
||||
|
||||
let result: ExecutionResult;
|
||||
|
||||
@@ -339,8 +347,13 @@ export class ImprovedButtonActionExecutor {
|
||||
context: ButtonExecutionContext
|
||||
): Promise<ExecutionResult> {
|
||||
try {
|
||||
console.log(`🔍 외부 호출 실행 시작 - relationships 구조:`, relationships);
|
||||
|
||||
const externalCallConfig = relationships.externalCallConfig;
|
||||
console.log(`🔍 externalCallConfig:`, externalCallConfig);
|
||||
|
||||
if (!externalCallConfig) {
|
||||
console.error('❌ 외부 호출 설정이 없습니다. relationships 구조:', relationships);
|
||||
throw new Error('외부 호출 설정이 없습니다');
|
||||
}
|
||||
|
||||
@@ -394,7 +407,7 @@ export class ImprovedButtonActionExecutor {
|
||||
timeout: restApiSettings.timeout || 30000,
|
||||
retryCount: restApiSettings.retryCount || 3,
|
||||
},
|
||||
templateData: restApiSettings.httpMethod !== 'GET' ? JSON.parse(requestBody) : {},
|
||||
templateData: restApiSettings.httpMethod !== 'GET' && requestBody ? JSON.parse(requestBody) : formData,
|
||||
};
|
||||
|
||||
console.log(`📤 백엔드로 전송할 데이터:`, requestPayload);
|
||||
@@ -412,11 +425,17 @@ export class ImprovedButtonActionExecutor {
|
||||
|
||||
// 데이터 매핑 처리 (inbound mapping)
|
||||
if (externalCallConfig.dataMappingConfig?.inboundMapping) {
|
||||
console.log(`📥 데이터 매핑 설정 발견 - HTTP 메서드: ${restApiSettings.httpMethod}`);
|
||||
console.log(`📥 매핑 설정:`, externalCallConfig.dataMappingConfig.inboundMapping);
|
||||
console.log(`📥 응답 데이터:`, responseData);
|
||||
|
||||
await this.processInboundMapping(
|
||||
externalCallConfig.dataMappingConfig.inboundMapping,
|
||||
responseData,
|
||||
context
|
||||
);
|
||||
} else {
|
||||
console.log(`ℹ️ 데이터 매핑 설정이 없습니다 - HTTP 메서드: ${restApiSettings.httpMethod}`);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -596,28 +615,24 @@ export class ImprovedButtonActionExecutor {
|
||||
connection?: any
|
||||
): Promise<any> {
|
||||
try {
|
||||
// 데이터 저장 API 호출
|
||||
const response = await fetch('/api/dataflow/execute-data-action', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${localStorage.getItem('token')}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
tableName,
|
||||
data,
|
||||
actionType,
|
||||
connection,
|
||||
}),
|
||||
console.log(`💾 테이블 데이터 저장 시작: ${tableName}`, {
|
||||
actionType,
|
||||
data,
|
||||
connection
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`데이터 저장 API 호출 실패: ${response.status}`);
|
||||
}
|
||||
// 데이터 저장 API 호출 (apiClient 사용)
|
||||
const response = await apiClient.post('/dataflow/execute-data-action', {
|
||||
tableName,
|
||||
data,
|
||||
actionType,
|
||||
connection,
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
console.log(`✅ 테이블 데이터 저장 성공: ${tableName}`, response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('데이터 저장 오류:', error);
|
||||
console.error('테이블 데이터 저장 오류:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -670,6 +685,111 @@ export class ImprovedButtonActionExecutor {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 다양한 API 응답 구조에서 실제 데이터 추출
|
||||
*/
|
||||
private static extractActualData(responseData: any): any {
|
||||
console.log(`🔍 데이터 추출 시작 - 원본 타입: ${typeof responseData}`);
|
||||
|
||||
// null이나 undefined인 경우
|
||||
if (!responseData) {
|
||||
console.log(`⚠️ 응답 데이터가 null 또는 undefined`);
|
||||
return [];
|
||||
}
|
||||
|
||||
// 이미 배열인 경우 (직접 배열 응답)
|
||||
if (Array.isArray(responseData)) {
|
||||
console.log(`✅ 직접 배열 응답 감지`);
|
||||
return responseData;
|
||||
}
|
||||
|
||||
// 문자열인 경우 JSON 파싱 시도
|
||||
if (typeof responseData === 'string') {
|
||||
console.log(`🔄 JSON 문자열 파싱 시도`);
|
||||
try {
|
||||
const parsed = JSON.parse(responseData);
|
||||
console.log(`✅ JSON 파싱 성공, 재귀 호출`);
|
||||
return this.extractActualData(parsed);
|
||||
} catch (error) {
|
||||
console.log(`⚠️ JSON 파싱 실패, 원본 문자열 반환:`, error);
|
||||
return [responseData];
|
||||
}
|
||||
}
|
||||
|
||||
// 객체가 아닌 경우 (숫자 등)
|
||||
if (typeof responseData !== 'object') {
|
||||
console.log(`⚠️ 객체가 아닌 응답: ${typeof responseData}`);
|
||||
return [responseData];
|
||||
}
|
||||
|
||||
// 일반적인 데이터 필드명들을 우선순위대로 확인
|
||||
const commonDataFields = [
|
||||
'data', // { data: [...] }
|
||||
'result', // { result: [...] }
|
||||
'results', // { results: [...] }
|
||||
'items', // { items: [...] }
|
||||
'list', // { list: [...] }
|
||||
'records', // { records: [...] }
|
||||
'rows', // { rows: [...] }
|
||||
'content', // { content: [...] }
|
||||
'payload', // { payload: [...] }
|
||||
'response', // { response: [...] }
|
||||
];
|
||||
|
||||
for (const field of commonDataFields) {
|
||||
if (responseData[field] !== undefined) {
|
||||
console.log(`✅ '${field}' 필드에서 데이터 추출`);
|
||||
|
||||
const extractedData = responseData[field];
|
||||
|
||||
// 추출된 데이터가 문자열인 경우 JSON 파싱 시도
|
||||
if (typeof extractedData === 'string') {
|
||||
console.log(`🔄 추출된 데이터가 JSON 문자열, 파싱 시도`);
|
||||
try {
|
||||
const parsed = JSON.parse(extractedData);
|
||||
console.log(`✅ JSON 파싱 성공, 재귀 호출`);
|
||||
return this.extractActualData(parsed);
|
||||
} catch (error) {
|
||||
console.log(`⚠️ JSON 파싱 실패, 원본 문자열 반환:`, error);
|
||||
return [extractedData];
|
||||
}
|
||||
}
|
||||
|
||||
// 추출된 데이터가 객체이고 또 다른 중첩 구조일 수 있으므로 재귀 호출
|
||||
if (typeof extractedData === 'object' && !Array.isArray(extractedData)) {
|
||||
console.log(`🔄 중첩된 객체 감지, 재귀 추출 시도`);
|
||||
return this.extractActualData(extractedData);
|
||||
}
|
||||
|
||||
return extractedData;
|
||||
}
|
||||
}
|
||||
|
||||
// 특별한 필드가 없는 경우, 객체의 값들 중에서 배열을 찾기
|
||||
const objectValues = Object.values(responseData);
|
||||
const arrayValue = objectValues.find(value => Array.isArray(value));
|
||||
|
||||
if (arrayValue) {
|
||||
console.log(`✅ 객체 값 중 배열 발견`);
|
||||
return arrayValue;
|
||||
}
|
||||
|
||||
// 객체의 값들 중에서 객체를 찾아서 재귀 탐색
|
||||
for (const value of objectValues) {
|
||||
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||
console.log(`🔄 객체 값에서 재귀 탐색`);
|
||||
const nestedResult = this.extractActualData(value);
|
||||
if (Array.isArray(nestedResult) && nestedResult.length > 0) {
|
||||
return nestedResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 모든 시도가 실패한 경우, 원본 객체를 단일 항목 배열로 반환
|
||||
console.log(`📦 원본 객체를 단일 항목으로 처리`);
|
||||
return [responseData];
|
||||
}
|
||||
|
||||
/**
|
||||
* 인바운드 데이터 매핑 처리
|
||||
*/
|
||||
@@ -680,29 +800,56 @@ export class ImprovedButtonActionExecutor {
|
||||
): Promise<void> {
|
||||
try {
|
||||
console.log(`📥 인바운드 데이터 매핑 처리 시작`);
|
||||
console.log(`📥 원본 응답 데이터:`, responseData);
|
||||
|
||||
const targetTable = inboundMapping.targetTable;
|
||||
const fieldMappings = inboundMapping.fieldMappings || [];
|
||||
const insertMode = inboundMapping.insertMode || 'insert';
|
||||
|
||||
// 응답 데이터가 배열인 경우 각 항목 처리
|
||||
const dataArray = Array.isArray(responseData) ? responseData : [responseData];
|
||||
console.log(`📥 매핑 설정:`, {
|
||||
targetTable,
|
||||
fieldMappings,
|
||||
insertMode
|
||||
});
|
||||
|
||||
// 응답 데이터에서 실제 데이터 추출 (다양한 구조 지원)
|
||||
let actualData = this.extractActualData(responseData);
|
||||
|
||||
console.log(`📥 추출된 실제 데이터:`, actualData);
|
||||
|
||||
// 배열이 아닌 경우 배열로 변환
|
||||
const dataArray = Array.isArray(actualData) ? actualData : [actualData];
|
||||
|
||||
console.log(`📥 처리할 데이터 배열:`, dataArray);
|
||||
|
||||
if (dataArray.length === 0) {
|
||||
console.log(`⚠️ 처리할 데이터가 없습니다`);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const item of dataArray) {
|
||||
const mappedData: Record<string, any> = {};
|
||||
|
||||
console.log(`📥 개별 아이템 처리:`, item);
|
||||
|
||||
// 필드 매핑 적용
|
||||
for (const mapping of fieldMappings) {
|
||||
const sourceValue = item[mapping.sourceField];
|
||||
if (sourceValue !== undefined) {
|
||||
console.log(`📥 필드 매핑: ${mapping.sourceField} -> ${mapping.targetField} = ${sourceValue}`);
|
||||
|
||||
if (sourceValue !== undefined && sourceValue !== null) {
|
||||
mappedData[mapping.targetField] = sourceValue;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📋 매핑된 데이터:`, mappedData);
|
||||
|
||||
// 데이터 저장
|
||||
await this.saveDataToTable(targetTable, mappedData, insertMode);
|
||||
// 매핑된 데이터가 비어있지 않은 경우에만 저장
|
||||
if (Object.keys(mappedData).length > 0) {
|
||||
await this.saveDataToTable(targetTable, mappedData, insertMode);
|
||||
} else {
|
||||
console.log(`⚠️ 매핑된 데이터가 비어있어 저장을 건너뜁니다`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ 인바운드 데이터 매핑 완료`);
|
||||
|
||||
Reference in New Issue
Block a user