티스토리 뷰
예약 가능 조건 확인
- 예약 가능한 일자인지 체크
- 휴무일 여부 체크
- 해당 예약가능 날짜 안에 사용시간대 리스트 중 예약 가능 불가능 체크
1,2,3 내용이 포함된 전체적인 틀 코드(캘린더예약 시스템 (1) 에 연장선)
// 최종 캘린더 리스트
List<CalandarVO> resultList = new ArrayList<>();
//해당 예약상품의 사용시간리스트 조회(날짜별 사용중인 시간대 포함)
List<Map<String,String> useTimeList = new ArrayList<>();
//휴무일 리스트 조회
List<HolidayVO> holidayList = new ArrayList<>();
//캘린더 일자별 반복문 실행
for(LocalDate dt : dtList){
CalandarVO<Map<String,Object>> vo = new CalendarVO<>();
Map<String,Object> map = new LinkedHashMap<>();
//일자별 예약 내용 map 화처리
map = calandarUtil.convertCalendarToMap(useTimeList,dt.toString());
//휴무일 체크
boolean holi = checkHolidayDate(holidayList,dt.toString());
//사용시간 예약 가능 , 불가능 체크
//사용시간 선택은 연속 3시간만 가능
calandarUtil.validatorUseTimeCheck(map,3,tmp.toString());
vo.getEtcMap().put("date",dt.toString()); //해당 일자
vo.getEtcMap().put("close",holi); //휴무일 여부 true,false
vo.setData(map);// 해당 일자에 들어가는 정보
resultList.add(vo);
}
메인 코드 상세 설명
CalandarVO.class
→ 일자 정보를 담는 클래스
public class CalendarVO<T> {
/**Object 정보*/
private T data;
/**요일 배열*/
private String[] week = {"월","화","수","목","금","토","일"}
/**기타 정보**/
private Map<String,Object> etcMap = new HashMap<>();
...
}
checkHolidayDate()
→ 휴무일 체크
List<HolidayVO> 리스트에 해당 예약 상품에 휴무일 일자 정보를 가져온다.
리스트 정보를 비교를 통해 같은 일자가 존재하는지 확인하여 boolean 값을 전달
boolean checkHolidayDate(List<HolidayVO> list, String date){
//일자에 해당하는 휴일 정보가 있는지 확인
HolidayVO vo = list.stream().filter(x-> x.isCloseDt(date)).findFirst().orElse(null);
//stream filter를 통해 조회하는 일자가 존재 하지 않을 경우 휴일이 x
if(vo == null){
return false;
}
return true;
}
convertCalendarToMap()
→ 일자에 포함되는 내용 map화
Map<String,Object> convertCalendarToMap(List<Map<String,Object>> list, String date){
//사용시간 (활성,비활성) 체크 여부 리스트
List<Map<String,String>> useList = new ArrayList<>();
//일자 데이터 정보
//LinkedHashMap을 쓰는 이유는 저장된 순서대로 사용하기 위해서
//HashMap 은 랜덤으로 저장되어 순서대로 정렬되기 어렵다.
Map<String,Object> map = new LinkedHashMap<>();
int index = 1;
for(Map<String,Object> tmp2 : list) {
//캘린더 사용시간 출력 데이터
Map<String,String> subMap = new HashMap<String, String>();
//캘린더 사용시간 예약 가능, 불가능 여부 확인 위한 데이터
Map<String,String> useMap = new HashMap<String, String>();
String key = "check_"+tmp2.get("tIdx");
String date = tmp2.get("yeyakDate") == null ? "" : tmp2.get("yeyakDate").toString();
//calendarDate 일자에 맞는 데이터 추출 ex) 2000-01-01홍길동
String yeyakDate = "".equals(date) ? "" : Arrays.stream(date.split(",")).filter(x->x.contains(calendarDate)).findFirst().orElse("");
//date 자체가 없는 경우 신청자가 없음으로 인식
if(!yeyakDate.isEmpty()) {
//이름 추출 ex) 2000-01-01홍길동 -> 홍길동 추출
String name = yeyakDate.isEmpty() ? "" : yeyakDate.substring(10);
subMap.put("useCheck", "Y");
subMap.put("name",name);
useMap.put("use", "Y");
}else {
subMap.put("useCheck", "N");
subMap.put("name", "");
useMap.put("use", "N");
}
subMap.put("tIdx", tmp2.get("tIdx").toString());
map.put(key, subMap);
useMap.put("index", index+"");
useMap.put("tIdx", tmp2.get("tIdx").toString());
useList.add(useMap);
index++;
}
//해당 일자 사용시간 리스트 정보
map.put("usetimes_"+calendarDate, useList);
return map;
}
validatorUseTimeCheck()
→예약가능 날짜에서 사용시간별로 선택할 수 있는지 없는지 여부 확인
예시) 3시간 예약을 해야하는 조건일 경우
- 3시간 예약은 연속적만 가능
- 3시간 예약이 불가능 할 경우 예약불가
사용시간 예약자 가능여부
□ | 09:00~10:00 | 예약불가 | |
▣ | 10:00~11:00 | 홍길동 | 예약불가 |
▣ | 11:00~12:00 | 홍길동 | 예약불가 |
▣ | 12:00~13:00 | 홍길동 | 예약불가 |
□ | 13:00~14:00 | 예약불가 | |
□ | 14:00~15:00 | 예약불가 |
void validatorUseTimeCheck(Map<String,Object> map, int timeCnt, String date) {
//해당 일자에 사용시간 리스트
List<Map<String,String>> useTimes = (List<Map<String,String>>) map.get("usetimes_"+date);
//해당 일자에 사용중이지 않은 사용시간 리스트
//java 8 버전 부터 제공하는 stream() 사용
List<Map<String,String>> notUseTimes =
useTimes.stream().filter(x-> "N".equals(x.get("use"))).collect(Collectors.toList());
//사용시간 리스트 개수
int len = useTimes.size();
int nlen = notUseTimes.size();
for(int i=0; i<len; i++){
Map<String,String> checkMap = (Map<String,String>) map.get("check_"+useTimes.get(i).get("tIdx"));
for(int j=0; j<nlen; j++){
boolean flag = true;
int s = 0;
int s2 = 0;
//미사용중인 사용시간만 확인
if(useTimes.get(i).get("tIdx").equals(notUseTimes.get(j).get("tIdx")){
s = Integer.parseInt(notUseTimes.get(j).get("index"));
//애초에 사용가능 시간대 개수가 신청개수보다 작을 경우 예약불가
if(timeCnt > nlen){
checkMap.put("ispossible","N");
flag = false;
}else {
//리스트 기준 왼쪽 element 확인
int left = 0;
int right = 0;
s2 = s;
// j 번째 기준으로 왼쪽과 오른쪽 데이터를 비교 체크 timeCnt - 1인 이유는 자기 자신은 제외
for(int a=0; a<timeCnt-1; a++){
s -= 1;
s2 += 1;
//s 요소 앞에 element와 비교
if((j-a-1) >= 0){
if(s == Integer.parseInt(notUseTimes.get(j-a-1).get("index"))){
left++;
}
}
//s2 요소 뒤에 element와 비교
if((j+a+1) < nlen){
//s2요소와 같이 않을 경우 예약 불가 표시
if(s2 == Integer.parseInt(notUseTimes.get(j+a+1).get("index"))){
right++;
}
}
}
//리스트 기준 왼쪽은 true이고 오른쪽은 false 일 경우 예약 가능하지만 체크는 불가능
if(left == (timeCnt-1) && right != (timeCnt-1)){
//timeCnt 보다 크거나 같을 경우 예약가능이지만 체크는 불가능
if((left + right + 1) >= timeCnt){
checkMap.put("ispossible","P");
flag = false;
}
//둘다 false 일경우
}else if(left != (timeCnt-1) && right != (timeCnt-1)){
//timeCnt 보다 크거나 강ㅌ을 경우 예약가능하지만 체크는 불가능
if((left + right + 1) >= timeCnt){
if(left > 0 && right > 0){
checkMap.put("ispossible","P");
flag = false;
}
}else {
checkMap.put("ispossible","N");
flag = false;
}
//리스트 기준 왼쪽이 false 오른쪽이 right일 경우
}else if(left != (timeCnt-1) && right == (timeCnt - 1)){
//right 해당하는 위치에서 제공하는 사용시간 개수보다 작을 경우 예약 불가
if(len - Integer.parseInt(notUseTimes.get(j).get("index")) < (timeCnt-1)){
checkMap.put("ispossible","N");
flag = false;
}
}
}
//예약 가능한 상황인 경우
if(flag){
//만약 마지막 사용시간들 중 신청가능개수보다 작을 경우 예약은 가하지만 체크는 불가능
if((len-1)-i < (timeCnt-1)){
checkMap.put("ispossible","P");
}else{
checkMap.put("ispossible","Y");
}
}
}
}
//notUseTimes에 없는 정보는 이미 신청된 정보이므로 ispossible은 N으로 처리
if(checkMap.get("ispossible") == null){
checkMap.put("ispossible","N");
}
map.put("check_"+useTimes.get(i).get("tIdx"), checkMap);
}
//예약정보 체크용으로 사용한 데이터는 캘린더에 출력을 안하기 떄문에 제거
map.remove("usetimes_"+date);
}
결과 화면 (1번케이스)
- 3time식 선택 가능하다고 하였을 때 3time 신청이 불가능 한 경우는 선택하지 않아도 이미 예약 불가로 처리되는 것을 확인
- 그리고 예약 가능한 번호는 10:00 ~ 11:00 만 가능하다. (3time 신청 조건은 연속적이어야 하기 때문에) 11:00~12:00 그리고 12:00~13:00에는 직접 체크가 불가능하다.
결과 화면 (2번케이스)
후기)
처음 달력을 이용한 예약 시스템을 작업을 할때 어떤 방식을 선택해야하나 고민이 많았습니다.
사실은 방법이 하나로 정해져있는건 아닙니다. 다만 SQL로 주로 작업을 하는게 편하다고 느끼고 있었지만
이전 작업자에게 인수인계를 받는 과정에서 달력 쿼리를 이해하는데 시간이 많이 투자가 되고 코드 가독성에 있어서 어려움이 있다는 것을 알게되었습니다.(저는 그랬어요 ㅠㅠ) 그렇다 보니 유지보수할때 조금 코드 일기에 시간소요가 덜 될 수 있는 방법이 무엇일까 고민하다 선택하게 되었는데요. 나름 열심히 코드에 대한 주석과 정리를 통해 다음 사람이 유지보수를 할때 어려움이 없을 수 있도록 했다는 생각이 들어 뿌듯한 시간이었습니다.
이 글을 보시게될 분이라면 한번쯤은 이런 고민을 해보시는 것도 정말 좋지 않나 생각이 듭니다.
그러고 보니 validatorUseTimeCheck() 부분의 대관여부 체크 알고리즘을 DP를 이용해서 좀 더 코드를 간략하게 정리 할 수 있을거 같은 생각이 드네요~ 해봐야겠어요~
TMI) 중간에 알고리즘 코드가 길어지는데 이건 왜 계속 코드블럭에 들어가면 무너질까요? ㅠㅠ
'프로그램 언어 > JAVA' 카테고리의 다른 글
java 캘린더 예약 시스템 (1) jdk1.8 기준 (0) | 2023.11.27 |
---|---|
자바(java) 시작 날짜와 마지막 날짜 사이의 리스트를 구하는 방법 (0) | 2023.05.17 |
JSP/SERVLET ServletFileUPload 이용한 HttpServletRequest 데이터 처리 방법(파일 포함) (0) | 2023.05.16 |
자바(java)에서 제공하는 lock 기능 (0) | 2023.05.03 |
자바(자바) stream 특정 key 값 중복 제거 처리 방 (0) | 2023.05.02 |
- Total
- Today
- Yesterday
- 스케줄러
- 리눅스
- 격리수준
- insert
- ncp
- 권한
- 캐시
- Lock
- 이미지
- hazelcast
- spring
- MySQL
- 캘린더
- 알고리즘
- 정의
- 컨테이너
- dockerfile
- Cache
- Quartz
- docker
- leatcode
- Java
- 도커
- 네이버 클라우드
- LocalDate
- dfs
- 개념 이해하기
- mybatis
- Linux
- centos7
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |