
@SpringBootApplication
public class MyServerApplication {
public static void main(String[] args) {
SpringApplication.run(MyServerApplication.class, args);
}
}
스프링부트 강의 2일차에 위 코드로 스프링부트 어플리케이션을 시작하는 법을 배웠습니다. 위 코드가 어떤 동작을 수행하는지 알아보도록 하겠습니다.
위 어노테이션을 아래 세 가지 어노테이션을 결합한 것입니다.
내장 Tomcat 서버 설정 및 실행, 의존성이 추가된 것들에 대한 기본 설정 등등 개발자가 비즈니스 로직에 집중할 수 있도록 설정을 도와주는 어노테이션으로 이해하고, 아직 이해가 안 가는 내용이 많으니 우선 암기하듯이 기억하고 넘어가도록 하겠습니다.
다음 코드들로 Spring Boot의 레이어드 아키텍처의 전형적인 예시를 살펴보도록 하겠습니다.
@Slf4j
@CrossOrigin
@AllArgsConstructor
@RestController
@RequestMapping("/")
public class MyController {
private final MyService service;
@PostMapping
public ResponseEntity<MyResponse> create(@RequestBody MyRequest request) {
log.info("CREATE");
if (ObjectUtils.isEmpty(request.getTitle()))
return ResponseEntity.badRequest().build();
MyModel result = this.service.add(request);
return ResponseEntity.ok(new MyResponse(result));
}
@GetMapping("{id}")
public ResponseEntity<MyResponse> readOne(@PathVariable Long id) {
log.info("READ ONE");
MyModel result = this.service.searchById(id);
return ResponseEntity.ok(new MyResponse(result));
}
@DeleteMapping
public ResponseEntity<?> deleteAll() {
log.info("DELETE ALL");
this.service.deleteAll();
return ResponseEntity.ok().build();
}
}
Cotroller 레이어의 역할은 HTTP 요청을 받아서 처리하고, 그에 대한 응답을 반환하는 것입니다.
@RestController 어노테이션에 의해 HTTP 요청을 받아 처리하게 됩니다. @RestController은 @Controller, @ResponseBody의 조합입니다.
Spring 애플리케이션에 들어오는 HTTP 요청을 DispatcherServlet 이라는 서블릿이 먼저 받고, 이 서블릿이 적절한 컨트롤러에게 요청을 전달합니다. 적절한 컨트롤러를 찾는 것은 Handler Mapping에 의해 이루어지는데, @RequestMapping 어노테이션을 통해 어느 컨트롤러의 어느 메서드가 특정 요청을 처리할지 결정합니다.
위 예시 코드에서는 / 경로로 들어오는 요청을 MyController가 받고, 내부적으로 @PostMapping, @GetMapping("{id}"), @DeleteMapping 어노테이션을 통해 메소드가 매핑되어 있습니다.
@Service
@AllArgsConstructor
public class TodoService {
private final MyRepository myRepository;
public MyModel add(MyRequest request) {
MyModel myModel = new MyModel();
myModel.setTitle(request.getTitle());
myModel.setOrder(request.getOrder());
myModel.setCompleted(request.getCompleted());
return this.myRepository.save(myModel);
}
public MyModel searchById(Long id) {
return this.myRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
public void deleteAll() {
this.myRepository.deleteAll();
}
}
Service 레이어의 역할은 비즈니스 로직을 처리하고, 데이터의 생성, 조회, 수정, 삭제 등의 작업을 수행하는 것입니다.
@Service 어노테이션을 통해 이 클래스가 서비스 계층임을 나타내고, Spring이 관리하는 빈으로 등록하게 됩니다.
주요 개념
@Repository
public interface MyRepository extends JpaRepository<MyModel, Long> {
}
데이터베이스와의 상호작용을 담당하는 레이어입니다. JPA를 통해 DB와 상호작용합니다.
우선 MyRepository 클래스는 @Repository 어노테이션을 통해 DB와의 상호작용을 위한 빈으로 등록됩니다.
JpaRepository<MyModel, Long>을 상속 받는다는 것은, Spring Data JPA가 제공하는 레포지토리 인터페이스가 됨을 의미합니다.
JpaRepository를 ctrl+클릭하면 아래 세 가지를 상속받고 있음을 확인할 수 있었습니다.
이를 통해 기본적인 CRUD 메서드가 제공되고, 페이징과 정렬 기능이 제공되며, 배치 작업, 플러시 관리 등을 추가로 지원받게 됩니다.
<MyModel, Long> 부분은
MyModel: 엔터티 클래스를 의미하며, JpaRepository가 처리하는 테이터 타입이 이 엔터티 클래스가 됩니다.
Long: 엔티티의 기본 키의 타입
위 서비스 코드를 다시 살펴보겠습니다.
private final MyRepository myRepository;
public MyModel add(MyRequest request) {
MyModel myModel = new MyModel();
myModel.setTitle(request.getTitle());
myModel.setOrder(request.getOrder());
myModel.setCompleted(request.getCompleted());
return this.myRepository.save(myModel);
}
myRepository.save 함수가 호출될 수 있었던 이유가 JpaRepository를 상속받았기 때문이며 myModel의 타입이 MyModel 임을 확인할 수 있습니다.