Skip to content

Commit 6e05702

Browse files
authored
refactor: 졸업학점 계산기 엑셀 업로드 리팩토링 - 1차 (#2045)
* feat: 파일 확장자 검증 어노테이션 추가 * feat: GraduationExcelService 추가 * chore: 미사용 코드 삭제 * chore: getKoinSemester 메소드 도메인 객체로 이동 * fix: GradeExcelData 스킵 메소드 네이밍 수정 * fix: Parser 메소드 삭제 * fix: GradeExcelData 합계 여부 메소드 네이밍 수정 * refactor: getKoinSemester 메소드 리펙토링 * fix: 미사용 상수 삭제 * fix: 미사용 예외 클래스 삭제 * fix: 엑셀 상수 네이밍 및 값 수정 * fix: GraduationExcelService 불필요한 어노테이션 삭제 * feat: Validated 어노테이션 추가 * feat: ConstraintViolationException 핸들러 추가
1 parent b96df73 commit 6e05702

File tree

11 files changed

+227
-167
lines changed

11 files changed

+227
-167
lines changed

src/main/java/in/koreatech/koin/domain/graduation/controller/GraduationApi.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import in.koreatech.koin.domain.graduation.dto.GraduationCourseCalculationResponse;
1616
import in.koreatech.koin.domain.graduation.model.GeneralEducationArea;
1717
import in.koreatech.koin.global.auth.Auth;
18+
import in.koreatech.koin.global.validation.FileTypeValid;
1819
import io.swagger.v3.oas.annotations.Operation;
1920
import io.swagger.v3.oas.annotations.media.Content;
2021
import io.swagger.v3.oas.annotations.media.Schema;
@@ -53,7 +54,7 @@ ResponseEntity<Void> createStudentCourseCalculation(
5354
@SecurityRequirement(name = "Jwt Authentication")
5455
@PostMapping("/graduation/excel/upload")
5556
ResponseEntity<String> uploadStudentGradeExcelFile(
56-
@RequestParam(value = "file") MultipartFile file,
57+
@FileTypeValid(extensions = {"xls", "xlsx"}) @RequestParam(value = "file") MultipartFile file,
5758
@Auth(permit = {STUDENT}) Integer userId
5859
);
5960

src/main/java/in/koreatech/koin/domain/graduation/controller/GraduationController.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package in.koreatech.koin.domain.graduation.controller;
22

3-
import java.io.IOException;
4-
import java.util.List;
5-
63
import static in.koreatech.koin.domain.user.model.UserType.COUNCIL;
74
import static in.koreatech.koin.domain.user.model.UserType.STUDENT;
85

6+
import java.io.IOException;
7+
import java.util.List;
8+
99
import org.springframework.http.ResponseEntity;
10+
import org.springframework.validation.annotation.Validated;
1011
import org.springframework.web.bind.annotation.GetMapping;
1112
import org.springframework.web.bind.annotation.PostMapping;
1213
import org.springframework.web.bind.annotation.RequestParam;
@@ -20,8 +21,10 @@
2021
import in.koreatech.koin.domain.graduation.service.GraduationService;
2122
import in.koreatech.koin.domain.user.model.UserType;
2223
import in.koreatech.koin.global.auth.Auth;
24+
import in.koreatech.koin.global.validation.FileTypeValid;
2325
import lombok.RequiredArgsConstructor;
2426

27+
@Validated
2528
@RestController
2629
@RequiredArgsConstructor
2730
public class GraduationController implements GraduationApi {
@@ -37,7 +40,7 @@ public ResponseEntity<Void> createStudentCourseCalculation(
3740

3841
@PostMapping("/graduation/excel/upload")
3942
public ResponseEntity<String> uploadStudentGradeExcelFile(
40-
@RequestParam(value = "file") MultipartFile file,
43+
@FileTypeValid(extensions = {"xls", "xlsx"}) @RequestParam(value = "file") MultipartFile file,
4144
@Auth(permit = {UserType.STUDENT}) Integer userId
4245
) {
4346
try {

src/main/java/in/koreatech/koin/domain/graduation/exception/ExcelFileCheckException.java

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/main/java/in/koreatech/koin/domain/graduation/exception/ExcelFileNotFoundException.java

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package in.koreatech.koin.domain.graduation.model;
22

3-
import org.apache.poi.ss.usermodel.Cell;
4-
import org.apache.poi.ss.usermodel.Row;
3+
import static in.koreatech.koin.global.code.ApiResponseCode.INVALID_SEMESTER_REGEX;
4+
5+
import in.koreatech.koin.global.exception.CustomException;
56

67
public record GradeExcelData(
78
String year,
@@ -15,29 +16,32 @@ public record GradeExcelData(
1516
String grade,
1617
String retakeStatus
1718
) {
18-
public static GradeExcelData fromRow(Row row) {
19-
return new GradeExcelData(
20-
getCellValueAsString(row.getCell(1)),
21-
getCellValueAsString(row.getCell(2)),
22-
getCellValueAsString(row.getCell(4)),
23-
getCellValueAsString(row.getCell(5)),
24-
getCellValueAsString(row.getCell(6)),
25-
getCellValueAsString(row.getCell(7)),
26-
getCellValueAsString(row.getCell(8)),
27-
getCellValueAsString(row.getCell(9)),
28-
getCellValueAsString(row.getCell(10)),
29-
getCellValueAsString(row.getCell(11))
30-
);
19+
20+
private static final String MIDDLE_TOTAL = "소 계";
21+
private static final String FAIL = "F";
22+
private static final String UNSATISFACTORY = "U";
23+
private static final String TOTAL = "합 계";
24+
private static final String FIRST_SEMESTER = "1";
25+
private static final String SECOND_SEMESTER = "2";
26+
private static final String SUMMER_SEMESTER = "하계";
27+
private static final String WINTER_SEMESTER = "동계";
28+
29+
public boolean isSkipRow() {
30+
return classTitle.equals(MIDDLE_TOTAL) ||
31+
grade.equals(FAIL) ||
32+
grade.equals(UNSATISFACTORY);
33+
}
34+
35+
public boolean isTotalRow() {
36+
return classTitle.equals(TOTAL);
3137
}
3238

33-
private static String getCellValueAsString(Cell cell) {
34-
if (cell == null) {
35-
return "";
36-
}
37-
return switch (cell.getCellType()) {
38-
case STRING -> cell.getStringCellValue();
39-
case NUMERIC -> String.valueOf((int)cell.getNumericCellValue());
40-
default -> "";
39+
public String getKoinSemester() {
40+
return switch (semester) {
41+
case FIRST_SEMESTER, SECOND_SEMESTER -> year + semester;
42+
case WINTER_SEMESTER -> year + "-" + "겨울";
43+
case SUMMER_SEMESTER -> year + "-" + "여름";
44+
default -> throw CustomException.of(INVALID_SEMESTER_REGEX);
4145
};
4246
}
4347
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package in.koreatech.koin.domain.graduation.service;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
import org.apache.poi.ss.usermodel.Cell;
9+
import org.apache.poi.ss.usermodel.Row;
10+
import org.apache.poi.ss.usermodel.Sheet;
11+
import org.apache.poi.ss.usermodel.Workbook;
12+
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
13+
import org.springframework.stereotype.Service;
14+
import org.springframework.web.multipart.MultipartFile;
15+
16+
import in.koreatech.koin.domain.graduation.model.GradeExcelData;
17+
18+
@Service
19+
public class GraduationExcelService {
20+
21+
public List<GradeExcelData> parseStudentGradeFromExcel(MultipartFile file) throws IOException {
22+
List<GradeExcelData> gradeExcelDatas = new ArrayList<>();
23+
24+
try (InputStream inputStream = file.getInputStream();
25+
Workbook workbook = new XSSFWorkbook(inputStream)
26+
) {
27+
Sheet sheet = workbook.getSheetAt(0);
28+
29+
for (Row row : sheet) {
30+
GradeExcelData gradeExcelData = fromRow(row);
31+
if (row.getRowNum() == 0 || gradeExcelData.isSkipRow()) {
32+
continue;
33+
}
34+
if (gradeExcelData.isTotalRow()) {
35+
break;
36+
}
37+
gradeExcelDatas.add(gradeExcelData);
38+
}
39+
}
40+
return gradeExcelDatas;
41+
}
42+
43+
private GradeExcelData fromRow(Row row) {
44+
return new GradeExcelData(
45+
getCellValueAsString(row.getCell(1)),
46+
getCellValueAsString(row.getCell(2)),
47+
getCellValueAsString(row.getCell(4)),
48+
getCellValueAsString(row.getCell(5)),
49+
getCellValueAsString(row.getCell(6)),
50+
getCellValueAsString(row.getCell(7)),
51+
getCellValueAsString(row.getCell(8)),
52+
getCellValueAsString(row.getCell(9)),
53+
getCellValueAsString(row.getCell(10)),
54+
getCellValueAsString(row.getCell(11))
55+
);
56+
}
57+
58+
private String getCellValueAsString(Cell cell) {
59+
if (cell == null)
60+
return "";
61+
62+
return switch (cell.getCellType()) {
63+
case STRING -> cell.getStringCellValue();
64+
case NUMERIC -> String.valueOf((int)cell.getNumericCellValue());
65+
default -> "";
66+
};
67+
}
68+
}

0 commit comments

Comments
 (0)