이건뭐 설명이 필요없네요.
아까 전시간에 만든 WebService를 호출해봅시다.

전시간에 만들어 놓은 웹서비스
http://mudchobo.tomeii.com/tt/328

플렉스빌더를 실행합니다.
Air로 프로젝트를 하나 만듭니다.
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="vertical">
   
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
           
            private function callWebService():void
            {
                helloWebService.sayHello(input.text);
            }
           
            private function resultHandler(event:ResultEvent):void
            {
                Alert.show(event.result.toString());   
            }
           
            private function faultHandler(event:FaultEvent):void
            {
                Alert.show(event.fault.message);   
            }
        ]]>
    </mx:Script>
   
    <mx:WebService id="helloWebService"
        wsdl="http://localhost:9080/HelloWebApp/HelloService?WSDL"
        useProxy="false"
        result="resultHandler(event)"
        fault="faultHandler(event)" />
       
    <mx:TextInput id="input" enter="callWebService()"/>
    <mx:Button id="button" label="Button" click="callWebService()"/>
       
</mx:WindowedApplication>
[/code]
wsdl부분에서만 주소를 WSDL파일 주소로 써주세요.
그 외에는 RemoteObject나 HTTPService와 같이 같은 방식으로 해주면 돼요.

다음엔 RESTful이 뭔지 좀 알아봐야겠습니다.

 
Posted by 머드초보
,
 
두번째글입니다.
프로그램 설치 및 체험(?)은 아래의 INSTALL NOW을 클릭해주세요 ^^

Alternative content

Get Adobe Flash player


