Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] notice 관련 기능 구현 #16

Merged
merged 33 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b8c9315
notice entity 정의
k-kbk Sep 26, 2023
df82249
notice CRUD 구현
k-kbk Sep 27, 2023
0c5a53d
ktlint
k-kbk Sep 27, 2023
ed7e910
[etc] restdocs와 openapi3를 이용한 swagger 생성 (#15)
dojinyou Sep 27, 2023
9f7406b
[etc] sycn sql & update final id (#17)
dojinyou Sep 27, 2023
bdc2121
[etc] springmockk 의존성 추가 및 mockito-core 제외 (#19)
dojinyou Sep 29, 2023
e0f9cc9
[etc] codecov 불필요한 동작 제거 (#21)
dojinyou Sep 29, 2023
9505601
[feature] Category Domain 정의 및 CRUD 개발 (#18)
dojinyou Sep 29, 2023
e0d4ef4
[etc] codecov 설정 파일 추가 (#22)
dojinyou Sep 29, 2023
4c03247
[etc] timezone 제거 및 Instant 사용 (#20)
dojinyou Sep 29, 2023
64cd199
아키텍쳐 리팩토링
k-kbk Sep 29, 2023
179c5d8
Merge branch 'main' into notice
k-kbk Sep 29, 2023
fdab756
formatting
k-kbk Sep 29, 2023
0960413
리뷰 반영
k-kbk Sep 30, 2023
dbb6a46
string validate 메서드 변경
k-kbk Sep 30, 2023
91a0689
[etc] jacoco 설정 및 테스트 수정 (#23)
dojinyou Sep 29, 2023
fd259ba
[feature] store 도메인 정의 및 sql 추가 및 test 작성 (#24)
dojinyou Sep 30, 2023
6733e9f
[feature] storehours domain 정의 및 테스트 작성 (#25)
dojinyou Oct 1, 2023
c635573
[etc] restdocs와 openapi3를 이용한 swagger 생성 (#15)
dojinyou Sep 27, 2023
05a9ccd
[etc] sycn sql & update final id (#17)
dojinyou Sep 27, 2023
10c0f8d
[etc] springmockk 의존성 추가 및 mockito-core 제외 (#19)
dojinyou Sep 29, 2023
5736a6b
[etc] codecov 불필요한 동작 제거 (#21)
dojinyou Sep 29, 2023
93d176a
[feature] Category Domain 정의 및 CRUD 개발 (#18)
dojinyou Sep 29, 2023
be37e69
[etc] timezone 제거 및 Instant 사용 (#20)
dojinyou Sep 29, 2023
ded30da
테스트 코드 작성
k-kbk Oct 8, 2023
88866ea
충돌 해결
k-kbk Oct 8, 2023
6b862de
줄바꿈
k-kbk Oct 8, 2023
92d3852
Update src/main/kotlin/com/mjucow/eatda/domain/notice/service/command…
k-kbk Oct 12, 2023
6b5ece3
Update src/main/kotlin/com/mjucow/eatda/domain/notice/service/query/N…
k-kbk Oct 12, 2023
eb8a540
리뷰 반영
k-kbk Oct 12, 2023
d9f94df
리뷰 반영
k-kbk Oct 15, 2023
dd036d5
테스트 수정
k-kbk Oct 15, 2023
7603c51
NoticeMother 추가
k-kbk Oct 15, 2023
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,50 @@
package com.mjucow.eatda.application.notice

import com.mjucow.eatda.domain.notice.Notice
import com.mjucow.eatda.domain.notice.NoticeRepository
import com.mjucow.eatda.presentation.notice.dto.CreateNoticeRequest
import com.mjucow.eatda.presentation.notice.dto.NoticeIdResponse
import com.mjucow.eatda.presentation.notice.dto.NoticeResponse
import com.mjucow.eatda.presentation.notice.dto.UpdateNoticeRequest
import jakarta.persistence.EntityNotFoundException
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Transactional
@Service
class NoticeService(
private val noticeRepository: NoticeRepository,
) {
fun create(request: CreateNoticeRequest): NoticeIdResponse {
val notice = noticeRepository.save(Notice(request.title, request.content))
return NoticeIdResponse(notice)
}

fun findAll(): List<NoticeResponse> {
return noticeRepository.findAllByOrderByCreatedAtDesc().map { NoticeResponse(it) }
}

@Throws(EntityNotFoundException::class)
fun findById(noticeId: Long): NoticeResponse {
val notice = noticeRepository.findByIdOrNull(noticeId)
?: throw EntityNotFoundException("공지사항이 존재하지 않습니다.")
return NoticeResponse(notice)
}

@Throws(EntityNotFoundException::class)
fun update(noticeId: Long, request: UpdateNoticeRequest): NoticeIdResponse {
val notice = noticeRepository.findByIdOrNull(noticeId)
?: throw EntityNotFoundException("공지사항이 존재하지 않습니다.")
val (newTitle, newContent) = request
notice.let {
if (newTitle != null) it.title = newTitle
if (newContent != null) it.content = newContent
}
return NoticeIdResponse(notice)
}

fun deleteById(noticeId: Long) {
return noticeRepository.deleteById(noticeId)
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/com/mjucow/eatda/domain/notice/Notice.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.mjucow.eatda.domain.notice

import com.mjucow.eatda.domain.common.BaseEntity
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Table

@Entity
@Table(name = "notice")
class Notice(
@Column(nullable = false) var title: String,
@Column(nullable = false) var content: String,
) : BaseEntity()
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.mjucow.eatda.domain.notice

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

interface NoticeRepository : JpaRepository<Notice, Long> {
fun findAllByOrderByCreatedAtDesc(): List<Notice>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ package com.mjucow.eatda.presentation.common

import jakarta.persistence.EntityNotFoundException
import org.springframework.http.HttpStatus
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseStatus

@GlobalControllerAdvice
class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException::class)
fun handleMethodArgumentNotValidException(exception: MethodArgumentNotValidException): ApiResponse<Unit> {
return ApiResponse.error(exception.bindingResult.allErrors.joinToString(" ") { it.defaultMessage.toString() })
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException::class)
fun handleIllegalArgumentException(exception: IllegalArgumentException): ApiResponse<Unit> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.mjucow.eatda.presentation.notice

import com.mjucow.eatda.application.notice.NoticeService
import com.mjucow.eatda.presentation.common.ApiResponse
import com.mjucow.eatda.presentation.notice.dto.CreateNoticeRequest
import com.mjucow.eatda.presentation.notice.dto.NoticeIdResponse
import com.mjucow.eatda.presentation.notice.dto.NoticeResponse
import com.mjucow.eatda.presentation.notice.dto.UpdateNoticeRequest
import jakarta.validation.Valid
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.DeleteMapping
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.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController

@RequestMapping("/api/v1/notices")
@RestController
class NoticeController(private val noticeService: NoticeService) {

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(
@RequestBody @Valid
request: CreateNoticeRequest,
): ApiResponse<NoticeIdResponse> {
return ApiResponse.success(noticeService.create(request))
}

@GetMapping
@ResponseStatus(HttpStatus.OK)
fun findAll(): ApiResponse<List<NoticeResponse>> {
return ApiResponse.success(noticeService.findAll())
}

@GetMapping("/{noticeId}")
@ResponseStatus(HttpStatus.OK)
fun findById(
@PathVariable noticeId: Long,
): ApiResponse<NoticeResponse> {
return ApiResponse.success(noticeService.findById(noticeId))
}

@PatchMapping("/{noticeId}")
@ResponseStatus(HttpStatus.OK)
fun update(
@PathVariable noticeId: Long,
@RequestBody request: UpdateNoticeRequest,
): ApiResponse<NoticeIdResponse> {
return ApiResponse.success(noticeService.update(noticeId, request))
}

@DeleteMapping("/{noticeId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
fun deleteById(
@PathVariable noticeId: Long,
) {
return noticeService.deleteById(noticeId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mjucow.eatda.presentation.notice.dto

import jakarta.validation.constraints.NotBlank

data class CreateNoticeRequest(
@field:NotBlank(message = "공지사항 제목은 필수 입력 값입니다.")
val title: String,
@field:NotBlank(message = "공지사항 내용은 필수 입력 값입니다.")
val content: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mjucow.eatda.presentation.notice.dto

import com.mjucow.eatda.domain.notice.Notice

data class NoticeIdResponse(
val id: Long,
) {
constructor(notice: Notice) : this(
notice.id!!
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.mjucow.eatda.presentation.notice.dto

import com.mjucow.eatda.domain.notice.Notice
import java.time.LocalDateTime

data class NoticeResponse(
val id: Long,
val title: String,
val content: String,
val createdAt: LocalDateTime,
) {
constructor(notice: Notice) : this(
notice.id!!,
notice.title,
notice.content,
notice.createdAt
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mjucow.eatda.presentation.notice.dto

data class UpdateNoticeRequest(
val title: String?,
val content: String?,
)