본문 바로가기
카테고리 없음

ajax를 이용한 검색어 자동 완성 기능 설명

by 멈추지않아 2022. 7. 6.

오늘 공부해보고 주변 사람들이 어려움을 겼는 한부분을 설명해보겠습니다. 

이 부분을 이해하면 다음에 다른 코드들의 흐름을 읽어보고 따라가는데 도움이 될 것 입니다.

suggest.jsp

<%@page import="java.util.ArrayList"%>
<%@page import="java.util.Collections"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%!
String[] keywords={
		"AJAX",
		"AJAX 실전 프로그래밍",
		"자바",
		"자바 프로그래밍",
		"자바스터디",
		"자바서비스",
		"자바캔"
};
public List search(String keyword){
	if(keyword==null || keywords.equals("")){
		System.out.println("se");
		return Collections.EMPTY_LIST;
	}
	System.out.println(keyword);
	keyword=keyword.toUpperCase();
	List result=new ArrayList(8);
	for(int i=0;i<keywords.length;i++){
		if(((String)keywords[i]).startsWith(keyword)){
			result.add(keywords[i]);
		}
	}
	return result;
}
%>
<%
request.setCharacterEncoding("utf-8");
String keyword=request.getParameter("keyword");
List keywordList=search(keyword);
out.print(keywordList.size());
out.print("|");
for(int i=0;i<keywordList.size();i++){
	String key=(String)keywordList.get(i);
	out.print(key);
	if(i<keywordList.size()-1){
		out.print(",");
	}
}

%>

suggestclient.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="httpRequest.js">
</script>
<script type="text/javascript">
var checkFirst=false;
var lastKeyword="";
var loopSendKeyword=false;
function startSuggest(){
	
	if(checkFirst==false){
		
		setTimeout("sendKeyword();",500);
	
		loopSendKeyword=true;
	
	}
	checkFirst=true;
}


function sendKeyword(){


	if(loopSendKeyword==false)return;
	var keyword=document.search.keyword.value;
	
	if(keyword==''){
		lastKeyword='';
		hide('suggest');
		
	}else if(keyword!=lastKeyword){
		lastKeyword=keyword;
	
		if(keyword!=''){
			var params="keyword="+encodeURIComponent(keyword);
			
			sendRequest("suggest.jsp",params,displayResult,'POST');
		}else{
			hide('suggest');
		}
	
	}
	setTimeout("sendKeyword();",500)
}
function displayResult(){
	if(httpRequest.readyState==4){
		if(httpRequest.status==200){
			
			var resultText=httpRequest.responseText;
			
			var result=resultText.split('|');
			var count=parseInt(result[0]);
			var keywordList=null;
			if(count>0){
				keywordList=result[1].split(',');
				var html='';
				for(var i=0;i<keywordList.length;i++){
					html+="<a href=\"javascript:select('"+keywordList[i]+"')\">"+keywordList[i]+"</a><br/>";
				}
				var listView=document.getElementById('suggestList');
				listView.innerHTML=html;
				show('suggest');
			}else{
				hide('suggest');
			}
		}else{
			alert("에러발생:"+httpRequest.status);
		}
	}
}

function select(selectedKeyword){

	document.search.keyword.value=selectedKeyword;
	loopSendKeyword=false;
	checkFirst=false;
	hide('suggest');
}
function show(elementId){

	var element=document.getElementById(elementId);
	if(elementId){
		element.style.display='';
	}
}
function hide(elementId){
	var element=document.getElementById(elementId);
	if(elementId){
		element.style.display='none';
	}
}
</script>
<style>
#view{
border:1px solid #999;
}
</style>
</head>
<body>
<form name="search">
<input type="text" name="keyword" id="keyword" onkeydown="startSuggest()"/>
<input type="button" value="검색"/>
<div id="suggest" style="display:;position:absolute;left:0px;top:30px;">
<div id="suggestList"></div>
</div>
</form>
</body>
</html>

httpRequest.js

/**
 * 
 */
function getXMLHttpRequest(){
	if(window.ActiveXObject){
		try{
			return new ActiveXObject("Msxml2.XMLHTTP");
		}catch(e){
			try{
				return new ActiveXObject("Microsoft.XMLHTTP");
			}catch(el){
				return null;
			}
		}
		
		
	}else if(window.XMLHttpRequest){
			return new XMLHttpRequest();
		}else{
			return null;
		}
}
var httpRequest=null;

function sendRequest(url,params,callback,method){

	httpRequest=getXMLHttpRequest();

	var httpMethod=method?method:'GET';

	if(httpMethod!='GET'&&httpMethod!='POST'){
		httpMethod='GET';
	}
	
	var httpParams=(params==null||params=='')?null:params;
		
	var httpUrl=url;
;
		if(httpMethod=='GET'&&httpMethod!=null){
		httpUrl=httpUrl+"?"+httpParams;

	}

	httpRequest.open(httpMethod,httpUrl,true);
	httpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	httpRequest.onreadystatechange=callback;
	httpRequest.send(httpMethod=='POST'?httpParams:null);
}

여기까지가 내가 사용할 전체 코드이다. 이제 코드를 하나씩 실제로 사용되는 순서로 해설해 보겟습니다.

 

<body>
<form name="search">
<input type="text" name="keyword" id="keyword" onkeydown="startSuggest()"/>
<input type="button" value="검색"/>
<div id="suggest" style="display:;position:absolute;left:0px;top:30px;">
<div id="suggestList"></div>
</div>
</form>
</body>

여기서 보면  입력하는 부분(input태그) 과 버튼(button태그)가 있습니다.

그리고 그밑에 검색어 자동완성 목록을 넣어줄 수 있게 설계한 div태그가 있습니다.

그럼 우선 우리가 글자를 입력하게 되면 keydown이 되어서 onkeydown에 열결되어있는 startSuggest()함수가 실행됩니다.

var checkFirst=false;
var lastKeyword="";
var loopSendKeyword=false;
function startSuggest(){
	
	if(checkFirst==false){
		
		setTimeout("sendKeyword();",500);
	
		loopSendKeyword=true;
	
	}
	checkFirst=true;
}

 

여기보시면 기본 값으로 checkFirst,loopSendKeyword가 false lastkeyword가 ""(비어있다는 뜻) 이렇게 배정되어있습니다.

startSuggest()함수가 keydown이라는 이벤트(행위)  발생으로 실행이 됩니다.

우선 if(checkFirst==false) 여기서 checkFirst가 false인지 확인을 하고  현재 초기값이 false인 그대로 이므로  checkFirst==false는 true가 되어서 if문에 진입하게 됩니다.

setTimeout("sendKeyword();",500);여기서 setTimeout은 두번째로 들어온 시간(1000=1초 현재 500이므로 0.5초)만큼 기다린 후에 실행하게 됩니다.

그동안  다음 코드를 실행하게 됩니다. 

다음 코드로 따라가다가 loopSendKeyword=true;이걸 만나서 loopSendKeyword값을 true로 바꺼 줍니다.

 또 밑으로 내려오면서 if문을 벗어나고 이어서 실행하다가 checkFirst=true; 만나서 checkFirst를true로 바꺼줍니다.

그러면 현재  startSuggest()함수를 모두 실행했습니다. setTimeout("sendKeyword();",500); 이코드를 실행하고 0.5초가 지나기 전까지는 실행되는 코드가 없어서 그냥 시간이 흘러가게 됩니다.

그리고 0.5초가 지나게 되면 sendKeyword()라는 함수를 실행하게 됩니다.

function sendKeyword(){


if(loopSendKeyword==false)return;
var keyword=document.search.keyword.value;

if(keyword==''){
lastKeyword='';
hide('suggest');

}else if(keyword!=lastKeyword){
lastKeyword=keyword;

if(keyword!=''){
var params="keyword="+encodeURIComponent(keyword);

sendRequest("suggest.jsp",params,displayResult,'POST');
}else{
hide('suggest');
}

}
setTimeout("sendKeyword();",500)
}

처음 시작해서 if(loopSendKeyword==false)return; 여기를 실행시키면 loopSendKeyword를 실행시키면 

startSuggest함수에서 loopSendKeyword=true;로 true로 바꺼주어서 loopSendKeyword==false는 false(loopSendKeyword의 값이 false라는 것이아니고 조건이 false라는 말입니다.)가 되게 됩니다.

var keyword=document.search.keyword.value;를 실행하게 되면 keyword라는 변수에  document 즉 html태그들을 객체로 만들어서 저장시킨 집합(모음) 안에서 name이 search인 요소를 찾고  또 그 객체 안에서 keyword를 찾고  그 keyword의 값 (즉 안에 저장되어있는 내용)을 keyword에 저장하게 됩니다.

현재 코드에서는 

search는 form태그를 가르키고(<form name="search">)

keyword는 form태그 내부에 있는 input 태그를 가르키게 됩니다.(<input type="text" name="keyword" id="keyword" onkeydown="startSuggest()"/>)

value 는 결국 우리가 입력한 값이 되게 됩니다. 

즉 keyword라는 변수에 우리가 입력한 변수를 저장하게 됩니다.

그럼 우리가  자바 라고 입력했다고 가정하고 하겠습니다.

실행하고 밑으로 내려가서 if(keyword=='')를 만나면 우리는 keyword가 현재  자바 이기때문에 keyword==''는  false가되고 

실행 하지 않고elseif로 넘어가게 됩니다. 그런데 만약 우리가 작성하고 지웠다고 하면 keyword가 ''가 되기 때문에 true가 되고 if문을 실행하게 됩니다.  그럼 if문이 어떤내용으로 실행되는지 확인해보겠습니다.

<--if문 내부(설명을 위한것 지금 자바를 입력했다고 가정하면 실행되지 않음)-->

lastKeyword='';를 만나서 lastKeyword에 ''를 저장해주게 됩니다.

그리고 hide('suggest');를 만나서 hide 함수를 실행 시켜주게 됩니다.

function hide(elementId){
	var element=document.getElementById(elementId);
	if(elementId){
		element.style.display='none';
	}
}

hide 함수를 보면 아까 hide('suggest');이렇게 실행했기 때문에 elementId='suggest'가 됩니다.

그럼 var element=document.getElementById(elementId); 여기를 만나면  아까 설명했던 document즉 html태그들을 객체로 만들어서 저장한 집합안에서 Id속성 값이 elementId인 객체를 찾게 됩니다.(getElementById ) 여기서 elementId는 suggest이므로  <div id="suggest" style="display:;position:absolute;left:0px;top:30px;"> 이게 element가 됩니다.

if(elementId) 이것을 만나면 elelmentId가 값을 가지고 있냐고 묻는 것이기 때문에 true가 됩니다. 저런게 조건문 작성시 0 null undefined  '' 이거빼고는 다 true가 됩니다.

element.style.display='none';을 만나면 아까 찾았던 

<div id="suggest" style="display:;position:absolute;left:0px;top:30px;">  여기 안에 style( style="display:;position:absolute;left:0px;top:30px;") 여기 안에 display(display:;)를 찾아서 안에 값을 none으로 바꺼줍니다. 그러면 display:none;이 되고 우리 눈에 보이지 않게 됩니다.

그러고 나면 hide('suggest')함수가 끝나고  다시 sendKeyword()함수로 돌아오게 됩니다.

<--if문끝(이부분까지 자바라고 입력했다고 가졍했기때문에 현재 실행되지 않음)-->

이제 다시 보면 else if(keyword!=lastKeyword)를 만나고 초기에 var lastKeyword="";이렇게 lastKeyword를 ""로 정의 했고 현재 keyword는 자바 이므로 서로 같지 않습니다 그래서 현재 keyword!=lastKeyword는 true를 반환하게 됩니다.(만약 !=이 아니고 ==이였다면 false를 반환하고 else if문 무시됨)

var params="keyword="+encodeURIComponent(keyword); 이 문장을 만나면

keyword=(변수 keyword아님)이라는 글자에다가 변수 keyword 내용을 URIComponent 형식으로 바꺼서  keyword=와 더하게 됩니다. 즉 문자 문자 더하기는 두문자를 이어주는게 되기때문에 params는 keyword=형식이 변경된keyword 값이 됩니다.

sendRequest("suggest.jsp",params,displayResult,'POST'); 만나서 sendRequest 함수를 실행하고 4가지 인자를 같이 전달해 줍니다.

function sendRequest(url,params,callback,method){

	httpRequest=getXMLHttpRequest();

	var httpMethod=method?method:'GET';

	if(httpMethod!='GET'&&httpMethod!='POST'){
		httpMethod='GET';
	}
	
	var httpParams=(params==null||params=='')?null:params;
		
	var httpUrl=url;
;
		if(httpMethod=='GET'&&httpMethod!=null){
		httpUrl=httpUrl+"?"+httpParams;

	}

	httpRequest.open(httpMethod,httpUrl,true);
	httpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	httpRequest.onreadystatechange=callback;
	httpRequest.send(httpMethod=='POST'?httpParams:null);
}

