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 13 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
13 changes: 13 additions & 0 deletions src/main/kotlin/com/mjucow/eatda/domain/notice/entity/Notice.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.mjucow.eatda.domain.notice.entity

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()
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.mjucow.eatda.domain.notice.service.command

import com.mjucow.eatda.domain.notice.entity.Notice
import com.mjucow.eatda.domain.notice.service.command.dto.CreateNoticeCommand
import com.mjucow.eatda.domain.notice.service.command.dto.UpdateNoticeCommand
import com.mjucow.eatda.persistence.notice.NoticeRepository
import jakarta.persistence.EntityNotFoundException
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Transactional
@Service
class NoticeCommandService(
private val repository: NoticeRepository,
) {
fun create(request: CreateNoticeCommand): Long {
return repository.save(Notice(request.title, request.content)).id
}

@Throws(EntityNotFoundException::class)
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
fun update(noticeId: Long, request: UpdateNoticeCommand) {
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
val notice = repository.findByIdOrNull(noticeId)
?: throw EntityNotFoundException("공지사항이 존재하지 않습니다.")
val (newTitle, newContent) = request
notice.let {
if (newTitle != null) it.title = newTitle
if (newContent != null) it.content = newContent
}

repository.save(notice)
}

fun deleteById(noticeId: Long) {
val notice = repository.findByIdOrNull(noticeId) ?: throw IllegalArgumentException()
k-kbk marked this conversation as resolved.
Show resolved Hide resolved

repository.delete(notice)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mjucow.eatda.domain.notice.service.command.dto

import jakarta.validation.constraints.NotBlank

data class CreateNoticeCommand(
@field:NotBlank(message = "공지사항 제목은 필수 입력 값입니다.")
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
val title: String,
@field:NotBlank(message = "공지사항 내용은 필수 입력 값입니다.")
val content: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mjucow.eatda.domain.notice.service.command.dto

data class UpdateNoticeCommand(
val title: String?,
val content: String?,
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.mjucow.eatda.domain.notice.service.query

import com.mjucow.eatda.domain.notice.service.query.dto.NoticeDto
import com.mjucow.eatda.domain.notice.service.query.dto.Notices
import com.mjucow.eatda.persistence.notice.NoticeRepository
import jakarta.persistence.EntityNotFoundException
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Transactional
@Service
class NoticeQueryService(
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
private val repository: NoticeRepository,
) {
fun findAll(): Notices {
return Notices(repository.findAllByOrderByCreatedAtDesc().map(NoticeDto::from))
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
}

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

return NoticeDto.from(notice)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.mjucow.eatda.domain.notice.service.query.dto

import com.mjucow.eatda.domain.notice.entity.Notice
import java.time.Instant

data class NoticeDto(
val id: Long,
val title: String,
val content: String,
val createdAt: Instant,
) {
companion object {
fun from(domain: Notice): NoticeDto {
return NoticeDto(
domain.id,
domain.title,
domain.content,
domain.createdAt
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.mjucow.eatda.domain.notice.service.query.dto

data class Notices(
val noticeList: List<NoticeDto>,
) : ArrayList<NoticeDto>(noticeList)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mjucow.eatda.persistence.notice

import com.mjucow.eatda.domain.notice.entity.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,67 @@
package com.mjucow.eatda.presentation.notice.controller

import com.mjucow.eatda.domain.notice.service.command.NoticeCommandService
import com.mjucow.eatda.domain.notice.service.command.dto.CreateNoticeCommand
import com.mjucow.eatda.domain.notice.service.command.dto.UpdateNoticeCommand
import com.mjucow.eatda.domain.notice.service.query.NoticeQueryService
import com.mjucow.eatda.domain.notice.service.query.dto.NoticeDto
import com.mjucow.eatda.domain.notice.service.query.dto.Notices
import com.mjucow.eatda.presentation.common.ApiResponse
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 noticeQueryService: NoticeQueryService,
private val noticeCommandService: NoticeCommandService,
) {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(
@RequestBody @Valid
command: CreateNoticeCommand,
): ApiResponse<Long> {
return ApiResponse.success(noticeCommandService.create(command))
}

@GetMapping
@ResponseStatus(HttpStatus.OK)
fun findAll(): ApiResponse<Notices> {
return ApiResponse.success(noticeQueryService.findAll())
}

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

@PatchMapping("/{noticeId}")
@ResponseStatus(HttpStatus.OK)
fun update(
@PathVariable("noticeId") noticeId: Long,
@RequestBody command: UpdateNoticeCommand,
) {
noticeCommandService.update(noticeId, command)
}

@DeleteMapping("/{noticeId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
fun deleteById(
@PathVariable("noticeId") noticeId: Long,
) {
noticeCommandService.deleteById(noticeId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class CategoryController(
@ResponseStatus(HttpStatus.CREATED)
fun create(@RequestBody command: CreateCommand): ApiResponse<Long> {
val id = categoryCommandService.create(command)

return ApiResponse.success(id)
}

Expand All @@ -57,4 +58,4 @@ class CategoryController(
) {
categoryCommandService.updateName(id, command)
}
}
}
k-kbk marked this conversation as resolved.
Show resolved Hide resolved
Loading