-
Notifications
You must be signed in to change notification settings - Fork 0
[Gibeom] Week7 미션 #68
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
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
de25943
feat : 6주차 api 설계 기초 jpa
7deb3e8
docs : ch06.md 수정
ecfb9c6
feat : 리뷰/멤버관계 수정
kite-pp 9729251
feat : 멤버 도메인 페이징 처리
kite-pp b1e2237
feat : 미션 도메인 오프셋 페이징 조회 기능 추가
kite-pp 2213fdd
feat : 리뷰 도메인 커서 페이징 기능 추가
kite-pp 6254b93
refactor : Store 도메인 구현 일부 변경
kite-pp e26be52
feat : Valid Exception 처리 추가
kite-pp 64b93bf
refactor : 자바 버전 변경으로 인한 코드 변경
kite-pp 7a12eda
refactor : 종속성 변경
kite-pp ebfe500
refactor : 자바 버전 변경으로 인한 코드수정
kite-pp 6c6ab14
docs : 7주차 핵심 키워드 작성
kite-pp 46cda5e
refactor : ddl-auto 수정
kite-pp 067cc43
refactor : member 도메인 Repository 메소드 수정
kite-pp b0f7937
refactor : 페이지네이션 Score:id 수정
kite-pp 7cd6e5f
docs : Stram API 관련 수정
kite-pp e61fb7f
Merge branch 'Gibeom-Week6' into Gibeom-Week7
kite-pp ed32523
refactor : 미션 생성시 Void 반환 대신 생성된 미션 정보 반환
kite-pp 04c0f1d
refactor : ApiResponse 응답 대신 ResponseEntity 래핑 후 반환 처리
kite-pp c9f6174
refactor : controller 경로 통일 및 review 커서 페이지네이션 수정
kite-pp f4553da
docs : FeedBack 조사
kite-pp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| DB_USER=root | ||
| DB_USER=USER | ||
| DB_PW=MY_PASSWORD_HERE | ||
| DB_URL=jdbc:mysql://localhost:3306/umc10th?serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true&useSSL=false | ||
| DB_URL=MY_URL |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| ResponseEntity | ||
| - 정의 : 스프링 프레임워크에서 제공하는 클래스. | ||
| - Http요청 또는 응답에 해당하는 HttpStatus, HttpHeader와 HttpBody를 포함하는 클래스 | ||
| - Http 응답의 주권을 가짐. 커스텀 가능 | ||
| - 상속 구현 클래스 (RequestBody, ResponseEntity) | ||
|
|
||
| 기존 상태 | ||
| - 클라이언트 측에서는 ApiResponse로 응답시 정해진 응답 (예 : 200이면 200, 500이면 500) | ||
| - 현재 ApiResponse 클래스는 정적 팩토리 메서드 형식. | ||
| - ApiResponse.java | ||
| ``` | ||
| //성공한 경우 | ||
| public static <T> ApiResponse<T> onSuccess(BaseSuccessCode code, T result){ | ||
| return new ApiResponse<>(true, code.getCode(), code.getMessage(), result); | ||
| } | ||
| ``` | ||
| 기존 방식의 한계 | ||
| - 클라이언트 측은 먼저 http status를 확인하고 바디를 확인함 | ||
| - 네트워크 불일치 : ApiResponse만 반환하면 내부 로직이 실패하더라도 Http 상태코드는 기본(200)으로 나가는 경우가 많았음 | ||
| - 상세한 정보가 Json바디 안에 숨겨져 있어 클라이언트가 Http 표준방식으로 1차 판단을 내리기 어려웠음 | ||
| - 단순한 소통 : 200, 500 위주의 단순한 소통만 가능했고, 201, 204 등 을 활용 못했음 | ||
|
|
||
| Why? | ||
| - API 사용자(프론트엔드 등등)는 응답바디 안의 Json뿐 아닌 브라우저나 앱이 수신하는 Status Code를 보고 1차 판단을 내림. | ||
| - 유연성 : ResponseEntity를 래핑해 감싼 응답을 보낸다면 커스텀 응답, 쿠키, 헤더 등 표준화된 응답을 유연하게 보낼 수 있음. | ||
| - ApiResponse의 데이터 규격을 유지하고 ResponseEntity로 감싸 네트워크 수준 상태코드로 명시적 관리 |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| - Page와 Slice | ||
|
|
||
| Spring Data JPA는 페이징을 위해 두가지 객체를 제공한다. Slice & Page | ||
|
|
||
| DB에 저장된 데이터들을 페이지에 맞춰 몇개씩 뿌릴 건지 알려주는 것 | ||
|
|
||
| - Page | ||
| - pageable 객체를 사용해 오프셋 기반 페이지네이션을 구현할 수 있는 객체. | ||
| - Slice를 상속함 | ||
| - Slice | ||
| - Page 보다 좀 더 추상적. | ||
| - 커서 기반 페이지네이션을 구현할 때 사용할 수 있는 객체 | ||
| - Response에 총 데이터 갯수는 보내지 않음 | ||
| - Pageable 객체 | ||
| - JPA가 제공하는 페이지네이션을 위한 객체 | ||
| - 페이징 정보(페이지 번호, 페이지 크기, 정렬방식 등..)를 담고 있는 인터페이스 | ||
| - 스프링 Data JPA에서 제공하는 `PageRequest` 클래스를 통해 인스턴스화 가능 | ||
| - 사용 이유 | ||
| - 모든 데이터를 한번에 뿌리게 되면 성능 저하 등 문제가 발생 | ||
| - 페이지네이션을 사용해 적절한 수의 정보만 올려주면 프론트에서 적절한 처리가능. | ||
| - Java stream API | ||
|
|
||
| 자바가 지원하는 함수형 프로그래밍 방식. | ||
|
|
||
| 함수형 프로그래밍이란? | ||
|
|
||
| - 코드가 “어떻게” 에서 “무엇을”로 포커싱이 옮겨간 프로그래밍 방식 | ||
| - 함수형 프로그래밍에서 함수는 `Int` ,`String` 같은 1급 객체로 취급. | ||
| - 이 특성을 활용하는 고차함수 : map, filter, reduce 등… | ||
| - (기존 객체의 상태를 변경하지 않고, 새로운 결과를 반환) | ||
| - 사용 이유 : 가독성, 불변성, 유지보수성, 병렬 처리성 (쓰레드 풀) | ||
|
|
||
| 단점 | ||
|
|
||
| - for문 같은 단순 반복문에 익숙한 개발자들에게는 람다식과 스트림이 이해가 어려울 수 있음 | ||
| - 중단점을 걸어서 디버깅하기 어려움. | ||
| - for문 보다 오버헤드가 조금 더 큼. | ||
|
|
||
| 병렬 처리 | ||
|
|
||
| - 작업을 여러 스레드에게 분할해 병렬적으로 처리하는 방법 | ||
| - `parallelStram()` 키워드와 `ForkJoinPool()` 을 사용해 스레드 지정 가능 | ||
| - CommonPool : 미리 생성해 놓은 스레드를 모든 애플리케이션이 이용하는 방식의 풀 | ||
| - 장점 : 정해진 수의 스레드를 미리 생성해 놓고 사용하기 때문에 스레드 생성/삭제 오버헤드 적음. 적은 양의 처리에 유리 | ||
| - 단점 : 각각의 애플리케이션 마다 알맞은 처리를 제공하기 힘들 수 있음 | ||
| - (군대 배식 느낌) | ||
| - ThreadPool : 각각의 컴포넌트마다 설정할 수 있는 풀 | ||
| - 장점 : 성능 튜닝 가능 | ||
| - 메모리 관리 등 신경써야 할 것들이 있음. | ||
| - (오마카세 느낌) | ||
| - 객체 그래프 탐색 | ||
|
|
||
| 객체 그래프 탐색 (Object Graph Navigation) | ||
|
|
||
| - 객체지향언어에서 참조를 사용해 연관된 객체를 타고 들어가 데이터를 조회하는 방식 | ||
| - ex) 멤버 객체에서 member.getTeam()처럼 연관관계를 통해 팀 정보를 가져오는 방식 | ||
|
|
||
| 특징 : 객체 간 연관관계를 통해 자유롭게 메모리상의 객체를 이동하며 탐색 | ||
|
|
||
| 장점 : SQL 직접 작성 시 필요한 조인 제약에서 벗어나 논리적인 도메인 모델 구조에 따라 데이터 조회 가능 | ||
|
|
||
| JPA에서의 활용 : JPA는 연관된 객체를 처음부터 로딩하지 않고 실제 사용 시점에 조회하는 지연로딩을 사용해 객체그래프 탐색을 지원 | ||
|
|
||
| 주의점 : 객체 그래프를 무분별 탐색하는 경우, 하이버네이트 등에서 N+1 문제가 발생할 수 있음. | ||
|
|
||
| **내 요약** | ||
|
|
||
| - Store store = member.getReviewList().get(0).getStore()와 같은 코드가 있다고 가정. | ||
| 1. 멤버의 리뷰리스트를 가져오고 | ||
| 2. 0번 객체를 가져오고 | ||
| 3. 그 리뷰의 가게를 가져오는 흐름을 표현 가능. | ||
| - 여기서 문제 : 어디까지 조회가 가능한가? | ||
| - 실행시 모든 데이터를 올려둘 수는 없음. 그렇다면 사용할 때만 필요한 정보를 가져오는 방식 Lazy-Loading(지연로딩)을 사용해 `.` 을 사용해 다음 객체를 불러올때마다 데이터를 가져옴. | ||
| - 만약 객체간 연결이 없거나, 다음 데이터를 조회할 수 없다면 null이 조회되거나 오류가 날 것. | ||
| - @Valid vs @Validated | ||
|
|
||
| @Valid | ||
|
|
||
| - 컨트롤러 단에서 객체의 유효성을 검사할 때 사용 | ||
| - 계층 구조 검증이 가능 (User 안에 있는 Address 객체도 검사하고 싶으면 Address 필드 위에 @Valid 를 붙여야 함) | ||
| - 한계 : 그룹화 검증이 불가능 | ||
|
|
||
| @Validated | ||
|
|
||
| - 스프링에서 자바표준기능을 확장해 만든 어노테이션 | ||
| - 용도 : Service 나 Repository 등 Bean 계층에서 검증이 필요할 때, 혹은 그룹검증이 필요할 때 사용. | ||
| - 특징 | ||
| - 제약조건 그룹화 : “회원가입때는 이 필드 검사하고, 정보수정때는 하지마” 같은 상황을 `groups` 속성으로 지정가능 | ||
| - 클래스 레벨 선언 : 클래스 상단에 `@Validated` 어노테이션을 붙여야 해당 클래스 내부의 메서드 파라미터에 대한 검증이 작동 | ||
| - 한계 : 계층구조 검증은 직접적으로 지원하지 않아, 내부 객체에는 여전히 @Valid를 써야함. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 47 additions & 8 deletions
55
.../umc10th/src/main/java/com/example/umc10th/domain/member/controller/MemberController.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,65 @@ | ||
| package com.example.umc10th.domain.member.controller; | ||
|
|
||
| import com.example.umc10th.domain.member.dto.MemberReqDTO; | ||
| import com.example.umc10th.domain.member.dto.MemberResDTO; | ||
| import com.example.umc10th.domain.member.enums.MissionStatus; | ||
| import com.example.umc10th.domain.member.service.MemberService; | ||
| import com.example.umc10th.domain.mission.dto.MissionResDTO; | ||
| 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.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/api") | ||
| @RequestMapping("/api/v1/members") | ||
| public class MemberController { | ||
|
|
||
| private MemberService memberService; | ||
| private final MemberService memberService; | ||
| //마이페이지 | ||
| @PostMapping("/v1/users/me") | ||
| public ApiResponse<MemberResDTO.GetInfo> getInfo( | ||
| @RequestBody MemberReqDTO.GetInfo dto | ||
| @GetMapping("/me") | ||
| public ResponseEntity<ApiResponse<MemberResDTO.GetInfo>> getInfo( | ||
| @AuthenticationPrincipal Long memberId | ||
| ){ | ||
| BaseSuccessCode code = MemberSuccessCode.OK; | ||
| MemberResDTO.GetInfo result = memberService.getInfo(memberId); | ||
| return ResponseEntity | ||
| .status(code.getStatus()) | ||
| .body(ApiResponse.onSuccess(code, result)); | ||
| } | ||
|
|
||
| // 홈화면 | ||
| @GetMapping("/home") | ||
| public ResponseEntity<ApiResponse<MemberResDTO.HomeResultDto>> getHome( | ||
| @AuthenticationPrincipal Long memberId, | ||
| @RequestParam(defaultValue = "0") int page | ||
| ){ | ||
| BaseSuccessCode code = MemberSuccessCode.OK; | ||
| return ApiResponse.onSuccess(code, memberService.getInfo(dto)); | ||
| MemberResDTO.HomeResultDto result = memberService.getHome(memberId, page); | ||
| return ResponseEntity | ||
| .status(code.getStatus()) | ||
| .body(ApiResponse.onSuccess(code, result)); | ||
| } | ||
|
|
||
| // 진행중/완료 미션 목록 조회 | ||
| @GetMapping("/missions") | ||
| public ResponseEntity<ApiResponse<List<MissionResDTO.MissionDto>>> getMissionsByStatus( | ||
| @AuthenticationPrincipal Long memberId, | ||
| @RequestParam MissionStatus status, | ||
| @RequestParam Integer pageSize, | ||
| @RequestParam Integer pageNum, | ||
| @RequestParam (required = false) String sort | ||
| ){ | ||
| BaseSuccessCode code = MemberSuccessCode.OK; | ||
| List<MissionResDTO.MissionDto> result = memberService.getMissionsByStatus(memberId, status, pageSize, pageNum, sort); | ||
| return ResponseEntity | ||
| .status(code.getStatus()) | ||
| .body(ApiResponse.onSuccess(code, result)); | ||
| } | ||
|
|
||
| } |
43 changes: 43 additions & 0 deletions
43
...om/umc10th/src/main/java/com/example/umc10th/domain/member/converter/MemberConverter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,47 @@ | ||
| package com.example.umc10th.domain.member.converter; | ||
|
|
||
| import com.example.umc10th.domain.member.dto.MemberReqDTO; | ||
| import com.example.umc10th.domain.member.dto.MemberResDTO; | ||
| import com.example.umc10th.domain.member.entity.Member; | ||
| import com.example.umc10th.domain.member.entity.mapping.MemberMission; | ||
|
|
||
| import org.springframework.data.domain.Page; | ||
|
|
||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| public class MemberConverter { | ||
|
|
||
| public static MemberResDTO.GetInfo toGetInfo(Member member) { | ||
| return MemberResDTO.GetInfo.builder() | ||
| .nickname(member.getNickname()) | ||
| .email(member.getEmail()) | ||
| .phoneNumber(member.getPhoneNumber()) | ||
| .userPoint(member.getUserPoint()) | ||
| .build(); | ||
| } | ||
|
|
||
| public static MemberResDTO.HomeResultDto toHomeResult(Member member, Page<MemberMission> memberMissions) { | ||
| List<MemberResDTO.HomeMissionDto> missionDtos = memberMissions.getContent().stream() | ||
| .map(MemberConverter::toHomeMissionDto) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| return MemberResDTO.HomeResultDto.builder() | ||
| .point(member.getUserPoint()) | ||
| .region(member.getRegion() != null ? member.getRegion().getRegionName() : null) | ||
| .missions(missionDtos) | ||
| .hasNext(memberMissions.hasNext()) | ||
| .build(); | ||
| } | ||
|
|
||
| public static MemberResDTO.HomeMissionDto toHomeMissionDto(MemberMission memberMission) { | ||
| return MemberResDTO.HomeMissionDto.builder() | ||
| .missionId(memberMission.getMission().getId()) | ||
| .storeName(null) | ||
| .storeCategory(null) | ||
| .rewardPoint(memberMission.getMission().getPoint()) | ||
| .deadline(null) | ||
| .status(memberMission.getStatus().name()) | ||
| .build(); | ||
| } | ||
| } |
5 changes: 1 addition & 4 deletions
5
Gibeom/umc10th/src/main/java/com/example/umc10th/domain/member/dto/MemberReqDTO.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,5 @@ | ||
| package com.example.umc10th.domain.member.dto; | ||
|
|
||
| public class MemberReqDTO { | ||
| //마이페이지 | ||
| public record GetInfo( | ||
| Long id | ||
| ){} | ||
|
|
||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.