본문 바로가기

Ajax & jQuery

Ajax(3) - CSV 형식 데이터 읽기, 검색 시 제시어 기능

1. CSV 읽어오기 ex. 뉴스 헤드라인 목록 - newsTitleCSV.jsp 
2. 검색 시 제시어 기능 만들기 - suggestClient.jsp

<%! ..%> 의 의미

jsp는 톰캣서버에 올라가서 자기 로컬 경로에 class, java파일이 생성됨
=> class파일 들어가보면 Init() Destroy() Service() 있음. 

<% ... %> 이렇게 만들면 그 안의 내용이 Service() 메소드 안에 생성이 됨 - 메소드 안에 또 메소드를 정의할 때는 이 안에 쓸 수 없음
<%! ... %> Service() 바깥에 생김 => 전역변수로 생성된다는 소리

 

httpRequest.js - XMLHttpRequest 객체 생성 파일 (공통으로 쓸 것)

function getXMLHttpRequest(){
	//IE인 경우
	if(window.ActiveXObject){
		try {
			// 객체 생성
			// 방법 1. XMLHttpRequest = new ActiveXObject("Msxml2.XMLHTTP"); 
			// 방법 2.  return으로 바로 돌려줄 수 있다
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			return ActiveXObject("Microsoft.XMLHTTP");
		}
	}else{ // Non-IE
		return new XMLHttpRequest();
	}
}

//getXMLHttpRequest() => 자동으로 실행되는게 아님, 호출하는 애가 필요
//Ajax 요청
var httpRequest = null;
function sendRequest(url,params,callback,method){
	
	// 객체를 만듬
	httpRequest = getXMLHttpRequest();
	
	// 이 sendRequest() 함수만 호출하면, 처리작업을 하고 callback함수 만듬
	
	// method 처리
	var httpMethod = method?method:"GET";
	
	// method를 받아서 그 method가 있으면 쓰고 없으면 'GET'방식 사용
	
	// 혹시 몰라서 한 번 더 체크한거
	if(httpMethod!="GET" && httpMethod!="POST"){
		httpMethod="GET";
	}
	// params 처리
	var httpParams=(params==null||params=="")?null:params;
	//url 처리
	var httpUrl = url;
	
	//GET방식이면서 data가 있으면,
	if(httpMethod=="GET" && httpParams!=null){
		httpUrl = httpUrl+"?"+httpParams;
	}
	
	httpRequest.open(httpMethod,httpUrl,true);
	httpRequest.setRequestHeader("Content-Type",
			"application/x-www-form-urlencoded");
	 // POST 방식일 때, 데이터 넘어가는 방식이라 반드시 넣어줘야함
	
	httpRequest.onreadystatechange = callback;
	httpRequest.send(httpMethod=="POST"?httpParams:null);
	//httpMethod가 POST 방식이면 httpParams를 보내고
	//그렇지 않으면 null을 넣는다
	
	// callback 함수까지 만들어 놓은 것
}

 

1. CSV형식으로 된 데이터 읽어오기

 

newsTitleCSV.jsp - csv 읽어오기

 

표본

newsTitleCSV.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setCharacterEncoding("UTF-8"); 
	String cp = request.getContextPath(); 
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>newsTitleCSV</title>

<style type="text/css">

.news{
	font-size: 9pt;
	display: block;
	margin: 0 auto;
	background: yellow;
	color: blue;
	border: 1px dashed black;
	width: 50%;
}

.newsError{
	font-size: 9pt;
	display: block;
	margin: 0 auto;
	background: orange;
	color: red;
	border: 5px double black;
	width: 50%;
}
</style>

<!-- 이 파일과 js폴더는 같은 경로에 있는거니깐 ../ 쓸 필요 없이 경로 바로 js/로 주면 됨 -->
<script type="text/javascript" src="js/httpRequest.js"></script>
<script type="text/javascript">

	function newsTitle() {
		sendRequest("newsTitleCSV_ok.jsp",null,displayNewsTitle,"GET");
		setTimeout("newsTitle()",3000);	//자기자신을 3초마다 호출
	}
	
	//콜백함수 여기서 받아줌
	function displayNewsTitle() {
		
		//넘어오는 데이터를 작업
		if(httpRequest.readyState==4){
			if(httpRequest.status==200){
				
				var csvStr = httpRequest.responseText;
				//alert(csvStr);
				
				var csvArray = csvStr.split("|");
				// 0번째 방 : 7
				// 1번째 방 : 모든 데이터들
				
				var countStr = csvArray[0];
				//alert(countStr);
				
				if (countStr == 0) {
					alert("News가 없다!");
					return;
				}
				
				var csvData = csvArray[1];
				
				// * 기준으로 나누기
				var newsTitleArray = csvData.split("*");
				//alert(newsTitleArray.length); 
				// 배열이라 alert로 못찍어보니깐 length로 찍어보기
				
				var html = "";
				
				html += "<ol>";
				
				// 모든 기사가 <li> 붙으면서 <ol> 안에 들어오게
				// ol 과 li 때문에 일렬번호가 화면에 붙는거임
				for(var i=0; i<newsTitleArray.length;i++) {
					
					var newsTtile = newsTitleArray[i];
					html += "<li>" + newsTtile + "</li>";
					
				}
				
				html += "</ol>";
				
				//alert(html);
				
				// 화면에 뿌려주기
				var newsDiv = document.getElementById("newsDiv");
				newsDiv.innerHTML = html;
				
			} else { //statue: 200이 아니면,
				
				var newsDiv = document.getElementById("newsDiv");
				newsDiv.innerHTML = httpRequest.status + "에러 발생!";
				
				// 에러 처리
				// 1) IE 인 경우
				newsDiv.className = "newsError";
				
				// 2) non IE 인 경우
				newsDiv.setAttribute("class","newsError");
				
			}
			
		}
	
		
	}
	
	// news를 보일 때
	function showNewsDiv() {
		
		var newsDiv = document.getElementById("newsDiv");
		newsDiv.style.display = "block";
		
	}
	
	// news를 숨길 때
	function hideNewsDiv() {
		
		var newsDiv = document.getElementById("newsDiv");
		newsDiv.style.display = "none";
		
	}
	
	window.onload = function() {
		newsTitle();
	}


	</script>

	</head>
	<body>

	<h2>헤드라인 뉴스</h2>
	<hr/>
	<br/>
	
	<div style="display: block; border: 3px solid; width: 50%;
	margin: 0 auto;">뉴스보기</div>
	
