IT 일기장

[Java] 인기 검색어 기능 구현 - 1 본문

프로그래밍 언어/Java

[Java] 인기 검색어 기능 구현 - 1

뽕슈 2021. 12. 25. 02:07
반응형

이건 분류하기가 참 애매하다. Ajax도 있고 JQuery도 있고 HTML,도 있고 그런디...

 

수행하는 프로젝트에서 인기검색어 구현을 해달라는 요청 건이 있었는데..

이것도 구현한지 시간이 꽤 지났다. 작년에 했던거 같은데 경험담으로 정리해놔야지

기획자의 기획서 바탕으로 구현했는데 흠.. 더 좋은 방법이 있을지 고민좀 해봐야겠다

아무튼 인기검색어를 제어하는 관리자 화면은 다음과 같다

 

관리자는 실제 사용자 사이트 화면에 인기 검색어를 출력하기 위해 제어하는 공간이다.

 

왼쪽에 보이는 "DB 검색순위"는 사용자가 검색한 단어를 DB에 INSERT해서 가장 많이 검색한 단어를 100개까지

페이지 단위로 나눴다. 그리고 추가 버튼을 누르면 "사용자 화면 검색 순위"에 추가되는 원리이다

 

오른쪽에 보이는 "사용자 화면 검색 순위"는 사용자 화면에 보여질 검색 순위를 제어한다.

체크박스 선택해서 삭제할수도 있고, 화살표 눌러서 위치 바꿀수도 있고, 

(솔직히 지금 볼 때는 화살표 보다는 드래그가 편하다)

저장 버튼을 누르면 현재 시점으로 적용된 사용자 화면 검색 순위가 반영된다.

사용자에 검색 순위가 반영되는 최대 개수는 10개다.

 

사용자 화면은 다음과 같다.

 

.. 뭐 사용자는 별거없다 상황에 맞게 적절히 원하는 곳에 배치 해주면 될 듯하다.

구현은 아래와 같이 했었다. 화면단은 입맛에 맞게 그려주면 될 듯해서 기능단만 정리해놔야지

 

테이블은 2개를 사용했는데 사용자가 검색 했을때 추가될 DB, 사용자 화면에 보여줄 DB 따로 구성했었다

 

## 사용자가 검색시 INSERT될 DB

TABLE NAME : t_popular_word
COLUMN : popw_word, popw_date

## 사용자 화면에 보여줄 DB

TABLE NAME : t_user_popular_word
COLUM : user_popw_word, user_popw_date, user_popw_order


popw_word : 사용자가 검색한 단어
popw_date : 검색한 날짜

user_popw_word : 사용자에게 보여줄 단어
user_popw_date : 표출일
user_popw_order : 단어 순서

 

1. DB 검색순위를 SELECT하는 쿼리는 다음과 같다

 

<select id="selectPopularWord" resultType="itgMap">
	/* selectPopularWord */
	SELECT popw_word, COUNT(popw_word) as wordcnt
	FROM t_popular_word
	GROUP BY popw_word
	ORDER BY wordcnt DESC
	LIMIT 0,100
</select>

 

 

DB는 MySQL을 사용했다. 검색한 단어를 카운팅하고 GROUP BY로 묶어서 가장 많이 검색된 단어를

100개까지 순차적으로 검색하는 쿼리다.

 

2. 페이징은 Ajax로 구현하려고 했으나 딱히 100개 불러온다고 속도에 중대한 영향을 미치는 것도 아니라는 판단이 들기도 하고, 게다가 우리 솔루션 특성상 Ajax 태우면 공통으로 로딩중 이미지를 출력하기 때문에 사용자들이 이게 뭐지.. 싶을거 같아서 방법을 바꿨다. 100개를 모두 부르고 안보이게 한뒤, 페이지를 누를때마다 10개씩 보이게끔 만들어봤다

 

<table id="searchRank" class="table table-bordered">
	<colgroup>
		<col style="width: 55px;">
		<col style="width: 70px;">
		<col style="width: *;">
	</colgroup>
	<thead>
		<tr>
			<th scope="col">
            	<input type="checkbox" name="chkAllone" id="chkAllone" value="Y" title="전체선택/해제" onclick="fn_displayBlockCheckAll(this);" />
           	</th>
			<th scope="col">순위</th>
			<th scope="col">DB 제목</th>
		</tr>
	</thead>
    <tbody id="popularWordList">
		<c:forEach var="popular" items="${popularWordList}" varStatus="status">
			<tr id="wordList${status.count}" class="tac">
    			<td class="text-c"><input type="checkbox" name="chkIdone" id="popWord${status.count}" value="${popular.popwWord}"></td>
    			<td style="text-align: center;">${listNo+status.count}</td>
    			<td style="text-align: center;">${popular.popwWord}</td>
    		</tr>
    	</c:forEach>
    </tbody>
</table>

<div class="text-center dataTables_paginate paging_simple_numbers" id="example1_paginate">
	<ul class="pagination">
		<c:forEach varStatus="status" begin="1" end="${paginationInfo.totalPageCount}">
			<li id="page${status.count}" class="paginate_button">
            	<a href="#none" onclick="goPage(${status.count-1})">${status.count}</a></li>
		</c:forEach>
	</ul>
</div>

 

