IDE & Framework/분류중

JS 상호작용되는 달력 만들기 (5) - 예약달력 (하)

Greensky0026 2021. 6. 1. 16:37
반응형

서론

 너무 프론트에만 치우친 포스팅이 될 것 같아서 글을 하 나 더 썻습니다.

MVC패턴에서 달력을 출력하기 위한 백엔드 작업을 기술하겠습니다.

View는 두개의 게시글에 걸쳐서 썼으니 제외하겠습니다.

 

목차

1. DB

    ㄱ. Place

    ㄴ. Share

    ㄷ. Rental

2. 구조

3. 데이터 정제

    ㄱ. 총 이용가능시간 계산

    ㄴ. 예약확인용 rental의 DTO 생성

    ㄷ. 이번달과 다음달로 데이터를 나눠 담을 준비

    ㄹ. DAO를 호출해 rental의 data를 정제 후 이번달, 다음달로 분류

    ㅁ. 달별로 나눈 데이터를 일별로 나눈다

        a. 사용할 맵 생성

        b. rental을 Dto_Refine_rental로 정제해서 map에 입력

4. 데이터 전송 준비

    ㄱ. JSONArray선언

    ㄴ. 변환 및 예약이 가득찬 날 계산

5. 데이터 전송

 


1.  DB

프로젝트의 ERD중 일부
좌측부터 각각 Share, Rental, Place

ㄱ. Place

 시설에 대한 테이블입니다.

ㄱ. Share

 시설 대여조건에대 대한 테이블입니다.

ㄴ. Rental

 시설의 예약결과 테이블입니다.

 

2.  구조

프로젝트의 IA중 일부

  • 예약페이지인 reservationplaceDetailView에서 진입 가능
  • PlaceDetailView는 Share_DTO를 보유하고 있음
  • Share의 외래키 place_no으로 place 및 rental 모두를 탐색할 수 있음
  • PlaceDetailView가 reservation에게 Share_DTO를 넘겨주게 함

필요한 데이터 선별

  • 공통 예약건수별 예약일자
  • 달력 : 게시자가 지정한 예약불가 요일, 예약이 있는 일자, 예약이 다 찬날
  • 시간표 : 게시자가 지정한 예약가능 시간, 시설의 대여시간당 가격, 예약건수별 예약시간, 

데이터 정제 필요성

  •  달력 및 시간표를 띄우는데 있어서 위의 정보가 다 필요하지 않음
  •  어차피 연산을 해야할 자료가 있다면 client보다 server에서 연산하는게 빠름 

 

3. 데이터 정제

Share의 DTO를 detailview로부터 받아옴

 * 전 페이지에서 작업하던 객체로써, place + share 전 항목이 입력되어 있음

Dto_Share detail;

ㄱ. 총 이용가능시간 계산

int totalTime = detail.getEndTime() - detail.getStartTime();

이후 예약이 가득 찬 날을 판별하기 위해 사용

 

ㄴ. 예약확인용 rental 새 DTO 생성

public class Dto_Reservation_rental {
	int month;
	int date;
	int startTime;
	int usingTime;
	
	public Dto_Reservation_rental(){ }
	
	public Dto_Reservation_rental(int month, int date, int startTime, int usingTime) {
		this.month = month;
		this.date = date;
		this.startTime = startTime;
		this.usingTime = usingTime;
	}

예약자의 정보가 없는 이유

  • 예약자가 달력을 볼 떄 누가 햿느냐는 중요하지 않고 예약이 차있어서 선택이 못한다는것이 중요
  • rental에서 달, 일, 시작시간, 예약시간(예약종료시간-예약시작시간)만을 담음

 

ㄷ. 이번달과 다음달로 데이터를 나눠 담을 준비

        Calendar currentCalendar = Calendar.getInstance();
        int month  = Integer.parseInt(df.format(currentCalendar.get(Calendar.MONTH) + 1));
		
