[Day26] 2022-03-04(금) Web Application 7 - Ajax - 이진만 강사님
[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')
1. button 클릭 시 getdata() 함수 실행
2. getdata( ) 함수에서 ajax 실행
① 서버에 /ajaximpl 요청
② 요청 후 응답이 왔을 경우 data를 함수로 받아서 display() 함수 실행
3. 서버에서 /ajaximpl 요청 수행
① JSON 형태로 data 생성
② return값 : HttpResponse( ) 객체 -> html 없이도 client에 유사한 response 줄 수 있음
③ json.dumps(data) : data를 JSON 형식으로 변환
④ content_type : 보내려는 내용물의 type
4. 받은 JSON 데이터 화면에 뿌리기
① display( ) 함수로 data 받기
② 받은 data를 each( ) 메서드로 객체 하나씩 꺼내서 화면에 출력
③ 최종 결과를 div 안에 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')