hyuko

여행일정 생성 본문

토이프로젝트/팀 프로젝트

여행일정 생성

hyuko12 2023. 6. 8. 09:54
728x90
반응형

여행 일정 생성에 대한 주요 도메인을 설명합니다.

우리의 목표는 다음과 같습니다.

  1. 여행 일정을 저장할 수 있어야 한다.
  2. 원하는 날짜를 선택할 수 있어야 합니다.
  3. 여행에 함께 할 인원을 선택하고 이를 공유 할 수 있어야 합니다.

이 세 가지를 중심으로 코드를 구현하려 했습니다. 하나씩 저장하면 간편하게 진행될 것이라 생각했습니다.

하지만 두 가지 주요 문제가 발생했습니다.

첫번째 문제는 여행 일정이란 것이 여러 날짜의 정보를 포함하고, 각 날짜마다 다른 장소들이 할당되어야 하는

상황이었습니다. 즉, 하나의 여행이 등록될 때, 여러 개의 날짜 정보가 해당 여행의 ID 값과 매칭되어 생성되어야 했습니다.

이와 더불어 , 해당 날짜 정보의 ID 값을 기준으로 location 정보들이 각각 생성되어야 했습니다.

 

두번째 문제는 클라이언트에서 서버로 데이터를 전송할 때 , 

하나의 여행 정보 안에 스케줄 데이터와 해당 스케줄에 맞는 위치 정보들이 한 번에 전달되는 상황이었습니다.

따라서, 이 정보들을 한 번에 등록해야 했습니다. 이 문제를 해결하기 위해 프로시저를 사용하기로 결정했습니다.

 

백엔드에서는 Spring Boot를 사용하여 서버를 구현했습니다. 클라이언트에서 데이터를 가져오는
DTO와 컨트롤러의 모습은 다음과 같습니다.

 

// TravelPlanReqDto.java
@Getter @Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TravelPlanReqDto {
    private int id;
    private LocalDate date;
    private List<LocationReqDto> location;
    private List<PartyDataReqDto> partyData;

    public void forEachLocation(Consumer<LocationReqDto> action) {
        for (LocationReqDto locationReqDto : location) {
            if (locationReqDto != null) {
                action.accept(locationReqDto);
            }
        }
    }
}

// TravelPlanController.java
@RestController
@RequestMapping("/api/v1/travel/plan")
@RequiredArgsConstructor
public class TravelPlanController {

    private final TravelService travelService;

    @PostMapping("/save")
    public ResponseEntity<?> plan(@RequestBody List<TravelPlanReqDto> travels) {
        travelService.travelSave(travels);
        return ResponseEntity.ok(DataRespDto.ofDefault());
    }
}
// TravelService.java
@Service
@RequiredArgsConstructor
public class TravelService {
    private static final String IMAGE_URL = "http://localhost:8080/image/region/";

    private final TravelRepository travelRepository;

    public void travelSave(List<TravelPlanReqDto> travels) {
        String travelName = UUID.randomUUID().toString();
        Integer travelId = null;

        for (TravelPlanReqDto dto : travels) {
            if (dto == null || dto.getLocation() == null || dto.getPartyData().isEmpty()) continue;

            travelId = saveTravelData(travelName, travelId, dto);
        }
    }

    private Integer saveTravelData(String travelName, Integer travelId, TravelPlanReqDto dto){
        for (LocationReqDto location : dto.getLocation()) {
            for (PartyDataReqDto party : dto.getPartyData()) {
                travelId = travelRepository.callInsertTravelData(
                        (travelId == null) ? travelName : null,
                        location.getAddr(),
                        location.getLat(),
                        location.getLng(),
                        party.getUserId(),
                        dto.getDate()
                );
            }
        }
        return travelId;
    }
}

 

TravelPlanReqDto에서는 여행에 필요한 날짜 정보와 함께갈 인원, 장소 정보를 리스트 형식으로 받아옵니다.

이를 서비스 계층에서 처리하여 저장합니다.

 

package com.korea.triplocation.service;

