Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

AJAX 사용하기 기본 예제

뭐 요즘은 웹에서는 기본이나 다름없이 되어버린 AJAX... 여러 사이트에서 난무하고 있는 관계로 이런 인터페이스에 대한 눈은 높아졌지만 난 아직 잘 다룰 줄을 모른다 이거지...
 
어쨌든 요즘은 자바스크립트랑 자바스크립트 라이브러리에 꽤나 흥미가 가고 있고 그중에서 AJAX는 거진 필수적이란 말이지... 빨리 공부해야 겠다... 이걸 왠만큼 다루기 시작하면 꽤나 재미날것 같다.


// AJAX Request Side
function requestTagList(tagName) {
    var url = '/ajaxfile.asp';

    var myAjax = new Ajax.Request(url,
        {
            method: 'post',
            parameters: {v:tagName},
            onSuccess: responseTagList,
            onFailure: function() { alert('HTML을 받아오지 못했습니다.');}
        }
    );
}

function responseTagList(reqResult) {
    var dataobj = decodeURIComponent(reqResult.responseText);
    $('div1').innerHTML = dataobj;
}

물론 이건 prototype.js를 사용한 AJAX이다. 여태까지 올리던건 그래두 내가 어느정도는 이해하고 있었는데 AJAX는 현재 거의 이해를 못하고 있기 때문에... 사용은 해야겠고 해서 prototype.js를 사용했다. 프로토타입을 사용하지 않으면 이 코드가 거진 3-4배의 불량으로 늘어난다. 프로토타입의 위대함을 새삼 느끼고 있다.

당연히 이걸 사용하기 위해서는
<script type="text/javascript" src="prototype.js"></script>
프로토타입을 불러들여야 하고 위의 코드는 당연히 javascript니까 스크립트 태그로 묶여야지....

먼가 엄청난듯 하지만 막상 보고 있으면 구조는 그리 복잡하지 않다.(prototype.js덕분에...)

Ajax.Request만들어 주고 Response할 URL적어주고 그 다음에 method는 AJAX에서의 post와 get의 차이는 아직 잘 모르겠다. 파라미터 필요하면 넘겨주고 필요없으면 ''하면 되고 그 다음은 이벤트 인데 onSuccess는 AJAX통신이 성공했을때 발생하고 onFailure는 실패했을때 발생한다. 그리고 여기선 안썼지만 onComplete는 AJAX통신이 성공하든지 말든지 일단 끝나면 발생한다.

이벤트에 해당하는 Function은 onFailure같은 방식으로 직접 써주어도 되고 onSuccess처럼 따로 Function을 정의하고 호출만 해도 된다.


// AJAX Response Side
<%
    tagSearch = request("v")

    sql = " SELECT bbs_num, bbs_title, bbs_writer "
    sql = sql & " FROM table "

    rs.open sql,con,3,1

    tagList = "<table border='1'><thead><tr>"
    tagList = tagList & "<th scope='col'>제목</th><th scope='col'>작성자</th><th scope='col'>작성일</th></tr></thead>"

    Do while rs.EOF=false
        bbsNum    = rs("bbs_num")
        cgName    = rs("cg_name")
        bbsTitle  = rs("bbs_title")
        bbsWriter = rs("bbs_writer")
        bbsDate   = left(rs("bbs_date"), 10)

        tagList = tagList & "<tbody><tr><td class='listSubject'>" & bbsTitle & "</td>"
        tagList = tagList & "<td nowrap='nowrap' class='listWriter'>" & bbsWriter & "</td></tr>"

        rs.MoveNext
    loop

    tagList = tagList & "</tbody></table>"

    rs.Close : con.close : Set con=nothing

    response.Write jEncode(tagList)
%>

<script language="javascript" runat="server">
    function jEncode(s)
    {
        return encodeURIComponent(s);
    }
</script>

Response쪽은 오히려 간단하다. 여기선 ASP로 구현이 되어 있는데 머 이쪽은 평소짜던 코드랑 그다지 다른게 없으므로 그냥 봐도 다른쪽 언어로 구현하는데도 큰 문제가 없을 것같다.

Response.Write로 페이지에 찍어내면 그냥 그걸 Request쪽에서 받을 수 있다. 필요한걸 만들고 찍어내면 된다. 머 XML이나 JSON을 이용할 수도 있지만 어쨌든 그냥 여기선 간단히 보았을 때....

넘기는 쪽에서 parameters: {v:tagName} 로 넘겼으므로 받는 쪽에서도 v라는 이름으로 파라미터를 받는다. 그걸 받아서 필요한 처리를 하고 코드를 만들던지 값만 넘겨서 받은 쪽에서 처리하던지 해서 필요한걸 마지막에 response.Write해주면 된다.


어쨌든 이렇게 하면 AJAX로 비동기 통신을 할 수 있다.

여기서 설명을 안한것 이 있는데 기본적으로 AJAX는 UTF-8이라고 한다. 그렇기 때문에 그냥 하면 영문은 상관없지만 한글의 경우는 다 깨져버리고 만다 그래서 그걸 해결하기 위해서 인코딩/디코딩과정을 거쳐야 한다.

Response쪽에서는 자바스크립트 메서드를 사용하기 위해서 자바스크립트에 runat="server"해서 자바스크립트를 서버사이드로 돌려서 encodeURIComponent()메서드를 사용해서 반환할 스트링을 인코딩해주고 Request쪽에서는 decodeURIComponent()메서드를 이용해서 디코딩해서 받으면 한글 문제를 해결할 수 있다.

