✏️ 0516
Spring 입문 2주차 강의
수준별 학습: 스탠다드-이론반 OT
Spring 개인 과제 (1~ 5단계)
Spring 입문_2주차
1주차 내용 적은 것 같다고 했던 과거의 나...반성해라
머리털 뽑히는 줄 알았네
3 Layer Architecture
: 서버 처리 과정을 크게 Controller, Service, Repository 3개로 분리
Controller
- 클라이언트의 요청을 받습니다.
- 요청에 대한 로직 처리는 Service에게 전담
- Service에서 처리 완료된 결과를 클라이언트에게 응답
Service
- 사용자의 요구사항을 처리 ('비즈니스 로직') 하는 실세 중에 실세
- DB 저장 및 조회가 필요할 때는 Repository에게 요청
Repository
- DB 관리 (연결, 해제, 자원 관리)
- DB CRUD 작업을 처리
IoC(제어의 역전), DI(의존성 주입)
IoC, DI는 객체지향의 SOLID 원칙 그리고 GoF 의 디자인 패턴과 같은 설계 원칙 및 디자인 패턴
DI 패턴을 통해서 IoC 설계 원칙을 이루어낸 것
DI라는 디자인 패턴을 통해서 IoC라는 설계 원칙을 지킨것
- 좋은 코드를 위한 Spring의 IoC와 DI
- 논리 간단
- 중복 제거, 표현 명확
- 처음 보는 사람도 쉽게 이해 & 수정 가능
- 의존성 최고화
- 새로운 기능 추가 시 구조 변경 X
- ....
의존성 (DI)
DI 를 사용하기 위해서는 객체 생성이 우선
다리가 다쳐서 목발을 사용하기 된다면 걸을 때 목발에 의존하고 있는 것과 같은 것!
강하게 결합되어 되어있는 코드를 Interface 를 활용해서 해결이 가능하다
Interface 다향성의 원리 사용
=> 약한 결합 및 약한 의존성
public class Consumer {
void eat(Food food) {
food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat(new Chicken());
}
}
interface Food {
void eat();
}
class Chicken implements Food{
@Override
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
class Pizza implements Food{
@Override
public void eat() {
System.out.println("피자를 먹는다.");
}
}
주입
=> 여러 방법을 통해 필요로 하는 객체를 해당 객체에 전달하는 것
public class Consumer {
// 필드에 직접 주입
Food food;
void eat() {
this.food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.food = new Chicken();
consumer.eat();
// set 메서드 주입
consumer.setFood(new Pizza());
consumer.eat();
}
}
// 이하 동일
public class Consumer {
Food food;
// 생성자
public Consumer(Food food) {
this.food = food;
}
void eat() {
this.food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer(new Chicken());
consumer.eat();
}
}
Food 를 Consumer 에 포함 시키고 Food 에 필요한 객체를 주입받아 사용하는 것
필드에 직접 주입, set 메서드를 통해 주입, 생성자를 통한 주입
다양한 방식으로 필요한 객체를 주입받아 사용할 수 있다
제어의 역전 (IoC)
위의 코드를 기반으로 설명하면 Consumer 가 직접 Food 를 만들어 먹었기 때문에
새로운 Food 를 만들려면 추가적인 요리준비(코드변경) 이 필요했다
제어의 흐름 => Consumer → Food
주입을 통해 Food 를 Consumer 에게 전달해주는 식으로 변경함으로써
Consumer 는 추가적인 요리준비(코드변경)없이 어느 Food 가 되었든 전부 먹을 수 있게 되었다
제어의 흐름 => Food → Consumer
JPA (ORM)
- DB 를 직접 다룰 때의 문제점
- 직접 DB로 접속해서 SQL 호출
- 애플리케이션에서 SQL 작성 => SQL 직접 수정 필요
- JDBC 를 사용해서 직접 실행
- SQL 결과를 객체로 직접 변환
새 필드 값이 추가가 되면 관련된 모든 코드들의 수정이 필요하고 작업이 굉장히 많아진다
ORM 이 없는 환경에서는 백엔드 개발자가 비즈니스 로직 개발보다,
SQL 작성 및 수정에 더 많은 노력을 들여야 했다
ORM ( Object-Relational Mapping )
객체와 DB의 관계를 매핑 해주는 도구
Objec : 객체
Relational : 관계형
반복적이고 번거로운 애플리케이션 단에서의 SQL 작업을 줄여주기 위한 기술
자바의 클래스와 DB 의 데이터를 직접 매핑하기 위한 코드 변경 작업을
ORM 을 사용하면 자동으로 처리해준다
@Entity // JPA가 관리할 수 있는 Entity 클래스 지정
@Getter
@Setter
@Table(name = "memo") // 매핑할 테이블의 이름을 지정
@NoArgsConstructor
public class Memo extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false)
private String username;
@Column(name = "contents", nullable = false, length = 500)
private String contents;
}
public interface MemoRepository extends JpaRepository<Memo, Long> {
List<Memo> findAllByOrderByModifiedAtDesc();
List<Memo> findAllByContentsContainsOrderByModifiedAtDesc(String keyword);
}
- 장점
- 객체지향적인 코드로 인해 더 직관적이고 로직에 집중 가능
- 재사용 및 유지보수의 편리성 증가
- 코드의 가독성 향상
- DBMS 에 대한 종속성 감소
- 단점
- 대량의 데이터를 처리하는 경우 성능 문제가 발생할 가능성
- 완벽한 ORM 으로만 서비스를 구현하기 어려움
- 사용하기는 편하지만 설계는 매우 신중하게
- 프로젝트의 복잡성이 커질 경우 난이도 또한 올라갈 수 있다
Entity
Entity
JPA 에서 관리되는 클래스
즉, 객체를 의미
Entity 클래스는 DB의 테이블과 매핑되어 JPA 에 의해 관리
@Entity // JPA가 관리할 수 있는 Entity 클래스 지정 (name = "memo") <= 지정할 클래스 이름도 설정가능
@Table(name = "memo") // 매핑할 테이블의 이름을 지정
public class Memo {
@Id // 테이블의 기본키 (PK)
// @GeneratedValue(strategy = GenerationType.IDENTITY) // auto increment 설정
private Long id;
// 필드의 이름과 테이블 컬럼의 이름을 매핑시켜준다
// 기본적으로 필드의 이름이 디폴트가 된다
// nullable: null 허용 여부 (false 일때 null 불가 / true 일때 null 허용)
// unique: 중복 허용 여부 (false 일때 중복 허용 / true 일때 중복 불가)
@Column(name = "username", nullable = false, unique = true)
private String username;
// length: 컬럼 길이 지정
@Column(name = "contents", nullable = false, length = 500)
private String contents;
}
- @Entity : JPA가 관리할 수 있는 Entity 클래스로 지정
- name = "Memo" : Entity 클래스 이름 지정
- JPA가 Entity 클래스를 인스턴스화 할 때 기본 생성자를 사용하기 때문에
반드시 현재 Entity 클래스에서 기본 생성자가 생성되고 있는지 확인
- @Table : 매핑할 테이블을 지정
- name = "memo" : 매핑할 테이블의 이름을 지정 ( default: Entity 명 )
- @Column : 필드의 이름과 테이블 컬럼의 이름을 매핑
- name = "username" : 필드와 매핑할 테이블의 컬럼 지정
- nullable = false : 데이터의 null 값 허용 여부 지정
- unique = true : 데이터의 중복 값 허용 여부 지정
- length = 500 : 데이터 값(문자)의 길이에 제약조건 ( default: 255 )
- @Id : 테이블의 기본 키를 지정
- 영속성 컨텍스트에서 Entity를 구분하고 관리할 때 사용되는 식별자 역할 수행
- 기본 키 즉, 식별자 값을 넣어주지 않고 저장하면 오류 발생
- @Id 옵션만 설정하면 기본 키 값을 개발자가 직접 확인하고 넣어줘야 하는 불편함 발생
- @GeneratedValue : 옵션을 추가하면 기본 키 생성을 DB에 위임 가능
- (strategy = GenerationType.IDENTITY)
- id bigint not null auto_increment : auto_increment 조건이 추가된 것
- 해당 옵션을 추가해주면 개발자가 직접 id 값을 넣어주지 않아도 자동으로 순서에 맞게 기본 키 추가
개인과제 (1~5단계)
죽...여...줘......
시작 전 확인할 것
- git init
- build.gradle 파일 (의존성)
- application.properties 파일
초반에 제대로 되는지 확인 안하고 실행하니까 어디서부터 꼬여있는지 모르겠어서 그냥 리셋시켰다
꼭 무언갈 추가하면 이상이 없는지 run 해서 잘 작동하는지 확인하기
(근데 대부분 오타였다)
예전에 스프링 배웠을 때도 코드가 점점 길어지면 길어질수록
어디서 잘못됐는지 확인하는 것에 시간이 오래 걸리기 때문에 되도록 자주 확인하는 것이 좋은 것 같다...
'개발 일지 > TIL' 카테고리의 다른 글
[ #24 ] TIL (2) | 2024.05.20 |
---|---|
[ #23 ] TIL (3) | 2024.05.19 |
[ #21 ] TIL (2) | 2024.05.14 |
[ #20 ] TIL (4) | 2024.05.13 |
[ #19 ] TIL (2) | 2024.05.10 |