diff --git a/keyword/chaptor09/keyword.md b/keyword/chaptor09/keyword.md new file mode 100644 index 0000000..1c556eb --- /dev/null +++ b/keyword/chaptor09/keyword.md @@ -0,0 +1,164 @@ +# + +## Spring Data JPA의 Paging + +Spring Data JPA는 데이터 조회 결과를 효율적으로 관리하기 위해 **Paging**(페이징) 기능을 제공합니다. 페이징은 대량의 데이터를 페이지 단위로 나누어 클라이언트에 반환하는 기술로, **Page**와 **Slice**라는 두 가지 주요 개념이 있습니다. + +### Page + +Page는 페이징의 전체 정보를 포함하는 데이터 구조입니다. 페이징 처리 시 요청된 페이지의 데이터뿐만 아니라, **전체 페이지 수**, **전체 데이터 수** 등의 메타데이터를 포함합니다. + +**특징** +* 요청한 페이지의 데이터 목록과 함께 페이징 정보를 포함. +* Page 객체는 데이터 외에 추가적인 페이징 정보도 함께 반환합니다. +* 데이터 총 개수를 알아야 하므로 COUNT **쿼리를 추가 실행**합니다. + +**Page 인터페이스 주요 메서드** +* `List 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 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 content = members.getContent(); // 현재 페이지 데이터 + +``` +⠀ +해당 데이터들을 클라이언트에게 전달해주면 됩니다. 필요한 데이터만 뽑아서 주는 것이 깔끔할 것이라고 생각은 합니다. 핵심은 Spring Data JPA가 위의 기능들을 제공해준다는 것입니다. + + +### Slice + +Slice는 Page와 유사하지만, **전체 페이지 수나 데이터 총 개수를 계산하지 않는** 데이터 구조입니다. 필요한 데이터만 조회하여 클라이언트에 반환하므로, 성능이 중요한 경우 유리합니다. + +**특징** +* 현재 페이지와 다음 페이지의 존재 여부 정보만 제공. +* COUNT **쿼리를 실행하지 않아** 성능이 더 우수. +* 전체 데이터 수나 전체 페이지 수는 알 수 없음. +* **무한 스크롤**이나 **다음 페이지 요청**이 필요한 상황에서 사용. + +**Slice 인터페이스 주요 메서드** +* List 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 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 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 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 findAllWithOrders(); +``` + +**EntityGraph** +```java +@EntityGraph(attributePaths = {"orders"}) +List findAllWithOrders(); +``` + + diff --git a/keyword/chaptor10/keyword.md b/keyword/chaptor10/keyword.md new file mode 100644 index 0000000..3938a6b --- /dev/null +++ b/keyword/chaptor10/keyword.md @@ -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이 발생 +