Sketcher

FullCalendar 와 DB 연동하기 -2 (이벤트 생성)

완두완두콩 2022. 2. 22. 20:35

FullCalendar 를 이용해서 스케줄 수정(생성) 을 하기 위해 다양한 자료를 찾아보았다.

기존의 FullCalendar 는 좌측의 메뉴에서 Drag&Drop 방식으로 이벤트를 생성하는 것이였는데 

실용적인가 싶기도 하고 , 해당 방법으로는 적용이 잘 되지 않아 날짜를 선택해서

이벤트를 생성하는 방식으로 바꾸었다.

 

오픈소스 라이브러리를 완전히 뜯어봐야 했고 JS 와 ajax 문법에도 무지해서

생각보다 시간이 더 오래걸리고 많이 헤맸다.

HTML


 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  <script>
 
        var calendar = null;
        var initialLocaleCode = 'ko';
        var localeSelectorEl = document.getElementById('locale-selector');
 
            $(document).ready(function (){
 
                    var calendarEl = document.getElementById('calendar');
                    calendar = new FullCalendar.Calendar(calendarEl, {
                        initialDate: '2022-02-07',
                        initialView: 'timeGridWeek',
                        headerToolbar: {
                            left: 'prev,next today',
                            center: 'title',
                            right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
                        },
                        navLinks: true,
                        editable: true,
                        selectable: true,
                        droppable: true// this allows things to be dropped onto the calendar
 
                        eventAdd: function () { // 이벤트가 추가되면 발생하는 이벤트
                            console.log()
                        },
 
                        // eventChange: function (obj) { // 이벤트가 수정되면 발생하는 이벤트
                        //     allEvent = calendar.getEvents();
                        //     console.log(allEvent);
                        // },
                        // eventRemove: function (obj) { // 이벤트가 삭제되면 발생하는 이벤트
                        //     console.log(obj);
                        // },
                        /**
                         * 드래그로 이벤트 추가하기
                         */
                        select: function (arg) { // 캘린더에서 드래그로 이벤트를 생성할 수 있다.
 
 
                            var title = prompt('일정을 입력해주세요.');
                            if (title) {
                                calendar.addEvent({
                                    title: title,
                                    start: arg.start,
                                    end: arg.end,
                                    allDay: arg.allDay,
                                })
                            }
                            var allEvent = calendar.getEvents(); // .getEvents() 함수로 모든 이벤트를 Array 형식으로 가져온다. (FullCalendar 기능 참조)
 
                            var events = new Array(); // Json 데이터를 받기 위한 배열 선언
                            for (var i = 0; i < allEvent.length; i++) {
                                var obj = new Object();     // Json 을 담기 위해 Object 선언
                                // alert(allEvent[i]._def.title); // 이벤트 명칭 알람
                                obj.title = allEvent[i]._def.title; // 이벤트 명칭  ConsoleLog 로 확인 가능.
                                obj.start = allEvent[i]._instance.range.start; // 시작
                                obj.end = allEvent[i]._instance.range.end; // 끝
 
                                events.push(obj);
                            }
                            var jsondata = JSON.stringify(events);
                            console.log(jsondata);
                            // saveData(jsondata);
 
                            $(function saveData(jsondata) {
                                $.ajax({
                                    url: "/full-calendar/calendar-admin-update",
                                    method: "POST",
                                    dataType: "json",
                                    data: JSON.stringify(events),
                                    contentType: 'application/json',
                                })
                                    .done(function (result) {
                                        // alert(result);
                                    })
                                    .fail(function (request, status, error) {
                                         alert("에러 발생" + error);
                                    });
                                calendar.unselect()
                            });
                        },
 
                        // drop: function (arg) {
                        //     // is the "remove after drop" checkbox checked?
                        //     if (document.getElementById('drop-remove').checked) {
                        //         // if so, remove the element from the "Draggable Events" list
                        //         arg.draggedEl.parentNode.removeChild(arg.draggedEl);
                        //     }
                        // }
                    });
                    calendar.render();
        });
 
 
 
 
    </script>
