1. Controller 클래스 설계 및 구조 생성
- API 계층을 Spring MVC 기반의 코드로 구현해 본다
1) 애플리케이션 경계 설정
- 커피 주문 애플리케이션으로 설정
2) 애플리케이션 기능 요구사항 수집
- 기능적으로 요구사항을 정리해 본다
3) 패키지 구조 생성
- 기능 기반 패키지 구조(package-by-feature)
- 애플리케이션에서 구현해야 하는 기능을 기준으로 패키지를 구성하는 것을 말한다
- 패키지를 커피 / 회원 / 주문 등 기능으로 구분할 수 있다 - 계층 기반 패키지 구조(package-by-layer)
- 패키지를 하나의 계층(Layer)으로 보고 클래스들을 계층별로 묶어서 관리하는 구조를 말한다
- controller / model / repository / service 등 계층으로 구분할 수 있다 - 테스트와 리팩토링이 용이하고, 향후에 마이크로 서비스 시스템으로의 분리가 상대적으로 용이한 기능 기반 패키지 구조 사용을 권장한다
4) 애플리케이션의 기능 요구사항 및 클래스 정리
- REST API 기반의 애플리케이션에서는 일반적으로 애플리케이션이 제공해야 될 기능을 리소스(Resource, 자원)로 분류한다
- 리소스에 해당하는 Controller 클래스를 작성한다
5) 엔트리포인트(Entrypoint) 클래스 작성
- Spring Boot 기반의 애플리케이션이 정상적으로 실행되기 위해서 가장 먼저 해야될 일은 main() 메서드가 포함된 애플리케이션의 엔트리포인트(Entrypoint, 애플리케이션 시작점)를 작성하는 것이다
- 부트스트랩(Bootstrap)은 애플리케이션이 실행되기 전에 여러가지 설정 작업을 수행하여 실행 가능한 애플리케이션으로 만드는 단계를 의미한다
- 엔트리포인트는 spring initializr를 사용하여 프로젝트를 생성하면 자동으로 만들어 진다
- exam_controller > src > main > java > com.dreamfactory.exam_controller > ExamControllerApplication 으로 자동 생성된다
//엔트리포인트 클래스
package com.dreamfactory.exam_controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//자동구성을 활성화 해 준다
//애플리케이션 패키지 내에서 @Component가 붙은 클래스를 검색한 후(scan), Spring Bean으로 등록하는 기능을
활성화 해 준다
//@Configuration 이 붙은 클래스를 자동으로 찾아주고, 추가적으로 Spring Bean을 등록하는 기능을 활성화 해 준다
public class ExamControllerApplication {
public static void main(String[] args) {
SpringApplication.run(ExamControllerApplication.class, args);
}
//SpringApplication.run : Spring 애플리케이션을 부트스트랩하고, 실행하는 역할을 한다
}
6) 애플리케이션의 Controller 구조 작성
- 회원관리를 위한 MemberController 구조 작성
package com.dreamfactory.exam_controller.member;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//@애터테이션에 의해 자동으로 import 된다
@RestController
//Spring MVC에서는 특정 클래스에 @RestController 를 추가하면 해당 클래스가 REST API의 리소스(자원, Resource)를
처리하기 위한 API 엔드포인트로 동작함을 정의한다
//@RestController가 추가된 클래스는 애플리케이션 로딩 시, Spring Bean 으로 등록 해 준다
@RequestMapping
//@RequestMapping 은 클라이언트의 요청과 클라이언트 요청을 처리하는 핸들러 메서드(Handler Method)를 매핑해주는
역할을 한다
//Controller 클래스 레벨에 추가하여 클래스 전체에 사용되는 공통 URL(Base URL)을 설정할 수 있다
public class MemberController {
}
- 커피정보를 위한 CoffeeController 구조 작성
package com.dreamfactory.exam_controller.coffee;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/coffees")
//v1은 버젼을 의미한다. coffees는 데이터 post, get 의 조회 위치 URI를 지정한다
//Controller 클래스 레벨에 추가하여 클래스 전체에 사용되는 공통 URL(Base URL)을 설정할 수 있다.
public class CoffeeController {
}
- 주문관리를 위한 OrderController 구조 작성
package com.dreamfactory.exam_controller.order;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping
public class OrderController {
}
[참조 자료]
※ REST API란?
- REST(Representational State Transfer)는 HTTP 네트워크 상의 리소스(Resource, 자원)를 정의하고 해당 리소스를 URI라는 고유의 주소로 접근하는 접근 방식을 의미한다
- REST API란 REST 방식을 통해서 리소스에 접근하기 위한 서비스 API를 지칭한다
※ REST에서 의미하는 리소스
- REST에서 의미하는 자원은 데이터베이스에 저장된 데이터, 문서, 이미지, 동영상 등 HTTP 통신을 통해 주고 받을 수 있는 모든 것을 의미한다
※ URI(Uniform Resource Identifier)와 URL(Uniform Resource Locator)
- URI는 네트워크 상에 있는 특정 리소스를 식별하는 통합 자원 식별자(Uniform Resource Identifier)를 의미한다
- URL은 인터넷에 있는 리소스를 나타내는 통합 리소스 식별자를 의미한다
- 일상적인 웹 상의 주소는 URL을 의미한다
- URI는 URL의 상위 개념으로 볼 수 있다
- URI는 리소스를 식별하는 식별자 역할을 하고, URL은 리소스의 위치를 가리킨다
- http://www.itivllage.tistory.com/manage? id = 1 에서
- http://www.itivllage.tistory.com/manage'까지는 리소스의 위치를 가리키는 URL이고
- http://www.itivllage.tistory.com/manage? id = 1는 리소스를 식별하기 위한 'id = 1'이라는 고유 식별자가 붙었으므로 URI이다
※ HTTP 에서 REST API 서비스를 만드는 경우의 REST API URI 작성 규칙
- URI의 마지막이 '/' 로 끝나지 않게 한다
- http://www.dreamfactory.com/coffees (good)
- http://www.dreamfactory.com/coffees/ (bad) - 동사 보다는 명사를 사용한다
- http://www.dreamfactory.com/coffees (good)
- http://www.dreamfactory.com/coffees/update (bad) - 단수형 보다는 복수형 명사를 사용한다
- http://www.dreamfactory.com/coffees (good)
- http://www.dreamfactory.com/coffee (bad) - URI는 기본 소문자를 사용한다
- 언더스코어( _ ) 대신에 하이픈(-)을 사용한다
- 파일 확장자는 URI에 포함하지 않는다
※ 참조 링크
- RESTful API의 URI 작성 규칙: https://itvillage.tistory.com/35
RESTful API의 URL 작성 규칙
REST API란? REST(Representational State Transfer)는 HTTP 네트워크 상의 리소스(Resource, 자원)를 정의하고 해당 리소스를 URI라는 고유의 주소로 접근하는 접근 방식을 의미하며, REST API란 REST 방식을 통..
itvillage.tistory.com
- @SpringBootApplication 의 역할: https://itvillage.tistory.com/36
@SpringBootApplication 의 역할
[코드 1-1] @SpringBootApplication public class CoffeeApplication { public static void main(String[] args) { SpringApplication.run(CoffeeApplication.class, args); } } [코드 1-1]과 같이 Spring Boot Ap..
itvillage.tistory.com
Spring Boot 애플리케이션의 부트스트랩(Bootstrap) 과정: https://itvillage.tistory.com/37
Spring Boot 애플리케이션의 부트스트랩(Bootstrap) 과정 알아보기
Spring Boot에서의 부트스트랩이란? 일반적으로 부트스트랩(Bootstrap)이란 어떠한 과정이 시작되어 알아서 진행되는 일련의 과정을 의미합니다. 컴퓨터의 부팅 과정을 생각해보면 이해가 쉬울것입
itvillage.tistory.com
2. 핸들러 메서드(Handler Method)
- MemberController에 클라이언트의 요청을 처리할 핸들러 메서드(Handler Method)가 아직 없기 때문에 localhost를 요청해도 에러가 발생한다
- 작업 중인 애플리케이션은 REST API 기반 애플리케이션이기 때문에 응답 메시지는 JSON 형식으로 클라이언트에게 전달된다
1) MemberController의 핸들러 메서드(Handler Method) 작성
- 회원 이메일 주소: email
- 회원 이름: name
- 회원 전화번호: phoneNumber
- 위의 정보를 기준으로 작성한다
package com.dreamfactory.exam_controller.member;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.sql.SQLOutput;
//@애터테이션에 의해 자동으로 import 된다
@RestController
@RequestMapping(value ="v1/members", produces = MediaType.APPLICATION_JSON_VALUE)
//produces애트리뷰트(Attribute)는 응답 데이터를 어떤 미디어 타입으로 클라이언트에게 전송할 지를 설정한다
//JSON 형식의 데이터를 응답 데이터로 전송하기 위해 MediaType.APPLICATION_JSON_VALUE 값을 설정했다
//이 값을 설정하지 않으면 현재 코드에서는 JSON 형식의 데이터를 응답으로 전송하지 않고, 문자열 자체를 전송한다
public class MemberController {
@PostMapping
//postMember() 메서드는 회원 정보를 등록해주는 핸들러 메서드이다
//클라이언트의 요청 데이터(request body)를 서버에 생성할 때 사용하는 애너테이션이다
//클라이언트에서 요청 전송 시 HTTP Method 타입을 동일하게 맞춰 주어야 한다(POST)
public String postMember(@RequestParam("email")String email,
@RequestParam("name")String name,
@RequestParam("phone")String phone) {
//@RequestParam() 핸들러 메서드의 파라미터 종류 중 하나이다
/*클라이언트에서 전송하는 요청 데이터를 쿼리 파라미터(Query Parmeter 또는 Query String),
폼 데이터(form-data), x-www-form-urlencoded 형식으로 전송하면 서버 쪽에서 전달 받을 때
사용하는 애너테이션이다*/
System.out.println("# email: " + email);
System.out.println("# name: " + name);
System.out.println("# phone: " + phone);
//클라이언트 쪽에서 JSON 형식의 데이터를 전송 받아야 하기 때문에
//응답 문자열을 JSON 형식에 맞게 작성한다
String reponse =
"{\"" +
"email\":\""+email+"\"," +
"\"name\":\""+name+"\",\"" +
"phone\":\"" + phone+
"\"}";
return reponse;
}
@GetMapping("/{member-id}")
//@GetMapping은 클라이언트가 서버에 리소스를 조회할 때 사용하는 애너테이션이다
//@GetMapping 애너테이션의 괄호 안에는 몇 가지 애트리뷰트(Attribute)를 사용할 수 있다
//여기서는 전체 HTTP URI의 일부를 지정했다
//클라이언트에서 getMember() 핸들러 메서드에 요청을 보낼 경우, 최종 URI는 형태는 아래와 같다
// /v1/members/{member-id}
//{member-id}는 회원 식별자를 의미한다
//클라이언트가 요청을 보낼 때 URI로 어떤 값을 지정하느냐에 따라서 동적으로 바뀌는 값이다
public String getMember(@PathVariable("member-id")long memberId) {
//getMember() 메서드는 특정 회원의 정보를 클라이언트 쪽에 제공하는 핸들러 메서드이다
//@PathVariable역시 핸들러 메서드의 파라미터 종류 중 하나이다
//@PathVariable의 괄호 안에 입력한 문자열 값은 @GetMapping("/{member-id}") 처럼 중괄호({ }) 안의 문자열과 동일해야 한다
//여기서는 두 문자열 모두 “member-id” 로 동일하게 지정했다
//두 문자열이 다르면 MissingPathVariableException이 발생한다
System.out.println("# memberId: " + memberId);
//not implementation
return null;
}
@GetMapping //별도의 URI를 지정해주지 않았기 때문에 클래스 레벨의 URI(“/v1/members”)에 매핑된다
//getMembers() 메서드는 회원 목록을 클라이언트에게 제공하는 핸들러 메서드이다
public String getMembers() {
System.out.println("# get Members");
//not implementation
return null;
}
}
- 쿼리 파라미터(Query Parameter 또는 QueryString)
- 요청 URL에서 ‘?’를 기준으로 붙는 key/value 쌍의 데이터를 말한다
- ex) http://localhost:8080/coffees/1?page=1&size=10 - RestController
- Spring MVC에서 웹 요청을 하기 위한 준비가 완료되었음을 의미한다 - RequestMapping
- RequestMapping(value="파일경로", method={HTTP 요청값}) 의 형식으로 작성한다
- HTTP 값을 지정하지 않으면 모든 HTTP요청에 매핑된다
- Request에 대한 헤더 값을 지정하면 매핑 범위를 좁힐 수 있다
헤더 값을 지정하여 범위를 좁힌 예)
@RequestMapping(value = "/ex/dream", headers = "key=val", method = GET)
@ResponseBody
public String getDreamWithHeader() {
return "Get some Dream with Header";
}
HTTP POST에 요청된 예)
@RequestMapping(value = "/ex/dream", method = POST)
@ResponseBody
public String postDream() {
return "Post some Dream";
}
headers속성을 사용하여 헤더를 여러개 지정할 수 있다
@RequestMapping(
value = "/ex/dream",
headers = { "key1=val1", "key2=val2" }, method = GET)
@ResponseBody
public String getDreamWithHeaders() {
return "Get some Dream with Header";
}
※ MemberController : postMember() 요청 및 응답
- HTTP POST Method와 요청 URI를 입력한다
- [Body] 탭에서 ‘x-www-form-urlencoded’ 형식의 요청 데이터를 KEY/VALUE 형태로 입력한다
- JSON 형식의 응답 데이터를 전달 받을 수 있다
- 우측 중간을 보면 ‘200’, ‘OK’ 라는 값을 통해서 클라이언트가 정상적으로 응답을 전달 받았음을 알 수 있다
2) CoffeeController의 핸들러 메서드(Handler Method) 작성
- 커피 식별자: coffee
- 식별자: coffeeId
- 커피명(영문): engName
- 커피명(한글): korName
- 가격: price
package com.dreamfactory.exam_controller.coffee;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value="v1/coffees", produces = MediaType.APPLICATION_JSON_VALUE)
//v1은 버젼을 의미한다. coffees는 데이터 post, get 의 조회 위치를 의미한다
public class CoffeeController {
@PostMapping
//postCoffee() 메서드는 커피 정보를 등록해 준다
public String postCoffee(@RequestParam("coffee")String coffee,
@RequestParam("coffeeId")String coffeeId,
@RequestParam("korName")String korName,
@RequestParam("engName")String engName,
@RequestParam("price")int price) {
System.out.println("# coffee:" + coffee);
System.out.println("# coffeeId:" + coffeeId);
System.out.println("# korName:" + korName);
System.out.println("# engName:" + engName);
System.out.println("# price:" + price);
String reponse =
"{\"" +
"coffee\":\""+coffee+"\"," +
"\"coffeeId\":\""+coffeeId+"\"," +
"\"korName\":\""+korName+"\"," +
"\"engName\":\""+engName+"\"," +
"\"price\":\""+price+
"\"}";
return reponse;
}
@GetMapping("/{coffee-id}")
//getCoffee() 메서드는 커피 정보을 클라이언트에게 제공하는 핸들러 메서드이다
public String getCoffee(@PathVariable("coffee-id")long coffeeId) {
System.out.println("# coffeeId: " + coffeeId);
return null;
}
@GetMapping //별도의 URI를 지정해주지 않았기 때문에 클래스 레벨의 URI(“/v1/coffees”)에 매핑된다
//getCoffees() 메서드는 커피 목록을 클라이언트에게 제공하는 핸들러 메서드이다
public String getCoffees() {
System.out.println("# get Coffees");
return null;
}
}
3) OrderController의 핸들러 메서드(Handler Method) 작성
- 회원 식별자: memberId
- 커피 식별자: coffeeId
package com.dreamfactory.exam_controller.order;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value="v1/orders", produces = MediaType.APPLICATION_JSON_VALUE)
public class OrderController {
@PostMapping
//postOrder() 메서드는 주문 정보를 등록한다
public String postOrder(@RequestParam("memberId")String memberId,
@RequestParam("coffeeId")String coffeeId) {
System.out.println("# memberId:" + memberId);
System.out.println("# coffeeId:" + coffeeId);
String reponse =
"{\"" +
"memberId\":\""+memberId+"\"," +
"\"coffeeId\":\""+coffeeId+
"\"}";
return reponse;
}
@GetMapping("/{order-id}")
public String getOrder(@PathVariable("order-id")long orderId) {
System.out.println("# orderId: " + orderId);
return null;
}
@GetMapping
public String getOrders() {
System.out.println("# get Orders");
return null;
}
}
※ 식별자(Identifier)
- 어떤 데이터를 식별할 수 있는 고유값을 의미한다
- 기본키(Primary key)는 대표적인 식별자 중 하나이다
- API 계층에서 사용하는 memberId, coffeeId 등은 데이터베이스의 테이블에 저장되는 로우(row)의 식별자인 기본키(Primary key)가 된다
※ 참조 링크
▶ 핸들러메서드 파라미터 : https://itvillage.tistory.com/41
Controller 핸들러 메서드의 Argument 알아보기
Controller의 핸들러 메서드는 다양한 유형의 Argument(인수)를 지원합니다. 그 중에서 REST API 애플리케이션에서 자주 사용되는 유형의 Argument를 간단히 살펴보도록 하겠습니다. Method Argument 설명 @Reque
itvillage.tistory.com
▶ 미디어 타입(Media Type) : https://ko.wikipedia.org/wiki/%EB%AF%B8%EB%94%94%EC%96%B4_%ED%83%80%EC%9E%85
미디어 타입 - 위키백과, 우리 모두의 백과사전
ko.wikipedia.org
▶ MIME 타입 : https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_Types
MIME 타입 - HTTP | MDN
MIME 타입이란 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘입니다: 웹에서 파일의 확장자는 별 의미가 없습니다. 그러므로, 각 문서와 함께 올바른 MIME 타입을 전송하도
developer.mozilla.org
https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
MIME 타입의 전체 목록 - HTTP | MDN
다음은 일반적인 확장자로 정렬된, 문서 타입과 관련된 MIME 타입의 포괄적인 목록입니다.
developer.mozilla.org
▶ HTTP POST Method의 요청 데이터 형식 : https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/POST
POST - HTTP | MDN
HTTP POST 메서드는 서버로 데이터를 전송합니다. 요청 본문의 유형은 Content-Type 헤더로 나타냅니다.
developer.mozilla.org
▶ HTTP 응답 상태(Response Status) : https://developer.mozilla.org/ko/docs/Web/HTTP/Status
HTTP 상태 코드 - HTTP | MDN
HTTP 응답 상태 코드는 특정 HTTP 요청이 성공적으로 완료되었는지 알려줍니다. 응답은 5개의 그룹으로 나누어집니다: 정보를 제공하는 응답, 성공적인 응답, 리다이렉트, 클라이언트 에러, 그리고
developer.mozilla.org
'Spring MVC' 카테고리의 다른 글
Spring MVC(4) - API 계층 - HTTP헤더(Header) (0) | 2022.09.21 |
---|---|
Spring MVC(3) - API 계층 -Controller (ResponseEntity 적용) (0) | 2022.09.21 |
Spring MVC(1) - 개요 (0) | 2022.09.21 |
Spring MVC - Testing - Mockito (0) | 2022.07.14 |
Spring MVC - 데이터 액서스 계층(Data Access Layer) - DDD (0) | 2022.07.03 |