diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/api/favorite/FavoriteController.java b/app-api/src/main/java/com/parkingcomestrue/parking/api/favorite/FavoriteController.java index 073e798d..433275f2 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/api/favorite/FavoriteController.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/api/favorite/FavoriteController.java @@ -3,6 +3,7 @@ import com.parkingcomestrue.parking.application.favorite.FavoriteService; import com.parkingcomestrue.parking.application.favorite.dto.FavoriteCreateRequest; import com.parkingcomestrue.parking.application.favorite.dto.FavoriteDeleteRequest; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.config.argumentresolver.MemberAuth; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -25,7 +26,7 @@ public class FavoriteController { @Operation(summary = "즐겨찾기 등록", description = "즐겨찾기 등록") @PostMapping("/favorites") public ResponseEntity create(@RequestBody FavoriteCreateRequest favoriteCreateRequest, - @Parameter(hidden = true) @MemberAuth Long memberId) { + @Parameter(hidden = true) @MemberAuth MemberId memberId) { favoriteService.createFavorite(favoriteCreateRequest, memberId); return ResponseEntity.status(HttpStatus.CREATED).build(); } @@ -33,7 +34,7 @@ public ResponseEntity create(@RequestBody FavoriteCreateRequest favoriteCr @Operation(summary = "즐겨찾기 해제", description = "즐겨찾기 해제") @DeleteMapping("/favorites") public ResponseEntity delete(@RequestBody FavoriteDeleteRequest favoriteDeleteRequest, - @Parameter(hidden = true) @MemberAuth Long memberId) { + @Parameter(hidden = true) @MemberAuth MemberId memberId) { favoriteService.deleteFavorite(favoriteDeleteRequest, memberId); return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); } diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/api/member/MemberController.java b/app-api/src/main/java/com/parkingcomestrue/parking/api/member/MemberController.java index c74b6c90..7f31cb49 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/api/member/MemberController.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/api/member/MemberController.java @@ -2,6 +2,7 @@ import com.parkingcomestrue.parking.application.auth.AuthService; import com.parkingcomestrue.parking.application.member.MemberService; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.member.dto.MemberLoginRequest; import com.parkingcomestrue.parking.application.member.dto.MemberSignupRequest; import com.parkingcomestrue.parking.application.member.dto.PasswordChangeRequest; @@ -49,9 +50,9 @@ public ResponseEntity signIn(HttpServletResponse httpServletResponse, @Operation(summary = "비밀번호 변경", description = "비밀번호 변경") @PatchMapping("/member/password") - public ResponseEntity changePassword(@Parameter(hidden = true) @MemberAuth Long memberId, + public ResponseEntity changePassword(@Parameter(hidden = true) @MemberAuth MemberId memberId, @RequestBody PasswordChangeRequest request) { - memberService.changePassword(memberId, request); + memberService.changePassword(memberId.getId(), request); return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); } } diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/api/parking/ParkingController.java b/app-api/src/main/java/com/parkingcomestrue/parking/api/parking/ParkingController.java index fbbdef4b..a5e2da0d 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/api/parking/ParkingController.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/api/parking/ParkingController.java @@ -1,5 +1,6 @@ package com.parkingcomestrue.parking.api.parking; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.parking.ParkingService; import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse; import com.parkingcomestrue.parking.application.parking.dto.ParkingLotsResponse; @@ -30,7 +31,6 @@ public class ParkingController { public ResponseEntity findParking(@PathVariable Long parkingId) { ParkingDetailInfoResponse parkingDetailInfoResponse = parkingService.findParking(parkingId); return ResponseEntity.status(HttpStatus.OK).body(parkingDetailInfoResponse); - } @Operation(summary = "주차장 반경 조회", description = "주차장 반경 조회") @@ -38,7 +38,7 @@ public ResponseEntity findParking(@PathVariable Long public ResponseEntity find( @ParkingQuery ParkingQueryRequest parkingQueryRequest, @ParkingSearchCondition ParkingSearchConditionRequest parkingSearchConditionRequest, - @Parameter(hidden = true) @MemberAuth(nullable = true) Long parkingMemberId + @Parameter(hidden = true) @MemberAuth(nullable = true) MemberId parkingMemberId ) { ParkingLotsResponse parkingLots = parkingService.findParkingLots(parkingQueryRequest, parkingSearchConditionRequest, parkingMemberId); diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/api/review/ReviewController.java b/app-api/src/main/java/com/parkingcomestrue/parking/api/review/ReviewController.java index 15519927..e4534804 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/api/review/ReviewController.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/api/review/ReviewController.java @@ -1,5 +1,6 @@ package com.parkingcomestrue.parking.api.review; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.review.ReviewService; import com.parkingcomestrue.parking.application.review.dto.ReviewCreateRequest; import com.parkingcomestrue.parking.config.argumentresolver.MemberAuth; @@ -8,6 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; @@ -22,9 +24,9 @@ public class ReviewController { private final ReviewService reviewService; @Operation(summary = "리뷰 등록", description = "리뷰 등록") - @PostMapping("/parkings/{parkingId}/reviews") + @PostMapping(value = "/parkings/{parkingId}/reviews", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity createReview(@PathVariable Long parkingId, - @Parameter(hidden = true) @MemberAuth Long memberId, + @Parameter(hidden = true) @MemberAuth MemberId memberId, @ModelAttribute ReviewCreateRequest request) { Long reviewId = reviewService.createReview(parkingId, memberId, request); return ResponseEntity.status(HttpStatus.CREATED).body(reviewId); diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/api/searchcondition/SearchConditionController.java b/app-api/src/main/java/com/parkingcomestrue/parking/api/searchcondition/SearchConditionController.java index c2d231e0..c9b85c69 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/api/searchcondition/SearchConditionController.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/api/searchcondition/SearchConditionController.java @@ -1,11 +1,13 @@ package com.parkingcomestrue.parking.api.searchcondition; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.searchcondition.SearchConditionService; import com.parkingcomestrue.parking.application.searchcondition.dto.SearchConditionDto; import com.parkingcomestrue.parking.config.argumentresolver.MemberAuth; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -13,24 +15,22 @@ import org.springframework.web.bind.annotation.RestController; @Tag(name = "조회 조건 컨트롤러") +@RequiredArgsConstructor @RestController public class SearchConditionController { private final SearchConditionService searchConditionService; - public SearchConditionController(SearchConditionService searchConditionService) { - this.searchConditionService = searchConditionService; - } - @Operation(summary = "조회 조건 조회", description = "조회 조건 조회") @GetMapping("/search-condition") - public ResponseEntity loadSearchCondition(@Parameter(hidden = true) @MemberAuth Long memberId) { + public ResponseEntity loadSearchCondition( + @Parameter(hidden = true) @MemberAuth MemberId memberId) { return ResponseEntity.ok(searchConditionService.findSearchCondition(memberId)); } @Operation(summary = "조회 조건 수정", description = "조회 조건 수정") @PutMapping("/search-condition") - public ResponseEntity updateSearchCondition(@Parameter(hidden = true) @MemberAuth Long memberId, + public ResponseEntity updateSearchCondition(@Parameter(hidden = true) @MemberAuth MemberId memberId, SearchConditionDto request) { searchConditionService.updateSearchCondition(memberId, request); return ResponseEntity.status(HttpStatus.CREATED).build(); diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/auth/AuthService.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/auth/AuthService.java index bffb26d0..9cc42122 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/application/auth/AuthService.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/auth/AuthService.java @@ -48,6 +48,13 @@ public String createSession(Long memberId) { return memberSession.getSessionId(); } + @Transactional + public void findAndUpdateSession(String sessionId) { + MemberSession session = findSession(sessionId); + session.updateExpiredAt(LocalDateTime.now().plusMinutes(DURATION_MINUTE)); + memberSessionRepository.save(session); + } + @Transactional(readOnly = true) public MemberSession findSession(String sessionId) { return memberSessionRepository.findBySessionIdAndExpiredAtIsGreaterThanEqual(sessionId, @@ -55,12 +62,6 @@ public MemberSession findSession(String sessionId) { .orElseThrow(() -> new ClientException(ClientExceptionInformation.UNAUTHORIZED)); } - @Transactional - public void updateSessionExpiredAt(MemberSession session) { - session.updateExpiredAt(LocalDateTime.now().plusMinutes(DURATION_MINUTE)); - memberSessionRepository.save(session); - } - @Transactional public String createAuthCode(AuthCodeRequest authCodeRequest) { String destination = authCodeRequest.getDestination(); diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/favorite/FavoriteService.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/favorite/FavoriteService.java index b8205282..9f11a0db 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/application/favorite/FavoriteService.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/favorite/FavoriteService.java @@ -1,10 +1,11 @@ package com.parkingcomestrue.parking.application.favorite; -import com.parkingcomestrue.parking.application.favorite.dto.FavoriteCreateRequest; -import com.parkingcomestrue.parking.application.favorite.dto.FavoriteDeleteRequest; import com.parkingcomestrue.common.domain.favorite.Favorite; import com.parkingcomestrue.common.domain.favorite.repository.FavoriteRepository; import com.parkingcomestrue.common.support.Association; +import com.parkingcomestrue.parking.application.favorite.dto.FavoriteCreateRequest; +import com.parkingcomestrue.parking.application.favorite.dto.FavoriteDeleteRequest; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DataIntegrityViolationException; @@ -19,10 +20,10 @@ public class FavoriteService { private final FavoriteRepository favoriteRepository; - public void createFavorite(FavoriteCreateRequest favoriteCreateRequest, Long memberId) { + public void createFavorite(FavoriteCreateRequest favoriteCreateRequest, MemberId memberId) { Long parkingId = favoriteCreateRequest.getParkingId(); - Favorite favorite = new Favorite(Association.from(memberId), Association.from(parkingId)); + Favorite favorite = new Favorite(Association.from(memberId.getId()), Association.from(parkingId)); saveFavorite(favorite); } @@ -35,9 +36,10 @@ private void saveFavorite(Favorite favorite) { } } - public void deleteFavorite(FavoriteDeleteRequest favoriteDeleteRequest, Long memberId) { + public void deleteFavorite(FavoriteDeleteRequest favoriteDeleteRequest, MemberId memberId) { Long parkingId = favoriteDeleteRequest.getParkingId(); - favoriteRepository.deleteByMemberIdAndParkingId(Association.from(memberId), Association.from(parkingId)); + favoriteRepository.deleteByMemberIdAndParkingId(Association.from(memberId.getId()), + Association.from(parkingId)); } } diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/member/MemberService.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/member/MemberService.java index b5bee195..14766bcc 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/application/member/MemberService.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/member/MemberService.java @@ -1,12 +1,12 @@ package com.parkingcomestrue.parking.application.member; +import com.parkingcomestrue.common.domain.member.Member; +import com.parkingcomestrue.common.domain.member.Password; +import com.parkingcomestrue.common.domain.member.repository.MemberRepository; import com.parkingcomestrue.parking.application.member.dto.MemberInfoResponse; import com.parkingcomestrue.parking.application.member.dto.MemberLoginRequest; import com.parkingcomestrue.parking.application.member.dto.MemberSignupRequest; import com.parkingcomestrue.parking.application.member.dto.PasswordChangeRequest; -import com.parkingcomestrue.common.domain.member.Member; -import com.parkingcomestrue.common.domain.member.repository.MemberRepository; -import com.parkingcomestrue.common.domain.member.Password; import com.parkingcomestrue.parking.support.exception.ClientException; import com.parkingcomestrue.parking.support.exception.ClientExceptionInformation; import org.springframework.stereotype.Service; diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/member/dto/MemberId.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/member/dto/MemberId.java new file mode 100644 index 00000000..aa7d465d --- /dev/null +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/member/dto/MemberId.java @@ -0,0 +1,21 @@ +package com.parkingcomestrue.parking.application.member.dto; + +import lombok.Getter; + +@Getter +public class MemberId { + + private long id; + + private MemberId(long id) { + this.id = id; + } + + public static MemberId from(long id) { + return new MemberId(id); + } + + public boolean isGuestUser() { + return id < 0; + } +} diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/parking/ParkingService.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/parking/ParkingService.java index 5cfc9ea0..9b8272f4 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/application/parking/ParkingService.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/parking/ParkingService.java @@ -9,12 +9,13 @@ import com.parkingcomestrue.common.domain.parking.ParkingFeeCalculator; import com.parkingcomestrue.common.domain.parking.ParkingType; import com.parkingcomestrue.common.domain.parking.PayType; -import com.parkingcomestrue.common.domain.parking.service.SearchingCondition; import com.parkingcomestrue.common.domain.parking.repository.ParkingRepository; import com.parkingcomestrue.common.domain.parking.service.ParkingFilteringService; +import com.parkingcomestrue.common.domain.parking.service.SearchingCondition; import com.parkingcomestrue.common.domain.searchcondition.FeeType; import com.parkingcomestrue.common.support.Association; import com.parkingcomestrue.parking.application.SearchConditionMapper; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse; import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse.FeeInfo; import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse.HolidayOperatingTime; @@ -51,7 +52,7 @@ public class ParkingService { @Transactional(readOnly = true) public ParkingLotsResponse findParkingLots(ParkingQueryRequest parkingQueryRequest, ParkingSearchConditionRequest parkingSearchConditionRequest, - Long memberId) { + MemberId memberId) { LocalDateTime now = LocalDateTime.now(); Location destination = Location.of(parkingQueryRequest.getLongitude(), parkingQueryRequest.getLatitude()); @@ -72,11 +73,11 @@ public ParkingLotsResponse findParkingLots(ParkingQueryRequest parkingQueryReque return new ParkingLotsResponse(parkingResponses); } - private List findMemberFavorites(Long memberId) { - if (memberId == null) { + private List findMemberFavorites(MemberId memberId) { + if (memberId.isGuestUser()) { return Collections.emptyList(); } - return favoriteRepository.findByMemberId(Association.from(memberId)); + return favoriteRepository.findByMemberId(Association.from(memberId.getId())); } private List findParkingLotsByOrderCondition(String priority, ParkingQueryRequest parkingQueryRequest, diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/review/ReviewService.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/review/ReviewService.java index 3f5040fa..03e4ed09 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/application/review/ReviewService.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/review/ReviewService.java @@ -1,5 +1,6 @@ package com.parkingcomestrue.parking.application.review; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.review.dto.ReviewCountResponse; import com.parkingcomestrue.parking.application.review.dto.ReviewCreateRequest; import com.parkingcomestrue.parking.application.review.dto.ReviewInfoResponse; @@ -24,10 +25,10 @@ public class ReviewService { private final ReviewDomainService reviewDomainService; @Transactional - public Long createReview(Long parkingId, Long reviewerId, ReviewCreateRequest request) { - reviewDomainService.validateDuplicateReview(Association.from(parkingId), Association.from(reviewerId)); + public Long createReview(Long parkingId, MemberId reviewerId, ReviewCreateRequest request) { + reviewDomainService.validateDuplicateReview(Association.from(parkingId), Association.from(reviewerId.getId())); - Review review = new Review(Association.from(parkingId), Association.from(reviewerId), request.toContents()); + Review review = new Review(Association.from(parkingId), Association.from(reviewerId.getId()), request.toContents()); reviewRepository.save(review); return review.getId(); } diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/review/dto/ReviewCreateRequest.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/review/dto/ReviewCreateRequest.java index f6b4a976..e3b6b2c6 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/application/review/dto/ReviewCreateRequest.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/review/dto/ReviewCreateRequest.java @@ -1,6 +1,8 @@ package com.parkingcomestrue.parking.application.review.dto; import com.parkingcomestrue.common.domain.review.Content; +import com.parkingcomestrue.common.support.exception.DomainException; +import com.parkingcomestrue.common.support.exception.DomainExceptionInformation; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -8,6 +10,9 @@ public record ReviewCreateRequest(List contents) { public Set toContents() { + if (contents == null) { + throw new DomainException(DomainExceptionInformation.INVALID_CONTENT); + } return contents.stream() .map(Content::find) .collect(Collectors.toSet()); diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/application/searchcondition/SearchConditionService.java b/app-api/src/main/java/com/parkingcomestrue/parking/application/searchcondition/SearchConditionService.java index 347c7d45..b56ada78 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/application/searchcondition/SearchConditionService.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/application/searchcondition/SearchConditionService.java @@ -1,6 +1,8 @@ package com.parkingcomestrue.parking.application.searchcondition; +import com.parkingcomestrue.common.domain.member.Member; import com.parkingcomestrue.parking.application.SearchConditionMapper; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.searchcondition.dto.SearchConditionDto; import com.parkingcomestrue.common.domain.parking.OperationType; import com.parkingcomestrue.common.domain.parking.ParkingType; @@ -26,8 +28,8 @@ public class SearchConditionService { private final SearchConditionRepository searchConditionRepository; private final SearchConditionMapper searchConditionMapper; - public SearchConditionDto findSearchCondition(Long memberId) { - SearchCondition searchCondition = searchConditionRepository.getByMemberId(memberId); + public SearchConditionDto findSearchCondition(MemberId memberId) { + SearchCondition searchCondition = searchConditionRepository.getByMemberId(Association.from(memberId.getId())); return toSearchConditionDto(searchCondition); } @@ -50,18 +52,18 @@ private List toDescriptions(Set } @Transactional - public void updateSearchCondition(Long memberId, SearchConditionDto searchConditionDto) { - SearchCondition newSearchCondition = createSearchCondition(memberId, searchConditionDto); + public void updateSearchCondition(MemberId memberId, SearchConditionDto searchConditionDto) { + SearchCondition newSearchCondition = createSearchCondition(Association.from(memberId.getId()), searchConditionDto); - searchConditionRepository.findByMemberId(memberId).ifPresentOrElse( + searchConditionRepository.findByMemberId(Association.from(memberId.getId())).ifPresentOrElse( existingSearchCondition -> existingSearchCondition.update(newSearchCondition), () -> searchConditionRepository.save(newSearchCondition) ); } - private SearchCondition createSearchCondition(Long memberId, SearchConditionDto searchConditionDto) { + private SearchCondition createSearchCondition(Association memberId, SearchConditionDto searchConditionDto) { return new SearchCondition( - Association.from(memberId), + memberId, searchConditionMapper.toEnums(OperationType.class, searchConditionDto.getOperationType()), searchConditionMapper.toEnums(ParkingType.class, searchConditionDto.getParkingType()), searchConditionMapper.toEnums(FeeType.class, searchConditionDto.getFeeType()), diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/config/argumentresolver/AuthArgumentResolver.java b/app-api/src/main/java/com/parkingcomestrue/parking/config/argumentresolver/AuthArgumentResolver.java index fa28a409..e83d1ab7 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/config/argumentresolver/AuthArgumentResolver.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/config/argumentresolver/AuthArgumentResolver.java @@ -1,7 +1,10 @@ package com.parkingcomestrue.parking.config.argumentresolver; -import com.parkingcomestrue.parking.application.auth.AuthService; import com.parkingcomestrue.common.domain.session.MemberSession; +import com.parkingcomestrue.parking.application.auth.AuthService; +import com.parkingcomestrue.parking.application.member.dto.MemberId; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; @@ -14,25 +17,34 @@ @Component public class AuthArgumentResolver implements HandlerMethodArgumentResolver { - private static final String JSESSIONID = "JSESSIONID"; private final AuthService authService; @Override public boolean supportsParameter(MethodParameter parameter) { - return parameter.hasParameterAnnotation(MemberAuth.class); + return parameter.getParameterType().equals(MemberId.class) && + parameter.hasParameterAnnotation(MemberAuth.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { MemberAuth memberAuth = parameter.getParameterAnnotation(MemberAuth.class); - String sessionId = webRequest.getHeader(JSESSIONID); + String sessionId = getJsessionid((HttpServletRequest) webRequest.getNativeRequest()); if (memberAuth.nullable() && sessionId == null) { - return null; + return MemberId.from(-1L); } MemberSession session = authService.findSession(sessionId); - return session.getMemberId(); + return MemberId.from(session.getMemberId()); + } + + private String getJsessionid(HttpServletRequest request) { + for (Cookie cookie : request.getCookies()) { + if (cookie.getName().equals(JSESSIONID)) { + return cookie.getValue(); + } + } + return null; } } diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/config/interceptor/AuthInterceptor.java b/app-api/src/main/java/com/parkingcomestrue/parking/config/interceptor/AuthInterceptor.java index 848879ce..0b08af4e 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/config/interceptor/AuthInterceptor.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/config/interceptor/AuthInterceptor.java @@ -2,6 +2,9 @@ import com.parkingcomestrue.parking.application.auth.AuthService; import com.parkingcomestrue.common.domain.session.MemberSession; +import com.parkingcomestrue.parking.support.exception.ClientException; +import com.parkingcomestrue.parking.support.exception.ClientExceptionInformation; +import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; @@ -21,9 +24,17 @@ public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { log.info("request: {}", request.getRequestURL()); - String sessionId = request.getHeader(JSESSIONID); - MemberSession session = authService.findSession(sessionId); - authService.updateSessionExpiredAt(session); + String sessionId = getJsessionid(request); + authService.findAndUpdateSession(sessionId); return true; } + + private String getJsessionid(HttpServletRequest request) { + for(Cookie cookie : request.getCookies()) { + if (cookie.getName().equals(JSESSIONID)) { + return cookie.getValue(); + } + } + throw new ClientException(ClientExceptionInformation.UNAUTHORIZED); + } } diff --git a/app-api/src/main/java/com/parkingcomestrue/parking/controlleradvice/GlobalExceptionHandler.java b/app-api/src/main/java/com/parkingcomestrue/parking/controlleradvice/GlobalExceptionHandler.java index 6d1a67d9..d7ac4165 100644 --- a/app-api/src/main/java/com/parkingcomestrue/parking/controlleradvice/GlobalExceptionHandler.java +++ b/app-api/src/main/java/com/parkingcomestrue/parking/controlleradvice/GlobalExceptionHandler.java @@ -1,6 +1,7 @@ package com.parkingcomestrue.parking.controlleradvice; import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.UNAUTHORIZED; import com.parkingcomestrue.parking.controlleradvice.dto.ExceptionResponse; @@ -30,16 +31,16 @@ public ResponseEntity handleException(final Exception e) { final ExceptionResponse exceptionResponse = new ExceptionResponse("알지 못하는 예외 발생"); log.error("알지 못하는 예외 발생", e); - return ResponseEntity.internalServerError() + return ResponseEntity.status(INTERNAL_SERVER_ERROR) .body(exceptionResponse); } @ExceptionHandler(DomainException.class) - public ResponseEntity handleServerException(final DomainException e) { + public ResponseEntity handleDomainException(final DomainException e) { final ExceptionResponse exceptionResponse = new ExceptionResponse(e.getMessage()); - log.error(e.getMessage(), e); + log.warn(e.getMessage(), e); - return ResponseEntity.internalServerError() + return ResponseEntity.status(BAD_REQUEST) .body(exceptionResponse); } diff --git a/app-api/src/test/java/com/parkingcomestrue/parking/application/auth/AuthServiceTest.java b/app-api/src/test/java/com/parkingcomestrue/parking/application/auth/AuthServiceTest.java index cd4ed735..6729d889 100644 --- a/app-api/src/test/java/com/parkingcomestrue/parking/application/auth/AuthServiceTest.java +++ b/app-api/src/test/java/com/parkingcomestrue/parking/application/auth/AuthServiceTest.java @@ -50,7 +50,7 @@ class AuthServiceTest extends ContainerTest { LocalDateTime originExpiredAt = originSession.getExpiredAt(); // when - authService.updateSessionExpiredAt(originSession); + authService.findAndUpdateSession(sessionId); MemberSession updatedSession = authService.findSession(sessionId); LocalDateTime updatedExpiredAt = updatedSession.getExpiredAt(); diff --git a/app-api/src/test/java/com/parkingcomestrue/parking/application/member/MemberServiceTest.java b/app-api/src/test/java/com/parkingcomestrue/parking/application/member/MemberServiceTest.java index 53635f62..b62c591e 100644 --- a/app-api/src/test/java/com/parkingcomestrue/parking/application/member/MemberServiceTest.java +++ b/app-api/src/test/java/com/parkingcomestrue/parking/application/member/MemberServiceTest.java @@ -4,12 +4,12 @@ import static com.parkingcomestrue.common.support.exception.DomainExceptionInformation.INVALID_PASSWORD; import static org.assertj.core.api.Assertions.assertThat; -import com.parkingcomestrue.parking.application.member.dto.MemberLoginRequest; -import com.parkingcomestrue.parking.application.member.dto.MemberSignupRequest; -import com.parkingcomestrue.parking.application.member.dto.PasswordChangeRequest; import com.parkingcomestrue.common.domain.member.Member; import com.parkingcomestrue.common.domain.member.repository.MemberRepository; import com.parkingcomestrue.common.support.exception.DomainException; +import com.parkingcomestrue.parking.application.member.dto.MemberLoginRequest; +import com.parkingcomestrue.parking.application.member.dto.MemberSignupRequest; +import com.parkingcomestrue.parking.application.member.dto.PasswordChangeRequest; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/app-api/src/test/java/com/parkingcomestrue/parking/application/parking/ParkingServiceTest.java b/app-api/src/test/java/com/parkingcomestrue/parking/application/parking/ParkingServiceTest.java index d1ddb3e6..6fb265fa 100644 --- a/app-api/src/test/java/com/parkingcomestrue/parking/application/parking/ParkingServiceTest.java +++ b/app-api/src/test/java/com/parkingcomestrue/parking/application/parking/ParkingServiceTest.java @@ -21,6 +21,7 @@ import com.parkingcomestrue.common.support.exception.DomainException; import com.parkingcomestrue.common.support.exception.DomainExceptionInformation; import com.parkingcomestrue.parking.application.ContainerTest; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse; import com.parkingcomestrue.parking.application.review.dto.ReviewCreateRequest; import java.time.LocalTime; @@ -52,7 +53,7 @@ class ParkingServiceTest extends ContainerTest { ReviewCreateRequest reviewCreateRequest = new ReviewCreateRequest( List.of(Content.LARGE_PARKING_SPACE.getDescription(), Content.EASY_TO_PAY.getDescription())); - reviewService.createReview(parking.getId(), member.getId(), reviewCreateRequest); + reviewService.createReview(parking.getId(), MemberId.from(member.getId()), reviewCreateRequest); // when, then ParkingDetailInfoResponse parkingDetailInfoResponse = parkingService.findParking(parking.getId()); diff --git a/app-api/src/test/java/com/parkingcomestrue/parking/application/review/ReviewServiceTest.java b/app-api/src/test/java/com/parkingcomestrue/parking/application/review/ReviewServiceTest.java index abc571bf..6500e53d 100644 --- a/app-api/src/test/java/com/parkingcomestrue/parking/application/review/ReviewServiceTest.java +++ b/app-api/src/test/java/com/parkingcomestrue/parking/application/review/ReviewServiceTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.SoftAssertions.assertSoftly; +import com.parkingcomestrue.parking.application.member.dto.MemberId; import com.parkingcomestrue.parking.application.review.dto.ReviewCreateRequest; import com.parkingcomestrue.parking.application.review.dto.ReviewInfoResponse; import com.parkingcomestrue.common.domain.member.Member; @@ -39,7 +40,7 @@ class ReviewServiceTest { ReviewCreateRequest request = new ReviewCreateRequest(List.of("주차 자리가 많아요", "결제가 편리해요")); //when - Long reviewId = reviewService.createReview(parking.getId(), reviewer.getId(), request); + Long reviewId = reviewService.createReview(parking.getId(), MemberId.from(reviewer.getId()), request); //then assertThat(reviewId).isNotNull(); @@ -51,10 +52,10 @@ class ReviewServiceTest { Parking parking = parkingRepository.saveAndGet(1).get(0); Member reviewer = memberRepository.saveAndGet(1).get(0); ReviewCreateRequest request = new ReviewCreateRequest(List.of("주차 자리가 많아요", "결제가 편리해요")); - reviewService.createReview(parking.getId(), reviewer.getId(), request); + reviewService.createReview(parking.getId(), MemberId.from(reviewer.getId()), request); //when, then - assertThatThrownBy(() -> reviewService.createReview(parking.getId(), reviewer.getId(), request)) + assertThatThrownBy(() -> reviewService.createReview(parking.getId(), MemberId.from(reviewer.getId()), request)) .isInstanceOf(DomainException.class) .hasMessage(DUPLICATE_REVIEW.getMessage()); } diff --git a/app-scheduler/src/test/java/com/parkingcomestrue/external/api/CircuitBreakerAspectTest.java b/app-scheduler/src/test/java/com/parkingcomestrue/external/api/CircuitBreakerAspectTest.java index a82fc94e..7bc77588 100644 --- a/app-scheduler/src/test/java/com/parkingcomestrue/external/api/CircuitBreakerAspectTest.java +++ b/app-scheduler/src/test/java/com/parkingcomestrue/external/api/CircuitBreakerAspectTest.java @@ -16,7 +16,7 @@ class CircuitBreakerAspectTest { /** * 요청 중 20%의 예외가 발생하면 api 요청 잠김 - * 잠긴 후, 2초 후에 다시 요청보내지도록 reset + * 잠긴 후, 200ms 후에 다시 요청보내지도록 reset */ @Autowired private CircuitBreakerTestService service; @@ -41,7 +41,7 @@ class CircuitBreakerAspectTest { } @Test - void 서비스가_잠긴후_특정시간이_지나면_다시_요청을_보낼수있다() throws ExecutionException, InterruptedException { + void 서비스가_잠긴후_특정시간이_지나면_다시_요청을_보낼수있다() throws InterruptedException { //given for (int i = 0; i < 8; i++) { service.call(() -> {}); @@ -49,12 +49,10 @@ class CircuitBreakerAspectTest { for (int i = 0; i < 2; i++) { service.call(() -> {throw new RuntimeException();}); } - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + Thread.sleep(1000); //when - ScheduledFuture future = scheduler.schedule(() -> service.call(() -> isExecuted[1] = true), 2, - TimeUnit.SECONDS); - future.get(); + service.call(() -> isExecuted[1] = true); //then Assertions.assertThat(isExecuted[1]).isTrue(); diff --git a/app-scheduler/src/test/java/com/parkingcomestrue/fake/CircuitBreakerTestService.java b/app-scheduler/src/test/java/com/parkingcomestrue/fake/CircuitBreakerTestService.java index 7137e307..925978fe 100644 --- a/app-scheduler/src/test/java/com/parkingcomestrue/fake/CircuitBreakerTestService.java +++ b/app-scheduler/src/test/java/com/parkingcomestrue/fake/CircuitBreakerTestService.java @@ -3,12 +3,11 @@ import com.parkingcomestrue.external.api.CircuitBreaker; import java.util.concurrent.TimeUnit; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; @Component public class CircuitBreakerTestService { - @CircuitBreaker(resetTime = 2, timeUnit = TimeUnit.SECONDS) + @CircuitBreaker(resetTime = 200, timeUnit = TimeUnit.MILLISECONDS) public void call(Runnable runnable) { runnable.run(); } diff --git a/domain/src/main/java/com/parkingcomestrue/common/domain/parking/TimeInfo.java b/domain/src/main/java/com/parkingcomestrue/common/domain/parking/TimeInfo.java index be58f636..3510809e 100644 --- a/domain/src/main/java/com/parkingcomestrue/common/domain/parking/TimeInfo.java +++ b/domain/src/main/java/com/parkingcomestrue/common/domain/parking/TimeInfo.java @@ -24,6 +24,11 @@ public class TimeInfo { private LocalTime endTime; public TimeInfo(LocalTime beginTime, LocalTime endTime) { + if (beginTime == null || endTime == null) { + this.beginTime = CLOSED.beginTime; + this.endTime = CLOSED.endTime; + return; + } this.beginTime = beginTime; this.endTime = endTime; } diff --git a/domain/src/main/java/com/parkingcomestrue/common/domain/review/Review.java b/domain/src/main/java/com/parkingcomestrue/common/domain/review/Review.java index 0a7c0b45..ceee31cf 100644 --- a/domain/src/main/java/com/parkingcomestrue/common/domain/review/Review.java +++ b/domain/src/main/java/com/parkingcomestrue/common/domain/review/Review.java @@ -13,6 +13,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.Table; import java.time.LocalDateTime; import java.util.Set; import lombok.AccessLevel; @@ -22,6 +24,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity +@Table(indexes = @Index(name = "review_ux_parking_id_reviewer_id", columnList = "parking_id, reviewer_id", unique = true)) public class Review { private static final int MAX_CONTENTS_SIZE = 3; diff --git a/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/SearchCondition.java b/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/SearchCondition.java index 5da57066..977e0fbc 100644 --- a/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/SearchCondition.java +++ b/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/SearchCondition.java @@ -18,6 +18,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.Table; import java.util.Set; import lombok.AccessLevel; import lombok.Getter; @@ -26,6 +28,7 @@ @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(indexes = @Index(name = "search_condition_ux_member_id", columnList = "member_id", unique = true)) public class SearchCondition { @Id diff --git a/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/repository/SearchConditionRepository.java b/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/repository/SearchConditionRepository.java index 2e1a9c89..00eb92e9 100644 --- a/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/repository/SearchConditionRepository.java +++ b/domain/src/main/java/com/parkingcomestrue/common/domain/searchcondition/repository/SearchConditionRepository.java @@ -1,6 +1,8 @@ package com.parkingcomestrue.common.domain.searchcondition.repository; +import com.parkingcomestrue.common.domain.member.Member; import com.parkingcomestrue.common.domain.searchcondition.SearchCondition; +import com.parkingcomestrue.common.support.Association; import com.parkingcomestrue.common.support.exception.DomainException; import com.parkingcomestrue.common.support.exception.DomainExceptionInformation; import java.util.Optional; @@ -8,9 +10,9 @@ public interface SearchConditionRepository extends Repository { - Optional findByMemberId(Long memberId); + Optional findByMemberId(Association memberId); - default SearchCondition getByMemberId(Long memberId) { + default SearchCondition getByMemberId(Association memberId) { return findByMemberId(memberId) .orElseThrow(() -> new DomainException(DomainExceptionInformation.INVALID_SEARCH_CONDITION)); } diff --git a/domain/src/main/resources/db/migration/mysql/V5.0.1__add_index.sql b/domain/src/main/resources/db/migration/mysql/V5.0.1__add_index.sql new file mode 100644 index 00000000..dd6ad2aa --- /dev/null +++ b/domain/src/main/resources/db/migration/mysql/V5.0.1__add_index.sql @@ -0,0 +1,5 @@ +ALTER TABLE parking MODIFY COLUMN location POINT NOT NULL SRID 4326; + +CREATE SPATIAL INDEX parking_ix_location ON parking (location); +CREATE UNIQUE INDEX search_condition_ux_member_id ON search_condition (member_id); +CREATE UNIQUE INDEX review_ux_parking_id_reviewer_id ON review (parking_id, reviewer_id); diff --git a/domain/src/testFixtures/java/repository/FakeSearchConditionRepository.java b/domain/src/testFixtures/java/repository/FakeSearchConditionRepository.java deleted file mode 100644 index 49ba4552..00000000 --- a/domain/src/testFixtures/java/repository/FakeSearchConditionRepository.java +++ /dev/null @@ -1,18 +0,0 @@ -package repository; - -import com.parkingcomestrue.common.domain.searchcondition.SearchCondition; -import com.parkingcomestrue.common.domain.searchcondition.repository.SearchConditionRepository; -import java.util.Optional; - -public class FakeSearchConditionRepository implements SearchConditionRepository { - - @Override - public Optional findByMemberId(Long memberId) { - return Optional.empty(); - } - - @Override - public void save(SearchCondition searchCondition) { - - } -}