Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions keyword/chaptor09/keyword.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#

## Spring Data JPA의 Paging

Spring Data JPA는 데이터 조회 결과를 효율적으로 관리하기 위해 **Paging**(페이징) 기능을 제공합니다. 페이징은 대량의 데이터를 페이지 단위로 나누어 클라이언트에 반환하는 기술로, **Page**와 **Slice**라는 두 가지 주요 개념이 있습니다.

### Page

Page는 페이징의 전체 정보를 포함하는 데이터 구조입니다. 페이징 처리 시 요청된 페이지의 데이터뿐만 아니라, **전체 페이지 수**, **전체 데이터 수** 등의 메타데이터를 포함합니다.

**특징**
* 요청한 페이지의 데이터 목록과 함께 페이징 정보를 포함.
* Page 객체는 데이터 외에 추가적인 페이징 정보도 함께 반환합니다.
* 데이터 총 개수를 알아야 하므로 COUNT **쿼리를 추가 실행**합니다.

**Page 인터페이스 주요 메서드**
* `List<T> getContent()`: 현재 페이지에 포함된 데이터.
* `int getNumber()`: 현재 페이지 번호 (0-based).
* `int getSize()`: 요청된 페이지 크기.
* `int getTotalPages()`: 전체 페이지 수.
* `long getTotalElements()`: 전체 데이터 개수.
* `boolean isFirst()`: 첫 번째 페이지 여부.
* `boolean isLast()`: 마지막 페이지 여부.
* `boolean hasNext()`: 다음 페이지가 있는지 여부.
* `boolean hasPrevious()`: 이전 페이지가 있는지 여부.

**사용예제**
```java
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

Pageable pageable = PageRequest.of(0, 10); // 첫 번째 페이지(0), 페이지 크기 10
Page<Member> members = memberRepository.findAll(pageable);

System.out.println("Total Elements: " + members.getTotalElements()); // 전체 데이터 개수
System.out.println("Total Pages: " + members.getTotalPages()); // 전체 페이지 수
System.out.println("Current Page: " + members.getNumber()); // 현재 페이지 번호
System.out.println("Page Size: " + members.getSize()); // 페이지 크기

List<Member> content = members.getContent(); // 현재 페이지 데이터

```
해당 데이터들을 클라이언트에게 전달해주면 됩니다. 필요한 데이터만 뽑아서 주는 것이 깔끔할 것이라고 생각은 합니다. 핵심은 Spring Data JPA가 위의 기능들을 제공해준다는 것입니다.


### Slice

Slice는 Page와 유사하지만, **전체 페이지 수나 데이터 총 개수를 계산하지 않는** 데이터 구조입니다. 필요한 데이터만 조회하여 클라이언트에 반환하므로, 성능이 중요한 경우 유리합니다.

**특징**
* 현재 페이지와 다음 페이지의 존재 여부 정보만 제공.
* COUNT **쿼리를 실행하지 않아** 성능이 더 우수.
* 전체 데이터 수나 전체 페이지 수는 알 수 없음.
* **무한 스크롤**이나 **다음 페이지 요청**이 필요한 상황에서 사용.

**Slice 인터페이스 주요 메서드**
* List<T> getContent(): 현재 페이지에 포함된 데이터.
* int getNumber(): 현재 페이지 번호 (0-based).
* int getSize(): 요청된 페이지 크기.
* boolean isFirst(): 첫 번째 페이지 여부.
* boolean hasNext(): 다음 페이지가 있는지 여부.

```java
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;

Pageable pageable = PageRequest.of(0, 10); // 첫 번째 페이지(0), 페이지 크기 10
Slice<Member> members = memberRepository.findAllByStatus("ACTIVE", pageable);

System.out.println("Current Page: " + members.getNumber()); // 현재 페이지 번호
System.out.println("Page Size: " + members.getSize()); // 페이지 크기
System.out.println("Has Next: " + members.hasNext()); // 다음 페이지 여부

List<Member> content = members.getContent(); // 현재 페이지 데이터

```

| **특징** | **Page** | **Slice** |
|----------------------|------------------------------------|-------------------------------------|
| **전체 데이터 수** | 제공 (`getTotalElements()`) | 제공하지 않음 |
| **전체 페이지 수** | 제공 (`getTotalPages()`) | 제공하지 않음 |
| **성능** | 상대적으로 느림 (`COUNT` 필요) | 상대적으로 빠름 (`COUNT` 필요 없음) |
| **사용 상황** | 일반적인 페이징 | 무한 스크롤, 간단한 페이지 네비게이션 |


**Page vs Slice**
* Page는 **전체 데이터 정보**를 제공하며 일반적인 페이징에 적합.
* Slice는 **성능 최적화**와 무한 스크롤에 적합.


---
## 객체 그래프 탐색

**객체 그래프 탐색**은 JPA에서 엔티티 간의 연관 관계를 탐색하며 데이터를 가져오는 작업을 의미합니다. JPA에서는 @OneToOne, @OneToMany, @ManyToOne, @ManyToMany 등의 연관 관계 매핑을 통해 객체 간 관계를 설정합니다.

### 객체 그래프 탐색 전략

**즉시 로딩 (Eager Loading)**
- 연관된 엔티티를 **즉시 로드**.
- 연관된 엔티티를 **JOIN 쿼리**로 한 번에 가져옴.
* 사용: @OneToOne, @ManyToOne 기본값.

```java
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "member_id")
private Member member;

```

**장점**
* 연관 데이터를 미리 가져와서 지연 로딩 문제 해결

