프로그래머스 웹백엔드 스터디 7기 / 1주차 - Spring Boot 프로젝트 셋업과 유저 API
12 Nov 2020 | Spring 스터디 프로그래머스 웹백엔드프로그래머스 웹백엔드 스터디 7기 활동을 하면서 공부한 내용과 기능 구현시 했던 고민들을 정리한 내용입니다.
Index
- 스터디 1주차
- 느낀점
- 고민했던 점
- 공부한 내용
- 구현한 기능
- References
스터디 1주차
Maven 기반 Spring Boot 프로젝트 생성
느낀점
CRUD 구현은 책보고 많이 따라해봐서 쉬울꺼라 생각했는데 역시나.. 책이나 강의처럼 이미 만들어져있는 코드를 따라 치는 것과, 그런 것없이 혼자 처음부터 구현해 나가는 것은 완전히 다른 차원이었다.
간단한 API 구현임에도 불구하고, 책을 따라 작성했을 때는 생각해보지 못한 고민들로 머릿속이 꽉 채워졌다.
예외처리는 어떻게 하는게 좋을까, 로그는 언제 어떻게 남겨야 할까, API 포멧을 하나로 통일시키는 방법은 없을까? 이 메소드는 static으로 하는게 좋을까? static은 언제/왜 사용하는거지? repository에서 유저 조회시 반환타입을 엔티티로 해야할까 유저 ID로 해야할까? 반환타입에서 Optional의 용도는 뭐지?..
코드를 잘 짜고 싶었다. 이왕이면 가독성도 좋게. 하나 둘 생각하다보니 생각보다 전혀 쉽지가 않았다. 봤던 부분 또 보고 다른 스터디원이 작성한 코드도 참조해보고. 힘들긴 했지만, 아직도 부족해보이지만, 그래도 스프링을 공부하면서 깊은 고민을 해볼 수 있는 기회였기에 만족스러웠다. 무엇보다 코드리뷰와 다른 분들의 구현 방법을 다양하게 접해볼 수 있어서 좋았다.
고민했던 점
-
Builder 패턴이 익숙지 않아 어떻게 코드에 녹여야 할지 고민이었다. 생성자와의 차이점을 이해하는데 시간이 좀 걸렸었다.
-
모든 API Response가 동일한 format을 갖도록 통일시키고 싶었다.
=> 고민 끝에, API 레벨에서 공통된 DTO로 랩핑해주는 클래스를 추가했고, static 메소드를 이용했다. 그리고 에러코드를 한 곳에서 관리할 수 있도록 ErrorCode 클래스를 만들었다.
=> 추가로 많은 블로그에서 ResponseEntity로 응답해주는 곳이 많아 ReponseEntity 사용이 필수인가 싶었는데, 필수가 아님을 알았다. -
Entity에서 DTO로 변환을 어디서 해줘야 할지 고민이었다. 서비스에서? 컨트롤러에서?
=> Controller에서. DTO란 말 그대로 Layer간 데이터를 넘기기 위한 목적이며, 외부 시스템에 의존적인 객체이다.
=> 서비스에서는 도메인 클래스를 반환한다. 서비스는 내부 서비스에서 서로 호출할 수도 있고, 컨트롤러가 여러 서비스를 호출에서 외부에 내보내기 위한 또 다른 객체를 만들 수도 있기 때문이다. -
예외처리를 어떻게 해줘야하지?
=> 각 레이어(controller, service, repository)마다 역할이 있다. 그 역할에 맞게 레이어별로 예외처리를 해줘야 했다. -
테스트 코드를 어떻게 어디까지 짜야하지
=> 테스트 코드 종류와 미션에 해당되는 컨트롤러 테스트와 mock 나중에 좀더 공부해봐야겠다.
공부한 내용
-
Spring 주요 개념
- Spring 뭔가요?
- 프로젝트이다. 다양한 프로젝트들로 구성되어 있는데 그중 우린 Spring Framework, Spring Security, Spring Boot 프로젝트를 사용할 것이다.
- Spring Framework은 다양한 모듈(기능)들을 제공하며, 주요 기술들이 카테고리화되어 있다. 각 카테고리 안에는 관련 모듈들로 구성된다.
- IoC/DI/컨테이너/빈 개념
- 토비 스프링에 있는 책을 기반으로 설명하셨다. 토비 스프링 책 vol1 을 개념서로 강추천해주셨는데, 추후 읽고 정리 해봐야겠다.
- IoC란, 자신이 사용할 객체의 모든 권한을 외부로 위임하는 것. 본인 조차 언제 호출될지, 어떤 객체가 전달될지 알 수 없고, 런타임때 의존 객체가 전달된다. 변경의 유연성 위해 코드상에서는 인터페이스로만 느슨하게 연결한다.
- 스프링 없이도 IoC 기능을 직접 만들 수 있다. 단지 스프링을 사용하면 좀 더 많은 기능을 제공해줄 뿐이다. ex. 객체가 만들어지기 전에 무언가를 한다던가, 만들어졌을 때 특정 이벤트를 듣는다던가, 단 한번만 만들어지도록 싱글톤 형식을 유지 등
- 스프링은 BeanFactory와 ApplicationContext(Bean Factory 서브타입)로 IoC 기능의 컨테이너를 제공한다.
- DI란, 객체를 생성할 때 필요한 의존들을 외부로부터 전달 받는 것. 의존 관계 주입 또한 스프링 없이도 구현할 수 있다.
- 정리한 포스트
- Spring 뭔가요?
-
Spring Boot?
-
스프링 애플리케이션을 빠르게 개발하고 시작하는데 도움을 주는 프로젝트. 필요한 환경 설정을 최소화해서 개발자가 비즈니스 로직에 집중할 수 있도록 도와줌
- 임베디드 톰켓, 언더토우를 사용해 독립 실행이 가능한 스프링 애플리케이션 개발
- J2EE(Java platform, Enterprise Edition)으로 웹 개발시 톰캣, 언더토우 같은 서블릿 컨테이너를 설치하고, 프로젝트 내 필요한 환경을 구성해야했음
- 자동 환경 설정(Auto Configuration) - @Conditional
- properties, yaml, command line 등을 이용한 쉬운 외부 환경 설정
- JAR을 사용해 자바 옵션만으로 배포(실행) 가능
- 등등
- 임베디드 톰켓, 언더토우를 사용해 독립 실행이 가능한 스프링 애플리케이션 개발
-
Spring Boot Starter
- POM(Project Objct Model, 프로젝트 구조와 사용할 라이브러리 등의 내용을 설명하는 설정 파일) 프로젝트로 주요 의존성 집합체
- 빌드에 필요한 의존성 자동으로 관리해주기 때문에 일일이 어떤 라이브러리가 필요한지 찾아볼 필요 x
- 스터터 명명 규칙: spring-boot-starter-*
- 웹 관련 프로젝트 스타트명: spring-boot-starter-web
-
- Maven 프로젝트 직접 세팅
- 유저 등록 / 조회 기능 API
- Builder 패턴 이용
- DTO/VO/DAO 개념
- JDBC Template으로 H2 Database 접근
- Rest API란
- 그런 REST API로 괜찮은가
- REST API Tutorial
- 리소스 기반 URI 표현
- HTTP verbs로 리소스 접근 / 조작
- HATEOAS(하이퍼미디어, 링크)를 지원해서 리소스에 연결된 다른 리소스로 접근 가능
- Hypermedia: 이미지, 영상, 텍스트 같이 서로 다른 형태의 미디어간의 연결
- 예외처리
- Controller 테스트 코드 작성
- @WebMvcTest이용
- Mock 객체를 이용해 실제 DB를 사용하지 않고 메모리상에서 처리되도록 구현
- API 테스트는 Postman 2 이용
구현한 기능
- Spring Boot 프로젝트 생성
- IDE는 IntelliJ 활용
- Spring Boot 버전 설정 (2.3.5)
- https://start.spring.io/ 활용
- Maven 정보
- groupId: com.github.prgrms, artifactId: social-server, packaging: jar
- Dependency: Web, Jdbc, H2 Database
- User Entity 관련 기능 만들기
- [API 1] 유저 목록을 조회된다.
- [API 2] ID로 유저 정보를 조회한다.
- [API 3] 유저를 저장한다.
- 요청과 응답을 DTO로 만든다.
- HTTP 요청을 처리하는 컨트롤러 테스트 작성
- 해당 컨트롤러에서 사용하는 서비스는 Mock 서비스로서 실제 DB를 사용하지 않고 메모리 상에서 처리가 되도록 구현한다.
- 컨트롤러가 이 서비스를 테스트 환경에서만 사용할 수 있게 한다.
CREATE TABLE users {
seq bigint NOT NULL AUTO_INCREMENT,
email varchar(50) NOT NULL,
passwd varchar(80) NOT NULL,
login_count int NOT NULL DEFAULT 0,
last_login_at datetime DEFAULT NULL,
create_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP(),
PRIMARY KEY (seq),
CONSTRAINT unq_user_email UNIQUE (email)
}
API 상세 설명
번호 | 설명 | 요청 | 응답 |
---|---|---|---|
1 | 유저 목록을 조회한다. | HTTP GET api/users | User 정보를 JSON 형태로 목록을 반환한다. |
H2 DB에서 읽는다. | |||
2 | ID로 유저 정보를 조회한다. | HTTP GET api/users/:userId | User 정보를 JSON 형태로 반환한다. |
H2 DB에서 읽는다. | |||
3 | 유저를 저장한다. | POST api/users/join | JSON 형태로 principal과 credentials를 입력받는다. |
{ "principal" : "이메일", "credentials" : "패스워드" } |
References
- 초보 웹 개발자를 위한 스프링 5 프로그래밍 입문
- 토비의 스프링 3.1
- 처음 배우는 스프링 부트 2