인터페이스 설계서 자동생성DTO

This commit is contained in:
Boram
2026-08-11 16:14:02 +09:00
parent d1f202aa9a
commit 494fbe9c45
5 changed files with 644 additions and 1 deletions

View File

@@ -0,0 +1,72 @@
package io.shinhanlife.dap.mcg.presentation;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientResponseException;
/**
* Gateway 화면에서 들어온 DTO 엑셀 요청을 실제 DTO 클래스가 있는 Tool Pod로 전달한다.
* 브라우저가 동일 출처(8081)만 호출하도록 하여 CORS와 배포 주소 차이를 숨긴다.
*/
@RestController
public class DtoDownloadProxyController {
private static final MediaType XLSX_MEDIA_TYPE = MediaType.parseMediaType(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
private final RestClient restClient;
private final String toolPodUrl;
public DtoDownloadProxyController(
RestClient.Builder restClientBuilder,
@Value("${mcp.gateway.fallback.default-url:http://localhost:8084}") String toolPodUrl) {
this.restClient = restClientBuilder.build();
this.toolPodUrl = toolPodUrl.replaceAll("/+$", "");
}
@GetMapping("/dto-download/options")
public List<String> options() {
// 셀렉트박스에 표시할 DTO 이름 목록을 Tool Pod에서 조회한다.
List<String> options = restClient.get()
.uri(toolPodUrl + "/dto-download/options")
.retrieve()
.body(new ParameterizedTypeReference<>() {});
return options == null ? List.of() : options;
}
@GetMapping("/dto-download/{dtoName}")
public ResponseEntity<byte[]> download(@PathVariable String dtoName) {
byte[] workbook;
try {
// 생성된 엑셀 바이트를 그대로 브라우저에 전달한다.
workbook = restClient.get()
.uri(toolPodUrl + "/dto-download/{dtoName}", dtoName)
.retrieve()
.body(byte[].class);
} catch (RestClientResponseException error) {
// 형식 불일치 등의 상태 코드와 오류 메시지도 변경 없이 전달한다.
return ResponseEntity.status(error.getStatusCode())
.contentType(error.getResponseHeaders() != null
&& error.getResponseHeaders().getContentType() != null
? error.getResponseHeaders().getContentType() : MediaType.TEXT_PLAIN)
.body(error.getResponseBodyAsByteArray());
}
String fileName = dtoName + ".xlsx";
return ResponseEntity.ok()
.contentType(XLSX_MEDIA_TYPE)
.contentLength(workbook == null ? 0 : workbook.length)
.header(HttpHeaders.CONTENT_DISPOSITION,
ContentDisposition.attachment().filename(fileName).build().toString())
.body(workbook == null ? new byte[0] : workbook);
}
}