Kotlin 비즈니스 로직 구현하기 - Service Layer

박미소·2023년 12월 27일
0

코틀린

목록 보기
16/44

비즈니스 로직 구현 단계.


interface로 구현해 어떤 argument를 받고 어떤 response를 보낸다.
실질적으로 뒤에서 구현. 근데 사실 하나의 인터페이스에서 여러 서비스 구현체가 나올일 이 없어 클래스로 바로
구현체를 작성한다.


CourseController 가 CourseService를 호출한다. 컨트롤러에서 CRUD를 작성했으니 서비스 단계에서도 CRUD를 이용해 비즈니스 로직을 실행한다. -> 그리고 다시 Response DTO를 return 하면 된다.


컨트롤러 메서드에 썼던 @Path Variable 인자를 서비스 메서드들에도 똑같이 써줘야 한다.

package com.teamsparta.courseregistration.domain.course.service

import com.teamsparta.courseregistration.domain.course.dto.CourseResponse
import com.teamsparta.courseregistration.domain.course.dto.CreateCourseRequest
import com.teamsparta.courseregistration.domain.course.dto.UpdateCourseRequest

interface CourseService {

    fun getAllCourseList(): List<CourseResponse>

    fun getOneCourseById(courseId: Long): CourseResponse

    fun createCourse(request: CreateCourseRequest): CourseResponse

    fun updateCourse(courseId: Long, request: UpdateCourseRequest): CourseResponse

    fun deleteCourse(courseId: Long)

}
package com.teamsparta.courseregistration.domain.course.service

import com.teamsparta.courseregistration.domain.course.dto.CourseResponse
import com.teamsparta.courseregistration.domain.course.dto.CreateCourseRequest
import com.teamsparta.courseregistration.domain.course.dto.UpdateCourseRequest
import org.springframework.stereotype.Service

@Service     // 직관적으로 Service 단계인것을 명시
class CourseServiceImpl: CourseService {
    override fun getAllCourseList(): List<CourseResponse> {
        // TODO: DB에서 모든 Course 목록(Entity)을 CourseResponse 목록으로 변환 후 반환
        TODO("Not yet implemented")
    }

    override fun getOneCourseById(courseId: Long): CourseResponse {
        // TODO: DB에서 ID기반으로 Course(Entity) 가져와서 CourseResponse 변환 후 반환
        TODO("Not yet implemented")
    }

    override fun createCourse(request: CreateCourseRequest): CourseResponse {
        // TODO: request를 Course(Entity)로 변환 후 DB에 저장
        TODO("Not yet implemented")
    }

    override fun updateCourse(courseId: Long, request: UpdateCourseRequest): CourseResponse {
        // TODO: DB에서 courseId에 해당하는 Course(Entity)를 가져와서 request 기반으로 업데이트 후 DB에 저장, 결과를 CourseResponse(데이터 클래스 프로퍼티 형식)로 변환 후 반환
        TODO("Not yet implemented")
    }

    override fun deleteCourse(courseId: Long) {
        // TODO: DB에서 courseId에 해당하는 Course(Entity)를 삭제, 연관된 CourseApplication, Lecture 모두 삭제
        TODO("Not yet implemented")
    }
}

이제 Controller와 연결하기 !!






CourseController에서 CourseService를 주입 받아야 한다.


생성자 주입 사용