이제 air프로젝트를 하나 생성합니다.
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="vertical" width="300" height="300"
    horizontalAlign="center" verticalAlign="middle"
    verticalScrollPolicy="off" horizontalScrollPolicy="off">
   
    <mx:Script>
        <![CDATA[
            import flash.net.navigateToURL;
            import mx.rpc.events.FaultEvent;
            import mx.controls.Alert;
            import mx.rpc.events.ResultEvent;
            import com.mudchobo.MudchoboOAuth;
           
            private var mudchoboOAuth:MudchoboOAuth;
            private var consumerToken:String = "자신의 Consumer Token";
            private var consumerSecret:String = "자신의 Consumer Secret";
            private var requestTokenURL:String = "http://www.storyq.net/oauth/request_token";
            private var accesstokenURL:String = "http://www.storyq.net/oauth/access_token";
            private var authorizeURL:String = "http://www.storyq.net/oauth/authorize";
           
            private function login():void
            {
                // RequestToken 요청
                mudchoboOAuth = new MudchoboOAuth(consumerToken, consumerSecret);
                mudchoboOAuth.requestOAuth(new Object(), requestTokenURL, "POST",
                    requestTokenResultHandler, requestTokenFaultHandler);
                currentState = "stateRequestToken";
            }
           
            private function logout():void
            {
                mudchoboOAuth = null;
                currentState = "";   
            }
           
            private function loginConfirm():void
            {
                // AccessToken요청
                mudchoboOAuth.requestOAuth(new Object(), accesstokenURL, "POST",
                    accessTokenResultHandler, accessTokenFaultHandler);
            }
           
            private function loginCancel():void
            {
                Alert.show("로그인에 실패했습니다.");   
                currentState = "stateStart";
            }
           
            // RequestToken 요청 성공 시
            private function requestTokenResultHandler(event:ResultEvent):void
            {
                currentState = "stateLogin";
                mudchoboOAuth.parseData(event.result.toString());
                authorizeHTML.location = mudchoboOAuth.authorizeSite(authorizeURL);
            }
           
            // RequestToken 요청 실패 시
            private function requestTokenFaultHandler(event:FaultEvent):void
            {
                Alert.show(event.fault.toString() + "요청이 잘못 되었습니다.");
                currentState = "stateStart";
            }
           
            // AccessToken 요청 성공 시
            private function accessTokenResultHandler(event:ResultEvent):void
            {
                currentState = "stateShowMyQ";
                mudchoboOAuth.parseData(event.result.toString());
               
                // 스토리큐에서 자신의 큐리스트를 가져온다.
                mudchoboOAuth.requestOAuth(new Object(), "http://www.storyq.net/boxes/mine.xml", "GET",
                    getQResultHandler, getQFaultHandler);
            }
           
            // AccessToken 요청 실패 시
            private function accessTokenFaultHandler(event:FaultEvent):void
            {
                Alert.show(event.fault.toString() + "요청이 잘못 되었습니다.");
                currentState = "stateStart";
            }
           
            // 자신의 큐리스트 가져오기 요청 성공 시
            private function getQResultHandler(event:ResultEvent):void
            {
                dgQ.dataProvider = event.result.boxes.box;
            }
           
            // 자신의 큐리스트 가져오기 요청 실패 시
            private function getQFaultHandler(event:FaultEvent):void
            {
                Alert.show(event.fault.toString() + "가져오는 도중 실패했습니다.");
            }
           
            // 버튼으로 다시 요청하기
            private function clickReplyHandler():void
            {
                mudchoboOAuth.requestOAuth(new Object(), "http://www.storyq.net/boxes/mine.xml", "GET",
                    getQResultHandler, getQFaultHandler);
            }
           
            // 더블클릭 시 해당 큐로 이동
            private function doubleClickDgQ():void
            {
                if (dgQ.selectedItem.uri != null)
                {
                    navigateToURL(new URLRequest(dgQ.selectedItem.uri), "_blank");
                }   
            }
        ]]>
    </mx:Script>
   
    <mx:states>
        <mx:State name="stateStart">
            <mx:SetProperty name="width" value="300"/>
            <mx:SetProperty name="height" value="300"/>
        </mx:State>
       
        <mx:State name="stateRequestToken">
            <mx:AddChild position="lastChild">
                <mx:Label text="잠시만 기다려주세요..."/>
            </mx:AddChild>
            <mx:SetProperty target="{btnLogin}" name="enabled" value="false"/>
        </mx:State>
       
        <mx:State name="stateLogin">
            <mx:SetProperty name="width" value="1024"/>
            <mx:SetProperty name="height" value="768"/>
            <mx:AddChild position="lastChild">
                <mx:HTML width="1024" height="642" id="authorizeHTML"/>
            </mx:AddChild>
            <mx:RemoveChild target="{btnLogin}"/>
            <mx:AddChild relativeTo="{authorizeHTML}" position="before">
                <mx:HBox id="hbox1">
                    <mx:Button label="확인" click="loginConfirm()"/>
                    <mx:Button label="취소" click="loginCancel()"/>
                </mx:HBox>
            </mx:AddChild>
            <mx:AddChild relativeTo="{hbox1}" position="before">
                <mx:Text text="아래 창에서 StoryQ사이트 로그인페이지로 이동합니다. &#xa;로그인 완료 후, 확인 버튼을 클릭하주세요." height="40"/>
            </mx:AddChild>
        </mx:State>
       
        <mx:State name="stateShowMyQ">
            <mx:RemoveChild target="{btnLogin}"/>
            <mx:AddChild position="lastChild">
                <mx:Button label="로그아웃" id="btnLogout" click="logout()"/>
                <mx:Button label="다시 가져오기" id="btnReply" click="clickReplyHandler()"/>
            </mx:AddChild>
            <mx:SetProperty name="width" value="550"/>
            <mx:SetProperty name="height" value="422"/>
            <mx:AddChild position="lastChild">
                <mx:DataGrid width="522" height="328" id="dgQ"
                    doubleClickEnabled="true" doubleClick="doubleClickDgQ()">
                    <mx:columns>
                        <mx:DataGridColumn headerText="제목" dataField="title"/>
                        <mx:DataGridColumn headerText="주소" dataField="uri"/>
                    </mx:columns>
                </mx:DataGrid>
            </mx:AddChild>
        </mx:State>
       
    </mx:states>
    <mx:Button label="스토리큐에 로그인" id="btnLogin" click="login()"/>
   