지금 위 소스는 DB 검색순위 화면 html이다. 여기서 내가 먼저 작업했던 부분은 저 인기검색어 관리자 페이지에 들어왔을 때 무조건 1페이지부터 보여줘야 되니 JQuery로 버튼을 활성화 시키고 맨 처음 10개 단어를 보여주게 했다

 

	// var은 구 버전.. 버그가 많기 때문에 요즘은 let 변수를 많이쓴다. 참고
    var list = "${fn:length(popularWordList)}";
    

	$(document).ready(function()
	{
		for(a=1 ; a<=list ; a++){
			$("#wordList"+a).hide();
		}
		for(b=1 ; b<=10 ; b++){
			$("#wordList"+b).show();
		}

		$("#page1").addClass("active");
		$("#page1").addClass("on");
    }

 

 

그 다음 페이지를 눌렀을 때는 goPage 함수를 태워서 2페이지를 누른 경우에는 11~20번째 단어, 3페이지를 누른 경우에는 21~30번째 단어 ... 이런식으로 버튼을 누르기 전에 화면은 hide, 버튼을 누른 후 화면은 show 방식으로 구현했다.

그리고 체크박스를 선택했었다면 해제를 시켜준다

 

	function goPage(page)
	{
		var firstIndex = (page*10)+1;
		var lastIndex = (page+1)*10;
		var pageButton = $(".paginate_button");

		if(pageButton.hasClass("active")&&pageButton.hasClass("on")){
			pageButton.removeClass("active");
			pageButton.removeClass("on");
		}
		for(c=1 ; c<=list ; c++){
			if($("#wordList"+c).css("display") != "none") $("#wordList"+c).hide();
		}
		for(d=firstIndex ; d<=lastIndex ; d++){
			$("#wordList"+d).show();
		}

		$("#page"+(page+1)).addClass("active");
		$("#page"+(page+1)).addClass("on");
		$("input[name=chkAllone]").prop("checked", false);
		$("input[name=chkIdone]").prop("checked", false);
	}

 

3. "추가" 버튼을 눌렀을때 "사용자 화면 검색 순위"에 추가하는건 마찬가지로 JQuery를 이용해서 체크박스에서 선택한 값을 읽어서 배열에 담고, append하는 원리로 구성했다

 

	function fn_chkAdd()
	{
		var userWord = $(".tac").find(".form-inline").length;
		var chkIdone = $("input[name=chkIdone]:checked");

		var chkarr = new Array();

		chkIdone.each(function(){
			chkarr.push($(this).val());
		});

		if(chkIdone.length == 0){
			alert("추가할 검색어를 선택해주세요.");
			return false;
		}
		else{
			if(userWord + chkIdone.length > 10){
				alert("검색 항목이 초과되었습니다.");
				return false;
			}
			else{
				var sortBtn = '<div class="btn-group-vertical" style="width: 20px;"><button type="button" id="upBtn" class="btn btn-primary btn-xs up" class="sort-btn"><span class="fa fa-sort-up"></span></button>';
				sortBtn += '<button type="button" id="downBtn" class="btn btn-primary btn-xs down" class="sort-btn"><span class="fa fa-sort-desc"></span></button></div>';
				$("#usrPopTable").children("tr:eq("+(userWord-1)+")").find("#sortBtn").html(sortBtn);
				for(a=1;a<=chkIdone.length;a++){
					var idIndex = getidIndex();
					var html = '';
					html += '<tr class="tac" id="usrWordForm'+idIndex+'" name="usrWordForm">';
					html += '<td class="text-c"><input type="checkbox" name="chkIdtwo" id="usrWord'+idIndex+'"></td>';
					html += '<td class="countNum" style="text-align:center;">'+(userWord+1)+'</td>';
					html += '<td style="text-align:center;"><div class="form-inline">';
					html += '<input type="text" name="usrPopWord" id="usrPopWord'+idIndex+'" maxlength="40" value="'+chkarr[a-1]+'" class="required form-control input-sm f-wd-300px" >';
					html += '</div></td>';
					html += '<td id="sortBtn" class="text-c">';
					html += sortBtn;
					html += '</td></tr>';

					$("#usrPopTable").append(html);
					userWord++;
				}
				sortBtnUpdate();
			}
		}
	}

 

getidIndex 함수를 만든 이유는 append 할 때 비어있는 자리를 찾아가게 하기위해 만들었던 함수다.

1~10까지 랜덤 함수를 돌리고 그 자리가 존재하면 그 다음 자리가 비이있기 때문에 이 원리를 이용해서 구현했었다.

 

    function getidIndex()
	{
		var len = 10;
		var userid = getRandomNumber()+1;
		var docObj = $("#usrWordForm"+userid);

		while(docObj.length != 0){
			userid = getRandomNumber()+1;
			docObj = $("#usrWordForm"+userid);
		}
		return userid;
	}

 

   	function getRandomNumber()
	{
		var num = "0123456789";
		var rnum = Math.floor(Math.random() * num.length);

		return rnum;
	}

 

sortBtnUpdate 함수는 최상단에 있는 단어는 아래로만 이동, 최하단에 있는 단어는 위로만 이동하게끔

기획해서 구현했던 함수였다

 

	function sortBtnUpdate()
	{
		var userWord = $(".tac").find(".form-inline").length;

		$("#usrPopTable").children("tr:eq(0)").find("#upBtn").remove();
		$("#usrPopTable").children("tr:eq("+(userWord-1)+")").find("#downBtn").remove();
	}

 

일단 DB 검색 순위 까지만 설명해도 이정도네.. 사용자 화면 검색 순위 구현 했던건 다음 게시물에다 정리해놔야겠다

반응형
Comments