@RequestMapping("/courses")
@RestController
class CourseController(
    private val courseService: CourseService       // 인터페이스만 주입해도 Spring에서 알아서 CourseService를 상속받는 @Service 어노테이션이 붙은 Bean들을 찾아주기 때문에 이런식으로 사용 가능.
) {

    @GetMapping()
    fun getCourseList(): ResponseEntity<List<CourseResponse>> {     // CourseResponse 하나하나를 리스트에 담아 Array 형태로 get.
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.getAllCourseList())                 // body로 DB에서 모든 Course 목록을 CourseResponse 목록으로 변환한 것이 담긴다.
                                                                    // body에 DTO가 담시는 것.
    }

    // 단일 코스 하나만 가져오기
    @GetMapping("/{courseId}")  // 여기에 표기한 PathVariable과 메서드 인자로 받는 PathVariable 네이밍 일치 시킴.
    fun getCourse(@PathVariable cousreId: Long): ResponseEntity<CourseResponse> {       // CourseResponse에서 하나만 id값에 기반해 하나만 get.
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.getOneCourseById(cousreId))
    }

    @PostMapping
    fun createCourse(@RequestBody createCourseRequest: CreateCourseRequest): ResponseEntity<CourseResponse> {
        // JSON이 CreateCourseRequest 데이터 클래스의 DTO로 매핑된다.
        // 생성을 하면 생선된 Response를 줘야함. ResponseEntity는 Spring 프레임워크에서 상세한 Response 객체를 구성하기 위해 제공하는 기능. 이걸 쓰는 이유는 DTO 뿐만이 아니라 statusCode도 같이 줘야하기 때문에.
        // 이 꺽쇠 안에는 CourseResponse란 DTO를 넣어 주면 됨.

        return ResponseEntity
            .status(HttpStatus.CREATED)                               //CREATED 201 반환
            .body(courseService.createCourse(createCourseRequest))
    }


    @PutMapping("/{courseId}")
    fun updateCourse(
        @PathVariable courseId: Long,
        @RequestBody updateCourseRequest: UpdateCourseRequest
    ): ResponseEntity<CourseResponse> {
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.updateCourse(courseId, updateCourseRequest))
    }


    @DeleteMapping("/{courseId}")
    fun deleteCourse(@PathVariable courseId: Long): ResponseEntity<Unit> {
        return ResponseEntity
            .status(HttpStatus.NO_CONTENT)
//            .body(courseService.deleteCourse(courseId))           // 이렇게 쓰면 오류남
            .build()                         // body를 굳이 표현하지 않을 때 빌드를 씀
    }
}


예외처리 하기


Transactional : 모델이 생성되거나(Create), 수정되거나(Update), 삭제 될 때(Delete) 오류가 난다면 롤백하기

Transactional 단위 지정하기

package com.teamsparta.courseregistration.domain.course.service

import com.teamsparta.courseregistration.domain.course.dto.CourseResponse
import com.teamsparta.courseregistration.domain.course.dto.CreateCourseRequest
import com.teamsparta.courseregistration.domain.course.dto.UpdateCourseRequest
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service     // 직관적으로 Service 단계인것을 명시
class CourseServiceImpl: CourseService {
    override fun getAllCourseList(): List<CourseResponse> {
        // TODO: DB에서 모든 Course 목록(Entity)을 CourseResponse 목록으로 변환 후 반환
        TODO("Not yet implemented")
    }

    override fun getOneCourseById(courseId: Long): CourseResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 만든 오류 던지기 throw ModelNotFoundException
        // TODO: DB에서 ID기반으로 Course(Entity) 가져와서 CourseResponse 변환 후 반환
        TODO("Not yet implemented")
    }


    @Transactional
    override fun createCourse(request: CreateCourseRequest): CourseResponse {
        // TODO:
        // TODO: request를 Course(Entity)로 변환 후 DB에 저장
        TODO("Not yet implemented")
    }


    @Transactional
    override fun updateCourse(courseId: Long, request: UpdateCourseRequest): CourseResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 만든 오류 던지기 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course(Entity)를 가져와서 request 기반으로 업데이트 후 DB에 저장, 결과를 CourseResponse(데이터 클래스 프로퍼티 형식)로 변환 후 반환
        TODO("Not yet implemented")
    }


    @Transactional
    override fun deleteCourse(courseId: Long) {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 만든 오류 던지기 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course(Entity)를 삭제, 연관된 CourseApplication, Lecture 모두 삭제
        TODO("Not yet implemented")
    }
}

트랜잭셔널 사용하려면 DB랑 연결해야 한다. 그래서 테스트 DB에 연결.







모델들마다 중복되는 예외처리를 생성하는 어노테이션 - 예외 핸들링하기


하지만 각 Controller마다 Exception에 대한 핸들링을 하다보니, 중복코드가 많이 생길 수 있다는 단점이 있다.

이를 위해, Spring에서는 Exception을 전역적으로 처리할 수 있도록 @ControllerAdvice, @RestControllerAdvice 어노테이션을 제공.

앞에서 했던것처럼, view가 아닌 data만을 다루기에 @RestControllerAdvice을 이용!

해당 Annotation을 Class에 지정한 후, @ExceptionHandler를 통해 전역적으로 Exception을 핸들링 할 수 있다.

package com.teamsparta.courseregistration.domain.exception.dto

data class ErrorResponse(
    val message: String?,
)




package com.teamsparta.courseregistration.domain.exception

// 다른 모델들 모두에게 예외를 던져주기 위해서 domain 파일 하위에 새로운 exception 패키지 생성
// 예외를 단순히 던지기만 할 것이기 때문에 데이터 클래스 생성
// 이 예외를 보고서 어떤 모델의 어떤 ID에서 NotFoundException이 발생했는지 알 수 있다.
// Exception의 종류 중 하나로 메시지(String)와 throw된 원인(cause)을 리턴해준다.

