매일 조금씩

01/13 - jQuery(2) : 사용법, 우편번호 검색기 본문

빅데이터 플랫폼 구축을 위한 자바 개발자 양성과정

01/13 - jQuery(2) : 사용법, 우편번호 검색기

mezo 2021. 1. 31. 15:32
728x90
반응형

Ajax

       * proxy

                 => 못가져오는 데이터도 가져올 수 있다.

       => 사이트 기본데이터가 풍성(실제)해짐

       * OpenAPI

       * 크롤링(스크래핑)

 

       => 프로젝트

                   있는 사이트 + 추가

 

 

DOM 

        접근  / 추가수정삭제 / 이벤트

         => 프레임워크 : jQuery

                              www.jQuery.com

                                     zipping(네트워크 전송량을 줄이기 위해 공백을 줄이는 것)

                                           - 개발자 버전 

                                           - 서비스버전

                                     * CDN

                              window.onload = function() {

                              }

                              ==

                              $( document ).ready( function() {

                               });

 

                              $each

 

* 시험 jsp

1. url에서 각 경로별 이름 /로 나뉘어진 각각이 뭔지

서버 / 프로젝트명/ 디렉토리명/ 파일명 ? 쿼리

 

2. jsp 특수기호에 대한 설명 

 1) directive                         - 페이지 선언 (나이제 jsp 쓸거야) 

                    page / include / tablib

                   <%@ page contentType="text/html; charset=utf-8" %>

                    contentType                  :  text/html; charset=utf-8

                    pageEncoding               :  utf-8

                    language                          :  java

    import              

2) declaration                   - 메서드 선언 / 멤버 변수 선언

                    <%!     %> 

3) scriptlet                          - 지역변수 /  제어문   - 많이 씀

                    <%

                             자바소스

                    %>    -> jsp 페이지를 만듦!

4) expression                   - 출력 (out.println 과 같은 역할)

                    <%=      %>

 

3. 기본객체(5개)에 대한 설명 

  • request  :  클라이언트의 요청정보를 저장한다.
  • response  :  응답 정보를 저장한다.
  • out  :  JSP 페이지가 생성하는 결과를 출력할 때 사용하는 출력 스트림이다.
  • session  :  HTTP 세션 정보를 저장한다.
  • application  :  웹 어플리케이션에 대한 정보를 저장한다.

4. include

      디렉티브

      액션태그

      두가지 방법의 차이 

         <jsp:include>

                   디자인 모듈(nav bar같은거)

         <%@ page include>

                   프로그램 모듈(코드에서 공통되는 부분) + 간단한 디자인

                   ( 파일명을 sub02.jspf로 확장자명을 바꿔주면 에러안남 )

 

5. 커넥션 풀링

커넥션 풀 기법이란, 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(pool) 속에 저장해 두고 있다가 필요할 때에 커넥션을 풀에서 가져다 쓰고 다시 풀에 반환하는 기법을 의미한다.

  • was에서 만들고 이걸 가져다 쓴다.
  • 걸 JNDI(자바 네이밍 데이터 인터페이스) 라고 한다.
  • 네임을 가지고 있어서 자바에서 가져다 쓸수 있다.
  • context.sml이라는 파일안에 데이터베이스 설정에 대한 얘기를 해줘야한다.

 


 

 

 

jQuery 사용 복습


 

 

jQueryEx01

> ex11.jsp

<script type="text/javascript">
	// jQuery = $ (원래는 jQuery였는데 $로 쓸수 있게 바뀜)
	//jQuery(document).ready(function() {
	//	console.log("Hello jQuery");
	//});
	
	// 이벤트 부분 (document).ready 생략 가능
	//$(function() {
	//	console.log("Hello jQuery");
	//});
	
	// ready는 '시작'인데 여러개써도됨 (1개가 좋다)
	$(document).ready(function() {
		console.log("Hello jQuery1");
	});
	
	$(document).ready(function() {
		console.log("Hello jQuery2");
	});
	
	$(document).ready(function() {
		console.log("Hello jQuery3");
	});
	
	
