Skip to content

Commit 2120ccb

Browse files
authored
refactor: 인증 유저 어노테이션 및 스웨거 관련 수정 (#123)
* feat(auth): 인증된 유저 ID를 UUID 형태로 받도록 어노테이션 생성 * feat(auth): 어노테이션 생성에 따른 컨트롤러 코드 수정 * fix(swagger): 스웨거 API 문서 중 날짜의 경우 예제와 다른 값 출력 해결 * test(auth): Auth Long -> UUID 에 따른 테스트 어노테이션 리졸버 수정 * feat(common): 공통 응답 객체 스웨거 적용 * feat(center-login): 기관 로그인 스웨거 명세 추가 * chore: 불필요한 import 제거 * feat(center-login): 기관 로그인 컨트롤러
1 parent 6f95b10 commit 2120ccb

19 files changed

+364
-323
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.somemore.auth.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
8+
9+
@Retention(RetentionPolicy.RUNTIME)
10+
@Target(ElementType.PARAMETER)
11+
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null :T(java.util.UUID).fromString(#this)")
12+
public @interface CurrentUser {
13+
14+
}

src/main/java/com/somemore/center/controller/CenterSignController.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.somemore.center.controller;
22

33
import com.somemore.auth.signout.usecase.SignOutUseCase;
4+
import com.somemore.center.dto.request.CenterSignRequestDto;
45
import com.somemore.global.common.response.ApiResponse;
56
import io.swagger.v3.oas.annotations.tags.Tag;
67
import jakarta.servlet.http.HttpServletResponse;
@@ -9,17 +10,30 @@
910
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1011
import org.springframework.web.bind.annotation.PostMapping;
1112
import org.springframework.web.bind.annotation.RequestMapping;
13+
import org.springframework.web.bind.annotation.RequestParam;
1214
import org.springframework.web.bind.annotation.RestController;
1315

1416
@RestController
1517
@Slf4j
1618
@RequiredArgsConstructor
1719
@RequestMapping("/api/center")
18-
@Tag(name = "center Sign API", description = "기관 로그아웃")
20+
@Tag(name = "center Sign API", description = "기관 로그인, 로그아웃")
1921
public class CenterSignController {
2022

2123
private final SignOutUseCase signOutUseCase;
2224

25+
/*
26+
* 기관 로그인 엔드포인트
27+
* 실제 로그인 절차는 필터에서 처리됩니다.
28+
* 이 엔드포인트는 로그인 요청을 받아 필터에 의한 인증 절차를 수행합니다.
29+
*/
30+
@PostMapping("/sign-in")
31+
public ApiResponse<String> signIn(
32+
@RequestParam CenterSignRequestDto requestDto
33+
) {
34+
return ApiResponse.ok("로그인되었습니다.");
35+
}
36+
2337
@PostMapping("/sign-out")
2438
public ApiResponse<String> signOut(
2539
HttpServletResponse response,

src/main/java/com/somemore/center/controller/PreferItemCommandApiController.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
package com.somemore.center.controller;
22

3+
import com.somemore.auth.annotation.CurrentUser;
34
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
45
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
56
import com.somemore.center.usecase.command.CreatePreferItemUseCase;
67
import com.somemore.global.common.response.ApiResponse;
78
import io.swagger.v3.oas.annotations.Operation;
89
import io.swagger.v3.oas.annotations.tags.Tag;
910
import jakarta.validation.Valid;
11+
import java.util.UUID;
1012
import lombok.RequiredArgsConstructor;
1113
import org.springframework.security.access.annotation.Secured;
12-
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1314
import org.springframework.web.bind.annotation.PostMapping;
1415
import org.springframework.web.bind.annotation.RequestBody;
1516
import org.springframework.web.bind.annotation.RequestMapping;
1617
import org.springframework.web.bind.annotation.RestController;
1718

18-
import java.util.UUID;
19-
2019
@RequiredArgsConstructor
2120
@RestController
2221
@RequestMapping("/api/preferItem")
@@ -28,10 +27,12 @@ public class PreferItemCommandApiController {
2827
@Secured("ROLE_CENTER")
2928
@Operation(summary = "기관 선호물품 등록 API")
3029
@PostMapping()
31-
public ApiResponse<PreferItemCreateResponseDto> registerPreferItem(@Valid @RequestBody PreferItemCreateRequestDto requestDto,
32-
@AuthenticationPrincipal String userId) {
30+
public ApiResponse<PreferItemCreateResponseDto> registerPreferItem(
31+
@Valid @RequestBody PreferItemCreateRequestDto requestDto,
32+
@CurrentUser UUID userId) {
3333

34-
PreferItemCreateResponseDto responseDto = createPreferItemUseCase.createPreferItem(UUID.fromString(userId), requestDto);
34+
PreferItemCreateResponseDto responseDto = createPreferItemUseCase.createPreferItem(userId,
35+
requestDto);
3536

3637
return ApiResponse.ok(200, responseDto, "관심 기관 등록 성공");
3738
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.somemore.center.dto.request;
2+
3+
import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
4+
import com.fasterxml.jackson.databind.annotation.JsonNaming;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import lombok.Builder;
7+
8+
@JsonNaming(SnakeCaseStrategy.class)
9+
@Builder
10+
public record CenterSignRequestDto(
11+
@Schema(description = "기관 아이디", example = "somemore")
12+
String accountId,
13+
@Schema(description = "기관 패스워드", example = "password1234")
14+
String accountPassword
15+
) {
16+
17+
}

src/main/java/com/somemore/global/common/response/ApiResponse.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package com.somemore.global.common.response;
22

3+
import io.swagger.v3.oas.annotations.media.Schema;
34
import lombok.Getter;
45
import lombok.NoArgsConstructor;
56

67
@NoArgsConstructor
78
@Getter
89
public class ApiResponse<T> {
910

11+
@Schema(description = "응답 상태 코드. 성공 시 200, 실패 시 오류 코드", example = "200")
1012
private int code;
13+
@Schema(description = "응답에 대한 메시지. 요청 성공/실패에 대한 설명", example = "요청 성공")
1114
private String message;
15+
@Schema(description = "API 요청 처리 결과로 반환되는 데이터", example = "{ name : 손모아 }")
1216
private T data;
1317

1418
public static <T> ApiResponse<T> ok(int status, T data, String message) {

src/main/java/com/somemore/interestcenter/controller/InterestCenterQueryApiController.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
package com.somemore.interestcenter.controller;
22

3+
import com.somemore.auth.annotation.CurrentUser;
34
import com.somemore.global.common.response.ApiResponse;
45
import com.somemore.interestcenter.dto.response.InterestCentersResponseDto;
56
import com.somemore.interestcenter.usecase.InterestCenterQueryUseCase;
67
import io.swagger.v3.oas.annotations.Operation;
78
import io.swagger.v3.oas.annotations.tags.Tag;
9+
import java.util.List;
10+
import java.util.UUID;
811
import lombok.RequiredArgsConstructor;
9-
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1012
import org.springframework.web.bind.annotation.GetMapping;
1113
import org.springframework.web.bind.annotation.RestController;
1214

13-
import java.util.List;
14-
import java.util.UUID;
15-
1615
@RequiredArgsConstructor
1716
@RestController
1817
@Tag(name = "Interest Center Query API", description = "관심 기관의 조회 API를 제공합니다")
@@ -22,9 +21,11 @@ public class InterestCenterQueryApiController {
2221

2322
@Operation(summary = "관심기관 목록 조회 API")
2423
@GetMapping("/api/interest-centers")
25-
public ApiResponse<List<InterestCentersResponseDto>> getInterestCenters(@AuthenticationPrincipal String volunteerId) {
24+
public ApiResponse<List<InterestCentersResponseDto>> getInterestCenters(
25+
@CurrentUser UUID volunteerId) {
2626

27-
List<InterestCentersResponseDto> responseDtos = interestCenterQueryUseCase.getInterestCenters(UUID.fromString(volunteerId));
27+
List<InterestCentersResponseDto> responseDtos = interestCenterQueryUseCase.getInterestCenters(
28+
volunteerId);
2829

2930
return ApiResponse.ok(200, responseDtos, "관심기관 조회 성공");
3031
}

src/main/java/com/somemore/recruitboard/controller/RecruitBoardCommandApiController.java

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
55

6+
import com.somemore.auth.annotation.CurrentUser;
67
import com.somemore.global.common.response.ApiResponse;
78
import com.somemore.imageupload.dto.ImageUploadRequestDto;
89
import com.somemore.imageupload.usecase.ImageUploadUseCase;
@@ -20,7 +21,6 @@
2021
import java.util.UUID;
2122
import lombok.RequiredArgsConstructor;
2223
import org.springframework.security.access.annotation.Secured;
23-
import org.springframework.security.core.annotation.AuthenticationPrincipal;
2424
import org.springframework.web.bind.annotation.DeleteMapping;
2525
import org.springframework.web.bind.annotation.PatchMapping;
2626
import org.springframework.web.bind.annotation.PathVariable;
@@ -47,16 +47,15 @@ public class RecruitBoardCommandApiController {
4747
@Operation(summary = "봉사 활동 모집글 등록", description = "봉사 활동 모집글을 등록합니다.")
4848
@PostMapping(value = "/recruit-board", consumes = MULTIPART_FORM_DATA_VALUE)
4949
public ApiResponse<Long> createRecruitBoard(
50-
@AuthenticationPrincipal String userId,
50+
@CurrentUser UUID userId,
5151
@Valid @RequestPart("data") RecruitBoardCreateRequestDto requestDto,
5252
@RequestPart(value = "img_file", required = false) MultipartFile image
5353
) {
5454

5555
String imgUrl = imageUploadUseCase.uploadImage(new ImageUploadRequestDto(image));
5656
return ApiResponse.ok(
5757
201,
58-
createRecruitBoardUseCase.createRecruitBoard(requestDto, getCenterId(userId),
59-
imgUrl),
58+
createRecruitBoardUseCase.createRecruitBoard(requestDto, userId, imgUrl),
6059
"봉사 활동 모집글 등록 성공"
6160
);
6261
}
@@ -65,13 +64,13 @@ public ApiResponse<Long> createRecruitBoard(
6564
@Operation(summary = "봉사 활동 모집글 수정", description = "봉사 활동 모집글을 수정합니다.")
6665
@PutMapping(value = "/recruit-board/{id}", consumes = MULTIPART_FORM_DATA_VALUE)
6766
public ApiResponse<String> updateRecruitBoard(
68-
@AuthenticationPrincipal String userId,
67+
@CurrentUser UUID userId,
6968
@PathVariable Long id,
7069
@Valid @RequestPart("data") RecruitBoardUpdateRequestDto requestDto,
7170
@RequestPart(value = "img_file", required = false) MultipartFile image
7271
) {
7372
String imgUrl = imageUploadUseCase.uploadImage(new ImageUploadRequestDto(image));
74-
updateRecruitBoardUseCase.updateRecruitBoard(requestDto, id, getCenterId(userId), imgUrl);
73+
updateRecruitBoardUseCase.updateRecruitBoard(requestDto, id, userId, imgUrl);
7574

7675
return ApiResponse.ok("봉사 활동 모집글 수정 성공");
7776
}
@@ -80,27 +79,25 @@ public ApiResponse<String> updateRecruitBoard(
8079
@Operation(summary = "봉사 활동 모집글 위치 수정", description = "봉사 활동 모집글의 위치를 수정합니다.")
8180
@PutMapping(value = "/recruit-board/{id}/location")
8281
public ApiResponse<String> updateRecruitBoardLocation(
83-
@AuthenticationPrincipal String userId,
82+
@CurrentUser UUID userId,
8483
@PathVariable Long id,
8584
@Valid @RequestBody RecruitBoardLocationUpdateRequestDto requestDto
8685
) {
8786

88-
updateRecruitBoardUseCase.updateRecruitBoardLocation(requestDto, id, getCenterId(userId));
87+
updateRecruitBoardUseCase.updateRecruitBoardLocation(requestDto, id, userId);
8988
return ApiResponse.ok("봉사 활동 모집글 위치 수정 성공");
9089
}
9190

9291
@Secured("ROLE_CENTER")
9392
@Operation(summary = "봉사 활동 모집글 상태 수정", description = "봉사 활동 모집글의 상태를 수정합니다.")
9493
@PatchMapping(value = "/recruit-board/{id}")
9594
public ApiResponse<String> updateRecruitBoardStatus(
96-
@AuthenticationPrincipal String userId,
95+
@CurrentUser UUID userId,
9796
@PathVariable Long id,
9897
@RequestBody RecruitBoardStatusUpdateRequestDto requestDto
9998
) {
10099
LocalDateTime now = LocalDateTime.now();
101-
updateRecruitBoardUseCase.updateRecruitBoardStatus(requestDto.status(), id,
102-
getCenterId(userId),
103-
now);
100+
updateRecruitBoardUseCase.updateRecruitBoardStatus(requestDto.status(), id, userId, now);
104101

105102
return ApiResponse.ok("봉사 활동 모집글 상태 수정 성공");
106103
}
@@ -109,15 +106,11 @@ public ApiResponse<String> updateRecruitBoardStatus(
109106
@Operation(summary = "봉사 활동 모집글 삭제", description = "봉사 활동 모집글을 삭제합니다.")
110107
@DeleteMapping(value = "/recruit-board/{id}")
111108
public ApiResponse<String> deleteRecruitBoard(
112-
@AuthenticationPrincipal String userId,
109+
@CurrentUser UUID userId,
113110
@PathVariable Long id
114111
) {
115-
deleteRecruitBoardUseCase.deleteRecruitBoard(getCenterId(userId), id);
112+
deleteRecruitBoardUseCase.deleteRecruitBoard(userId, id);
116113
return ApiResponse.ok("봉사 활동 모집글 삭제 성공");
117114
}
118115

119-
private static UUID getCenterId(String userId) {
120-
return UUID.fromString(userId);
121-
}
122-
123116
}

src/main/java/com/somemore/recruitboard/dto/request/RecruitBoardCreateRequestDto.java

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,51 @@
1616
@JsonNaming(SnakeCaseStrategy.class)
1717
@Builder
1818
public record RecruitBoardCreateRequestDto(
19-
@Schema(description = "봉사 모집글 제목", example = "서울 청계천 환경 미화 봉사 모집")
20-
@NotBlank(message = "모집글 제목은 필수 값입니다.")
21-
String title,
22-
@Schema(description = "봉사 모집글 내용", example = "서울 청계천 주변 환경 미화 봉사 모집합니다. <br>")
23-
@NotBlank(message = "모집글 내용은 필수 값입니다.")
24-
String content,
25-
@Schema(description = "봉사 지역", example = "서울")
26-
@NotBlank(message = "봉사 지역은 필수 값입니다.")
27-
String region,
28-
@Schema(description = "예상 모집 인원", example = "4")
29-
@NotNull(message = "예상 모집 인원은 필수 값입니다.")
30-
Integer recruitmentCount,
31-
@Schema(description = "봉사 시작 일시", example = "2024-11-20T10:00:00")
32-
@NotNull(message = "봉사 시작 일시는 필수 값입니다.")
33-
LocalDateTime volunteerStartDateTime,
34-
@Schema(description = "봉사 종료 일시", example = "2024-11-20T12:00:00")
35-
@NotNull(message = "봉사 종료 일시는 필수 값입니다.")
36-
LocalDateTime volunteerEndDateTime,
37-
@Schema(description = "봉사 활동 유형", example = "ENVIRONMENTAL_PROTECTION")
38-
@NotNull(message = "봉사 활동 유형은 필수 값입니다.")
39-
VolunteerCategory volunteerCategory,
40-
@Schema(description = "봉사 시간 인정 여부", example = "true")
41-
@NotNull(message = "시간 인정 여부는 필수 값입니다.")
42-
Boolean admitted,
43-
@NotNull(message = "위치 정보는 필수 값입니다.")
44-
LocationCreateRequestDto location
19+
@Schema(description = "봉사 모집글 제목", example = "서울 청계천 환경 미화 봉사 모집")
20+
@NotBlank(message = "모집글 제목은 필수 값입니다.")
21+
String title,
22+
@Schema(description = "봉사 모집글 내용", example = "서울 청계천 주변 환경 미화 봉사 모집합니다. <br>")
23+
@NotBlank(message = "모집글 내용은 필수 값입니다.")
24+
String content,
25+
@Schema(description = "봉사 지역", example = "서울")
26+
@NotBlank(message = "봉사 지역은 필수 값입니다.")
27+
String region,
28+
@Schema(description = "예상 모집 인원", example = "4")
29+
@NotNull(message = "예상 모집 인원은 필수 값입니다.")
30+
Integer recruitmentCount,
31+
@Schema(description = "봉사 시작 일시", example = "2024-11-20T10:00:00", type = "string")
32+
@NotNull(message = "봉사 시작 일시는 필수 값입니다.")
33+
LocalDateTime volunteerStartDateTime,
34+
@Schema(description = "봉사 종료 일시", example = "2024-11-20T12:00:00", type = "string")
35+
@NotNull(message = "봉사 종료 일시는 필수 값입니다.")
36+
LocalDateTime volunteerEndDateTime,
37+
@Schema(description = "봉사 활동 유형", example = "ENVIRONMENTAL_PROTECTION")
38+
@NotNull(message = "봉사 활동 유형은 필수 값입니다.")
39+
VolunteerCategory volunteerCategory,
40+
@Schema(description = "봉사 시간 인정 여부", example = "true")
41+
@NotNull(message = "시간 인정 여부는 필수 값입니다.")
42+
Boolean admitted,
43+
@NotNull(message = "위치 정보는 필수 값입니다.")
44+
LocationCreateRequestDto location
4545
) {
4646

4747
public RecruitBoard toEntity(UUID centerId, Long locationId, String imgUrl) {
4848
RecruitmentInfo recruitmentInfo = RecruitmentInfo.builder()
49-
.region(region)
50-
.recruitmentCount(recruitmentCount)
51-
.volunteerStartDateTime(volunteerStartDateTime)
52-
.volunteerEndDateTime(volunteerEndDateTime)
53-
.volunteerCategory(volunteerCategory)
54-
.admitted(admitted)
55-
.build();
49+
.region(region)
50+
.recruitmentCount(recruitmentCount)
51+
.volunteerStartDateTime(volunteerStartDateTime)
52+
.volunteerEndDateTime(volunteerEndDateTime)
53+
.volunteerCategory(volunteerCategory)
54+
.admitted(admitted)
55+
.build();
5656

5757
return RecruitBoard.builder()
58-
.centerId(centerId)
59-
.locationId(locationId)
60-
.title(title)
61-
.content(content)
62-
.imgUrl(imgUrl)
63-
.recruitmentInfo(recruitmentInfo)
64-
.build();
58+
.centerId(centerId)
59+
.locationId(locationId)
60+
.title(title)
61+
.content(content)
62+
.imgUrl(imgUrl)
63+
.recruitmentInfo(recruitmentInfo)
64+
.build();
6565
}
6666
}

0 commit comments

Comments
 (0)