Back-end/SpringBoot

[SpringBoot] 도서 관리 서비스 - API 생성하기

K_EY 2026. 1. 18. 00:31

01_@SpringBootApplication


📍 @SpringBootApplication

@SpringBootApplication // 스프링을 실행시키기 위해 필요한 다양한 설정들을 모두 자동으로 해줌
public class LibraryAppApplication {

  public static void main(String[] args) {
    SpringApplication.run(LibraryAppApplication.class, args); // 스프링 애플리케이션을 실행(run)
  }

}

 

 

 

 

 

 

 

 

02_네트워크와 API


📍 Network

데이터를 주고 받는 것(=택배)

 

 

 

📍 IP

각 컴퓨터의 고유 주소(=집 주소)

256을 넘지 않는 4개의 숫자로 이루어짐

ex. 244.66.51.9

 

 

 

📍 Domain Name

IP는 외우기 어려우니까 외우기 쉽게 별칭을 달아준 것

ex. 빨간집

 

 

 

📍 port number

컴퓨터에서 돌아가는 여러 프로그램 중 한 프로그램을 특정하는 것

ex. 3000

 

 

 

📍 HTTP

컴퓨터 간의 데이터를 주고 받는 표준(=운송장)

ex. 내놓아라 파란집 둘째, 빨간포션 2개

 

 

HTTP 요청

GET /portion?color=red&count=2
Host: spring.com:3000

 

HTTP method(GET) : HTTP 요청을 받는 컴퓨터에게 요구하는 행위(데이터를 달라)

path(/portion) : HTTP 요청을 받는 컴퓨터에게 원하는 자원

Query(?color=red&count=2) : 자원을 요구할 때 필요한 조건

Host : HTTP 요청을 받는 컴퓨터와 프로그램 정보

 

POST /oak/leather
Host: spring.com:3000

오크가죽정보

 

HTTP method(POST) : HTTP 요청을 받는 컴퓨터에게 요구하는 행위(데이터 저장해라)

path(/oak/leather) : HTTP 요청을 받는 컴퓨터에게 원하는 자원

Body(오크가죽정보) : 실제 저장할 정보

Host : HTTP 요청을 받는 컴퓨터와 프로그램 정보

 

  • 그 외 HTTP Method

PUT : 데이터를 수정하라

DELETE : 데이터를 삭제하라

 

  • 정보를 보내는 2가지 방법
  1. Query : GET, DELETE에서 사용
  2. body : POST, PUT에서 사용

 

 

HTTP 응답

HTTP/1.1 200 OK
Content-Type: application/json

{
 "name":"A",
 "age":null
}

 

  •  상태코드
    • 200 OK : 정상적으로 수행
    • 300 Moved Permanently : 다른 곳으로 옮겨가라
    • 404 Not Found : 요청을 찾을 수 없다
    • 500 Internal Server Error : 내부에 문제가 생김

 

 

 

📍 API(Application Programming Interface)

정해진 약속을 하여 특정 기능을 수행하는 것

💡 
첫째줄 - Method path Query
여러줄 - 헤더(여러 줄 가능)
(한 줄 띄기)
여러줄 - 바디(여러 줄 가능)

 

 

 

📍 URL(Uniform Resource Locator)

주소창

http://spring.com:3000/portion?color=red&count=2

 

http : 사용하고 있는 프로토콜

spring.com:3000 : 도메인 이름. 포트, 도메인 이름은 IP로 대체 가능

portion : path

color=red&count=2 : 쿼리. 추가 정보

 

 

 

 

03_GET API


Query를 사용하여 데이터 요청

 

 

 

📍 덧셈 API 명세서

HTTP Method : GET
HTTP Path : /add
Query(key, value) : int number1, int number2
API의 반환 결과 : int(두 숫자의 덧셈 결과)

 

 

 

📍 @RequestParam

controller/calculator/CalculatorController

