diff --git a/src/main/java/com/zipte/platform/security/jwt/util/RequestMatcherHolder.java b/src/main/java/com/zipte/platform/security/jwt/util/RequestMatcherHolder.java index a3add02..cbb59fd 100644 --- a/src/main/java/com/zipte/platform/security/jwt/util/RequestMatcherHolder.java +++ b/src/main/java/com/zipte/platform/security/jwt/util/RequestMatcherHolder.java @@ -23,7 +23,6 @@ public class RequestMatcherHolder { new RequestInfo(OPTIONS, "/**", null), new RequestInfo(GET, "/", null), new RequestInfo(GET, "/login", null), - new RequestInfo(POST, "/error", null), // 개발용 new RequestInfo(POST, "/api/v1/auth/dev-login-1", null), @@ -66,6 +65,9 @@ public class RequestMatcherHolder { // 알림 new RequestInfo(GET, "/api/v1/notification/**", UserRole.MEMBER), + // 가중치 + new RequestInfo(GET, "/api/v1/weight/**", UserRole.MEMBER), + // review new RequestInfo(POST, "/api/v1/review/**", UserRole.MEMBER), new RequestInfo(GET, "/api/v1/review/**", null), @@ -85,11 +87,13 @@ public class RequestMatcherHolder { new RequestInfo(GET, "/index.html", null), new RequestInfo(GET, "/error", null), + // Swagger UI 및 API 문서 관련 요청 - new RequestInfo(GET, "/swagger-ui/**", null), new RequestInfo(GET, "/v3/api-docs/**", null), + new RequestInfo(GET, "/swagger-ui/**", null), new RequestInfo(GET, "/swagger-resources/**", null), new RequestInfo(GET, "/webjars/**", null), + new RequestInfo(GET, "/swagger-ui.html", null), // 정적 아이콘 요청 new RequestInfo(GET, "/favicon.ico", null), diff --git a/src/main/java/com/zipte/platform/server/adapter/in/web/UserWeightApi.java b/src/main/java/com/zipte/platform/server/adapter/in/web/UserWeightApi.java index d1ee152..cb71640 100644 --- a/src/main/java/com/zipte/platform/server/adapter/in/web/UserWeightApi.java +++ b/src/main/java/com/zipte/platform/server/adapter/in/web/UserWeightApi.java @@ -4,8 +4,10 @@ import com.zipte.platform.security.oauth2.domain.PrincipalDetails; import com.zipte.platform.server.adapter.in.web.dto.request.UserWeightRequest; import com.zipte.platform.server.adapter.in.web.dto.response.UserWeightResponse; +import com.zipte.platform.server.adapter.in.web.swagger.UserWeightApiSpec; import com.zipte.platform.server.application.in.user.UserWeightUseCase; import com.zipte.platform.server.domain.user.UserWeight; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @@ -13,13 +15,19 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/weight") -public class UserWeightApi { +public class UserWeightApi implements UserWeightApiSpec { private final UserWeightUseCase userWeightService; @PostMapping - public ApiResponse create(@RequestBody UserWeightRequest request) { - userWeightService.createWeight(request); + public ApiResponse create( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestBody @Valid UserWeightRequest request) { + + /// UserId 추출 + Long userId = principalDetails.getUser().getId(); + + userWeightService.createWeight(userId, request); return ApiResponse.created("나만의 가중치값이 생성되었습니다."); } @@ -33,7 +41,9 @@ public ApiResponse getMyWeight(@AuthenticationPrincipal Prin } @DeleteMapping("/{id}") - public ApiResponse delete(@AuthenticationPrincipal PrincipalDetails principalDetails, @PathVariable Long id) { + public ApiResponse delete(@AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable Long id) { + userWeightService.removeWeight(principalDetails.getId(), id); return ApiResponse.ok("정상적으로 삭제 되었습니다."); diff --git a/src/main/java/com/zipte/platform/server/adapter/in/web/dto/request/UserWeightRequest.java b/src/main/java/com/zipte/platform/server/adapter/in/web/dto/request/UserWeightRequest.java index d97072e..46b4083 100644 --- a/src/main/java/com/zipte/platform/server/adapter/in/web/dto/request/UserWeightRequest.java +++ b/src/main/java/com/zipte/platform/server/adapter/in/web/dto/request/UserWeightRequest.java @@ -1,23 +1,36 @@ package com.zipte.platform.server.adapter.in.web.dto.request; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import lombok.Data; @Data public class UserWeightRequest { - private Long id; - - private Long userId; - - private int convenience; // 편의시설 (마트, 병원 등 근접성) - - private int transportation; // 교통 (지하철, 버스 정류장까지 소요 시간) - - private int regionPreference; // 지역 선호도 - - private int parkAccess; // 공원 접근성 - - private int distanceToWork; // 직장/학교와의 거리 - + @NotNull(message = "편의시설 가중치는 필수입니다.") + @Min(value = 1, message = "편의시설 가중치는 1 이상이어야 합니다.") + @Max(value = 100, message = "편의시설 가중치는 100 이하이어야 합니다.") + private Integer convenience; // 편의시설 (마트, 병원 등 근접성) + + @NotNull(message = "교통 가중치는 필수입니다.") + @Min(value = 1, message = "교통 가중치는 1 이상이어야 합니다.") + @Max(value = 100, message = "교통 가중치는 100 이하이어야 합니다.") + private Integer transportation; // 교통 (지하철, 버스 정류장까지 소요 시간) + + @NotNull(message = "지역 선호도 가중치는 필수입니다.") + @Min(value = 1, message = "지역 선호도 가중치는 1 이상이어야 합니다.") + @Max(value = 100, message = "지역 선호도 가중치는 100 이하이어야 합니다.") + private Integer regionPreference; // 지역 선호도 + + @NotNull(message = "공원 접근성 가중치는 필수입니다.") + @Min(value = 1, message = "공원 접근성 가중치는 1 이상이어야 합니다.") + @Max(value = 100, message = "공원 접근성 가중치는 100 이하이어야 합니다.") + private Integer parkAccess; // 공원 접근성 + + @NotNull(message = "직장/학교와의 거리 가중치는 필수입니다.") + @Min(value = 1, message = "직장/학교와의 거리 가중치는 1 이상이어야 합니다.") + @Max(value = 100, message = "직장/학교와의 거리 가중치는 100 이하이어야 합니다.") + private Integer distanceToWork; // 직장/학교와의 거리 } diff --git a/src/main/java/com/zipte/platform/server/adapter/in/web/swagger/UserWeightApiSpec.java b/src/main/java/com/zipte/platform/server/adapter/in/web/swagger/UserWeightApiSpec.java new file mode 100644 index 0000000..13dafab --- /dev/null +++ b/src/main/java/com/zipte/platform/server/adapter/in/web/swagger/UserWeightApiSpec.java @@ -0,0 +1,64 @@ +package com.zipte.platform.server.adapter.in.web.swagger; + +import com.zipte.platform.core.response.ApiResponse; +import com.zipte.platform.security.oauth2.domain.PrincipalDetails; +import com.zipte.platform.server.adapter.in.web.dto.request.UserWeightRequest; +import com.zipte.platform.server.adapter.in.web.dto.response.UserWeightResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.http.MediaType; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "유저 가중치 API", description = "AI를 위한 유저 가중치 관련 API") +public interface UserWeightApiSpec { + + @Operation( + summary = "유저 가중치 설정", + description = "JWT 토큰을 기반으로 가중치를 설정합니다.", + requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody( + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + examples = { + @ExampleObject(name = "나의 가중치 등록 예시", value = SUCCESS_PAYLOAD), + } + ) + ) + ) + ApiResponse create(@AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestBody @Valid UserWeightRequest request); + + @Operation( + summary = "유저 가중치 조회", + description = "JWT 토큰을 기반으로 나의 가중치 현황를 조회합니다." + ) + ApiResponse getMyWeight( + @AuthenticationPrincipal PrincipalDetails principalDetails); + + @Operation( + summary = "유저 가중치 삭제", + description = "JWT 토큰을 기반으로 가중치를 삭제합니다." + ) + ApiResponse delete( + @AuthenticationPrincipal PrincipalDetails principalDetails, + + @Parameter(required = true, description = "가중치의 ID", example = "1") + @PathVariable Long id); + + + String SUCCESS_PAYLOAD = """ + { + "convenience": 4, + "transportation": 5, + "regionPreference": 3, + "parkAccess": 2, + "distanceToWork": 5 + } + + """; + +} diff --git a/src/main/java/com/zipte/platform/server/application/in/user/UserWeightUseCase.java b/src/main/java/com/zipte/platform/server/application/in/user/UserWeightUseCase.java index a2e3d22..ebad587 100644 --- a/src/main/java/com/zipte/platform/server/application/in/user/UserWeightUseCase.java +++ b/src/main/java/com/zipte/platform/server/application/in/user/UserWeightUseCase.java @@ -19,7 +19,7 @@ public interface UserWeightUseCase { */ - UserWeight createWeight(UserWeightRequest request); + UserWeight createWeight(Long userId, UserWeightRequest request); UserWeight getWeight(Long userId); diff --git a/src/main/java/com/zipte/platform/server/application/service/UserWeightService.java b/src/main/java/com/zipte/platform/server/application/service/UserWeightService.java index b0fc15b..ffb5cab 100644 --- a/src/main/java/com/zipte/platform/server/application/service/UserWeightService.java +++ b/src/main/java/com/zipte/platform/server/application/service/UserWeightService.java @@ -24,10 +24,10 @@ public class UserWeightService implements UserWeightUseCase { private final UserPort loadUserPort; @Override - public UserWeight createWeight(UserWeightRequest request) { + public UserWeight createWeight(Long userId, UserWeightRequest request) { /// 유저 예외처리 - if(!loadUserPort.checkExistingById(request.getUserId())){ + if (!loadUserPort.checkExistingById(userId)) { throw new NoSuchElementException(ErrorCode.NOT_USER.getMessage()); } @@ -35,8 +35,8 @@ public UserWeight createWeight(UserWeightRequest request) { /// 객체 생성 - UserWeight userWeight = UserWeight.of(request.getUserId(), request.getConvenience(), request.getTransportation(), - request.getRegionPreference(), request.getParkAccess(), request.getDistanceToWork()); + UserWeight userWeight = UserWeight.of(userId, request.getConvenience(), request.getTransportation(), + request.getRegionPreference(), request.getParkAccess(), request.getDistanceToWork()); return weightPort.saveUserWeight(userWeight); }