import com.korea.triplocation.api.dto.request.travel.LocationReqDto;
import com.korea.triplocation.api.dto.request.travel.PartyDataReqDto;
import com.korea.triplocation.api.dto.request.travel.TravelPlanReqDto;
import com.korea.triplocation.api.dto.request.travel.TravelUpdateReqDto;
import com.korea.triplocation.api.dto.response.MyTravelInfoRespDto;
import com.korea.triplocation.domain.travel.entity.*;
import com.korea.triplocation.repository.TravelRepository;
import com.korea.triplocation.security.PrincipalUser;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class TravelService {
    private static final String IMAGE_URL = "http://localhost:8080/image/region/";

    private final TravelRepository travelRepository;

    public void travelSave(List<TravelPlanReqDto> travels) {
        String travelName = UUID.randomUUID().toString();
        Integer travelId = null;

        for (TravelPlanReqDto dto : travels) {
            if (dto == null || dto.getLocation() == null || dto.getPartyData().isEmpty()) continue;

            travelId = saveTravelData(travelName, travelId, dto);
        }
    }

    private Integer saveTravelData(String travelName, Integer travelId, TravelPlanReqDto dto){
        for (LocationReqDto location : dto.getLocation()) {
            for (PartyDataReqDto party : dto.getPartyData()) {
                travelId = travelRepository.callInsertTravelData(
                        (travelId == null) ? travelName : null,
                        location.getAddr(),
                        location.getLat(),
                        location.getLng(),
                        party.getUserId(),
                        dto.getDate()
                );
            }
        }
        return travelId;
    }
CREATE DEFINER=`admin`@`%` PROCEDURE `InsertTravelData`(IN travelName VARCHAR(255), IN addr VARCHAR(255), IN lat decimal(18,10), IN lng decimal(18,10), IN userId integer, IN scheduleDate date)
BEGIN
    DECLARE v_travelId INT DEFAULT (SELECT MAX(travel_id) FROM travels_tb);
    DECLARE v_locationId INT;
    DECLARE v_scheduleId INT;

    -- Check if the travel name is NULL
    IF travelName IS NOT NULL THEN
        -- Insert into travels_tb and get the generated ID
        INSERT INTO travels_tb(travel_name) VALUES (travelName);
        SET v_travelId = LAST_INSERT_ID();
    END IF;

    -- Check if the same dateId and visitDate already exist in schedule_tb
   IF NOT EXISTS (SELECT 1 FROM schedule_tb WHERE travel_id = v_travelId AND schedule_date = scheduleDate) THEN
    -- Insert into schedule_tb and get the generated ID
    INSERT INTO schedule_tb(travel_id, schedule_date) VALUES (v_travelId, scheduleDate);
    SET v_scheduleId = LAST_INSERT_ID();
ELSE 
    -- If record already exists, get the schedule_id
    SET v_scheduleId = (SELECT schedule_id FROM schedule_tb WHERE travel_id = v_travelId AND schedule_date = scheduleDate);
END IF;

    -- Insert into location_tb and get the generated ID
    IF NOT EXISTS (SELECT 1 FROM location_tb WHERE address = addr) THEN
    
    INSERT INTO location_tb(address, location_x, location_y) VALUES (addr, lat, lng);
    SET v_locationId = LAST_INSERT_ID();
ELSE
	SET v_locationId = (SELECT location_id FROM location_tb WHERE address = addr);
END IF;

    -- Insert into travel_participants_tb, ignore if the pair (travel_id, user_id) already exists
    IF NOT EXISTS (SELECT 1 FROM travel_participants_tb WHERE travel_id = v_travelId AND user_id = userId) THEN
    INSERT INTO travel_participants_tb(travel_id, user_id) VALUES (v_travelId, userId);
END IF;

    -- Insert into travel_routes_tb
    IF NOT EXISTS (SELECT 1 FROM travel_routes_tb WHERE schedule_id = v_scheduleId AND location_id = v_locationId) THEN
    
    INSERT INTO travel_routes_tb(schedule_id, location_id) VALUES (v_scheduleId, v_locationId);
    END IF;
    
    SELECT v_travelId, v_locationId, v_scheduleId;
END

여행 이름은 사용자에게서 받지 않고, 랜덤으로 생성된 UUID를 사용하여 저장합니다.

그리고 이 저장된 여행 이름에 따라 여행을 저장하고,

저장된 여행에 따라 위치 정보를 추출하여 저장하는 로직을 구현하였습니다.

이 서비스를 거쳐 프로시저를 호출하여 일관성을 유지합니다.

이렇게 하여 여행 일정 생성 도메인의 핵심적인 부분을 다루었습니다.

728x90
반응형