![[인프런 워밍업 클럽 3기 - BE] 1주차 발자국](https://cdn.inflearn.com/public/files/blogs/8cbcde54-dd18-447c-8221-afeccf5691ba/인프런스터디 썸네일.png)
[인프런 워밍업 클럽 3기 - BE] 1주차 발자국
해당 블로그의 발자국은 정보근님의 입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 강의 기반으로 작성하였습니다.
모르거나 헷갈리는 내용만 정리!
1주차
이론
웹 프레임워크
동적 웹서비스 개발을 편리하게 만들어주는 도구. 웹 개발이 건축이라면, 프레임워크는 건축을 돕는 여러 도구. 프레임워크와 라이브러리를 구분하는 키는 제어의 주도권. 비유해보자면, 프레임워크는 DIY 가구 키트이고 라이브러리는 가구를 만들기 위한 공구들을 모아둔 공구 상자라 할 수 있다. 라이브러리는 사용자가 주도권을 가지고 원하는 것을 만들 수 있다. 프레임워크 안에서도 라이브러리를 사용할 수 있다.
레이어드 아키텍처 (Controller-Service-Repository)
가장 대중적인 소프트웨어 아키텍처. 기능별로 아래와 같은 세가지 계층으로 구분된다.
Presentation (Controller) : 클라이언트가 요청할 수 있는 인터페이스 정의. 전달받은 데이터를 검증해 Service의 메소드 호출
Business (Service) : 목적에 맞게 데이터 처리. 레포지토리의 메소드를 호출해 저장, 수정, 조회, 삭제 수행
Data Access (Repository) : 데이터베이스에 접근해 작업 요청
HTTP 상태 코드
응답에서 요청의 처리 결과를 표현하는 코드
200: OK
201: Created
202: Accepted
300: Multiple Choices
400: Bad Request
401: Unauthorized
403: Forbidden
404: Not Found
405: Method Not Allowed
415: Unsupported Media Type
500: Internal Server Error
502: Bad Gateway
503: Service Unavailable
504: Gateway Timeout
REST API
HTTP 통신으로 동작하는 어플리케이션 기능을 정의하는 일종의 규칙, 컨벤션. HTTP 규약에는 강제성이 없다.
ex) POST /members
클라이언트에서 서버로 데이터를 전달하는 방법
Query Parameter, HTTP Request Body (@RequestBody), Path Variable
JPA란
JPA는 Java Persistence API의 약어로, 자바 ORM 기술의 표준 인터페이스 의미
ORM
Object Relational Mapping의 약어로, 객체 관계 매핑 의미. 객체지향 프로그래밍의 인스턴스와 관계형 데이터베이스를 매핑해주는 기술. 구체적인 DBMS에 대한 의존성이 줄어든다는 장점이 있지만 충분한 학습이 필요하고 모든 기능을 구현하기에 한계가 있다는 단점이 있다.
실습
repository 패키지
스프링에서 리포지토리는 데이터베이스와 직접적으로 상호작용하는 레이어. 데이터베이스에 쿼리를 보내는 리포지토리 레이어를 만들고 서비스 레이어에서 리포지토리 레이어를 참좨 다양한 기능을 개발할 수 있도록 분리
Spring Data JPA를 사용하면 기본적인 리포지토리 개발이 매우 쉽다. 스프링이 실행되면 직접 기본적인 CRUD 코드를 만들어주기 때문. 물론 기본적인 기능 외에도 커스텀 메소드를 정의할 수도 있다.
엔티티 개발 - 연관관계 있을 때 어노테이션
@OneToMany
: 일대다 관계 정의 | 한 엔티티가 여러 다른 엔티티와 관계를 맺는 경우 사용
@ManyToOne
: 다대일 관계 정의 | 여러 엔티티가 한 엔티티와 관계를 맺는 경우 사용
package com.yongback.portfolio.domain.entity
import jakarta.persistence.*
@Entity
class Experience(
title: String,
description: String,
startYear: Int,
startMonth: Int,
endYear: Int?,
endMonth: Int?,
isActive: Boolean
) : BaseEntity() {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "experience_id")
var id: Long? = null
var title: String = title
var description: String = description
var startYear: Int? = startYear
var startMonth: Int? = startMonth
var endYear: Int? = endYear
var endMonth: Int? = endMonth
var isActive: Boolean = isActive
@OneToMany(targetEntity = ExperienceDetail::class, fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
@JoinColumn(name = "experience_id")
var details: MutableList<ExperienceDetail> = mutableListOf()
fun getEndYearMonth(): String {
if (endYear == null || endMonth == null) {
return "Present"
}
return "${endYear}.${endMonth}"
}
fun update(
title: String,
description: String,
startYear: Int,
startMonth: Int,
endYear: Int?,
endMonth: Int?,
isActive: Boolean
) {
this.title = title
this.description = description
this.startYear = startYear
this.startMonth = startMonth
this.endYear = endYear
this.endMonth = endMonth
this.isActive = isActive
}
fun addDetails(details: MutableList<ExperienceDetail>?) {
if (details != null) {
this.details.addAll(details)
}
}
}
Experience는 ExperienceDetail과 1:N의 관계를 가진다. 경력이 하나 있으면 그 경력에 대응하는 상세내용을 여러 개 작성할 수 있는 구조이다. @OneToMany
로 Experience 엔티티가 일대다 관계에서 1에 해당한다고 선언하고 N의 대상은 ExperienceDetail임을 targetEntity 파라미터로 지정해준다. fetch는 데이터를 가져오는 전략을 의미하는데, EAGER는 데이터베이스에서 Experience를 가져오는 동시에 ExperienceDetail을 모두 가져오고 LAZY는 실제로 ExperienceDetail을 호출할 때 데이터베이스에서 가져온다. EAGER는 경우에 따라 성능에 치명적인 영향을 가져올 수 있기 때문에 항상 FetchType을 LAZY로 선언해주는 것이 좋다. cascade는 JPA 영속성 컨텍스트에서 엔티티 상태에 변화가 생겼을 때, 매핑된 엔티티를 어떻게 처리할지를 결정한다.
회고
이번주에는 학교에서 배웠던 내용이 많이 겹쳐서 복습한다는 느낌으로 강의를 수강하였다. 까먹었던 내용들도 강의를 들으면서 상기시킬 수 있었다. Kotlin을 처음 써봐서 아직 어색한데, 익숙해질 수 있도록 다음주까지 많이 연습을 해야 할 것 같다.
미션
이번주 미션은 과제 깃허브 리포지토리를 만들고, 미니 프로젝트를 위한 1:N 테이블을 설계하는 것이다. 내가 기획한 미니 프로젝트는 사용자가 독서 기록을 관리하고, 책을 읽은 후 평점과 리뷰를 남길 수 있는 독서 기록 관리 시스템이다. 배운 개념을 그대로 적용하면 되고, 몇년 전에도 과제로 해봤던 내용이라 크게 어렵지 않았다.