2022.07.15 TIL + FullCalendar / 백엔드와 프론트엔드의 역할

Wintering·2022년 7월 15일
0

2022TIL

목록 보기
71/87

7월15일(금)

내일배움캠프 D+88👾

Today I Learned ✅
JavaScript FullCalendar 사용하기 가이드

  • FullCalendar
(function () {
    $(function () {
        // calendar element 취득
        var calendarEl = $('#calendar')[0];
        // full-calendar 생성하기
        var calendar = new FullCalendar.Calendar(calendarEl, {
            height: '500px', // calendar 높이 설정
            expandRows: true, // 화면에 맞게 높이 재설정
            // slotMinTime: '08:00', // Day 캘린더에서 시작 시간
            // slotMaxTime: '20:00', // Day 캘린더에서 종료 시간
            // 해더에 표시할 툴바
            headerToolbar: {
                left: 'prev,next today',
                center: 'title',
                // right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
                right: 'dayGridMonth'
            },
            initialView: 'dayGridMonth', // 초기 로드 될때 보이는 캘린더 화면(기본 설정: 달)
            // initialDate: '2021-07-15', // 초기 날짜 설정 (설정하지 않으면 오늘 날짜가 보인다.)
            // navLinks: true, // 날짜를 선택하면 Day 캘린더나 Week 캘린더로 링크
            // editable: true, // 수정 가능?
            // selectable: true, // 달력 일자 드래그 설정가능
            nowIndicator: true, // 현재 시간 마크
            dayMaxEvents: true, // 이벤트가 오버되면 높이 제한 (+ 몇 개식으로 표현)
            locale: 'ko', // 한국어 설정
            eventAdd: function (obj) { // 이벤트가 추가되면 발생하는 이벤트
                console.log(obj);
            },
            // eventChange: function(obj) { // 이벤트가 수정되면 발생하는 이벤트
            //     console.log(obj);
            // },
            // eventRemove: function(obj){ // 이벤트가 삭제되면 발생하는 이벤트
            //     console.log(obj);
            // },
            select: function (arg) { // 캘린더에서 드래그로 이벤트를 생성할 수 있다.
                // var title = prompt('Event Title:');
                // if (title) {
                //     calendar.addEvent({
                //         title: title,
                //         start: arg.start,
                //         end: arg.end,
                //         allDay: arg.allDay
                //     })
                // }
                // calendar.unselect()
            },
            // 이벤트

            eventSources: [
                {
                    url: '/api/cafes/calender?id=' + id,
                    color: 'yellow',
                    textColor: 'black'
                },
                {
                    url: '/hosts/profile/api/cafes/calender/schedule?id=' + id,
                    color: 'aliceblue',
                    textColor: 'black'
                }
            ]
        });
        // 캘린더 랜더링
        calendar.render();
    });
})();

오늘 사용한 FulCalendar의 코드, 다양한 기능을 팀장님이 이미 구현해놓으셔서 나는 원래 등록되어있던 예약 내역 말고, 카페별 휴무일을 등록하는 과정을 추가했다.

원래의 코드는

events: '/api/cafes/calender?id'+id 

의 형태였는데, 일정을 받아올 url이외에, 휴무일을 받아올 api url이 필요했기 때문에 공식문서의 가이드에 따라

eventSources: [
                {
                    url: '/api/cafes/calender?id=' + id,
                    color: 'yellow',
                    textColor: 'black'
                },
                {
                    url: '/hosts/profile/api/cafes/calender/schedule?id=' + id,
                    color: 'aliceblue',
                    textColor: 'black'
                }
            ]
        });

의 형태로 바꿔서 받아주었다.
하지만 가이드에 따라 잘 진행했음에도, 휴무일이 불러와지지 않았는데 첫번째로는, 내가 휴무일을 불러올 컨트롤러의 상단에 'RequestMapping("/hosts/profile")'을 써놓은 것을 까먹고 GetMapping에 매핑 된 주소로만 api를 불러서 주소를 찾을 수 없어서 나타난 오류였고, 오류를 해결하니 500에러로 내 해당 컨트롤러에서 template Resolving Error가 자꾸 떴다. 이는 ApiController와 Controller의 차이였다.

팀장님의 컨트롤러는 태초에 작성을 RestController로 해주었기 때문에, 다른 과정이 필요하지 않았으나,

@RestController
public class CafeApiController {
    @GetMapping("/api/cafes/calender")
    public List<CafeCalenderInfoResponseDto> ReadCafeEventInfo(@RequestParam Long id){
        return cafeService.findEventListForCalenderByCafeId(id);
    }
 }

나의 컨트롤러는 원래 있던 일반 Controller였기 때문에, @RequestBody를 붙여주어야 오류가 뜨지 않고 정상적으로 작동했다.

