Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
9b52122
feat: 리뷰 작성 API 수정 및 REST 구조 개선
cha-hyunwoo May 8, 2026
077b761
feat: 리뷰 도메인 전용 예외 처리 및 에러 코드 수정
cha-hyunwoo May 8, 2026
7a988ce
refactor: 리뷰 DTO 필드 최적화 및 레포지토리 인터페이스 수정
cha-hyunwoo May 8, 2026
e6eab26
feat: 회원 관련 URI 경로 수정 (/users -> /members)
cha-hyunwoo May 10, 2026
49e76ea
feat: MemberMission 기본 상태 변경 (CHALLENGING -> READY)
cha-hyunwoo May 10, 2026
0dbea2d
feat: MemberSuccessCode 구현
cha-hyunwoo May 10, 2026
96d6a9d
refactor: Fetch Join을 이용한 미션 목록 조회
cha-hyunwoo May 10, 2026
f77f6f3
refactor: 미션 관련 API 구조 정비 및 DTO 리팩토링
cha-hyunwoo May 10, 2026
c46a603
refactor: MissionConverter 코드 리팩토링
cha-hyunwoo May 10, 2026
35f9829
refactor: MissionRepository 코드 삭제
cha-hyunwoo May 10, 2026
3f8255e
refactor: 미션 서비스 코드 정리 및 DTO 매핑 로직 수정
cha-hyunwoo May 10, 2026
7f56b9b
feat: READY 상태 추가
cha-hyunwoo May 10, 2026
2d78e66
feat: status 컬럼 추가
cha-hyunwoo May 10, 2026
ddc4cb2
refactor: uri 수정
cha-hyunwoo May 10, 2026
fec22c2
refactor: 지역별 미션 컨버터 수정
cha-hyunwoo May 10, 2026
18d357d
feat: 미션 에러 코드 추가
cha-hyunwoo May 10, 2026
7cd0b0e
feat: 에러 정보 String이 아닌 code로 받게 수정
cha-hyunwoo May 10, 2026
ccaab38
feat: 쿼리 추가
cha-hyunwoo May 10, 2026
860afbf
refactor: dto 미션 목록 추가
cha-hyunwoo May 10, 2026
ffec1bc
feat: region 인터페이스 설정
cha-hyunwoo May 10, 2026
b66bd8f
feat: 지역별 미션 조회 추가
cha-hyunwoo May 10, 2026
d3b01d6
feat: Enum 임의 값 추가
cha-hyunwoo May 11, 2026
ad67d1f
refactor: GeneratedValue 수정
cha-hyunwoo May 11, 2026
7187790
feat: @Valid 어노테이션 검증 실패 예외 추가
cha-hyunwoo May 11, 2026
89605d3
refactor: 컬럼명 오류 수정
cha-hyunwoo May 11, 2026
f66ee1f
feat: MissionController 가게 미션 생성 추가
cha-hyunwoo May 11, 2026
056a363
refactor: reward -> rewardPoint로 통일
cha-hyunwoo May 11, 2026
9cfab48
feat: QUERY_NOT_VALID 에러코드 추가
cha-hyunwoo May 11, 2026
f229fa8
feat: 슬라이스 커서 기반 페이지네이션 구현
cha-hyunwoo May 11, 2026
491abd8
feat: 슬라이스 커서 기반 페이지네이션, 가게 내 미션 조회 추가
cha-hyunwoo May 11, 2026
198bb66
feat: 가게 미션 조회 추가
cha-hyunwoo May 11, 2026
1c62e4d
feat: CREATED 성공 코드 추가
cha-hyunwoo May 11, 2026
db85075
feat: 리뷰 작성 db 저장 기능 추가
cha-hyunwoo May 11, 2026
49e1ebc
feat: 약관 enum 추가
cha-hyunwoo May 11, 2026
8ad5051
feat: BaseEntity동작을 위한EnableJpaAuditing
cha-hyunwoo May 11, 2026
27995fa
feat: BaseErrorCode 상속
cha-hyunwoo May 11, 2026
1ff410e
refactor: 코드 단순화
cha-hyunwoo May 11, 2026
977dc5c
refactor: Store 코드 삭제
cha-hyunwoo May 11, 2026
66ef595
refactor: 오타 수정
cha-hyunwoo May 12, 2026
9f09aa6
feat: 내가 작성한 리뷰들 조회 getReviews 작성
cha-hyunwoo May 12, 2026
604c69a
feat: 페이지네이션 틀, 리뷰 상세정보 ReviewResDTO 작성
cha-hyunwoo May 12, 2026
3948ecb
feat: 커서 기반 페이지네이션 내가 작성한 리뷰 조회
cha-hyunwoo May 12, 2026
7418d9c
feat: 리뷰 조회 에러와 성공 코드 추가
cha-hyunwoo May 12, 2026
b24996c
feat: 페이지네이션 틀과 리뷰 관련 toGetReview 작성
cha-hyunwoo May 12, 2026
0f60053
feat: id순 내림차순 쿼리와 rating순 쿼리 작성
cha-hyunwoo May 12, 2026
8f5ca73
feat: PostMapping으로 RequestBody로 받기
cha-hyunwoo May 12, 2026
a2e4c26
feat: RequestBody로 받을 memberId추가
cha-hyunwoo May 12, 2026
26d28cc
feat: 매개변수 memberId 삭제
cha-hyunwoo May 12, 2026
b9c56ce
docs: 7주차 핵심 키워드 정리
cha-hyunwoo May 12, 2026
a8ba722
refactor: 미션 생성시 status READY상태
cha-hyunwoo May 13, 2026
9833d04
feat: ResponseEntity로 HTTP status 통일
cha-hyunwoo May 15, 2026
57f8f2b
fix: MissionSuccessCode CREATED 상태코드 201로 수정
cha-hyunwoo May 15, 2026
82021c9
feat: Spring Security 의존성 추가
cha-hyunwoo May 18, 2026
e9dc608
feat: password 컬럼 추가
cha-hyunwoo May 18, 2026
15f7d9f
feat: findByEmail메서드 추가
cha-hyunwoo May 18, 2026
b527af5
feat: Spring Security 보안 설정 추가
cha-hyunwoo May 18, 2026
1e404af
feat: 사용자 상세 정보 로드 서비스 추가
cha-hyunwoo May 18, 2026
f6997a7
feat: Spring Security 사용자 인증 정보 클래스 추가
cha-hyunwoo May 18, 2026
4a4abc6
feat: 권한이 없는 사용자가 접근할 때 JSON으로 응답해주는 핸들러 작성
cha-hyunwoo May 18, 2026
211f883
feat: 로그인 안했을떄 사용자가 접근할 때 JSON으로 응답해주는 핸들러 작성
cha-hyunwoo May 18, 2026
a49ffa3
feat: 예외상황 핸들러 추가
cha-hyunwoo May 18, 2026
2f823ad
refactor: 전역 MemberSuccessCode를 Member 도메인으로 통합
cha-hyunwoo May 18, 2026
5e1ece2
chore: StoreController 미사용 import 제거
cha-hyunwoo May 18, 2026
684e89f
refactor: 인증 관련 엔드포인트 수정
cha-hyunwoo May 18, 2026
b8ddca3
chore: ReviewController 미사용 import 제거
cha-hyunwoo May 18, 2026
af9280e
chore: MissionController 미사용 import 제거
cha-hyunwoo May 18, 2026
2bb127f
feat: 회원가입 메서드 signUp 작성
cha-hyunwoo May 18, 2026
e42cd53
feat: 회원가입 SignUpReqDTO, SignUpResDTO 작성
cha-hyunwoo May 18, 2026
6e6f1e7
feat: 회원가입 signUp메서드 작성
cha-hyunwoo May 18, 2026
358e0da
feat: 회원가입 toMember, toSignUp 컨버터 메서드 작성
cha-hyunwoo May 18, 2026
fd05d46
docs: 8주차 핵심키워드 작성
cha-hyunwoo May 18, 2026
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
4 changes: 4 additions & 0 deletions Hyeonu/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ dependencies {
// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.1'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.1'

// Security
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
}