package com.group.libraryapp.controller.calculator;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculatorController {

    @GetMapping("/add") // GET /add
    public int addTwoNumbers(@RequestParam int number1, @RequestParam int number2) {
        return number1 + number2;
    }
}

🔍 코드 설명

  • @RestController : 주어진 클래스를 Controller(API의 진입 지점)으로 만들어 준다. API를 개발하려고 하는 클래스에 작성. 이 어노테이션이 있어야 클래스 안에 함수를 만들고 API 호출됐을 때 이 함수로 연결
  • @GetMapping("/add") : GET /add. 아래 함수를 HTTP Method가 GET이고 HTTP path가 /add인 API로 지정한다.
  • @RequestParam : Query를 통해서 넘어온 데이터를 함수 파라미터에 넣을 때 사용
@RequestParam 문제점 : Query가 늘어나면 함수의 파라미터도 길어짐

 

 

 

📍 DTO

해결책 : 객체를 받아서 사용

DTO(Data Transfer Object) : 정보를 전달하는 역할의 객체

 

dto/calculator/request/CalculatorAddRequest

package com.group.libraryapp.dto.calculator.request;

public class CalculatorAddRequest {
    private final int number1;
    private final int number2;

    public CalculatorAddRequest(int number1, int number2) {
        this.number1 = number1;
        this.number2 = number2;
    }

    public int getNumber1() {
        return number1;
    }

    public int getNumber2() {
        return number2;
    }
}

 

controller/calculator/CalculatorController

package com.group.libraryapp.controller.calculator;

import com.group.libraryapp.dto.calculator.request.CalculatorAddRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculatorController {

    @GetMapping("/add")
    public int addTwoNumbers(CalculatorAddRequest request) { // API 호출될 때 주어진 Query가 이 객체에 있는 값에 들어가게 됨
        return request.getNumber1() + request.getNumber2();
    }
}

 

 

 

 

 

04_POST API


HTTP body를 사용하여 데이터 받음

 

  • JSON(JavaScript Object Notation)

객체 표기법

HTTP body에서 사용됨

{
   "key": value
}

 

 

 

📍 곱셈 API 명세서

HTTP Method : POST
HTTP Path : /multiply 
HTTP Body : { “number1”:숫자, “number2”:숫자 }
API의 반환 결과 : 숫자(곱셈 결과)

 

 

 

📍 코드로 구현

dto/calculator/request/CalculatorMultiplyRequest

package com.group.libraryapp.dto.calculator.request;

public class CalculatorMultiplyRequest {
    private int number1;
    private int number2;

    public int getNumber1() {
        return number1;
    }

    public int getNumber2() {
        return number2;
    }
}

 

controller/calculator/CalculatorController

package com.group.libraryapp.controller.calculator;

import com.group.libraryapp.dto.calculator.request.CalculatorAddRequest;
import com.group.libraryapp.dto.calculator.request.CalculatorMultiplyRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculatorController {

    @PostMapping("/multiply") // POST /multiply
    public int multiplyTwoNumbers(@RequestBody CalculatorMultiplyRequest request) {
        return request.getNumber1() *request.getNumber2();
    }
}

🔍 코드 설명

  • @RequestBody : POST API에서 HTTP body 안에 담긴 json을 DTO 객체로 변환시킬 수 있음. DTO 객체 앞에 작성.



 

 

05_유저 생성 API


📍 도서관 사용자 등록 API 명세서

HTTP Method : POST
HTTP Path : /user
HTTP Body(JSON) : { “name”: String(null 불가능), “age”: Integer }
결과 반환 : x (HTTP 상태코드 200 OK면 충분)

 

 

 

📍 POST API 구현

dto/user/request/UserCreateRequest

package com.group.libraryapp.dto.user.request;

public class UserCreateRequest {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }
}

 

domain/user/User

package com.group.libraryapp.domain.user;

