From baad5653e885f222cb3733f468ee79461f07c09e Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 2 Aug 2023 16:46:56 +0900 Subject: [PATCH] =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B3=B5?= =?UTF-8?q?=EC=A7=80=EC=82=AC=ED=95=AD=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/notice/CreateNoticeRequest.kt | 10 +++ .../sodalive/notice/GetNoticeResponse.kt | 13 ++++ .../sodalive/notice/ServiceNotice.kt | 15 +++++ .../notice/ServiceNoticeController.kt | 38 +++++++++++ .../sodalive/notice/ServiceNoticeService.kt | 66 +++++++++++++++++++ .../notice/ServiceServiceNoticeRepository.kt | 37 +++++++++++ .../sodalive/notice/UpdateNoticeRequest.kt | 7 ++ 7 files changed, 186 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/notice/CreateNoticeRequest.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/notice/GetNoticeResponse.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNotice.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceServiceNoticeRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/notice/UpdateNoticeRequest.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/notice/CreateNoticeRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/notice/CreateNoticeRequest.kt new file mode 100644 index 0000000..5c48a40 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/notice/CreateNoticeRequest.kt @@ -0,0 +1,10 @@ +package kr.co.vividnext.sodalive.notice + +data class CreateNoticeRequest( + val title: String, + val content: String +) { + fun toEntity(): ServiceNotice { + return ServiceNotice(title, content) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/notice/GetNoticeResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/notice/GetNoticeResponse.kt new file mode 100644 index 0000000..aa35bbf --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/notice/GetNoticeResponse.kt @@ -0,0 +1,13 @@ +package kr.co.vividnext.sodalive.notice + +data class GetNoticeResponse( + val totalCount: Int, + val noticeList: List +) + +data class NoticeItem( + val id: Long, + val title: String, + val content: String, + val date: String +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNotice.kt b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNotice.kt new file mode 100644 index 0000000..6800fff --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNotice.kt @@ -0,0 +1,15 @@ +package kr.co.vividnext.sodalive.notice + +import kr.co.vividnext.sodalive.common.BaseEntity +import javax.persistence.Column +import javax.persistence.Entity + +@Entity +data class ServiceNotice( + @Column(nullable = false) + var title: String, + @Column(columnDefinition = "TEXT", nullable = false) + var content: String, + @Column(nullable = false) + var isActive: Boolean = true +) : BaseEntity() diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeController.kt new file mode 100644 index 0000000..f1f7921 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeController.kt @@ -0,0 +1,38 @@ +package kr.co.vividnext.sodalive.notice + +import kr.co.vividnext.sodalive.common.ApiResponse +import org.springframework.data.domain.Pageable +import org.springframework.security.access.prepost.PreAuthorize +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 + +@RestController +@RequestMapping("/notice") +class ServiceNoticeController(private val service: ServiceNoticeService) { + @PostMapping + @PreAuthorize("hasRole('ADMIN')") + fun createNotice(@RequestBody request: CreateNoticeRequest) = ApiResponse.ok( + service.save(request), + "등록되었습니다." + ) + + @PutMapping + @PreAuthorize("hasRole('ADMIN')") + fun updateNotice(@RequestBody request: UpdateNoticeRequest) = ApiResponse.ok( + service.update(request), + "수정되었습니다." + ) + + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('ADMIN')") + fun deleteCoin(@PathVariable id: Long) = ApiResponse.ok(service.delete(id), "삭제되었습니다.") + + @GetMapping + fun getNoticeList(pageable: Pageable, timezone: String) = ApiResponse.ok(service.getNoticeList(pageable, timezone)) +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeService.kt new file mode 100644 index 0000000..10d28c2 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceNoticeService.kt @@ -0,0 +1,66 @@ +package kr.co.vividnext.sodalive.notice + +import kr.co.vividnext.sodalive.common.SodaException +import org.springframework.data.domain.Pageable +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.ZoneId +import java.time.format.DateTimeFormatter + +@Service +@Transactional(readOnly = true) +class ServiceNoticeService(private val repository: ServiceServiceNoticeRepository) { + @Transactional + fun save(request: CreateNoticeRequest): Long { + if (request.title.isBlank()) throw SodaException("제목을 입력하세요.") + if (request.content.isBlank()) throw SodaException("내용을 입력하세요.") + + val notice = request.toEntity() + return repository.save(notice).id!! + } + + @Transactional + fun update(request: UpdateNoticeRequest) { + if (request.id <= 0) throw SodaException("잘못된 요청입니다.") + if (request.title.isNullOrBlank() && request.content.isNullOrBlank()) { + throw SodaException("수정할 내용을 입력하세요.") + } + + val notice = repository.findByIdOrNull(request.id) + ?: throw SodaException("잘못된 요청입니다.") + + if (!request.title.isNullOrBlank()) notice.title = request.title + if (!request.content.isNullOrBlank()) notice.content = request.content + } + + @Transactional + fun delete(id: Long) { + if (id <= 0) throw SodaException("잘못된 요청입니다.") + val notice = repository.findByIdOrNull(id) + ?: throw SodaException("잘못된 요청입니다.") + + notice.isActive = false + } + + fun getNoticeList(pageable: Pageable, timezone: String): GetNoticeResponse { + val totalCount = repository.getNoticeTotalCount() + val noticeList = repository.getNoticeList(pageable) + .asSequence() + .map { + val createdAt = it.createdAt!! + .atZone(ZoneId.of("UTC")) + .withZoneSameInstant(ZoneId.of(timezone)) + + NoticeItem( + it.id!!, + it.title, + it.content, + createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + ) + } + .toList() + + return GetNoticeResponse(totalCount, noticeList) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceServiceNoticeRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceServiceNoticeRepository.kt new file mode 100644 index 0000000..90d5a47 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/notice/ServiceServiceNoticeRepository.kt @@ -0,0 +1,37 @@ +package kr.co.vividnext.sodalive.notice + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.notice.QServiceNotice.serviceNotice +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface ServiceServiceNoticeRepository : JpaRepository, ServiceNoticeQueryRepository + +interface ServiceNoticeQueryRepository { + fun getNoticeTotalCount(): Int + fun getNoticeList(pageable: Pageable): List +} + +@Repository +class ServiceNoticeQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : ServiceNoticeQueryRepository { + override fun getNoticeTotalCount(): Int { + return queryFactory + .select(serviceNotice.id) + .from(serviceNotice) + .where(serviceNotice.isActive.isTrue) + .fetch() + .size + } + + override fun getNoticeList(pageable: Pageable): List { + return queryFactory + .selectFrom(serviceNotice) + .where(serviceNotice.isActive.isTrue) + .offset(pageable.offset) + .limit(pageable.pageSize.toLong()) + .orderBy(serviceNotice.id.desc()) + .fetch() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/notice/UpdateNoticeRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/notice/UpdateNoticeRequest.kt new file mode 100644 index 0000000..c3da07d --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/notice/UpdateNoticeRequest.kt @@ -0,0 +1,7 @@ +package kr.co.vividnext.sodalive.notice + +data class UpdateNoticeRequest( + val id: Long, + val title: String? = null, + val content: String? = null +)