구독하기 2
<Subscribe.java>
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(
uniqueConstraints = {
@UniqueConstraint(
name="subscribe_uk",
columnNames = {"fromUserId", "toUserId"}
)
}
)
public class Subscribe {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@JoinColumn(name = "fromUserId")
@ManyToOne
private User fromUser;
@JoinColumn(name = "toUserId")
@ManyToOne
private User toUser;
private LocalDateTime createDate;
@PrePersist
public void createDate() {
this.createDate = LocalDateTime.now();
}
}
<SubscribeApiController.java>
@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);
}
}
<SubscribeService.java>
@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);
}
}
<SubscribeRepository.java>
public interface SubscribeRepository extends JpaRepository<Subscribe, Integer>{
@Modifying
@Query(value = "INSERT INTO subscribe(fromUserId, toUserId, createDate) VALUES(:fromUserId, :toUserId, now())", nativeQuery = true)
void mSubscribe(int fromUserId, int toUserId);
@Modifying
@Query(value = "DELETE FROM subscribe WHERE fromUserId = :fromUserId AND toUserId = :toUserId", nativeQuery = true)
void mUnSubscribe(int fromUserId, int toUserId);
}
postman 에서 아래와 같이 로그인 한다.
검은부분에 post 요청 주소, username, password 값 넣고 로그인

성공적인 로그인이 되면 아래와 같이 200번

그 후, 아래와 같이 2번 유저를 구독한다.

SubscribeApiController.java 에서
구독하기 주소가 아래와 같으므로
@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);
}
성공하면

위와 같은 메세지가 postman에 나오게 된다.
위에 더보기에 보여준 듯이, SubscribeApiController.java 에서 구독하기 메서드의 리턴값이 아래와 같은 형태이므로
return new ResponseEntity<>(new CMRespDto<>(1, "구독하기 성공", null), HttpStatus.OK);
데이터베이스에서도 아래와 같은 결과를 확인할 수 있다.

<예외처리>
Subscribe.java 에서
@Table(
uniqueConstraints = {
@UniqueConstraint(
name="subscribe_uk",
columnNames = {"fromUserId", "toUserId"}
)
}
)
이와 같은 처리를 했기 때문에 동일한 유저를 또 구독하면 에러가 생기게 된다.
따라서
만약 1번 유저가 2번 유저를 한 번 더 구독하면, 아래와 같은 메세지가 나오도록 예외처리

<SubscribeService.java> - 이 부분은 위에서 SubscribeService.java 파일 첨부할 때 이미 이렇게 되어있었음
@Transactional
public void 구독하기(int fromUserId, int toUserId) {
try {
subscribeRepository.mSubscribe(fromUserId, toUserId);
} catch (Exception e) {
throw new CustomApiException("이미 구독을 하였습니다.");
}
}
<CustomApiException.java>
public class CustomApiException extends RuntimeException{
private static final long serialVersionUID = 1L;
public CustomApiException(String message) {
super(message);
}
}
<ControllerExceptionHandler.java>
@ExceptionHandler(CustomApiException.class)
public ResponseEntity<?> apiException(CustomApiException e) {
return new ResponseEntity<>(new CMRespDto<>(-1, e.getMessage(), null), HttpStatus.BAD_REQUEST);
}
추가적으로, 구독취소하기도 deletemapping 으로 하면 아래와 같이 잘됨

마지막으로, SecurityConfig.java 에서,
.antMatchers("/", "/user/**", "/image/**", "/subscribe/**", "/comment/**", "/api/**").authenticated()
이 중에 추가 안 된 부분 있으면 추가 시켜놓기.
참고 자료 : 이지업 사이트 강의 "스프링부트 SNS프로젝트 - 포토그램 만들기"