프로젝트형 IoT 서비스 개발 4회차/1. 인터페이스 개발

[Day26] 2022-03-04(금) Web Application 7 - Ajax - 이진만 강사님

powerstone 2022. 3. 4. 23:27
728x90

[1] Ajax 개요

  1. Ajax(Asynchronous JavaScript and XML)

    - 비동기 통신 지원 방식

    - 새로운 언어가 아니라 JavaScript에 추가된 통신 방식

    - 화면 전체를 재로드 하지 않고 서버에서 특정 데이터를 송수신

      -> 전체 페이지를 재로드 하지 않고, 웹 페이지의 일부를 갱신 가능

  2. 장점

    - 페이지 이동  없이 고속으로 화면 전환

    - 서버 처리를 기다리지 않고, 비동기 요청이 가능

    - 수신하는 데이터 양을 줄일 수 있고, 클라이언트에게 처리를 위임할 수도 있음

    - 플러그인 없이도 인터렉티브한 웹페이지 구현 가능

  3. 단점

    - Ajax를 쓸 수 없는 브라우저에 대한 문제

    - HTTP 클라이언트의 기능이 한정

    - 페이지 이동없는 통신으로 인한 보안상의 문제

    - 지원하는 Charset이 한정되어 있다.

    - 스크립트로 작성되므로 디버깅이 용이하지 않음

    - 요청을 남발하면 역으로 서버 부하가 늘 수 있음

    - 동일-출처 정잭으로 인해 다른 도메인과는 통신이 불가능

  4. jQuery를 이용한 Ajax

    - jQuery에서 기본적으로 $.ajax( ) 를 제공

    - [ 형식 ] 

      $.ajax({name1: value1, name2: value2,...})

 

[2] 진행 중인 PROJECT에서 Ajax 활용

 - ajax.html

<style>
    div {
        margin: 0 auto;
        width: 300px;
        border:2px solid red;
    }

</style>

<script>
    function display(data){
        var result = '';
        $(data).each(function(index, item){
            result += '<h3>';
            result += item.id+' '+item.name+' '+item.age;
            result += '<h3>';
        });
        $('div').html(result);
    }

    function getdata(){
        $.ajax({
            url: 'ajaximpl',
            success: function(data){
                display(data);
            }
        });
    }

    $(document).ready(function(){
        // setInterval(function(){
          //  getdata();
        // }, 3000);

        $('button').click(function(){
            getdata();
        });
    });
</script>

<section>
    <h1>AJAX PAGE</h1>
    <button>GET DATA</button>
    <div></div>
</section>

- views.py 중 일부

@request_mapping("")
class MyView(View):

    @request_mapping("/", method="get")
    def home(self, request):
        return render(request, 'home.html');

    @request_mapping("/ajax", method="get")
    def ajax(self, request):
        context = {
            'center': 'ajax.html'
        };
        return render(request, 'home.html', context);

    @request_mapping("/ajaximpl", method="get")
    def ajaximpl(self, request):
        # [{}, {}, {}]
        data = []
        for i in range(1, 10):
            dic = {}
            dic['id'] = 'id'+str(i)
            dic['name'] = 'james'+str(i)
            dic['age'] = i
            data.append(dic)

        return HttpResponse(json.dumps(data), content_type='application/json')

출력 결과 : GET DATA 버튼 클릭 시 빨간 상자 안에 DATA 출력

  1. button 클릭 시 getdata() 함수 실행

ajax.html

  2. getdata( ) 함수에서 ajax 실행

    ① 서버에 /ajaximpl  요청

    ② 요청 후 응답이 왔을 경우 data를 함수로 받아서 display() 함수 실행

ajax.html

  3. 서버에서 /ajaximpl 요청 수행

    ① JSON 형태로 data 생성

    ② return값 : HttpResponse( ) 객체 -> html 없이도 client에 유사한 response 줄 수 있음

    ③ json.dumps(data) : data를 JSON 형식으로 변환

    ④ content_type : 보내려는 내용물의 type

