백엔드 맛보기

이준석·2025년 11월 26일

Web_Development_Basics

목록 보기
12/14

프론트엔드 맛보기에서 가짜 서버(Mock server)로 맛보기를 했다.

문제는 Postman으로 API 사용법과 실제 화면이 어떻게 연동 되는지 확인했으나, Mock server는 가짜 Postman에서는 가짜 응답이기에 실제 데이터 변동이 없었다

추가(POST) 해도 세팅한 값만 오는 문제
-> 새로고침 하면 리셋됨 = 가짜 서버라 저장된 데이터 변화 X

학습 목표

백엔드 프레임워크를 경험해본다.

  • 2-3 API에서 진행한 코드를 이용해 백엔드 Spring 프레임워크를 진행해보자

Postman과 서버 연동을 실습해본다.

  • Spring 프레임워크로 만든 '진짜' Service에 연결을 해보자

이론

백엔드 프레임워크를 경험해본다.

  • 백엔드 프레임워크백엔드 서버를 만드는 아주 잘 갖추어진 밀키트 또는 로봇이다.
  • 프론트엔드 프레임워크(주 : 컴포넌트)는 처음부터 만들기 어려우니, 이름바 밀키트를 사용해 쉽게 변형하여 사용했다.
  • 순수 자바로 들기 = 맨손으로 주방 만들기(순수 Java 등)
    (클라이언트의 요청 : GET, POST ... 등을 하나하나 직접 받고, 구분하고, 처리하고, 다시 포장하여 응답하는 건 힘들다.)
  • 백엔드 프레임워크를 사용해보자.(주방(서버) 만들기, Spring 사용)
    (API 요청을 받을 수 있는 가스레인지, 오븐, 조리대, 주문서(요청) 접수 시스템이 모두 완비된 최신식 주방 보유)
    -> 이걸로 요청받으면, 도구(기능)를 사용하여 요리(비즈니스 로직) 출력한다.

핵심 역할 : 계층형(레이어드) 아키택쳐

각 계층인 컨트롤러 - 서비스 - 레포지토리가 계층을 이루어 손님이 요청한 음식을 요리하고 다시 손님에게 전달할 때까지 과정을 수행한다.

'주방 매니저' - Controller (컨트롤러)

  • '손님(클라이언트)'요청(Request)POST /items 이나 GET /items 과 같은 'API 엔드포인트가 도착하는 진입점'이자, 요리한 음식(데이터)을 다시 손님에게 응답(Response) 하기 위한 출발점 역할을 한다.
  • 손님의 요청이 유효한지 검사한다.
  • 실제 일은 서비스 에게 시키고, 자신은 주문 받기/서빙 하기만 한다.

'메인 셰프' - Service (서비스)

  • '실제 비즈니스 로직'을 담당합니다.
  • 비즈니스 로직 이란?
    → 비즈니스(현실 세계의 업무)를 처리하기 위한 규칙과 절차를 의미합니다.
    (e.g. 손님이 주문한 요리를 한다. )
  • 리포지토리(저장소, DB와 통신함(꺼내줘, 저장해))에게 ‘데이터 저장/조회’를 시킵니다.

'음식' - Entity (엔터티)

  • 서비스가 처리하는 상품(서버 자원) 을 의미합니다.
  • 손님이 주문한 음식 자체 입니다.
    (일종의 라벨링. 고기 : 언제 만들어졌고, 어떤 고기이고(돼지, 소, 닭 등) 이런거)

'저장소' - Repository (리포지토리)

  • 오직 '데이터베이스'와 통신하는 역할만 집니다.
    (=냉장고)
  • 서비스가 "상품 줘"라고 하면, DB에서 상품을 꺼내줍니다.
  • 서비스가 "상품 저장해"라고 하면, DB에 상품을 저장합니다.

