서버가 필요하기때문에 내장서버를 가진 starter-web과 websocket을 의존성으로 가져와야한다.
webSocketConfig
@Configuration
@EnableWebSocket
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer {
private final WebSocketHandler webSocketHandler;
private final SocketTextHandler socketTextHandler;
private final HandshakeInterceptor ChattingHandshakeInterceptor;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// endpoint 설정 : /api/v1/chat/{postId}
// 이를 통해서 ws://localhost:8080/chat/rooms/{방번호} 으로 요청이 들어오면 websocket 통신을 진행한다.
// setAllowedOrigins("*")는 모든 ip에서 접속 가능하도록 해줌
registry.addHandler(socketTextHandler, "/chat/rooms/*")
.addInterceptors(ChattingHandshakeInterceptor)
//cors설정
.setAllowedOrigins("*");
//sockjs설정
// .withSockJS();
}
}
sockjs는 현재 cors에러가 생겨서 주석처리를 해놓았다.
setAllowedOrigins 는 cors메서드인데 여기서 허용하는 주소를 설정하면 해당하는주소만 접근할수있다고한다.
현재는 " * " 로 모든 주소에서 접근이 가능하도록 처리해주었다.
addInterceptors는 웹소켓에 클라이언트가 핸드셰이킹(연결)이 일어나기전에 필요한 처리를 해줄수있는 인터셉터를 추가해줄수있는 메서드이다.
요청하는 주소에 방번호를 가지고있어서 해당 데이터를 처리해주기위해서 인터셉터를 추가해주었다.
현재의 데이터베이스는 직원의 연차에 대해 저장하는 컬럼이 아무데도 없으므로 데이터베이스 부터 수정해주었다.
서비스 테이블구조
직원테이블에 직원이 몇개의 연차를 가지고있는지를 저장하기위해서 연차 컬럼을 추가해주었고.
신청한연차를 기록하기위해서 연차기록테이블을 만들어주었다.
올해입사한 직원은 11일 그외에는 15일 이라는 규정을 상수로 만들까하다가 변경이 생기는경우
데이터베이스에서 모두 처리해주기 위해서 정책테이블을 만들어주었다.
연차에대한 규정은 annualLeave(정책구분) - newEmployee , experienced (정책이름) 으로 조회해서 정책내용으로 받아올수있다. 나름 트리 구조나 카테고리같은 구조를 생각하고 만들었는데 효용성이 있는지는 잘 모르겠다.
나중에 정책구분도 따로 테이블이 생긴다면 외래키로 조회해서
연차관련 정책을 한번에 받아온다던가 하는데에 쓰일것같아서 만들어봤다.
연차세팅
우선은 직원들의 연차를 초기화 시킬수있는 기능을 만들었다.
Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/annual-leave")
public class AnnualLeaveController {
private final AnnualLeaveService service;
@PutMapping("/set-annual-leave")
public void setAnnualLeave(){
service.setAnnualLeave();
}
}
Service
@Service
@RequiredArgsConstructor
public class AnnualLeaveService {
private final MemberRepository memberRepository;
private final CompanyPolicyRepository policyRepository;
@Transactional
public void setAnnualLeave() {
int newEmployee = getAnnualLeavePolicy("newEmployee");
int experienced = getAnnualLeavePolicy("experienced");
memberRepository.findAll().stream().forEach(employee -> {
//올해
int thisYear = LocalDate.now().getYear();
//직원의 입사연도정보
int employeeStartYear = employee.getStartDate().getYear();
if(employeeStartYear == thisYear){
employee.setAnnualLeave(newEmployee);
}else{
employee.setAnnualLeave(experienced);
}
});
}
private int getAnnualLeavePolicy(String employeeStatus){
String policyGubn = "annualLeave";
return Integer.parseInt(policyRepository.findByPolicyGubnAndPolicyName(policyGubn,employeeStatus)
.orElseThrow(()->new IllegalArgumentException("없는 정책입니다."))
.getPolicyContent());
}
}
Repository
public interface MemberRepository extends JpaRepository<Employee,Long> {
Employee findByName(String name);
}
아직 리팩토링이 더필요한 부분이긴한데.. 서비스에서 출퇴근리스트를 필터링하고 그룹화해줘서 만들었던 메서드를 일급컬렉션으로 옮기고 응답을 해주는 객체인 CommuteTimeResponse로 매핑해주는 메서드 들이다. 이런 부분들을 jpql로 애초에 응답객체의 형식에맞춰서 데이터를 조회해올수도있지만 직원객체에서 출퇴근데이터를 이미 가지고있어서 나는 그냥 있는데이터를 처리해서 응답객체를 만들어주는 방법을 사용했다. 성능적으로 뭐가 더 좋은지는 잘 모르겠다.
CommuteTotalResponse(DTO)
@Getter
@Setter
public class CommuteTotalResponse {
private List<CommuteTimeResponse> detail = new ArrayList<>();
private Integer sum;
public CommuteTotalResponse(List<CommuteTimeResponse> detail) {
this.detail = detail;
this.sum = detail.stream().mapToInt(CommuteTimeResponse::getWorkingMinutes).sum();
}
}