반응형
1. 동기화통신 VS 비동기화통신
1) AJAX(Asynchronus Javascript + XML)란?
- 페이지의 새로고침 없이 페이지 일부를 고칠 수 있는 것
2) 동기화통신 (클라 >>> 서버)
- 버튼 클릭, 사용자 입력 마다 페이지 새로고침이 일어남
- 비효율적
- 서버가 응답할 동안 클라는 가만히 있어야 함
3) 비동기화통신 (클라 >>> ajax엔진 >>> 서버)
- 클라가 AJAX 엔진을 통해 서버에게 요청함
- WAS는 서버를 실행해 AJAX 엔진에게 응답함
- 클라는 자신이 직접 요청한 것이 아니기 때문에 (AJAX 엔진을 통해 요청과 응답함) 다른 작업도 가능함
- 웹프로그램의 실행 결과는 HTML,XML... 다양히
- 페이지의 새로고침 없이 DHTML처럼 HTML 문서의 태그를 고칠 수 있음
- 페이지의 새로고침 없이 비동기식 통신으로 결과를 응답받아 사용자에게 정보 제공 가능
- 하나의 페이지에서 보다 많은 정보를 더 빠르게 제공 가능
4) XMLHttpRequest 객체
- AJAX엔진을 이용하기 위해 필요한 가장 핵심적인 자바스크립트 객체

2. ajax 사용 예시
1) [전달값 없음] DHTML (동기 통신) 과 AJAX (비동기 통신) 의 비교
hello_one.jsp - 요청
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<style type="text/css">
#display {
width: 50%;
padding: 5px;
margin: 10px;
font-size: 30px;
border: 1px solid red;
}
</style>
</head>
<body>
<h1>AJAX Programming</h1>
<hr>
<div id="display">Hello, AJAX!!!</div>
<div>
<button type="button" id="btn1">번역하기</button>
<button type="button" id="btn2">배경색 변경</button>
</div>
<script type="text/javascript">
//🖤방법1. DHTML(Dynamic HTML) 기능 이용
/*
//Element 객체(button 태그)의 클릭 이벤트에 의해 호출될 이벤트 처리 함수 등록
document.getElementById("btn1").onclick=function() {
//DHTML(Dynamic HTML) 기능을 이용하여 페이지의 요소(태그) 변경
// => 현재 웹프로그램의 실행 결과를 이용하여 페이지의 요소 변경
document.getElementById("display").innerHTML="안녕하세요. 에이젝스!!!";
}
*/
//🖤방법2. AJAX 기능(Asynchronus Javascript + XML) 이용
//XMLHttpRequest 객체를 저장하기 위한 전역변수 선언
//XMLHttpRequest 객체 : 비동기식으로 웹프로그램을 요청하여 응답받아 처리하기 위한 객체 - AJAX Engine
var xhr=null;
//step1) XMLHttpRequest 객체를 생성하여 반환하는 함수 선언
// => 브라우저 종류와 버전에 따라 XMLHttpRequest 객체를 생성하는 방법이 다양하므로 함수로 선언
function getXMLHttpRequest() {
if(window.ActiveXObject) {//IE4~IE6
try {
return new ActiveXObject("msxml2.XMLHTTP");//IE5~IE6
} catch (e) {
try {
return new ActiveXObject("MicrosoftXML.HTTP");//IE4
} catch (e) {
return null;
}
}
} else if(window.XMLHttpRequest) {//IE7 이상 또는 대다수의 웹브라우저
return new XMLHttpRequest();
} else {
return null;
}
}
//step2) Element 객체(button 태그)의 클릭 이벤트에 의해 호출될 이벤트 처리 함수 등록
document.getElementById("btn1").onclick=function() {
//AJAX 기능(Asynchronous Javascript + XML)을 이용하여 페이지의 요소(태그) 변경
// => XMLHttpRequest 객체를 사용하여 비동기식으로 다른 웹프로그램을 요청하여 실행
//결과를 XML로 제공받아 페이지의 요소 변경
//1.XMLHttpRequest 객체를 생성하여 저장 - 전역변수와 함수 이용
xhr=getXMLHttpRequest();
// 현재 회사에서는 GetXMLHttp() 로 사용 중!!!!!!!!!!
//2.XMLHttpRequest 객체의 준비상태(ReadyState)가 변경될 경우 호출될 이벤트 처리 함수 등록
//XMLHttpRequest.readyState : XMLHttpRequest 객체의 준비상태 정보를 저장한 속성(Property)
// => XMLHttpRequest 객체의 준비상태는 순차적으로 자동 변경
// => 0(기본),1(요청 초기화 - open),2(요청 - send),3(응답대기 - 처리중),4(응답 - 결과)
//XMLHttpRequest.onreadystatechange : XMLHttpRequest 객체의 준비상태가 변경될 경우
//호출될 이벤트 처리 함수를 저장(등록)하기 위한 이벤트 속성(Property)
xhr.onreadystatechange=changeHTML;//이벤트 처리 함수는 4번 호출
//3.XMLHttpRequest 객체로 open 메소드 호출 - 준비상태 : 1
//XMLHttpRequest.open(method, url[, async]) : XMLHttpRequest 객체로 웹프로그램을
//요청하기 위한 정보를 설정하는 메소드
// => method : 요청방식 - GET(검색), POST(삽입), PUT(전체 변경), PATCH(일부 변경), DELETE(삭제) 등
// => url : 요청 웹프로그램의 URL 주소 - 현재 서버의 웹프로그램만 요청 가능
// => async : 동기식 통신 또는 비동기식 통신 구분 - false(동기식 통신) 또는 true(비동기식 통신 - 기본)
xhr.open("get","hello_two.jsp",true);//비동기식 통신 : 요청에 대한 응답의 기다림 미발생 - 다른 작업 가능
//xhr.open("get","hello_two.jsp",false);//동기식 통신 - 요청에 대한 응답의 기다림 발생 - 다른 작업 불가능
//4.XMLHttpRequest 객체로 send 메소드 호출 - 준비상태 : 2
//XMLHttpRequest.send(data) : XMLHttpRequest 객체로 웹프로그램을 요청하기 위한 메소드
// => data : 요청 웹프로그램에 전달할 값을 [이름=값&이름=값&...] 형식으로 표현하여 제공
// => 리퀘스트 메세지의 몸체부에 값을 저장하여 전달 - POST 방식으로 요청하여 값 전달
// => 전달값이 없거나 GET 방식으로 요청한 경우 매개변수에는 null 전달
xhr.send(null);//웹프로그램 요청 - 준비상태가 자동으로 [3]과 [4]로 자동 변경
}
//step3) XMLHttpRequest 객체의 준비상태가 변경될 경우 호출될 이벤트 처리 함수
// => 요청에 대한 응답 결과를 제공받아 처리하는 함수
function changeHTML() {
/*
if(xhr.readyState==1) {
alert("요청 초기화 상태");
} else if(xhr.readyState==2) {
alert("요청 상태");
} else if(xhr.readyState==3) {
alert("응답 대기 상태");
} else if(xhr.readyState==4) {
alert("응답 완료 상태");
}
*/
//5.응답결과를 제공받아 페이지의 요소 조작 - DHTML
if(xhr.readyState==4) {
//XMLHttpRequest.status : 요청에 대한 실행 결과의 상태코드(StatusCode)를 저장한 속성(Property)
if(xhr.status==200) {//요청에 대한 정상적인 실행결과를 응답받은 경우
//XMLHttpRequest.responseText : 웹프로그램 요청에 대한 실행결과를 TEXT 또는 HTML로 저장한 속성(Property)
//XMLHttpRequest.responseXML : 웹프로그램 요청에 대한 실행결과를 XML로 저장한 속성(Property)
document.getElementById("display").innerHTML=xhr.responseText;
} else {//요청에 대한 비정상적인 실행결과를 응답받은 경우 - 에러코드 : 4XX or 5XX
alert("에러코드 = "+xhr.status);
}
} else {//요청에 응답결과를 제공받기 전인 경우
document.getElementById("display").innerHTML="<img src='images/loading.gif' width='50'>";
}
}
document.getElementById("btn2").onclick= function() {
if(this.innerHTML === "분홍색으로 변경"){
document.getElementById("display").style = "background-color:pink;";
this.innerHTML = "흰색으로 변경";
} else {
document.getElementById("display").style = "background-color:white;";
this.innerHTML = "분홍색으로 변경";
}
}
</script>
</body>
</html>
hello_two.jsp - 응답
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//응답결과를 받기 전까지 기다리기 위해 작성
for(int i=1; i<=2000000; i++){
System.out.println(i+"번째 처리중...");
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
</head>
<body>
// <!-- XML을 아직 안배웠으니 HTML로 응답해주기 -->
안녕하세요. 에이젝스!!!
</body>
</html>
2) [전달값있음] 요청방식 비교 | [GET] [POST] [PUT] [PATCH] [DELETE]
data_one.jsp - 요청
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<style type="text/css">
#display{
width: 50%;
padding: 5px;
margin: 10px;
font-size: 30px;
border: 1px solid black;
}
</style>
</head>
<body>
<h1>AJAX - 값 전달</h1>
<hr />
<div id="display">요청 웹프로그램에 대한 실행 결과 출력</div>
<div>
// <!-- AJAX를 이용하므로 form태그 없어도 됨 & name속성도 없어도 됨 -->
이름 : <input type="text" id="name">
<button type="button" id="getBtn">GET 방식의 요청</button>
<button type="button" id="postBtn">POST 방식의 요청</button>
</div>
<script type="text/javascript">
//1.
//XMLHttpRequest 객체를 저장하기 위한 전역변수
var xhr=null;
//2.
//XMLHttpRequest 객체를 생성하여 반환하는 함수
function getXMLHttpRequest() {
if(window.ActiceXObject){
try {
return new ActiceXObject("msxml2.XMLHTTP");
} catch (e) {
try {
return new ActiceXObject("MicrosoftXML.HTTP");
} catch (e) {
return null;
}
}
} else if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
return null;
}
}
이벤트 처리함수
//요청 웹프로그램의 응답결과를 제공받아 페이지의 요소를 변경하는 이벤트 처리 함수
function viewMessage() {
//5.
if(xhr.readyState==4){
if(xhr.status==200){
document.getElementById("display").innerHTML=xhr.responseText;
} else {
alert("에러코드 = "+xhr.status);
}
}
}
[GET 방식의 요청]
//3.
//[GET 방식의 요청] 버튼태그 클릭 시 호출되는 이벤트 처리 함수 등록
//=> 일반적으로 검색할 때 - select
document.getElementById("getBtn").onclick = function() {
//입력태그의 입력값 반환받아 저장
var name = document.getElementById("name").value;
//입력값 검증
if(name==""){
document.getElementById("display").innerHTML = "이름을 입력해주세요.";
return;
}
//입력값이 있다면 입력태그 초기화
document.getElementById("name").value="";
//1. XMLHttpRequest 객체를 생성하여 저장
xhr = getXMLHttpRequest();
//2. XMLHttpRequest 객체의 준비상태(readyState)가 변경될 경우 호출될 이벤트 처리 함수 등록
xhr.onreadystatechange=viewMessage;
//3.4. XMLHttpRequest 객체를 이용하여 웹프로그램을 GET 방식으로 요청
// => [GET 방식으로 웹프로그램을 요청할 경우] 질의문자열(QueryString)을 사용하여 값 전달
//문제점) 전달값에 URL 주소로 표현 불가능한 문자값이 존재하는 경우 브라우저에 따라 400 에러코드 발생
//해결법) 전달값에 URL 주소로 표현 불가능한 문자값이 존재하는 경우 부호화 처리하여 전달
name = encodeURIComponent(name);
xhr.open("get","data_two.jsp?name="+name ,true);
//전달값이 하나면 모르겠으나, 전달값이 많을 경우 GET 보다 POST 방식으로 요청하는 것이 좋음
xhr.send(null);
}
[POST 방식의 요청]
//[POST 방식의 요청] 버튼태그 클릭 시 호출되는 이벤트 처리 함수 등록
//=> 일반적으로 삽입할 때 - insert (대량의 값을 전달할 때, 부호화처리할 필요도 없음)
document.getElementById("postBtn").onclick = function() {
//입력태그의 입력값 반환받아 저장
var name = document.getElementById("name").value;
//입력값 검증
if(name==""){
document.getElementById("display").innerHTML = "이름을 입력해주세요.";
return;
}
//입력값이 있다면 입력태그 초기화
document.getElementById("name").value="";
//1. XMLHttpRequest 객체를 생성하여 저장
xhr = getXMLHttpRequest();
//2. XMLHttpRequest 객체의 준비상태(readyState)가 변경될 경우 호출될 이벤트 처리 함수 등록
xhr.onreadystatechange=viewMessage;
//3.4. XMLHttpRequest 객체를 이용하여 웹프로그램을 POST 방식으로 요청
//=> [POST 방식으로 웹프로그램을 요청할 경우]
//=> send 메소드의 매개변수를 사용하여 값 전달
//문제점) send 메소드를 이용하여 값을 전달할 경우
// => "multipart/form-data" 형식(원시데이타 형식)으로 전달
// => 요청 웹프로그램의 request 객체의 getParameter() 메소드로 전달값 반환 불가능
//해결법) "application/x-www-form-urlencoded" 형식(텍스트 데이타)으로 값이 전달되도록 리퀘스트 메세지의 헤더 정보 변경
xhr.open("post","data_two.jsp"); //async 매개변수의 전달값이 생략된 경우 자동으로 true로 지정
//XMLHttpRequest.setRequestHeader(header, value) : XMLHttpRequest 객체를 이용하여 웹프로그램을 요청할 때 사용하는 리퀘스트 메세지의 헤더 정보를 변경하는 메소드
// => 리퀘스트 메세지의 몸체부에 저장된 값이 텍스트 형식의 문자값을 표현되도록 설정
// => open 메소드 호출 후 사용 가능
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded"); //전달값이 몇개든 한번만 설정하면 됨
xhr.send("name="+name);
}
[PATCH, PUT 방식의 요청]
//[PATCH, PUT 방식의 요청] - 변경할 때 (update)
[DELETE 방식의 요청]
//[DELETE 방식의 요청] - 삭제할 때 (delete)
</script>
</body>
</html>
data_two.jsp - 응답
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//POST 방식으로 요청하여 전달된 값에 대한 캐릭터셋 변경
request.setCharacterEncoding("utf-8");
//전달값을 반환받아 저장
String name = request.getParameter("name");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
</head>
<body>
<%=name %>님, 환영합니다.
</body>
</html>
3) AJAX모듈을 이용한 비동기 통신
- 모듈이 여러개 모이면? 라이브러리
js/xhr.js
//자바스크립트의 중복코드를 최소화하기 위해 AJAX 모듈 만들어 사용하기
//강사님이 직접 만드신 파일임
//꼭 이거 안써도 됨
/* AJAX Module : 전역변수와 함수를 이용하여 AJAX 기능 제공 */
var xhr=null;
function getXMLHttpRequest() {
if(window.ActiveXObject) {//IE4 ~ IE6
try {
return new ActiveXObject("msxml2.XMLHTTP");//IE5 ~ IE6
} catch (e) {
try {
return new ActiveXObject("MicrosoftXMLHTTP");//IE4
} catch (e) {
return null;
}
}
} else if(window.XMLHttpRequest) {//IE7 이상 또는 기타 브라우저
return new XMLHttpRequest();
} else {
return null;
}
}
/* 요청과 응답 처리를 위한 함수 선언 */
// 이 함수만 호출하면 내부적으로 XMLHttpRequest 객체를 만들어 요청에 대한 처리까지 가능함
// 즉, 매개변수만 잘 전달하면 AJAX가 자동으로 구현될 것임
function sendRequest(method, url, param, callback) {
xhr=getXMLHttpRequest();
//요청방식에 대한 검증과 저장
var httpMethod=method?method:"get";
if(httpMethod!="get" && httpMethod!="post") {
httpMethod="get";
}
//전달값에 대한 검증과 저장
var httpParam=(param==null || param=="")?null:param;
//요청 URL 주소 저장
var httpUrl=url;
//GET 방식으로 요청시 전달값이 존재할 경우 URL 주소에 QueryString 추가
if(httpMethod=="get" && httpParam!=null) {
httpUrl=httpUrl+"?"+httpParam;
}
//응답결과를 제공받아 처리하기 위한 함수 등록
xhr.onreadystatechange=callback;
//웹어플리케이션 요청
xhr.open(httpMethod, httpUrl);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(httpMethod=="post"?httpParam:null);
}
module_one.jsp - 요청
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<script type="text/javascript" src="js/xhr.js"></script>
<style type="text/css">
#display{ width: 50%; padding: 5px; margin: 10px; font-size: 30px; border: 1px solid black;}
</style>
</head>
<body>
<h1>AJAX Module</h1>
<hr />
<div id="display">요청 웹프로그램에 대한 실행 결과 출력</div>
<table>
<tr>
<td>아이디</td>
<!--<%-- form태그를 안쓰기 때문에 name 속성 안써도 됨 --%>-->
<td><input type="text" id="id"></td>
</tr>
<tr>
<td>이름</td>
<td><input type="text" id="name"></td>
</tr>
<tr>
<td colspan="2"><button type="button" id="btn">요청(AJAX)</button></td>
</tr>
</table>
<script type="text/javascript">
document.getElementById("btn").onclick = function() {
var id=document.getElementById("id").value;
if(id==""){
document.getElementById("display").innerHTML = "아이디를 입력해 주세요.";
return;
}
var name=document.getElementById("name").value;
if(name==""){
document.getElementById("display").innerHTML = "이름을 입력해 주세요.";
return;
}
document.getElementById("id").value="";
document.getElementById("name").value="";
//AJAX 기능을 제공하는 모듈을 사용하여 요청과 응답 처리 - sendRequest 함수 호출
/*
//GET 방식으로 웹프로그램을 요청한 경우 모든 전달값을 부호화 처리하여 전달
id=encodeURIComponent(id);
name=encodeURIComponent(name);
sendRequest("get", "module_two.jsp", "id="+id+"&name="+name, viewMessage);
//이 메소드 하나만 호출하면?
//전역변수 만들어짐, XMLHttpRequest객체만들어짐
//open(), send() 알아서 요청하고 요청에 대한 응답결과도 처리해줌
*/
//POST 방식으로 웹프로그램을 요청한 경우 모든 전달값을 부호화 처리하여 전달
sendRequest("post", "module_two.jsp", "id="+id+"&name="+name, viewMessage);
}
function viewMessage() {
if(xhr.readyState==4){
if(xhr.status==200){
document.getElementById("display").innerHTML = xhr.responseText;
} else {
alert("에러코드 = "+xhr.status);
}
}
}
</script>
</body>
</html>
module_two.jsp - 응답
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//POST 방식으로 요청하여 전달된 값에 대한 캐릭터셋 변경
request.setCharacterEncoding("utf-8");
String id = request.getParameter("id");
String name = request.getParameter("name");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%=name %>[<%=id %>]님, 환영합니다.
</body>
</html>
응답 결과