계층형 아키택쳐의 장점 : 코드 어플리케이션 레밸

  • 이 구조의 최대 장점은 부품 교체 입니다. 저장소(Repository)를 메모리에서 데이터베이스로 바꿔도 주방 매니저(Controller)와 메인 셰프(Service)는 코드를 한 줄도 바꿀 필요가 없습니다!
    - 레밸 설정이 중요하다.
    예) 컴퓨터 - 노트북 : 같은 레밸
    다른 레밸이면 서로 혼용 불가
    하드웨어 레밸 : 서버, 스위치, 데스크탑 ... 어떤 걸
    • 레파지토리를 바꿔도 컨트롤러나 서비스가 변화 없듯, 서비스나 컨트롤러를 바꿔도 나머지 변동 사항이 없다. 같은 레밸끼리만 교환하면 된다.

백엔드 프레임워크의 종류

Spring - Java

  • 정부 표준 프레임워크로 지정될 만큼 안전성과 신뢰도가 높다.
  • 생태계가 크다 = 오류가 많이 발견했다 = 이미 해결됐다.

Node.js - JavaScript

  • 노드는 프레임워크보단 환경에 가깝다. 프론트엔드와 동일한 JavaScript 사용함
    -> 프레임워크는 노드 환경에서 돌아가는 Express나 Nest.js 같은 것들임
    -> 빠른 속도와 실시간 처리가 빠르며 상대적으로 빠른 개발 속도 빠릅니다.

Django / Flask - Python

파이썬 : GOAT
문법이 간결하고 개발 속도가 빠르다.
인스타그램이 Django임


Java와 Spring 설치

Java는 그냥 시중에 돌아다니는 17버전 ㄱㄱ
1.
스프링 프로젝트 파일 다운로드
위 링크로 들어가서 초록색의 Code 버튼을 누르고 Download ZIP 버튼을 눌러 압축된 프로젝트를 다운로드합니다.
위 링크는 GitHub 로, 개발자들이 프로젝트를 올리고 공유하는 허브입니다!

  1. https://github.com/live-commerce-platform/web-basic-backend
    에서 Code -> Downroad ZIP -> 설치

파일 탐색기가 열리면, 방금 압축을 푼 폴더 (예: wishlist-backend-main)를 선택하고 OK를 누릅니다.
IntelliJ가 "Trust and Open Project?"라고 물으면 Trust Project 버튼을 눌러 프로젝트를 신뢰합니다.
IntelliJ가 프로젝트를 불러온 후, 오른쪽 하단에서 Gradle이 프로젝트를 동기화하고 의존성(라이브러리)을 다운로드하는 것을 기다려야 합니다. (1~3분 정도 소요될 수 있습니다.)


3-2

wishlist_backend에 대한 구조

wishlist/
└── src/main/java/com/sparta/wishlist/
├── controller/ # 🤵 API 진입점
│ └── ItemController.java

├── service/ # 🧑‍🍳 비즈니스 로직 (핵심 요리)
│ ├── ItemService.java
│ └── ItemServiceImpl.java

├── repository/ # 🧊 데이터 저장소
│ ├── ItemRepository.java
│ ├── InMemoryItemRepository.java
│ └── DatabaseItemRepository.java

├── dto/ # 📝 데이터 전송 객체
│ ├── ItemRequestDto.java
│ └── ItemResponseDto.java

├── entity/ # 🍱 서버 자원
│ └── Item.java

├── exception/ # ⚠️ 예외 처리
│ ├── CustomException.java
│ ├── ErrorCode.java
│ ├── ErrorResponse.java
│ └── GlobalExceptionHandler.java

├── config/ # ⚙️ 설정
│ └── DatabaseConfig.java

└── WishlistApplication.java # 🚀 서버 실행 파일

외울 필요는 없음

src/main/java/com/sparta/wishlist/ : 프로젝트의 '진짜' Java 코드가 위치하는 소스(source) 폴더입니다. React의 src/와 같습니다.
controller/ : '주방 매니저'의 영역입니다. API 명세서처럼 클라이언트의 HTTP 요청(GET, POST 등)을 가장 먼저 받는 진입점(Endpoint)입니다.
ItemController.java : "주방 매니저"입니다. 주문서(DTO)를 검사하고, 실제 요리는 ItemService에게 시킵니다.

