Spring Boot로 백엔드 서비스를 만들 때 가장 많이 하는 일이 REST API + JPA로 CRUD 서버 만들기입니다.
이 글에서는 프로젝트 구조 → 엔티티/DTO 설계 → 컨트롤러/서비스/리포지토리 레이어 분리 → 예외 처리까지 실무 패턴 위주로 정리합니다.
예제 코드는 Kotlin 기준이지만, Java로도 거의 동일하게 적용할 수 있습니다.
실무에서는 여기에 HTTP 상태 코드 매핑, 로그 출력, 트레이싱 ID 등을 추가해서 사용합니다.
5. 테스트: 슬라이스 테스트와 통합 테스트
5-1. Repository 테스트 (슬라이스)
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.beans.factory.annotation.Autowired
import org.assertj.core.api.Assertions.assertThat
@DataJpaTestclassUserRepositoryTest@Autowiredconstructor(
privateval userRepository: UserRepository
) {
@Testfun `이메일로 사용자 조회`() {
val saved = userRepository.save(User(name = "test", email = "test@example.com"))
val found = userRepository.findByEmail("test@example.com")
assertThat(found?.id).isEqualTo(saved.id)
}
}
5-2. 컨트롤러 통합 테스트
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.post
@SpringBootTest@AutoConfigureMockMvcclassUserControllerTest(
privateval mockMvc: MockMvc
) {
@Testfun `사용자 생성 API`() {
val body = """
{
"name": "kwkang",
"email": "test@example.com"
}
""".trimIndent()
mockMvc.post("/api/users") {
contentType = "application/json"
content = body
}.andExpect {
status { isOk() }
}
}
}
Repository 레벨은 슬라이스 테스트(@DataJpaTest),
API 레벨은 MockMvc를 이용한 통합 테스트 조합이 많이 쓰입니다.
6. 실무에서 Spring Boot + JPA 사용할 때의 체크리스트
엔티티와 DTO 분리: 엔티티를 외부 API에 그대로 노출하지 않기
트랜잭션 경계: 비즈니스 로직이 있는 서비스 레이어에 @Transactional 명시
지연 로딩 주의: where, fetch join, DTO 변환 타이밍을 고려해서 N+1 문제 방지
예외 처리 공통화: @RestControllerAdvice로 에러 응답 형식을 통일
테스트 전략: 슬라이스 테스트(+ 인메모리 DB)와 통합 테스트를 적절히 섞어서 사용
위 흐름대로 한 번 프로젝트를 직접 만들어 보면,
Spring Boot로 만드는 대부분의 “전형적인 REST 백엔드” 구조를 한 번에 익힐 수 있습니다.
이후에는 보안(Spring Security), 모니터링(Actuator), 배포 전략(프로필, 설정 분리) 등을 단계적으로 확장해 나가면 됩니다.
강경원
@theo
백엔드 엔지니어. Java/Spring으로 밥 벌고, 사이드로 Next.js와 실시간 서비스를 만듭니다. 만들면서 배운 것들을 기록해요.