</mx:WindowedApplication>
[/code]
대충만들어서 코드가 지저분합니다만-_-;
아마 알아보실 수 있을듯(응?-_-)합니다.

프로그램을 실행하면, 로그인버튼이 있는데, 로그인 버튼을 클릭하면, 위에서 말한 RequestToken절차가 실행됩니다. RequestToken을 얻어오게 되면, AIR프로그램은 자신의 브라우저를 하나 열어서 로그인 RequestToken을 파라미터로 한 Authorize사이트로 이동합니다.
여기서 사용자는 자신의 아이디로 로그인을 합니다. 로그인이 완료되면, 서버쪽에서 AccessToken을 만들어놓습니다.
로그인 후 위에 확인버튼을 클릭하게 되면, 클라이언트에서는 AccessToken절차가 시작됩니다. AccessToken을 가져온 뒤 그 해당 AccessToken을 이용해 보호된 자원에 접근하는 과정입니다.

접근해서 가져온 데이터는 자신의 큐리스트를 보여주는 겁니다.
자신의 큐들을 데이터그리드에 넣었으며, 그 데이터그리드의 해당 칼럼을 더블클릭하게 되면 해당 큐로 이동하게 됩니다. 정말 별거없네-_-;

위에 코드는 위와 같은 절차로 되어있습니다.
혹시...Oauth로 삽질하시는 분은 이 글로 도움이 되었으면 하네요 ^^

이전 글 링크 - http://mudchobo.tomeii.com/tt/323
PS. 이 짓으로 추석을 날렸습니다-_-;
 
Posted by 머드초보
,
 
우선 OAuth인증에 대해서.....
잘 모르겠지만, 오픈되어있는 인증인 듯 합니다-_-;(응?)
어쨌든, 이걸 이용해서 인증을 하고, 인증이 되었으면, 보호된 자원으로부터 접근을 할 수 있습니다.
절차는 이렇습니다.

1. RequestToken얻어오기.
우선 매쉬업애플리케이션을 등록하면, consumer key와 consumer Secret을 받게 됩니다.
이것과 requestToken요청할 수 있는 주소를 알면 RequestToken을 얻을 수 있습니다.

2. Authorize하기.
RequestToken을 가지고, 인증페이지로 가서 로그인을 합니다. 로그인이 완료되면, 서버프로바이더에서는 해당 RequestToken에 대해서 AccessToken을 준비해놨을겁니다.

3. AccessToken얻어오기.
서버프로바이더가 준비한 AccessToken을 요청합니다. 이건 consumer key, consumer secret, requestToken, requestTokenSecret, AccessToken요청할 수 있는 주소를 알면 얻어올 수 있습니다.

4. 해당 AccessToken을 이용해서 자원에 접근하기.
이 AccessToken이 있으면 해당 자원에 접근할 수 있습니다. 이 토큰으로 보호된 자원에 접근할 수 있는 것이죠.

이런 절차의 인증방식을 사용합니다. 너무 간소화했지만, 여기에 가면 자세히 설명이 있습니다.
http://aproxacs.springnote.com/pages/1279246 (aproxacs님 감사해요~)

AIR에서도 OAuth인증을 사용하는 곳에 인증을 할 수 있습니다.
사실 오픈마루가 제공하는 귓속말을 하려고 했는데, 이건 잘 안되더라구요 ㅠ 운영자님께 문의해놨습니다 ㅠ

스토리큐로 해봅시다 ^^ 이 서비스 정말 획기적인데요? OAuth때문에 처음알았습니다 ^^

여기서 사용한 라이브러리는 as3용 oauth라이브러리 http://code.google.com/p/oauth-as3/
암호화 라이브러리 http://code.google.com/p/as3crypto/ 를 사용했습니다.

