이전 글에서 이야기 했든 완전한 VO로 DB값을 불러오지 않았을 때는 List<Map<String, Object>> eList = empLogic.excelDown(eVO);
이렇게 List< Map > 형식으로 파라미터에 VO를 담아서 값을 가져왔기 때문에 아래 코드에서 VO를 Map타입으로 가져올 수 없다는 Exception이 발동했었다.
<발생한 에러>
symbol: method excelDown(EmpVO)
location: variable empLogic of type EmpLogic
@GetMapping("excelDown")
public ResponseEntity<Resource> excelDown(EmpVO eVO) {
try {
logger.info("excelDown");
// 엑셀 다운로드를 위한 데이터 조회
List<Map<String, Object>> eList = empLogic.excelDown(eVO);
// 엑셀 파일 생성
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet("사원 목록");
Row row;
Cell cell;
int rowNo = 0;
// 테이블 헤더용 스타일
CellStyle headStyle = wb.createCellStyle();
headStyle.setBorderTop(BorderStyle.THIN);
headStyle.setBorderBottom(BorderStyle.THIN);
headStyle.setBorderLeft(BorderStyle.THIN);
headStyle.setBorderRight(BorderStyle.THIN);
headStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headStyle.setAlignment(HorizontalAlignment.CENTER);
// 데이터용 경계 스타일 테두리만 지정
CellStyle bodyStyle = wb.createCellStyle();
bodyStyle.setBorderTop(BorderStyle.THIN);
bodyStyle.setBorderBottom(BorderStyle.THIN);
bodyStyle.setBorderLeft(BorderStyle.THIN);
bodyStyle.setBorderRight(BorderStyle.THIN);
// 헤더 생성
row = sheet.createRow(rowNo++);
cell = row.createCell(0);
cell.setCellStyle(headStyle);
cell.setCellValue("사원번호");
cell = row.createCell(1);
cell.setCellStyle(headStyle);
cell.setCellValue("이름");
cell = row.createCell(2);
cell.setCellStyle(headStyle);
cell.setCellValue("성별");
cell = row.createCell(3);
cell.setCellStyle(headStyle);
cell.setCellValue("전화번호");
// 데이터 부분 생성
for (Map<String, Object> emp : eList) {
row = sheet.createRow(rowNo++);
cell = row.createCell(0);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_code")));
cell = row.createCell(1);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_name")));
cell = row.createCell(2);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_gender")));
cell = row.createCell(3);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_phone")));
}
// 엑셀 파일을 ByteArray로 변환
ByteArrayOutputStream bos = new ByteArrayOutputStream();
wb.write(bos);
wb.close();
// ByteArray를 Resource로 변환
ByteArrayResource resource = new ByteArrayResource(bos.toByteArray());
// 파일 이름에 공백이 있는 경우 URL 인코딩 필요
String filename = "employee_list.xlsx";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", filename);
headers.setContentLength(bos.size());
return ResponseEntity.ok()
.headers(headers)
.contentLength(bos.size())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
} catch (IOException e) {
// 예외 처리
logger.error("Error occurred while creating Excel file", e);
// 예외 처리에 따른 응답 코드 설정
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
empList를 수정해봤으니 그걸 토대로 excelDown을 수정하였다.
Dao는 기본적인 CRUD를 적어두는 곳이고 excelDown이 결국 직원목록(select)을 불러오는 것이 목적이기 때문에 Dao는 추가적으로 코드를 만들지 않고 empList와 연결하였다.
👇 Controller
데이터 조회하는 부분과 데이터 생성하는 부분을 수정하였다.
List<EmpVO> eList = empLogic.excelDown();
for (EmpVO emp : eList)
👇 Logic
public List<EmpVO> excelDown() {
logger.info("excelDown");
List<EmpVO> nList = null;
nList = empDao.empList();
return nList;
}
아래 코드에서 get은 String 타입에서 사용 가능 한 것이고 emp의 타입은 EmpVO이기 때문에 사용할 수 없다는 에러가 발생했다.
error: cannot find symbol
cell.setCellValue(String.valueOf(emp.get("e_code")));
symbol: method get(String)
location: variable emp of type EmpVO
// 데이터 생성
for (EmpVO emp : eList) {
row = sheet.createRow(rowNo++);
cell = row.createCell(0);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_code")));
cell = row.createCell(1);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_name")));
cell = row.createCell(2);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_gender")));
cell = row.createCell(3);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.get("e_phone")));
}
구글링을 해보니 일반적으로 Java의 VO(값 객체) 클래스에서는 필드에 직접 접근하여 값을 가져오는 방식을 사용한다고 한다. 그에 따라 아래와 같이 수정하였다.
// 데이터 생성
for (EmpVO emp : eList) {
row = sheet.createRow(rowNo++);
cell = row.createCell(0);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.getE_code()));
cell = row.createCell(1);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.getE_name()));
cell = row.createCell(2);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.getE_gender()));
cell = row.createCell(3);
cell.setCellStyle(bodyStyle);
cell.setCellValue(String.valueOf(emp.getE_phone()));
}
PostMan에서 get방식으로 http://localhost:8000/emp/excelDown
단위 테스트를 진행하였다. 그 결과 글자가 깨져 나오는 에러가 발생했다.
포스트맨에 대해서 찾아본 결과,
포스트맨은 직접 엔드포인트를 호출하면 해당 엔드포인트에서 반환되는 데이터가 포스트맨 화면에 출력되는 구조이다. 그러나 엑셀 파일 다운로드와 같은 결과가 나오는 엔드포인트를 포스트맨에서 단위 테스트를 하면 엑셀 파일처럼 이진 데이터가 아닌 텍스트 형태로 보여지게 된다.
따라서 포스트맨에서 테스트할 때에는 엑셀 파일이 다운로드되지 않고 반환된 텍스트 데이터가 포스트맨 화면에 표시되어 글자가 깨지는 것이다.
주소창에 직접 입력하면 엑셀 파일이 다운로드 되고 파일 안에 직원목록이 정상적으로 출력되는 것을 확인할 수 있다.