Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/kotlin/gogo/gogostage/GogoStageApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gogo.gogostage

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.scheduling.annotation.EnableAsync
import org.springframework.scheduling.annotation.EnableScheduling

@EnableScheduling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class BoardProcessor(
isFiltered = false,
createdAt = LocalDateTime.now(),
imageUrl = writeCommunityBoardDto.imageUrl,
viewCount = 0
)

return boardRepository.save(board)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class Board(
@Column(name = "like_count", nullable = false)
var likeCount: Int,

@Column(name = "view_count", nullable = false)
var viewCount: Int,

@Column(name = "is_filtered", nullable = false)
var isFiltered: Boolean,

Expand All @@ -57,4 +60,8 @@ class Board(
isFiltered = true
}

fun plusViewCount() {
viewCount += 1
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gogo.gogostage.domain.community.boardview.persistence

import gogo.gogostage.domain.community.board.persistence.Board
import jakarta.persistence.*

@Entity
@Table(name = "tbl_board_view")
class BoardView(

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
val id: Long = 0,

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id", nullable = false)
val board: Board,

@Column(name = "student_id", nullable = false)
val studentId: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package gogo.gogostage.domain.community.boardview.persistence

import org.springframework.data.jpa.repository.JpaRepository

interface BoardViewRepository: JpaRepository<BoardView, Long> {

fun existsByBoardIdAndStudentId(boardId: Long, studentId: Long): Boolean
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package gogo.gogostage.domain.community.root.application

import gogo.gogostage.domain.community.board.application.BoardReader
import gogo.gogostage.domain.community.board.persistence.Board
import gogo.gogostage.domain.community.board.persistence.BoardRepository
import gogo.gogostage.domain.community.boardlike.persistence.BoardLike
import gogo.gogostage.domain.community.boardlike.persistence.BoardLikeRepository
import gogo.gogostage.domain.community.boardview.persistence.BoardView
import gogo.gogostage.domain.community.boardview.persistence.BoardViewRepository
import gogo.gogostage.domain.community.comment.persistence.Comment
import gogo.gogostage.domain.community.comment.persistence.CommentRepository
import gogo.gogostage.domain.community.commentlike.persistence.CommentLike
import gogo.gogostage.domain.community.commentlike.persistence.CommentLikeRepository
import gogo.gogostage.domain.community.root.application.dto.*
import gogo.gogostage.domain.community.root.event.BoardViewEvent
import gogo.gogostage.global.error.StageException
import gogo.gogostage.global.internal.student.stub.StudentByIdStub
import org.springframework.data.repository.findByIdOrNull
Expand All @@ -24,6 +28,8 @@ class CommunityProcessor(
private val commentLikeRepository: CommentLikeRepository,
private val commentMapper: CommunityMapper,
private val boardRepository: BoardRepository,
private val boardViewRepository: BoardViewRepository,
private val boardReader: BoardReader
) {

fun likeBoard(studentId: Long, board: Board): LikeResDto {
Expand Down Expand Up @@ -130,4 +136,22 @@ class CommunityProcessor(

commentRepository.save(comment)
}

@Transactional
fun saveBoardView(event: BoardViewEvent) {
val board = boardReader.read(event.boardId)

if (!boardViewRepository.existsByBoardIdAndStudentId(board.id, board.studentId)) {
val newBoardView = BoardView(
board = board,
studentId = board.studentId,
)

boardViewRepository.save(newBoardView)

board.plusViewCount()

boardRepository.save(board)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import gogo.gogostage.domain.community.board.application.BoardProcessor
import gogo.gogostage.domain.community.board.application.BoardReader
import gogo.gogostage.domain.community.root.application.dto.*
import gogo.gogostage.domain.community.root.event.BoardCreateEvent
import gogo.gogostage.domain.community.root.event.BoardViewEvent
import gogo.gogostage.domain.community.root.event.CommentCreateEvent
import gogo.gogostage.domain.community.root.persistence.SortType
import gogo.gogostage.domain.game.persistence.GameCategory
Expand Down Expand Up @@ -55,7 +56,16 @@ class CommunityServiceImpl(
val board = boardReader.read(boardId)
stageValidator.validStage(student, board.community.stage.id)
stageValidator.validProfanityFilter(student, board)
return communityReader.readBoardInfo(isFiltered, board, student)
val response = communityReader.readBoardInfo(isFiltered, board, student)

applicationEventPublisher.publishEvent(
BoardViewEvent(
boardId = boardId,
studentId = student.studentId,
)
)

return response
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ data class GetCommunityBoardInfoResDto(
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
val createdAt: LocalDateTime,
val imageUrl: String?,
val viewCount: Int,
val stage: StageDto,
val commentCount: Int,
val comment: List<CommentDto>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package gogo.gogostage.domain.community.root.event

data class BoardViewEvent(
val boardId: Long,
val studentId: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gogo.gogostage.domain.community.root.event.handler

import gogo.gogostage.domain.community.root.application.CommunityProcessor
import gogo.gogostage.domain.community.root.event.BoardViewEvent
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Component
import org.springframework.transaction.event.TransactionPhase
import org.springframework.transaction.event.TransactionalEventListener

@Component
class BoardViewEventHandler(
private val communityProcessor: CommunityProcessor,
) {

@Async("asyncExecutor")
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
fun eventHandler(event: BoardViewEvent) {
communityProcessor.saveBoardView(event)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ class CommunityCustomRepositoryImpl(
stage = stageDto,
commentCount = board.commentCount,
comment = commentDto,
imageUrl = board.imageUrl
imageUrl = board.imageUrl,
viewCount = board.viewCount,
)

return response
Expand Down
32 changes: 32 additions & 0 deletions src/main/kotlin/gogo/gogostage/global/config/AsyncConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package gogo.gogostage.global.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.annotation.EnableAsync
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import java.util.concurrent.Executor
import java.util.concurrent.ThreadPoolExecutor


@Configuration
@EnableAsync
class AsyncConfig {

@Bean(name = ["asyncExecutor"])
fun asyncExecutor(): Executor {
val executor = ThreadPoolTaskExecutor()
executor.corePoolSize = 5
executor.maxPoolSize = 20
executor.queueCapacity = 50
executor.keepAliveSeconds = 60
executor.setAllowCoreThreadTimeOut(true)
executor.setPrestartAllCoreThreads(true)
executor.setWaitForTasksToCompleteOnShutdown(true)
executor.setAwaitTerminationSeconds(20)
executor.setRejectedExecutionHandler(ThreadPoolExecutor.CallerRunsPolicy())
executor.initialize()

return executor
}

}