아...소스코드가 너무 기네-_-;
우선 제가 만든 OAuth요청 클래스입니다.
[code]
package com.mudchobo
{
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.http.HTTPService;
   
    import org.iotashan.oauth.OAuthConsumer;
    import org.iotashan.oauth.OAuthRequest;
    import org.iotashan.oauth.OAuthSignatureMethod_HMAC_SHA1;
    import org.iotashan.oauth.OAuthToken;
   
    public class MudchoboOAuth
    {
        private var consumer_key:String;
        private var consumer_secret:String;
        private var oauth_token:String = "";
        private var oauth_token_secret:String = "";
       
        public function MudchoboOAuth(consumer_key:String, consumer_secret:String)
        {
            this.consumer_key = consumer_key;
            this.consumer_secret = consumer_secret;
        }
       
        // OAuth요청
        public function requestOAuth(params:Object, url:String, method:String,
            resultHandler:Function, faultHandler:Function):void
        {
            var consumerToken:OAuthConsumer = new OAuthConsumer(consumer_key, consumer_secret);
            var oauthToken:OAuthToken = null;
            if (oauth_token != "")
            {
                oauthToken = new OAuthToken(oauth_token, oauth_token_secret);
            }
            var request:OAuthRequest = new OAuthRequest(
                method, url, params, consumerToken, oauthToken);
            var builtUrl:String = request.buildRequest(new OAuthSignatureMethod_HMAC_SHA1());
            trace(builtUrl);
           
            var requestHTTPService:HTTPService = new HTTPService();
            requestHTTPService.url = url;
            requestHTTPService.method = method;
            requestHTTPService.addEventListener(ResultEvent.RESULT, resultHandler);
            requestHTTPService.addEventListener(FaultEvent.FAULT, faultHandler);
            requestHTTPService.send(params);
        }
       
        // Authorize를 위한 로그인 사이트  주소 리턴.
        public function authorizeSite(authrizeURL:String):String
        {
            return authrizeURL + "?oauth_token=" + oauth_token;
        }
       
        // Data파싱 후 oauthToken과 oauthTokenSecret추출
        public function parseData(data:String):void
        {
            var tokenStart:Number = data.indexOf("oauth_token");
            var tokenEnd:Number = data.indexOf("&oauth_token_secret");
            this.oauth_token = data.substring(tokenStart + 12, tokenEnd);
            this.oauth_token_secret = data.substring(tokenEnd + 20);
        }
    }
}
[/code]
메소드중에 requestOAuth메소드가 있는데, 이것은 parameter와 url, method, resultHandler, faultHandler만 지정해주면 자동으로 OAuth에 필요한 파라메터를 만들어서 요청해주는 메소드입니다.
이걸로 RequestToken, AccessToken, 그 외 보호된 자원에 접근하기 위한 요청으로 쓸 수 있습니다.

authorizeSite메소드는 로그인 해주는 사이트로 이동할 때, requestToken을 파라메터로 붙여주는 주소를 리턴해줍니다.

parseData메소드는 요청 후 리턴받은 데이터가 oauth_token=~~~~&oauth_token_secret=~~~ 라고 되어있는 것을 단순히 파싱해서 변수에 저장하는 역할을 합니다.(참고로, 오픈마루의 귓속말서비스 같은 경우 AccessToken을 요청할 때 뒤에 오픈아이디를 같이 붙여줘서 리턴값이 틀립니다. 그걸 참고해서 저걸 사용해야할 듯 싶습니다.)

글이 너무 길어져서 다음글로 패스-_-;
http://mudchobo.tomeii.com/tt/324
 
Posted by 머드초보
,
 
이거 완전 신기하네요-_-;
HTMLLoader라는 클래스가 AIR전용으로 있는데요.
HTML을 읽어와서 보여주는 역할 뿐아니라 JAVASCRIPT함수를 호출할 수 있으며(ActionScript3에서 자바스크립트 문법을 그대로 사용할 수 있는 듯 합니다-_- 아직많이 해보지는 않았지만-_-), 물론 자바스크립트 프레임워크 메소드도 호출이 가능하겠죠.