@Controller
public class hostProfileController {
    @ResponseBody
    @GetMapping("/api/cafes/calender/schedule")
    public List<CafeCalenderInfoResponseDto> ReadCafeScheduleInfo(@RequestParam Long id) {
        return cafeScheduleService.findScheduleListForCalenderByCafeId(id);
    }
}

Today I Learned ✅
백엔드와 프론트엔드

어떤 로직에 대한 처리를 할 때, 내가 프론트엔드가 해줘야할 것과 백엔드에서 처리를 해야할 것에 대해 상당히 혼용된 개념을 갖고 있었고 그에 따라 불필요한 생각을 많이 했다는 걸 오늘 튜터님과의 질의응답을 통해 느꼈다.

내가 오늘 구현하고자 했던 것은 이벤트의 시작일이 7일 이내면 취소가 불가능하게 처리하는 것이었다.
처음에 구상한 로직은 아래와 같았고, 다음과 같은 문제점들이 있었다.

1. EventDB에 CancelAvail이라는 취소가 가능한 상태인지 점검해주는 컬럼 추가
2. 백엔드에서, 이벤트 시작일과 현재일을 비교하여 7일 이내라면 DB의 CancelAvail값을 false로 업데이트
3. 프론트엔드에서 cancelAvail의 컬럼값을 비교하여, true면 버튼을 활성화하고, false면 버튼을 비활성화
  • 문제점
    • 버튼이 보이고 안보이고는 온전히 프론트엔드의 영역, 백엔드에서부터 db에 접근해서 컬럼을 바꾸고 말고하는 비효율적인 처리를 할 필요가 X ( 어플리케이션의 성능을 가장 많이 떨어뜨리는 요인 중 하나는 DB에 접근하는 것)
    • CancelAvail을 바꿔준다는 것 자체가 백엔드에서 수정되긴 했지만, url을 타고 직접 api에 접근했을 때 수정이나 삭제를 막아주는 역할을 하지는 못한다. 즉 위의 로직은 백엔드에 관한 처리가 되어있지 않다.
    • CancelAvail이라는 컬럼을 바꿔준다는 건 한번 서버를 불러올 때마다 db를 불러오고 -> 다시 db에 들어가서 정보를 수정하고, 그 정보를 다시 받아오는 등 db에 접근만 3번이 일어난다. db의 정보를 통해 정보를 수정하는 컬럼은 추가될 필요도 없고 추가되어봤자 성능만 떨어뜨린다

적어보고 나니 너무나 당연한데, 로직을 짤 때는 알아채지 못했고 다른 코드들도 비슷하게 처리하려 했어서 내가 개념을 굉장히 많이 혼동하고 있음을 깨달았다. 그리고 다음과 같이 해결했다.

  • 해결 후 로직
--백엔드처리--
1. Service클래스에 StartDate와 현재날짜를 비교하여, true/false를 리턴하는 메소드 추가 
2. delete를 구현하는 Api controller에 생성한 메소드를 추가하여, 
   메소드가 true일 때만 삭제 로직을 수행하고, false면 삭제 로직을 수행하지 않음
   (DB에 접근할 필요가 X, 효율적으로 삭제처리를 막을 수 있다.)

--프론트엔드처리--
1. Event엔티티를 받아서 매핑해줄 EventResponseDto를 생성
2. EventResponseDto에 CancelAvail이라는 변수 추가 
   (DB에 컬럼을 추가한 게 아니라, Dto에만 컬럼추가. DB의 StartDate에 관한 정보만을 받아서
   생성자에서 해당 정보로 CancelAvail에 대한 결과를 리턴해주는 메소드를 따로 만들어서, 
   값을 넣어줌  -> DB에는 없지만, 프론트엔드쪽으로는 cancleAvail에 관련된 값이 넘어감)
3. if문을 사용하여 해당 변수의 값이 true면 버튼 활성화, false면 버튼 비활성화

(+) 올바르게 로직을 이해하고 구현해야 하는 중요성을 다시 한 번 깨달았고, 내 잘못된 지식을 바로잡을 수 아주 TIL 쓰기 보람찬 날이었따.

1개의 댓글

comment-user-thumbnail
2022년 7월 15일

지나가다 댓글 남겨 봅니다...ㅎㅎ
DB에 여러 번 접근 한다는 것은 비효율 적이라는 의견에 동의 합니다.
하지만 구현하신 cancelAvail의 동작 방식(?)에 대해선 다른 방향으로 한번 생각해볼 수도 있을것 같아요
개인적으로, 프론트는 믿지 말자 라는 생각이 있어서 업데이트 여부 판별을 프론트에서만 해주는 것은 좀 위험해 보이고 디비 접근같은 경우도, '꼭 cancelAvail이라는 컬럼이 필요한가' 에 대한 고민도 한번 해볼만한 것 같습니다.

답글 달기