회원가입, 로그인, 회원수정까지 구현을 완료하였고, 각 기능에서 검증까지 추가하였다.
이번에는 구독기능을 추가하여보자.
하나의 유저는 여러유저 구독 가능(FromUser 와 ToUser는 1 : N)
하나의 유저는 여러유저에게 구독 받기 가능(ToUser와 FromUser는 1 : N)
따라서 최종적으로 fromUser와 toUser는 N:M의 관계를 갖는다.
N:M의 관계에서는 Foreign Key를 특정 테이블에 둘 수 없기에 관계 테이블을 생성한다.
관계 테이블은 원 테이블과 1:N (관계테이블이 N)의 관계를 갖으며, 원 테이블의 PK를 FK로 갖는다.
즉 관계테이블인 Subscribe를 만들어야한다.
Subscribe 클래스를 구현한 뒤 JPA의 어노테이션들을 이용해 테이블화하였다.
상단의 어노테이션은 (FromUserId, ToUserId) 쌍을 unique 하게 하는 제약조건을 @UniqueConstraint 를 이용해 추가한 것이며.
@ManyToOne 어노테이션으로 fromUser가 User테이블과 다대일 매핑의 FK임을 명시하였다.
toUser 또한 User테이블과 다대일 매핑의 FK이다.
이 FK의 이름은 ORM을 자동으로 지정되는데 이를 지정해주기 위해 @JoinColumn을 사용하였다.
SubscribeRepository 이다. 우선 JpaRepository를 상속하여 구현해놓았다.
/api/subscribe/{toUserId} 로 요청이 들어올 때 Post 요청이면 구독을. Delete 요청이면 구독취소를 진행한다.
현재 세션에 접속중인 유저의 Id가 fromUser 가 되며. 사용자가 현재 보고있는 유저정보 페이지의 Id가 toUser가 된다.
subscribeService 객체에서 구독과 구독취소를 진행하며. 수행결과는 CMRespDto에 담기고. 이를 ResponseEntity에 담아 반환한다.
Controller 에서 호출되어 실제 구독과 구독취소를 담당하는 SubscribeService 클래스이다.
구독 시
1. JPA의 subscribeRepository.save()를 사용하고 싶으나, 이 때 파라미터로 Subscribe 객체가 들어간다.
2. 이에 따라 fromUserId 와 toUserId로 Subscribe 객체를 만들면 되나. Id는 int, Subscribe의 필드는 User이다.
3. 따라서 findById를 생성하고, 이를 바탕으로 User를 찾아서 Subscribe 객체에 넣어준 뒤 save하면 된다. 그러나 이는 너무 번거롭다.
따라서 JPA가 제공하는 쿼리 메서드가 아닌 Repository에 사용자가 생성한 네이티브 쿼리들을 사용하자.
그리고 unique constraints 가 위배될 경우 CustomApiException이 터지도록 하였다.
구독과 구독취소의 네이티브 쿼리문을 작성하였다.
: 표시는 메서드의 파라미터를 쿼리문에 사용하겠다는 의미이다.
파라미터로 메시지만 넘어오므로, 이 메시지만 사용한다.
ControllerExceptionHandler에 CustomApiException 을 추가하고 메시지를 담은 CMRespDto 객체를 반환한다.
Postman 으로 Id:2 사용자로 접속 후 http://localhost:8080/api/subscribe/1 요청을 보내자 제대로 성공 CMRespDto를 반환한다.
DB에 중복 추가시 설정해놓은 unique 제약조건을 위배하게 되고, CustomApiException이 터져 에러 메시지를 담은 CMRespDto를 반환하게된다.