<!--  마우스 커서를 올리면 뉴스 헤드라인이 뜨고 올리지 않으면 숨겨진다
	<div onmouseover="showNewsDiv();" onmouseout="hideNewsDiv();"
	style="display: block; border: 3px solid; width: 50%;
	margin: 0 auto;">뉴스보기</div> 
	-->

	<div id="newsDiv" class="news"></div>
	</body>
	</html>
newsTitleCSV_ok.jsp
<%@page import="java.util.Date"%>
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setCharacterEncoding("UTF-8"); 
	String cp = request.getContextPath(); 
%>

<%!
	
	// 여러 기사들이 저장된 db에서 읽어오는 기준? 
	// 1. title을 subject로 입력했다면 subject만 select 해오기
	// 2. substring으로 앞 몇 글자만 select 해오기 
	
	// db에서 읽어와서 배열에 넣었다고 가정
	String[] newsTitle={
			"21일 국토교통부 실거래가 공개시스템에 따르면", 
			"서초선포레 아파트 전용면적 21.58㎡는 올해 3분기 총 3건이 거래됐다",
			"연이어 석 달 동안 거래된 것으로 나온 이 아파트 가격은",
			"10억~14억7500만원으로 3.3㎡당 최소 1억5291만원에서 ",
			"최대 2억2555만원에 이른다. 서초선포레가 위치한 청계산입구역 인근 ",
			"공인중개사 사무소는 '서초선포레는 서울주택도시공사(SH공사)가 관리하는",
			"아파트인지라 민간이 매매할 수 없다'며 의아하다는 반응을 내놓았다.",
			"[단독]아메리카노에 버블 추가 화제...요즘 이상한 유행돌고 있다고 해 취재"
	};
	// 데이터 하나 더 추가? => 시간 지나면 알아서 추가되어서 화면에 뜸
	// 지워도 마찬가지 (기자입장에서는 이 기사만 등록하고 삭제해도
	//  실시간으로 네이버 메인페이지에 적용이 됨)

	// CSV : ,로 구분된 데이터

%>

<%
// 실제로는 위에 db 읽어오는 부분이고, 이 아래부분 코드는 늘 똑같을 것임 

// 기사가 7개라면, (갯수는 중요. 배열의 갯수니깐)
// 구분자 | (구분자 *로 써도 됨. 사용자 정의)

// 갯수 | 제목 | 기사작성날짜 (기사와 기사의 구분자는 *로)
// 7| 21일 국토교통부 실거래가 공개시스템에 따르면 | [2019.10.22 오전 10:16]* 
// 서초선포레 아파트 전용면적 21.58㎡는 올해 3분기 총 3건이 거래됐다 |  [2019.10.22 오전 10:16]* 
// ... 

// 전역변수인 newsTitle에 접근 가능
	out.print(newsTitle.length + "|"); // 7|
	
	for (int i=0; i<newsTitle.length; i++) {
		
		out.print(newsTitle[i] + "["+ new Date() + "]");
		
		if(i!=(newsTitle.length-1)) { // 6일 때까지 * 모양 붙여라 => 맨 마지막 기사에는 * 안붙게
		
			out.print("*"); 
			
		}
	}
	

%>

 

2. 검색 시 제시어 기능 만들기

검색엔진 원리: 사용자가 검색한 단어를 DB에 누적시켜 저장시킨 뒤 검색빈도가  높은 목록을 정리해서 출력해준다

 

 

 

suggestClient.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setCharacterEncoding("UTF-8"); 
	String cp = request.getContextPath(); 
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>

<style type="text/css">

.suggest{
	display: none;
	position: absolute;
	left: 11px;
	top: 131px;
}

</style>

<script type="text/javascript" src="js/httpRequest.js"></script>

