서론
너무 프론트에만 치우친 포스팅이 될 것 같아서 글을 하 나 더 썻습니다.
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
ㄱ. Place
시설에 대한 테이블입니다.
ㄱ. Share
시설 대여조건에대 대한 테이블입니다.
ㄴ. Rental
시설의 예약결과 테이블입니다.
2. 구조
- 예약페이지인 reservation은 placeDetailView에서 진입 가능
- 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);
이렇게 넘어간 자료들을 바탕으로 아래 포스팅한 캘린더가 작성이 되었습니다.
위에 서술한대로 고칠점이 좀 많은 코드이긴 한데, 시간이 허락한다면 수정하도록 하겠습니다.
'IDE & Framework > 분류중' 카테고리의 다른 글
[jsp] getParameter, getAttribute 차이 [짧] (0) | 2021.07.01 |
---|---|
JSP-톰캣 DataSource-server context를 사용한 DB connect (0) | 2021.06.02 |
JS 상호작용되는 달력 만들기 (4) - 예약달력 (중) (0) | 2021.06.01 |
JS 상호작용되는 달력 만들기 (3) - 예약달력 (상) (5) | 2021.06.01 |
JS 상호작용되는 달력 만들기 (2) - 날짜 검색 달력 (1) | 2021.05.31 |