From 9235fdf5d5afe048d86f7c608060b53430df2920 Mon Sep 17 00:00:00 2001 From: eunjungL Date: Wed, 17 Jul 2024 15:31:27 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20TravelPlan=20=EA=B4=80=EB=A0=A8=20E?= =?UTF-8?q?ntity=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../travelplan/day/domain/PlanDay.java | 31 ++++++++++++++++++ .../touroot/travelplan/domain/TravelPlan.java | 26 +++++++++++++++ .../travelplan/place/domain/PlanPlace.java | 32 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/day/domain/PlanDay.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/place/domain/PlanPlace.java diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/day/domain/PlanDay.java b/backend/src/main/java/woowacourse/touroot/travelplan/day/domain/PlanDay.java new file mode 100644 index 00000000..621f6f7e --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/day/domain/PlanDay.java @@ -0,0 +1,31 @@ +package woowacourse.touroot.travelplan.day.domain; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import woowacourse.touroot.entity.BaseEntity; +import woowacourse.touroot.travelplan.domain.TravelPlan; +import woowacourse.touroot.travelplan.place.domain.PlanPlace; + +import java.util.List; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class PlanDay extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + int order; + + @JoinColumn(name = "plan_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private TravelPlan plan; + + @OneToMany(mappedBy = "day") + List places; +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java new file mode 100644 index 00000000..4b78179f --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java @@ -0,0 +1,26 @@ +package woowacourse.touroot.travelplan.domain; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import woowacourse.touroot.entity.BaseEntity; +import woowacourse.touroot.travelplan.day.domain.PlanDay; + +import java.util.List; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class TravelPlan extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + String title; + + @OneToMany(mappedBy = "plan") + List days; +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/place/domain/PlanPlace.java b/backend/src/main/java/woowacourse/touroot/travelplan/place/domain/PlanPlace.java new file mode 100644 index 00000000..e3349857 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/place/domain/PlanPlace.java @@ -0,0 +1,32 @@ +package woowacourse.touroot.travelplan.place.domain; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import woowacourse.touroot.entity.BaseEntity; +import woowacourse.touroot.place.domain.Place; +import woowacourse.touroot.travelplan.day.domain.PlanDay; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class PlanPlace extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String description; + + @Column(nullable = false) + private int order; + + @JoinColumn(name = "plan_day_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private PlanDay day; + + @JoinColumn(name = "place_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Place place; +} From 44275e4a7597abd7f681293a7e22ccd18480d74b Mon Sep 17 00:00:00 2001 From: eunjungL Date: Wed, 17 Jul 2024 17:38:36 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=EC=97=AC=ED=96=89=EA=B8=B0=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../touroot/place/domain/Place.java | 15 +++-- .../place/repository/PlaceRepository.java | 4 ++ .../controller/TravelPlanController.java | 26 ++++++++ .../touroot/travelplan/domain/TravelPlan.java | 15 ++++- .../TravelPlanDay.java} | 18 +++--- .../TravelPlanPlace.java} | 17 ++++-- .../travelplan/dto/PlanDayCreateRequest.java | 20 +++++++ .../dto/PlanLocationCreateRequest.java | 9 +++ .../travelplan/dto/PlanPlaceRequest.java | 22 +++++++ .../dto/TravelPlanCreateRequest.java | 19 ++++++ .../dto/TravelPlanCreateResponse.java | 4 ++ .../repository/TravelPlanDayRepository.java | 7 +++ .../repository/TravelPlanPlaceRepository.java | 7 +++ .../repository/TravelPlanRepository.java | 7 +++ .../travelplan/service/TravelPlanService.java | 59 +++++++++++++++++++ 15 files changed, 228 insertions(+), 21 deletions(-) create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java rename backend/src/main/java/woowacourse/touroot/travelplan/{day/domain/PlanDay.java => domain/TravelPlanDay.java} (55%) rename backend/src/main/java/woowacourse/touroot/travelplan/{place/domain/PlanPlace.java => domain/TravelPlanPlace.java} (57%) create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceRequest.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanDayRepository.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanPlaceRepository.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanRepository.java create mode 100644 backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java diff --git a/backend/src/main/java/woowacourse/touroot/place/domain/Place.java b/backend/src/main/java/woowacourse/touroot/place/domain/Place.java index 5509ca4c..630c3a94 100644 --- a/backend/src/main/java/woowacourse/touroot/place/domain/Place.java +++ b/backend/src/main/java/woowacourse/touroot/place/domain/Place.java @@ -1,14 +1,15 @@ package woowacourse.touroot.place.domain; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import woowacourse.touroot.entity.BaseEntity; @Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) @Entity public class Place extends BaseEntity { @@ -26,4 +27,8 @@ public class Place extends BaseEntity { private String longitude; private String googlePlaceId; + + public Place(String name, String latitude, String longitude) { + this(null, name, latitude, longitude, null); + } } diff --git a/backend/src/main/java/woowacourse/touroot/place/repository/PlaceRepository.java b/backend/src/main/java/woowacourse/touroot/place/repository/PlaceRepository.java index a3933b86..4b0c8ce6 100644 --- a/backend/src/main/java/woowacourse/touroot/place/repository/PlaceRepository.java +++ b/backend/src/main/java/woowacourse/touroot/place/repository/PlaceRepository.java @@ -3,5 +3,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import woowacourse.touroot.place.domain.Place; +import java.util.Optional; + public interface PlaceRepository extends JpaRepository { + + Optional findByNameAndLatitudeAndLongitude(String name, String lat, String lng); } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java b/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java new file mode 100644 index 00000000..791ef472 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java @@ -0,0 +1,26 @@ +package woowacourse.touroot.travelplan.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import woowacourse.touroot.travelplan.dto.TravelPlanCreateRequest; +import woowacourse.touroot.travelplan.dto.TravelPlanCreateResponse; +import woowacourse.touroot.travelplan.service.TravelPlanService; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/api/v1/travel-plans") +public class TravelPlanController { + + private final TravelPlanService travelPlanService; + + @PostMapping + public ResponseEntity createTravelPlan(@Valid @RequestBody TravelPlanCreateRequest request) { + TravelPlanCreateResponse data = travelPlanService.createTravelPlan(request); + return ResponseEntity.ok().body(data); + } +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java index 4b78179f..92797c00 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java @@ -2,15 +2,17 @@ import jakarta.persistence.*; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import woowacourse.touroot.entity.BaseEntity; -import woowacourse.touroot.travelplan.day.domain.PlanDay; +import java.time.LocalDate; import java.util.List; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) @Entity public class TravelPlan extends BaseEntity { @@ -19,8 +21,15 @@ public class TravelPlan extends BaseEntity { private Long id; @Column(nullable = false) - String title; + private String title; + + @Column(nullable = false) + private LocalDate startDate; @OneToMany(mappedBy = "plan") - List days; + private List days; + + public TravelPlan(String title, LocalDate startDate) { + this(null, title, startDate, null); + } } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/day/domain/PlanDay.java b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlanDay.java similarity index 55% rename from backend/src/main/java/woowacourse/touroot/travelplan/day/domain/PlanDay.java rename to backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlanDay.java index 621f6f7e..fe08d0d3 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/day/domain/PlanDay.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlanDay.java @@ -1,31 +1,35 @@ -package woowacourse.touroot.travelplan.day.domain; +package woowacourse.touroot.travelplan.domain; import jakarta.persistence.*; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import woowacourse.touroot.entity.BaseEntity; -import woowacourse.touroot.travelplan.domain.TravelPlan; -import woowacourse.touroot.travelplan.place.domain.PlanPlace; import java.util.List; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) @Entity -public class PlanDay extends BaseEntity { +public class TravelPlanDay extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) - int order; + @Column(name = "plan_day_order", nullable = false) + Integer order; @JoinColumn(name = "plan_id", nullable = false) @ManyToOne(fetch = FetchType.LAZY) private TravelPlan plan; @OneToMany(mappedBy = "day") - List places; + private List places; + + public TravelPlanDay(int order, TravelPlan plan) { + this(null, order, plan, null); + } } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/place/domain/PlanPlace.java b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlanPlace.java similarity index 57% rename from backend/src/main/java/woowacourse/touroot/travelplan/place/domain/PlanPlace.java rename to backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlanPlace.java index e3349857..71733dad 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/place/domain/PlanPlace.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlanPlace.java @@ -1,17 +1,18 @@ -package woowacourse.touroot.travelplan.place.domain; +package woowacourse.touroot.travelplan.domain; import jakarta.persistence.*; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import woowacourse.touroot.entity.BaseEntity; import woowacourse.touroot.place.domain.Place; -import woowacourse.touroot.travelplan.day.domain.PlanDay; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) @Entity -public class PlanPlace extends BaseEntity { +public class TravelPlanPlace extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -19,14 +20,18 @@ public class PlanPlace extends BaseEntity { private String description; - @Column(nullable = false) - private int order; + @Column(name = "plan_place_order", nullable = false) + private Integer order; @JoinColumn(name = "plan_day_id", nullable = false) @ManyToOne(fetch = FetchType.LAZY) - private PlanDay day; + private TravelPlanDay day; @JoinColumn(name = "place_id", nullable = false) @ManyToOne(fetch = FetchType.LAZY) private Place place; + + public TravelPlanPlace(String description, int order, TravelPlanDay day, Place place) { + this(null, description, order, day, place); + } } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java new file mode 100644 index 00000000..86050510 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java @@ -0,0 +1,20 @@ +package woowacourse.touroot.travelplan.dto; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import woowacourse.touroot.travelplan.domain.TravelPlan; +import woowacourse.touroot.travelplan.domain.TravelPlanDay; + +import java.util.List; + +public record PlanDayCreateRequest( + @NotNull(message = "날짜는 비어있을 수 없습니다.") + @Min(value = 0, message = "날짜는 1 이상이어야 합니다.") + int day, + @NotNull(message = "여행 장소 정보는 비어있을 수 없습니다.") List places +) { + + public TravelPlanDay toPlanDay(TravelPlan plan) { + return new TravelPlanDay(day, plan); + } +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java new file mode 100644 index 00000000..10db2f04 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java @@ -0,0 +1,9 @@ +package woowacourse.touroot.travelplan.dto; + +import jakarta.validation.constraints.NotNull; + +public record PlanLocationCreateRequest( + @NotNull(message = "위도는 비어있을 수 없습니다.") String lat, + @NotNull(message = "경도는 비어있을 수 없습니다.") String lng +) { +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceRequest.java new file mode 100644 index 00000000..e2d9f70a --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceRequest.java @@ -0,0 +1,22 @@ +package woowacourse.touroot.travelplan.dto; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import woowacourse.touroot.place.domain.Place; +import woowacourse.touroot.travelplan.domain.TravelPlanDay; +import woowacourse.touroot.travelplan.domain.TravelPlanPlace; + +public record PlanPlaceRequest( + @NotBlank(message = "장소명은 비어있을 수 없습니다.") String placeName, + String description, + @NotNull + @Min(value = 0, message = "순서는 1 이상이어야 합니다.") + int order, + PlanLocationCreateRequest location +) { + + public TravelPlanPlace toPlanPlace(TravelPlanDay day, Place place) { + return new TravelPlanPlace(description, order, day, place); + } +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java new file mode 100644 index 00000000..6f4feb4b --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java @@ -0,0 +1,19 @@ +package woowacourse.touroot.travelplan.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import woowacourse.touroot.travelplan.domain.TravelPlan; + +import java.time.LocalDate; +import java.util.List; + +public record TravelPlanCreateRequest( + @NotBlank(message = "여행 계획 제목은 비어있을 수 없습니다.") String title, + @NotNull(message = "시작일은 비어있을 수 없습니다.") LocalDate startDate, + @NotNull(message = "여행 날짜 정보는 비어있을 수 없습니다.") List days +) { + + public TravelPlan toTravelPlan() { + return new TravelPlan(title, startDate); + } +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java new file mode 100644 index 00000000..4dec6f98 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java @@ -0,0 +1,4 @@ +package woowacourse.touroot.travelplan.dto; + +public record TravelPlanCreateResponse(Long id) { +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanDayRepository.java b/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanDayRepository.java new file mode 100644 index 00000000..18bf271f --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanDayRepository.java @@ -0,0 +1,7 @@ +package woowacourse.touroot.travelplan.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import woowacourse.touroot.travelplan.domain.TravelPlanDay; + +public interface TravelPlanDayRepository extends JpaRepository { +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanPlaceRepository.java b/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanPlaceRepository.java new file mode 100644 index 00000000..66d04742 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanPlaceRepository.java @@ -0,0 +1,7 @@ +package woowacourse.touroot.travelplan.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import woowacourse.touroot.travelplan.domain.TravelPlanPlace; + +public interface TravelPlanPlaceRepository extends JpaRepository { +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanRepository.java b/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanRepository.java new file mode 100644 index 00000000..0665c7a6 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/repository/TravelPlanRepository.java @@ -0,0 +1,7 @@ +package woowacourse.touroot.travelplan.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import woowacourse.touroot.travelplan.domain.TravelPlan; + +public interface TravelPlanRepository extends JpaRepository { +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java new file mode 100644 index 00000000..ab5f3376 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java @@ -0,0 +1,59 @@ +package woowacourse.touroot.travelplan.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import woowacourse.touroot.place.domain.Place; +import woowacourse.touroot.place.repository.PlaceRepository; +import woowacourse.touroot.travelplan.domain.TravelPlan; +import woowacourse.touroot.travelplan.domain.TravelPlanDay; +import woowacourse.touroot.travelplan.dto.PlanDayCreateRequest; +import woowacourse.touroot.travelplan.dto.PlanPlaceRequest; +import woowacourse.touroot.travelplan.dto.TravelPlanCreateRequest; +import woowacourse.touroot.travelplan.dto.TravelPlanCreateResponse; +import woowacourse.touroot.travelplan.repository.TravelPlanDayRepository; +import woowacourse.touroot.travelplan.repository.TravelPlanPlaceRepository; +import woowacourse.touroot.travelplan.repository.TravelPlanRepository; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class TravelPlanService { + + private final TravelPlanRepository travelPlanRepository; + private final TravelPlanDayRepository travelPlanDayRepository; + private final TravelPlanPlaceRepository travelPlanPlaceRepository; + private final PlaceRepository placeRepository; + + @Transactional + public TravelPlanCreateResponse createTravelPlan(TravelPlanCreateRequest request) { + TravelPlan travelPlan = travelPlanRepository.save(request.toTravelPlan()); + + for (PlanDayCreateRequest dayRequest : request.days()) { + TravelPlanDay travelPlanDay = travelPlanDayRepository.save(dayRequest.toPlanDay(travelPlan)); + createPlanPlace(dayRequest.places(), travelPlanDay); + } + + return new TravelPlanCreateResponse(travelPlan.getId()); + } + + private void createPlanPlace(List request, TravelPlanDay travelPlanDay) { + for (PlanPlaceRequest planRequest : request) { + Place place = placeRepository.findByNameAndLatitudeAndLongitude( + planRequest.placeName(), + planRequest.location().lat(), + planRequest.location().lng() + ).orElseGet(() -> placeRepository.save( + new Place( + planRequest.placeName(), + planRequest.location().lat(), + planRequest.location().lng() + ) + ) + ); + + travelPlanPlaceRepository.save(planRequest.toPlanPlace(travelPlanDay, place)); + } + } +} From 34638692c753df26ecdd0d7e60ecc59e5c432885 Mon Sep 17 00:00:00 2001 From: eunjungL Date: Wed, 17 Jul 2024 17:50:16 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20swagger=20=EC=84=A4=EB=AA=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../travelplan/controller/TravelPlanController.java | 4 ++++ .../travelplan/dto/PlanDayCreateRequest.java | 5 ++++- .../travelplan/dto/PlanLocationCreateRequest.java | 9 +++++++-- ...laceRequest.java => PlanPlaceCreateRequest.java} | 8 ++++++-- .../travelplan/dto/TravelPlanCreateRequest.java | 13 ++++++++++--- .../travelplan/dto/TravelPlanCreateResponse.java | 7 ++++++- .../travelplan/service/TravelPlanService.java | 6 +++--- 7 files changed, 40 insertions(+), 12 deletions(-) rename backend/src/main/java/woowacourse/touroot/travelplan/dto/{PlanPlaceRequest.java => PlanPlaceCreateRequest.java} (65%) diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java b/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java index 791ef472..c91afc23 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java @@ -1,5 +1,7 @@ package woowacourse.touroot.travelplan.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -11,6 +13,7 @@ import woowacourse.touroot.travelplan.dto.TravelPlanCreateResponse; import woowacourse.touroot.travelplan.service.TravelPlanService; +@Tag(name = "여행기") @RequiredArgsConstructor @RestController @RequestMapping("/api/v1/travel-plans") @@ -18,6 +21,7 @@ public class TravelPlanController { private final TravelPlanService travelPlanService; + @Operation(summary = "여행기 생성") @PostMapping public ResponseEntity createTravelPlan(@Valid @RequestBody TravelPlanCreateRequest request) { TravelPlanCreateResponse data = travelPlanService.createTravelPlan(request); diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java index 86050510..99aedbca 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanDayCreateRequest.java @@ -1,5 +1,6 @@ package woowacourse.touroot.travelplan.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import woowacourse.touroot.travelplan.domain.TravelPlan; @@ -8,10 +9,12 @@ import java.util.List; public record PlanDayCreateRequest( + @Schema(description = "여행 계획 날짜", example = "1") @NotNull(message = "날짜는 비어있을 수 없습니다.") @Min(value = 0, message = "날짜는 1 이상이어야 합니다.") int day, - @NotNull(message = "여행 장소 정보는 비어있을 수 없습니다.") List places + @Schema(description = "여행 장소 정보") + @NotNull(message = "여행 장소 정보는 비어있을 수 없습니다.") List places ) { public TravelPlanDay toPlanDay(TravelPlan plan) { diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java index 10db2f04..5ba1bd42 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanLocationCreateRequest.java @@ -1,9 +1,14 @@ package woowacourse.touroot.travelplan.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; public record PlanLocationCreateRequest( - @NotNull(message = "위도는 비어있을 수 없습니다.") String lat, - @NotNull(message = "경도는 비어있을 수 없습니다.") String lng + @Schema(description = "여행 장소 위도", example = "37.5175896") + @NotNull(message = "위도는 비어있을 수 없습니다.") + String lat, + @Schema(description = "여행 장소 경도", example = "127.0867236") + @NotNull(message = "경도는 비어있을 수 없습니다.") + String lng ) { } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceCreateRequest.java similarity index 65% rename from backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceRequest.java rename to backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceCreateRequest.java index e2d9f70a..6605e3c1 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceRequest.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceCreateRequest.java @@ -1,5 +1,6 @@ package woowacourse.touroot.travelplan.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @@ -7,13 +8,16 @@ import woowacourse.touroot.travelplan.domain.TravelPlanDay; import woowacourse.touroot.travelplan.domain.TravelPlanPlace; -public record PlanPlaceRequest( +public record PlanPlaceCreateRequest( + @Schema(description = "여행 장소 이름", example = "신나는 여행 장소") @NotBlank(message = "장소명은 비어있을 수 없습니다.") String placeName, + @Schema(description = "여행 장소 설명", example = "잠실한강공원") String description, + @Schema(description = "여행 장소 순서", example = "1") @NotNull @Min(value = 0, message = "순서는 1 이상이어야 합니다.") int order, - PlanLocationCreateRequest location + @NotNull PlanLocationCreateRequest location ) { public TravelPlanPlace toPlanPlace(TravelPlanDay day, Place place) { diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java index 6f4feb4b..e88e2fce 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateRequest.java @@ -1,5 +1,6 @@ package woowacourse.touroot.travelplan.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import woowacourse.touroot.travelplan.domain.TravelPlan; @@ -8,9 +9,15 @@ import java.util.List; public record TravelPlanCreateRequest( - @NotBlank(message = "여행 계획 제목은 비어있을 수 없습니다.") String title, - @NotNull(message = "시작일은 비어있을 수 없습니다.") LocalDate startDate, - @NotNull(message = "여행 날짜 정보는 비어있을 수 없습니다.") List days + @Schema(description = "여행 계획 제목", example = "신나는 잠실 한강 여행") + @NotBlank(message = "여행 계획 제목은 비어있을 수 없습니다.") + String title, + @Schema(description = "여행 계획 시작일", example = "2024-11-16") + @NotNull(message = "시작일은 비어있을 수 없습니다.") + LocalDate startDate, + @Schema(description = "여행 날짜 정보") + @NotNull(message = "여행 날짜 정보는 비어있을 수 없습니다.") + List days ) { public TravelPlan toTravelPlan() { diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java index 4dec6f98..26b147be 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/TravelPlanCreateResponse.java @@ -1,4 +1,9 @@ package woowacourse.touroot.travelplan.dto; -public record TravelPlanCreateResponse(Long id) { +import io.swagger.v3.oas.annotations.media.Schema; + +public record TravelPlanCreateResponse( + @Schema(description = "생성된 여행 계획 id") + Long id +) { } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java index ab5f3376..df08ad3f 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java @@ -8,7 +8,7 @@ import woowacourse.touroot.travelplan.domain.TravelPlan; import woowacourse.touroot.travelplan.domain.TravelPlanDay; import woowacourse.touroot.travelplan.dto.PlanDayCreateRequest; -import woowacourse.touroot.travelplan.dto.PlanPlaceRequest; +import woowacourse.touroot.travelplan.dto.PlanPlaceCreateRequest; import woowacourse.touroot.travelplan.dto.TravelPlanCreateRequest; import woowacourse.touroot.travelplan.dto.TravelPlanCreateResponse; import woowacourse.touroot.travelplan.repository.TravelPlanDayRepository; @@ -38,8 +38,8 @@ public TravelPlanCreateResponse createTravelPlan(TravelPlanCreateRequest request return new TravelPlanCreateResponse(travelPlan.getId()); } - private void createPlanPlace(List request, TravelPlanDay travelPlanDay) { - for (PlanPlaceRequest planRequest : request) { + private void createPlanPlace(List request, TravelPlanDay travelPlanDay) { + for (PlanPlaceCreateRequest planRequest : request) { Place place = placeRepository.findByNameAndLatitudeAndLongitude( planRequest.placeName(), planRequest.location().lat(), From 1359b9c8c5b097101d7bea633816b4c46959c192 Mon Sep 17 00:00:00 2001 From: eunjungL Date: Wed, 17 Jul 2024 18:06:07 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EC=97=AC=ED=96=89=20=EA=B3=84?= =?UTF-8?q?=ED=9A=8D=20=EC=9E=91=EC=84=B1=20=EC=8B=9C=20=EC=A7=80=EB=82=9C?= =?UTF-8?q?=20=EB=82=A0=EC=A7=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/exception/BadRequestException.java | 8 ++++++ .../touroot/travelplan/domain/TravelPlan.java | 7 ++++++ .../travelplan/service/TravelPlanService.java | 9 ++++--- .../travelplan/domain/TravelPlanTest.java | 25 +++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 backend/src/main/java/woowacourse/touroot/global/exception/BadRequestException.java create mode 100644 backend/src/test/java/woowacourse/touroot/travelplan/domain/TravelPlanTest.java diff --git a/backend/src/main/java/woowacourse/touroot/global/exception/BadRequestException.java b/backend/src/main/java/woowacourse/touroot/global/exception/BadRequestException.java new file mode 100644 index 00000000..94306533 --- /dev/null +++ b/backend/src/main/java/woowacourse/touroot/global/exception/BadRequestException.java @@ -0,0 +1,8 @@ +package woowacourse.touroot.global.exception; + +public class BadRequestException extends RuntimeException { + + public BadRequestException(String message) { + super(message); + } +} diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java index 92797c00..4699b2bc 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/domain/TravelPlan.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import woowacourse.touroot.entity.BaseEntity; +import woowacourse.touroot.global.exception.BadRequestException; import java.time.LocalDate; import java.util.List; @@ -32,4 +33,10 @@ public class TravelPlan extends BaseEntity { public TravelPlan(String title, LocalDate startDate) { this(null, title, startDate, null); } + + public void validateStartDate() { + if (startDate.isBefore(LocalDate.now())) { + throw new BadRequestException("지난 날짜에 대한 계획은 작성할 수 없습니다."); + } + } } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java index df08ad3f..43099620 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java @@ -28,14 +28,17 @@ public class TravelPlanService { @Transactional public TravelPlanCreateResponse createTravelPlan(TravelPlanCreateRequest request) { - TravelPlan travelPlan = travelPlanRepository.save(request.toTravelPlan()); + TravelPlan travelPlan = request.toTravelPlan(); + travelPlan.validateStartDate(); + + TravelPlan savedTravelPlan = travelPlanRepository.save(travelPlan); for (PlanDayCreateRequest dayRequest : request.days()) { - TravelPlanDay travelPlanDay = travelPlanDayRepository.save(dayRequest.toPlanDay(travelPlan)); + TravelPlanDay travelPlanDay = travelPlanDayRepository.save(dayRequest.toPlanDay(savedTravelPlan)); createPlanPlace(dayRequest.places(), travelPlanDay); } - return new TravelPlanCreateResponse(travelPlan.getId()); + return new TravelPlanCreateResponse(savedTravelPlan.getId()); } private void createPlanPlace(List request, TravelPlanDay travelPlanDay) { diff --git a/backend/src/test/java/woowacourse/touroot/travelplan/domain/TravelPlanTest.java b/backend/src/test/java/woowacourse/touroot/travelplan/domain/TravelPlanTest.java new file mode 100644 index 00000000..0548a6a6 --- /dev/null +++ b/backend/src/test/java/woowacourse/touroot/travelplan/domain/TravelPlanTest.java @@ -0,0 +1,25 @@ +package woowacourse.touroot.travelplan.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import woowacourse.touroot.global.exception.BadRequestException; + +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThatCode; + +@DisplayName("여행 계획") +class TravelPlanTest { + + @DisplayName("여행 계획은 지난 날짜를 검증할 시 예외가 발생한다.") + @Test + void validateStartDate() { + // given + TravelPlan travelPlan = new TravelPlan("test", LocalDate.MIN); + + // when & then + assertThatCode(travelPlan::validateStartDate) + .isInstanceOf(BadRequestException.class) + .hasMessage("지난 날짜에 대한 계획은 작성할 수 없습니다."); + } +} From f06c6389a26f5ba5bd4a79e359c284103f555cab Mon Sep 17 00:00:00 2001 From: eunjungL Date: Wed, 17 Jul 2024 18:19:17 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20TravelPlanService=20method=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../travelplan/service/TravelPlanService.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java index 43099620..35f91105 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java @@ -32,31 +32,37 @@ public TravelPlanCreateResponse createTravelPlan(TravelPlanCreateRequest request travelPlan.validateStartDate(); TravelPlan savedTravelPlan = travelPlanRepository.save(travelPlan); + createPlanDay(request, savedTravelPlan); + return new TravelPlanCreateResponse(savedTravelPlan.getId()); + } + + private void createPlanDay(TravelPlanCreateRequest request, TravelPlan savedTravelPlan) { for (PlanDayCreateRequest dayRequest : request.days()) { TravelPlanDay travelPlanDay = travelPlanDayRepository.save(dayRequest.toPlanDay(savedTravelPlan)); createPlanPlace(dayRequest.places(), travelPlanDay); } - - return new TravelPlanCreateResponse(savedTravelPlan.getId()); } private void createPlanPlace(List request, TravelPlanDay travelPlanDay) { for (PlanPlaceCreateRequest planRequest : request) { - Place place = placeRepository.findByNameAndLatitudeAndLongitude( - planRequest.placeName(), - planRequest.location().lat(), - planRequest.location().lng() - ).orElseGet(() -> placeRepository.save( - new Place( - planRequest.placeName(), - planRequest.location().lat(), - planRequest.location().lng() - ) - ) - ); - + Place place = getPlace(planRequest); travelPlanPlaceRepository.save(planRequest.toPlanPlace(travelPlanDay, place)); } } + + private Place getPlace(PlanPlaceCreateRequest planRequest) { + return placeRepository.findByNameAndLatitudeAndLongitude( + planRequest.placeName(), + planRequest.location().lat(), + planRequest.location().lng() + ).orElseGet(() -> placeRepository.save( + new Place( + planRequest.placeName(), + planRequest.location().lat(), + planRequest.location().lng() + ) + ) + ); + } } From eeba1f0468e101bfc6f88e5957bba5851266f655 Mon Sep 17 00:00:00 2001 From: eunjungL Date: Thu, 18 Jul 2024 11:16:35 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20PlanPlaceRequest=EC=97=90=20toP?= =?UTF-8?q?lace=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../touroot/travelplan/dto/PlanPlaceCreateRequest.java | 4 ++++ .../touroot/travelplan/service/TravelPlanService.java | 9 +-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceCreateRequest.java b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceCreateRequest.java index 6605e3c1..182cf88b 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceCreateRequest.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/dto/PlanPlaceCreateRequest.java @@ -23,4 +23,8 @@ public record PlanPlaceCreateRequest( public TravelPlanPlace toPlanPlace(TravelPlanDay day, Place place) { return new TravelPlanPlace(description, order, day, place); } + + public Place toPlace() { + return new Place(placeName, location.lat(), location.lng()); + } } diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java index 35f91105..f962ea03 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/service/TravelPlanService.java @@ -56,13 +56,6 @@ private Place getPlace(PlanPlaceCreateRequest planRequest) { planRequest.placeName(), planRequest.location().lat(), planRequest.location().lng() - ).orElseGet(() -> placeRepository.save( - new Place( - planRequest.placeName(), - planRequest.location().lat(), - planRequest.location().lng() - ) - ) - ); + ).orElseGet(() -> placeRepository.save(planRequest.toPlace())); } } From 8f8829714875636d4250148d54aa9106ba584c18 Mon Sep 17 00:00:00 2001 From: eunjungL Date: Thu, 18 Jul 2024 11:36:36 +0900 Subject: [PATCH 7/7] =?UTF-8?q?style:=20TravelPlanControllere=20=EA=B0=9C?= =?UTF-8?q?=ED=96=89=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../touroot/travelplan/controller/TravelPlanController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java b/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java index c91afc23..de03821f 100644 --- a/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java +++ b/backend/src/main/java/woowacourse/touroot/travelplan/controller/TravelPlanController.java @@ -25,6 +25,7 @@ public class TravelPlanController { @PostMapping public ResponseEntity createTravelPlan(@Valid @RequestBody TravelPlanCreateRequest request) { TravelPlanCreateResponse data = travelPlanService.createTravelPlan(request); - return ResponseEntity.ok().body(data); + return ResponseEntity.ok() + .body(data); } }