service/ : 🧑‍🍳 '메인 셰프'의 영역입니다. "상품을 수정하기 전에 존재하는지 확인하라"와 같은 핵심 비즈니스 로직을 담당합니다.
ItemService.java : '메인 셰프'가 지켜야 할 '규칙'(인터페이스)입니다. "저장하기", "조회하기" 기능이 있어야 함을 정의합니다.
ItemServiceImpl.java : '메인 셰프'의 '실제 행동'(구현체)입니다. ItemRepository를 호출하여 실제 로직을 수행합니다.

repository/ : 🧊 '저장소 관리인'의 영역입니다. 오직 데이터베이스와의 통신만 책임집니다.
ItemRepository.java : '저장소'가 지켜야 할 '규칙'(인터페이스)입니다. "데이터베이스에서 저장", "데이터베이스에서 조회" 기능 등을 정의합니다.
InMemoryItemRepository.java : '임시 저장소'(구현체)입니다. @Profile("memory")이 붙여주어, '메모리'라는 서버가 종료되면 휘발되는 저장소에서 작동합니다.
DatabaseItemRepository.java : '진짜 저장소'(구현체)입니다. @Profile("database")가 붙여주어, ' 데이터베이스'라는 저장소에 영구 관리되도록 작동합니다.

dto/ : Controller와 Service가 데이터를 주고받을 때 사용하는 전용 양식(DTO)입니다.
ItemRequestDto.java : 클라이언트로부터 받는 '주문서'(요청 DTO)입니다.
ItemResponseDto.java : 클라이언트에게 돌려줄 '영수증'(응답 DTO)입니다.

entity/ : 🍱 '서버 자원'를 정의하는 곳입니다.
Item.java : '상품'이란 무엇인가? (id, name, price...)를 정의하는 핵심 데이터 객체입니다. Repository가 데이터베이스와 통신할 때 이 객체를 사용합니다.

exception/ : ⚠️ '안전 관리자' 영역입니다. 앱 전체에서 발생하는 모든 에러를 관리합니다.
GlobalExceptionHandler.java : "상품을 찾을 수 없습니다(404)", "입력값이 비어있습니다(400)" 같은 예외가 발생하면, 이 '안전 관리자'가 모두 잡아채서 클라이언트에게 ErrorResponse.java 양식으로 응답합니다.

config/ : ⚙️ 프로젝트의 '설정' 파일이 모여있습니다.
DatabaseConfig.java : '데이터베이스'를 사용하기 위한 초기 연결 설정을 담당합니다.
WishlistApplication.java : 🚀 서버를 켰다 껐다 하는 '메인 전원' 스위치입니다. 이 파일을 실행(Run)하면 localhost:8080에서 서버가 시작됩니다.

src/main/resources/ : Java 코드가 아닌, 프로젝트의 '설정'이나 '자원' 파일이 모여있는 곳입니다.
application.properties : "지금 '임시 저장소'(memomory)를 쓸까, '진짜 저장소'(database)를 쓸까?"를 정하는 설정 스위치가 있는 파일입니다.
firebase-service-account.json : '데이터베이스'에 들어갈 수 있는 '보안 키(Key)'입니다.

정리

  1. Spring 서버는 Controller를 통해서 요청이 들어온다.

  2. 여기서 들어온 요청을 Service단에서 처리해준다.

  3. Service단에서 처리한 비즈니스 로직에 대해서 조회(GET)하거나 저장하거나 수정(PUT)할 것이 있다면 Repository(일종의 냉장고. 부르고, 저장함)를 호출해서 DB와 직접 전송/통신해서 정보를 바꿔준다. 그 정보를 다시 Controller에 돌려준다.

  4. 이 과정에서 dto는 각 계층 간의 데이터가 오고 깔 때, 그 사이의 데이터를 저장하는 역할을 한다.

  5. entity는 repository. 즉 데이터 저장소에 데이터를 어떤 식으로 저장해줄지에 대한 재료의 명세표라고 보면 된다.

  6. exception는 일종의 예외 처리이다.(관리자 영역)
    - 기본적으로 처리되는 것도 있고

    • 우리가 직접 예외에 대해 수정해서 사용할 수 있다.
      (=커스텀, CustomExceptionHandler.java)
      - global : 전역에서 발생한 예외를 어떻게 처리할지 판단
      (ExceptionHandler.java)
    • 예외가 발생했을 때, 어떻게 돌려줄지 (ErrorResponse.java)
    • 예외가 발생했을 때, 어떤 코드로 돌려줄지
      (ErrorCode.java )
  7. config는 말 그대로 설정
    새로운 기술 설정 파일을 추가하면 여기에 추가해야 함

  8. WishlistApplication.Java는 Main 파일이라 생각하면 된다. 이걸 실행해야 나머지 것들이 실행되는 것이다.

