계층 돌아보기
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F026aa827-67bf-4a64-ae2a-7f7a700a3acb%2F1466f2b0-1c7a-483b-beb6-4c868873a518%2FUntitled.png?table=block&id=58e3ba2e-d8d6-4562-a935-a1b1fcdb0da2&cache=v2)
- Domain Model: 도메인 데이터와 비즈니스 로직을 포함
- 도메인: 객체의 속성들이 가질 수 있는 값들의 집합
- 비즈니스 로직이란?
- 프로그램에서 규칙에 따라 데이터를 생성·표시·저장·변경하는 부분
- Repository: DB와 상호 작용하여 Domain model 객체를 메모리에 띄운다.
- Dto: Client - Controller - Service 사이의 약속된 데이터 교환 형식
- Service: 외부에서 요청하는 비즈니스 로직을 처리하고 도메인 모델 객체 간의 상호 작용을 통제
- Controller: HTTP 요청을 받아와 Service 계층에 전달하고 응답을 처리
백엔드는 뭘 하는가?
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F026aa827-67bf-4a64-ae2a-7f7a700a3acb%2Fc4965cc0-9194-4b52-b8b4-65d8a7fa7eb6%2FUntitled.png?table=block&id=d9d7b381-1d6a-490a-bf75-b1f8d204c729&cache=v2)
- 클라이언트(유저)의 요청이 Web Server를 통해 인터넷 상에 전송되어, 목적지인 백엔드에 도착
- 어떤 요청인데요? (예시: 인스타그램)
- 회원가입?
- 보낸 회원가입 폼이 유효한가?
- 로그인?
- 유저의 로그인 요청이 정상적인가?
- 게시글 업로드(저장)?
- 누가 어떤 게시물을 언제 업로드하는가?
- 게시글 수정?
- 어떤 게시글을 수정하지?
- 수정을 요청하는 사람이 작성자가 맞는가?
- 게시글 삭제?
- 어떤 게시글을 삭제하지?
- 삭제를 요청하는 사람이 작성자가 맞는가?
- 댓글?
- 좋아요?
- 다시 클라이언트는 요청을 처리한 백엔드의 응답을 받아 관련된 사안을 처리
- 백엔드는 클라이언트의 요청을 받아 유효성 검사 등을 거친 뒤 요청을 처리하고 적절한 형식의 응답을 전송
퀴즈: 색깔에 관련된 계층 및 객체 맞히기
- 클라이언트의 요청을 받아
- Controller, RequestDto
- 유효성 검사 등을 거친 뒤
- Service, RequestDto, Repository
- 요청을 처리하고
- Service, Repository, Domain
- 적절한 형식의
- ResponseDto, Domain
- 응답을 전송
- ResponseDto, Controller
ORM이란?
- Object-Relational Mapping (객체-관계 매핑)
- Java 객체와 RDB 테이블을 서로 매핑해주는 일종의 중재자
- 다른 진영에도 ORM은 존재(JavaScript 등)
JDBC란?
- Java Database Connectivity
- Java 기반 애플리케이션의 데이터를 DB에 저장 및 수정하거나, 저장된 데이터를 Java에서 사용할 수 있도록 하는 자바 API
- Java 애플리케이션에서 데이터베이스에 접근하기 위해 JDBC API를 사용하여 데이터베이스에 연동
- 애플리케이션 쪽에서 DB에 존재하는 데이터에 쿼리를 가할 수 있음
JPA란?
- Java Persistence API
- Java 진영의 ORM 기술 표준
- 인터페이스이며, 따라서 실제 구현체가 아니다.
- JPA 인터페이스를 구현한 대표적인 오픈소스가 Hibernate
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F026aa827-67bf-4a64-ae2a-7f7a700a3acb%2Fd4fb7008-8c68-42a4-9401-5dcbbe24ecf6%2FUntitled.png?table=block&id=7fe2bfec-88cb-4330-bf86-a9f21f94ea79&cache=v2)
- 개발자가 애플리케이션에서 JPA API를 호출하면, 해당하는 구현체(Hibernate 등) 내부에서 JDBC API를 호출하여 DB에 소통한다.
- 예) 찾고 싶은 User 객체의 id(Long)를 서버에서 전송하여 특정 User의 정보를 조회하는 경우
- 객체(Entity)의 정보를 바탕으로 JPA API를 호출
- 내부에서 JDBC API가 호출되어 쿼리를 DB에 날림
- DB가 쿼리 결과 데이터를 JDBC API에 응답으로 전달
- 받은 결과 데이터를 JPA가 객체에 매핑하여 User 객체를 Java 애플리케이션에 띄운다.
- → userRepository.findById(Long userId);
JPA 왜 쓰나요?
- 직접적인 SQL 쿼리 작성을 피하고 “객체” 중심으로 복잡한 문제를 풀어나갈 수 있다.
- 어떤 앱이든 기초적이면서도 핵심적인 기능을 공통적으로 갖고 있기 때문
- 특정 테이블의 정보 조회 → select * from ?? where ….
- 반복되는 단조로운 쿼리 작성→ 개발자 자체의 휴먼 에러 발생 가능
- 그냥 repository.findBy로 한줄로 찾는게 정신건강에 이롭다.
- 다만 쿼리를 아예 작성할 필요가 없는 것은 아니다.
- RDB와 객체 간의 괴리감을 ORM의 중재로 극복
- Java의 객체 상속 개념과 RDB 테이블의 SuperType/SubType은 상당한 괴리가 존재함
- JPA의 테이블 간 관계 매핑 기능을 활용하여, 개발자는 객체간의 관계에만 초점을 맞출 수 있음
- 개발자가 Java 클래스 상에 추가하는 객체 사이의 크고 작은 관계들을 JPA가 유효성 검사 후 테이블에 이행
- JPA 자체에서 제공하는 수많은 편의 기능들
- 어노테이션을 기반으로 한 깔끔하고 직관적인 관계 설정
- mySQL에서 show columns from tables;
- 지연로딩(LAZY) 및 Cascade, orphanRemoval 등 디테일한 객체 및 테이블 상태 관리
- 그 외
- SQL Injection 등의 외부 공격을 ORM 레벨에서 기초적으로 방어 가능
그냥 모두가 하니까?
Springboot에서 mySQL 데이터베이스 연동
- MacOS 기준
- mySQL 설치 (brew install mysql)
- mysql -u root -p 명령어 실행
- 비밀번호 입력 란 등장, 최초로 설치한 경우 비밀번호가 없기에 바로 Enter
- 만약 이미 mySQL이 있고 인증 계정과 비밀번호를 등록해놓은 경우 입력해야 함
- create database “이름”; 으로 데이터베이스 생성
application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect // Hibernate 설정 spring.jpa.show-sql=true // 서버에서 발생하는 쿼리를 로그에 드러낸다. spring.jpa.properties.hibernate.format_sql=true // 나타날 쿼리를 일정한 형식으로 출력 spring.datasource.url=jdbc:mysql://localhost:3306/[만든 DB명]?useSSL=false&serverTimezone=UTC spring.datasource.username=[이름] -> 최초 실행해서 계정이 없는 경우 root spring.datasource.password=[비번] -> 최초 실행해서 계정이 없는 경우 생략 spring.jpa.hibernate.ddl-auto=create // JPA로 DB 접근 시 테이블을 다 깨뜨리고 처음부터 다시 생성
편집 테스트 한 번 해볼게요.. 이거 보이시나요? 보이시면 당근을 흔들어주세요.
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-jdbc' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok'
- 이제 application.properties에 mySQL 설정이 사라지면, JPA가 DB를 찾지 못해 서버가 빌드되지 않는다.
- 근데 프로젝트에선 SQL 링크가 민감한 정보가 될 텐데, 은닉할 수는 없나요?
- User 객체를 domain 패키지에 추가하고 빌드하여 DB에 생성 (구체적인 내용은 추후 다룰 예정)
@Entity public class User { @Id @Column(name = "user_id") private Long id; private String name; // 닉네임 private int height; // 키 private int weight; // 몸무게 private int gender; // 성별 (0, 1) private int age; public User(String name, int height, int weight, int gender, int age) { this.name = name; this.height = height; this.weight = weight; this.gender = gender; this.age = age; } }
계층 돌아보기
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F026aa827-67bf-4a64-ae2a-7f7a700a3acb%2F1466f2b0-1c7a-483b-beb6-4c868873a518%2FUntitled.png?table=block&id=4b0c82c1-f21e-4cca-8bfc-3559f1bb899f&cache=v2)
- Domain Model: 도메인 데이터와 비즈니스 로직을 포함
- 도메인: 객체의 속성들이 가질 수 있는 값들의 집합
- 비즈니스 로직이란?
- 프로그램에서 규칙에 따라 데이터를 생성·표시·저장·변경하는 부분
- Repository: DB와 상호 작용하여 Domain model 객체를 메모리에 띄운다.
- Dto: Client - Controller - Service 사이의 약속된 데이터 교환 형식
- Service: 외부에서 요청하는 비즈니스 로직을 처리하고 도메인 모델 객체 간의 상호 작용을 통제
- Controller: HTTP 요청을 받아와 Service 계층에 전달하고 응답을 처리
백엔드는 뭘 하는가?
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F026aa827-67bf-4a64-ae2a-7f7a700a3acb%2Fc4965cc0-9194-4b52-b8b4-65d8a7fa7eb6%2FUntitled.png?table=block&id=209e7524-f195-477a-a405-92f101ebb38a&cache=v2)
- 클라이언트(유저)의 요청이 Web Server를 통해 인터넷 상에 전송되어, 목적지인 백엔드에 도착
- 어떤 요청인데요? (예시: 인스타그램)
- 회원가입?
- 보낸 회원가입 폼이 유효한가?
- 로그인?
- 유저의 로그인 요청이 정상적인가?
- 게시글 업로드(저장)?
- 누가 어떤 게시물을 언제 업로드하는가?
- 게시글 수정?
- 어떤 게시글을 수정하지?
- 수정을 요청하는 사람이 작성자가 맞는가?
- 게시글 삭제?
- 어떤 게시글을 삭제하지?
- 삭제를 요청하는 사람이 작성자가 맞는가?
- 댓글?
- 좋아요?
- 다시 클라이언트는 요청을 처리한 백엔드의 응답을 받아 관련된 사안을 처리
- 백엔드는 클라이언트의 요청을 받아 유효성 검사 등을 거친 뒤 요청을 처리하고 적절한 형식의 응답을 전송
퀴즈: 색깔에 관련된 계층 및 객체 맞히기
- 클라이언트의 요청을 받아
- controller, requestdto
- 유효성 검사 등을 거친 뒤
- service, dto, repository
- 요청을 처리하고
- Service,
- 적절한 형식의
- responsedto
- 응답을 전송
- dto,
ORM이란?
- Object-Relational Mapping (객체-관계 매핑)
- Java 객체와 RDB 테이블을 서로 매핑해주는 일종의 중재자
- 다른 진영에도 ORM은 존재(JavaScript 등)
JDBC란?
- Java Database Connectivity
- Java 기반 애플리케이션의 데이터를 DB에 저장 및 수정하거나, 저장된 데이터를 Java에서 사용할 수 있도록 하는 자바 API
- Java 애플리케이션에서 데이터베이스에 접근하기 위해 JDBC API를 사용하여 데이터베이스에 연동
- 애플리케이션 쪽에서 DB에 존재하는 데이터에 쿼리를 가할 수 있음
JPA란?
- Java Persistence API
- Java 진영의 ORM 기술 표준
- 인터페이스이며, 따라서 실제 구현체가 아니다.
- JPA 인터페이스를 구현한 대표적인 오픈소스가 Hibernate
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F026aa827-67bf-4a64-ae2a-7f7a700a3acb%2Fd4fb7008-8c68-42a4-9401-5dcbbe24ecf6%2FUntitled.png?table=block&id=fec1f006-53de-468f-baba-06792b86f8c1&cache=v2)
- 개발자가 애플리케이션에서 JPA API를 호출하면, 해당하는 구현체(Hibernate 등) 내부에서 JDBC API를 호출하여 DB에 소통한다.
- 예) 찾고 싶은 User 객체의 id(Long)를 서버에서 전송하여 특정 User의 정보를 조회하는 경우
- 객체(Entity)의 정보를 바탕으로 JPA API를 호출
- 내부에서 JDBC API가 호출되어 쿼리를 DB에 날림
- DB가 쿼리 결과 데이터를 JDBC API에 응답으로 전달
- 받은 결과 데이터를 JPA가 객체에 매핑하여 User 객체를 Java 애플리케이션에 띄운다.
- → userRepository.findById(Long userId);
JPA 왜 쓰나요?
- 직접적인 SQL 쿼리 작성을 피하고 “객체” 중심으로 복잡한 문제를 풀어나갈 수 있다.
- 어떤 앱이든 기초적이면서도 핵심적인 기능을 공통적으로 갖고 있기 때문
- 특정 테이블의 정보 조회 → select * from ?? where ….
- 반복되는 단조로운 쿼리 작성→ 개발자 자체의 휴먼 에러 발생 회치
- 그냥 repository.findBy로 한줄로 찾는게 정신건강에 이롭다.
- 다만 쿼리를 아예 작성할 필요가 없는 것은 아니다.
- RDB와 객체 간의 괴리감을 ORM의 중재로 극복
- Java의 객체 상속 개념과 RDB 테이블의 SuperType/SubType은 상당한 괴리가 존재함
- JPA의 테이블 간 관계 매핑 기능을 활용하여, 개발자는 객체간의 관계에만 초점을 맞출 수 있음
- 개발자가 Java 클래스 상에 추가하는 객체 사이의 크고 작은 관계들을 JPA가 유효성 검사 후 테이블에 이행
- JPA 자체에서 제공하는 수많은 편의 기능들
- 어노테이션을 기반으로 한 깔끔하고 직관적인 관계 설정
- mySQL에서 show columns from tables;
- 지연로딩(LAZY) 및 Cascade, orphanRemoval 등 디테일한 객체 및 테이블 상태 관리
- 그 외
- SQL Injection 등의 외부 공격을 ORM 레벨에서 기초적으로 방어 가능
그냥 모두가 하니까?
Springboot에서 mySQL 데이터베이스 연동
- MacOS 기준
- mySQL 설치 (brew install mysql)
- mysql -u root -p 명령어 실행
- 비밀번호 입력 란 등장, 최초로 설치한 경우 비밀번호가 없기에 바로 Enter
- 만약 이미 mySQL이 있고 인증 계정과 비밀번호를 등록해놓은 경우 입력해야 함
- create database “이름”; 으로 데이터베이스 생성
application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect // Hibernate 설정 spring.jpa.show-sql=true // 서버에서 발생하는 쿼리를 로그에 드러낸다. spring.jpa.properties.hibernate.format_sql=true // 나타날 쿼리를 일정한 형식으로 출력 spring.datasource.url=jdbc:mysql://localhost:3306/[만든 DB명]?useSSL=false&serverTimezone=UTC spring.datasource.username=[이름] -> 최초 실행해서 계정이 없는 경우 root spring.datasource.password=[비번] -> 최초 실행해서 계정이 없는 경우 생략 spring.jpa.hibernate.ddl-auto=create // JPA로 DB 접근 시 테이블을 다 깨뜨리고 처음부터 다시 생성
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-jdbc' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok'
- 이제 application.properties에 mySQL 설정이 사라지면, JPA가 DB를 찾지 못해 서버가 빌드되지 않는다.
- 근데 프로젝트에선 SQL 링크가 민감한 정보가 될 텐데, 은닉할 수는 없나요?
- User 객체를 domain 패키지에 추가하고 빌드하여 DB에 생성 (구체적인 내용은 추후 다룰 예정)
@Entity public class User { @Id @Column(name = "user_id") private Long id; private String name; // 닉네임 private int height; // 키 private int weight; // 몸무게 private int gender; // 성별 (0, 1) private int age; public User(String name, int height, int weight, int gender, int age) { this.name = name; this.height = height; this.weight = weight; this.gender = gender; this.age = age; } }