[인프런 워밍업 클럽 스터디] BE 1기 첫번째 발자국
Section 1. 생애 최초 API 만들기
1. 스프링 부트 프로젝트를 설정해 시작하고 실행하는 방법
만들어져 있는 스프링 프로젝트를 다운로드 받아 IntelliJ를 통해 여는 경우: INntelliJ 실행 후 첫 화면의 Open을 통해 가져온다.
메인 함수가 있는 클래스 옆에 있는 초록색 세모 버튼을 눌러 Run을 선택하면 실행된다.
아무것도 없는 상태에서 새로 스프링 프로젝트를 시작하는 경우:
https://start.spring.io/에 접속해 요소를 각각 설정해 준다.
Project: 빌드 툴을 고르는 항목
Language: 서버 개발 시 사용할 언어
Spring Boot: 스프링 부트의 버전. 옆에 알파벳이 붙지 않은, 가장 최신 버전을 고르는 게 좋다.
Project Metadata: 프로젝트에 사용될 다양한 이름을 설정하는 항목. Java의 버전은 11이 가장 많이 사용된다.
Dependencies: 프로젝트에서 사용하는 라이브러리(*미리 만들어져 있는 기능을 가져다 사용하는 것)이나 프레임워크(*프로그래밍 개발 시 미리 만들어져 있는 구조에 코드를 가져다 끼워 넣는 것)
위와 같은 설정을 마치고 Generate를 통해 프로젝트를 만들면 압축 파일이 다운로드 되고, 그 후의 과정은 '만들어져 있는 스프링 프로젝트를 다운로드 받아 IntelliJ를 통해 여는 경우'와 동일하다.
2. 서버 개발에 필요한 다양한 개념
서버: 어떠한 기능을 제공하는 프로그램. 그 프로그램을 실행시키고 있는 컴퓨터
네트워크: 인터넷을 통해 데이터를 주고 받게 하는 시스템
HTTP: 웹을 통한 컴퓨터 간의 통신에 대한 표준화된 방식
HTTP 요청: HTTP Method(GET, POST)와 Path(/portion)이 핵심이며, 요청에서 데이터를 전달하기 위한 방법은 쿼리와 바디이다.
HTTP 응답: 상태 코드
API: 클라이언트와 서버는 HTTP를 주고 받으며 기능을 동작하고, 이때 정해진 규칙이다.
3. 스프링 부트를 이용한 GET API / POST API 개발
API Specification(명세): API를 개발하기 전에 API의 HTTP method, HTTP path, 쿼리와 바디, API의 반환 결과를 결정해야 한다.
GET API
쿼리로 들어오는 값의 개수가 많아진다면? 즉
@RequestParam
이 많아지면 코드가 길어지고, 실수의 여지가 생기므로 쿼리를 받는 Class를 만든다.DTO(Data Transfer Object) 객체: '쿼리'를 서버 안 Controller로 전달하는 역할
POST API
쿼리를 사용하지 않고 바디(Body)를 사용한다.
Json: 바디에 데이터를 담아주는 방식
{
"name": "최태현",
"age": 99
}
POST API의 경우에는 Body를 통해 데이터가 들어오기 때문에 @ReqestBody를 꼭 사용해주어야 한다.
HTPP Body는 @ReqestBody를 통해 DTO에 매핑되고, Controller로 들어가 최종 결과를 반환한다.
유저 생성 & 조회 API 개발
유저 조회 시 필요한 JSON으로 결과 반환하기: Controller에서 그냥 객체를 반환하면, JSON으로 응답이 간다. 이때 객체에는 getter가 있어야 한다.
Section 2. 생애 Database 조작하기
디스크와 메모리의 차이, Database의 필요성
컴퓨터의 핵심 부품 세 가지: CPY는 연산담당, DISK는 장기기록, RAM(메모리)는 단기기억의 역할을 수행한다.
서버를 실행시켜 API를 동작시키는 과정
스프링부트 서버가 DISK에 파일로 존재한다.
서버를 실행하면 DISK의 코드 정보가 RAM으로 복사된다.
API가 실행되면 연산이 수행되고, CPU와 RAM을 왔다 갔다 한다.
(ex) POST API를 통해 생긴 유저 정보는 RAM에 쓰여 있다.
서버가 종료되면 RAM에 있는 모든 정보가 사라지므로 재시작하면 유저 정보가 없는 것.
DISK에 정보를 저장하기 위해 DB를 사용하는 것.
MySQL Database를 SQL과 함께 조작하기
DDL(Data Definition Language): 데이터를 정의하는 SQL
DB
create database [데이터베이스 이름];
show databases;
drop database [데이터베이스 이름];
use [데이터베이스 이름];
테이블
create table [테이블 이름] (
[필드1 이름] [타입] [부가조건],
[필드 2 이름] [타입] [부가조건],
...
primary key ([필드 이름])
);
show tables;
drop table [테이블 이름];
DML(Data Manipulation Language): 데이터를 조작하기 위한 SQL
CRUD
Create(생성): 데이터를 넣는다
Retrieve or Read(읽기): 조회한다
Update(업데이트): 수정한다
Delete(제거): 삭제한다
# 데이터 넣기
INSERT INTO [테이블 이름] (필드1이름, 필드2이름, ...) VALUES (값1, 값2, ...)
# 데이터 조회하기
SELECT * FROM [테이블 이름] WHERE [조건];
# 데이터 업데이트하기
UPDATE [테이블 이름] SET 필드1이름=값1, 필드2이름=값2, ... WHERE [조건];
# 데이터 삭제하기
DELETE FROM [테이블 이름] WHERE [조건];
스프링 서버를 이용해 Database에 접근하고 데이터를 저장, 조회, 업데이트, 삭제하기
스프링 서버와 DB 연결:
application.yml
파일을 생성해 스프링 서버와 연결할 DB 정보를 설정한다.DB를 통해 데이터를 저장, 조회하기
POST API를 DB를 이용하게 변경하기 (Controller)
jdbcTemplate을 이용해 MySQL에 SQL을 보낸다.
"INSERT INTO user(name, age) VALUES(?, ?)";
와 같이 값이 들어가야 하는 부분에는 ?를 사용한다.jdbcTemplate.update(sql, request.getName(), request.getAge());
jdbcTemplate.update
는 INSERT, UPDATE, DELETE 쿼리에 사용 가능첫 파라미터는 sql, ?를 대신할 값을 차례로 넣어줌
GET API를 DB를 이용하게 변경하기 (Controller)
jdbcTemplate.query(sql, RowMapper 구현 익명클래스)
: query를 사용하면 SELECT 쿼리를 날릴 수 있다.@Override
함수: ResultSet 객체에는 결과가 담겨있고, 이 객체에getType("필드이름")
을 사용해서 실제 값을 가져온다.람다를 이용해 더 간결한 코드 작성도 가능하다.
UPDATE API, DELETE API 예외 처리: 대상이 없으면
IllegalArgumentException
과 같은 표준 예외를 throw해야한다.기본적인 코드 구조: 유저(대상)이 있는지 id나 name을 통해 확인한다→ 유저 데이터가 있다면 비어 있지 않은 리스트를 받아오고, 유저 데이터가 없다면 비어있는 리스트가 반환된다.→ if문으로 검사해서 유저가 존재하지 않으면
IllegalArgumentException
을 던진다.
Section 3. 역할의 분리와 스프링 컨테이너
좋은 코드(Clean Code)의 중요성
코드를 작성하는 시간보다 읽는 시간이 훨씬 많다는 점을 고려해야 한다. 팀으로 협업하는 환경에서는 다른 사람이 작성한 코드를 읽어야 할 때도 있고, 내가 오래 전에 작성한 코드를 읽을 때도 있다. 코드를 읽어야만 맥락을 이해하고 기존 코드를 수정하거나 새로운 코드를 추가할 수 있다.
클린코드를 읽으면 쉽게 코드를 읽고 이해할 수 있기에 중요한 것.
기존의 Controller 코드에서는 한 개의 API가 너무 많은 역할을 수행하고 있다.
API의 진입 지점으로써 HTTP Body를 객체로 변환
현재 유저가 있는지, 없는지 등을 확인하고 예외 처리
SQL을 사용해 실제 DB와의 통신 담당
기존 Controller에서 하고 있는 역할을 분리하기(리팩토링)
UserService 클래스: 현재 유저가 있는지 없는지 등을 확인하고 예외 처리하는 역할을 부여한다.
UserRepository 클래스: DB에 SQL을 날리는 역할, 저장장치와의 접근을 담당한다.
Layered Architecture: 각 클래스가 각자의 역할을 가지고 겹겹이 쌓인 것
UserRepository 클래스 자체가 JdbcTemplate를 갖도록 해서 파라미터를 통해 매번 넘겨주지 않아도 되게 한다.
<1주차 학습 내용 회고>
진도표에 따라 강의 수강이 이루어지고 있다는 점은 스스로에게 수고했다고 말하고 싶다. 사실 1일차 과제부터 제시간에 제출하지 못했기에 (아직도..) 해결하는 대로 velog와 발자국도 수정할 예정이다.
DB는 전공 수업에서 다뤘던 이후로 오랜만에 해 본 건데 API와 연결하는 부분이 아직 손에 익지 않아서 연습을 더 해봐야겠다.
Java의 경우도 학교 수업에서 배웠던 거랑 다르게 조금 더 응용된 걸 많이 사용하고 있어서 새롭게 느껴진다.
<미션>
과제1
2주차 발자국 작성 전까지 추가 예정
GET API와 POST API를 직접 작성해 보는 실습
LocalDate.parse를 이용해서 String을 DayOfWeek로 변환했다. LocalDate가 제공하는 메소드를 이용해 요일을 출력했다.
리스트의 합을 구하는 것에 시간이 많이 소요되었는데, Controller에서 Request 클래스에서 return 받은 리스트 객체를 이용해 합을 구할 수 있었다.
강의를 보며 그대로 따라하는 것보다 직접 해보려니 더 어렵게 느껴졌던 과제였다. 그래도 직접 적용해 보면서 이해도가 올라가고 있음이 느껴졌다.
익명 클래스, 람다 모두 프로그램/코드를 간결하게 한다. 특히 람다는 기존의 메서드 선언에 꼭 필요한 부분이 아닌 것은 생략할 수 있어서 클린하게만 코드를 작성한다면 추후에도 이용하기 좋은 방법 같았다.
이외에도 코드의 가독성을 높일 수 있는 여러가지 방법을 공부했는데, 지금까지는 왠지 복잡하고 오히려 에러가 나면 디버깅 하는 것이 귀찮아 잘 쓰지 않았던 것들이었다. 앞으로는 열린 마음으로 스트림 API, 함수형 인터페이스 같은 것들을 사용해 보며 익숙해져야겠다.
평소라면 강의 수강을 하면서도 더 알아보거나 공부할 생각을 안 했을텐데, 미션이라는 의무가 부여되었기에 조금 더 능동적으로 공부할 수 있던 일주일이었다. 미션 수행이 조금씩 밀리고 있는데 다음 주는 놓치는 미션 없이 모두 성공해 보겠다.
댓글을 작성해보세요.