views.py
Python과 JSON 데이터 변환

  4. 받은 JSON 데이터 화면에 뿌리기

    ① display( ) 함수로 data 받기

    ② 받은 data를 each( ) 메서드로 객체 하나씩 꺼내서 화면에 출력

    ③ 최종 결과를 div 안에 html 문서로 뿌려주기

ajax.html

    - each( ) 메서드 사용 방법

      - [형식]

        ① $.each(data, function(index, item){ });

        ② $(data).each(function(index, item){ });

      - data가 JSON인 경우

        -> [{key1: value, key2: value,...}, {key1: value, key2: value,...}, {key1: value, key2: value,... },...]

        -> index : 0 ~ n-1 까지 배열의 index

        -> item :  배열 내의 각 index에 해당하는 객체

      - data가 객체인 경우

        -> {key1: value, key2: value, key3: value,...}

        -> index : key1, key2, key3,...

        -> item : 각 key에 해당하는 value

 

[3] 진행 중인  PROJECT에서 AJAX 활용2 (코드만)

  - /geo 화면에서 Busan 버튼 클릭 시 AJAX로 데이터 가져와서 지도에 마커 생성 및 클릭 시 해당 링크 연결하기

  - 큰 틀은 [2]와 동일

  - geo.html

<style>
    #map {
        margin: 0 auto;
        width: 400px;
        height: 400px;
    }
    .ifimg {
        width: 80px;
    }
