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
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package hs.kr.entrydsm.feed.adapter.`in`.screen

import hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response.QueryScreenResponse
import hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response.ScreenResponse
import hs.kr.entrydsm.feed.application.screen.port.`in`.CreateScreenUseCase
import hs.kr.entrydsm.feed.application.screen.port.`in`.QueryScreenUseCase
import hs.kr.entrydsm.feed.application.screen.port.`in`.UpdateScreenUseCase
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PatchMapping
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.RequestPart
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
import java.util.UUID

/**
* 화면 정보 관련 HTTP 요청을 처리하는 웹 어댑터 클래스입니다.
*
* 이 클래스는 화면 정보와 관련된 모든 HTTP 엔드포인트를 제공하며,
* 클라이언트의 요청을 적절한 서비스 메서드로 라우팅합니다.
*
* @property screenService 화면 정보 비즈니스 로직을 처리하는 서비스
*/
@RestController
@RequestMapping("/screen")
class ScreenWebAdapter(
private val createScreenUseCase: CreateScreenUseCase,
private val updateScreenUseCase: UpdateScreenUseCase,
private val queryScreenUseCase: QueryScreenUseCase,
) {
/**
* 새로운 화면 이미지를 업로드하고 저장합니다.
*
* @param image 업로드할 화면 이미지 파일
* @return 업로드된 화면 이미지 정보가 포함된 응답 객체
*/
@ResponseStatus(value = HttpStatus.CREATED)
@PostMapping
suspend fun createScreen(
@RequestPart(name = "image") image: MultipartFile,
): ScreenResponse = createScreenUseCase.execute(image)
Comment thread
coehgns marked this conversation as resolved.

/**
* 기존 화면 이미지를 새로운 이미지로 업데이트합니다.
*
* @param id 업데이트할 화면의 고유 식별자
* @param image 새로운 화면 이미지 파일
* @return 업데이트된 화면 이미지 정보가 포함된 응답 객체
*/
@PatchMapping("/{screen-id}")
fun updateScreen(
@PathVariable(name = "screen-id") id: UUID,
@RequestPart(name = "image") image: MultipartFile,
): ScreenResponse = updateScreenUseCase.execute(id, image)

/**
* 모든 화면 이미지 목록을 조회합니다.
*
* @return 화면 이미지 목록이 포함된 응답 객체 리스트
*/
@GetMapping
fun queryScreen(): List<QueryScreenResponse> = queryScreenUseCase.execute()
Comment thread
coehgns marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response

import java.time.LocalDateTime
import java.util.UUID

/**
* 화면 정보 조회 응답을 위한 데이터 클래스입니다.
* 화면의 상세 정보와 메타데이터를 클라이언트에 반환할 때 사용됩니다.
*
* @property id 화면 정보의 고유 식별자 (UUID)
* @property image 화면에 표시될 이미지의 URL 또는 경로
* @property createAt 화면 정보가 생성된 일시
* @property modifyAt 화면 정보가 마지막으로 수정된 일시
*/
data class QueryScreenResponse(
val id: UUID,
val image: String,
val createAt: LocalDateTime,
val modifyAt: LocalDateTime,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response

/**
* 화면 정보 응답을 위한 데이터 클래스입니다.
* 클라이언트에게 반환되는 화면 관련 정보를 담고 있습니다.
*
* @property image 화면에 표시될 이미지의 URL 또는 경로
*/
data class ScreenResponse(
val image: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package hs.kr.entrydsm.feed.adapter.out.entity.screen

import hs.kr.entrydsm.feed.global.entity.BaseEntity
import jakarta.persistence.Column
import jakarta.persistence.Entity
import java.util.UUID

/**
* 화면 정보를 데이터베이스에 저장하기 위한 JPA 엔티티 클래스입니다.
*
* @property image 화면에 표시될 이미지의 경로 또는 URL
* @property adminId 화면을 등록한 관리자 ID (UUID)
* @param id 엔티티의 고유 식별자 (생성 시 자동 생성됨)
*/
@Entity(name = "tbl_screen")
class ScreenJpaEntity(
id: UUID? = null,
var image: String,
@Column(columnDefinition = "BINARY(16)")
val adminId: UUID,
) : BaseEntity(id)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package hs.kr.entrydsm.feed.adapter.out.mapper.screen

import hs.kr.entrydsm.feed.adapter.out.entity.screen.ScreenJpaEntity
import hs.kr.entrydsm.feed.model.screen.Screen
import org.mapstruct.Mapper

/**
* 화면(Screen) 도메인 모델과 JPA 엔티티 간의 변환을 담당하는 매퍼 인터페이스입니다.
* MapStruct를 사용하여 구현체가 자동으로 생성됩니다.
*/
@Mapper(componentModel = "spring")
interface ScreenMapper {
/**
* Screen 도메인 모델을 JPA 엔티티로 변환합니다.
*
* @param model 변환할 Screen 도메인 모델
* @return 변환된 ScreenJpaEntity 인스턴스
*/
fun toEntity(model: Screen): ScreenJpaEntity

/**
* JPA 엔티티를 Screen 도메인 모델로 변환합니다.
*
* @param entity 변환할 ScreenJpaEntity 인스턴스
* @return 변환된 Screen 도메인 모델
*/
fun toModel(entity: ScreenJpaEntity): Screen
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package hs.kr.entrydsm.feed.adapter.out.persistence.screen

import hs.kr.entrydsm.feed.adapter.out.mapper.screen.ScreenMapper
import hs.kr.entrydsm.feed.adapter.out.persistence.screen.repository.ScreenRepository
import hs.kr.entrydsm.feed.application.screen.port.out.FindScreenPort
import hs.kr.entrydsm.feed.application.screen.port.out.SaveScreenPort
import hs.kr.entrydsm.feed.model.screen.Screen
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Component
import java.util.UUID

/**
* 화면 정보 도메인과 데이터베이스 간의 상호작용을 담당하는 어댑터 클래스입니다.
*
* @property screenRepository 화면 정보 엔티티를 데이터베이스에서 조작하기 위한 리포지토리
* @property screenMapper 화면 정보 도메인 객체와 엔티티 간의 변환을 담당하는 매퍼
*/
@Component
class ScreenPersistenceAdapter(
private val screenRepository: ScreenRepository,
private val screenMapper: ScreenMapper,
) : SaveScreenPort, FindScreenPort {
override fun saveScreen(screen: Screen) {
screenRepository.save(screenMapper.toEntity(screen))
}

override fun findAll(): List<Screen> {
return screenRepository.findAll().map { screenMapper.toModel(it) }
}
Comment thread
coehgns marked this conversation as resolved.

override fun findByIdOrNull(screenId: UUID): Screen? =
screenRepository.findByIdOrNull(screenId)?.let {
screenMapper.toModel(it)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package hs.kr.entrydsm.feed.adapter.out.persistence.screen.repository

import hs.kr.entrydsm.feed.adapter.out.entity.screen.ScreenJpaEntity
import org.springframework.data.jpa.repository.JpaRepository
import java.util.UUID

/**
* 화면(Screen) 데이터에 접근하기 위한 JPA Repository 인터페이스입니다.
* 화면 엔티티의 CRUD 작업을 위한 기본 메서드를 상속받아 사용합니다.
*/
interface ScreenRepository : JpaRepository<ScreenJpaEntity, UUID>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package hs.kr.entrydsm.feed.application.screen.exception

import hs.kr.entrydsm.feed.global.error.exception.CasperException
import hs.kr.entrydsm.feed.global.error.exception.ErrorCode

/**
* 화면 정보를 찾을 수 없을 때 발생하는 예외 클래스입니다.
*
* @property status HTTP 상태 코드 (404)
* @property message 에러 메시지
*/
object ScreenNotFoundException : CasperException(
ErrorCode.SCREEN_NOT_FOUND,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package hs.kr.entrydsm.feed.application.screen.port.`in`

import hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response.ScreenResponse
import org.springframework.web.multipart.MultipartFile

/**
* 화면 생성을 위한 유스케이스 인터페이스입니다.
* 화면 도메인에서 새로운 화면 이미지를 업로드하고 생성하는 역할을 담당합니다.
*/
interface CreateScreenUseCase {

suspend fun execute(file: MultipartFile): ScreenResponse
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package hs.kr.entrydsm.feed.application.screen.port.`in`

import hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response.QueryScreenResponse
Comment thread
coehgns marked this conversation as resolved.

/**
* 화면 목록 조회를 위한 유스케이스 인터페이스입니다.
* 화면 도메인에서 모든 화면 목록을 조회하는 역할을 담당합니다.
*/
interface QueryScreenUseCase {
/**
* 모든 화면 목록을 조회합니다.
*
* @return 화면 목록 응답
*/
fun execute(): List<QueryScreenResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package hs.kr.entrydsm.feed.application.screen.port.`in`

import hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response.ScreenResponse
import org.springframework.web.multipart.MultipartFile
import java.util.UUID

/**
* 화면 업데이트를 위한 유스케이스 인터페이스입니다.
* 화면 도메인에서 기존 화면 이미지를 새로운 이미지로 업데이트하는 역할을 담당합니다.
*/
interface UpdateScreenUseCase {
/**
* 특정 화면 이미지를 업데이트합니다.
*
* @param screenId 업데이트할 화면의 고유 식별자
* @param file 새로운 화면 이미지 파일
* @return 화면 업데이트 응답
*/
fun execute(
screenId: UUID,
file: MultipartFile,
): ScreenResponse
}
Comment thread
coehgns marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package hs.kr.entrydsm.feed.application.screen.port.out

import hs.kr.entrydsm.feed.model.screen.Screen
import java.util.UUID

/**
* 화면 조회를 위한 포트 인터페이스입니다.
* 화면 도메인 객체를 다양한 방식으로 조회하는 메서드를 정의합니다.
*/
interface FindScreenPort {
/**
* 모든 화면을 조회합니다.
*
* @return 모든 화면 목록 (없을 경우 빈 목록)
*/
fun findAll(): List<Screen>

/**
* 화면 ID로 화면을 조회합니다.
*
* @param screenId 조회할 화면의 고유 식별자
* @return 조회된 화면 객체, 없을 경우 null
*/
fun findByIdOrNull(screenId: UUID): Screen?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package hs.kr.entrydsm.feed.application.screen.port.out

import hs.kr.entrydsm.feed.model.screen.Screen

/**
* 화면 저장을 위한 포트 인터페이스입니다.
* 화면 도메인 객체를 저장하거나 업데이트하는 메서드를 정의합니다.
*/
interface SaveScreenPort {
/**
* 화면을 저장하거나 업데이트합니다.
*
* @param screen 저장하거나 업데이트할 화면 도메인 객체
*/
fun saveScreen(screen: Screen)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package hs.kr.entrydsm.feed.application.screen.service

import hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response.ScreenResponse
import hs.kr.entrydsm.feed.application.screen.port.`in`.CreateScreenUseCase
import hs.kr.entrydsm.feed.application.screen.port.out.SaveScreenPort
import hs.kr.entrydsm.feed.global.utils.admin.AdminUtils
import hs.kr.entrydsm.feed.infrastructure.s3.PathList
import hs.kr.entrydsm.feed.infrastructure.s3.util.FileUtil
import hs.kr.entrydsm.feed.model.screen.Screen
import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile

/**
* 화면 이미지 생성을 처리하는 서비스 클래스입니다.
*
* @property saveScreenPort 화면 저장을 위한 포트
* @property userUtils 사용자 인증 유틸리티
* @property fileUtil 파일 업로드 유틸리티
*/
@Service
class CreateScreenService(
private val saveScreenPort: SaveScreenPort,
private val adminUtils: AdminUtils,
private val fileUtil: FileUtil,
) : CreateScreenUseCase {

override suspend fun execute(file: MultipartFile): ScreenResponse {
val adminId = adminUtils.getCurrentAdmin().id

val fileName = fileUtil.upload(file, PathList.SCREEN)
saveScreenPort.saveScreen(
Screen(
image = fileName,
adminId = adminId,
),
)
return ScreenResponse(fileName)
}
Comment thread
coehgns marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package hs.kr.entrydsm.feed.application.screen.service

import hs.kr.entrydsm.feed.adapter.`in`.screen.dto.response.QueryScreenResponse
import hs.kr.entrydsm.feed.application.screen.port.`in`.QueryScreenUseCase
import hs.kr.entrydsm.feed.application.screen.port.out.FindScreenPort
import hs.kr.entrydsm.feed.infrastructure.s3.PathList
import hs.kr.entrydsm.feed.infrastructure.s3.util.FileUtil
import org.springframework.stereotype.Service

/**
* 화면 이미지 목록 조회를 처리하는 서비스 클래스입니다.
*
* @property findScreenPort 화면 조회를 위한 포트
* @property fileUtil 파일 URL 생성을 위한 유틸리티
*/
@Service
class QueryScreenService(
private val findScreenPort: FindScreenPort,
private val fileUtil: FileUtil,
) : QueryScreenUseCase {
/**
* 모든 화면 이미지 목록을 조회합니다.
*
* @return 화면 이미지 목록 (각 항목은 ID, URL, 생성일시, 수정일시 포함)
*/
override fun execute(): List<QueryScreenResponse> {
return findScreenPort.findAll()
.map { it ->
QueryScreenResponse(
it.id!!,
Comment thread
coehgns marked this conversation as resolved.
fileUtil.generateObjectUrl(it.image, PathList.SCREEN),
it.createdAt,
it.modifiedAt,
)
}
}
}
Loading
Loading