인터페이스 다운로드 변경사항 반영
This commit is contained in:
@@ -11,7 +11,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.*;
|
import org.apache.poi.ss.usermodel.*;
|
||||||
@@ -45,6 +47,7 @@ public class DtoExcelDownloadController {
|
|||||||
private static final String MCI_BASE_PACKAGE = "io.shinhanlife.dap.mcc.infra.itrf.mci";
|
private static final String MCI_BASE_PACKAGE = "io.shinhanlife.dap.mcc.infra.itrf.mci";
|
||||||
private static final String INVALID_DTO_MESSAGE =
|
private static final String INVALID_DTO_MESSAGE =
|
||||||
"dto의 내용이 엑셀파일 양식에 맞지않습니다 파일을 확인해주세요";
|
"dto의 내용이 엑셀파일 양식에 맞지않습니다 파일을 확인해주세요";
|
||||||
|
private static final Pattern VARIANT_SUFFIX = Pattern.compile("_[IO]$");
|
||||||
|
|
||||||
private final Map<String, String> dtoClasses;
|
private final Map<String, String> dtoClasses;
|
||||||
|
|
||||||
@@ -54,8 +57,12 @@ public class DtoExcelDownloadController {
|
|||||||
|
|
||||||
@GetMapping("/dto-download/options")
|
@GetMapping("/dto-download/options")
|
||||||
public List<String> options() {
|
public List<String> options() {
|
||||||
// 클래스패스에서 자동 검색된 DTO 목록을 화면에 제공한다.
|
// DTO는 항상 _I/_O 한 쌍으로 존재하므로 접미사를 제거한 이름 단위로 묶어 화면에 제공한다.
|
||||||
return List.copyOf(dtoClasses.keySet());
|
Set<String> baseNames = new TreeSet<>();
|
||||||
|
for (String simpleName : dtoClasses.keySet()) {
|
||||||
|
baseNames.add(VARIANT_SUFFIX.matcher(simpleName).replaceFirst(""));
|
||||||
|
}
|
||||||
|
return List.copyOf(baseNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/dto-download/{dtoName}")
|
@GetMapping("/dto-download/{dtoName}")
|
||||||
@@ -328,7 +335,9 @@ public class DtoExcelDownloadController {
|
|||||||
|
|
||||||
private Annotation telegramMetadata(Field field) {
|
private Annotation telegramMetadata(Field field) {
|
||||||
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
||||||
if (annotation.annotationType().getSimpleName().equals("GlowTrgmField")) {
|
String annotationName = annotation.annotationType().getSimpleName();
|
||||||
|
if (annotationName.equals("GlowTrgmField")
|
||||||
|
|| annotationName.equals("GlowMciFieldInfo")) {
|
||||||
return annotation;
|
return annotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
const select = $('toolSelect'), args = $('arguments'), result = $('result');
|
const select = $('toolSelect'), args = $('arguments'), result = $('result');
|
||||||
|
|
||||||
async function loadDtoOptions() {
|
async function loadDtoOptions() {
|
||||||
// 서버가 itrf/mci/**/io 패키지에서 찾은 DTO 목록으로 셀렉트박스를 구성한다.
|
// 서버가 itrf/mci/**/io 패키지에서 찾은 DTO를 _I/_O 접미사 없이 이름 단위로 묶어 셀렉트박스를 구성한다.
|
||||||
const dtoSelect = $('dtoSelect');
|
const dtoSelect = $('dtoSelect');
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/dto-download/options', { headers: { 'Cache-Control': 'no-cache' } });
|
const response = await fetch('/dto-download/options', { headers: { 'Cache-Control': 'no-cache' } });
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
for (const dtoName of dtoNames) {
|
for (const dtoName of dtoNames) {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = dtoName;
|
option.value = dtoName;
|
||||||
option.textContent = `${dtoName}.java`;
|
option.textContent = dtoName;
|
||||||
dtoSelect.appendChild(option);
|
dtoSelect.appendChild(option);
|
||||||
}
|
}
|
||||||
if (!dtoNames.length) dtoSelect.innerHTML = '<option value="">DTO 파일이 없습니다.</option>';
|
if (!dtoNames.length) dtoSelect.innerHTML = '<option value="">DTO 파일이 없습니다.</option>';
|
||||||
@@ -115,34 +115,51 @@
|
|||||||
function openDtoModal() { $('dtoDownloadModal').classList.remove('hidden'); loadDtoOptions(); $('dtoSelect').focus(); }
|
function openDtoModal() { $('dtoDownloadModal').classList.remove('hidden'); loadDtoOptions(); $('dtoSelect').focus(); }
|
||||||
function closeDtoModal() { $('dtoDownloadModal').classList.add('hidden'); $('dtoDownloadButton').focus(); }
|
function closeDtoModal() { $('dtoDownloadModal').classList.add('hidden'); $('dtoDownloadButton').focus(); }
|
||||||
async function downloadSelectedDto() {
|
async function downloadSelectedDto() {
|
||||||
// 선택한 DTO의 엑셀 생성 API를 호출하고 응답 Blob을 브라우저 다운로드로 저장한다.
|
// 선택한 DTO 이름의 _I/_O 엑셀 생성 API를 순차 호출해 존재하는 파일을 각각 브라우저 다운로드로 저장한다.
|
||||||
const dtoName = $('dtoSelect').value;
|
const baseName = $('dtoSelect').value;
|
||||||
if (!dtoName) return alert('다운로드할 DTO를 선택해주세요.');
|
if (!baseName) return alert('다운로드할 DTO를 선택해주세요.');
|
||||||
const confirmButton = $('dtoConfirmButton');
|
const confirmButton = $('dtoConfirmButton');
|
||||||
confirmButton.disabled = true;
|
confirmButton.disabled = true;
|
||||||
|
const errors = [];
|
||||||
|
let successCount = 0;
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/dto-download/${encodeURIComponent(dtoName)}`);
|
for (const variant of ['I', 'O']) {
|
||||||
if (!response.ok) {
|
const dtoName = `${baseName}_${variant}`;
|
||||||
// 422는 GlowTrgmField 메타데이터가 없어 설계서 양식으로 변환할 수 없는 경우다.
|
try {
|
||||||
const message = (await response.text()).trim();
|
const response = await fetch(`/dto-download/${encodeURIComponent(dtoName)}`, {
|
||||||
throw new Error(response.status === 422
|
cache: 'no-store',
|
||||||
? 'dto의 내용이 엑셀파일 양식에 맞지않습니다 파일을 확인해주세요'
|
headers: { 'Cache-Control': 'no-cache' }
|
||||||
: message || (response.status === 404
|
});
|
||||||
? `${dtoName}.xlsx 파일을 찾을 수 없습니다.`
|
if (response.status === 404) continue; // _I/_O 중 한쪽만 존재하는 DTO는 정상 케이스이므로 건너뛴다.
|
||||||
: `다운로드에 실패했습니다. (HTTP ${response.status})`));
|
if (!response.ok) {
|
||||||
|
// 422는 GlowTrgmField 메타데이터가 없어 설계서 양식으로 변환할 수 없는 경우다.
|
||||||
|
const message = (await response.text()).trim();
|
||||||
|
throw new Error(response.status === 422
|
||||||
|
? `${dtoName}: dto의 내용이 엑셀파일 양식에 맞지않습니다 파일을 확인해주세요`
|
||||||
|
: message || `${dtoName} 다운로드에 실패했습니다. (HTTP ${response.status})`);
|
||||||
|
}
|
||||||
|
const blob = await response.blob();
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `${dtoName}.xlsx`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
link.remove();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
successCount += 1;
|
||||||
|
// 브라우저가 연속 다운로드를 한 번에 차단하지 않도록 다음 요청 전에 짧은 간격을 둔다.
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
} catch (error) {
|
||||||
|
errors.push(error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const blob = await response.blob();
|
if (successCount === 0) {
|
||||||
const url = URL.createObjectURL(blob);
|
alert(errors.length ? errors.join('\n') : `${baseName} 파일을 찾을 수 없습니다.`);
|
||||||
const link = document.createElement('a');
|
return;
|
||||||
link.href = url;
|
}
|
||||||
link.download = `${dtoName}.xlsx`;
|
if (errors.length) alert(errors.join('\n'));
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
link.remove();
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
closeDtoModal();
|
closeDtoModal();
|
||||||
} catch (error) {
|
|
||||||
alert(error.message);
|
|
||||||
} finally {
|
} finally {
|
||||||
confirmButton.disabled = false;
|
confirmButton.disabled = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user