티스토리 뷰
1. Spring Framework와 Spring Boot의 차이점
1) Spring Framework
- 자바 개발을 편리하게 해주는 오픈소스 프레임워크
- 경량 컨테이너로서 자바 객체를 직접 관리
- 제어의 역전이라는 기술을 통해 어플리케이션 간의 느슨한 결합을 도모할 수 있다. => 컨트롤의 제어권이 사용자가 아닌 프레임워크에 있어서 필요에 따라 스프링에서 사용자의 코드를 호출할 수 있다.
- 의존성 주입이라는 기술을 통해 각각의 계층이나 서비스들 간의 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.
- AOP는 트랜잭션, 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리할 수 있다.
- 자바 기반 어플리케이션을 만드는 데 사용
- 의존성 주입
- 느슨하게 결합된 어플리케이션을 만드는데 도움이 된다.
- 서버를 명시적으로 설정해야 한다.
- 수동으로 구성 빌드
2) Spring Boot
- 스프링 프레임워크를 사용하기 위한 설정의 많은 부분을 자동화하여 편하게 스프링 사용 가능
- 주로 REST API 개발을 위해 사용
- AutoConfiguration
- 독립 실행형 어플리케이션을 만드는데 도움이 된다.
- Tomcat이나 Jetty와 같은 임베디드 서버를 제공
- 초기 설정 기본 구성 가능
2. MVC
1) 소개
- 정의: 소프트웨어 공학게에서 사용하는 디자인 패턴 중 하나로 Model, View, Controller의 앞 글자를 따라서 MVC 디자인 패턴이라고 합니다.
- 흐름: 1) 웹 브라우저로부터 사용자의 요청을 받으면 Controller가 이 요청에 대한 비즈니스 로직을 수행한다. 2) 이 과정에서 Controller는 필요에 따라 Model을 호출하여 데이터를 요청한다. 3) 사용자 요청이 모두 처리되면 View를 통해 원하는 정보를 화면에 출력한다.
2) MVC 1과 MVC 2의 차이점
- MVC 1 : 웹 개발 시 JSP가 View와 Controller의 역할을 모두 감당한다. 따라서 Java코드와 Html, CSS 코드가 섞여 소스가 복잡해지고 가독성이 떨어지고 유지보수가 힘들어진다. 하지만 설계가 간단하여 개발 속도가 빠르고 규모가 작은 프로젝트에 적합하다.
- MVC 2: 1에서 유지보수가 힘들다는 단점을 보완해서 나온 모델이다. JSP를 View의 역할만 하게 하고 Controller 역할은 Servlet이 수행한다. 따라서 Java 코드와 Html, CSS 코드가 분리되어 확장에 용이하고 유지보수가 수월해진다. 하지만 초기 설계 단계에 비용이 많이 들고 개발 시간이 오래 걸린다는 단점이 있다.
- MVC 의 요청 처리 흐름: 클라이언트는 URL을 통해 요청을 전송 => Dispatcher Servlet은 핸들러 매핑을 통해 해당 요청이 어느 Controller에서 온 요청인지 찾음 => Dispatcher Servlet은 핸들러 어댑터에게 요청의 전달을 맡김 => 핸들러 어댑터는 해당 컨트롤러에 요청을 전달 => 컨트롤러는 비즈니스 로직을 처리한 후 반환할 뷰의 이름을 반환 => 디스패처 서블릿은 뷰 리졸버를 통해 반환할 뷰를 찾음 => 디스패처 서블릿은 컨트롤러에서 뷰에 전달할 데이터를 추가 => 데이터가 추가된 뷰를 반환
3) HTTP 응답 - HTTP API
- HTTP API를 제공하는 경우에 HTML이 아니라 데이터를 전달해야하므로 HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어 보낸다.
package hello.springmvc.basic.response;
import hello.springmvc.basic.HelloData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Controller
@ResponseBody
//@RestController //=> @Controller + @ResponseBody
public class ResponseBodyController {
//HttpServletResponse 객체를 통해서 Http 메시지 바디에 ok 응답 메시지를 전달한다.
@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletResponse response) throws IOException {
response.getWriter().write("ok");
}
//HttpEntity를 상속 받은 ResponseEntity는 Http 메시지 헤더, 바디 정보를 가지고 Http 응답 코드를 설정한다.
@GetMapping("/response-body-string-v2")
public ResponseEntity<String> responseBodyV2() {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
//view를 사용하지 않고 Http 메시지 컨버터를 통해서 HTTP 메시지를 직접 입력할 수 있다.
// @ResponseBody
@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
return "ok";
}
//ResponseEntity를 반환하는데 Http 메시지 컨버터를 통해 JSON 형식으로 변환되어 반환된다.
@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return new ResponseEntity<>(helloData, HttpStatus.OK);
}
//응답코드 설정
@ResponseStatus(HttpStatus.OK)
// @ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
}
4) 요청 매핑 핸들러 어댑터 구조
- 클라이언트의 HTTP 요청 => Dispatcher Servlet에서 핸들러 조회 => 핸들러를 처리할 수 있는 핸들러 어댑터 조회 => 핸들러 어댑터 => 핸들러(Controller) 호출 => 핸들러 어댑터를 통해 ModelAndView 반환 => Dispatcher Servlet의 viewResolver 호출 => View 반환 => render(model) 호출 => View => HTML 응답
- Dispatcher Servlet -> RequestMapping(핸들러 어댑터) -> Argument Resolver(컨트롤러의 파라미터, 에노테이션 정보를 기반으로 전달 데이터 생성) -> HTTP 메시지 컨버터
5) @RequestBody, @RequestParam, @ModelAttribute
- @RequestBody: 클라이언트가 전송하는 JSON 형태의 HTTP Body 내용을 Message Converter를 통해 Java Object로 변환시켜주는 역할을 한다.
- @RequestParam: 1개의 HTTP 요청 파라미터를 받기 위해 사용하며 필수 여부가 true이므로 기본적으로 반드시 해당 파라미터가 전송되어야 한다.
- @ModelAttribute: HTTP Body 내용과 HTTP 파라미터의 값들을 생성자, Getter, Setter를 통해 주입하기 위해 사용된다.
6) 의존성 주입(DI)
- 필요한 객체를 직접 생성하는 것이 아닌 외부로부터 객체를 받아서 사용하는 것으로 객체 간의 결합도를 줄이고 코드의 재사용성을 높일 수 있다.
- 생성자 주입, 필드 주입, 수정자 주입
- 생성자 주입을 권장하는 이유
- 순환 참조 가능
- 의존 관계에 내용을 외부로 노출 시킴으로써 어플리케이션을 실행하는 시점에서 오류를 체크할 수 있음