kakao-tech-campus-2nd-step3 / Team13_BE

13조 백엔드
4 stars 5 forks source link

돌봄대상자/보호자/요양보호사 데이터 파일 입출력 기능 구현 #34

Open pykido opened 4 days ago

pykido commented 4 days ago

📝 이슈 설명

각 요양원이 직접 관리하던 돌봄대상자/보호자/요양보호사 정보를 돌봄다리 서비스를 이용하며 이전하는 기능이 필요합니다. 요양원 관리자가 엑셀(.xlsx) 파일의 양식으로 정보를 입력 & 추출할 수 있어야 합니다.

이 API를 사용한 유저 플로우는 다음과 같아요!

  1. 요양원 관리자가 관리자 페이지에 접속 후 정보 입력 기능에 접근
  2. 정보를 입력할 엑셀 파일 양식 다운로드 버튼을 클릭하여 엑셀 파일 다운로드
  3. 다운로드 받은 엑셀 양식에 맞춰 정보들을 기입
  4. 엑셀 업로드 버튼을 통한 파일 업로드 (단, 업로드 시 중복된 정보가 업로드되지 않도록, 입력 양식에 맞게 업로드되는지, 검증하는 로직이 필요)
  5. 파일 데이터가 DB에 반영

⭐️⭐️ 중요한 내용!!

  1. 돌봄대상자/보호자/요양보호사 데이터 유형이 서로 다를 수 있기에 한 엑셀 파일에 각각 서로 다른 시트가 있어야할 듯합니다.
  2. 업로드 실패 시 exception을 통해 업로드를 중단시키지는 마시고 입력에 사용자로 하여금 업로드 성공/실패한 정보를 직접 확인 가능하게끔 할 수 있게 해야합니다!
  3. 어떤 데이터가 들어갈지는 서로 이야기해봐야할 거 같으니 관련 자료 리서치해주세요!

1. POI 라이브러리 사용 (build.gradle에 추가)

    // POI
    implementation 'org.apache.poi:poi-ooxml:5.3.0' // excel 파일(.xlsx)을 처리
    implementation 'org.apache.commons:commons-compress:1.27.1' // 압축 파일 처리

2. 컨트롤러

(1) 고객 정보 입력할 엑셀 양식 다운로드

    @GetMapping("/excel/download")
    public ResponseEntity<byte[]> downloadExcelTemplate() {
                 // 서비스 로직 불러와서 작업
        return ResponseEntity.ok()
            .header("Content-Disposition", "attachment; filename=엑셀파일 이름")
            .header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")  // MIME 타입 설정
            .body(data);
    }

(2) 고객 정보 입력한 엑셀 파일 업로드하여 DB에 저장

    @PostMapping("/excel/upload")
    public ResponseEntity<FileUploadResponseDto> uploadExcelData(
        @RequestParam("file") MultipartFile file) {
                 // 서비스 로직 불러와서 작업 
        return ResponseEntity.status(HttpStatus.OK).body(result);
    }

3. dto

(1) 파일 업로드 후 response

import java.util.List;

public record FileUploadResponseDto(
    String storeName,
    List<FileDataResponseDto> uploadedData,
    List<FileDataREsponseDto> failedData
) {
}

(2) 파입 업로드 후

public record FileDataResponseDto(
    String name,
    String phone,
         ....

) {
}

4. 서비스 로직

        // 데이터 넣을 엑셀 양식 생성
    public byte[] generateDataExcelTemplate() {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Data");
            sheet.setDefaultColumnWidth(28);
            setCellStyleText(workbook, sheet, 5);
            createHeader(workbook, sheet);
            createSampleData(sheet);
            return convertWorkbookToByteArray(workbook);
        } catch (IOException e) {
            throw new ApplicationException(ApplicationError.FILE_DOWNLOAD_ERROR);
        }
    }

       // 데이터 업로드 
       @Transactional
public FileUploadResponseDto uploadExcelFile(MultipartFile file) {
    try (Workbook workbook = new XSSFWorkbook(file.getInputStream())) {

        FileUploadResponseDto responseDto = new FileUploadResponseDto(store.getName(), new ArrayList<>(), new ArrayList<>());

        for (Row row : sheet) {
            if (isHeaderRow(row)) continue;

            String phoneNumber = getCellValueAsString(row.getCell(5));
            String name = getCellValueAsString(row.getCell(3));

            validateData(name, phoneNumber);

        return responseDto;
    } catch (IOException e) {
        throw new ApplicationException(ApplicationError.FILE_UPLOAD_ERROR, e);
    }
}

☑️ TODO

pykido commented 3 days ago

추가적으로 전화번호의 경우 01012345678과 같이 text 형태로 입력해야하기에 엑셀 템플릿 만들 때 해당 셀 타입을 text로 지정해주셔야해요!