data class ModelNotFoundException(val modelName: String, val id: Long): RuntimeException(
    "Model $modelName not found with given id: $id"
)




package com.teamsparta.courseregistration.domain.exception

import com.teamsparta.courseregistration.domain.exception.dto.ErrorResponse
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice



//이렇게 exception 패키지 내 클래스 생성. 전략적으로 한 곳에서 Exception을 처리할 수 있다.

@RestControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(ModelNotFoundException::class)       // 만든 data class ModelNotFoundException
    fun handleModelNotFoundException(e: ModelNotFoundException): ResponseEntity<ErrorResponse> {         // status 코드만 리턴 받을 것임
        return ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body(ErrorResponse(message = e.message))
    }

}






다른 모델 컨트롤러와 서비스 연결하기


하나의 Aggregate로 묶어 CourseService 안에서 Lecture, CourseApplication에 관련된 command들을 구현

단점: CourseService가 너무 커진다.

package com.teamsparta.courseregistration.domain.course.service

import com.teamsparta.courseregistration.domain.course.dto.CourseResponse
import com.teamsparta.courseregistration.domain.course.dto.CreateCourseRequest
import com.teamsparta.courseregistration.domain.course.dto.UpdateCourseRequest
import com.teamsparta.courseregistration.domain.courseapplication.dto.ApplyCourseRequest
import com.teamsparta.courseregistration.domain.courseapplication.dto.CourseApplicationResponse
import com.teamsparta.courseregistration.domain.courseapplication.dto.UpdateApplicationStatusRequest
import com.teamsparta.courseregistration.domain.lecture.dto.AddLectureRequest
import com.teamsparta.courseregistration.domain.lecture.dto.LectureResponse
import com.teamsparta.courseregistration.domain.lecture.dto.UpdateLectureRequest


interface CourseService {

    fun getAllCourseList(): List<CourseResponse>

    fun getOneCourseById(courseId: Long): CourseResponse

    fun createCourse(request: CreateCourseRequest): CourseResponse

    fun updateCourse(courseId: Long, request: UpdateCourseRequest): CourseResponse

    fun deleteCourse(courseId: Long)

    fun getAllLectureList(courseId: Long): List<LectureResponse>

    fun getOneLecture(courseId: Long, lectureId: Long): LectureResponse

    fun addLecture(courseId: Long, request: AddLectureRequest): LectureResponse

    fun updateLecture(courseId: Long, lectureId: Long, request: UpdateLectureRequest): LectureResponse

    fun removeLecture(courseId: Long, lectureId: Long)

    fun getCourseApplicationList(courseId: Long): List<CourseApplicationResponse>

    fun getOneCourseApplication(courseId: Long, applicationId: Long): CourseApplicationResponse

    fun applyCourse(courseId: Long, request: ApplyCourseRequest): CourseApplicationResponse

    fun updateApplicationStatus(
        courseId: Long,
        applicationId: Long,
        request: UpdateApplicationStatusRequest
    ): CourseApplicationResponse
}
package com.teamsparta.courseregistration.domain.course.service

import com.teamsparta.courseregistration.domain.course.dto.CourseResponse
import com.teamsparta.courseregistration.domain.course.dto.CreateCourseRequest
import com.teamsparta.courseregistration.domain.course.dto.UpdateCourseRequest
import com.teamsparta.courseregistration.domain.courseapplication.dto.ApplyCourseRequest
import com.teamsparta.courseregistration.domain.courseapplication.dto.CourseApplicationResponse
import com.teamsparta.courseregistration.domain.courseapplication.dto.UpdateApplicationStatusRequest
import com.teamsparta.courseregistration.domain.exception.ModelNotFoundException
import com.teamsparta.courseregistration.domain.lecture.dto.AddLectureRequest
import com.teamsparta.courseregistration.domain.lecture.dto.LectureResponse
import com.teamsparta.courseregistration.domain.lecture.dto.UpdateLectureRequest
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional


@Service     // 직관적으로 Service 단계인것을 명시
class CourseServiceImpl: CourseService {
    override fun getAllCourseList(): List<CourseResponse> {
        // TODO: DB에서 모든 Course 목록(Entity)을 CourseResponse 목록으로 변환 후 반환
        TODO("Not yet implemented")
    }


    override fun getOneCourseById(courseId: Long): CourseResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 만든 오류 던지기 throw ModelNotFoundException
        // TODO: DB에서 ID기반으로 Course(Entity)를 가져와서 CourseResponse 변환 후 반환
//        TODO("Not yet implemented")
        throw ModelNotFoundException(modelName = "Course", id = 3L)
    }


    @Transactional
    override fun createCourse(request: CreateCourseRequest): CourseResponse {
        // TODO:
        // TODO: request를 Course(Entity)로 변환 후 DB에 저장
        TODO("Not yet implemented")
    }


    @Transactional
    override fun updateCourse(courseId: Long, request: UpdateCourseRequest): CourseResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 만든 오류 던지기 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course(Entity)를 가져와서 request 기반으로 업데이트 후 DB에 저장, 결과를 CourseResponse(데이터 클래스 프로퍼티 형식)로 변환 후 반환
//        TODO("Not yet implemented")
        throw ModelNotFoundException(modelName = "Course", id = 3L)
    }


    @Transactional
    override fun deleteCourse(courseId: Long) {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 만든 오류 던지기 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course(Entity)를 삭제, 연관된 CourseApplication, Lecture 모두 삭제
//        TODO("Not yet implemented")
        throw ModelNotFoundException(modelName = "Course", id = 3L)
    }


    override fun getAllLectureList(courseId: Long): List<LectureResponse> {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course목록을 가져오고, 하위 lecture들을 가져온 다음, LectureResopnse로 변환해서 반환
        TODO("Not yet implemented")
    }


    override fun getOneLecture(courseId: Long, lectureId: Long): LectureResponse {
        // TODO: 만약 courseId, lectureId에 해당하는 Lecture가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId, lectureId에 해당하는 Lecture를 가져와서 LectureResponse로 변환 후 반환
        TODO("Not yet implemented")
    }


    @Transactional
    override fun addLecture(courseId: Long, request: AddLectureRequest): LectureResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course를 가져와서 Lecture를 추가 후 DB에 저장, 결과를을 LectureResponse로 변환 후 반환
        TODO("Not yet implemented")
    }


    @Transactional
    override fun updateLecture(courseId: Long, lectureId: Long, request: UpdateLectureRequest): LectureResponse {
        // TODO: 만약 courseId, lectureId에 해당하는 Lecture가 없다면 throw ModelNotFoundException
        /* TODO: DB에서 courseId, lectureId에 해당하는 Lecture를 가져와서
            request로 업데이트 후 DB에 저장, 결과를을 LectureResponse로 변환 후 반환 */
        TODO("Not yet implemented")
    }


    @Transactional
    override fun removeLecture(courseId: Long, lectureId: Long) {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId, lectureId에 해당하는 Lecture를 가져오고, 삭제
        TODO("Not yet implemented")
    }


    override fun getCourseApplicationList(courseId: Long): List<CourseApplicationResponse> {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId에 해당하는 Course를 가져오고, 하위 courseApplication들을 CourseApplicationResponse로 변환 후 반환
        TODO("Not yet implemented")
    }


    override fun getOneCourseApplication(courseId: Long, applicationId: Long): CourseApplicationResponse {
        // TODO: 만약 courseId, applicationId에 해당하는 CourseApplication이 없다면 throw ModelNotFoundException
        // TODO: DB에서 courseId, applicationId에 해당하는 CourseApplication을 가져와서 CourseApplicationResponse로 변환 후 반환
        TODO("Not yet implemented")
    }


    // 정책 부분
    @Transactional
    override fun applyCourse(courseId: Long, request: ApplyCourseRequest): CourseApplicationResponse {
        // TODO: 만약 courseId에 해당하는 Course가 없다면 throw ModelNotFoundException
        // TODO: 만약 course가 이미 마감됐다면, throw IllegalStateException        // 마감됐다는 것이 state 가 illegal 하다는 것과 동일.
        // TODO: 이미 신청했다면, throw IllegalStateException
        TODO("Not yet implemented")

    }


    // 정책 부분
    @Transactional
    override fun updateApplicationStatus(
        courseId: Long,
        applicationId: Long,
        request: UpdateApplicationStatusRequest
    ): CourseApplicationResponse {
        // TODO: 만약 courseId, applicationId에 해당하는 CourseApplication이 없다면 throw ModelNotFoundException
        // TODO: 만약 status가 이미 변경된 상태면 throw IllegalStateException
        // TODO: Course의 status가 CLOSED상태 일시 throw IllegalStateException
        // TODO: 승인을 하는 케이스일 경우, course의 numApplicants와 maxApplicants가 동일하면, course의 상태를 CLOSED로 변경
        // TODO: DB에서 courseApplication을 가져오고, status를 request로 업데이트 후 DB에 저장, 결과를 CourseApplicationResponse로 변환 후 반환
        TODO("Not yet implemented")
    }
}
package com.teamsparta.courseregistration.domain.courseapplication.controller