Spring 서버의 데이터 흐름 훑어보기

폴더가 controller, service, repository, dto, entity 등으로 나뉘어 복잡해 보이지만, 데이터가 흐르는 길(순서)은 명확하다.

Postman으로 POST /items에 ‘새우깡’ JSON을 보내는 순간의 흐름을 '식당' 비유로 간략하게 따라가 봅시다.

1. -> [Request] 주문 접수 from (홀)

Request 들어올 때, Response 대답할 때, API를 관리해주는 것 = Contoller

Contoller을 거치지 않고서는 Client가 Service나 Repository에 접근할 방법이 없다.

  • Client (손님): POST /items로 ‘새우깡’ JSON을 담아 요청(주문)합니다.
  • Controller (매니저): 주문을 받고, 주문서(ItemRequestDto)가 문제 없는지 검사합니다.
  • Controller: "셰프님, 이 '주문서(DTO)'대로 처리해주세요"라고 Service에게 넘깁니다.

2. [Processing] 요리 (주방)

  • Service (셰프): ‘주문서(DTO)’를 "주방에서 쓸 상품(Entity)"로 변환합니다.
  • Service: "저장소에 이 '상품(Entity)'대로 저장해주세요"라고 Repository를 호출합니다.
  • Repository (저장소): "저장소에 ‘상품(Entity)’을 저장하고, id가 발급된 최종본을 Service에게 돌려줍니다.

3. <- [Response] 서빙 to (홀)

  • Service (셰프): 저장된 "상품(Entity)"을 "손님용 영수증(ItemResponseDto)"으로 다시 변환합니다.
  • Controller (매니저): "영수증(DTO)"과 "주문 성공(201 Created)"했다는 상태로 손님(Client)에게 응답합니다.

이처럼 각자 역할이 명확히 분리되어 있어, 만약 셰프(Service)가 요리 레시피를 변경해 내용을 바꾸더라도, 주방 매니저(Controller)는 변경된 레시피에 대해서 몰라도 주문을 받고 음식을 서빙할 수 있습니다.

각자 역할이 명확히 분리되어 있기 때문에 한 역할이 변경사항이 생겨도 다른 역할은 건드릴 필요가 없어진다는 특징을 가집니다.


실습

프론트엔드는 가짜 서버를 만들었다면
이번에는 진짜 서버를 만들어서 Postman으로 테스트를 할 것이다.
1. ../src/main/java/com.sparta.wishlist/controller/itemController.java

실행하면 빨간 줄이 4개 보임
-> 각 기능을 보고, 어떤 기능인지 파악해보자
1-1. 새 찜 상품 생성 => POST
: PostMapping("/items") = 이 앤드포인트(주소, /items)로 들어오는 Post 요청에 대해 매핑을 해준다. 이 다음에 있는 매서드들이 관리를 할거다.

1-2. 전체 찜 상품 조회 => GET

!!!같은 엔드포인트("/items")라도 매서드가 다르면(@Post ~, @Get ~) 다르게 인식한다.!!!

PostMapping와 GetMapping 모두 /items란 동일한 앤드포인트를 갖고 있음에도 매서드에 따라 다르게 인식한다.

1-5. 찜 상품 단건 조회 => GET
1-3. 기존 찜 상품 수정 => PUT
1-4. 찜 상품 삭제 => DELETE

매서드 설명

