diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 6c94357..1a0e6de 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,16 +1,19 @@
## PULL REQUEST
-### π μμ
μ€μΈ λΈλμΉ
+### π Issue Ticket
-
### π μ£Όμ μμ
μ¬ν
-
### π (Optional) μ°Έκ³ μλ£
-- μ€ν¬λ¦°μ·μ 첨λΆν΄μ£ΌμΈμ.
-
-### κ΄λ ¨ μ΄μ
-
+### (μ€μ) μλΈλͺ¨λμ΄ μμ λμλμ?
+- κΈ°μ‘΄ μ»€λ° :
+- λ³κ²½ μ»€λ° :
+- λ³κ²½ μ¬ν :
+- [] ν΄λΉ μλΈλͺ¨λ λ³κ²½μ¬νμ΄ PRμ μ λ°μλμλμ?
+
### κΌ νμΈν΄ μ£ΌμΈμ!!
--
+-
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index a96161b..680093b 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -1,42 +1,35 @@
-name: λΉλ ν
μ€νΈ / λ¦¬λ·°μ΄ ν λΉ
+name: ν
μ€νΈ μ½λ λ° λΉλ
on:
pull_request:
- types: [opened, synchronize, closed]
+ types: [ opened, synchronize, closed ]
branches:
- 'develop'
- 'master'
jobs:
- build_and_review_assign:
- name: "[CI] Check Build/Testcases and Assign Reviewer"
+ test:
+ name: "[CI] Check Tests"
runs-on: ubuntu-latest
steps:
- - name: (Set Up) checkout
+ - name: Checkout code
uses: actions/checkout@v3
with:
token: ${{ secrets.GIT_TOKEN }}
submodules: true
- - name: (Set Up) Set up JDK 17
+ - name: Setup Java 17
uses: actions/setup-java@v3
with:
java-version: '17'
- distribution: 'temurin'
+ distribution: 'adopt'
- - name: (Set Up) Grant Execute permission for gradlew
- run: chmod 777 gradlew
+ - name: Update Git submodules
+ run: git submodule update --remote --recursive
- - name: (Build) Build with Gradle
- id: build
- run: ./gradlew test -i
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
- - name: (Assign Reviewer)
- if: steps.build.outcome == 'success'
- uses: hkusu/review-assign-action@v1
- with:
- assignees: ${{ github.actor }}
- reviewers: HyungJu, h-beeen
- ready-comment: 'μ½λ 리뷰 μμ²ν©λλ€ π '
- merged-comment: 'μ±κ³΅μ μΌλ‘ Merge λμμ΅λλ€. Shout out to :wink:'
+ - name: Test with Gradle
+ run: ./gradlew test
diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt
new file mode 100644
index 0000000..de0538c
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt
@@ -0,0 +1,21 @@
+package com.vacgom.backend.domain.member
+
+import com.vacgom.backend.global.auditing.BaseEntity
+import jakarta.persistence.*
+
+@Entity
+@Table(name = "t_member")
+class Member(nickname: String) : BaseEntity() {
+
+ @Id
+ @Column(name = "member_id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ var id: Long? = null
+
+ @Column(name = "nickname")
+ val nickname: String
+
+ init {
+ this.nickname = nickname
+ }
+}
diff --git a/src/main/kotlin/com/vacgom/backend/global/exception/ApiExceptionHandler.kt b/src/main/kotlin/com/vacgom/backend/global/exception/ApiExceptionHandler.kt
new file mode 100644
index 0000000..36f6c8a
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/global/exception/ApiExceptionHandler.kt
@@ -0,0 +1,55 @@
+package com.vacgom.backend.global.exception
+
+import com.vacgom.backend.global.exception.error.BusinessException
+import com.vacgom.backend.global.exception.error.ErrorCode
+import com.vacgom.backend.global.exception.error.ErrorResponse
+import com.vacgom.backend.global.exception.error.GlobalError
+import com.vacgom.backend.global.logger.CommonLogger
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.web.bind.MethodArgumentNotValidException
+import org.springframework.web.bind.MissingServletRequestParameterException
+import org.springframework.web.bind.annotation.ExceptionHandler
+import org.springframework.web.bind.annotation.ResponseStatus
+import org.springframework.web.bind.annotation.RestControllerAdvice
+
+@RestControllerAdvice
+class ApiExceptionHandler {
+ companion object : CommonLogger();
+
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler(MethodArgumentNotValidException::class)
+ fun handleMethodArgumentNotValidException(ex: MethodArgumentNotValidException): ErrorResponse? {
+ return ErrorResponse(ex.fieldErrors)
+ }
+
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler(MissingServletRequestParameterException::class)
+ fun missingServletRequestParameterException(): ErrorResponse? {
+ return ErrorResponse(GlobalError.INVALID_REQUEST_PARAM)
+ }
+
+ @ExceptionHandler(BusinessException::class)
+ fun handleBusinessException(
+ exception: BusinessException
+ ): ResponseEntity {
+ logBusinessException(exception)
+ return convert(exception.errorCode)
+ }
+
+ private fun convert(
+ errorCode: ErrorCode
+ ): ResponseEntity {
+ return ResponseEntity
+ .status(errorCode.status)
+ .body(ErrorResponse(errorCode))
+ }
+
+ private fun logBusinessException(exception: BusinessException) {
+ if (exception.errorCode.status.is5xxServerError) {
+ log.error("", exception)
+ } else {
+ log.error("Error Message = {}", exception.message)
+ }
+ }
+}
diff --git a/src/main/kotlin/com/vacgom/backend/global/exception/ApiExceptionHandlingFilter.kt b/src/main/kotlin/com/vacgom/backend/global/exception/ApiExceptionHandlingFilter.kt
new file mode 100644
index 0000000..37cb8e1
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/global/exception/ApiExceptionHandlingFilter.kt
@@ -0,0 +1,45 @@
+package com.vacgom.backend.global.exception
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.vacgom.backend.global.exception.error.BusinessException
+import com.vacgom.backend.global.exception.error.ErrorResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletException
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.stereotype.Component
+import org.springframework.web.filter.OncePerRequestFilter
+import java.io.IOException
+
+
+@Component
+class ApiExceptionHandlingFilter(
+ private val om: ObjectMapper
+) : OncePerRequestFilter() {
+
+ @Throws(ServletException::class, IOException::class)
+ override fun doFilterInternal(
+ request: HttpServletRequest,
+ response: HttpServletResponse,
+ chain: FilterChain
+ ) {
+ try {
+ chain.doFilter(request, response)
+ } catch (exception: BusinessException) {
+ setErrorResponse(response, exception)
+ }
+ }
+
+ private fun setErrorResponse(
+ response: HttpServletResponse,
+ exception: BusinessException
+ ) = try {
+ response.contentType = MediaType.APPLICATION_JSON_VALUE
+ response.status = HttpStatus.UNAUTHORIZED.value()
+ om.writeValue(response.outputStream, ErrorResponse(exception.errorCode))
+ } catch (exception: IOException) {
+ throw RuntimeException(exception)
+ }
+}
diff --git a/src/main/kotlin/com/vacgom/backend/global/exception/error/BusinessException.kt b/src/main/kotlin/com/vacgom/backend/global/exception/error/BusinessException.kt
new file mode 100644
index 0000000..638ee2b
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/global/exception/error/BusinessException.kt
@@ -0,0 +1,6 @@
+package com.vacgom.backend.global.exception.error
+
+
+class BusinessException(
+ val errorCode: ErrorCode
+) : RuntimeException(errorCode.message)
diff --git a/src/main/kotlin/com/vacgom/backend/global/exception/error/ErrorCode.kt b/src/main/kotlin/com/vacgom/backend/global/exception/error/ErrorCode.kt
new file mode 100644
index 0000000..550d1dc
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/global/exception/error/ErrorCode.kt
@@ -0,0 +1,9 @@
+package com.vacgom.backend.global.exception.error
+
+import org.springframework.http.HttpStatus
+
+interface ErrorCode {
+ val message: String
+ val status: HttpStatus
+ val code: String
+}
diff --git a/src/main/kotlin/com/vacgom/backend/global/exception/error/ErrorResponse.kt b/src/main/kotlin/com/vacgom/backend/global/exception/error/ErrorResponse.kt
new file mode 100644
index 0000000..4b7b4a0
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/global/exception/error/ErrorResponse.kt
@@ -0,0 +1,41 @@
+package com.vacgom.backend.global.exception.error
+
+import org.springframework.validation.FieldError
+import java.time.LocalDateTime
+
+data class ErrorResponse(
+ val timeStamp: String = LocalDateTime.now().toString(),
+ val errorCode: String,
+ val errorMessage: String,
+ val details: Any? = null
+) {
+ constructor(
+ errorCode: ErrorCode
+ ) : this(
+ errorCode = errorCode.code,
+ errorMessage = errorCode.message
+ )
+
+ constructor(
+ errorCode: ErrorCode,
+ details: Any?
+ ) : this(
+ errorCode = errorCode.code,
+ errorMessage = errorCode.message,
+ details = details
+ )
+
+ constructor(
+ fieldError: FieldError?
+ ) : this(
+ errorCode = fieldError?.code ?: "",
+ errorMessage = fieldError?.defaultMessage ?: ""
+ )
+
+ constructor(fieldErrors: List) : this(
+ GlobalError.INVALID_REQUEST_PARAM,
+ fieldErrors.associate {
+ it.field to (it.defaultMessage ?: "null")
+ }
+ )
+}
diff --git a/src/main/kotlin/com/vacgom/backend/global/exception/error/GlobalError.kt b/src/main/kotlin/com/vacgom/backend/global/exception/error/GlobalError.kt
new file mode 100644
index 0000000..432f9c5
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/global/exception/error/GlobalError.kt
@@ -0,0 +1,12 @@
+package com.vacgom.backend.global.exception.error
+
+import org.springframework.http.HttpStatus
+
+enum class GlobalError(
+ override val message: String,
+ override val status: HttpStatus,
+ override val code: String
+) : ErrorCode {
+ GLOBAL_NOT_FOUND("리μμ€κ° μ‘΄μ¬νμ§ μμ΅λλ€.", HttpStatus.NOT_FOUND, "G_001"),
+ INVALID_REQUEST_PARAM("μμ² νλΌλ―Έν°κ° μ ν¨νμ§ μμ΅λλ€.", HttpStatus.BAD_REQUEST, "G_002");
+}
diff --git a/src/main/kotlin/com/vacgom/backend/global/logger/CommonLogger.kt b/src/main/kotlin/com/vacgom/backend/global/logger/CommonLogger.kt
new file mode 100644
index 0000000..0d8e1c9
--- /dev/null
+++ b/src/main/kotlin/com/vacgom/backend/global/logger/CommonLogger.kt
@@ -0,0 +1,7 @@
+package com.vacgom.backend.global.logger
+
+import org.slf4j.LoggerFactory
+
+abstract class CommonLogger {
+ val log = LoggerFactory.getLogger(this.javaClass)!!
+}
diff --git a/src/main/kotlin/com/vacgom/backend/member/domain/Member.kt b/src/main/kotlin/com/vacgom/backend/member/domain/Member.kt
deleted file mode 100644
index f0f339e..0000000
--- a/src/main/kotlin/com/vacgom/backend/member/domain/Member.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.vacgom.backend.member.domain
-
-import com.vacgom.backend.global.auditing.BaseEntity
-import jakarta.persistence.*
-
-@Entity
-@Table(name = "t_user")
-class User(
- val nickname: String
-) : BaseEntity() {
-
- @Id
- @Column(name = "user_id")
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- var id: Long? = null
-}