Skip to content

Commit

Permalink
Merge pull request #25 from jojaeng2/feature/#14-#15-#16-CRUD-작성
Browse files Browse the repository at this point in the history
[피드] 댓글, 공유하기, 좋아요 CRUD 작성
  • Loading branch information
jojaeng2 authored Sep 20, 2023
2 parents 11909e2 + bf7745d commit 2e8bdb8
Show file tree
Hide file tree
Showing 23 changed files with 406 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package joryu.sns_service.comment.controller

import joryu.sns_service.comment.dto.request.CommentCreateRequest
import joryu.sns_service.comment.dto.request.CommentUpdateRequest
import joryu.sns_service.comment.dto.response.CommentResponse
import joryu.sns_service.comment.service.CommentService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.net.URI

@RestController
@RequestMapping("/comments")
class CommentController(
private val commentService: CommentService
) {
@PostMapping
fun createComment(@RequestBody req: CommentCreateRequest): ResponseEntity<Void> {
val commentId = commentService.create(req.postId, req.parentCommentId, req.content)
return ResponseEntity.created(URI.create("/comments/${commentId}")).build()
}

@GetMapping("/{id}")
fun findComment(@PathVariable id: Long): ResponseEntity<CommentResponse> {
val comment = commentService.findOneById(id)
return ResponseEntity.ok(CommentResponse(comment))
}

@PutMapping("/{id}")
fun updateComment(@PathVariable id: Long, @RequestBody req: CommentUpdateRequest): ResponseEntity<Void> {
commentService.update(id, req.content)
return ResponseEntity.noContent().build()
}

@DeleteMapping("/{id}")
fun deleteComment(@PathVariable id: Long): ResponseEntity<Void> {
commentService.delete(id)
return ResponseEntity.noContent().build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package joryu.sns_service.comment.dto.request

data class CommentCreateRequest(
val postId: Long,
val parentCommentId: Long?,
val content: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package joryu.sns_service.comment.dto.request

data class CommentUpdateRequest(
val content: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package joryu.sns_service.comment.dto.response

import joryu.sns_service.comment.entity.Comment

data class CommentResponse(
val commentId: Long,
val postId: Long,
val parentCommentId: Long?,
val content: String,
) {
constructor(comment: Comment) : this(
commentId = comment.id,
postId = comment.post.id,
parentCommentId = comment.parent?.id,
content = comment.content,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ class Comment(
@Column(name = "content", nullable = false, length = 1000)
var content: String = content
private set

fun changeContent(content: String) {
this.content = content
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package joryu.sns_service.comment.service

import joryu.sns_service.comment.entity.Comment
import joryu.sns_service.comment.repository.CommentRepository
import joryu.sns_service.post.repository.PostRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional(readOnly = true)
class CommentService(
private val postRepository: PostRepository,
private val commentRepository: CommentRepository,
) {
@Transactional
fun create(postId: Long, parentCommentId: Long?, content: String): Long {
val post = postRepository.findById(postId).orElseThrow()
val parentComment = parentCommentId?.let { commentRepository.findById(it).orElseThrow() }
return commentRepository.save(Comment(post, parentComment, content)).id
}

fun findOneById(id: Long): Comment {
return commentRepository.findById(id).orElseThrow()
}

@Transactional
fun update(id: Long, newContent: String) {
val commentForUpdate = commentRepository.findById(id).orElseThrow()
commentForUpdate.changeContent(newContent)
}

@Transactional
fun delete(id: Long) {
commentRepository.deleteById(id)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package joryu.sns_service.post.controller

import joryu.sns_service.post.dto.req.PostCreateRequest
import joryu.sns_service.post.dto.req.PostUpdateRequest
import joryu.sns_service.post.dto.resp.PostResponse
import jakarta.servlet.http.HttpServletRequest
import joryu.sns_service.post.dto.request.PostCreateRequest
import joryu.sns_service.post.dto.request.PostUpdateRequest
import joryu.sns_service.post.dto.response.PostResponse
import joryu.sns_service.post.service.PostService
import joryu.sns_service.utils.IpUtils
import org.springframework.http.HttpRequest
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
Expand All @@ -27,8 +30,8 @@ class PostController(
}

@GetMapping("/{id}")
fun findPost(@PathVariable id: Long): ResponseEntity<PostResponse> {
val post = postService.findOneById(id)
fun findPost(@PathVariable id: Long, httpServletRequest: HttpServletRequest): ResponseEntity<PostResponse> {
val post = postService.findOneById(id, IpUtils.getClientIp(httpServletRequest))
return ResponseEntity.ok(PostResponse(post))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package joryu.sns_service.post.controller

import joryu.sns_service.post.dto.response.PostLikeCountResponse
import joryu.sns_service.post.service.PostLikeService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/like")
class PostLikeController(
private val postLikeService: PostLikeService
) {
@PostMapping("/posts/{postId}/member/{memberId}")
fun like(@PathVariable postId: Long, @PathVariable memberId: Long): ResponseEntity<Void> {
postLikeService.like(postId, memberId)
return ResponseEntity.noContent().build()
}

@DeleteMapping("/posts/{postId}/member/{memberId}")
fun cancelLike(@PathVariable postId: Long, @PathVariable memberId: Long): ResponseEntity<Void> {
postLikeService.cancelLike(postId, memberId)
return ResponseEntity.noContent().build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package joryu.sns_service.post.controller

import joryu.sns_service.post.dto.response.PostResponse
import joryu.sns_service.post.service.ShareService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/share")
class ShareController(
private val shareService: ShareService
) {
@PostMapping("/posts/{postId}/member/{memberId}")
fun share(@PathVariable postId: Long, @PathVariable memberId: Long): ResponseEntity<Void> {
shareService.share(postId, memberId)
return ResponseEntity.noContent().build()
}

@GetMapping("/posts/member/{memberId}")
fun findAllSharePosts(@PathVariable memberId: Long): ResponseEntity<List<PostResponse>> {
val shares = shareService.findAllSharePosts(memberId)
return ResponseEntity.ok(shares.map { share -> PostResponse(share.post) })
}

@DeleteMapping("/posts/{postId}/member/{memberId}")
fun cancelLike(@PathVariable postId: Long, @PathVariable memberId: Long): ResponseEntity<Void> {
shareService.cancelShare(postId, memberId)
return ResponseEntity.noContent().build()
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package joryu.sns_service.post.dto.req
package joryu.sns_service.post.dto.request

data class PostCreateRequest(
val content: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package joryu.sns_service.post.dto.req
package joryu.sns_service.post.dto.request

data class PostUpdateRequest(
val content: String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package joryu.sns_service.post.dto.response

data class PostLikeCountResponse(
val likeCount: Long,
)
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package joryu.sns_service.post.dto.resp
package joryu.sns_service.post.dto.response

import joryu.sns_service.post.entity.Post

data class PostResponse(
val id: Long,
val content: String,
val viewCount: Long,
val likeCount: Long,
) {
constructor(post: Post) : this(
id = post.id,
content = post.content,
viewCount = post.viewCount
viewCount = post.getViewCount(),
likeCount = post.getLikeCount(),
)
}
22 changes: 19 additions & 3 deletions sns_service/src/main/kotlin/joryu/sns_service/post/entity/Post.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package joryu.sns_service.post.entity

import jakarta.persistence.CascadeType
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.OneToMany
import jakarta.persistence.Table
import joryu.sns_service.common.entity.BaseEntity
import org.hibernate.Hibernate
import org.hibernate.annotations.LazyCollection
import org.hibernate.annotations.LazyCollectionOption

@Table(name = "post")
@Entity
Expand All @@ -19,15 +24,26 @@ class Post(
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0

@Column(name = "view_count", nullable = false)
var viewCount: Long = 0
private set

@OneToMany(mappedBy = "post", cascade = [CascadeType.REMOVE])
private val postViews: List<PostView> = listOf()

@Column(name = "content", nullable = false, length = 1000)
var content: String = content
private set

@OneToMany(mappedBy = "post")
private val postLikes: List<PostLike> = listOf()

fun changeContent(content: String) {
this.content = content
}

fun getViewCount(): Long {
return Hibernate.size(postViews).toLong()
}

fun getLikeCount(): Long {
return Hibernate.size(postLikes).toLong()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package joryu.sns_service.post.entity

import jakarta.persistence.Entity
import jakarta.persistence.FetchType
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Index
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import joryu.sns_service.common.entity.BaseEntity

@Table(
name = "post_view", indexes = [
Index(name = "idx_post_view", columnList = "post_id, ip", unique = true)
]
)
@Entity
class PostView(
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
val post: Post,

val ip: String,
) : BaseEntity() {
constructor() : this(Post(), "")

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import joryu.sns_service.common.entity.BaseEntity
import joryu.sns_service.profile.entity.Profile

@Table(name = "share")
@Entity
class Share(
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "profile_id", nullable = false)
val shareMember: Profile,

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
val post: Post,
) : BaseEntity() {
constructor() : this(Post())
constructor() : this(Profile(), Post())

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package joryu.sns_service.post.repository

import joryu.sns_service.post.entity.Post
import joryu.sns_service.post.entity.PostLike
import joryu.sns_service.profile.entity.Profile
import org.springframework.data.jpa.repository.JpaRepository

interface PostLikeRepository : JpaRepository<PostLike, Long>
interface PostLikeRepository : JpaRepository<PostLike, Long> {
fun countByPost(post: Post): Long
fun deleteByLikeMemberAndPost(likeMember: Profile, post: Post): Void
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package joryu.sns_service.post.repository

import joryu.sns_service.post.entity.Post
import joryu.sns_service.post.entity.PostView
import org.springframework.data.jpa.repository.JpaRepository

interface PostViewRepository : JpaRepository<PostView, Long> {
fun existsByPostAndIp(post: Post, ip: String): Boolean
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package joryu.sns_service.post.repository

import joryu.sns_service.post.entity.Post
import joryu.sns_service.post.entity.Share
import joryu.sns_service.profile.entity.Profile
import org.springframework.data.jpa.repository.JpaRepository

interface ShareRepository : JpaRepository<Share, Long>
interface ShareRepository : JpaRepository<Share, Long> {
fun findAllByShareMember(shareMember: Profile): List<Share>
fun deleteByShareMemberAndPost(shareMember: Profile, post: Post): Void
}
Loading

0 comments on commit 2e8bdb8

Please sign in to comment.