        //dto를 이번달과 다음달로 분류
		ArrayList<Dto_Reservation_rental> thisMonthDtos = new ArrayList<Dto_Reservation_rental>();
		ArrayList<Dto_Reservation_rental> nextMonthDtos = new ArrayList<Dto_Reservation_rental>();
  • 사전에 데이터의 갯수 파악이 불가하므로 ArrayList 사용
  • 예약가능한 날자가 제약사항으로 인해 사실상 이번달과 다음달밖에 없기에 직접 생성함

 

ㄹ. DAO를 호출해 rental의 data를 정제 후 이번달, 다음달로 분류

Dao_Reservation dao = new Dao_Reservation();
ArrayList<Dto_Reservation_rental> dtos = dao.refineShares(detail.getPlace_no());
		
//dto를 이번달과 다음달로 분류
for(Dto_Reservation_rental dto : dtos) {
	System.out.println("이번달 : " + month + "   dto의 달 : " + dto.getMonth());
	if (dto.getMonth() == month) {
		thisMonthDtos.add(dto);
	} else {
		nextMonthDtos.add(dto);
	}

! 쿼리 사용시

String query1 = "SELECT checkInDate, startTime, endTime ";
String query2 = "FROM (SELECT *, TIMESTAMPDIFF(DAY, now(), checkInDate) timeDiff FROM rental WHERE place_no = ? AND cancellationDate IS NULL) r ";
String query3 = "WHERE r.timeDiff BETWEEN 1 AND 31 ";
String query4 = "ORDER BY checkInDate ASC, startTime ASC";
String query = query1 + query2 + query3 + query4;
        
  • timeDiff을 사용해 예약가능일자(금일기준 내일~+30일 이전)만을 호출 

ㅁ. 달별로 나눈 데이터를  일별로 나눈다

a. 사용할 맵 생성

LinkedHashMap<Integer, Dto_Refine_rental> thisMonthResMap = 
		new LinkedHashMap<Integer, Dto_Refine_rental>();
LinkedHashMap<Integer, Dto_Refine_rental> nextMonthResMap = 
		new LinkedHashMap<Integer, Dto_Refine_rental>();
             
  • LinkedHashMap사용 이유 : 정렬된 자료의 순서를 유지하기 위해 사용함
  •  구성 : key : 날짜, value :  rental을 정제한 Dto_Refine_rental의 인스턴스

 

b.  rental을 Dto_Refine_rental로 정제해서 map에 입력

for (Dto_Reservation_rental dto : thisMonthDtos) {
  Dto_Refine_rental refineData;
  //예약일자가 map에 존재하지 않는다면 추가
  if (thisMonthResMap.containsKey(dto.getDate()) == false) {
    //map에 넣을 dto 생성
    refineData = new Dto_Refine_rental();
  } else {
    //이 경우는 이미 map에 존재하므로, 불러온다
    refineData = thisMonthResMap.get(dto.getDate());
  }
  refineData.insertData(detail.getStartTime(), dto.getStartTime(), dto.getUsingTime());
  //해당 키값의 벨류를 갱신시켜준다. (put은 갱신 및 추가 둘다 사용 가능
  thisMonthResMap.put(dto.getDate(), refineData);
}

for (Dto_Reservation_rental dto : nextMonthDtos) {
  Dto_Refine_rental refineData;
  //예약일자가 map에 존재하지 않는다면 추가
  if (nextMonthResMap.containsKey(dto.getDate()) == false) {
    //map에 넣을 dto 생성
    refineData = new Dto_Refine_rental();
  } else {
    //이 경우는 이미 map에 존재하므로, 불러온다
    refineData = nextMonthResMap.get(dto.getDate());
  }
  refineData.insertData(detail.getStartTime(), dto.getStartTime(), dto.getUsingTime());
  //해당 키값의 벨류를 갱신시켜준다. (put은 갱신 및 추가 둘다 사용 가능
  nextMonthResMap.put(dto.getDate(), refineData);
}

Dto_Refine_rental

public class Dto_Refine_rental {

	ArrayList<Integer> startNum;
	ArrayList<Integer> shareTime;
	int totalShareTime;
	
	public Dto_Refine_rental(){
		startNum = new ArrayList<Integer>();
		shareTime = new ArrayList<Integer>();
		totalShareTime = 0;
	}
	
	public void insertData(int shareStartTime, int rentalStartTime, int useTime){
		int sNum = rentalStartTime - shareStartTime;
		startNum.add(sNum);
		this.shareTime.add(useTime);
		totalShareTime += useTime;
	}
}

예약일자가 필요없는 이유

  • rental에 date값이 존재하기 때문
  • rental의 date값으로 map의 Key를 탐색하거나 생성한 이후 정제하기 때문
  • 굳이 종료시간-시작시간을 연산해 사용시간을 사용하는 이유
  • 여기서 계산하지 않으면 어차피 js에서 연산해야 하기 떄문에 정제하는김에 같이 정제

 

4. 데이터 전송 준비

ㄱ. JSONArray선언

JSONArray thisMonthResData = new JSONArray();
JSONArray nextMonthResData = new JSONArray();

ㄴ. 변환 및 예약이 가득찬 날 계산

for(Map.Entry<Integer, Dto_Refine_rental> refineData :thisMonthResMap.entrySet()) {
	Dto_Refine_rental dto = refineData.getValue();
			
	JSONObject jsonObject = new JSONObject();
	jsonObject.put("date", refineData.getKey());
	jsonObject.put("startNum", dto.getStartNum());
	jsonObject.put("shareTime", dto.getShareTime());
	jsonObject.put("totalShareTime", dto.getTotalShareTime());
	thisMonthResData.add(jsonObject);
				
	if(totalTime <= dto.getTotalShareTime()) {
		thisMonthFullDate.add(refineData.getKey());
	}
}

처음부터 JSON쓰면 되는데 Map을 거쳐간 이유

  • 프로젝트 개발일정때문에 중간에 삽질한 부분(맵 사용)을 제거하지 못하고 그대로 사용
  • 이후 시간이 허락한다면 포스팅과 함께 소스도 수정 예정

예약이 가득찬 날 같이 연산하는 이유

  • refine_rental에 총 예약시간도 같이 연산했으므로 전체 순차탐색을 하는김에 같이 실행

 

5. 데이터 전송

// share-detail 정보 dto로 담아 전송
request.setAttribute("DETAIL", detail);

//정제된 rental data(refine_rental)를 이번달과 다음달로 나눠서 전송
request.setAttribute("thisMonthResData", thisMonthResData);
request.setAttribute("nextMonthResData", nextMonthResData);

//예약이 가득 찬 날의 배열
Integer[] thisMonthFullDateList = thisMonthFullDate.toArray(new Integer[thisMonthFullDate.size()]);
Integer[] nextMonthFullDateList = nextMonthFullDate.toArray(new Integer[nextMonthFullDate.size()]);

request.setAttribute("thisMonthFullDateList", thisMonthFullDateList);
request.setAttribute("nextMonthFullDateList", nextMonthFullDateList);

 

 

 이렇게 넘어간 자료들을 바탕으로 아래 포스팅한 캘린더가 작성이 되었습니다.

위에 서술한대로 고칠점이 좀 많은 코드이긴 한데, 시간이 허락한다면 수정하도록 하겠습니다.

 

반응형