httpRequest=getXMLHttpRequest(); 우선 여기를 실행하면

function getXMLHttpRequest(){
	if(window.ActiveXObject){
		try{
			return new ActiveXObject("Msxml2.XMLHTTP");
		}catch(e){
			try{
				return new ActiveXObject("Microsoft.XMLHTTP");
			}catch(el){
				return null;
			}
		}
		
		
	}else if(window.XMLHttpRequest){
			return new XMLHttpRequest();
		}else{
			return null;
		}
}

이 함수가 실행되고 window.ActiveXObject가 있으면 if(window.ActiveXObject)여기서 true가 반환되고 

return new ActiveXObject("Msxml2.XMLHTTP");이것이 실행되면서 new ActiveXObject("Msxml2.XMLHTTP");이 객체가 반환 되는데 오류가 생기면 catch 로넘어가서return new ActiveXObject("Microsoft.XMLHTTP"); ActiveXObject("Microsoft.XMLHTTP");객체가 반환되고 여기서 또 오류가 생기면 return null; null을 반환하게 됩니다.

 

window.ActiveXObject이 없으면else if(window.XMLHttpRequest)로 넘어가서 window.XMLHttpRequest가 있는지 확인하고 있으면  return new XMLHttpRequest();  XMLHttpRequest 객체를 반환 해줍니다 

 

그런데 이것도 없으면 return null null을 반환 합니다.

 이렇게 다 실행하고 나서 sendRequest로 돌아오면 httpRequest에 xml관련 객체가 반환 되어 있을 것입니다.

var httpMethod=method?method:'GET';이것을  만나면 method?method:'GET'; method가 있으면method 없음면 'GET' 을 반환시키는 삼항연산자를 실행하게 됩니다. 현재 sendRequest("suggest.jsp",params,displayResult,'POST');여기서 method에 POST를 저장했으므로 POST가 반환되고 httpMethod에는 POST가 저장 됩니다.

if(httpMethod!='GET'&&httpMethod!='POST')를 만나서  httpMethod가 GET도 아니고 POST가 아니면 true를 반환하게 되고 현재 POST이므로 false를 반환하게 됩니다.(만약 true를 반환하게 된다면 httpMethod='GET';를 실행해서 httpMethod는 GET이 됩니다.)

var httpParams=(params==null||params=='')?null:params;여기를 실행하면 아까랑 똑같이 삼항연산자 인데params==null||params=='' 아까

var params="keyword="+encodeURIComponent(keyword);
sendRequest("suggest.jsp",params,displayResult,'POST');

이두코드로 인해서 parms에 keyword=형식이 변경된keyword 값이 저장 되었습니다. 빈공간도 아니고 null도 아니므로 false를 반환하고 httpParams에는 params의 값을 저장하게 됩니다.

var httpUrl=url; httpUrl은 sendRequest("suggest.jsp",params,displayResult,'POST');여기서 받아온 suggest.jsp를 httpUrl에 저장하게 됩니다.

if(httpMethod=='GET'&&httpMethod!=null) httpMethod는 var httpMethod=method?method:'GET';여기서 넘어온 POST로 결정 되었기 때무누에  false를 반환하고 그냥 지나가게 됩니다.(만약 true라면 httpMethod='GET';이것을 만나서httpMethod를 GET로 설정합니다.

httpRequest.open(httpMethod,httpUrl,true); 여기서 open에 각각 변수의 내용을 담아서 실행하고 첫번재 인자는 post인지 get인지 정하게 되고 두번째는 전송할 주소 세번째는 true이면 비동기  false이면 동기로 전송합니다.
httpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); 헤더에 이러한 내용을 담고
httpRequest.onreadystatechange=callback; 상태가 변경될시 실행할 함수를 등록 현재 sendRequest("suggest.jsp",params,displayResult,'POST');여기서 displayResult를 받아왔으므로 displayResult가 등록됩니다.
httpRequest.send(httpMethod=='POST'?httpParams:null);여기서httpMethod=='POST'가 sendRequest("suggest.jsp",params,displayResult,'POST');여기서 POST받아와서 true가 됬으므로 httpParams을 넘겨 주게 된다.var httpParams=(params==null||params=='')?null:params;즉 여기서 설정된keyword=형식이 변경된keyword 값이전달 됩니다.

 

오늘은 여기서 마치고 내일 이어서 설명하겠습니다.