그리고 한글 문제를 해결하기 위해서 중요한 또 한가지.... Response쪽 asp파일은 반드시 UTF-8로 저장이 외어야 한다. 페이지에 UTF-8로 캐릭터셋을 정의하라는 것이 아니라 파일을 UTF-8로 저장을 해주어야 한다. 에디터에 따라 안그런것들도 있지만 대개의 에디터들은 파일을 저장하는 인코딩타입을 정해주는 옵션이 있다. 그에 따라 UTF-8로 저장을 해주어야 한다.
2007/10/22 01:05 2007/10/22 01:05

트리구조에서 자신의 자식 또는 부모 찾기

처음 계층형 게시판을 접했을 때부터 나의 고민은 이거였다. 자신의 자식 또는 부모 찾기....

물론 이건 물론 만드는 사람의 정책에 따라 결정되는 문제이긴 한데 내가 생각하기에는 상당히 필요한 거였고 이게 또 계층형 혹은 트리구조는 여기저기에서 상당히 많이 필요한 것이기 때문에 자주 부딪히는 문제거리였다.

게시판의 계층형 글
(예시가 상당히 허접스럽긴 하지만 대충 이해해주고 봐주길 바란다.)

계층형 게시판에서 흔히 볼수 있는 구조이고 보통 계층형을 구현하면 무한계층이기 때문에 저런식의 구조로 맘껏 할 수 있다. 문제는 여기서 삭제를 할때 생긴다.(혹은 트리메뉴에서 통째로 이동을 시킬 때....)

"테스트 2"를 삭제할 때 하위메뉴가 달렸으면 삭제를 못하게 할 수도 있고 테스트2를 삭제하면 그하위에 달린 것도 삭제되게 할 수도 있다. 어쨌든 자신의 상위관계랑은 묶여다녀야 한다. 상위만 사라지고 하위만 남는 경우는 당연히 생기면 안된다.

요즘은 Flag를 하나 두고도 하긴 하지만 기본적으로 계층형일때는 3개의 플래그를 둔다. Group, Refer, Step이렇게 3개인데 꽤나 고민했었는데 이 3개로 자신의 하위를 골라내기가 어렵더란 말이지. 여기서 자신의 하위란 것은 "테스트 2"를 골랐을때 4,5는 나오지 않고 3만 골라낼 수 있어야 한다는거지.

이게 딱 필요한 상황이 생겼는데 동기인 J녀석이 해결해냈다. 먼가 깔끔하진 않은것 같지만 어쨌든 돌아가긴 잘 돌아간다. 오랫동안 고민하던건데 해결되서 기쁘다.. ㅎㅎ 현재 ASP를 하고 있기 때문에 예제가 ASP소스이다.. ㅎ


' 부모 찾기
do while bbsNum <> ""

    sql =       " SELECT TOP 1 bbsNum FROM board_table "
    sql = sql & " WHERE bbs_step < (SELECT bbs_step FROM board_table WHERE bbsNum="& bbsNum &")"
    sql = sql & " AND bbs_level = (SELECT bbs_level FROM board_table WHERE bbsNum="& bbsNum &") - 1"
    sql = sql & " AND bbs_group = (SELECT bbs_group FROM board_table WHERE bbsNum="& bbsNum &")"
    sql = sql & " ORDER BY bbs_step DESC "

    rs.open sql,con,3,1

    if rs.eof=false then
        bbsNum = rs(0)
        bbsNum = bbsNum & ""
    else                  '//부모가 없으면
        BGRPT_IDNO = ""   '//루프 끝냄
    end if

    rs.close
loop

어째보면 좀 무식해 보이긴 하지만 우리수준에서는 이정도 밖에 할 수 없었다. 어쨌든 삭제든 머든 하려고 할 때 현재의 bbsNum은 가지고 있을테고 그걸 가지고 step는 작고 level은 -1 작고 group가 같은 걸 찾아서 있으면 다시 bbsNum에 넣어서 loop를 돌리고 없으면 bbsNum에 공백을 넣어서 loop를 끝내는 구조이다.

먼가 더 좋은 해결책이 있을것 같기도 하지만...


'자식 찾기
sql =       " SELECT * FROM board_table "
sql = sql & " WHERE bbs_step >= (SELECT bbs_step FROM board_table WHERE bbsNum="& bbsNum &")"
sql = sql & " AND bbs_group = (SELECT bbs_group FROM board_table WHERE bbsNum="& bbsNum &")"
sql = sql & " ORDER BY bbs_step "

rs.open sql,con,3,1

if rs.eof=false then level = rs("bbs_level")

isStart = true

do while rs.eof=false
    bbsNum = rs("bbsNum")
    '//레벨이 크면 자식이다.
    if level < rs("bbs_level") or isStart=true then   
        '//여기서 먼가 액션을.....
        isStart = false
        rs.MoveNext
    '//레벨같거나 작은 거 만나면 루프멈춤
    else               
        Exit do
    end if
loop

자식을 찾을때도 물론 좀 무식한 방법이다. 같은 group의 step가 크거나 같은 목록을 가져와서 자신의 level을 기억해 둔 다음에 loop를 돌리면서 각 글마다 level을 비교해서 자식인지 아닌지를 비교하는 것이다.

왠만한건 돌려봤는데 큰 무리는 없이 잘 돌아갔다. 근데 지금 소스를 좀 보고 있자니 무한계층수준까지 죽~ 올라갔을대도 과연 잘 돌아갈지는 잘 모르겠네... ㅎㅎㅎㅎ 개량하다보면 좀더 좋은게 나타나겠지...
2007/10/22 00:08 2007/10/22 00:08