diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoTestController.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoTestController.java index aefab7d9..cc46af58 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoTestController.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoTestController.java @@ -2,27 +2,99 @@ import com.back.web7_9_codecrete_be.domain.location.dto.KakaoLocalResponse; import com.back.web7_9_codecrete_be.domain.location.service.KakaoLocalService; +import com.back.web7_9_codecrete_be.global.rsData.RsData; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.List; +@Tag(name = "Location - Kakao", description = "카카오 로컬 API 연동(주변 음식점 조회, 좌표→주소 변환) 관련 엔드포인트") @RestController -@RequestMapping("/api/test") +@RequestMapping("/api/v1/location/kakao") @RequiredArgsConstructor public class KakaoTestController { private final KakaoLocalService kakaoLocalService; - @GetMapping("/kakao-restaurants") + @Operation( + summary = "주변 음식점 조회(테스트)", + description = "테스트용 하드코딩 좌표(서울 시청 근처)로 카카오 로컬에서 주변 음식점을 조회합니다., 하드코딩 좌표 : lat - 37.5665, lng -126.9780" + ) + @ApiResponse(responseCode = "200", description = "조회 성공", + content = @Content(schema = @Schema(implementation = KakaoLocalResponse.Document.class))) + @GetMapping("/restaurants") + public List testKakaoRestaurants() { - // ✅ 테스트용 하드코딩 좌표 (서울 시청 근처) double lat = 37.5665; double lng = 126.9780; return kakaoLocalService.searchNearbyRestaurants(lat, lng); } + + @Operation( + summary = "주변 음식점 조회(테스트)", + description = "테스트용 좌표(서울 시청 근처)로 카카오 로컬에서 주변 음식점을 조회합니다, 좌표는 입력하면 됩니다." + + "예시 : http://localhost:8080/api/v1/location/kakao/restaurant?lat=37.5665&lng=126.9780" + ) + @PostMapping("/restaurant") + public List KakaoRestaurants( + @RequestParam double lat, + @RequestParam double lng + ){ + return kakaoLocalService.searchNearbyRestaurants(lat, lng); + } + + @Operation( + summary = "주변 카페 조회(테스트)", + description = "테스트용 하드코딩 좌표(서울 시청 근처)로 카카오 로컬에서 주변 카페를 조회합니다., 하드코딩 좌표 : lat - 37.5665, lng -126.9780" + ) + @ApiResponse(responseCode = "200", description = "조회 성공", + content = @Content(schema = @Schema(implementation = KakaoLocalResponse.Document.class))) + @GetMapping("/cafes") + public List testKakaoCafes() { + + double lat = 37.5665; + double lng = 126.9780; + + return kakaoLocalService.searchNearbyCafes(lat, lng); + } + + @Operation( + summary = "주변 카페 조회(테스트)", + description = "테스트용 좌표(서울 시청 근처)로 카카오 로컬에서 주변 카페를 조회합니다, 좌표는 입력하면 됩니다." + + "예시 : http://localhost:8080/api/v1/location/kakao/cafes?lat=37.5665&lng=126.9780" + ) + @PostMapping("/cafes") + public List KakaoCafes( + @RequestParam double lat, + @RequestParam double lng + ){ + return kakaoLocalService.searchNearbyCafes(lat, lng); + } + + + @Operation( + summary = "좌표를 주소로 변환", + description = "위도(lat), 경도(lon)를 받아 카카오 API로 주소명(address_name)을 반환합니다." + ) + @ApiResponse(responseCode = "200", description = "변환 성공", + content = @Content(schema = @Schema(implementation = RsData.class))) + @GetMapping("/coord2address") + public RsData coord2Address( + @Parameter(description = "위도(latitude)", example = "37.5665", required = true) + @RequestParam double lat, + + @Parameter(description = "경도(longitude)", example = "126.9780", required = true) + @RequestParam double lon + ) { + String addressName = kakaoLocalService.coordinateToAddressName(lat, lon); + return RsData.success("좌표를 주소로 변환했습니다.", addressName); + } } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/LocationController.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/LocationController.java index fe1872d0..b38a28c3 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/LocationController.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/LocationController.java @@ -1,15 +1,59 @@ package com.back.web7_9_codecrete_be.domain.location.controller; +import com.back.web7_9_codecrete_be.domain.location.dto.request.LocationRequestDto; +import com.back.web7_9_codecrete_be.domain.location.dto.response.LocationResponseDto; import com.back.web7_9_codecrete_be.domain.location.service.LocationService; +import com.back.web7_9_codecrete_be.domain.users.entity.User; +import com.back.web7_9_codecrete_be.global.rq.Rq; +import com.back.web7_9_codecrete_be.global.rsData.RsData; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController -@RequestMapping("/api/v1/location") +@RequestMapping("/api/v1/location/my") @RequiredArgsConstructor +@Tag(name = "Location", description = "위치(Location) 관련 API") public class LocationController { private final LocationService locationService; + private final Rq rq; + @GetMapping() + @Operation(summary = "사용자 위치 조회", description = "사용자의 위치 정보를 조회합니다.") + public RsData getMyLocation( + ){ + User user = rq.getUser(); + return RsData.success("내 위치정보를 조회합니다", locationService.getLocation(user)); + } + + + @PostMapping() + @Operation(summary = "사용자 위치 저장", description = "사용자의 위치 정보를 저장합니다.") + public RsData saveMyLocation( + @RequestBody LocationRequestDto locationRequestDto + ){ + User user = rq.getUser(); + return RsData.success("내 위치정보를 저장했습니다.", locationService.saveLocation(locationRequestDto, user)); + } + + + @PatchMapping + @Operation(summary = "사용자 위치 수정", description = "사용자의 위치 정보를 수정합니다.") + public RsData modifyMyLocation( + @RequestBody LocationRequestDto locationRequestDto + ){ + User user = rq.getUser(); + return RsData.success("내 위치정보를 수정했습니다.", locationService.modifyLocation(locationRequestDto, user)); + } + + @DeleteMapping + @Operation(summary = "사용자 위치 삭제", description = "사용자의 위치 정보를 삭제합니다.") + public RsData deleteMyLocation( + ){ + User user = rq.getUser(); + locationService.removeLocation(user); + return RsData.success("내 위치정보를 삭제했습니다.", null); + } } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/TmapController.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/TmapController.java index 46551541..6119270f 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/TmapController.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/TmapController.java @@ -1,26 +1,74 @@ package com.back.web7_9_codecrete_be.domain.location.controller; import com.back.web7_9_codecrete_be.domain.location.service.TmapService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +@Tag( + name = "Location - Tmap", + description = "Tmap 대중교통 길찾기 API 연동" +) @RestController @RequiredArgsConstructor -@RequestMapping("/api/tmap") +@RequestMapping("/api/v1/location") public class TmapController { private final TmapService tmapService; - @GetMapping("/transit") + @Operation( + summary = "대중교통 경로 조회", + description = """ + 출발지(startX, startY)와 도착지(endX, endY) 좌표를 기반으로 + Tmap 대중교통 API를 호출하여 경로 정보를 조회합니다. + """ + ) + @ApiResponse( + responseCode = "200", + description = "경로 조회 성공", + content = @Content( + mediaType = "application/json", + schema = @Schema( + description = "Tmap 대중교통 경로 조회 결과(JSON 문자열)" + ) + ) + ) + @GetMapping("/tmap/transit") public String getTransit( + + @Parameter( + description = "출발지 경도 (longitude)", + example = "126.9780", + required = true + ) @RequestParam double startX, + + @Parameter( + description = "출발지 위도 (latitude)", + example = "37.5665", + required = true + ) @RequestParam double startY, + + @Parameter( + description = "도착지 경도 (longitude)", + example = "127.0276", + required = true + ) @RequestParam double endX, + + @Parameter( + description = "도착지 위도 (latitude)", + example = "37.4979", + required = true + ) @RequestParam double endY ) { return tmapService.getRoute(startX, startY, endX, endY); } -} \ No newline at end of file +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoCoordinateResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoCoordinateResponse.java new file mode 100644 index 00000000..d2dab475 --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoCoordinateResponse.java @@ -0,0 +1,71 @@ +package com.back.web7_9_codecrete_be.domain.location.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +@Schema(description = "카카오 좌표 → 주소 변환 응답 DTO") +public class KakaoCoordinateResponse { + + @Schema( + description = "주소 변환 결과 목록", + example = "[]" + ) + private List documents; + + @Data + @Schema(description = "좌표 변환 결과 문서") + public static class Document { + + @Schema(description = "지번 주소 정보") + private Address address; + + @Schema(description = "도로명 주소 정보") + private RoadAddress road_address; + } + + @Data + @Schema(description = "지번 주소 상세 정보") + public static class Address { + + @Schema(description = "전체 지번 주소", example = "서울 중구 태평로1가 31") + private String address_name; + + @Schema(description = "시/도", example = "서울") + private String region_1depth_name; + + @Schema(description = "구", example = "중구") + private String region_2depth_name; + + @Schema(description = "동", example = "태평로1가") + private String region_3depth_name; + + @Schema(description = "산 여부 (Y/N)", example = "N") + private String mountain_yn; + + @Schema(description = "본번", example = "31") + private String main_address_no; + + @Schema(description = "부번", example = "0") + private String sub_address_no; + } + + @Data + @Schema(description = "도로명 주소 상세 정보") + public static class RoadAddress { + + @Schema(description = "전체 도로명 주소", example = "서울 중구 세종대로 110") + private String address_name; + + @Schema(description = "도로명", example = "세종대로") + private String road_name; + + @Schema(description = "건물명", example = "서울시청") + private String building_name; + + @Schema(description = "우편번호", example = "04524") + private String zone_no; + } +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoLocalResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoLocalResponse.java index c66f8318..46dcaf31 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoLocalResponse.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoLocalResponse.java @@ -1,20 +1,37 @@ package com.back.web7_9_codecrete_be.domain.location.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data +@Schema(description = "카카오 로컬 API 장소 검색 응답 DTO") public class KakaoLocalResponse { + + @Schema(description = "장소 검색 결과 목록") private List documents; @Data + @Schema(description = "카카오 장소 정보") public static class Document { + + @Schema(description = "장소명", example = "디라이프 스타일키친 광화문점") private String place_name; - private String x; // longitude - private String y; // latitude + + @Schema(description = "경도(longitude)", example = "126.97826128583668") + private String x; + + @Schema(description = "위도(latitude)", example = "37.56842610180289") + private String y; + + @Schema(description = "도로명 주소", example = "서울 중구 세종대로 136") private String road_address_name; + + @Schema(description = "지번 주소", example = "서울 중구 태평로1가 84") private String address_name; + + @Schema(description = "카카오 장소 상세 URL", example = "http://place.map.kakao.com/444516464") private String place_url; } -} \ No newline at end of file +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/TmapResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/TmapResponse.java index 2e248d8a..87121037 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/TmapResponse.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/TmapResponse.java @@ -1,15 +1,31 @@ package com.back.web7_9_codecrete_be.domain.location.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data +@Schema(description = "Tmap 대중교통 경로 조회 요청 DTO") public class TmapResponse { + @Schema(description = "출발지 경도 (longitude)", example = "126.9780") private String startX; + + @Schema(description = "출발지 위도 (latitude)", example = "37.5665") private String startY; + + @Schema(description = "도착지 경도 (longitude)", example = "127.0276") private String endX; + + @Schema(description = "도착지 위도 (latitude)", example = "37.4979") private String endY; - private int count; //최대 응답 결과 개수 - private String format; //출력포멧 : jsom, xml + @Schema(description = "최대 응답 결과 개수", example = "5") + private int count; + + @Schema( + description = "응답 포맷 (json / xml)", + example = "json", + allowableValues = {"json", "xml"} + ) + private String format; } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/request/LocationRequestDto.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/request/LocationRequestDto.java new file mode 100644 index 00000000..ae83bb9d --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/request/LocationRequestDto.java @@ -0,0 +1,16 @@ +package com.back.web7_9_codecrete_be.domain.location.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema(description = "위치 요청 DTO") +public class LocationRequestDto { + + @Schema(description = "위도", example = "37.566535") + private double lat; + + @Schema(description = "경도", example = "126.9779692") + private double lon; + +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/LocationResponseDto.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/LocationResponseDto.java new file mode 100644 index 00000000..075576ac --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/LocationResponseDto.java @@ -0,0 +1,30 @@ +package com.back.web7_9_codecrete_be.domain.location.dto.response; + +import com.back.web7_9_codecrete_be.domain.location.entity.Location; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + + +@Getter +@AllArgsConstructor +@Schema(description = "위치 응답 DTO") +public class LocationResponseDto { + + @Schema(description = "위도", example = "37.566535") + private double lat; + @Schema(description = "경도", example = "126.9779692") + private double lon; + @Schema(description = "주소", example = "서울특별시 중구 세종대로 110") + private String address; + + + public static LocationResponseDto from(Location location) { + return new LocationResponseDto( + location.getLat(), + location.getLon(), + location.getAddress() + ); + } +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/entity/Location.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/entity/Location.java index a70fdba4..eae569fc 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/entity/Location.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/entity/Location.java @@ -1,6 +1,7 @@ package com.back.web7_9_codecrete_be.domain.location.entity; +import com.back.web7_9_codecrete_be.domain.users.entity.User; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; @@ -18,11 +19,11 @@ public class Location { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // TODO : 추후 user Entity 보고 확인 예정 우선 주석 처리 -/* + @ManyToOne @JoinColumn(name="user_id", nullable = false) private User user; -*/ + @Column(length = 255) private String address; @@ -32,4 +33,33 @@ public class Location { private double lat; private double lon; + + + @PrePersist + public void prePersist() { + this.modified_date = LocalDateTime.now(); // ⭐ insert 때도 채움 + } + + @PreUpdate + public void preUpdate() { + this.modified_date = LocalDateTime.now(); + } + + protected Location(User user, double lat, double lon, String address) { + this.user = user; + this.lat = lat; + this.lon = lon; + this.address = address; + } + + public static Location create(User user, double lat, double lon, String addressName) { + return new Location(user, lat, lon, addressName); + } + + public void update(double lat, double lon, String address) { + + this.lat = lat; + this.lon = lon; + this.address = address; + } } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/repository/LocationRepository.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/repository/LocationRepository.java index 7c68fd91..3c526aa9 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/repository/LocationRepository.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/repository/LocationRepository.java @@ -1,7 +1,13 @@ package com.back.web7_9_codecrete_be.domain.location.repository; import com.back.web7_9_codecrete_be.domain.location.entity.Location; +import com.back.web7_9_codecrete_be.domain.users.entity.User; import org.springframework.data.jpa.repository.JpaRepository; public interface LocationRepository extends JpaRepository { + + + Location findByUser(User user); + + boolean existsByUser(User user); } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java index e6ff9ffb..b8299297 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java @@ -1,6 +1,9 @@ package com.back.web7_9_codecrete_be.domain.location.service; +import com.back.web7_9_codecrete_be.domain.location.dto.KakaoCoordinateResponse; import com.back.web7_9_codecrete_be.domain.location.dto.KakaoLocalResponse; +import com.back.web7_9_codecrete_be.global.error.code.LocationErrorCode; +import com.back.web7_9_codecrete_be.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; @@ -22,6 +25,7 @@ public List searchNearbyRestaurants(double lat, dou .queryParam("y", lat) .queryParam("x", lng) .queryParam("radius", 1000) // 반경 1km + .queryParam("sort", "distance") .build() ) .retrieve() @@ -29,4 +33,56 @@ public List searchNearbyRestaurants(double lat, dou .block() // 동기 호출 (필요하면 비동기로 변경 가능) .getDocuments(); } + public List searchNearbyCafes(double lat, double lng) { + + return kakaoWebClient.get() + .uri(uriBuilder -> uriBuilder + .path("/v2/local/search/keyword.json") + .queryParam("query", "카페") + .queryParam("category_group_code", "CE7") + .queryParam("y", lat) + .queryParam("x", lng) + .queryParam("radius", 1000) // 반경 1km + .queryParam("sort", "distance") + .build() + ) + .retrieve() + .bodyToMono(KakaoLocalResponse.class) + .block() // 동기 호출 (필요하면 비동기로 변경 가능) + .getDocuments(); + } + + public String coordinateToAddressName(double lat, double lng) { + + KakaoCoordinateResponse response = kakaoWebClient.get() + .uri(uriBuilder -> uriBuilder + .path("/v2/local/geo/coord2address.json") + .queryParam("x", lng) + .queryParam("y", lat) + .build() + ) + .retrieve() + .bodyToMono(KakaoCoordinateResponse.class) + .block(); + + if (response == null || response.getDocuments() == null || response.getDocuments().isEmpty()) { + throw new BusinessException(LocationErrorCode.ADDRESS_NOT_FOUND); + } + + KakaoCoordinateResponse.Document doc = response.getDocuments().get(0); + + String addressName = null; + if (doc.getRoad_address() != null && doc.getRoad_address().getAddress_name() != null) { + addressName = doc.getRoad_address().getAddress_name(); + } else if (doc.getAddress() != null) { + addressName = doc.getAddress().getAddress_name(); + } + + if (addressName == null || addressName.isBlank()) { + throw new BusinessException(LocationErrorCode.ADDRESS_NOT_FOUND); + } + + return addressName; + } + } \ No newline at end of file diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/LocationService.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/LocationService.java index f4217e5b..262dcaa2 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/LocationService.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/LocationService.java @@ -1,13 +1,92 @@ package com.back.web7_9_codecrete_be.domain.location.service; +import com.back.web7_9_codecrete_be.domain.location.dto.KakaoLocalResponse; +import com.back.web7_9_codecrete_be.domain.location.dto.request.LocationRequestDto; +import com.back.web7_9_codecrete_be.domain.location.dto.response.LocationResponseDto; +import com.back.web7_9_codecrete_be.domain.location.entity.Location; import com.back.web7_9_codecrete_be.domain.location.repository.LocationRepository; +import com.back.web7_9_codecrete_be.domain.users.entity.User; +import com.back.web7_9_codecrete_be.domain.users.repository.UserRepository; +import com.back.web7_9_codecrete_be.global.error.code.AuthErrorCode; +import com.back.web7_9_codecrete_be.global.error.code.LocationErrorCode; +import com.back.web7_9_codecrete_be.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor public class LocationService { private final LocationRepository locationRepository; + private final KakaoLocalService kakaoLocalService; + + @Transactional(readOnly = true) + public LocationResponseDto getLocation(User user){ //내 위치 불러오기 + + Location location =locationRepository.findByUser(user); + if(location == null){ + throw new BusinessException(LocationErrorCode.LOCATION_NOT_FOUND); + } + + return LocationResponseDto.from(location); + } + + @Transactional + public LocationResponseDto saveLocation(LocationRequestDto locationRequestDto, User user){ //내 위치 저장 + //예외 처리할 것: 내 위치가 저장되어있는지 확인 //로그인 되어있는지 확인 //추가하면 좋을것? 이게 대한민국의 좌표인지 + validateKoreaCoordinate(locationRequestDto.getLat(), locationRequestDto.getLon()); + + if (locationRepository.existsByUser(user)) { + throw new BusinessException(LocationErrorCode.LOCATION_ALREADY_EXISTS); + } + String addressName = kakaoLocalService.coordinateToAddressName(locationRequestDto.getLat(), locationRequestDto.getLon()); + if (addressName == null || addressName.isBlank()) { + throw new BusinessException(LocationErrorCode.LOCATION_NOT_EXIST_IN_KAKAO); + } + Location location = Location.create(user, locationRequestDto.getLat(), locationRequestDto.getLon(), addressName); + locationRepository.save(location); + return LocationResponseDto.from(location); + } + + @Transactional + public LocationResponseDto modifyLocation(LocationRequestDto locationRequestDto, User user){ //내 위치 수정 + + Location location = locationRepository.findByUser(user); + if(location == null) + throw new BusinessException(LocationErrorCode.LOCATION_NOT_FOUND); + + String addressName = kakaoLocalService.coordinateToAddressName(locationRequestDto.getLat(), locationRequestDto.getLon()); + + if (addressName == null || addressName.isBlank()) { + throw new BusinessException(LocationErrorCode.LOCATION_NOT_EXIST_IN_KAKAO); + } + + location.update(locationRequestDto.getLat(), locationRequestDto.getLon(), addressName); + location.preUpdate(); + return LocationResponseDto.from(location); + } + + @Transactional + public void removeLocation(User user){ //내 위치 삭제 + Location location = locationRepository.findByUser(user); + if(location == null){ + throw new BusinessException(LocationErrorCode.LOCATION_NOT_HAVE); + } + locationRepository.delete(location); + } + +// public User getUserEntity(Long userId){ //userId를 이용해서 User 객체 가져오기 +// return userRepository.findById(userId).orElseThrow( +// () -> new BusinessException(AuthErrorCode.UNAUTHORIZED_USER) +// ); +// } + + + private void validateKoreaCoordinate(double lat, double lon) { + if (lat < 33.0 || lat > 39.5 || lon < 124.0 || lon > 132.0) { + throw new BusinessException(LocationErrorCode.INVALID_KOREA_COORDINATE); + } + } } diff --git a/src/main/java/com/back/web7_9_codecrete_be/global/error/code/LocationErrorCode.java b/src/main/java/com/back/web7_9_codecrete_be/global/error/code/LocationErrorCode.java new file mode 100644 index 00000000..c18a2bcd --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/global/error/code/LocationErrorCode.java @@ -0,0 +1,22 @@ +package com.back.web7_9_codecrete_be.global.error.code; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum LocationErrorCode implements ErrorCode{ + + LOCATION_NOT_FOUND(HttpStatus.NOT_FOUND, "L-100", "위치(좌표)를 찾을 수 없습니다."), + ADDRESS_NOT_FOUND(HttpStatus.NOT_FOUND, "L-101" , "위치(주소)를 찾을 수 없습니다."), + LOCATION_ALREADY_EXISTS(HttpStatus.NOT_FOUND, "L-102", "이미 저장되어있는 위치입니다."), + INVALID_KOREA_COORDINATE(HttpStatus.NOT_FOUND, "L-103" , "한국 좌표가 아닙니다"), + LOCATION_NOT_EXIST_IN_KAKAO(HttpStatus.NOT_FOUND, "L-104", "해당 좌표는 카카오에 등록되어있지 않습니다."), + LOCATION_NOT_HAVE(HttpStatus.NOT_FOUND, "L-105", "저장되어있는 좌표가 없어서 삭제가 불가능합니다."); + + private final HttpStatus status; + private final String code; + private final String message; + +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/global/security/SecurityConfig.java b/src/main/java/com/back/web7_9_codecrete_be/global/security/SecurityConfig.java index be26824b..70ebb226 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/global/security/SecurityConfig.java +++ b/src/main/java/com/back/web7_9_codecrete_be/global/security/SecurityConfig.java @@ -52,6 +52,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/v3/api-docs/**", // Swagger "/swagger-ui/**", // Swagger UI "/h2-console/**", // H2 Console + "/api/v1/location/**", //location 정보 조회 도메인(임시) "/api/v1/concerts/**", // concert 정보 조회 도메인 "/api/v1/artists/**" // artist 정보 저장 도메인(임시) ).permitAll()