[Springboot] 포토그램 구독/구독취소 구현
아이티윌의 국비지원 [스프링부트 SNS 포토그램 프로젝트] 강의를 수강하며 정리한 내용입니다.
오늘의 실습
- 구독 모델 및 API 제작
🔎그 전에 알아야할 것
연관관계 개념
실습
[Subscribe.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table()
public class Subscribe {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@JoinColumn(name = "fromUserId")
@ManyToOne // User 1 : Sub N
private User fromUser;
@JoinColumn(name = "toUserId")
@ManyToOne
private User toUser;
private LocalDateTime createDate;
@PrePersist
public void createDate() {
this.createDate = LocalDateTime.now();
}
}
@Table
: 1번 유저가 2번 유저를 중복해서 팔로우 할 수 없으니 유니크 제약 조건을 추가한다.
@JoinColumn
: 칼럼의 이름을 설정해주는 어노테이션으로 설정해주지 않으면 알아서 이름을 만들어 준다.
@ManyToOne
: 다대일 관계에 사용
구독테이블과 구독유저테이블, 구독받는유저테이블 관계를 보면
subscribe N : fromUserId 1
subscribe N : toUserId 1
이므로 @ManyToOne
어노테이션을 붙여줘야 한다. (Subscribe 엔티티가 여러 User 엔티티와 다대일 관계를 갖는다.)
서버를 실행했을 때 subscribe 테이블이 자동 생성되어 있는 것을 확인!
[SubscribeRepository.java]
1
2
3
4
5
6
7
8
9
10
11
public interface SubscribeRepository extends JpaRepository<Subscribe, Integer>{
@Modifying // INSERT, DELETE, UPDATE 를 네이티브 쿼리로 작성하려면 해당 어노테이션 필요
@Query(value = "INSERT INTO subscribe(fromUserId, toUserId, createDate) VALUES(:fromUserId, :toUserId, now())", nativeQuery = true)
void mSubscribe(@Param("fromUserId") int fromUserId, @Param("toUserId") int toUserId);
@Modifying
@Query(value= "DELETE FROM subscribe WHERE fromUserId=:fromUserId AND toUserId=:toUserId", nativeQuery=true)
void mUnSubscribe(@Param("fromUserId") int fromUserId, @Param("toUserId") int toUserId);
}
@Modifying
: INSERT, DELETE, UPDATE 를 네이티브 쿼리로 작성하려면 해당 어노테이션 필요하다.
fromUserId와 toUserId의 타입이 테이블에선 User이고 Service에선 int이기에 nativeQuery를 만들어주었다.
[SubscribeService.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RequiredArgsConstructor
@Service
public class SubscribeService {
private final SubscribeRepository subscribeRepository;
@Transactional
public void 구독하기(int fromUserId, int toUserId) {
try {
subscribeRepository.mSubscribe(fromUserId, toUserId);
}catch(Exception e) {
throw new CustomApiException("이미 구독을 하였습니다.");
}
}
@Transactional
public void 구독취소하기(int fromUserId, int toUserId) {
subscribeRepository.mUnSubscribe(fromUserId, toUserId);
}
}
구독취소의 경우 오류날 상황이 없다고 생각해 예외처리 안 함!
[SubscribeApiController.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RequiredArgsConstructor
@RestController
public class SubscribeApiController {
private final SubscribeService subscribeService;
@PostMapping("/api/subscribe/{toUserId}")
public ResponseEntity<?> subscribe(@AuthenticationPrincipal PrincipalDetails principalDetails, @PathVariable int toUserId){
subscribeService.구독하기(principalDetails.getUser().getId(), toUserId);
return new ResponseEntity<>(new CMRespDto<>(1, "구독 성공", null), HttpStatus.OK);
}
@DeleteMapping("/api/subscribe/{toUserId}")
public ResponseEntity<?> unSubscribe(@AuthenticationPrincipal PrincipalDetails principalDetails, @PathVariable int toUserId){
subscribeService.구독취소하기(principalDetails.getUser().getId(), toUserId);
return new ResponseEntity<>(new CMRespDto<>(1, "구독 취소성공", null), HttpStatus.OK);
}
}
포스트맨으로 동작 확인
중복해서 구독을 요청할 경우 예외처리 핸들러가 잘 동작하는 것도 확인!
This post is licensed under CC BY 4.0 by the author.