-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- 기존의 코드는 프 -> 백 데이터 전달 과정에서 계속 오류가 남. - 이에 따라 백 측에서 데이터를 받아오는 코드 로직 자체를 변경한 v2를 작성함.
- Loading branch information
Showing
8 changed files
with
361 additions
and
0 deletions.
There are no files selected for viewing
138 changes: 138 additions & 0 deletions
138
...java/com/solucitation/midpoint_backend/domain/history2/api/SearchHistoryControllerV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.api; | ||
|
||
import com.fasterxml.jackson.core.JsonParser; | ||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.solucitation.midpoint_backend.domain.history2.dto.PlaceDtoV2; | ||
import com.solucitation.midpoint_backend.domain.history2.dto.SearchHistoryRequestDtoV2; | ||
import com.solucitation.midpoint_backend.domain.history2.dto.SearchHistoryResponseDtoV2; | ||
import com.solucitation.midpoint_backend.domain.history2.service.SearchHistoryServiceV2; | ||
import com.solucitation.midpoint_backend.domain.member.dto.ValidationErrorResponse; | ||
import com.solucitation.midpoint_backend.domain.member.entity.Member; | ||
import com.solucitation.midpoint_backend.domain.member.service.MemberService; | ||
import jakarta.validation.ConstraintViolation; | ||
import jakarta.validation.Validator; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
@Slf4j | ||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/search-history-v2") | ||
public class SearchHistoryControllerV2 { | ||
private final MemberService memberService; | ||
private final Validator validator; | ||
private final SearchHistoryServiceV2 searchHistoryService; | ||
|
||
/** | ||
* 검색 결과에서 저장하고 싶은 장소를 리스트로 받아와서 저장합니다. | ||
* | ||
* @param authentication 인증 정보 | ||
* @return 장소를 성공적으로 저장하면 201 CREATED를 반환합니다. | ||
* 로그인을 하지 않고 시도 시 401 UNAUTHORIZED를 반환합니다. | ||
* 사용자를 찾을 수 없는 경우 404 NOT_FOUND를 반환합니다. | ||
* 저장하려는 장소 정보에 문제가 있을 때 (필드가 공백이거나 null일 경우) 400 BAD_REQUEST를 반환합니다. | ||
* 기타 사유로 저장 실패 시 500 INTERNAL_SERVER_ERROR를 반환합니다. | ||
* @throws JsonProcessingException | ||
*/ | ||
@PostMapping("") | ||
public ResponseEntity<Object> saveHistory(Authentication authentication, | ||
@RequestBody SearchHistoryRequestDtoV2 request) { | ||
try { | ||
String neighborhood = request.getNeighborhood(); | ||
List<PlaceDtoV2> searchHistoryRequestDtos = request.getHistoryDto(); | ||
|
||
System.out.println("ssearchHistoryRequestDtos.size()= " +searchHistoryRequestDtos.size()); | ||
for (PlaceDtoV2 searchHistoryRequestDto : searchHistoryRequestDtos) { | ||
System.out.println("searchHistoryRequestDto = " + searchHistoryRequestDto.getPlaceId()); | ||
} | ||
|
||
// neighborhood 검증 | ||
if (neighborhood == null || neighborhood.trim().isEmpty()) { | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST) | ||
.body(Map.of("error", "EMPTY_FIELD", "message", "동 정보가 누락되었습니다.")); | ||
} | ||
|
||
// 인증 검증 | ||
if (authentication == null || !authentication.isAuthenticated()) { | ||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED) | ||
.body(Map.of("error", "UNAUTHORIZED", "message", "해당 서비스를 이용하기 위해서는 로그인이 필요합니다.")); | ||
} | ||
|
||
String memberEmail = authentication.getName(); | ||
Member member = memberService.getMemberByEmail(memberEmail); | ||
if (member == null) { | ||
return ResponseEntity.status(HttpStatus.NOT_FOUND) | ||
.body(Map.of("error", "USER_NOT_FOUND", "message", "사용자를 찾을 수 없습니다.")); | ||
} | ||
|
||
// 리스트 내의 모든 요소에 대한 검증 수행 | ||
for (PlaceDtoV2 place : searchHistoryRequestDtos) { | ||
Set<ConstraintViolation<PlaceDtoV2>> violations = validator.validate(place); | ||
if (!violations.isEmpty()) { | ||
List<ValidationErrorResponse.FieldError> fieldErrors = violations.stream() | ||
.map(violation -> new ValidationErrorResponse.FieldError(violation.getPropertyPath().toString(), violation.getMessage())) | ||
.collect(Collectors.toList()); | ||
ValidationErrorResponse errorResponse = new ValidationErrorResponse(fieldErrors); | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); | ||
} | ||
} | ||
|
||
// 데이터 저장 | ||
searchHistoryService.save(neighborhood, memberEmail, searchHistoryRequestDtos); | ||
return ResponseEntity.status(HttpStatus.CREATED).body(Map.of("message", "장소를 저장하였습니다.")); | ||
|
||
} catch (IllegalArgumentException e) { | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); | ||
} catch (RuntimeException e) { | ||
return ResponseEntity.status(HttpStatus.NOT_FOUND) | ||
.body(Map.of("error", "USER_NOT_FOUND", "message", "사용자를 찾을 수 없습니다.")); | ||
} catch (Exception e) { | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) | ||
.body(Map.of("error", e.getMessage(), "message", "장소 저장 중 오류가 발생하였습니다.")); | ||
} | ||
} | ||
|
||
|
||
/** | ||
* 사용자가 지금까지 저장한 검색 정보를 전부 최신순부터 가져옵니다. | ||
* | ||
* @param authentication 인증 정보 | ||
* @return 검색 기록 조회가 성공하면 200 OK와 결과 리스트를 반환합니다. | ||
* 로그인을 하지 않고 시도 시 401 UNAUTHORIZED를 반환합니다. | ||
* 사용자를 찾을 수 없는 경우 404 NOT_FOUND를 반환합니다. | ||
* 기타 사유로 저장 실패 시 500 INTERNAL_SERVER_ERROR를 반환합니다. | ||
*/ | ||
@GetMapping("") | ||
public ResponseEntity<Object> getHistory(Authentication authentication) { | ||
try { | ||
if (authentication == null || !authentication.isAuthenticated()) { | ||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED) | ||
.body(Map.of("error", "UNAUTHORIZED", "message", "해당 서비스를 이용하기 위해서는 로그인이 필요합니다.")); | ||
} | ||
|
||
String memberEmail = authentication.getName(); | ||
Member member = memberService.getMemberByEmail(memberEmail); | ||
if (member == null) { | ||
return ResponseEntity.status(HttpStatus.NOT_FOUND) | ||
.body(Map.of("error", "USER_NOT_FOUND", "message", "사용자를 찾을 수 없습니다.")); | ||
} | ||
|
||
List<SearchHistoryResponseDtoV2> searchHistoryResponseDtos = searchHistoryService.getHistory(member); | ||
return ResponseEntity.ok(searchHistoryResponseDtos); | ||
} catch (Exception e) { | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) | ||
.body(Map.of("error", e.getMessage(), "message", "검색 기록 조회 중 오류가 발생하였습니다.")); | ||
} | ||
} | ||
|
||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/com/solucitation/midpoint_backend/domain/history2/dto/PlaceDtoV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.dto; | ||
|
||
import jakarta.validation.constraints.NotBlank; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class PlaceDtoV2 { | ||
@NotBlank(message = "장소ID가 누락되었습니다.") | ||
private String placeId; // 장소의 고유 ID | ||
|
||
@NotBlank(message = "장소명이 누락되었습니다.") | ||
private String placeName; // 장소의 이름 | ||
|
||
@NotBlank(message = "주소가 누락되었습니다.") | ||
private String placeAddress; // 장소의 주소 | ||
|
||
private String imageUrl; // 장소 이미지 | ||
} |
19 changes: 19 additions & 0 deletions
19
...java/com/solucitation/midpoint_backend/domain/history2/dto/SearchHistoryRequestDtoV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.dto; | ||
|
||
import jakarta.validation.constraints.NotBlank; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class SearchHistoryRequestDtoV2 { | ||
@NotBlank | ||
private String neighborhood; | ||
|
||
private List<PlaceDtoV2> historyDto = new ArrayList<>(); | ||
} |
18 changes: 18 additions & 0 deletions
18
...ava/com/solucitation/midpoint_backend/domain/history2/dto/SearchHistoryResponseDtoV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.dto; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class SearchHistoryResponseDtoV2 { | ||
private String neighborhood; | ||
private LocalDateTime serachTime; | ||
private List<PlaceDtoV2> places = new ArrayList<>(); | ||
} |
33 changes: 33 additions & 0 deletions
33
src/main/java/com/solucitation/midpoint_backend/domain/history2/entity/PlaceInfoV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.entity; | ||
|
||
import jakarta.persistence.*; | ||
import lombok.*; | ||
|
||
@Entity | ||
@Table(name = "place_info") | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@AllArgsConstructor | ||
@Builder | ||
public class PlaceInfoV2 { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "place_info_id") | ||
private Long id; | ||
|
||
@Column(name="place_id", nullable = false) | ||
private String placeId; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "search_history_id", nullable = false) | ||
private SearchHistoryV2 searchHistory; | ||
|
||
@Column(name = "place_name", nullable = false) | ||
private String name; | ||
|
||
@Column(name = "place_address", nullable = false) | ||
private String address; | ||
|
||
@Column(name="place_image_url", nullable = false) | ||
private String imageUrl; | ||
} |
40 changes: 40 additions & 0 deletions
40
src/main/java/com/solucitation/midpoint_backend/domain/history2/entity/SearchHistoryV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.entity; | ||
|
||
import com.solucitation.midpoint_backend.domain.member.entity.Member; | ||
import jakarta.persistence.*; | ||
import lombok.*; | ||
import org.hibernate.annotations.CreationTimestamp; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import static jakarta.persistence.FetchType.LAZY; | ||
|
||
@Entity | ||
@Table(name = "search_history") | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@AllArgsConstructor | ||
@Builder | ||
public class SearchHistoryV2 { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "search_history_id") | ||
private Long id; | ||
|
||
@Column(name="neighborhood", nullable = false) | ||
private String neighborhood; // 동 정보 ex. 청파동 | ||
|
||
@ManyToOne(fetch = LAZY) | ||
@JoinColumn(name = "member_id", nullable = false) | ||
private Member member; | ||
|
||
@CreationTimestamp | ||
@Column(name = "search_date", nullable = false, updatable = false) | ||
private LocalDateTime searchDate; | ||
|
||
@OneToMany(mappedBy = "searchHistory", fetch = LAZY, cascade = CascadeType.ALL, orphanRemoval = true) | ||
@Builder.Default | ||
private List<PlaceInfoV2> placeList = new ArrayList<>(); | ||
} |
13 changes: 13 additions & 0 deletions
13
...m/solucitation/midpoint_backend/domain/history2/repository/SearchHistoryRepositoryV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.repository; | ||
|
||
import com.solucitation.midpoint_backend.domain.history2.entity.SearchHistoryV2; | ||
import com.solucitation.midpoint_backend.domain.member.entity.Member; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.List; | ||
|
||
@Repository | ||
public interface SearchHistoryRepositoryV2 extends JpaRepository<SearchHistoryV2, Long> { | ||
List<SearchHistoryV2> findByMemberOrderBySearchDateDesc(Member member); | ||
} |
78 changes: 78 additions & 0 deletions
78
...ava/com/solucitation/midpoint_backend/domain/history2/service/SearchHistoryServiceV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package com.solucitation.midpoint_backend.domain.history2.service; | ||
|
||
import com.solucitation.midpoint_backend.domain.history2.dto.PlaceDtoV2; | ||
import com.solucitation.midpoint_backend.domain.history2.dto.SearchHistoryRequestDtoV2; | ||
import com.solucitation.midpoint_backend.domain.history2.dto.SearchHistoryResponseDtoV2; | ||
import com.solucitation.midpoint_backend.domain.history2.entity.PlaceInfoV2; | ||
import com.solucitation.midpoint_backend.domain.history2.entity.SearchHistoryV2; | ||
import com.solucitation.midpoint_backend.domain.history2.repository.SearchHistoryRepositoryV2; | ||
import com.solucitation.midpoint_backend.domain.member.entity.Member; | ||
import com.solucitation.midpoint_backend.domain.member.service.MemberService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class SearchHistoryServiceV2 { | ||
@Value("${cloud.aws.s3.bucket}") | ||
private String bucket; | ||
|
||
private final String defaultImageUrl = String.format("https://%s.s3.%s.amazonaws.com/%s", bucket, "ap-northeast-2", "place_default_image.png"); | ||
private final SearchHistoryRepositoryV2 searchHistoryRepository; | ||
private final MemberService memberService; | ||
|
||
@Transactional | ||
public void save(String neighborhood, String memberEmail, List<PlaceDtoV2> placeDtos) { | ||
Member member = memberService.getMemberByEmail(memberEmail); | ||
|
||
SearchHistoryV2 searchHistory = SearchHistoryV2.builder() | ||
.member(member) | ||
.neighborhood(neighborhood) | ||
.build(); | ||
|
||
System.out.println("placeDtos.size() = " + placeDtos.size()); | ||
for (PlaceDtoV2 dto : placeDtos) { | ||
String imageUrl = dto.getImageUrl(); | ||
if (imageUrl == null || imageUrl.trim().isEmpty()) { // 이미지 url이 없거나 공백 | ||
imageUrl = defaultImageUrl; | ||
} | ||
|
||
PlaceInfoV2 placeInfo = PlaceInfoV2.builder() | ||
.name(dto.getPlaceName()) | ||
.placeId(dto.getPlaceId()) | ||
.address(dto.getPlaceAddress()) | ||
.imageUrl(imageUrl) | ||
.searchHistory(searchHistory) // searchHistory 필드 설정 | ||
.build(); | ||
searchHistory.getPlaceList().add(placeInfo); | ||
System.out.println("placeInfo = " + placeInfo); | ||
} | ||
searchHistoryRepository.save(searchHistory); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public List<SearchHistoryResponseDtoV2> getHistory(Member member) { | ||
List<SearchHistoryV2> histories = searchHistoryRepository.findByMemberOrderBySearchDateDesc(member); | ||
|
||
return histories.stream() | ||
.map(history -> new SearchHistoryResponseDtoV2( | ||
history.getNeighborhood(), | ||
history.getSearchDate(), | ||
history.getPlaceList().stream() | ||
.map(placeInfo -> new PlaceDtoV2( | ||
placeInfo.getPlaceId(), | ||
placeInfo.getName(), | ||
placeInfo.getAddress(), | ||
placeInfo.getImageUrl() | ||
)) | ||
.collect(Collectors.toList()) | ||
)) | ||
.collect(Collectors.toList()); | ||
} | ||
} |