import com.teamsparta.courseregistration.domain.course.service.CourseService
import com.teamsparta.courseregistration.domain.courseapplication.dto.ApplyCourseRequest
import com.teamsparta.courseregistration.domain.courseapplication.dto.CourseApplicationResponse
import com.teamsparta.courseregistration.domain.courseapplication.dto.UpdateApplicationStatusRequest
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*


@RequestMapping("/course/{courseId}/applications")
@RestController
class CourseApplicationController(
    private val courseService: CourseService
) {


    @GetMapping
    fun getApplicationList(@PathVariable courseId: Long): ResponseEntity<List<CourseApplicationResponse>> {
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.getCourseApplicationList(courseId))
    }


    @GetMapping("/{applicationId}")
    fun getApplication(
        @PathVariable courseId: Long,
        @PathVariable applicationId: Long,
    ): ResponseEntity<CourseApplicationResponse> {
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.getOneCourseApplication(courseId, applicationId))
    }


    @PostMapping
    fun applyCourse(
        @PathVariable courseId: Long,
        @RequestBody applyCourseRequest: ApplyCourseRequest
    ): ResponseEntity<CourseApplicationResponse> {
        return ResponseEntity
            .status(HttpStatus.CREATED)
            .body(courseService.applyCourse(courseId, applyCourseRequest))
    }

    @PatchMapping("/{applicationId}")
    fun updateApplicationStatus(
        @PathVariable courseId: Long,
        @PathVariable applicationId: Long,
        @RequestBody updateApplicationStatusRequest: UpdateApplicationStatusRequest
    ): ResponseEntity<CourseApplicationResponse> {
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.updateApplicationStatus(courseId, applicationId, updateApplicationStatusRequest))
    }
}
package com.teamsparta.courseregistration.domain.lecture.controller

import com.teamsparta.courseregistration.domain.course.service.CourseService
import com.teamsparta.courseregistration.domain.lecture.dto.AddLectureRequest
import com.teamsparta.courseregistration.domain.lecture.dto.LectureResponse
import com.teamsparta.courseregistration.domain.lecture.dto.UpdateLectureRequest
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
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



// 컨트롤러에 서비스 연결
@RequestMapping("/courese/{courseId}/lectures")        // 여기서 @PathVariable로 courseId를 썼기 때문에 모든 함수 내  @PathVariable 자리에 courseId 지정해야 함.
@RestController                                          // @RequestMapping이 있다 보니까
class LectureController(
    private val courseService: CourseService
) {

    @GetMapping
    fun getLectureList(@PathVariable courseId: Long): ResponseEntity<List<LectureResponse>> {
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.getAllLectureList(courseId))
    }


    @GetMapping("/{lectureId}")
    fun getLecture(@PathVariable courseId: Long, @PathVariable lectureId: Long): ResponseEntity<LectureResponse> {
        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.getOneLecture(courseId, lectureId))
    }


    @PostMapping
    fun addLecture(
        @PathVariable courseId: Long,
        @RequestBody addLectureRequest: AddLectureRequest
    ): ResponseEntity<LectureResponse> {            // 완성을 했으면 lecture가 어떤 데이터로 생성이 됐는지 Resonse를 보내야 하니까 ResponseEntity에 AddLectureRequest를 지정해서 리턴 시키는 것.

        return ResponseEntity
            .status(HttpStatus.CREATED)
            .body(courseService.addLecture(courseId, addLectureRequest))
    }

    @PutMapping("/{lectureId}")    //  이미 생성된 강좌이니 수정할 때 강좌 아이디가 필요함
    fun updateLecture(
        @PathVariable courseId: Long,
        @PathVariable lectureId: Long,
        @RequestBody updateLectureRequest: UpdateLectureRequest
    ): ResponseEntity<LectureResponse> {

        return ResponseEntity
            .status(HttpStatus.OK)
            .body(courseService.updateLecture(courseId, lectureId, updateLectureRequest))
    }


    @DeleteMapping("/{lectureId}")
    fun removeLecture(
        @PathVariable courseId: Long,
        @PathVariable lectureId: Long,
    ): ResponseEntity<Unit> {            // 아무것도 리턴하지 않는다는 뜻

        return ResponseEntity
            .status(HttpStatus.NO_CONTENT)
            .build()
    }

}




Controller와 Service가 모두 연결됐다.

@Transactional : 예외가 있으면 삭제가 안되고 롤백이 되게한다.







0개의 댓글