**단점**
* 불필요한 데이터를 미리 가져오면 성능 저하 가능
* 쿼리가 예측하기 힘들어짐


**지연 로딩 (Lazy Loading)**
* 연관된 엔티티를 **실제 사용하는 시점**에 로드.
* 기본값: @OneToMany, @ManyToMany.

```java
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
private List<Order> orders;

```

**장점**
* 필요한 데이터를 사용할 때만 가져옴.
* 메모리 및 성능 효율성.

⠀**단점**
* 실제 데이터 접근 시 추가 쿼리 발생.

**N+1 문제**
* 즉시 로딩 시 **연관된 데이터의 개수만큼 추가적인 SELECT 쿼리가 발생**.

```sql
SELECT * FROM member;
SELECT * FROM orders WHERE member_id = 1;
SELECT * FROM orders WHERE member_id = 2;

```


해결 방법

**Fetch Join**
```java
@Query("SELECT m FROM Member m JOIN FETCH m.orders")
List<Member> findAllWithOrders();
```

**EntityGraph**
```java
@EntityGraph(attributePaths = {"orders"})
List<Member> findAllWithOrders();
```


85 changes: 85 additions & 0 deletions keyword/chaptor10/keyword.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

### 1. Spring Security
인증(Authentication)과 인가(Authorization)을 제공하기 위한 강력하고 확장 가능한 보안 프레임워크

- 인증(Authentication) : 사용자 확인
- 인가(Authorization) : 인증된 사용자의 접근 권한 확인
- 보호 : CSRF 방어, 세션 고정 공격 방어, HTTP 응답 헤더 설정 등을 통해 어플리케이션 보호

**Servlet Filter** 체인을 활용하여 보안 처리를 수행하는 것이 특징. 따라서 이는 요청(Request)와 응답(Response)을 가로채고 필요한 인증 및 인가 로직을 처리하기에 적합하다.

Spring Security는 Servlet Filter를 기반으로 동작하며, 필터 체인(Filter Chain)을 사용해 요청과 응답을 가로채고 보안 로직을 적용한다.

**Spring Security의 주요 필터 체인**

- **SecurityContextPersistenceFilter**
* SecurityContext를 생성하거나 복원하여 요청에 적용.
* 요청 완료 후 컨텍스트를 저장.
- **UsernamePasswordAuthenticationFilter**
* 사용자의 자격 증명을 처리 (기본적으로 폼 기반 로그인 처리).
- **BasicAuthenticationFilter**
* HTTP Basic 인증을 처리
- **AnonymousAuthenticationFilter**
* 인증되지 않은 사용자에게 익명 권한을 부여
- **FilterSecurityInterceptor**
* 인가(Authorization) 결정을 수행.
* AccessDecisionManager를 호출하여 요청한 리소스에 대한 권한을 확인.


----

### 2. 인증(Authentication)
사용자의 신원을 확인하는 과정.

**Spring Security 주요 개념**
- Authentication 객체
- 사용자의 인증 상태를 나타낸다.
- SecurityContext에 저장되어 애플리케이션 전역에서 사용된다.
- 주요 필드
- Principal : 인증된 사용자 정보 (UserDetails)
- Credential : 사용자의 인증 자격 증명 (ex. 비밀번호)
- Authorities : 사용자가 가진 권한 목록
- SecurityContext
- 요청의 보안 정보를 저장하는 컨텍스트
- SecurityContextHolder를 통해 접근 가능하다.
- AuthenticationManager
- 인증 로직을 처리하는 인터페이스
- 일반적으로 ProviderManager가 구현체
- 여러 AuthenticationProvider를 위임받아 인증을 수행



**인증 흐름**
- 사용자가 애플리케이션에 요청을 보냄 (로그인 폼, API 요청 등).
- UsernamePasswordAuthenticationFilter
- 요청의 인증 정보를 파싱하여 Authentication 객체를 생성.
- 이 객체를 AuthenticationManager에 전달.
- AuthenticationManager는 여러 AuthenticationProvider 중 적합한 것을 선택하여 인증을 수행.
- AuthenticationProvider
- 데이터베이스, LDAP, OAuth 등 인증 방식을 구현.
- 사용자가 제공한 자격 증명(Credentials)과 저장된 정보 비교.
- 인증
* 성공 시 Authentication 객체를 생성하여 SecurityContext에 저장.
* 실패 시 예외를 던지로 실패 처리 로직으로 이동


---
### 3. 인가(Authorization)
**Authorization**은 사용자가 특정 리소스에 접근할 수 있는 권한이 있는지 확인하는 과정.

**주요 개념**
* **GrantedAuthority**
* 사용자의 권한을 나타내는 인터페이스.
* 일반적으로 ROLE_USER, ROLE_ADMIN 등과 같은 역할(Role)을 정의.
- **AccessDecisionManager**
- 인가 여부를 판단하는 핵심 컴포넌트.
- AccessDecisionVoter를 사용하여 투표 방식으로 권한을 판단.

**인가 흐름**
- 인증된 사용자가 요청한 리소스를 FilterSecurityInterceptor가 가로챔.
- 요청 URL과 HTTP 메서드에 따라 적용할 보안 정책을 결정 (SecurityConfig에 정의된 설정 참조).
- **AccessDecisionManager**가 호출되어 인가 여부를 판단
- 요청한 리소스에 대한 권한과 사용자의 권한을 비교
- 권한 검사가 성공하면 요청이 처리됨.
- 실패 시, AccessDeniedException이 발생