이번 과제는 고민을 좀 많이 하면서 했다 출근과 퇴근을 분리해야할지 하나로 합쳐서 안에서 분기로 처리할지.
결국에는 하나로 합쳐서 데이터에따라 분기로 처리해주었다
출퇴근 기능
1. 아이디를 파라미터로 받아서 직원정보를 조회하고 출퇴근 기록을 저장
2. 데이터를 조회해서 당일 출퇴근 기록이없는경우 새로 출퇴근기록을 저장
3. 데이터를 조회해서 당일 출근기록은 있는데 퇴근이없는경우 퇴근시간을 업데이트
4. 데이터를 조회해서 당일 출퇴근기록이 전부있는경우 새로 출근기록을 저장.
예외처리
1. 등록되지않은 직원이 출근 (직원이 조회되지않음)
2. 출근한 직원이 다시 출근
3. 퇴근하려는 직원이 출근하지않았던 경우
4. 그 날, 출근했다 퇴근한 직원이 다시 출근하려는경우
예외의 2번과 3번은 서비스계층내부에서 분기로 처리하면서 자동으로 처리가 된다 (출근 퇴근을 따로등록할수없음)
4번의 경우는 출근하고 퇴근했다가 다시 출근해서 추가적으로 근무를 해야하는경우도 있을것같아서 막지는 않았다.
추가적으로 출근기록을 생성하도록 처리해주었다.
Controller
@RestController
@RequestMapping("/commute")
public class CommuteController {
private final CommuteService service;
public CommuteController(CommuteService service) {
this.service = service;
}
@PostMapping
public void checkWork(@RequestBody Map<String, Long> json) {
service.checkWork(json.get("employeeId"));
}
}
Service
@Service
@RequiredArgsConstructor
@Slf4j
public class CommuteService {
private final CommuteHistoryRepository repository;
private final MemberRepository memberRepository;
@Transactional
public void checkWork(Long employeeId) {
//해당 아이디의 직원을 조회
//예외사항 1번에대해서 예외를 발생시킴
Employee employee = memberRepository.findById(employeeId).orElseThrow(()-> new IllegalArgumentException("직원 정보가없습니다."));
//직원의 금일 근무정보가 있는지 조회
EmployeeTodayCommuteList employeeTodayCommuteList = new EmployeeTodayCommuteList(employee);
checkStartOrEndWorking(employeeTodayCommuteList, employee);
}
private void checkStartOrEndWorking(EmployeeTodayCommuteList employeeTodayCommuteList, Employee employee) {
// 금일근무정보가 없거나 ,근무기록은 있지만 근무중이 아닌경우(이미퇴근) ,새로 출근기록 생성
if (employeeTodayCommuteList.isWorkEnd()) {
CommuteHistory save = repository.save(new CommuteHistory(employee));
save.startWorking(); // 출근기록 업데이트
} else {
//출근 기록이있는경우 퇴근으로
employeeTodayCommuteList.getWorkingCommuteHistory().endWorking(); //퇴근기록업데이트
}
}
}
서비스 계층에서 출퇴근정보에서 필요한정보를 가져오려다보니 코드가 너무 커져서 출근기록을 List로 가진 일급컬렉션을 만들어주고 그안에서 필요한 정보를 연산하는 메서드들을 만들어주고 사용했다.
코드를 줄이고 이해하기 쉽게 만드는데에 일급컬렉션이 유용하게 쓰이는것같다.
EmployeeCommuteList(일급컬렉션)
@Getter
public class EmployeeTodayCommuteList {
private List<CommuteHistory> commuteHistoryList;
public EmployeeTodayCommuteList(Employee employee) {
this.commuteHistoryList = employee.getCommuteHistories().stream()
.filter(target -> target.getStartTime().toLocalDate().equals(LocalDateTime.now().toLocalDate()))
.collect(Collectors.toList());
}
public Boolean isWorkEnd(){
//1.직원의 금일 근무정보가있는경우
//퇴근을 안한근무정보가(퇴근시간정보==null)있다면 true, 없다면 false
//commuteHistoryList.stream().noneMatch(CommuteHistory::getIsWorking) 퇴근안한정보가있다면 false를 리턴
return commuteHistoryList == null || commuteHistoryList.stream().noneMatch(CommuteHistory::getIsWorking);
}
public CommuteHistory getWorkingCommuteHistory(){
//아직 퇴근하지않은 객체를 찾아서리턴
return commuteHistoryList.stream().filter(CommuteHistory::getIsWorking)
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
}
서비스계층에서 직원정보만받아서 내부에서 당일 출퇴근정보만 필터링해서 List로 만들도록 생성자를 만들어줬다.
그 외에 조건문에서 사용할 메서드나 필요한 객체를 리턴할수있게 메서드를 만들어주었다.
Repository
public interface CommuteHistoryRepository extends JpaRepository<CommuteHistory, Long> {
}
사실 명세만보면 다 쉽게만들수있을줄알았는데 이렇게 로직하나로 고민을 할줄은 몰랐다.
나는 출퇴근시스템을 카드찍는 장면을 떠올리면서 만들어서 카드를 찍는 하나의 행동으로 출퇴근이 다되도록 만들어봤다.
한번찍으면 출근,두번째는 퇴근,세번째는 다시 출근이되도록.
이 방법말고도 특정시간전에는 모두 출근으로찍히게 하고 퇴근시간이후에는 퇴근으로 찍히게할까 라는 생각도해봤지만
유연근무제나 반차같은 개념도 있어서 유연성이 떨어진다는 생각이들었다.
이런 비즈니스적인 요구사항도 최대한 생각하면서 만들어보는게 생각보다 재미있는것같다.
'백엔드 > 자바' 카테고리의 다른 글
스프링부트 예외처리 - @RestControllerAdvice (1) | 2024.03.15 |
---|---|
[인프런 워밍업 클럽_0기] BE과제 미니프로젝트 2단계 - 출퇴근기록 조회 (0) | 2024.03.11 |
[인프런 워밍업 클럽_0기] BE과제 미니프로젝트 1단계 - 3 직원등록,조회기능 (0) | 2024.03.10 |
[인프런 워밍업 클럽_0기] BE과제 미니프로젝트 1단계 - 2 팀 등록,조회 기능,에러처리 @RestControllerAdvice (0) | 2024.03.09 |
[인프런 워밍업 클럽_0기] BE과제 미니프로젝트 1단계 - 1 JpaMappedBy,JoinColumn,1:N,OneToMany,ManyToOne (0) | 2024.03.07 |