// saveUser API가 사용돼서 유저가 저장되면 이 객체를 만들어서 실제 리스트에 저장
public class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        // API 통해서 들어온 name 값이 null이거나 비어있을 경우 예외 던짐
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException(String.format("잘못된 name이 들어왔습니다.", name));
        }
        this.name = name;
        this.age = age;
    }
}

 

controller/user/UserController

package com.group.libraryapp.controller.user;

import com.group.libraryapp.domain.user.User;
import com.group.libraryapp.dto.user.request.UserCreateRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class UserController {
    // Instance 생성
    private final List<User> users = new ArrayList<>();

    @PostMapping("/user") // 1. POST /user가 실행되면
    public void saveUser(@RequestBody UserCreateRequest request) { // 2. 함수 실행. json 형식으로 HTTP Body에 name과 age가 들어오면 DTO로 값이 매핑
        users.add(new User(request.getName(), request.getAge())); // 3. 유저 생성. 만들어진 유저 객체는 Users 리스트에 저장된다.
    } // 4. 200 OK 반환
}

 

 

 

 

06_유저 조회 API


📍 유저 조회 API 명세서

HTTP Method : GET
HTTP Path : /user
Query : 없음
결과 반환: [{ “id”: Long, “name”: String(null 불가능), “age”: Integer }, ...]

Controller에서 getter가 있는 객체를 반환하면 JSON이 된다.

 

  • Id : 유저 별로 겹치지 않는 유일한 번호(Primary Key). 여기서는 저장할 때 List에 담겨 있는 유저의 순서를 id로 지정
package com.group.libraryapp.domain.user;

public class Fruit {
    private String name;
    private int price;

    public Fruit(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
}

package com.group.libraryapp.controller.user;

import com.group.libraryapp.domain.user.Fruit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/fruit")
    public Fruit fruit() {
        return new Fruit("바나나", 2000);
    }
}

 

JSON 형식으로 반환

 

 

 

📍 GET API 구현

domain/user/User

package com.group.libraryapp.domain.user;

// saveUser API가 사용돼서 유저가 저장되면 이 객체를 만들어서 실제 리스트에 저장
public class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        // API 통해서 들어온 name 값이 null이거나 비어있을 경우 예외 던짐
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException(String.format("잘못된 name이 들어왔습니다.", name));
        }
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }
}

 

 

dto/user/response/UserResponse

package com.group.libraryapp.dto.user.response;

import com.group.libraryapp.domain.user.User;

public class UserResponse {
    private long id;
    private String name;
    private Integer age;

    public UserResponse(long id, User user) {
        this.id = id;
        this.name = user.getName();
        this.age = user.getAge();
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }
}

 

 

controller/user/UserController

package com.group.libraryapp.controller.user;

import com.group.libraryapp.domain.user.Fruit;
import com.group.libraryapp.domain.user.User;
import com.group.libraryapp.dto.user.request.UserCreateRequest;
import com.group.libraryapp.dto.user.response.UserResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class UserController {
    // Instance 생성
    private final List<User> users = new ArrayList<>();

    @PostMapping("/user") // 1. POST /user가 실행되면
    public void saveUser(@RequestBody UserCreateRequest request) { // 2. 함수 실행. json 형식으로 HTTP Body에 name과 age가 들어오면 DTO로 값이 매핑
        users.add(new User(request.getName(), request.getAge())); // 3. 유저 생성. 만들어진 유저 객체는 Users 리스트에 저장된다.
    } // 4. 200 OK 반환

    @GetMapping("/user")
    public List<UserResponse> getUsers() { // UserResponse 반환
        List<UserResponse> responses = new ArrayList<>(); // 빈 UserResponse 리스트 생성
        for (int i = 0; i < users.size(); i++) {
            responses.add(new UserResponse(i + 1, users.get(i))); // 우리가 갖고 있는 List<User> users를 userResponse로 변환
        }
        return responses;
    }
}

 

  • 현재 API의 문제점

서버 재시작하면 데이터 사라짐

유저 정보가 메모리에서만 유지되고 있기 때문