parent
ea87fef5b0
commit
17f1a1670d
@ -0,0 +1,60 @@
|
|||||||
|
package kr.re.etri.autoflow.controllers;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import kr.re.etri.autoflow.service.DatasetService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Tag(name = "Dataset API", description = "외부 데이터셋 목록 조회 API (Python requests 코드 기반)")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/datasets")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ExternalDataSetController {
|
||||||
|
|
||||||
|
private final DatasetService datasetService;
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "데이터셋 목록 조회",
|
||||||
|
description = "외부 API(/export/dataset_list)를 호출하여 데이터셋 목록을 조회합니다."
|
||||||
|
)
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "성공적으로 데이터셋을 조회했습니다."),
|
||||||
|
@ApiResponse(responseCode = "400", description = "잘못된 요청입니다.", content = @Content),
|
||||||
|
@ApiResponse(responseCode = "500", description = "서버 내부 오류", content = @Content)
|
||||||
|
})
|
||||||
|
@GetMapping("/list")
|
||||||
|
public ResponseEntity<?> getDatasetList(
|
||||||
|
@Parameter(description = "프로젝트 인덱스", example = "10")
|
||||||
|
@RequestParam(required = false) Integer ds_prj_idx,
|
||||||
|
@Parameter(description = "검색 키워드", example = "traffic")
|
||||||
|
@RequestParam(required = false) String search_keyword,
|
||||||
|
@Parameter(description = "그룹 이름", example = "AIGroup")
|
||||||
|
@RequestParam(required = false) String grp_name
|
||||||
|
) {
|
||||||
|
Map<String, Object> result = datasetService.getDatasetList(ds_prj_idx, search_keyword, grp_name);
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/download")
|
||||||
|
@Operation(
|
||||||
|
summary = "데이터셋 다운로드",
|
||||||
|
description = "외부 API 서버로 POST 요청을 보내 ZIP 파일을 다운로드합니다.",
|
||||||
|
parameters = {
|
||||||
|
@Parameter(name = "datasetName", description = "다운로드할 데이터셋 이름", in = ParameterIn.QUERY, required = true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
public ResponseEntity<?> downloadDataset(
|
||||||
|
@RequestParam("datasetName") String datasetName
|
||||||
|
) {
|
||||||
|
return datasetService.downloadDataset(datasetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
package kr.re.etri.autoflow.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class DatasetService {
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
private static final String BASE_URL = "http://52.14.11.43:18010";
|
||||||
|
private static final String LIST_ENDPOINT = "/export/dataset_list";
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Map<String, Object> getDatasetList(Integer ds_prj_idx, String search_keyword, String grp_name) {
|
||||||
|
try {
|
||||||
|
// ✅ URL + 파라미터 구성
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(BASE_URL + LIST_ENDPOINT);
|
||||||
|
if (ds_prj_idx != null) builder.queryParam("ds_prj_idx", ds_prj_idx);
|
||||||
|
if (search_keyword != null) builder.queryParam("search_keyword", search_keyword);
|
||||||
|
if (grp_name != null) builder.queryParam("grp_name", grp_name);
|
||||||
|
|
||||||
|
String apiUrl = builder.toUriString();
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
HttpEntity<Void> request = new HttpEntity<>(headers);
|
||||||
|
|
||||||
|
ResponseEntity<Map> response = restTemplate.exchange(
|
||||||
|
apiUrl,
|
||||||
|
HttpMethod.GET,
|
||||||
|
request,
|
||||||
|
Map.class
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, Object> body = response.getBody();
|
||||||
|
|
||||||
|
if (body == null) {
|
||||||
|
return Map.of(
|
||||||
|
"success", false,
|
||||||
|
"message", "API 응답이 비어 있습니다."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = Boolean.TRUE.equals(body.get("success"));
|
||||||
|
if (success) {
|
||||||
|
return Map.of(
|
||||||
|
"success", true,
|
||||||
|
"data", body.get("data"),
|
||||||
|
"total_count", body.get("total_count")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Map.of(
|
||||||
|
"success", false,
|
||||||
|
"message", body.get("message")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Map.of(
|
||||||
|
"success", false,
|
||||||
|
"message", "API 요청 실패: " + e.getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Value("${external.api.base-url:http://52.14.11.43:18010}")
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
private static final String DOWNLOAD_ENDPOINT = "/export/dataset";
|
||||||
|
|
||||||
|
private final WebClient webClient = WebClient.builder()
|
||||||
|
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public ResponseEntity<?> downloadDataset(String datasetName) {
|
||||||
|
String apiUrl = baseUrl + DOWNLOAD_ENDPOINT;
|
||||||
|
log.info("외부 API 요청 URL: {}", apiUrl);
|
||||||
|
log.info("요청 데이터셋 이름: {}", datasetName);
|
||||||
|
|
||||||
|
// 요청 본문(JSON)
|
||||||
|
String requestBody = String.format("{\"dataset_name\":\"%s\"}", datasetName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// WebClient로 외부 API POST 요청
|
||||||
|
return webClient.post()
|
||||||
|
.uri(apiUrl)
|
||||||
|
.bodyValue(requestBody)
|
||||||
|
.exchangeToMono(response -> {
|
||||||
|
if (response.statusCode().equals(HttpStatus.OK)) {
|
||||||
|
// 파일 스트림 수신
|
||||||
|
return response.bodyToMono(byte[].class)
|
||||||
|
.map(bytes -> {
|
||||||
|
ByteArrayResource resource = new ByteArrayResource(bytes);
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
headers.setContentDisposition(ContentDisposition.attachment()
|
||||||
|
.filename(datasetName + ".zip", StandardCharsets.UTF_8)
|
||||||
|
.build());
|
||||||
|
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 오류 응답 처리
|
||||||
|
return response.bodyToMono(String.class)
|
||||||
|
.map(errorBody -> {
|
||||||
|
log.error("다운로드 실패 (HTTP {}): {}", response.statusCode(), errorBody);
|
||||||
|
return ResponseEntity.status(response.statusCode())
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body(errorBody);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.block();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("API 요청 중 오류 발생", e);
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.body("API 요청 중 오류 발생: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in new issue