소셜 로그인은 가장 마지막에 하는걸로 하고, 댓글 기능부터 만들기로 했다.
@Entity
@Table(name = "comments")
class Comment(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
@Column(nullable = false)
var content: String,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
var post: Post,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "admin_id")
var admin: Admin? = null,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
var user: Users? = null,
@Column(nullable = false)
var createdAt: LocalDateTime = LocalDateTime.now()
)
이렇게 유저, 어드민, 게시글과 연결하고
interface CommentRepository : JpaRepository<Comment, Long> {
fun findByPostId(postId: Long): List<Comment>
}
이걸로 댓글 작성시 게시글의 아이디를 찾을수 있게 하고
interface CommentService {
fun createComment(postId: Long, commentRequest: CommentRequest, userPrincipal: UserPrincipal): CommentResponse
fun updateComment(id: Long, commentRequest: CommentRequest, userPrincipal: UserPrincipal): CommentResponse
fun deleteComment(id: Long, userPrincipal: UserPrincipal)
fun getCommentsByPostId(postId: Long): List<CommentResponse>
fun getAllComments(): List<CommentResponse>
fun getCommentById(id: Long): CommentResponse
}
이렇게 생성, 삭제, 수정, 조회를 만들고
@Service
@Transactional
class CommentServiceImpl(
private val commentRepository: CommentRepository,
private val adminRepository: AdminRepository,
private val userRepository: UserRepository,
private val postRepository: PostRepository
) : CommentService {
@Transactional
override fun createComment(postId: Long, commentRequest: CommentRequest, userPrincipal: UserPrincipal): CommentResponse {
val userId = userPrincipal.id
// 각자의 Repository에서 사용자가 존재하는지 확인
val user = userRepository.findById(userId).orElse(null)
val admin = adminRepository.findById(userId).orElse(null)
// 사용자가 존재하지 않으면 예외
if (user == null && admin == null) {
throw ModelNotFoundException("User or Admin not found or deleted", userId)
}
// Post가 존재하는지 확인
val post = postRepository.findById(postId).orElseThrow {
ModelNotFoundException("Post not found or deleted", postId)
}
// Comment 객체를 생성하고 저장
val comment = Comment(
content = commentRequest.content,
post = post,
user = user,
admin = admin
)
val savedComment = commentRepository.save(comment)
return CommentResponse.toResponse(savedComment)
}
@Transactional
override fun updateComment(id: Long, commentRequest: CommentRequest, userPrincipal: UserPrincipal): CommentResponse {
val userId = userPrincipal.id
// 각자의 Repository에서 사용자가 존재하는지 확인
val user = userRepository.findById(userId).orElse(null)
val admin = adminRepository.findById(userId).orElse(null)
// 사용자가 존재하지 않으면 예외
if (user == null && admin == null) {
throw ModelNotFoundException("User or Admin not found or deleted", userId)
}
val comment = commentRepository.findById(id).orElseThrow {
ModelNotFoundException("Comment not found or deleted", id)
}
// 댓글 작성자 또는 어드민 여부 확인
if (comment.user?.id != userId && comment.admin?.id != userId) {
throw IllegalStateException("User does not have permission to update this comment")
}
comment.content = commentRequest.content
comment.updatedAt = LocalDateTime.now()
val updatedComment = commentRepository.save(comment)
return CommentResponse.toResponse(updatedComment)
}
@Transactional
override fun deleteComment(id: Long, userPrincipal: UserPrincipal) {
val userId = userPrincipal.id
// 각자의 Repository에서 사용자가 존재하는지 확인
val user = userRepository.findById(userId).orElse(null)
val admin = adminRepository.findById(userId).orElse(null)
// 사용자가 존재하지 않으면 예외
if (user == null && admin == null) {
throw ModelNotFoundException("User or Admin not found or deleted", userId)
}
val comment = commentRepository.findById(id).orElseThrow {
ModelNotFoundException("Comment not found or deleted", id)
}
// 댓글 작성자 또는 어드민 여부 확인
if (comment.user?.id != userId && comment.admin?.id != userId) {
throw IllegalStateException("User does not have permission to delete this comment")
}
commentRepository.delete(comment)
}
override fun getAllComments(): List<CommentResponse> {
return commentRepository.findAll().map(CommentResponse::toResponse)
}
@Transactional
override fun getCommentById(id: Long): CommentResponse {
val comment = commentRepository.findById(id).orElseThrow { ModelNotFoundException("Comment not found or deleted", id) }
return CommentResponse.toResponse(comment)
}
@Transactional
override fun getCommentsByPostId(postId: Long): List<CommentResponse> {
val comments = commentRepository.findByPostId(postId)
return comments.map(CommentResponse::toResponse)
}
}
이렇게 유저 프린시팔로 유저, 어드민을 각각 감지해서 로그인을 해야 댓글을 생성하고, 글을 작성한 사람만 수정, 삭제를 할수 있게 한다.
@RestController
@RequestMapping("/comments")
class CommentController(val commentService: CommentService) {
@PostMapping("/post/{postId}")
fun createComment(
@PathVariable postId: Long,
@RequestBody commentRequest: CommentRequest,
@AuthenticationPrincipal userPrincipal: UserPrincipal
): ResponseEntity<CommentResponse> {
val response = commentService.createComment(postId, commentRequest, userPrincipal)
return ResponseEntity.ok(response)
}
@PutMapping("/{id}")
fun updateComment(
@PathVariable id: Long,
@RequestBody commentRequest: CommentRequest,
@AuthenticationPrincipal userPrincipal: UserPrincipal
): ResponseEntity<CommentResponse> {
val response = commentService.updateComment(id, commentRequest, userPrincipal)
return ResponseEntity.ok(response)
}
@DeleteMapping("/{id}")
fun deleteComment(
@PathVariable id: Long,
@AuthenticationPrincipal userPrincipal: UserPrincipal
): ResponseEntity<Void> {
commentService.deleteComment(id, userPrincipal)
return ResponseEntity.noContent().build()
}
@GetMapping("/post/{postId}")
fun getCommentsByPostId(@PathVariable postId: Long): ResponseEntity<List<CommentResponse>> {
val comments = commentService.getCommentsByPostId(postId)
return ResponseEntity.ok(comments)
}
@GetMapping
fun getAllComments(): ResponseEntity<List<CommentResponse>> {
val comments = commentService.getAllComments()
return ResponseEntity.ok(comments)
}
@GetMapping("/{id}")
fun getCommentById(@PathVariable id: Long): ResponseEntity<CommentResponse> {
val comment = commentService.getCommentById(id)
return ResponseEntity.ok(comment)
}
}
그리고 이렇게 댓글 생성시에만 포스트 아이디를 입력 하도록 한다.