한번 해보니 잘 되네요-_-;

AIR로 프로젝트를 만들고, src폴더에 prototype-1.6.0.2.js 파일을 넣구요.
prototypetest.html파일을 아래와 같이 작성했습니다.
[code]
<?xml version="1.0" encoding="EUC-KR" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>AIR와 JAVASCRIPT(prototype)연동</title>
<script src="prototype-1.6.0.2.js" type="text/javascript"></script>
</head>
<body>
<div id="myDiv">
안녕하세요!<br />
후....추석날 뭔짓이냐..-_-;
</div>
</body>
</html>
[/code]
저기 DIV내용을 FLEX로 가져오겠습니다.
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            private var _htmlLoader:HTMLLoader;
           
            private function clickHandler():void
            {
                _htmlLoader = new HTMLLoader();
                _htmlLoader.addEventListener(Event.COMPLETE, completeHandler);
                _htmlLoader.load(new URLRequest("prototypetest.html"));
            }
           
            private function completeHandler(event:Event):void
            {
                Alert.show(_htmlLoader.window.$("myDiv").innerHTML);
            }
        ]]>
    </mx:Script>
   
    <mx:Button label="DIV내용을 프로토타입함수 사용해서 가져오기" click="clickHandler()"/>
   
</mx:WindowedApplication>
[/code]
간단합니다. HTMLLoader를 이용해서 HTML파일을 읽어와서 다 읽어오게 되면, HTMLLoader객체에 포함되어있는 window라는 property가 있는데 이것을 이용해서 prototype함수를 호출하면 됩니다.
$('') 요게 먹힙니다-_-; 아래는 결과입니다.
사용자 삽입 이미지

우선 이게 되서 제가 기쁜게...Oauth인증이.....AIR에서 안되더라구요-_-;
AIR에서도 되는군요-_-; 다시 시도를...-_-;
근데, 신기하게 JAVASCRIPT에서는 되더라구요. 그래서 왠지 JAVASCRIPT를 이용해서 인증하고 사용하면 될 것 같은 느낌이 들어서 시도해보려고 해요. 망할..Oauth-_-;

 
Posted by 머드초보
,
 
책이 나오기 까지 참 많이 힘들었죠 ^^
(에이레네님 수고하셨어요~ ^^)

이 책은 그전에 AIR가 정식 런칭하지 않은 상태에서 그전에 출간되었습니다.
그 후 AIR가 정식 출간되고 나서, 정식버전에 바뀐 내용이 수정되고, 내용이 추가되면서 책이 다시 바뀌게 되었죠.

어쨌든 이제 나오게 되어서 다행이네요 ^^
AIR에 관한 책은 옥상훈님이 쓰신 "예제로 배우는 Adobe 플렉스(개정판)"과 "Flex/AIR Bible"책이 있는데요. 이 책은 Flex와 같이 나온 책이라 순수 AIR책이라고 하기에는 뭔가 맘에 걸립니다-_-;

하지만, 이번에 나오는 AIR in Action은 순수 AIR관련된 책이므로 AIR에 대해서 완벽하게 공부하실 분은 꼭 보셨으면 합니다. AIR에서 특화된 기능을 예제로 잘 만들어서 활용하고, 설명까지 상세히 나와있어서 AIR를 처음 접하는 개발자분들이나 FLEX만 주로하는 개발자들이 봐도 전혀 손색이 없어 보이네요.

http://www.aladdin.co.kr/shop/wproduct.aspx?ISBN=8992939175
알라딘에 판매정보가 떴는데 아직 출간하지 않아서 주문할 수 없네요.

2008년 9월 23일날 출간하려나봅니다 ^^

사용자 삽입 이미지

 
Posted by 머드초보
,