Gatherer – Online Collaboration tool 만들기 by 13th warrior (2)
두번째 강좌
Flex Builder를 기반으로 진행하겠습니다.
https://svn.xp-dev.com/svn/icksishu_13thwarrior/testBoard 의 프로젝트를 checkout하셨죠? 그리고 testBoard 의 프로젝트를 import하셨겠지요? 아직 안하셨으면 svn checkout 하시고, import 하시기 바랍니다. FlexBuilder 3부터는 프로젝트를 통채로 import할 수 있어서 편해졌습니다.
testBoard.mxml 파일부터 시작합니다. 경로는 PROJECT_ROOT\testBoard\src\testBoard.mxml 입니다. testBoard.mxml는 gatherer의 첫 화면이고 DB를 연결하여 다른 클래스에 값을 셋팅하는 역할을 담당합니다. 구현에서 눈여겨 볼 점은 State로 구성했다는 것입니다.
선언부의 소스 먼저 볼까요?
<mx:states> <mx:State name="room"> <mx:AddChild position="lastChild"> <mx:Label text="Gathering v.1.0 by 13th Warrior" bottom="10" right="10" fontSize="12" fontWeight="bold"/> </mx:AddChild> <mx:AddChild position="lastChild"> <ns2:whiteboardPanel x="10" y="21" id="board" width="600" height="737"> </ns2:whiteboardPanel> </mx:AddChild> <mx:AddChild position="lastChild"> <ns1:camPanel x="618" y="21" width="396" height="319" id="camPanel"> </ns1:camPanel> </mx:AddChild> <mx:SetStyle name="backgroundColor" value="#A990B8"/> <mx:AddChild position="lastChild"> <ns1:chatPanel x="618" y="348" width="396" height="410" id="chatPanel"> </ns1:chatPanel> </mx:AddChild> <mx:SetProperty name="width" value="1067"/> <mx:SetProperty name="height" value="776"/> </mx:State> <mx:State name="login"> <mx:AddChild position="lastChild"> <mx:Label text="Gathering v.1.0 by 13th Warrior" bottom="10" right="10" fontSize="12" fontWeight="bold"/> </mx:AddChild> <mx:AddChild position="lastChild"> <ns1:LoginPanel id="loginPanel" creationComplete="init()" horizontalCenter="0" verticalCenter="0" height="172"> </ns1:LoginPanel> </mx:AddChild> <mx:AddChild position="lastChild"> <ns1:RoomList id="roomList" visible="false" creationComplete="roomConnection()" horizontalCenter="0" verticalCenter="0"> </ns1:RoomList> </mx:AddChild> <mx:SetStyle name="backgroundColor" value="#A790B8"/> <mx:SetStyle name="fontStyle" value="normal"/> </mx:State> </mx:states>
room과 login 두 개의 state를 선언하고 몇가지 화면을 담습니다. mx:Application 태그에서 login state를 디폴트로 선언했구요. login -> roomlist -> room(board, cam, chat) 으로 넘어갑니다. 매번 유저 이벤트로 동작시켜야 하죠.
login의 동작을 보자면
private function init():void{ trace("init"); con = new Connection("192.168.10.99", 3306, "root", "mysql","board"); con.addEventListener(Event.CONNECT, handleConnected); con.connect("euckr"); loginPanel.idInputArea.addEventListener(FocusEvent.FOCUS_IN, addEvent); }
DB 연결하고 id와 password를 입력할 수 있는 이벤트 리스너를 달아주는 것이 끝입니다. 그러면 동작은 loginPanel로 넘어가게 되지요. DB 커넥션은 asSql이라는 swc 라이브러리를 사용했습니다. 프로젝트 URL은 http://code.google.com/p/assql 이고 라이센스는 MPL입니다. DB 커넥션과 핸들링을 쉽게 해주는 라이브러리이죠.
이제 LoginPanel.mxml을 살펴보죠.
경로는 PROJECT_ROOT\src\extenders\panel\LoginPanel.mxml입니다. component 선언부는 그저 위치와 이벤트 핸들러고 별다른 내용은 없습니다. 여기서도 asSql을 사용했는데요, asSql의 특징은 보통 자바나 C/C++에서 DB 커넥션을 열고 ResultSet 객체를 받아서 핸들링을 하는 것과는 달리 커넥션 후 쿼리에 대한 결과를 MySqlToken 클래스 인스턴스로 받아서 그에 대한 핸들링을 비동기 이벤트 핸들러로 수행한다는 겁니다. LoginPanel.mxml 소스를 보면 로그인 버튼 이벤트 핸들러로 clickConBtn()이 있고 토큰의 핸들러로 selectResult()를 설정합니다. selectResult()는ResultSet을 얻어서 loginResult()가 수행되도록 하죠.
private function clickConBtn():void{ if(idInputArea.text == ""){ Alert.show("ID를 입력해 주세요."); } else{ userID = idInputArea.text; var query:String = 'SELECT pw from members where id =\''+userID+'\''; var token:MySqlToken = st.executeQuery(query); token.addResponder(new AsyncResponder(selectResult, fault)); } } private function selectResult(data:Object, token:Object):void{ var rs:ResultSet = ResultSet(data); dataAC = rs.getRows(); loginResult(); } private function loginResult():void{ if(dataAC.length > 0){ if((dataAC[0].pw == null)||(dataAC[0].pw != pwInputArea.text)) { this.removeEventListener(KeyboardEvent.KEY_UP, enterHandler); Alert.show("Login Fail"); }else{ this.removeEventListener(KeyboardEvent.KEY_UP, enterHandler); Alert.show("Login Success"); isLogin = true; } } else{ this.removeEventListener(KeyboardEvent.KEY_UP, enterHandler); Alert.show("Login Fail"); } }
ResultSet의 핸들링이 비동기로 이뤄지기 때문에 로그인이되었다 안되었다라는 판단을 바로 해서는 안되며 비동기로 동작하는 메소드에서 값을 설정한 후 다른 이벤트 핸들러가 동작하도록 하는 것이 좋습니다. LoginPanel.mxml의 동작이 끝나면 testBoard.mxml의 updateComplete 이벤트에 의해 testBoard.updateState()가 호출됩니다. 그러면 다시 testBoard.mxml로 가서 login state 다음인 room state가 실행되겠죠. state가 넘어가는 것을 구현하는 것은 쉽습니다. 선언한 state를 바꿔주기만 하면 되거든요. updateState()를 보면 쉽게 알 수 있습니다.
private function updateState():void{ if(loginPanel.getLogin() == true) { userID = loginPanel.getID(); roomName = roomList.getRoomName(); loginPanel.setVisible(false); roomList.setVisible(true); roomList.setUserID(userID); //roomList.findEmptyRoom(); if(roomList.getIsRoom() == true) { roomList.setVisible(false); currentState = "room"; board.setUserID(userID); camPanel.setUserID(userID); chatPanel.setUserID(userID); board.setRoomName(roomName); camPanel.setRoomName(roomName); chatPanel.setRoomName(roomName); } } }
이번 강좌는 여기서 끝내고 다음 강좌에서는 실제 사용하는 컨트롤들 중 chatPanel부터 살펴보도록 하겠습니다.
P.S 타겟을 Flex에 어느정도 능숙하다고 생각하다보니 너무 건성건성 하는 것이 아닌가 싶네요. 질문이 있으시면 언제든 답글을 달아놓으시면 성심성의껏 아는 한도에서 설명드리겠습니다.





















