[SpringBoot 핵심 원리] 예제 만들기 (1) (+ @Controller와 @RestController 차이)

윤경·2021년 12월 15일
0

Spring Boot

목록 보기
57/79
post-thumbnail

🔗 스프링 핵심 원리 - 고급편


[1] 프로젝트 생성

🔗 새로 프로젝트 생성하기


[2] 예제 프로젝트 만들기 - V0

: 버전0으로 가장 간단한 예제 만들기

상품 주문 프로세스로 가정하고 일반적인 웹 애플리케이션에서 Controller → Service → Repository 흐름을 최대한 단순하게 만들었다.

✔️ OrderRepositoryV0.java

@Repository // 안에 @Component가 있어 자동으로 컴포넌트 스캔 대상이 됨(스프링 빈 등록)
@RequiredArgsConstructor
public class OrderRepositoryV0 {

    public void save(String itemId) {

        // 저장 로직
        if(itemId.equals("ex")) {   // (다양한 예제를 위해)"ex"라는 것이 넘어오면 예외 발생시킬
            throw new IllegalStateException("예외 발생!");
        }
        sleep(1000);    // 상품을 저장하는데 1초 정도 걸린다고 가정
    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

@Repository: 컴포넌트 스캔의 대상이 됨. 따라서 스프링 빈으로 자동 등록됨.
sleep(1000): 리포지토리는 상품을 저장하는데 약 1초가량 소요되는 것으로 가정하기 위해 1초 지연을 부여함.

그리고 예외 발생 상황을 확인하기 위해 itemId의 값이 "ex"로 넘어온다면 IllegalStateException 예외가 발생하도록 했다.

✔️ OrderServiceV0.java

@Service    // @Service 안에 @Component가 있어 자동으로 컴포넌트 스캔의 대상이 됨(자동으로 스프링 빈 등록)
@RequiredArgsConstructor    // 생성자 자동 생성
public class OrderServiceV0 {

    private final OrderRepositoryV0 orderRepository;

    public void orderItem(String itemId) {
        orderRepository.save(itemId);
    }
}

@Service: 컴포넌트 스캔의 대상이 됨. 따라서 마찬가지로 스프링 빈으로 자동 등록됨.

실무에서는 복잡한 비즈니스 로직이 서비스 계층에 포함되지만, 예제이기 때문에 단순함을 살리기 위해 리포지토리에 저장을 호출하는 코드만 넣었다.

✔️ OrderControllerV0.java

@RestController // @Controller + @ResponseBody
@RequiredArgsConstructor
public class OrderControllerV0 {

    private final OrderServiceV0 orderService;

    @GetMapping("/v0/request")
    public String request(String itemId) {
        orderService.orderItem(itemId);

        return "ok";
    }
}

@RestController: 컴포넌트 스캔과 스프링 (📌아래 참고) RestController로 인식됨.

⬇️ 예외 발생시


📌 @Controller vs @RestController

이들은 Spring에서 컨트롤러를 지정해주기 위한 annotation들이다.

전통적인 Spring MVC의 컨트롤러@Controller,
그리고 Restful 웹 서비스의 컨트롤러@RestController

이 둘의 주요 차이점은 HTTP Response Body가 생성되는 방식이다.

- @Controller (Spring MVC Controller)

[Controller - View]

전통적인 Spring MVC의 컨트롤러인 @Controller는 주로 View를 반환하기 위해 사용한다.

출처: 망나니 개발자

이런 과정을 통해 Spring MVC Container는 Client의 요청으로부터 View를 반환한다.

  1. 클라이언트는 URI 형식으로 웹 서비스에 요청을 보냄.
  2. Mapping 되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트.
  3. Controller가 요청을 처리한 후, 응답을 DispatcherServlet으로 반환하고 DispatcherServlet은 View를 사용자에게 반환.

‼️ @Controller가 View를 반환하기 위해서는 ViewResolver가 사용되며, ViewResolver 설정에 맞게 View를 찾아 렌더링한다.

[Controller - Data]

하지만 Spring MVC의 컨트롤러에서도 데이터를 반환해야 하는 경우도 있다.

Spring MVC의 Controller에서는 데이터를 반환하기 위해 @ResponseBody 어노테이션을 사용해야 한다.
이를 통해 Controller도 Json 형태로 데이터를 반환할 수 있다.

출처: 망나니 개발자

  1. 클라이언트는 URI 형식으로 웹 서비스에 요청을 보냄.
  2. Mapping 되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트.
  3. @ResponseBody를 사용해 Client에게 Json 형태로 데이터 반환 ➡️ [Controller - View]와 차이

@RestController가 데이터를 반환하기 위해서는 viewResolver 대신 HttpMessageConverter가 동작한다.

HttpMessageConverter에는 여러 Converter가 등록되어 있고, 반환해야 하는 데이터에 따라 사용하는 Converter가 달라진다.

단순 문자열의 경우 StringHttpMessageConverter 사용, 객체의 경우 MappingJackson2HttpMessageConverter 사용
➡️ 데이터 종류에 따라 서로 다른 MessageConverter 작동

Spring은 클라이언트의 HTTP Accept 헤더와 서버의 컨트롤러 반환 타입 정보 둘을 조합해 적합한 HttpMessageConverter를 선택해 이를 처리한다.

- @RestController (Spring Restful Controller)

[RestController]

@RestController는 Spring MVC Controller에 @ResponseBody가 추가된 것이다.

당연히 RestController의 주 용도는 Json 형태로 객체 데이터를 반환하는 것이다.

(참고한 포스트의 작성자분께선 VueJs+SpringBoot 프로젝트 시 SpringBoot를 API 서버로 활용할 때, 그리고 Android 앱 개발을 하며 데이터를 반환할 때 사용하였다고 하심)

출처: 망나니 개발자

  1. 클라이언트는 URI 형식으로 웹 서비스에 요청을 보냄.
  2. Mapping 되는 Handler와 그 Type을 찾는 DispatcherServlet이 요청을 인터셉트.
  3. RestController는 해당 요청을 처리하고 데이터를 반환

1, 2 과정은 동일


참고

profile
개발 바보 이사 중

0개의 댓글