cs

우선 , 코드를 JS 형식으로 많이 바꾸었다. 기존의 addEventListner 방식을 JS 형식으로 바꾸었고

document.addEventListener('DOMContentLoaded', function ()

FullCalendar 에서만 사용하는 함수인

eventAdd: function , select: function 을 추가하여 생성을 했다.

eventAdd 는 이벤트가 추가되면 발생하는 이벤트인데 , 현재 log 값만 찍는 것으로 돼있는데

만약 지우게 되면 이상하게 작동하지 않는 문제가 발생하여 일단 그대로 놔두었다.

 

select 함수는 이벤트를 선택하여 만들었을시에 실행되는 함수인데 이는 뒤에서 리뷰하겠다. 

 

Json 방식으로 데이터를 넘기고, 받는 것이 처음이라 어떤 데이터가 넘어가는지 , 어떻게 받아야하는지

전혀 알지 못해서 막막했었다.

 

우선 console.log(); 를 통해 어떤 데이터가 넘어가는지 확인을 해보기로 했고 무수한 삽질 끝에

다음과 같은 데이터로 첫 가공을 했다.

개발자 도구 콘솔

스케줄을 하나 생성했을 경우에 나타나는 log로 , 각각에 대해서 리뷰해보자면

allDay 는 종일 발생하는 이벤트인지 여부로 아닌 경우에는 false.

나의 경우 의미 있는 값은 아니라서 패스하였다.

end와 start 부분이 가장 중요한데 , 스케줄의 LocalDateTime 이 모두 들어있기에

해당 데이터를 가져올 필요가 있었다.

그 외에는 페이지에 대한 기본 정보와 JS 이기에 start, end 를 가져오기 위해 노력했다.

 

위의 코드에서 자세하게 주석을 달아놓았으니 참고하면 좋을 것 같다.

 

전체적인 흐름은 , allEvent 변수에 생성되는 모든 이벤트의 정보를 Array 형식으로 받고 , 

생성된 개수만큼 for 문을 돌려 obj 변수에 담고 , 

JSON.stringfy 를 이용하여 obj를 String 형식으로 데이터를 변환하여 뿌려지고 전송하는 과정이다.

 

말로 푸니 상당히 간단해보이는 작업인데.. 처음이라 시간이 너무 많이 걸렸다.

하는 도중 , TroubleShooting 하기도 애매한 정말 기본적인 오류가 많이 나왔기에 에러 처리는 패스하였다.

(주로 JSON 형식으로 데이터를 넘기는 데에 있어서 문제가 많았다.)

 

결국 JSON 데이터를 String 식으로 파싱한 결과 

다음과 같은 2차 가공된 데이터가 개발자 콘솔 로그에 찍히게 됐다.

 

(기쁨)

드디어 내가 원하는 데이터로 가공했으니 이제는 Controller 에서 받아봐야하는 일이 남았다.

 

Controller


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
32
  @PostMapping("/calendar-admin-update")
    @ResponseBody
    public String addEvent(@RequestBody List<Map<String, Object>> param) throws Exception {
 
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",Locale.KOREA);
 
        for (int i = 0; i < param.size(); i++) {
 
            String username = (String) param.get(i).get("title");
            String startDateString = (String) param.get(i).get("start");
            String endDateString = (String) param.get(i).get("end");
 
            LocalDateTime startDate = LocalDateTime.parse(startDateString, dateTimeFormatter);
            LocalDateTime endDate = LocalDateTime.parse(endDateString, dateTimeFormatter);
 
            UserDto userDto = UserDto.builder()
                    .username(username)
                    .build();
 
            String user = userService.saveUser(userDto);
            User userEntity = userRepository.findById(user).get();
 
            ManagerHopeTimeDto managerHopeTimeDto = ManagerHopeTimeDto.builder()
                    .user(userEntity)
                    .managerHopeDateStart(startDate)
                    .managerHopeDateEnd(endDate)
                    .build();
 
            managerHopeTimeService.saveManagerHopeTime(managerHopeTimeDto);
        }
        return "/full-calendar/calendar-admin-update";
    }
cs

우선 , 가장 먼저 알게된 사실은 JSON 데이터는 List<Map<String, Object>> 같은 방식으로

받아야한다는 것을 알았다. (List<Map>형태 )

 

데이터를 받는 방식에는 @RequestBody 와 @RequestParam 이 있는데 둘 중 무엇을 써야하나

고민했고 답은 @RequestBody 였다.

이 외에도 게시판 프로젝트에서 사용했던 @ModelAttribute 도 있었는데 이는 

contentType: multipart/form-data 형식을 지원하기에 제외하였다.

 

@RequestParam

@RequestBody

@ModelAttribute

 

결국 , 나는 JSON 형태의 데이터를 Java Object 로 변경하려 했기에 

@RequestBody 어노테이션을 사용하였다.

 

그 후의 과정은 조회에서 JSON 데이터를 받았던 과정과 비슷하다.

JSON 데이터를 받은 만큼 for 문을 돌려서 우선 String 값으로 변수를 만든다.

(JSON.stringfy 를 이용해서 전부 String 값으로 만들었기 때문에 String 으로 값을 받는다.)

 

그 다음, 이제 데이터를 형식에 맞게 가공하는 일만 남았다.

지금은 스케줄을 생성하면 생성된 title(이름)이 user 에 저장되는 방식으로 만들었는데

저장되는게 아닌 , 기존의 user와 매칭해서 스케줄을 생성하는 방식으로 바꾸어야한다.

 

데이터를 넘겨받는 도중 ,

400 에러가 뜨며

Required request body is missing 오류가 콘솔창에 찍혔다.

왜 그럴까 몇번이고 시도해본 끝에 , 날짜 값이 제대로 매칭되지 않아서 생기는

오류임을 확인했다.

스케줄에서 보내주는 JSON 데이터는 다음과 같은 

"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

형태로 전송이 됐는데 , 내 코드에서는 해당 값을 전혀 읽지 못했다.

(+ 기존의 로그에서는 시간이 9시간 빠른 상태로 로그가 찍혔었다.

이를 해결하기 위해 , LOCALE.KOREA 사용)

 

내가 현재 설정한 DateFormat은 

"yyyy-MM-dd HH:mm"

형태로 시간과 분까지만 내게 유효한 데이터였기에 위의 데이터를 가공하기 위해

dateTimeFormatter 로 전체 값을 받고 , 해당 값을 내가 설정한 format 으로

파싱하여 startDate, endDate 에 넣었다.

 

그 후 , Builder 를 통해 Service 에 값을 save 하고 나면 다음과 같은

결과 값이 저장된다.

 

데이터가 넘어가는 중..

 

중구난방 이상한 데이터들

지금 for 문 안의 로직도 제대로 설정이 안됐고 , user 에 값이 저장되는 등 해서

값이 마구마구 생겨버렸지만 어쨋거나 JSON 형식으로 데이터를 받아와서

DB 에 저장하는 것 까지는 성공하였다!..

 

나머지는 제대로 된 로직을 작성하는 일 뿐이다. 라기엔

+ ERD 수정도 해야하고!..

+ 이벤트 수정도 해야하고

+ 이벤트 삭제도 해야하고

+ 테스트케이스 작성도 해야하고

 

생각보다 시간이 더 걸릴 것 같다..

 

FullCalendar 다음편!..

https://dodokong.tistory.com/45?category=1262083

 

FullCalendar 와 DB 연동하기 -3 (이벤트 수정 & 삭제)

FullCalendar 를 이용한 단순 기능 구현은 이번 챕터가 마지막일 것 같다!.. 조회 , 생성을 해보니 어느정도 감이 잡혀서 수정과 삭제는 그리 오랜 시간이 걸리지는 않았다. 문제는 Controller 로직일뿐!

dodokong.tistory.com