Skip to content
2 changes: 2 additions & 0 deletions src/main/java/hyu/erica/capstone/CapstoneApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableJpaAuditing
@EnableFeignClients
@EnableAsync
public class CapstoneApplication {

public static void main(String[] args) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/hyu/erica/capstone/client/PlanClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ public interface PlanClient {
@GetMapping("/restaurants/search")
RestaurantRequestDTO getRestaurants(@RequestParam String query);

@GetMapping("/attractions/search")
@GetMapping("/attraction/search")
AttractionRequestDTO getAttractions(@RequestParam String query);
}
82 changes: 38 additions & 44 deletions src/main/java/hyu/erica/capstone/domain/Attraction.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,70 +22,64 @@
public class Attraction {

@Id
@Column(name = "UC_SEQ")
private Long ucSeq;
@Column(name = "content_id")
private Long contentId;

@Column(name = "MAIN_TITLE")
private String mainTitle;
@Column(name = "content_name")
private String contentName;

@Column(name = "GUGUN_NM")
private String gugunNm;
@Column(name = "district")
private String district;

@Column(name = "LAT")
private Double lat;
@Column(name = "latitude")
private Double latitude;

@Column(name = "LNG")
private Double lng;
@Column(name = "longitude")
private Double longitude;

@Column(name = "PLACE")
private String place;
@Column(name = "travel_destination")
private String travelDestination;

@Column(name = "TITLE")
@Column(name = "title")
private String title;

@Column(name = "SUBTITLE")
@Column(name = "subtitle")
private String subtitle;

@Column(name = "MAIN_PLACE")
private String mainPlace;
@Column(name = "address")
private String address;

@Column(name = "ADDR1")
private String addr1;
@Column(name = "contact")
private String contact;

@Column(name = "ADDR2")
private String addr2;
@Column(name = "homepage")
private String homepage;

@Column(name = "CNTCT_TEL")
private String cntctTel;
@Column(name = "transportation_info", columnDefinition = "TEXT")
private String transportationInfo;

@Column(name = "HOMEPAGE_URL")
private String homepageUrl;
@Column(name = "operating_days")
private String operatingDays;

@Column(name = "TRFC_INFO", columnDefinition = "TEXT")
private String trfcInfo;
@Column(name = "closed_days")
private String closedDays;

@Column(name = "USAGE_DAY")
private String usageDay;
@Column(name = "operating_hours")
private String operatingHours;

@Column(name = "HLDY_INFO")
private String hldyInfo;
@Column(name = "admission_fee")
private String admissionFee;

@Column(name = "USAGE_DAY_WEEK_AND_TIME", columnDefinition = "TEXT")
private String usageDayWeekAndTime;
@Column(name = "amenities")
private String amenities;

@Column(name = "USAGE_AMOUNT")
private String usageAmount;
@Column(name = "image_url")
private String imageUrl;

@Column(name = "MIDDLE_SIZE_RM1")
private String middleSizeRm1;
@Column(name = "thumbnail_image_url")
private String thumbnailImageUrl;

@Column(name = "MAIN_IMG_NORMAL")
private String mainImgNormal;
@Column(name = "details", columnDefinition = "LONGTEXT")
private String details;

@Column(name = "MAIN_IMG_THUMB")
private String mainImgThumb;

@Lob
@Column(name = "ITEMCNTNTS")
private String itemcntnts; // ITEMCNTNTS (상세 설명)
}
10 changes: 10 additions & 0 deletions src/main/java/hyu/erica/capstone/domain/TripPlan.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import static jakarta.persistence.GenerationType.*;

import hyu.erica.capstone.domain.enums.TripPlanStatus;
import hyu.erica.capstone.domain.mapping.PreferAttraction;
import hyu.erica.capstone.domain.mapping.PreferRestaurant;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
Expand Down Expand Up @@ -45,6 +48,9 @@ public class TripPlan {

private LocalDate endDate;

@Enumerated(value = EnumType.STRING)
private TripPlanStatus tripPlanStatus;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;
Expand All @@ -56,5 +62,9 @@ public class TripPlan {
private List<PreferRestaurant> preferRestaurants;


public void setStatus(TripPlanStatus status) {
this.tripPlanStatus = status;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package hyu.erica.capstone.domain.enums;

public enum TripPlanStatus {
PROGRESSING, DONE, FAILED
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import org.springframework.stereotype.Repository;

@Repository

public interface AttractionRepository extends JpaRepository<Attraction, Long> {
// 키워드 검색
List<Attraction> findByMainTitleContaining(String keyword);
List<Attraction> findByContentNameContaining(String contentName);
}


Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
public interface PreferAttractionRepository extends JpaRepository<PreferAttraction, Long> {

List<PreferAttraction> findAllByTripPlanId(Long tripPlanId);
boolean existsByAttraction_ContentIdAndUserId(Long attractionId, Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
@Repository
public interface PreferRestaurantRepository extends JpaRepository<PreferRestaurant, Long> {
List<PreferRestaurant> findAllByTripPlanId(Long tripPlanId);
boolean existsByRestaurantIdAndUserId(Long restaurantId, Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package hyu.erica.capstone.service.async;

import hyu.erica.capstone.api.code.status.ErrorStatus;
import hyu.erica.capstone.api.exception.GeneralException;
import hyu.erica.capstone.client.PlanClient;
import hyu.erica.capstone.domain.Attraction;
import hyu.erica.capstone.domain.Restaurant;
import hyu.erica.capstone.domain.Style;
import hyu.erica.capstone.domain.TripPlan;
import hyu.erica.capstone.domain.User;
import hyu.erica.capstone.domain.enums.TripPlanStatus;
import hyu.erica.capstone.domain.mapping.PreferAttraction;
import hyu.erica.capstone.domain.mapping.PreferRestaurant;
import hyu.erica.capstone.repository.AttractionRepository;
import hyu.erica.capstone.repository.PreferAttractionRepository;
import hyu.erica.capstone.repository.PreferRestaurantRepository;
import hyu.erica.capstone.repository.RestaurantRepository;
import hyu.erica.capstone.repository.TripPlanRepository;
import hyu.erica.capstone.repository.UserRepository;
import hyu.erica.capstone.web.dto.client.AttractionRequestDTO;
import hyu.erica.capstone.web.dto.client.RestaurantRequestDTO;
import java.util.concurrent.CompletableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class StyleBackgroundTaskService {

private final PlanClient planClient;
private final TripPlanRepository tripPlanRepository;
private final UserRepository userRepository;
private final RestaurantRepository restaurantRepository;
private final AttractionRepository attractionRepository;
private final PreferRestaurantRepository preferRestaurantRepository;
private final PreferAttractionRepository preferAttractionRepository;

@Async
@Transactional
public void handleTripPlanDetails(Long tripPlanId, Style style, User user) {
TripPlan tripPlan = tripPlanRepository.findById(tripPlanId)
.orElseThrow(() -> new GeneralException(ErrorStatus._TRIP_PLAN_NOT_FOUND));

log.info("handleTripPlanDetails: " + tripPlanId);

User managedUser = userRepository.findById(user.getId())
.orElseThrow(() -> new GeneralException(ErrorStatus._USER_NOT_FOUND));


try {
String prompt = buildPrompt(style);

// 외부 API 병렬 호출
CompletableFuture<AttractionRequestDTO> attractionFuture =
CompletableFuture.supplyAsync(() -> planClient.getAttractions(prompt));
CompletableFuture<RestaurantRequestDTO> restaurantFuture =
CompletableFuture.supplyAsync(() -> planClient.getRestaurants(prompt));

AttractionRequestDTO attractions = attractionFuture.join();
RestaurantRequestDTO restaurants = restaurantFuture.join();

// 레스토랑 저장
for (Long restaurantId : restaurants.restaurant_ids()) {
Restaurant restaurant = restaurantRepository.findById(restaurantId)
.orElseThrow(() -> new GeneralException(ErrorStatus._RESTAURANT_NOT_FOUND));
preferRestaurantRepository.save(PreferRestaurant.builder()
.restaurant(restaurant)
.user(managedUser)
.isPrefer(true)
.tripPlan(tripPlan)
.build());
}

// 어트랙션 저장
for (Long attractionId : attractions.attraction_ids()) {
Attraction attraction = attractionRepository.findById(attractionId)
.orElseThrow(() -> new GeneralException(ErrorStatus._ATTRACTION_NOT_FOUND));
preferAttractionRepository.save(PreferAttraction.builder()
.attraction(attraction)
.user(managedUser)
.tripPlan(tripPlan)
.build());
}

tripPlan.setStatus(TripPlanStatus.DONE);

} catch (Exception e) {
tripPlan.setStatus(TripPlanStatus.FAILED);
log.info(e.toString());
// 로그 남기기
}

tripPlanRepository.save(tripPlan);
}

private String buildPrompt(Style style) {
return new StringBuilder()
.append("여행 지역 : ").append(style.getCity().name()).append("\n")
.append("시작 날짜 : ").append(style.getStartDate()).append("\n")
.append("종료 날짜 : ").append(style.getEndDate()).append("\n")
.append("선호 활동 : ").append(style.getPreferActivity()).append("\n")
.append("추가 요구 사항 : ").append(style.getRequirement())
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
import hyu.erica.capstone.web.dto.style.response.UserStyleFinalResponseDTO;
import hyu.erica.capstone.web.dto.style.response.UserStyleInitResponseDTO;
import hyu.erica.capstone.web.dto.style.response.UserStyleResponseDTO;
import hyu.erica.capstone.web.dto.tripPlan.response.TripPlanResponseDTO;

public interface StyleCommandService {

UserStyleInitResponseDTO initStyle(Long userId);

UserStyleResponseDTO updateStyle(Long userId, Long styleId, UserStyleRequestDTO request);

UserStyleFinalResponseDTO submitStyle(Long styleId, Long userId);
TripPlanResponseDTO submitStyle(Long styleId, Long userId);
}
Loading