diff --git a/build.gradle b/build.gradle index a3d6fb5..ec2ea9f 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,12 @@ dependencies { // MAC OS implementation 'io.netty:netty-resolver-dns-native-macos:4.1.68.Final:osx-aarch_64' + //Querydsl 추가 + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor """com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta""" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + } tasks.named('test') { diff --git a/src/main/java/Journey/Together/domain/place/controller/PlaceController.java b/src/main/java/Journey/Together/domain/place/controller/PlaceController.java new file mode 100644 index 0000000..99a14a9 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/controller/PlaceController.java @@ -0,0 +1,37 @@ +package Journey.Together.domain.place.controller; + +import Journey.Together.domain.member.dto.LoginReq; +import Journey.Together.domain.member.dto.MemberRes; +import Journey.Together.domain.member.service.MemberService; +import Journey.Together.domain.place.dto.response.MainRes; +import Journey.Together.domain.place.dto.response.PlaceDetailRes; +import Journey.Together.domain.place.service.PlaceService; +import Journey.Together.global.common.ApiResponse; +import Journey.Together.global.exception.Success; +import Journey.Together.global.security.PrincipalDetails; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/v1/place") +@Tag(name = "Place", description = "여행지 정보 API") +public class PlaceController { + + private final PlaceService placeService; + + @GetMapping("/main") + public ApiResponse getMain(@RequestHeader("Authorization") String accesstoken, + @RequestParam String areacode, @RequestParam String sigungucode) { + return ApiResponse.success(Success.GET_MAIN_SUCCESS, placeService.getMainPage(areacode, sigungucode)); + } + + @GetMapping("/{placeId}") + public ApiResponse getPlaceDetail(@AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable Long placeId){ + return ApiResponse.success(Success.GET_PLACE_DETAIL_SUCCESS, placeService.getPlaceDetail(principalDetails.getMember(), placeId)); + } + +} diff --git a/src/main/java/Journey/Together/domain/place/dto/response/MainRes.java b/src/main/java/Journey/Together/domain/place/dto/response/MainRes.java new file mode 100644 index 0000000..afc8c82 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/dto/response/MainRes.java @@ -0,0 +1,9 @@ +package Journey.Together.domain.place.dto.response; + +import java.util.List; + +public record MainRes( + List recommendPlaceList, + List aroundPlaceList +) { +} diff --git a/src/main/java/Journey/Together/domain/place/dto/response/PlaceDetailRes.java b/src/main/java/Journey/Together/domain/place/dto/response/PlaceDetailRes.java new file mode 100644 index 0000000..5d26ec5 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/dto/response/PlaceDetailRes.java @@ -0,0 +1,37 @@ +package Journey.Together.domain.place.dto.response; + +import Journey.Together.domain.place.entity.Place; + +import java.util.List; + +public record PlaceDetailRes( + Long placeId, + String name, + String imgae, + String address, + String category, + String overview, + String mapX, + String mapY, + + Boolean isMark, + + Integer bookmarkNum, + + List disability, + List subDisability, + List reviewList +) { + static String cat = "관광지"; + public static PlaceDetailRes of(Place place, Boolean isMark, Integer bookmarkNum, List disability, List subDisability, List reviewList){ + if(place.getCategory().equals("B02")) + cat = "숙소"; + else if (place.getCategory().equals("A05")) + cat = "맛집"; + + + + return new PlaceDetailRes(place.getId(), place.getName(), place.getFirstImg(), place.getAddress(), cat, place.getOverview(), place.getMapX(), place.getMapY(), isMark, + bookmarkNum, disability, subDisability, reviewList); + } +} diff --git a/src/main/java/Journey/Together/domain/place/dto/response/PlaceRes.java b/src/main/java/Journey/Together/domain/place/dto/response/PlaceRes.java new file mode 100644 index 0000000..8d59b9f --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/dto/response/PlaceRes.java @@ -0,0 +1,18 @@ +package Journey.Together.domain.place.dto.response; + +import Journey.Together.domain.place.entity.Place; + +import java.util.List; + +public record PlaceRes( + Long placeId, + String name, + String image, + List disability, + String address +) { + public static PlaceRes of(Place place, List disability){ + + return new PlaceRes(place.getId(), place.getName(), place.getFirstImg(), disability,place.getAddress()); + } +} diff --git a/src/main/java/Journey/Together/domain/place/dto/response/PlaceReviewDto.java b/src/main/java/Journey/Together/domain/place/dto/response/PlaceReviewDto.java new file mode 100644 index 0000000..019802f --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/dto/response/PlaceReviewDto.java @@ -0,0 +1,13 @@ +package Journey.Together.domain.place.dto.response; + +import java.time.LocalDateTime; + +public record PlaceReviewDto( + Long reviewId, + String nickname, + String profileImg, + String content, + String reviewImg, + Float grade, + LocalDateTime date) { +} diff --git a/src/main/java/Journey/Together/domain/place/entity/DisabilityCategory.java b/src/main/java/Journey/Together/domain/place/entity/DisabilityCategory.java new file mode 100644 index 0000000..3f5c825 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/entity/DisabilityCategory.java @@ -0,0 +1,21 @@ +package Journey.Together.domain.place.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class DisabilityCategory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; +} diff --git a/src/main/java/Journey/Together/domain/place/entity/DisabilityPlaceCategory.java b/src/main/java/Journey/Together/domain/place/entity/DisabilityPlaceCategory.java new file mode 100644 index 0000000..a5e0094 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/entity/DisabilityPlaceCategory.java @@ -0,0 +1,31 @@ +package Journey.Together.domain.place.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class DisabilityPlaceCategory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "place_id") + private Place place; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "subCategory_id") + private DisabilitySubCategory subCategory; + + @Builder + public DisabilityPlaceCategory(Place place, DisabilitySubCategory subCategory){ + this.place=place; + this.subCategory=subCategory; + } +} diff --git a/src/main/java/Journey/Together/domain/place/entity/DisabilitySubCategory.java b/src/main/java/Journey/Together/domain/place/entity/DisabilitySubCategory.java new file mode 100644 index 0000000..c42471d --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/entity/DisabilitySubCategory.java @@ -0,0 +1,22 @@ +package Journey.Together.domain.place.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class DisabilitySubCategory { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String subname; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private DisabilityCategory category; + +} diff --git a/src/main/java/Journey/Together/domain/place/entity/DisabilitySubCategoryRepository.java b/src/main/java/Journey/Together/domain/place/entity/DisabilitySubCategoryRepository.java new file mode 100644 index 0000000..4ab97d1 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/entity/DisabilitySubCategoryRepository.java @@ -0,0 +1,6 @@ +package Journey.Together.domain.place.entity; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DisabilitySubCategoryRepository extends JpaRepository { +} diff --git a/src/main/java/Journey/Together/domain/place/entity/Place.java b/src/main/java/Journey/Together/domain/place/entity/Place.java new file mode 100644 index 0000000..73be4f7 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/entity/Place.java @@ -0,0 +1,75 @@ +package Journey.Together.domain.place.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.HashSet; +import java.util.Set; + +@Entity +@Getter +@Table(name = "place") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Place { + + @Id + private Long id; + + private String name; + + private String address; + @Column(columnDefinition = "TEXT") + private String firstImg; + private String category; + private String mapX; + private String mapY; + private String createdAt; + @Column(columnDefinition = "TEXT") + private String overview; + + private String areaCode; + + private String sigunguCode; + + + private Boolean settingDisability; + + + @OneToMany(mappedBy = "place", cascade = CascadeType.ALL, orphanRemoval = true) + private Set placeDisabilityCategories = new HashSet<>(); + + public void setArea(String areaCode, String sigunguCode) { + this.areaCode = areaCode; + this.sigunguCode = sigunguCode; + } + + public void setOverview(String overview){ + this.overview = overview; + } + + public void setting(){ + this.settingDisability = true; + } + + @Builder + public Place(Long id, String name, String address, String firstImg, String category, String mapX, String mapY, String createdAt, String areaCode, String sigunguCode){ + this.id =id; + this.name=name; + this.address=address; + this.firstImg=firstImg; + this.category=category; + this.mapX=mapX; + this.mapY=mapY; + this.createdAt=createdAt; + this.areaCode = areaCode; + this.sigunguCode = sigunguCode; + } + + public Long getId() { + return id; + } + +} diff --git a/src/main/java/Journey/Together/domain/place/repository/DisabilityPlaceCategoryRepository.java b/src/main/java/Journey/Together/domain/place/repository/DisabilityPlaceCategoryRepository.java new file mode 100644 index 0000000..a702c63 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/repository/DisabilityPlaceCategoryRepository.java @@ -0,0 +1,23 @@ +package Journey.Together.domain.place.repository; + +import Journey.Together.domain.place.entity.DisabilityPlaceCategory; +import Journey.Together.domain.place.entity.Place; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface DisabilityPlaceCategoryRepository extends JpaRepository { + + List findAllByPlace(Place place); + + + @Query("SELECT DISTINCT dpc.subCategory.category.id FROM DisabilityPlaceCategory dpc " + + "WHERE dpc.place.id = :placeId") + List findDisabilityCategoryIds(@Param("placeId") long placeId); + + @Query("SELECT DISTINCT dpc.subCategory.id FROM DisabilityPlaceCategory dpc " + + "WHERE dpc.place.id = :placeId") + List findDisabilitySubCategoryIds(@Param("placeId") long placeId); +} diff --git a/src/main/java/Journey/Together/domain/place/repository/PlaceRepository.java b/src/main/java/Journey/Together/domain/place/repository/PlaceRepository.java new file mode 100644 index 0000000..5c2ba7f --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/repository/PlaceRepository.java @@ -0,0 +1,21 @@ +package Journey.Together.domain.place.repository; + + +import Journey.Together.domain.place.entity.Place; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface PlaceRepository extends JpaRepository { + + @Query(value = "SELECT * FROM place p ORDER BY RAND() LIMIT :count", nativeQuery = true) + List findRandomProducts(@Param("count") int count); + + @Query(value = "SELECT * FROM place p WHERE area_code = :areacode AND sigungu_code = :sigungucode " + + "ORDER BY RAND() LIMIT :count", nativeQuery = true) + List findAroundProducts(@Param("areacode") String areacode, @Param("sigungucode") String sigungucode, + @Param("count") int count); + +} diff --git a/src/main/java/Journey/Together/domain/place/service/PlaceService.java b/src/main/java/Journey/Together/domain/place/service/PlaceService.java new file mode 100644 index 0000000..1c9ae52 --- /dev/null +++ b/src/main/java/Journey/Together/domain/place/service/PlaceService.java @@ -0,0 +1,82 @@ +package Journey.Together.domain.place.service; + +import Journey.Together.domain.member.entity.Member; +import Journey.Together.domain.place.dto.response.MainRes; +import Journey.Together.domain.place.dto.response.PlaceDetailRes; +import Journey.Together.domain.place.dto.response.PlaceRes; +import Journey.Together.domain.place.dto.response.PlaceReviewDto; +import Journey.Together.domain.place.entity.DisabilityPlaceCategory; +import Journey.Together.domain.place.entity.Place; +import Journey.Together.domain.place.repository.DisabilityPlaceCategoryRepository; +import Journey.Together.domain.place.repository.PlaceRepository; +import Journey.Together.domain.placeBookbark.entity.PlaceBookmark; +import Journey.Together.domain.placeBookbark.repository.PlaceBookmarkRepository; +import Journey.Together.global.common.ApiResponse; +import Journey.Together.global.exception.ApplicationException; +import Journey.Together.global.exception.ErrorCode; +import Journey.Together.global.exception.ErrorResponse; +import Journey.Together.global.exception.Success; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import software.amazon.awssdk.services.s3.endpoints.internal.Value; + +import java.util.*; + +@Service +@RequiredArgsConstructor +public class PlaceService { + private final PlaceRepository placeRepository; + private final DisabilityPlaceCategoryRepository disabilityPlaceCategoryRepository; + private final PlaceBookmarkRepository placeBookmarkRepository; + + + private final Integer recommnedPlaceNum = 4; + private final Integer aroundPlaceNum = 2; + + // 메인페이지 가져오기 + public MainRes getMainPage(String areacode, String sigungucode){ + + List recommondPlaces = placeRepository.findRandomProducts(recommnedPlaceNum); + List aroundPlaces = placeRepository.findAroundProducts(areacode, sigungucode, aroundPlaceNum); + + + return new MainRes(getPlaceRes(recommondPlaces), getPlaceRes(aroundPlaces)); + } + + //여행지 상세 정보 가져오기 + public PlaceDetailRes getPlaceDetail(Member member, Long placeId){ + // PlaceDetailRes of(Place place, Boolean isMark, Integer bookmarkNum, List disability, List subDisability, List< PlaceReviewDto > reviewList) + + Place place = placeRepository.findById(placeId).orElseThrow( + ()->new ApplicationException(ErrorCode.NOT_FOUND_PLACE_EXCEPTION)); + + List placeBookmarkList = placeBookmarkRepository.findAllByPlace(place); + Boolean isMark = placeBookmarkList.stream() + .anyMatch(placeBookmark -> placeBookmark.getMember().equals(member)); + + List disability = disabilityPlaceCategoryRepository.findDisabilityCategoryIds(placeId); + List subDisability = disabilityPlaceCategoryRepository.findDisabilitySubCategoryIds(placeId); + + return PlaceDetailRes.of(place, isMark, placeBookmarkList.size(), disability, subDisability, null); + + + + } + + private List getPlaceRes(List list){ + List placeList = new ArrayList<>(); + + for(Place place : list){ + Set disability = new HashSet<>(); + disabilityPlaceCategoryRepository.findAllByPlace(place) + .forEach(disabilityPlaceCategory -> { + disability.add(disabilityPlaceCategory.getSubCategory().getCategory().getId().toString()); + }); + placeList.add(PlaceRes.of(place, new ArrayList<>(disability))); + } + + return placeList; + } + + +} diff --git a/src/main/java/Journey/Together/domain/placeBookbark/entity/PlaceBookmark.java b/src/main/java/Journey/Together/domain/placeBookbark/entity/PlaceBookmark.java new file mode 100644 index 0000000..5fb7660 --- /dev/null +++ b/src/main/java/Journey/Together/domain/placeBookbark/entity/PlaceBookmark.java @@ -0,0 +1,27 @@ +package Journey.Together.domain.placeBookbark.entity; + +import Journey.Together.domain.member.entity.Member; +import Journey.Together.domain.place.entity.Place; +import jakarta.persistence.*; +import lombok.*; + +@Getter +@Setter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class PlaceBookmark { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "place_id") + Place place; + +} diff --git a/src/main/java/Journey/Together/domain/placeBookbark/repository/PlaceBookmarkRepository.java b/src/main/java/Journey/Together/domain/placeBookbark/repository/PlaceBookmarkRepository.java new file mode 100644 index 0000000..5d82f64 --- /dev/null +++ b/src/main/java/Journey/Together/domain/placeBookbark/repository/PlaceBookmarkRepository.java @@ -0,0 +1,17 @@ +package Journey.Together.domain.placeBookbark.repository; + + +import Journey.Together.domain.place.entity.Place; +import Journey.Together.domain.placeBookbark.entity.PlaceBookmark; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface PlaceBookmarkRepository extends JpaRepository { + + List findAllByPlace(Place place); + + +} diff --git a/src/main/java/Journey/Together/domain/placeReview/entity/PlaceReview.java b/src/main/java/Journey/Together/domain/placeReview/entity/PlaceReview.java new file mode 100644 index 0000000..91d0f79 --- /dev/null +++ b/src/main/java/Journey/Together/domain/placeReview/entity/PlaceReview.java @@ -0,0 +1,38 @@ +package Journey.Together.domain.placeReview.entity; + +import Journey.Together.domain.member.entity.Member; +import Journey.Together.domain.place.entity.Place; +import Journey.Together.global.common.BaseTimeEntity; +import com.fasterxml.jackson.databind.ser.Serializers; +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Getter +@Setter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class PlaceReview extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "place_review_id") + Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "place_id") + Place place; + + Float grade; + + String content; + + + +} diff --git a/src/main/java/Journey/Together/domain/placeReview/entity/PlaceReviewImg.java b/src/main/java/Journey/Together/domain/placeReview/entity/PlaceReviewImg.java new file mode 100644 index 0000000..674fdf7 --- /dev/null +++ b/src/main/java/Journey/Together/domain/placeReview/entity/PlaceReviewImg.java @@ -0,0 +1,22 @@ +package Journey.Together.domain.placeReview.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Getter +@Setter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class PlaceReviewImg { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "place_review_id") + PlaceReview placeReview; + + String imgUrl; +} diff --git a/src/main/java/Journey/Together/global/exception/ErrorCode.java b/src/main/java/Journey/Together/global/exception/ErrorCode.java index 6ba6075..0037cc0 100644 --- a/src/main/java/Journey/Together/global/exception/ErrorCode.java +++ b/src/main/java/Journey/Together/global/exception/ErrorCode.java @@ -32,7 +32,7 @@ public enum ErrorCode { //4000: Apply Error NOT_APPLY_EXCEPTION(HttpStatus.BAD_REQUEST,4000,"지원 기간 지났습니다"), - NOT_FOUND_POST_EXCEPTION(HttpStatus.NOT_FOUND,4001,"존재하지 않는 글입니다."), + NOT_FOUND_PLACE_EXCEPTION(HttpStatus.NOT_FOUND,4001,"존재하지 않는 여행지입니다."), NOT_FOUND_APPLY_EXCEPTION(HttpStatus.NOT_FOUND,4002,"존재하지 않는 지원서입니다."), ALREADY_APPLY_EXCEPTION(HttpStatus.BAD_REQUEST,4003,"이미 지원했습니다."), ALREADY_DECISION_EXCEPION(HttpStatus.BAD_REQUEST,4004,"이미 지원 결정했습니다."), diff --git a/src/main/java/Journey/Together/global/exception/Success.java b/src/main/java/Journey/Together/global/exception/Success.java index 5590221..0def0ac 100644 --- a/src/main/java/Journey/Together/global/exception/Success.java +++ b/src/main/java/Journey/Together/global/exception/Success.java @@ -18,8 +18,10 @@ public enum Success { /** * 200 OK */ - GET_USER_MAIN_SUCCESS(HttpStatus.OK, "메인 페이지 유저 정보 조회 성공"), + GET_USER_INTEREST_SUCCESS(HttpStatus.OK, "사용자 관심 유형 정보 조회 성공"), + GET_MAIN_SUCCESS(HttpStatus.OK, "메인 페이지 정보 조회 성공"), + GET_PLACE_DETAIL_SUCCESS(HttpStatus.OK, "여행지 상세정보 조회 성공"), GET_MYPAGE_SUCCESS(HttpStatus.OK, "마이 페이지 조회 성공"), GET_LINKS_SUCCESS(HttpStatus.OK, "이주의 링크 조회 성공"), GET_SITES_SUCCESS(HttpStatus.OK, "추천 사이트 조회 성공"),