@PostMapping("/items")
public ResponseEntity saveItem(@Valid @RequestBody ItemRequestDto dto) throws ExecutionException, InterruptedException
{
ItemResponseDto responseDto = itemService.saveItem(dto);
return ResponseEntity.status(HttpStatus.CREATED).body(responseDto);
}

  1. PostMapping 매서드에 /items 앤드포인트를 받으면 ResponseEntity의 ItemResponseDto 를 담은 형태로 리턴해줄거야. 그리고 이 아이템의 이름은 saveItem으로 할거야

  2. ItemResponseDto : web-basic-backend-main\src\main\java\com\sparta\wishlist\dto의 ItemRequestDto.java를 열면

    이다. 여기에는 price, category, description, link, image가 포함될거다.

    추가로, 해당 코드에서 @NotBlank, @Min은 saveItem()의 @Valid라는 annotation과 관련이 있다.(이건 나중에)

    추가로2, saveItem(@Valid @RequestBody ItemRequestDto dto)에서 dto는 ItemRequestDto에서 실제로 구현된 것이 dto라는 뜻이다.

    이 dto는 그 아래에 있는 ItemResponseDto responseDto = itemService.saveItem(dto);이다.

  • Controller로 들어온 것은 Service로 들어갈거니까
    -> ItemResponseDto responseDto = itemService.saveItem(dto);에itemService로 데이터를 보내줄 것이다. 어디로? itemService의 saveItem()라는 매소드로
  • ResponseEntity :
  1. savaItem의 body는 ItemRequestDto의 형식으로 dto를 하면 좋겠다.
    saveItem(@Valid @RequestBody ItemRequestDto dto) 중...
    -> ItemRequestDto

  2. ItemResponseDto responseDto = itemService.saveItem(dto);은 이 매소드의 결과값을 ItemResponseDto에 저장한다는 의미이다.

  • 그래서 saveItem에 Ctrl + 클릭하면 해당 위치로 이동됨
  1. saveItem 설명

    saveItem은 ItemRequestDto가 들어오면 발동해서 ItemResponseDto로 리턴 할 것이다. 라는 의미.

  • 이미지 우측 하단 확인 : port가 8080이고, 해당 프로그램이 3.446초만에 실행됐다 출력

백엔드에서 서버에
Postman에서 Mock server URL로 작성한 것을

WishlistApplication을 실행 시 localhost:8080으로 출력된 것으로 주소를 바꾼다
(mock server URL -> https://localhost:8080)

실제로 적용 됐는지 확인해보자
0. GET 실행(찜 목록 조회) -> 없음

여기에 추가해보자
1. POST 실행 -> 출력 : id=1
2. GET 실행(찜 목록 조회) id=1 -> 출력
3. DELETE 실행 -> 없음
4. GET 실행(찜 목록 조회) -> 없음
결과 : 실제 데이터에 영향을 준다.

추가로 더 해보자
5. POST 실행 -> 출력 : id=2
-> id가 2인 것은 1번이 삭제됐으니, 별다른 설정없이 실행하면 그 다음부터 숫자가 추가된다.
6. GET 실행('단건' 목록 조회) id=1 -> 출력 : 해당 상품 없음
-> 이전 가짜 응답이면 그냥 출력 됐음
7. GET 실행('단건' 목록 조회) id=2 -> 출력 : 5번에서 추가한 것이 뜸

PutMapping에서도 마찬가지임
8. PUT 실행(찜 상품 수정) id=1 -> 출력 : 해당 상품 없음
9. PUT 실행(찜 상품 수정) id=2 -> 출력 : 2번에 해당하는 내용이 수정됨(기계식 키보드, 12만원 -> 기계식 키보드 v2, 13.5만원)

포트 번호 바꾸고 싶다면

web-basic-backend-main\src\main\resources\application.properties에서 바꾸면 된다.

3-2에서는 application.properties의 memory에서 돌아가고 있었음
!!! 메모리 위에서만 저장되기에 임시 저장이다.
인텔리제이를 껐다가 다시 키면 데이터가 없다.


이제 임시 저장이 아니라 데이터 저장이 필요하다.

따라서 데이터 베이스 연동이 필요한데, 이걸 3-3 DB에서 하는거고

3-4. 프론트엔드의 찜목록과 백엔드의 찜목록을 둘 다 연동하여 하나의 서비스인 웹 프로젝트를 만들어 볼 수 있다.

profile
공부 정리방

0개의 댓글