노션으로 다시 돌아갔습니다 😅

[Spring MVC] API 계층 적용하기 (Prac Project - 1. 커피 주문 애플리케이션 시작)

by mignon25

커피 주문 애플리케이션의 기능 요구 사항

  • 주인이 커피 정보를 관리하는 기능
    • 커피 정보 등록 기능
    • 등록한 커피 정보 수정 기능
    • 등록한 커피 정보 삭제 기능
    • 등록한 커피 정보 조회 기능

 

  • 고객이 커피 정보를 조회하는 기능
    • 커피 정보 조회 기능

 

  • 고객이 커피를 주문하는 기능
    • 커피 주문 등록 기능
    • 커피 주문 취소 기능
    • 커피 주문 조회 기능

 

  • 고객이 주문한 커피를 주인이 조회하는 기능
    • 커피 주문 조회 기능
    • 고객에게 전달 완료한 커피에 대한 주문 완료 처리 기능

 

 

커피 주문 애플리케이션에 필요한 리소스

REST API 기반의 애플리케이션에서 일반적으로 애플리케이션이 제공해야 할 기능을 리소스(Resource, 자원)로 분류한다. 

커피 주문 애플리케이션에는 다음과 같은 리소스가 필요할 것이다.

 

  • 회원(Member)
    • 주인과 회원의 구분 : Member의 ROLE을 통해 구분
  • 커피(Coffee)
  • 주문(Order)

 

 

엔트리포인트(Entrypoint) 클래스 작성

Spring Boot 기반의 애플리케이션이 정상적으로 실행되기 위해 가장 먼저 해야할 일은 main() 메서드가 포함된 애플리케이션의 엔트리포인트(Entrypoint, 애플리케이션 시작점)을 작성하는 것이다.

 

Spring Initializer 를 통해 프로젝트를 생성하게 되면 엔트리포인트 클래스가 자동으로 작성되어 있다. 

package com.codestates;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // 1
public class Section3Week1Application {

	public static void main(String[] args) { 
		SpringApplication.run(Section3Week1Application.class, args); // 2
	}

}
  1. @SpringBootApplication
    • 자동 구성 활성화
    • 애플리케이션 패키지 내에서 @Component가 붙은 클래스를 검색(scan)한 후, Spring Bean 으로 등록
    • @Configuration 이 붙은 클래스를 자동으로 찾아주고, 추가적으로 Spring Bean 등록
  2. SpringApplication.run(Section3Week1Application.class, args);
    • Spring 애플리케이션을 부트스트랩하고, 실행하는 역할
    • 부트스트랩 : 애플리케이션이 실행되기 전에 여러가지 설정 작업을 수행하여 실행 가능한 애플리케이션으로 만드는 것.

 

 

커피 주문 애플리케이션의 Controller 구조 작성

MemberController 구조 작성

package com.codestates.member;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController // 1
@RequestMapping("v1/members") // 2
public class MemberController {
    
}
  1. @RestController
    • Spring MVC에서는 특정 클래스에 @RestController를 추가하면 해당 클래스가 REST API의 리소스를 처리하기 위한 API 엔드포인트로 동작한다.
    • @RestController 가 추가된 클래스는 애플리케이션 로딩 시, Spring Bean 으로 등록된다. 
  2. @RequestMapping
    • 클라이언트의 요청과 클라이언트 요청을 처리하는 핸들러 메서드(Handler Method)를 매핑해주는 역할
    • Controller 클래스 레벨에 추가하여 클래스 전체에 사용되는 공통 URL(Base URL) 설정

 

CoffeeController 구조 작성

package com.codestates.coffee;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1/coffees")
public class CoffeeController {
}

 

OrderController 구조 작성

package com.codestates.order;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1/orders")
public class OrderController {
}

 

 

핸들러 메서드(Handler Method)  - (1) MemberController

요청에 필요한 Member 정보

  • email
  • name
  • phoneNumber

 

MemberController

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 = "{" +
                "\"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("MemberController.getMembers");
        
        // not implementation
        return null;
    }
    
}

produces

  • 클래스 레벨의 @RequestMapping에 추가된 옵션
  • 응답 데이터를 어떤 미디어 타입으로 클라이언트에게 전송할지 설정
  • {MediaType.APPLICATION_JSON_VALUE} : JSON 형식으로 전송하겠다는 의미
  • 이 값을 설정하지 않으면 현재 위의 코드에서는 JSON 형식의 데이터를 응답으로 전송하지 않고, 문자열 자체를 전송한다. 

 

produces = {MediaType.APPLICATION_JSON_VALUE} 적용

 

produces 옵션 미적용

@RequestParam

  • 핸들러 메서드의 파라미터 종류 중 하나
  • 클라이언트 쪽에서 전송하는 요청 데이터를 다음의 형식으로 전송하면 이를 서버 쪽에서 전달 받을 때 사용하는 애너테이션
    • 쿼리 파라미터(Query Parameter or Query String)
      EX) localhost:8080/v1/members?email=mignon@email.com&name=minhyeong&phone=010-0000-0000 
    • 폼 데이터(form-data)
    • x-www-from-urlencoded

 

POST 리턴 값

  • postMember() 핸들러 메서드의 현재 리턴 타입은 String
  • 클라이언트 쪽에서 JSON 형식의 데이터를 전송 받아야 하므로 응답 문자열을 JSON 형식에 맞게 작성한 상태
    -> produces 옵션 설정으로 인해 JSON 형식으로 바뀌어 전달된다. 
  • 일반적으로 데이터 생성 후 클라이언트 쪽으로 생성한 데이터를 리턴해주는 것이 관례

 

{member-id}

  • 회원 식별자를 의미
  • 클라이언트가 요청을 보낼 때 URI에서 이 부분을 어떤 값으로 지정하느냐에 따라 동적으로 바뀌게 된다. 

 

@PathVariable

  • 핸들러 메서드의 파라미터 종류 중 하나
  • @GetMapping("/{member-id}") 에서 지정된 중괄호 ({}) 안의 문자열과 동일해야 한다. 
  • 두 문자열이 다를 경우 MissingPathVariableException 발생
  • EX) GET, localhost:8080/v1/members/1

 

 

핸들러 메서드(Handler Method)  - (2) OrderController

package com.codestates.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
    public String postOrder(
            @RequestParam("memberId") long memberId,
            @RequestParam("coffeeId") long coffeeId
    ) {

        System.out.println("memberId = " + memberId);
        System.out.println("coffeeId = " + coffeeId);

        String response = "{" +
                "\"email\":\"" + memberId + "\"," +
                "\"phone\":\"" + coffeeId + "\"" +
                "}";

        return response;
    }

    @GetMapping("/{order-id}")
    public String getOrder(@PathVariable("order-id") long orderId) {
        System.out.println("orderId = " + orderId);

        // not implementation
        return null;
    }

    @GetMapping
    public String getOrders() {
        System.out.println("OrderController.getOrders");

        // not implementation
        return null;
    }

}

 

 

Practice Project - 커피 주문 애플리케이션

  1. API 계층 적용하기(Controller)
  2. API 계층에 ResponseEntity, Header 적용

 

 

Additional Keyword

블로그의 정보

Mignon'S Dev Log

mignon25

활동하기