</script>

> ex12.jsp

<script type="text/javascript">
	$(document).ready(function() {
		// selector로 html에 접근한다. selector => html
		// $( selector ).메서드() => 기능
		// selector의 개념은 css와 똑같다.
	});
	
</script>

 

jQuery 메서드

 

1. each 

어제에 이어서 each를 통해서 각각의 데이터를 분류해서 줄수도 있다.

> ex051.jsp

 

 

2. extend

객체에 대한 확장을 해주는것

> extend01.jsp

<script type="text/javascript">
	// $( tag/id/class ).css('color', 'red')
	$(document).ready(function() {
		// 객체 선언
		let object = { name: '홍길동'};
		console.log(object);
		
		// 객체 추가
		object.region1 = '서울시 종로구';
		object.part1 = '리더';
		
		console.log(object);
		
		$.extend( object, 
			{ region2: '서울시 강남구', part2: '베이스' },
			{ region3: '서울시 강남구', part3: '베이스' }
		);
		
		console.log(object);
		
		let output = '';
		
		// for문안쓰고 each로 객체 전부 출력 가능
		$.each(object, (key, value) => {
			console.log(key, value);
		});
	});
</script>

 

 

3. noconflict

'$' 충돌 방지로서 $사용으로 충돌이 나는 걸 방지하기 위해 $사용하지 말라고 해주는것

> noconflict01.jsp

<script type="text/javascript">
	$.noConflict() // 이거 주석처리 하거나 $를 jQuery로 바꾸면 아래꺼 실행됨
	const J = jQuery;
	J(document).ready(function() {
		// noconflict
		// $사용으로 충돌이 나는 걸 방지하기 위해 $사용하지 말라고 해주는것
		//console.log('Hello jQuery');
		
		let object = { name: '홍길동'};
		J.extend(object,
				{ region2: '서울시 강남구', part2: '베이스1' }
		);
		
		console.log(object);
		
		// each
		J.each(object, (key, value) => {
			console.log(key, value);
		});
	});
</script>

 

 

4. filter

> filter01.jsp

//$('h2:even').css('background-color', 'yellow');
$('h2').filter(':even').css('background-color', 'yellow');

위처럼 쓰는데 그럼 원래대로가 더 낫지않냐 라고 생각할 수 있는데 

변수화시키는 거랑 연관이 있다.

const h2 = $('h2');
console.log(h2);

h2.filter(':even').css('background-color', 'yellow');
h2.filter(':odd').css('background-color', 'blue');

 

filter로 select조건 뿐만아니라 수학적 조건도 줄수 있다.

> filter02.jsp

<script type="text/javascript">
	$(document).ready(function() {
		$('h2').filter(function(index, item){
			//console.log(index, item.innerHTML);
			return index%2 == 0;
		}).css('background-color','yellow');
	});
</script>

 

5. end

> end01.jsp

filter같은 메서드들을 막 붙여서 써서 깊이 들어가게 될 경우 사이에 넣어서 잘라서 적용되게 할수 있다.

<script type="text/javascript">
	$(document).ready(function() {
		// 계속 깊이 들어감 
		//$('h2').css('background-color','orange').filter(':even').css('color','red').filter(':odd').css('color','blue');
		
		// end()에서 자르고 그 뒤 filter는 새롭게 적용
		$('h2').css('background-color','orange').filter(':even').css('color','red').end().filter(':odd').css('color','blue');
		
	});
</script>

 

 

6. eq

> eq01.jsp

eq(인덱스값)

eq(-1) 하면 마지막거에 적용됨. 에러가 안나게 회전을 한다.

first, last도 가능.

<script type="text/javascript">
	$(document).ready(function() {
		//$('h2').eq(0).css('background-color','orange');
		//$('h2').eq(-1).css('background-color','red');
		$('h2').first().css('background-color','orange');
		$('h2').last().css('background-color','orange');
		
	});