3. 브라우저 캐싱 무효화 | 실시간 업데이트 정보 받기
1) 브라우저 캐싱 기능
- 동일한 웹프로그램을 지속적으로 요청한 경우 브라우저 캐싱 기능에 의해 서버에서 제공하는 응답결과가 아닌 기존 응답결과를 재사용하는 것
- 최초 응답결과를 계속 사용하여 응답 처리
- 같은 페이지를 요청 시 브라우저에 캐시메모리를 저장하고, 요청 시 제공
2) 브라우저 캐싱 기능 무효화 필요할 때
- 지속적으로 요청해야 하는 프로그램인 경우 캐싱기능 무효화 처리 해야함
- 특히, 웹브라우저 중 인터넷익스플로러는 캐싱 기능을 이용하기 때문에 무효화처리 필수
- ex) 실시간 댓글 업데이트
- 댓글목록을 계속 요청해야만 출력 가능
- 즉, 댓글 출력을 제공해주는 프로그램은 캐싱 기능을 사용하면 안됨
- ex) 실시간 날씨 업데이트
- 실시간 날씨 정보를 계속 요청해야만 출력 가능
- 즉, 날씨 출력을 제공해주는 프로그램은 캐싱 기능을 사용하면 안됨
clock_one.jsp - 요청
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<script type="text/javascript" src="js/xhr.js"></script>
<style type="text/css">
div {
font-size: 20px;
margin: 10px;
}
</style>
</head>
<body>
<h1>브라우저 캐싱</h1>
<hr>
<div>
클라이언트 시스템의 현재 날짜와 시간은 <span id="clientTime">2023년 1월 9일 16시 16분 22초</span>입니다.
</div>
<div>
서버 시스템의 현재 날짜와 시간은 <span id="serverTime">2023년 1월 9일 16시 16분 22초</span>입니다.
</div>
<script type="text/javascript">
//1.
//브라우저가 실행되는 시스템(클라이언트)의 현재 날짜와 시간
//브라우저가 실행되는 시스템(클라이언트)의 현재 날짜와 시간을 제공받아 태그를 변경하는 함수
// => 클라이언트에 따라 다른 결과 제공 가능
function displayClientTime() {
var now=new Date();
var displayTime=now.getFullYear()+"년 "+(now.getMonth()+1)+"월 "+now.getDate()+"일 "
+now.getHours()+"시 "+now.getMinutes()+"분 "+now.getSeconds()+"초";
document.getElementById("clientTime").innerHTML=displayTime;
}
displayClientTime();
setInterval(displayClientTime, 1000);
//2.
//웹프로그램을 실행하는 시스템(서버)의 현재 날짜와 시간
//웹프로그램을 실행하는 시스템(서버)의 현재 날짜와 시간을 제공받아 태그를 변경하는 함수
// => 서버의 날짜와 시간을 제공받아 사용하므로 모든 클라이언트에게 동일한 결과 제공
//문제점)동일한 웹프로그램을 지속적으로 요청한 경우 브라우저 캐싱 기능에 의해 서버에서
//제공하는 응답결과가 아닌 기존 응답결과를 재사용 - 최초 응답결과를 계속 사용하여 응답 처리
//해결법-1)웹프로그램에 대한 요청 URL 주소를 지속적으로 변경하여 요청 - 질의문자열(QueryString) 이용
//해결법-2)요청 웹프로그램에서 응답결과에 대한 브라우저 캐싱 기능을 무효화 처리
function displayServerTime() {
//sendRequest("get", "clock_two.jsp?dummy="+new Date().getTime(), null, function() {
sendRequest("get", "clock_two.jsp", null, function() {
if(xhr.readyState==4) {
if(xhr.status==200) {
document.getElementById("serverTime").innerHTML=xhr.responseText;
} else {
alert("에러코드 = "+xhr.status);
}
}
});
}
displayServerTime();
setInterval(displayServerTime, 1000);
</script>
</body>
</html>
clock_two.jsp - 응답
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//request.getProtocol() : 요청 웹프로그램에서 사용하는 통신규약(Protocol)을 반환하는 메소드
String protocol=request.getProtocol();
//요청에 대한 응답결과를 브라우저 캐싱 기능에 의해 사용되지 않도록 설정
if(protocol.equals("HTTP/1.0")) {
response.setDateHeader("Expires", -1);//캐싱 만료기간 설정
response.setHeader("Pragma", "no-cache");//캐싱 기능 비활성화 설정
} else if(protocol.equals("HTTP/1.1")) {
response.setHeader("Cache-control", "no-cache");//캐싱 기능 비활성화 설정
}
Date now=new Date();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초");
String displayTime=simpleDateFormat.format(now);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Expires" content="-1">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<title>AJAX</title>
</head>
<body>
<%=displayTime %>
</body>
</html>
응답 결과
- 1초마다 반복 호출됨