<script type="text/javascript">

	//메인
	function sendKeyword() {
		
		var userKeyword = document.myForm.userKeyword.value;
		
		if(userKeyword=="") {
			
			hide();
			return;
		}
		
		// 삭제alert(userKeyword);
		var params = "userKeyword=" + userKeyword;
		sendRequest("suggestClient_ok.jsp",
				params,displaySuggest,"POST");
	}
	
	// 콜백함수
	function displaySuggest() {
		
		if(httpRequest.readyState==4) {
			if(httpRequest.status==200) {
				
				//넘어오는 데이터 받아내고
				var resultText = httpRequest.responseText;
				// 4|a,b,c,d (갯수|keyword1들) 형태 
				
				var resultArray = resultText.split("|");
				
				var count = parseInt(resultArray[0]);
				
				var keywordList = null; 
				
				// 반복문을 통해 keyword들을 담는다
				if(count>0) {
					
					keywordList = resultArray[1].split(",");
					// , 로 구분하여 배열로 들어감
					
					var html = ""; 
					
					//제시어에 링크걸기
					for(var i=0; i<keywordList.length; i++) {
						
						html += "<a href=\"javascript:select('"
								+ keywordList[i] + "');\">"
								+ keywordList[i] + "</a><br/>";
						// <a href="javascript:select('ajax');">ajax</a><br/>
							
					}
					
					var suggestListDiv = 
						document.getElementById("suggestListDiv");
					
					suggestListDiv.innerHTML = html;
					show();
					
				} else { // count == 0 인 경우, 
					
					hide();
				
				}
			} else { // status!=200
				
				hide();
			
			}
			
		} else {	// readyState != 400
				hide();
		
			}
	}
	
	// 리스트에서 클릭한게 검색창(input box)에 들어가게끔 
	// = 사용자가 제시어에서 클릭한 키워드
	function select(selectKeyword) {
		
		// 클릭한 제시어를 inputbox에 넣음
		document.myForm.userKeyword.value = selectKeyword;
		hide(); // 클릭하면 더이상 제시어리스트창은 안보여야하니깐
		
	}
	
	// 화면보기
	function show() {
		var suggestDiv = document.getElementById("suggestDiv");
		suggestDiv.style.display = "block";
	}
	
	// 화면 숨기기
	function hide() {
		var suggestDiv = document.getElementById("suggestDiv");
		suggestDiv.style.display = "none";
	}
	
	window.onload = function() {
		hide();
	}

</script>



</head>

<body>
<h1>제시어</h1>
<form action="" name="myForm">

<input type="text" name="userKeyword" onkeyup="sendKeyword();"/>
<input type="button" value="검색"/>

<!-- 검색 바로밑에 뿌려줘야하니깐 br주지 말고 -->
<div id="suggestDiv" class="suggest">
	<div id="suggestListDiv"></div>
</div>


</form>

</body>
</html>

 

suggestClient_ok.jsp
<%@page import="java.util.Iterator"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.Collections"%>
<%@page import="java.util.List"%>
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setCharacterEncoding("UTF-8"); 
	String cp = request.getContextPath(); 
	
%>

<%!
	// ! 없으면 Service() 안에 만들어짐
	//DB에서 읽어왔다고 가정 
	String[] keywords = {
			"ajax","Ajax","Ajax실전프로그래밍","AJA","AZERA","자수",
			"자전거","자라","자바프로그래밍","자바 서비스 페이지(jsp)",
			"자바스터디","astra","abort","자바 서비스","자바캔",
			"ABC마트","Apple"
	};

	// ! 없으면 Service() 안에 또 메소드가 되어버림 => 메소드 안에 메소드 생성될 수 없으니까 안됨.
	public List<String> search(String userKeyword){
		
		if(userKeyword==null || userKeyword.equals(""))
			return null; 
		// 이렇게 return해도 됨 (자바에서도 마찬가지)	
		// return Collections.EMPTY_LIST;
		
		// 소문자 입력시 대문자로 결과를 반영 (회사에 따라 다름)
		// userKeyword = userKeyword.toUpperCase();
		
		// List로 반환
		List<String> lists = new ArrayList<String>();
		
		// 사용자 입력 단어, db 있는 단어 비교작업
		for(int i=0; i<keywords.length; i++) {
			
			if(keywords[i].startsWith(userKeyword)) {
				// 사용자가 입력한 값을 가지고 앞부분부터 비교
				 lists.add(keywords[i]); //배열에 있는 그 값을 lists에 넣어라
			}
		}
		
		return lists; 
	}

%>


<%
// Service() 안에  올 애니깐 위에랑 분리시켜준거임

	String userKeyword = request.getParameter("userKeyword");
	List<String> keywordList = search(userKeyword);
	
	//몇개인지 
	out.print(keywordList.size());
	out.print("|"); //구분자
	
	Iterator<String> it = keywordList.iterator();
	
	while (it.hasNext()) {
		
		String value = (String)it.next();
		
		out.print(value);
		
		if(keywordList.size()-1 > 0) {
			out.print(",");
		}
		
	}
	
	// 이렇게 만들어진 결과를 text로 suggestClient.jsp로 넘어가는것
	
%>