</script>

 

7. add

추가선택

> add01.jsp

<script type="text/javascript">
	$(document).ready(function() {
		//$('h2:even').css('color', 'red');
		// ' '과 ','는 다르다.
		// ' '는 자손이고 ','는 and이다.
		//$('h2:even, h2:odd').css('color', 'red');
		// filter가 낫다.
		$('h2:even').css('color', 'red').add('h2:odd').css('color', 'blue');
	});
</script>

 

8. is

있는지 검사한 다음에 css를 줄수도 있다.

> is01.jsp

<script type="text/javascript">
	$(document).ready(function() {
		$( 'h2').each(function(){
			// is로 검사한 후 적용
			if($(this).is('.select')){
				$(this).css('color', 'orange');
			}
		})		
	});
</script>

 

 

9. find

> find01.jsp

특정위치의 문서를 찾을 때 활용될 수 있음

<script type="text/javascript">
	$(document).ready(function() {
		$(document).find('.select').each(function(){
			console.log(this);
		});
	});
</script>

xml문서를 분석해서 처리

> find02.jsp

<script type="text/javascript">
	let xml = '';
	xml += '<books>';
	xml += '<book>';
	xml += '<title>jQuery</title>';
	xml += '<publisher>출판사1</publisher>';
	xml += '</book>';
	xml += '<book>';
	xml += '<title>JSP</title>';
	xml += '<publisher>출판사2</publisher>';
	xml += '</book>';
	xml += '</books>';
	
	$(document).ready(function() {
		console.log(typeof xml);	// String
		
		// String -> xml
		const xmlDoc = $.parseXML(xml);
		console.log(typeof xmlDoc);
		console.log(xmlDoc);
		
		// xml을 검색하는 방법
		$(xmlDoc).find( 'title' ).each( function(){
			//console.log(this);
			//console.log(this.innerHTML);
			
			console.log($(this).html() );
		});
	});
</script>

 

 

 

----------------------------여기까지 은근쓰이는 메서드들..

 

 

 

1. addClass

클래스 추가 삭제

> addClass01.jsp

  • addClass
  • removeClass
  • toggleClass - 클릭할 때마다 add, remove 반복

이걸로 css 애니메이션 효과를 줄수 있다.

<script type="text/javascript">
	$(document).ready(function() {
		document.getElementById('btn1').onclick = function(){
			$('h2').addClass('high-light');
		};
		document.getElementById('btn2').onclick = function(){
			$('h2').removeClass('high-light');
			
		};
		document.getElementById('btn3').onmouseover = function(){
			// onlick - 클릭할 때마다 add, remove 반복
			// onmouseover - 마우스 올릴때마다 add, remove반복
			$('h2').toggleClass('high-light');
			
		};
	});
</script>

 

2. attr

> attr01.jsp

태그 속성 추가, 삭제

(src, width, type 같은거)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
	.high-light{
		background-color: yellow;
	}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		document.getElementById('btn1').onclick = function(){
			// 처음 하나만 나옴
			//const src = $('img').attr('src');
			//console.log(src);
			
			// each 사용
			//$('img').each(function(){
			//	console.log($(this).attr('src'));
			//});
			$('img').attr('src', function(index, item){
				console.log(item);
				// 태그 한 줄전체를 가져옴
				console.log(this);
			});
			
			
			
		};
		
		// 속성 추가
		document.getElementById('btn2').onclick = function() {
			//$('img').attr('height', 100);
			//$('img').attr('width', 100);
			
			$('img').attr('width', function(index){
				return (index + 1)*100;
			});
		};
		
		// 속성 삭제
		document.getElementById('btn3').onclick = function() {
			$('img').removeAttr('width');
			
		};
		
		// 규정된 속성이 아니고.. 개발에 필요한 속성을 부여 가능!
		document.getElementById('btn4').onclick = function() {
			$('img').attr('data-index', function(index){
				return (index+1) * 100;
			});
			
		};
		
		document.getElementById('btn5').onclick = function() {
			$('img').removeAttr('data-index');
		};
		
		
	});