4. 자바스크립트 함수의 모듈화와 사용법
logger.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<!-- log()를 모듈화시켜 불러서 사용하기 -->
<script type="text/javascript" src="<%=request.getContextPath()%>/js/log.js"></script>
</head>
<body>
<h1>로그함수</h1>
<hr />
<div id="log"></div>
<script type="text/javascript">
//document.getElementById("log").innerHTML += "메세지 출력-1<br>"
//document.getElementById("log").innerHTML += "메세지 출력-2<br>"
/*
function log(message) {
var logElement = document.getElementById("log");
if(logElement!=null) logElement.innerHTML += message+"<br>";
}
log("메세지 출력-1");
log("메세지 출력-2");
*/
//변수에 값이 정상적으로 저장되었는지 아닌지 확인하고 싶을 때 사용함
//alert()함수 사용보다 더 좋음!
var id="abc123", name="홍길동";
log("아이디 = "+id,"이름 = "+name);
id="xyz123", name="임꺽정";
log("아이디 = "+id,"이름 = "+name);
</script>
</body>
</html>
js/log.js
function log(message) {
var logElement = document.getElementById("log");
if(logElement != null){
logElement.innerHTML += message+"<br>";
}
}

5. 데이터의 종류
1) 데이타(값)의 종류
바이너리 데이타 (Binary File)
- 메타 데이타를 포함하면서 0, 1의 단순한 나열로 이루어진 파일
- 해당 파일을 읽을 수 있는 특정 응용 프로그램에서만 해석 가능
- 보안성 요할 때 사용
- ex) .doc : 워드 프로그램에서 열기 가능
- .ppt : 파워포인트 프로그램에서 열기 가능
- .hwp : 한글 프로그램에서 열기 가능
텍스트 데이타 (Text File)
- 표준화된 문자 표현 방법에 의해 저장된 파일
- 모든 응용 프로그램에서 해석 가능
- 호환성 요할 때 사용
- AJAX로 값 전달할 시 이용
- ex) .txt : 모든 프로그램에서 열기 가능
2) 비구조적 문서 VS 구조적 문서
비구조적 문서
- ex) CSV 문서
구조적 문서
- ex) xml 문서
- ex) json 문서

