[Java] 공용 엑셀 업로드 모듈 제작일기
1. 개요
회사에서 엑셀 업로드 요구사항이 들어왔는데, 회사 레거시 프로젝트 내에 추상화 된 엑셀 업로드 모듈이 존재하지 않았다. 여태까지는 엑셀 업로드 기능이 오면 대부분 시간이 오래걸려서 거절하거나, 하드코딩을 해서 제작해주던 상황이었는데 이참에 하나 추상화 된 모듈을 만들어보기로 했다. 이 포스팅에서는 이름
, 나이
, 주소
로 이루어진 회원 엑셀을 업로드 할 수 있도록 만들어 달라는 요구사항이 있다고 가정하기로 하자.
2. 하드코딩 버전
우선 엑셀 업로드의 목표가 되는 작업을 요약하자면 다음과 같다.
- 파일을 읽어들여 워크북 타입으로 변환 (여기서는 클라이언트로 받은 Multipart 객체를 다룬다.)
- 데이터를 불러올 특정 시트 내의 열 객체와 행 객체를 반복하여 읽어들인다. 일반적인 2차원 배열 순회 과정을 생각하면 된다.
- 이때 사용자 업로드 양식에 지정된 순서대로 일치하는 순서의 컬럼의 값을 미리 지정된 타입의 객체에 저장한다.
- 성공적으로 변환 된 모델은 컬렉션 객체에 순서대로 저장한다.
자료의 유효성을 체크하거나 DB 에 insert 하는 작업은 요청별로 상이할 수 있으니 정제되기 전의 DTO 리스트를 만드는 것을 우선 목표로 한다.
1
//코드 영역
3. 추상화
우선 엑셀의 양식과 일치시킬 메타데이터를 정한다. 이번 모듈은 엑셀 양식의 헤더정보를 바탕으로 모델의 필드와 매핑시킬 예정이므로 헤더 데이터를 담는 @ExcelHeader
애노테이션을 생성한다. 그리고 ExcelReader
유틸의 타입이 될 부모 DTO 클래스 ExcelDto
를 작성한다. 추후 등록에 실패한 Row 반환 시 사용자가 row number 를 확인해야 하므로 부모 객체 필드에 integer 타입으로 rowNumber 를 미리 선언한다. 이때 리플렉션을 활용하여 ExcelHeader
의 명칭과 일치하는 필드에 값을 채워준다.
4. 싱글톤 객체로 만들기
사실 ExcelReader 객체는 사용할 때 마다 새로운 인스턴스를 생성할 필요는 없다. 동시성 이슈가 발생할만한 전역 변수도 없다. 스프링 컨테이너에 빈으로 등록해놓고 사용할 필요도 현재로써는 없다. 따라서 싱글톤 객체로 만들어 관리하도록 한다. 제네릭 클래스를 일반 클래스로 변경하고 제네릭 타입을 메소드 범위로 옮겨온다.