</script>
</head>
<body>
<button id="btn1">이미지 내용</button>
<button id="btn2">이미지 추가</button>
<button id="btn3">속성 삭제</button>
<br /><hr /><br />
<button id="btn4">속성 추가</button>
<button id="btn5">속성 삭제</button>
<br /><hr /><br />
<img src="./images/Chrysanthemum.jpg" width="150" />
<img src="./images/Desert.jpg" width="150" />
<img src="./images/Hydrangeas.jpg" width="150" />
<img src="./images/Jellyfish.jpg" width="150" />

</body>
</html>

 

3. html내용 가져오기

> html01.jsp

html, text로 태그 안의 html 태그나 text를 가져오고 수정하는 것이 가능하다. 

근데 text에 html 태그를 넣어서 html 처럼 쓰는 것은 불가능!

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		// html 데이터 가져오기
		document.getElementById('btn1').onclick = function(){
			// 전통적인 방법
			const result = document.getElementById('result');
			
			// html
			console.log(result.innerHTML);
			console.log(result.textContent);
			
			
			// jQuery 사용
			console.log($('#result').html());
			console.log($('#result').text());
		};
		
		// html 데이터 수정하기
		document.getElementById('btn2').onclick = function(){
			// html수정
			$('#result').html("Hello jQuery");
			//text 수정 조심! html역할을 못한다.
			$('#result').text("<b>Hello jQuery</b>");	// html안됨
			
		};
		
	});
</script>

 

4. 태그의 생성과 추가

> html02.jsp

태그의 생성
$(<h2> Hello jQuery</h2>')
appendTo(B) / prependTo(B)
insertBefore(B) / insertAfter(B)

 

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		document.getElementById('btn1').onclick = function(){
			// 태그의 생성
			// $(<h2> Hello jQuery</h2>')
			
			// appendTo(B) / prependTo(B)
			// insertBefore(B) / insertAfter(B)
			
			// appendTo(B) - 뒤에 붙이기
			//$('<h2>Hello jQuery</h2>').appendTo('div');
			// prependTo(B) - 앞에 붙이기
			//$('<h2>Hello jQuery</h2>').prependTo('div');
			// 이렇게도 가능
			$('<h2></h2>').html('Hello jQuery').appendTo('div');
			
		};
		
		document.getElementById('btn2').onclick = function(){
			/* 
			$('<img />')
				.attr('src','./images/Desert.jpg')
				.attr('width','512')
				.attr('height','384')
				.appendTo('div');
			*/
			
			// 위처럼 하면 불편하니까 아래처럼 속성형식으로 해준다.
			
			$('<img />',{
				'src':'./images/Jellyfish.jpg',
				'width':'512',
				'height':'384'
			}).appendTo('div');
		};
		
	});
</script>

 

html을 변수로 정의해서 append로 붙일 수도 있다.

> html03.jsp

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		document.getElementById('btn1').onclick = function(){
			const h1 = '<h1>Header1</h1>';
			const h2 = '<h2>Header2</h2>';
			
			$('div').append(h1, h2, h1, h2);
		};
	});
</script>

 

5. 애니메이션 

setInterval

2초마다 첫번째 <img>를 body 마지막에 붙이기

> html04.jsp

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		setInterval(function(){
			$('img').first().appendTo('body');
		},2000);
	});
</script>

 

6. 이벤트로 태그 삭제

> html05.jsp

  • remove - 본인을 삭제
  • empty - 자식을 삭제
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		document.getElementById('btn1').onclick = function() {
			// div 본인
			$('div').remove();
		};
		
		document.getElementById('btn2').onclick = function() {
			// div 자식
			$('div').empty();
		};
		
		document.getElementById('btn3').onclick = function() {
			// div 본인
			//$('div > *').first().remove();
			$('h2').first().remove();
		};
	});