</style>
<script>
    $(document).ready(function(){
        var mapContainer = document.getElementById('map'), // 지도를 표시할 div
            mapOption = {
                center: new kakao.maps.LatLng(33.450701, 126.570667), // 지도의 중심좌표
                level: 6 // 지도의 확대 레벨
            };

        // 지도를 표시할 div와  지도 옵션으로  지도를 생성합니다
        var map = new kakao.maps.Map(mapContainer, mapOption);

        // 일반 지도와 스카이뷰로 지도 타입을 전환할 수 있는 지도타입 컨트롤을 생성합니다
        var mapTypeControl = new kakao.maps.MapTypeControl();

        // 지도에 컨트롤을 추가해야 지도위에 표시됩니다
        // kakao.maps.ControlPosition은 컨트롤이 표시될 위치를 정의하는데 TOPRIGHT는 오른쪽 위를 의미합니다
        map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);

        // 지도 확대 축소를 제어할 수 있는  줌 컨트롤을 생성합니다
        var zoomControl = new kakao.maps.ZoomControl();
        map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);

        $('#s').click(function(){
            // 37.496718, 126.989691
             var moveLatLon = new kakao.maps.LatLng(37.496718, 126.989691);

            // 지도 중심을 이동 시킵니다
            map.setCenter(moveLatLon);

            // 마커를 표시할 위치입니다
            var position =  new kakao.maps.LatLng(37.496300, 126.999999);

            // 마커를 생성합니다
            var marker = new kakao.maps.Marker({
                position: position
            });

            // 마커를 지도에 표시합니다.
            marker.setMap(map);

            // 마커에 커서가 오버됐을 때 마커 위에 표시할 인포윈도우를 생성합니다
            var iwContent = '<div style="padding:5px;">Hello World!</div><img class="ifimg" src="/static/img/com.jpg">'; // 인포윈도우에 표출될 내용으로 HTML 문자열이나 document element가 가능합니다

            // 인포윈도우를 생성합니다
            var infowindow = new kakao.maps.InfoWindow({
                content : iwContent
            });

            // 마커에 마우스오버 이벤트를 등록합니다
            kakao.maps.event.addListener(marker, 'mouseover', function() {
              // 마커에 마우스오버 이벤트가 발생하면 인포윈도우를 마커위에 표시합니다
                infowindow.open(map, marker);
            });

            // 마커에 마우스아웃 이벤트를 등록합니다
            kakao.maps.event.addListener(marker, 'mouseout', function() {
                // 마커에 마우스아웃 이벤트가 발생하면 인포윈도우를 제거합니다
                infowindow.close();
            });
            kakao.maps.event.addListener(marker, 'click', function() {
                location.href='http://www.naver.com';
            });
        });

        function display(positions){
            // 35.157627, 129.059282
            var moveLatLon = new kakao.maps.LatLng(35.157627, 129.059282);

            // 지도 중심을 이동 시킵니다
            map.setCenter(moveLatLon);

            // 마커를 표시할 위치와 내용을 가지고 있는 객체 배열입니다
            // new kakao.maps.LatLng()

            for (var i = 0; i < positions.length; i ++) {
                // 마커를 생성합니다
                var marker = new kakao.maps.Marker({
                    map: map, // 마커를 표시할 지도
                    position: new kakao.maps.LatLng(positions[i].lat, positions[i].lng) // 마커의 위치
                });

                // 마커에 표시할 인포윈도우를 생성합니다
                var infowindow = new kakao.maps.InfoWindow({
                    content: positions[i].content // 인포윈도우에 표시할 내용
                });

                // 마커에 mouseover 이벤트와 mouseout 이벤트를 등록합니다
                // 이벤트 리스너로는 클로저를 만들어 등록합니다
                // for문에서 클로저를 만들어 주지 않으면 마지막 마커에만 이벤트가 등록됩니다
                kakao.maps.event.addListener(marker, 'mouseover', makeOverListener(map, marker, infowindow));
                kakao.maps.event.addListener(marker, 'mouseout', makeOutListener(infowindow));
                kakao.maps.event.addListener(marker, 'click', makeClickListener(positions[i].target));
            }

            // 마커를 클릭하면 해당하는 페이지로 이동
            function makeClickListener(target){
                return function() {
                    location.href=target;
                };
            }

            // 인포윈도우를 표시하는 클로저를 만드는 함수입니다
            function makeOverListener(map, marker, infowindow) {
                return function() {
                    infowindow.open(map, marker);
                };
            }

            // 인포윈도우를 닫는 클로저를 만드는 함수입니다
            function makeOutListener(infowindow) {
                return function() {
                    infowindow.close();
                };
            }
        };

        function getdata(){
            $.ajax({
            url: 'geoimpl',
            success: function(data){
                display(data);
            }
            });
        };

        $('#b').click(function(){
            getdata();
        });
    });
</script>
<section>
    <h1>Map</h1>
    <button id="s">Seoul</button><button id="b">Busan</button>
    <div id="map"></div>
</section>

  - views.py 일부

@request_mapping("/geo", method="get")
def geo(self, request):
    context = {
        'center': 'geo.html'
    };
    return render(request, 'home.html', context);

@request_mapping("/geoimpl", method="get")
def geoimpl(self, request):
    positions = [
        {
            'content': '<div>네이버</div><img class="ifimg" src="static/img/p1.jpg">',
            'lat': 35.157555,
            'lng': 129.059555,
            'target': 'http://www.naver.com'
        },
        {
            'content': '<div>구글</div><img class="ifimg" src="static/img/p2.jpg">',
            'lat': 35.157111,
            'lng': 129.059111,
            'target': 'http://www.google.com'
        },
        {
            'content': '<div>다음</div><img class="ifimg" src="static/img/p3.jpg">',
            'lat': 35.157777,
            'lng': 129.059777,
            'target': 'http://www.daum.net'
        },
        {
            'content': '<div>MSN</div><img class="ifimg" src="static/img/com.jpg">',
            'latlng': 35.157000,
            'lng': 129.059000,
            'target': 'http://www.msn.com'
        }
    ]
    return HttpResponse(json.dumps(positions), content_type='application/json')

 

728x90