프로젝트를 진행중에
내 #달 근무 표를 뽑아야 했다.
출퇴근을 찍는 테이블인 Commute 가 있었고
휴가랑, 출장, 시차근무제를 신청한경우 Attendence 테이블에 추가도 되는 식으로 진행돼서
이 두개를 매칭해서 내 근무표를 뽑아온다.
Service
public List<List<CommuteListResDto>> MonthlyAttendance(String employeeId, CommuteListReqDto commuteListReqDto) {
Employee employee = employeeRepository.findByEmployeeId(employeeId).orElseThrow(() -> new IllegalArgumentException(" 없는 회원입니다. "));
LocalDateTime month = commuteListReqDto.getMonth();
Date firstDayOfMonth = Date.valueOf(month.toLocalDate().withDayOfMonth(1));
Date lastDayOfMonth = Date.valueOf(month.toLocalDate().withDayOfMonth(month.toLocalDate().lengthOfMonth()));
// 한달간 내 출퇴근
List<CommuteRecord> MonthCommute = commuteRepository.findAllByEmployeeAndAttendanceDateBetween(employee, firstDayOfMonth, lastDayOfMonth);
List<Attendance> allByEmployeeAndWorkStartTimeBetween = attendanceRepository.findAllByEmployeeAndWorkStartTimeBetween(employee, month.toLocalDate().withDayOfMonth(1).atStartOfDay(), month.toLocalDate().withDayOfMonth(month.toLocalDate().lengthOfMonth()).atTime(23, 59, 59))
.orElseThrow(()-> new IllegalArgumentException(String.valueOf(month.getMonth()) + "의 해당하는 근무표가 없습니다."));
return allByEmployeeAndWorkStartTimeBetween.stream()
.map(x -> CommuteListResDto.toDto(x, MonthCommute))
.collect(Collectors.toList());
}
DTO
public static List<CommuteListResDto> toDto(Attendance attendance, List<CommuteRecord> commuteRecords) {
List<CommuteListResDto> result = new ArrayList<>(); // 결과를 저장할 리스트 생성
CommuteListResDtoBuilder builder = CommuteListResDto.builder(); // 빌더 객체 생성
if (O04.name().equals(attendance.getWorkPolicy()) || O03.name().equals(attendance.getWorkPolicy()) || O09.name().equals(attendance.getWorkPolicy())) {
LocalDate startDate = attendance.getWorkStartTime().toLocalDate(); // 휴가 시작
LocalDate endDate = attendance.getWorkEndTime().toLocalDate(); // 휴가 종료
while (!startDate.isAfter(endDate)) {
CommuteListResDto dto = builder // 빌더를 사용하여 객체 생성
.attendanceDate(Date.valueOf(startDate))
.workPolicy(attendance.getWorkPolicy())
.workStartTime(attendance.getWorkStartTime())
.workEndTime(attendance.getWorkEndTime())
.tardy("휴가 혹은 병가 혹은 출장")
.build();
result.add(dto);
// 다음 날짜
startDate = startDate.plusDays(1);
}
} else {
Date day = Date.valueOf(attendance.getWorkStartTime().toLocalDate());
CommuteRecord commuteRecord = commuteRecords.stream()
.filter(x -> x.getAttendanceDate().equals(day))
.findFirst().orElseThrow(() -> new IllegalArgumentException("매칭되는 날짜가 없습니다."));
CommuteListResDto dto = builder
.attendanceDate(day)
.workPolicy(attendance.getWorkPolicy())
.workStartTime(attendance.getWorkStartTime())
.tardy("시차 반차")
.build();
result.add(dto);
}
return result;
}
만약 4월20일 부터 4월 25일 까지 휴가가 등록 되어 있으면
Commute 테이블에 4/20 ~ 4/25일의 출퇴근 기록은 없다.
그러면 Attendance에서 가져와서 4/20 ~ 4/25 일은 휴가로 만들어준다.
근데 기존 builder 를 사용해서 하면 4/20 일 꺼만 만들어지기 때문에 list를 사용해준다.
일반 map 사용
일반 map 사용시 휴가인 4/20 ~ 4/24 일까지는 이차원 리스트로 들어간다.
관리하기 어려워
FlatMap을 사용하기로 했다.
return allByEmployeeAndWorkStartTimeBetween.stream()
.flatMap(attendance -> CommuteListResDto.toDto(attendance, MonthCommute).stream())
.collect(Collectors.toList());
return 부분이 이렇게 바뀌게 된다.
리턴 타입도 List가 하나 빠지게된다.
FlatMap
Map vs flatMap
map()은 단일 스트림의 원소를 매핑시킨 후 매핑시킨 값을 다시 스트림으로 변환하는 중간 연산이다. 1:1 로 매칭해서 변환한다.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> x = numbers.stream()
.map(x -> x * x)
.collect(Collectors.toList());
// x: [1, 4, 9, 16, 25]
flatMap() 은 map() + Flattening(펼친다)
flatMap은 각 요소에 대해 매핑 함수를 적용하여 생성된 각각의 결과 스트림을 하나의 스트림으로 연결한다. 각 요소에 대해 1:N 또는 0:N 매핑을 수행하기 때문에 각 요소마다 여러 개의 결과가 생성될 수 있다. 반환된 스트림은 평평하게(1차원) 펼쳐진 결과이다.
List<String> lines = Arrays.asList("hello world", "goodbye world", "welcome home");
List<String> words = lines.stream()
.map(line -> line.split("\\s+")) // 각 줄을 단어로 분할하여 스트림의 스트림을 생성
.flatMap(Arrays::stream) // 각 스트림을 하나의 스트림으로 평평하게 펼침
.collect(Collectors.toList());
// words: ["hello", "world", "goodbye", "world", "welcome", "home"]
리스트나 2차원 리스트도 1차원 리스트로 펼칠 수 있다.
댓글