</script>

 

7. 이벤트를 주는 방법

> event01.jsp

항상 해왔던 방식

document.getElementById('btn1').onclick = function() {
    console.log('btn1 click');
};

 

다른 방식

$('#btn1').on('click', function(){
    console.log('btn1 click');
});

 

이걸 더 짧게

$('#btn1').click( function(){
    console.log('btn1 click');
});

 

이걸 화살표 함수로

$('#btn1').click(() => {
    console.log('btn1 click');
});

 

 

8. 여러가지 이벤트

> event02.jsp

mouseenter

mouseleave

표현방법 2가지, hover 사용

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		/*
		$('h2').on('mouseenter', function(){
			$(this).addClass('reverse');
		});
		
		$('h2').on('mouseleave', function(){
			$(this).removeClass('reverse');
		});
		*/
		
		/*
		// 위의 다른 표현 방법 
		$('h2').on({
			mouseenter: function(){
				$(this).addClass('reverse');
			},
			mouseleave: function(){
				$(this).removeClass('reverse');
			}
		});
		*/
		
		// 함수형 표현 방법  hover사용
		$('h2').hover(
			function(){
				$(this).addClass('reverse');
			},
			function(){
				$(this).removeClass('reverse');
			}
		);
	});
</script>

 

9. 이벤트 없애기 off

> event03.jsp

off 로 한번 실행 수 이벤트 없애거나 

on말고 one써서 한번만 실행되게 할수 있음. on일때 $(this).off()를 써야했던걸 one쓰면 안해도됨

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		/*
		$('h2').on('click',function(){
			console.log('click');
			$(this).off();
			// 이렇게 하면 처음 클릭했을 때 click 출력되고 이벤트가 off됨
		});
		*/
		
		// 위에껄 함수로 one
		$('h2').one('click',function(){
			console.log('click');
		});
	});
</script>

 

10. 이벤트로 좌표값 얻어내기

> event04.jsp

함수에 인자를 받을 수 있는데 그걸 이벤트 객체라고 한다.

함수가 발생할때의 그 주변상황을 알수 있다.

그 인자로 이벤트가 발생된 좌표값을 알수있다.

가장중요!

w3schools.com 에서 HTML Canvas는 그림을 그릴수 있다!

<canvas></canvas>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		$('h2').on('click',function(e){
			console.log('clickX : ' , e.pageX);
			console.log('clickY : ' , e.pageY);
		});
	});
</script>

 

 

11. 좌표값 가지고 그림그리기

event05.jsp

<canvas></canvas> 

드래그하면 선그려짐 

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		//$('#canvas').on('click',function(e){
		//	// canvas로 사각형이 그려지는데 그 사각형 내부를 클릭하면 각 위치가 출력됨
		//	console.log('clickX : ' , e.pageX);
		//	console.log('clickY : ' , e.pageY);
		//});
		
		const canvas = document.getElementById('canvas');
		const context = canvas.getContext('2d');
		
		$('#canvas').on({
			mousedown: function(e){
				const x = e.pageX;
				const y = e.pageY;
				
				context.beginPath();
				context.moveTo( x, y);
			},
			mouseup: function(e){
				const x = e.pageX;
				const y = e.pageY;
				
				// 실제 선을 그리는 메서드
				context.lineTo( x, y);
				context.stroke();
			}
		});
	});
</script>
</head>
<body>

<canvas id="canvas" width="700" height="400"></canvas>
</body>

 

12. click 같은 동작 없이 자동으로 이벤트를 부르는 것 trigger

event06.jsp

