서비스 공지사항 API 추가

This commit is contained in:
Klaus 2023-08-02 16:46:56 +09:00
parent 0c106540cd
commit baad5653e8
7 changed files with 186 additions and 0 deletions

View File

@ -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)
}
}

View File

@ -0,0 +1,13 @@
package kr.co.vividnext.sodalive.notice
data class GetNoticeResponse(
val totalCount: Int,
val noticeList: List<NoticeItem>
)
data class NoticeItem(
val id: Long,
val title: String,
val content: String,
val date: String
)

View File

@ -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()

View File

@ -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))
}

View File

@ -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)
}
}

View File

@ -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<ServiceNotice, Long>, ServiceNoticeQueryRepository
interface ServiceNoticeQueryRepository {
fun getNoticeTotalCount(): Int
fun getNoticeList(pageable: Pageable): List<ServiceNotice>
}
@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<ServiceNotice> {
return queryFactory
.selectFrom(serviceNotice)
.where(serviceNotice.isActive.isTrue)
.offset(pageable.offset)
.limit(pageable.pageSize.toLong())
.orderBy(serviceNotice.id.desc())
.fetch()
}
}

View File

@ -0,0 +1,7 @@
package kr.co.vividnext.sodalive.notice
data class UpdateNoticeRequest(
val id: Long,
val title: String? = null,
val content: String? = null
)