tasks.named('test') {
Expand Down
152 changes: 152 additions & 0 deletions Hyeonu/keyword_summary/ch07.md
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 |
115 changes: 115 additions & 0 deletions Hyeonu/keyword_summary/ch08.md
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 토큰

동작

토큰에 사용자 정보 담아서 → 요청마다 토큰 검증

장점

토큰 탈취 시 만료 전까지 막기 어려움
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

토큰 탈취 시 만료 전까지 막기 어려움은 JWT 방식의 장점보다 단점에 가깝습니다. Stateless의 장점은 서버 확장성과 세션 저장소 의존성 감소로 정리하고, 토큰 탈취 위험과 즉시 로그아웃의 어려움은 단점으로 분리하면 개념 구분이 더 정확해집니다.


예시

JWT

이번 주차는 Stateful 방식
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing // BaseEntity 동작
@SpringBootApplication
public class Umc10thApplication {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spring Security를 도입한 뒤 /members/me API에서 memberId를 요청 바디로 받으면 다른 사용자의 ID를 넣어 조회할 수 있는 구조가 됩니다. @AuthenticationPrincipal 또는 SecurityContext에서 인증된 사용자를 가져오도록 바꾸면 인증 계층과 회원 조회 유스케이스의 책임이 더 명확해집니다.

){
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,5 +1,6 @@
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;

Expand All @@ -17,4 +18,22 @@ public static MemberResDTO.GetInfo toGetInfo(Member member) {
.status(member.getStatus())
.build();
}

// DTO -> Entity 변환
public static Member toMember(MemberReqDTO.SignUpReqDTO dto, String encodedPassword) {
return Member.builder()
.name(dto.name())
.gender(dto.gender())
.birth(dto.birth())
.address(dto.address())
.detailAddress(dto.detailAddress())
.phoneNumber(dto.phoneNumber())
.email(dto.email())
.password(encodedPassword) // BCrypt 암호화된 비밀번호
.build();
}

public static MemberResDTO.SignUpResDTO toSignUpResDTO(Member member) {
return new MemberResDTO.SignUpResDTO(member.getId());
}
}
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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회원가입 요청 DTO에 비밀번호, 이메일, 이름 같은 필수 입력값 검증이 아직 보이지 않습니다. @NotBlank, @Email, 길이 제한 등을 DTO에 선언하고 Controller에서 @Valid를 적용하면 잘못된 입력이 Service 계층까지 내려가지 않아 계층 책임이 더 분명해집니다.

){}
}
Loading