JS <-> 컨트롤러 (스프링부트)

김정현·2024년 8월 23일
0

포트폴리오

목록 보기
5/8

JS에서 획득한 데이터를 컨트롤러로 혹은 컨트롤러에서 가공한 파일을 JS파일로 이동시켜 정보를 사용해야 하는 경우가 있다.

이번 프로젝트에선 clickDeparturePoint 라는 JS 배열을 Controller에서 사용하고,

컨트롤러에서 위 배열을 사용해 viaPoints라는 JSON형태의 데이터를 JS파일로 가져와 사용해야했다.

(ajaxLoad 는 구성 되어있음)

const commonLib = {
    /**
     * ajax 요청 공통 기능
     *
     * @param responseType : 응답 데이터 타입(text - text로, 그외는 json)
     */
    ajaxLoad(url, method = "GET", data, headers, responseType) {
        if (!url) {
            return;
        }

        const csrfToken = document.querySelector("meta[name='csrf_token']")?.content?.trim();
        const csrfHeader = document.querySelector("meta[name='csrf_header']")?.content?.trim();

        if (!/^http[s]?/i.test(url)) {
            let rootUrl = document.querySelector("meta[name='rootUrl']")?.content?.trim() ?? '';
            rootUrl = rootUrl === '/' ? '' : rootUrl;

             url = /^http[s]?/i.test(rootUrl) ? rootUrl + url : location.protocol + "//" + location.host + rootUrl + url;

            // url = location.protocol + "//" + location.host + rootUrl + url;
        }

        method = method.toUpperCase();
        if (method === 'GET') {
            data = null;
        }

        if (data && !(data instanceof FormData) && typeof data !== 'string' && data instanceof Object) {
            data = JSON.stringify(data);
        }

        if (csrfHeader && csrfToken) {
            headers = headers ?? {};
            headers[csrfHeader] = csrfToken;
        }

        const options = {
            method
        };

        if (data) options.body = data;
        if (headers) options.headers = headers;

        return new Promise((resolve, reject) => {
            fetch(url, options)
                .then(res => responseType === 'text' ? res.text() : res.json()) // res.json() - JSON / res.text() - 텍스트
                .then(data => resolve(data))
                .catch(err => reject(err));
        });
    },
    /**
     * 에디터 로드
     *
     */
    editorLoad(id) {
        if(!ClassicEditor || !id?.trim()) return;

        return ClassicEditor.create(document.getElementById(id.trim()), {});
    }
};

(ajaxLoad 메서드에선 responseType을 명시하지 않는다면 JSON으로 응답받음)
JS파일에서

commonLib.ajaxLoad('walking/map', 'POST', {clickDeparturePoint}, {
                        "Content-Type": "application/json"
                    })
                        .then(response => {
                            console.log('Server Response:', response);
                                callback(response);
                        })
                        .catch(error => {
                            console.error('Error:', error);
                        });

요청 본문에 Controller로 보내야할 clickDeparturePoint 배열을 담아서 보낼 ContentType을 명시한 후, 보낸다.

그리고 응답 받아야하는 정보를 받기위해서

	@ResponseBody
    @PostMapping("/map")
    public String postMainMap(@RequestBody Map<String, List<Map<String, String>>> data) throws JsonProcessingException {
        // Ajax로 선택한 마커 "clickDeparturePoint" 데이터 받아옴
        List<Map<String, String>> clickDeparturePoint = data.get("clickDeparturePoint");

        String viaPoints = mainMapMarkerService.viaMarkerLocation(clickDeparturePoint);
        System.out.println("viapoints:" + viaPoints);
        return viaPoints;
    }

Controller에서 위와 같이 @ResponseBody를 사용한다.

@ResponseBody

-> 메서드의 반환값을 HTTP 응답 본문에 직접 작성

JS에 사용할 데이터(viaPoints)를 응답 본문에 담아서 보낸다. (viaPoints 는 service 파트에서 JSON으로 가공하였다.)

이렇게 한 후, JS에서 ajaxLoad 에서 응답 본문을 처리한다.

.then(response => {
           console.log('Server Response:', response);
                                callback(response);
              })

위와같이 다소 복잡할 거 같아 callback 메서드를 작성하여 처리하였다.

callback 메서드에서 핵심은

 function callback(response) {
       const viaPoints = response;
   .
   .
   .
 }

응답 본문에 담긴 데이터를 객체로 받아 원하는대로 처리하면 된다.
응답받은 데이터는 JSON으로 응답을 보냈기때문에 JS에서 JSON으로 수신받는다.

위와 같이 ajax처리를 한다면 화면이동(url 이동) 없이 데이터를 주고 받으며 자연스러운 화면 처리를 할 수 있다.
ajax 는 fetch 형식의 전송이다.

위와 다르게 화면의 이동이 있을때 데이터를 주고받는 방법이 있는데,

Controller -> JS 파일로 주고 받을때 템플릿을 통해 주고 받는다.(타임 리프 사용)

간단하게

Controller에서

model.addAttribute("startMarker", startMarker);

모델에 추가하고,

<div th:data-startMarker="*{startMarker}"></div>

타임리프에서 data- 속성을 사용하여 JS에서 접근하게끔 구성하였다.

data-*

data-* 속성은 HTML5에서 사용자 정의 데이터를 HTML 요소에 저장하는 방법. data-startMarker와 같은 형식은 data-로 시작하는 속성을 사용자가 자유롭게 정의할 수 있음을 의미. 이 속성에 저장된 데이터는 자바스크립트에서 element.dataset.startMarker로 접근 가능.

const startMarkerElement = document.querySelector('[data-startMarker]');
const startMarkerData = startMarkerElement.getAttribute('data-startMarker');
const startMarkerArray = JSON.parse(startMarkerData);

그 후, js에서 위와 같이 querySelector, getAttribute 를 통해 데이터를 가져온 후 JSON 형식을 JS형식으로 변경해주었다.

0개의 댓글