6. 데이타의 종류에 따른 ajax 예시
1) html_two.jsp문서를 AJAX 기능으로 요청하여 "HTML 형식의 문서"로 응답 받아 태그를 변경하여 클라이언트에게 전달
💚AJAX엔진에게 [HTML]로 응답
- 앞에서 요청과 응답 : HTML로 받음
- 클라가 AJAX엔진을 통해 서버 WAS에게 요청 >>>
- WAS가 프로그램을 실행해 그 결과를 HTML로 전달 >>>
- AJAX엔진은 HTML을 출력
💚 news/html_one.jsp - HTML파일로 AJAX엔진에게 전달
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
//<%-- html_two.jsp문서를 AJAX 기능으로 요청하여 HTML 형식의 문서로 응답 받아 태그를 변경하여
//클라이언트에게 전달하는 JSP 문서 --%>
//<%-- 문제점) 다른 웹프로그램에서 JSP 문서(html_two.jsp)를 AJAX 기능으로 요청하여 응답받아 사용하기 불편 --%>
//<%-- 결과를 <table>로 출력하고 싶어도 이미 <ol><li>로 주기 때문에 사용하기 불편 --%>
//<%-- 해결법) AJAX 기능으로 요청하는 JSP 문서는 실행 결과를 HTML 문서가 아닌 데이타가 저장된
//문서 형식(CSV,XML,JSON 등)로 응답되도록 처리 - REST(RePresentional State Transfer) API (=RESTfull) : 상태전달 --%>
//<%-- => 웹프로그램에 대한 처리 결과값만 제공받아 HTML 태그로 변환(Parsing)하여 응답 처리 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/xhr.js"></script>
<style type="text/css">
#newsList{ width: 50%; margin: 0 auto; }
#newsHead{ padding: 5px; text-align: center; font-size: x-large; border: 2px solid black;}
#newsContent{ padding: 5px; font-size: medium; border: 2px dashed black; display: none;}
</style>
</head>
<body>
<h1>헤드라인 뉴스</h1>
<hr />
<div id="newsList">
<div id="newsHead">헤드라인 뉴스</div>
<div id="newsContent">
<!--<%--
<ol>
<li>뉴스제목-1[언론사-1]</li>
<li>뉴스제목-2[언론사-2]</li>
<li>뉴스제목-3[언론사-3]</li>
<li>뉴스제목-4[언론사-4]</li>
<li>뉴스제목-5[언론사-5]</li>
</ol>
--%>-->
</div>
</div>
<script type="text/javascript">
document.getElementById("newsList").onmouseover = function() {
//AJAX 기능을 사용하여 웹프로그램을 요청하여 응답결과를 제공받아 처리
sendRequest("get", "html_two.jsp", null, function() {
if(xhr.readyState==4){
if(xhr.status==200){
document.getElementById("newsContent").innerHTML=xhr.responseText;
}else{
alert("에러코드 = "+xhr.status);
}
}
});
document.getElementById("newsContent").style="display:block;"
}
document.getElementById("newsList").onmouseout = function() {
document.getElementById("newsContent").style="display:none;"
}
</script>
</body>
</html>
💚 news/html_two.jsp
<%@ 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>
</head>
<body>
<ol>
<li>현아-던, 입술에 커플 피어싱 '반짝'…결별 2달 만에 재결합 시그널인가[스포티비뉴스]</li>
<li>이보영 연기력이 아깝다…'재벌집 막내딸' 변신 실패한 손나은[텐아시아]</li>
<li>‘주영훈♥’ 이윤미 “국내 자산가 1위부터 10위까지 회장님들과 친해” (동상이몽2)[뉴스엔]</li>
<li>11기 현숙 "앞트임하고 쌍꺼풀 진해져…'보아 닮은꼴' 감사"[엑스포츠뉴스]</li>
<li>'김희애 아들' 전진서, 소속사 찾았다..이지훈x엄현경과 한솥밥[OSEN]</li>
</ol>
</body>
</html>
2) csv_two.jsp문서를 AJAX 기능으로 요청하여 "CSV 형식의 문서"로 응답 받아 태그로 변경하여 클라이언트에게 전달
💚AJAX엔진에게 [데이타]로 응답
- 원래 AJAX가 만들어진 이유 : 요청과 응답을 **데이타(값)**으로 하기 위해
- 일반적으로 결과를 데이타로 받아서 HTML로 바꿔서 출력하고 싶을 때 이용
- 클라가 AJAX엔진을 통해 서버WAS에게 요청 -> WAS가 프로그램을 실행해 그 결과를 값으로 전달 -> AJAX엔진은 그 값을 받아 HTML로 파싱해 출력함
csv 형식의 파일 - AJAX에서 비권장
- CSV(Comma Separated Values) : 콤마(,)를 사용하여 값을 구분하는 비구조적인 데이타 표현 방식
- 데이타 파일로는 괜찮지만, 웹에서 AJAX로 요청해서 사용하기에는 비구조적인 데이타 문서이므로 부적절
xml 형식의 파일 - AJAX에서 권장
- XML(eXensible Markup Language) : 엘리먼트(태그)를 사용하여 값을 구분하는 구조적인 데이타 표현 방식
- 구조적인 데이타 문서
- 특히, 웹에서 AJAX로 요청해서 사용하기 적절
- 대량의 데이타에 적절
json 형식의 파일 - AJAX에서 권장
- JSON(JavaScript Object Notation) : 자바스크립트에서 객체를 표현하는 방법을 사용하여 값을 구분하는 구조적인 데이타 표현 방식
- 구조적인 데이타 문서
- 특히, 웹에서 AJAX로 요청해서 사용하기 적절
- 파싱할 때 값 가져오기 쉽도록
- 단, 대량의 데이타에는 부적절 (2megaByte 이상..)
- 그러나 텍스트데이타는 대부분 2megaByte 이하이므로 JSON 많이 사용함
💚 news/csv_one.jsp - csv파일로 AJAX엔진에게 전달
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
//<%-- csv_two.jsp문서를 AJAX 기능으로 요청하여 CSV 형식의 텍스트 데이타로 응답 받아 태그로 변경하여
//클라이언트에게 전달하는 JSP 문서 --%>
//<%-- => CSV 형식의 데이타를 제공받아 HTML 태그로 변환하여 페이지의 요소 변경 - 파싱(Parsing:해석) 처리 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/xhr.js"></script>
<style type="text/css">
#newsList{ width: 50%; margin: 0 auto; }
#newsHead{ padding: 5px; text-align: center; font-size: x-large; border: 2px solid black; }
#newsContent{ padding: 5px; font-size: medium; border: 2px dashed black; display: none; }
</style>
</head>
<body>
<h1>헤드라인 뉴스</h1>
<hr />
<div id="newsList">
<div id="newsHead">헤드라인 뉴스</div>
<div id="newsContent">
<%--
<ol>
<li>뉴스제목-1[언론사-1]</li>
<li>뉴스제목-2[언론사-2]</li>
<li>뉴스제목-3[언론사-3]</li>
<li>뉴스제목-4[언론사-4]</li>
<li>뉴스제목-5[언론사-5]</li>
</ol>
--%>
</div>
</div>
<script type="text/javascript">
document.getElementById("newsList").onmouseover = function() {
//AJAX 기능을 사용하여 웹프로그램을 요청하여 응답결과를 제공받아 처리
sendRequest("get", "csv_two.jsp", null, function() {
if(xhr.readyState==4){
if(xhr.status==200){
//파싱작업
var csv = xhr.responseText;
//행(뉴스)을 분리하여 반환되는 Array 객체를 변수에 저장
var newsArray = csv.split("*");
//alert("newsArray.length = "+newsArray.length); //5
var html="<ol>";
for(i=0; i<newsArray.length; i++){
//열(제목과 언론사)을 분리하여 반환되는 Array 객체를 변수에 저장
var news=newsArray[i].split("|");
var title=news[0].trim(); //Array 객체의 0번째 요소값 >> 제목
var publisher=news[1].trim(); //Array 객체의 1번째 요소값 >> 언론사
html+="<li>"+title+"["+publisher+"]</li>";
}
html+="</ol>";
document.getElementById("newsContent").innerHTML=html;
}else{
alert("에러코드 = "+xhr.status);
}
}
});
document.getElementById("newsContent").style="display:block;"
}
document.getElementById("newsList").onmouseout = function() {
document.getElementById("newsContent").style="display:none;"
}
</script>
</body>
</html>
💚 news/csv_two.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
//<%-- 요청에 의해 실행 결과를 CSV 형식의 데이타로 응답하는 JSP 문서 --%>
//<%-- => 뉴스 제목과 언론사를 , 문자 대신 | 문자를 사용하여 구분 --%>
//<%-- => 뉴스와 뉴스는 엔터(Enter) 대신 * 문자를 사용하여 구분 --%>
현아-던, 입술에 커플 피어싱 '반짝'…결별 2달 만에 재결합 시그널인가|스포티비뉴스*
이보영 연기력이 아깝다…'재벌집 막내딸' 변신 실패한 손나은|텐아시아*
‘주영훈♥’ 이윤미 “국내 자산가 1위부터 10위까지 회장님들과 친해” (동상이몽2)|뉴스엔*
11기 현숙 "앞트임하고 쌍꺼풀 진해져…'보아 닮은꼴' 감사"|엑스포츠뉴스*
'김희애 아들' 전진서, 소속사 찾았다..이지훈x엄현경과 한솥밥|OSEN
3) xml_two.jsp문서를 AJAX 기능으로 요청하여 "XML 형식의 문서"로 응답 받아 태그로 변경하여 클라이언트에게 전달
💚 news/xml_one.jsp - xml파일로 AJAX엔진에게 응답
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
//<%-- xml_two.jsp문서를 AJAX 기능으로 요청하여 XML 형식의 문서로 응답 받아 태그로 변경하여
//클라이언트에게 전달하는 JSP 문서 --%>
//<%-- => XML 형식의 데이타를 제공받아 HTML 태그로 변환하여 페이지의 요소 변경
// - 파싱(Parsing:해석) 처리 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/xhr.js"></script>
<style type="text/css">
#newsList{ width: 50%; margin: 0 auto; }
#newsHead{ padding: 5px; text-align: center; font-size: x-large; border: 2px solid black; }
#newsContent{ padding: 5px; font-size: medium; border: 2px dashed black; display: none; }
</style>
</head>
<body>
<h1>헤드라인 뉴스</h1>
<hr />
<div id="newsList">
<div id="newsHead">헤드라인 뉴스</div>
<div id="newsContent">
<!--
<%--
<ol>
<li>뉴스제목-1[언론사-1]</li>
<li>뉴스제목-2[언론사-2]</li>
<li>뉴스제목-3[언론사-3]</li>
<li>뉴스제목-4[언론사-4]</li>
<li>뉴스제목-5[언론사-5]</li>
</ol>
--%>
-->
</div>
</div>
<script type="text/javascript">
document.getElementById("newsList").onmouseover = function() {
//AJAX 기능을 사용하여 웹프로그램을 요청하여 응답결과를 제공받아 처리
sendRequest("get", "xml_two.jsp", null, function() {
if(xhr.readyState==4){
if(xhr.status==200){
//XMLHttpRequest 객체의 responseXML 속성(Property)으로 요청에 대한
//응답 결과를 XML 문서로 제공받아 변수에 저장
var xmlDoc=xhr.responseXML;
//alert(xmlDoc); //[object XMLDocument] - XMLDocument 객체임
//즉, Document객체처럼 .연산자로 XMLDocument객체에 접근가능
//파싱
//Document.getElementsByTagName(tagName) : Document 객체에서 태그명을
//이용하여 태그를 검색해 검색된 태그에 대한 Element 객체들이 저장된
//NodeList 객체(HTMLCollection 객체)를 반환하는 메소드
var newsList=xmlDoc.getElementsByTagName("news");
//alert(newsList); //[object HTMLCollection] HTMLCollection객체 : NodeList의 자식이므로 NodeList와 동일 취급
//alert(newsList.length); //5 : 엘리먼트 객체가 총 5개 있다는 것
var html="<ol>";
for(i=0; i<newsList.length; i++){
//NodeList.item(i) : NodeList 객체에서 첨자 위치의 Element
//객체를 반환하는 메소드
var news=newsList.item(i);
//alert(news+i); //[object Element]0 , [object Element]1 , [object Element]2 , [object Element]3 , [object Element]4
//var title=news.getElementsByTagName("title").item(0); //<title>현아-던, 입술에 커플 피어싱 '반짝'…결별 2달 만에 재결합 시그널인가</title>
var title=news.getElementsByTagName("title").item(0).firstChild.nodeValue; //현아-던, 입술에 커플 피어싱 '반짝'…결별 2달 만에 재결합 시그널인가
var publisher=news.getElementsByTagName("publisher").item(0).firstChild.nodeValue;
html+="<li>"+title+"["+publisher+"]</li>";
}
html+="</ol>";
document.getElementById("newsContent").innerHTML = html;
}else{
alert("에러코드 = "+xhr.status);
}
}
});
document.getElementById("newsContent").style="display:block;"
}
document.getElementById("newsList").onmouseout = function() {
document.getElementById("newsContent").style="display:none;"
}
</script>
</body>
</html>
💚 news/xml_two.jsp
<?xml version="1.0" encoding="utf-8"?>
<%@ page language="java" contentType="text/xml; charset=UTF-8"
pageEncoding="UTF-8"%>
//<%-- 요청에 의해 실행 결과를 XML 형식의 데이타로 응답하는 JSP 문서 --%>
//<%-- => 엘리먼트(태그)를 사용하여 값 표현 --%>
//<%-- => 루트 엘리먼트는 반드시 한개만!!! ex) <newslist> --%>
//<%-- => 02.Well-Formed XML ppt 참고--%>
//<%-- => 단점) 속도 느림, 파싱하기 불편(사용불편) --%>
<newslist>
<news>
<title>현아-던, 입술에 커플 피어싱 '반짝'…결별 2달 만에 재결합 시그널인가</title>
<publisher>스포티비뉴스</publisher>
</news>
<news>
<title>이보영 연기력이 아깝다…'재벌집 막내딸' 변신 실패한 손나은</title>
<publisher>텐아시아</publisher>
</news>
<news>
<title>‘주영훈♥’ 이윤미 “국내 자산가 1위부터 10위까지 회장님들과 친해” (동상이몽2)</title>
<publisher>뉴스엔</publisher>
</news>
<news>
<title>11기 현숙 "앞트임하고 쌍꺼풀 진해져…'보아 닮은꼴' 감사"</title>
<publisher>엑스포츠뉴스</publisher>
</news>
<news>
<title>'김희애 아들' 전진서, 소속사 찾았다..이지훈x엄현경과 한솥밥</title>
<publisher>OSEN</publisher>
</news>
</newslist>
- 브라우저 엔진이 가진 DOM 파서에 의해 실행 시 출력됨
- 출력이 안되면 xml 문서에 에러났다는 것!!
4) json_two.jsp문서를 AJAX 기능으로 요청하여 "JSON 형식의 문서"로 응답 받아 태그로 변경하여 클라이언트에게 전달
💚 news/json_one.jsp - json파일로 AJAX엔진에게 응답
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
//<%-- json_two.jsp문서를 AJAX 기능으로 요청하여 XML 형식의 문서로 응답 받아 태그로 변경하여
//클라이언트에게 전달하는 JSP 문서 --%>
//<%-- => JSON 형식의 데이타를 제공받아 HTML 태그로 변환한여 페이지의 요소 변경 - 파싱(Parsing:해석) 처리 --%>
//<%-- 장점: XML보다 더 빠르게 데이타를 압축해서 전달 가능 --%>
//<%-- 단점: 대용량의 데이타에는 부적절 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/xhr.js"></script>
<style type="text/css">
#newsList{ width: 50%; margin: 0 auto; }
#newsHead{ padding: 5px; text-align: center; font-size: x-large; border: 2px solid black; }
#newsContent{ padding: 5px; font-size: medium; border: 2px dashed black; display: none; }
</style>
</head>
<body>
<h1>헤드라인 뉴스</h1>
<hr />
<div id="newsList">
<div id="newsHead">헤드라인 뉴스</div>
<div id="newsContent">
<!--
<%--
<ol>
<li>뉴스제목-1[언론사-1]</li>
<li>뉴스제목-2[언론사-2]</li>
<li>뉴스제목-3[언론사-3]</li>
<li>뉴스제목-4[언론사-4]</li>
<li>뉴스제목-5[언론사-5]</li>
</ol>
--%>
-->
</div>
</div>
<script type="text/javascript">
document.getElementById("newsList").onmouseover = function() {
//AJAX 기능을 사용하여 웹프로그램을 요청하여 응답결과를 제공받아 처리
sendRequest("get", "json_two.jsp", null, function() {
if(xhr.readyState==4){
if(xhr.status==200){
//eval(text):
// => 문자값을 전달받아 자바스크립트 명령으로 실행하는 함수
// => 문자값을 전달받아 자바스크립트 객체로 변환하기 위해 앞뒤에 ()연산자 추가
//var result = eval("("+xhr.responseText+")");
//or
//JSON.parse(json) :
// => JSON 형식으로 표현된 데이타를 자바스크립트 객체로 변환하여 반환하는 함수
// => 즉, JSON 형식으로 표현된 데이타는 그냥 문자값일 뿐임
var result = JSON.parse(xhr.responseText);
//alert(result); //[object Object],[object Object],[object Object],[object Object],[object Object]
//Object객체가 여러개 있는 배열로 나옴
//즉, [object Array] Array객체임
var html="<ol>";
for(i=0; i<result.length; i++){
var title=result[i].title;
var publisher=result[i].publisher;
html+="<li>"+title+"["+publisher+"]</li>";
}
html+="</ol>";
document.getElementById("newsContent").innerHTML = html;
}else{
alert("에러코드 = "+xhr.status);
}
}
});
document.getElementById("newsContent").style="display:block;"
}
document.getElementById("newsList").onmouseout = function() {
document.getElementById("newsContent").style="display:none;"
}
</script>
</body>
</html>
💚 news/json_two.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
//<%-- 요청에 의해 실행 결과를 JSON 형식의 데이타로 응답하는 JSP 문서 --%>
//<%-- => 크롬(Chrome) 앱스토어에서 JSON Viewer 프로그램을 브라우저에 설치하여 실행 --%>
//<%-- xml보다 함축적으로 표현 가능 --%>
//<%-- csv보다 구조적으로 표현 가능 --%>
//<%--요소가 하나인 Object 객체 만들 필요 없으니 --%>
//<%-- {"newsList" : []} --%>
//<%-- 아래처럼 만들자 --%>
//<%-- 주의) ["]더블 쿼테이션 문자는 [\\\\"] 이렇게 변환 필요 --%>
[
{
"title":"현아-던, 입술에 커플 피어싱 '반짝'…결별 2달 만에 재결합 시그널인가",
"publisher":"스포티비뉴스"
} ,
{
"title":"이보영 연기력이 아깝다…'재벌집 막내딸' 변신 실패한 손나은",
"publisher":"텐아시아"
} ,
{
"title":"‘주영훈♥’ 이윤미 “국내 자산가 1위부터 10위까지 회장님들과 친해” (동상이몽2)",
"publisher":"뉴스엔"
} ,
{
"title":"11기 현숙 \\\\"앞트임하고 쌍꺼풀 진해져…'보아 닮은꼴' 감사\\\\"",
"publisher":"엑스포츠뉴스"
} ,
{
"title":"'김희애 아들' 전진서, 소속사 찾았다..이지훈x엄현경과 한솥밥",
"publisher":"OSEN"
}
]
반응형
'web > javascript' 카테고리의 다른 글
[js - ajax] 16. ajax통신 예시 (0) | 2024.05.21 |
---|---|
[js - ajax] 15. ajax엔진 1개 vs 다수 | 응답 데이터 XML vs JSON vs XML&JSON (0) | 2024.05.21 |
[js - jquery] 13. jqeury 이벤트 기능 | 에니메이션 기능 (0) | 2024.05.20 |
[js - jquery] 12. jquery 개념 | 선택자 | each() | css() | attr() | text() | html() | 태그 추가,삭제,이동 (0) | 2024.05.19 |
[js] 11. 자바스크립트 쿠키(Cookie) 사용법 (0) | 2024.05.19 |