IT모저모

[SpringBoot] 데이터 엑셀 다운로드 (feat. 어노테이션만들기, 본문

Develop/SpringBoot

[SpringBoot] 데이터 엑셀 다운로드 (feat. 어노테이션만들기,

YU JIN 2024. 12. 10. 17:59
반응형

안녕하세요 ~~

 

좀 지난 개발 이야기지만 끄적여보겠습니다 (다시 사용할 일이 생겨서..)

사내 근태프로그램을 만드는 중에 개인의 월 근태 기록을 엑셀로 다운로드 받아야하는 일이 생겼습니다.

 

저는 컴퓨터공학 전공을 하긴 했지만 학교다닐땐 진짜 못했걸랑요

시험을 위해서만 공부해왔던 저라...?

 

그래서 자바와 스프링부트를 혼자 독학했어요...

암튼 제 사담이었고요...

 

여기저기 구글링을 하며 

이 기능에 제일 적합하면서 최대한 유연성있는 코드를 짜보자 해서 해당 코드를 만들게 됐어요

 

근태기록이라 함은

정해진 근무 스케줄이 있고 (저희는 유연근로제는 하지 않음) 정해진 식사시간, 연장근로시작, 휴일근로시간 등등 대체근무 등 엄청 많잖아요?

 

이를 에스원데이터와 연동하고 전자결재와 연동하기 전까지의 엑셀 데이터를 추출하는 작업을 했습니다.

전재결재 연동 후에도 엑셀 데이터 추출가능합니다 ^^

 

 

우선 .. 

엑셀데이터를 출력하기 위해서는 정해진 틀이 필요하기 때문에 제가 손수 엑셀로 이 폼으로 나오면 좋겠다를 디자인 했어여 

(저희는 기획자가 없어서 제가 혼자 다 해야함니다...)

 

파일은 yyyy년 MM월 이름.xlsx 으로 받아져야하고 

아래의 디자인으로 파일이 받아져야합니다.,

 

 

매주 52시간 근로의 법이 있기 때문에 매주 총 근로시간도 계산해줘야하구요

실제 출근시각과 퇴근시각은 정산하는 시각과 다를 수 있기때문에 모든걸 고려해줘야합니다

아무튼... 저는 이 디자인 그리는 것도 정말 힘들었네요..

노란색 cell의 경우 출퇴근시각이 찍혀있지 않으면 노란색으로 표기했습니다! 

 

 

근무일자, 근무요일~~~ 연장근무합계까지

cell backgroud가 정해져있는데 이는 어노테이션을 생성해줘서 dto에 어노테이션을 붙여 알아서 읽어오게끔했어요

아래 코드를 봐주세욧

 

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelColumn {

    String headerName() default "";
}

 

해당 어노테이션을 생성한 후에,

 

@Data
@Builder
@Getter @Setter
public class WorkHistoryDTO extends BaseTimeEntity {

    private int id;

    @ExcelColumn(headerName = "근무일자")
    private String work_date;
}

 

위의 예시처럼 어노테이션을 지정하게 되면

어노테이션을 붙여놓은 컬럼만 읽어와 자동으로 cell value를 추가하게 됩니다

 

 

for (int i = 0; i < excelHeaderList.size(); i++) {
            cell = row.createCell(i);
            cell.setCellValue(excelHeaderList.get(i));
            cell.setCellStyle(headerStyle);
}

 

요런식으로 하면 value를 추가하고 셀에 스타일을 추가하게 됩니다!

 

private Class<?> getClass(List<?> data) {
        // List가 비어있지 않다면 List가 가지고 있는 모든 DTO는 같은 필드를 가지고 있으므로,
        // 맨 마지막 DTO만 빼서 클래스 정보를 반환한다.
        if(!CollectionUtils.isEmpty(data)) {
            return data.get(data.size()-1).getClass();
        } else {
            throw new IllegalStateException("조회된 리스트가 비어 있습니다. 확인 후 다시 진행해주시기 바랍니다.");
        }
    }

    private List<String> getHeaderName(Class<?> type) {
        // 스트림으로 엑셀 헤더 이름들을 리스트로 반환
        // 1. 매개변수로 전달된 클래스의 필드들을 배열로 받아, 스트림을 생성
        // 2. @ExcelColumn 애너테이션이 붙은 필드만 수집
        // 3. @ExcelColumn 애너테이션이 붙은 필드에서 애너테이션의 값을 매핑
        // 4. LinkedList로 반환
        List<String> excelHeaderNameList =  Arrays.stream(type.getDeclaredFields())
                .filter(s -> s.isAnnotationPresent(ExcelColumn.class))
                .map(s -> s.getAnnotation(ExcelColumn.class).headerName())
                .collect(Collectors.toCollection(LinkedList::new));

        // 헤더의 이름을 담은 List가 비어있을 경우, 헤더 이름이 지정되지 않은 것이므로, 예외를 발생시킨다.
        if(CollectionUtils.isEmpty(excelHeaderNameList)) {
            throw new IllegalStateException("헤더 이름이 없습니다.");
        }
        return excelHeaderNameList;
    }

 

해당 코드를 참고 하여 엑셀을 생성하는데 도움이 되셨으면 합니다~

 

물론 다음의 나에게두 ^^

 

감사합니닷

더 좋은 코드가 있으면 알려주세용 

Comments