-
Notifications
You must be signed in to change notification settings - Fork 0
[Hyeonu] Week8 미션 #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: Hyeonu
Are you sure you want to change the base?
Changes from all commits
9b52122
077b761
7a988ce
e6eab26
49e76ea
0dbea2d
96d6a9d
f77f6f3
c46a603
35f9829
3f8255e
7f56b9b
2d78e66
ddc4cb2
fec22c2
18d357d
7cd0b0e
ccaab38
860afbf
ffec1bc
b66bd8f
d3b01d6
ad67d1f
7187790
89605d3
f66ee1f
056a363
9cfab48
f229fa8
491abd8
198bb66
1c62e4d
db85075
49e1ebc
8ad5051
27995fa
1ff410e
977dc5c
66ef595
9f09aa6
604c69a
3948ecb
7418d9c
b24996c
0f60053
8f5ca73
a2e4c26
26d28cc
b9c56ce
a8ba722
9833d04
57f8f2b
82021c9
e9dc608
15f7d9f
b527af5
1e404af
f6997a7
4a4abc6
211f883
a49ffa3
2f823ad
5e1ece2
684e89f
b8ddca3
af9280e
2bb127f
e42cd53
6e6f1e7
358e0da
fd05d46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| - Page와 Slice | ||
|
|
||
| **Page 란?** | ||
|
|
||
| Spring Data JPA에서 제공하는 페이지네이션 객체 중 하나로, 전체 페이지 정보까지 포함하는 페이징 방식이다. | ||
|
|
||
| 예를 들어 게시글이 총 100개 있고, 한 페이지에 10개씩 보여준다면 | ||
|
|
||
| - 현재 페이지 번호 | ||
| - 전체 데이터 개수 | ||
| - 전체 페이지 수 | ||
| - 다음 페이지 여부 | ||
|
|
||
| 이런 정보들을 모두 알 수 있다. | ||
|
|
||
| ```java | ||
| Page<Mission> missions=missionRepository.findByStoreId(storeId,pageable); | ||
| ``` | ||
|
|
||
| **장점** | ||
|
|
||
| - 프론트엔드에서 페이지 UI 만들기 편함 ("총 15페이지 중 현재 3페이지”) | ||
| - 전체 데이터 규모 파악 가능 | ||
|
|
||
| **단점** | ||
|
|
||
| - COUNT 쿼리 비용 발생 (데이터가 많아질수록 성능 부담 발생 가능) | ||
| - Offset 기반의 한계 (뒤 페이지로 갈수록 느려질 수 있다. | ||
|
|
||
| **Slice 란?** | ||
|
|
||
| Page보다 가벼운 페이지네이션 방식이다. | ||
|
|
||
| 전체 개수는 계산하지 않음 | ||
|
|
||
| ```java | ||
| Slice<Mission> missions = missionRepository.findByStoreId(storeId, pageable); | ||
| ``` | ||
|
|
||
| Spring 공식 문서에서도 `Slice`는 COUNT 쿼리 없이 **다음 페이지 존재 여부만 확인**한다고 설명한다 | ||
| **장점** | ||
|
|
||
| - 성능이 더 좋음 (COUNT 쿼리가 없음) | ||
| - 무한스크롤 구현에 적합 | ||
|
|
||
| **단점** | ||
|
|
||
| - 전체 페이지 수를 알 수 없다. | ||
|
|
||
| | 항목 | Page | Slice | | ||
| | --- | --- | --- | | ||
| | 전체 개수 | O | X | | ||
| | Count 쿼리 | O | X | | ||
| | 성능 | 상대적으로 느림 | 상대적으로 빠름 | | ||
| | 사용처 | 게시판, 관리자 페이지 | 무한스크롤, 커서 페이징 | | ||
| - Java stream API | ||
|
|
||
| Java 8부터 추가된 기능으로, 컬렉션 데이터를 함수형 방식으로 처리할 수 있게 해주는 API이다. | ||
|
|
||
| 예: | ||
|
|
||
| ```java | ||
| List<MissionResponseDTO> dtoList = | ||
| missions.stream() | ||
| .map(MissionConverter::toDTO) | ||
| .toList(); | ||
| ``` | ||
|
|
||
| **주요 메서드** | ||
|
|
||
| map() | ||
|
|
||
| 데이터 변환 | ||
|
|
||
| `mission -> dto` | ||
|
|
||
| filter() | ||
|
|
||
| 조건 필터림 | ||
|
|
||
| `point>100` | ||
|
|
||
| forEach() | ||
|
|
||
| 반복 처리 | ||
|
|
||
| collect()/toList() | ||
|
|
||
| 결과 수집 | ||
|
|
||
| **장점** | ||
|
|
||
| - 코드가 간결해짐 | ||
| - 가독성이 좋음 (데이터 흐름이 잘 보임) | ||
|
|
||
| **단점** | ||
|
|
||
| - 익숙하지 않으면 오히려 어려움 (람다식) | ||
| - 디버깅 불편 (중간 상태 확인 어려움) | ||
| - 객체 그래프 탐색 | ||
|
|
||
| JPA에서 객체 간 연관관계를 통해 다른 엔티티에 접근하는 방식 | ||
|
|
||
| 예: | ||
|
|
||
| ```java | ||
| mission.getStore().getName(); | ||
| ``` | ||
|
|
||
| **장점** | ||
|
|
||
| - SQL Join을 직접 안 써도 됨 | ||
| - 코드가 직관적 | ||
|
|
||
| **단점** | ||
|
|
||
| - Lazy Loading 문제 (필요할 때 추가 쿼리가 발생할 수 있음 (N+1문제) | ||
| - @Valid vs @Validated | ||
|
|
||
| **@Valid** | ||
|
|
||
| Java Bean Validation 표준 어노테이션 | ||
|
|
||
| 주로 `Request Body` 검증 | ||
|
|
||
| ```java | ||
| @PostMapping | ||
| public void create( | ||
| @RequestBody @Valid MissionRequest request | ||
| ) | ||
| ``` | ||
|
|
||
| 검증 실패 시 `MethodArgumentNotValidException` 발생 | ||
|
|
||
| **@Validated** | ||
|
|
||
| Spring에서 제공하는 확장 검증 기능 | ||
|
|
||
| 예: | ||
|
|
||
| ```java | ||
| @Validated | ||
| @RestController | ||
| ``` | ||
|
|
||
| **차이점** | ||
|
|
||
| | 항목 | @Valid | @Validated | | ||
| | --- | --- | --- | | ||
| | 제공 | Java 표준 | Spring | | ||
| | 그룹 검증 | X | O | | ||
| | 메서드 파라미터 검증 | 제한적 | O | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| - Spring Security가 무엇인가? | ||
|
|
||
| 자바 기반 웹 애플리케이션의 보안을 담당하는 프레임워크이다. | ||
|
|
||
| 개발자가 보안 로직을 직접 구현하지않고 몇가지 설정만으로 아래 3가지를 처리할 수 있음 | ||
|
|
||
| - 인증(Authentication)- 이 사용자가 누구인지 식별(로그인) | ||
| - 인가(Authorization)- 이 사용자가 해당 리소스에 접근할 권한이 있는지 식별(권한 확인) | ||
| - 보안 위협 방어- CSRF, XSS 등 각종 공격으로부터 보호 | ||
|
|
||
| Filter Chain을 통해 HTTP요청을 순차적으로 필터링하며, SecurityConfig를 통해 커스텀 보안 설정을 적용할 수 있다. | ||
|
|
||
|
|
||
|
|
||
| - 인증(Authentication)vs 인가(Authorization) | ||
|
|
||
|
|
||
|
|
||
| **인증(Authentication)** | ||
|
|
||
| 목적 | ||
|
|
||
| 사용자 신원 확인 | ||
|
|
||
| 실패 시 | ||
|
|
||
| 401 Unauthorized | ||
|
|
||
| 예시 | ||
|
|
||
| 로그인, 회원가입 | ||
|
|
||
| Spring Security | ||
|
|
||
| `AuthenticationEntryPoint` | ||
|
|
||
|
|
||
|
|
||
| **인가(Authorization)** | ||
|
|
||
| 목적 | ||
|
|
||
| 리소스 접근 권한 확인 | ||
|
|
||
| 실패 시 | ||
|
|
||
| 403 Forbidden | ||
|
|
||
| 예시 | ||
|
|
||
| 관리자 페이지 접근 | ||
|
|
||
| Spring Security | ||
|
|
||
| `AccessDeniedHandler` | ||
|
|
||
| 인증 먼저 그 다음 인가 | ||
|
|
||
| - Stateful vs Stateless | ||
|
|
||
|
|
||
|
|
||
| **Stateful** | ||
|
|
||
| 상태 저장 | ||
|
|
||
| 서버가 저장 | ||
|
|
||
| 방식 | ||
|
|
||
| 세션 | ||
|
|
||
| 동작 | ||
|
|
||
| 로그인 시 서버에 세션 저장 → 요청마다 세션 확인 | ||
|
|
||
| 장점 | ||
|
|
||
| 구현 간단 | ||
| 즉시 로그아웃 가능 | ||
|
|
||
| 단점 | ||
|
|
||
| 서버 부하 | ||
| 확장성 낮음 | ||
|
|
||
| 예시 | ||
|
|
||
| 폼 로그인 | ||
|
|
||
|
|
||
|
|
||
| **Stateless** | ||
|
|
||
| 상태 저장 | ||
|
|
||
| 서버가 저장 안함 | ||
|
|
||
| 방식 | ||
|
|
||
| JWT 토큰 | ||
|
|
||
| 동작 | ||
|
|
||
| 토큰에 사용자 정보 담아서 → 요청마다 토큰 검증 | ||
|
|
||
| 장점 | ||
|
|
||
| 토큰 탈취 시 만료 전까지 막기 어려움 | ||
|
|
||
| 예시 | ||
|
|
||
| JWT | ||
|
|
||
| 이번 주차는 Stateful 방식 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,9 +4,9 @@ | |
| import com.example.umc10th.domain.member.dto.MemberResDTO; | ||
| import com.example.umc10th.domain.member.service.MemberService; | ||
| import com.example.umc10th.global.apiPayload.ApiResponse; | ||
| import com.example.umc10th.global.apiPayload.code.BaseSuccessCode; | ||
| import com.example.umc10th.global.apiPayload.code.MemberSuccessCode; | ||
| import com.example.umc10th.domain.member.exception.code.MemberSuccessCode; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
|
|
@@ -20,13 +20,23 @@ public class MemberController { | |
| private final MemberService memberService; | ||
|
|
||
| // 마이페이지 | ||
| @PostMapping("/v1/users/me") | ||
| public ApiResponse<MemberResDTO.GetInfo> getInfo( | ||
| @PostMapping("/v1/members/me") | ||
| public ResponseEntity<ApiResponse<MemberResDTO.GetInfo>> getInfo( | ||
| // 받은 JSON 데이터를 자바 객체(dto)로 변환해서 씀 | ||
| @RequestBody MemberReqDTO.GetInfo dto | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Spring Security를 도입한 뒤 |
||
| ){ | ||
| BaseSuccessCode code= MemberSuccessCode.OK; | ||
| return ApiResponse.onSuccess(code,memberService.getInfo(dto)); | ||
| return ResponseEntity | ||
| .status(MemberSuccessCode.OK.getStatus()) | ||
| .body(ApiResponse.onSuccess(MemberSuccessCode.OK,memberService.getInfo(dto))); | ||
| } | ||
|
|
||
| // 회원가입 | ||
| @PostMapping("/auth/sign-up") | ||
| public ResponseEntity<ApiResponse<MemberResDTO.SignUpResDTO>> signUp( | ||
| @RequestBody MemberReqDTO.SignUpReqDTO dto | ||
| ){ | ||
| return ResponseEntity | ||
| .status(MemberSuccessCode.SIGN_UP.getStatus()) | ||
| .body(ApiResponse.onSuccess(MemberSuccessCode.SIGN_UP,memberService.signUp(dto))); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,26 @@ | ||
| package com.example.umc10th.domain.member.dto; | ||
|
|
||
| import com.example.umc10th.domain.member.enums.Address; | ||
| import com.example.umc10th.domain.member.enums.Gender; | ||
|
|
||
| import java.time.LocalDate; | ||
|
|
||
| public class MemberReqDTO { | ||
|
|
||
| // 마이페이지 | ||
| public record GetInfo( | ||
| Long id | ||
| ){} | ||
|
|
||
| // 회원가입 | ||
| public record SignUpReqDTO( | ||
| String name, | ||
| Gender gender, | ||
| LocalDate birth, | ||
| Address address, | ||
| String detailAddress, | ||
| String phoneNumber, | ||
| String email, | ||
| String password | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 회원가입 요청 DTO에 비밀번호, 이메일, 이름 같은 필수 입력값 검증이 아직 보이지 않습니다. |
||
| ){} | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
토큰 탈취 시 만료 전까지 막기 어려움은 JWT 방식의 장점보다 단점에 가깝습니다. Stateless의 장점은 서버 확장성과 세션 저장소 의존성 감소로 정리하고, 토큰 탈취 위험과 즉시 로그아웃의 어려움은 단점으로 분리하면 개념 구분이 더 정확해집니다.