[Section3] Spring MVC - API 계층 1
🧑🏻💻 TIL(Today I Learned)
✔️ Spring MVC 아키텍처, Controller
1. Spring MVC란?
➡️ Spring 모듈 중에 웹 계층을 담당하는 몇 가지 모듈이 있는데 그중에서 서블릿(Servlet) API 를 기반으로 클라이언트의 요청을 처리하는 모듈을 "spring-webmvc" 라고 함
➡️ 클라이언트의 요청을 편리하게 처리해 주는 프레임워크
📍서블릿(Servelt)이란?
: 클라이언트의 요청을 처리하도록 특정 규약에 맞추어서 Java 코드로 작성하는 클래스 파일
: Spring MVC 내부에서는 서블릿을 기반으로 웹 애플리케이션이 동작함
: 아파치 톰캣(Apache Tomcat)은 서블릿이 웹 애플리케이션으로 실행 되도록 도와주는 서블릿 컨테이너(Servlet Container) 중 하나
🔎 Model
➡️ Spring MVC 에서 "M"
➡️ Spring MVC 기반의 웹 애플리케이션이 클라이언트의 요청을 전달받으면 요청 사항을 처리하기 위한 작업을 하는데 이렇게 처리한 작업의 결과 데이터를 클라이언트에게 응답으로 돌려주는 작업의 처리 결과 데이터를 의미함
서비스 계층(Service Layer) : 클라이언트의 요청 사항을 구체적으로 처리하는 영역
비즈니스 로직(Business Logic) : 실제로 요청 사항을 처리하기 위해 Java 코드로 구현한 것
🔎 View
➡️ Spring MVC에서 "V"
➡️ Model 데이터를 이용해서 웹 브라우저 같은 클라이언트 애플리케이션의 화면에 보이는 리소스(Resource) 제공하는 역할
➡️ 다양한 View의 형태는 다음과 같음
- HTML 페이지의 출력
- 클라이언트 애플리케이션에 보이는 HTML 페이지를 직접 렌더링 해서 클라이언트 측에 전송하는 방식
- 즉, 기본적인 HTML 태그로 구성된 페이지에 Model 데이터를 채워 넣은 후 최종적인 HTML 페이지 만들어서 클라이언트에게 전송
- Spring MVC에서 지원하는 HTML 페이지 출력 기술에는 Thymleaf, FreeMaker, JSP + JSTL, Tiles 등이 있음 - PDF, Excel 등의 문서 형태로 출력
- Model 데이터를 가공해서 PDF 문서나 Excel 문서를 만들어서 클라이언트 측에 전송하는 방식
- 문서 내에서 데이터가 동적으로 변경되어야 하는 경우 사용할 수 있는 방식 - XML, JSON 등 특정 형식의 포맷으로 변환
- Model 데이터를 특정 프로토콜 형태로 변환해서 변환된 데이터를 클라이언트 측에 전송하는 방식
- 특정 형식의 데이터만 정송하고 프론트엔드 측에서 이 데이터를 기반으로 HTML 페이지를 만드는 방식
- 프론트엔드 영역과 백엔드 영역이 명확하게 구분되기 때문에 개발 및 유지보수가 상대적으로 용이함
- 프론트엔드 측에서 비동기 클라이언트 애플리케이션을 만드는 것이 가능함
JSON(JavaScript Object Notation)이란?
: Spring MVC에서 클라이언트 애플리케이션과 서버 애플리케이션이 주고받는 데이터 형식
: { "속성" : "값" }
🔎 Controller
➡️ Spring MVC에서 "C"
➡️ 클라이언트 측의 요청을 직접적으로 전달받는 엔드포인트(Endpoint)로써 Model과 View의 중간에서 상호 작용을 해주는 역할
➡️ 즉 클라이언트의 요청을 받아서 비즈니스 로직을 거친 후에 Model 데이터가 만들어지면 Model 데이터를 View로 전달하는 역할
⭐️ 전체적인 MVC 동작 흐름
Client가 요청 데이터 전송 -> Controller가 요청 데이터 수신 -> 비즈니스 로직 처리 -> Model 데이터 생성
-> Controller에게 Model 데이터 전달 -> Controller가 View에게 Model 데이터 전달 -> View가 응답 데이터 생성
2. Spring MVC의 동작 방식과 구성 요소
- 클라이언트의 요청을 제일 먼저 전달받는 구성요소는 DispatcherServlet
- DispatcherServlet은 HandlerMapping 인터페이스에게 Controller의 검색을 위임
- DispatcherServlet은 검색된 Controller 정보를 토대로 HandlerAdapter 인터페이스에게 Controller 클래스 내에 있는 Handler 메서드의 호출을 위임
- HandlerAdapter 인터페이스는 Controller 클래스의 Handler 메서드를 호출
- DispatcherServlet은 ViewResolver에게 View의 검색을 위임
- DispatcherServlet은 View에게 Model 데이터를 포함한 응답 데이터 생성을 위임
- DispatcherServlet은 최종 응답 데이터를 클라이언트에게 전달
DispatcherServlet이 애플리케이션의 가장 앞단에 배치되어 다른 구성요소들과 상호작용하면서 클라이언트의 요청을 처리하는 패턴
-> Front Controller Pattern
3. [실습]Controller 클래스 설계 및 구조 생성
➡️ 오늘 배운 API 계층은 클라이언트의 요청을 직접적으로 받는 계층
➡️ Controller 클래스가 Spring MVC에서 클라이언트 요청의 최종 목적지
✔️ Java 패키지 구조
- 기능 기반 패키지 구조(pakage-by-feature)
- 애플리케이션의 패키지를 애플리케이션에서 구현해야 하는 기능을 기준으로 패키지를 구성하는 것
- 나누어진 패키지 안에는 하나의 기능을 완성하기 위한 계층별(API, 서비스, 데이터 엑세스) 클래스들이 모여있음
- 예를 들어 회원을 관리하기 위한 회원 기능과 상품을 관리하기 위한 상품 기능을 각각 패키지로 나누는 것 - 계층 기반 패키지 구조(package-by-layer)
- 패키지를 하나의 계층으로 보고 클래스들을 계층별로 묶어서 관리하는 구조
- 예를 들어 controller, dto(API 계층), model, service(비즈니스 계층), respository(데이터 액세스 계층) 나누는 것
두 가지 패키지 구조는 애플리케이션의 요구 사항이나 특성에 따라 상황에 맞게 적절하게 사용하면 됨
-> 하지만 SpringBoot에서는 테스트와 리팩토링이 용이하고 나중에 마이크로 서비스 시스템으로의 분리가 상대적으로 편리한 기능 기반 구조 사용을 권장함
📍Controller 설계
: 제일 먼저 '클라이언트로부터 발생할 요청에는 어떤 것들이 있을까' 고민해 보자
: 즉 '클라이언트 요청을 처리할 서버 애플리케이션의 기능으로 뭐가 필요할까'
📍 애플리케이션에 필요한 리소스
: REST API 기반의 애플리케이션에서는 일반적으로 애플리케이션이 제공해야 될 기능을 리소스(Resource,자원)으로 분류
: 만약 커피 주문 애플리케이션을 만든다면 회원, 커피, 주문 등과 같은 리소스가 필요할 것
➡️ 즉, 해당 리소스에 해당하는 Controller를 만들면 됨
🔎 엔트리포인트(Entrypoint) 클래스
➡️ SpringBoot 기반의 애플리케이션이 정상적으로 실행되기 위해서 가장 먼저 해야할 일은 main() 메서드가 포함된 애플리케이션의 엔트리 포인트 즉, 애플리케이션의 시작점을 작성하는것
➡️ Spring Initializr 를 통해 생성한 프로젝트에는 이미 작성되어 있음
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // (1)
public class Section3Week1Application {
public static void main(String[] args) {
// (2)
SpringApplication.run(Section3Week1Application.class, args);
}
}
- @SpringBootApplication
- 자동 구성 활성화
- 애플리케이션 패키지 내에서 @Component가 붙은 클래스를 검색한 후, Spring Bean으로 등록하는 기능 활성화
- @Configuration이 붙은 클래스 자동으로 찾아주고 Spring Bean을 등록하는 기능 - SpringApplication.run(Section3Week1Application.class, args);
- Spring 애플리케이션을 부트스트랩하고 실행하는 역할
부트스트랩(Bootstrap)이란?
: 애플리케이션이 실행되기 전에 여러가지 설정 작업을 수행하여 실행 가능한 애플리케이션으로 만드는 단계
🔎 Controller 구조 작성
- @RestController
- 해당 클래스가 REST API의 리소스(자원, Resource)를 처리하기 위한 API 엔드포인트로 동작함을 의미
- @RestController가 추가된 클래스는 애플리케이션 로딩 시 Spring Bean으로 등록해 줌 - @RequestMapping
- 클라이언트 요청과 클라이언트 요청을 처리하는 핸들러 메서드(Handler Method)를 매핑해 주는 역할
- 클래스 전체에 사용되는 공통 URL 설정을 함
❓ 엔드포인트(EndPoint)
: 해당 API를 호출할 때의 URL
: 즉 해당 API를 호출하였을 때 어떤 로직이 실행되는지 그 위치를 의미하는 URL
4. [실습]핸들러 메서드(Handler Method)
➡️ Controller 안에 Handler Method를 작성해야 클라이언트의 요청을 처리할 수 있음
클라이언트 요청을 위해 "Postman" 이라는 툴을 사용함
🔎 핸들러 메서드 적용
package com.codestates.member;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/v1/members", produces = {MediaType.APPLICATION_JSON_VALUE})
public class MemberController {
@PostMapping
public String postMember(@RequestParam("email") String email,
@RequestParam("name") String name,
@RequestParam("phone") String phone) { // 회원 정보 등록하는 핸들러 메서드
System.out.println("# email: " + email);
System.out.println("# name: " + name);
System.out.println("# phone: " + phone);
String response = // JSON 형식에 맞추어 문자열 작성
"{\"" +
"email\":\""+email+"\"," +
"\"name\":\""+name+"\",\"" +
"phone\":\"" + phone+
"\"}";
return response;
}
@GetMapping("/{member-id}")
public String getMember(@PathVariable("member-id")long memberId) { // 특정 회원 정보 조회
System.out.println("# memberId: " + memberId);
// not implementation
return null;
}
@GetMapping
public String getMembers() { // 모든 회원 정보
System.out.println("# get Members");
// not implementation
return null;
}
}
- @RequestMapping(value = "/v1/members", produces = {MediaType.APPLICATION_JSON_VALUE})
→ produces 속성은 응답 데이터를 어떤 미디어 타입으로 클라이언트에게 전송할지 설정함
이 코드에서는 JSON 형식의 데이터를 응답 데이터로 전송하겠다는 의미
이 값을 설정하지 않으면 JSON 형식의 데이터를 응답으로 전송하지 않고 문자열 자체를 전송함 - @PostMapping
→ 클라이언트의 요청 데이터(request body)를 서버에 생성할 때 사용하는 애너테이션 - @RequestParam
→ 핸들러 메서드의 파라미터 종류 중 하나
클라이언트 쪽에서 전송하는 요청 데이터를 쿼리 파라미터 (Query Parameter)또는 폼 데이터(form-data), x-www-form-urlencoded 형식으로 전송하면 이를 서버 쪽에서 전달받을 때 사용하는 애너테이션
❓ 쿼리 파라미터(Query Parameter 또는 QueryString)
: 요청 URL에서 "?"를 기준으로 붙는 key/value 쌍의 데이터
ex) http://localhost:8080/coffees/1?page=1&size=10
- @GetMapping
: 클라이언트가 서버에 리소스를 조회할 때 사용하는 애너테이션
클라이언트 쪽에서 getMember() 핸들러 메서드에 요청을 보낼 경우 최종 URI 형태
: /v1/members/{member-id}
: {member-id}는 회원 식별자를 의미하며 클라이언트가 요청을 보낼 때 URI로 어떤 값을 지정하느냐에 따라서 동적으로 바뀌는 값
- @PathVariable
: 핸들러 메서드의 파라미터 종류 중 하나
: 이 애너테이션의 괄호 안에 입력한 문자열 값은 @GetMapping("/{member-id}")의 중괄호 안의 문자열과 동일해야 함
: 만약 다르면 에러 발생
'SEB_BE_45 > 공부 정리' 카테고리의 다른 글
[Section3] Spring MVC - 서비스 계층 (0) | 2023.06.13 |
---|---|
[Section3] Spring MVC - API 계층 2 (0) | 2023.06.12 |
[SEB BE] Section 2 회고 / 20230608 (0) | 2023.06.08 |
[Section2] Spring Framework 핵심 - AOP2 (0) | 2023.06.07 |
[Section2] Spring Framework 핵심 - AOP (0) | 2023.06.05 |