$(document).ready(function() {
    // 클릭할때마다 *하나씩 증가
    $('h2').on('click', function(){
        $(this).html(function(index,item){
            return item+ '*';
        });
    });

    // 1초마다 click 이벤트를 일으킴
    // 1초마다 *하나씩 증가
    setInterval(() => {
        $('h2').last().trigger('click');
    }, 1000);

});

 

13. 이벤트 전달

event07.jsp

html 맨안쪽 꺼의 이벤트가 발생하면 그걸 둘러싼 것들은 자동 발생된다.

근데 이렇게 되면 안된다. 이렇게 진행되는 이벤트를 막아줘야한다.

이런걸 이벤트 버블링이라고 한다. 이 버블링을 막아야한다!

어떻게 막냐?

e.stopPropagation을 사용한다.

이벤트 인자 e를 받아옴으로써 e.stopPropagation가 true면 e.stopPropagation()를 실행하여 버블링을 막는 것이다.

맨 안쪽태그의 id가 p일때..

$('#p').on('click', function(e){
    console.log('p');
    // 이벤트 버블링 방지
    if(e.stopPropagation){
        e.stopPropagation();
    }
});

 

 

 

 

 

 

응용 실습) jQuery로 xml로 된 우편번호 검색 구현

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		document.getElementById('btn').onclick = function(){
			const strDong = document.getElementById('dong').value.trim();
			alert(strDong);
			
			const request = new XMLHttpRequest();
			request.onreadystatechange = () =>{
				if(request.readyState == 4){
					if(request.status==200){
						
						const data = request.responseText.trim();
						console.log(data);
						
						//console.log(request.responseXML);
						const xmlData = request.responseXML;
						
						const seqs = xmlData.getElementsByTagName('seq');
						const zipcodes = xmlData.getElementsByTagName('zipcode');
						const sidos = xmlData.getElementsByTagName('sido');
						const guguns = xmlData.getElementsByTagName('gugun');
						const dongs = xmlData.getElementsByTagName('dong');
						const ris = xmlData.getElementsByTagName('ri');
						const bunjis = xmlData.getElementsByTagName('bunji');
						
						//console.log(zipcodes);
						//console.log(seqs.length);
						
						let result = '<table width="800" border="1">';
						for(let i=0; i<seqs.length; i++){
							let seqValue = seqs[i].childNodes[0].nodeValue;
							let zipcodeValue = zipcodes[i].childNodes[0].nodeValue;
							let sidoValue = sidos[i].childNodes[0].nodeValue;
							let gugunValue = guguns[i].childNodes[0].nodeValue;
							let dongValue = dongs[i].childNodes[0].nodeValue;
							
							// 데이터가 없을 때 처리하는 방법
							let riValue = '';
							if(ris[i].childNodes[0] != null){
								riValue = ris[i].childNodes[0].nodeValue;
							}
							let bunjiValue = '';
							if(bunjis[i].childNodes[0] != null){
								bunjiValue = bunjis[i].childNodes[0].nodeValue;
							}
							
							result += '<tr>';
							result += '<td>' + seqValue +'</td>';
							result += '<td>' + zipcodeValue +'</td>';
							result += '<td>' + sidoValue +'</td>';
							result += '<td>' + gugunValue +'</td>';
							result += '<td>' + dongValue +'</td>';
							result += '<td>' + riValue +'</td>';
							result += '<td>' + bunjiValue +'</td>';
							result += '</tr>';
							
						}
						result += '</table>';
						
						//request.open('GET','./data/xml.jsp?strDong=' + strDong, true); 
						//request.send();
						
						$('#result').append(result);
						
					}else{
						alert("에러페이지");
					}
				}
			};
			
			request.open('GET','./data/xml.jsp?strDong=' + strDong, true); 
			request.send();
		};
	});
</script>
</head>
<body>
<form>
동이름: <input type="text" id="dong" size="30" />
<input type="button" id="btn" value="우편번호 검색" />
</form>
<hr /><br />
<div id="result"></div>

</body>
</html>

 

 

 

 

 

 

 

728x90
반응형