예전 Flex 2~3버전에서 데이터를 다운받기 위해서는 ByteArray 형식을 특정 웹페이지에 데이터를 업로드 시키고 해당 웹페이지에서 파일다운로드 시키는 방식을 이용했다.
파일데이터를 웹프로그램에서 HTTP 헤더를 바이너리로 지정해야만 했기때문.
하지만 4버전부터는 Flex의 ByteArray를 웹페이지를 거치지 않고 직접 다운로드 가능하다.
이는 ByteArray를 FileReference의 save 함수의 인자로 직접넣는게 가능해졌기 때문이다.

이를 응용하면 Flex에서 작성된 데이터를 ByteArray 형식으로 변환해 다운로드 할 수 있다.
아래는 화면을 캡춰해서 PC로 바로 저장하는 화면이다. 

캡춰후 다운로드

화면캡춰&다운로드 버튼을 누르면 파일을 저장하는 화면이 나타난다.

 
위 화면처럼 화면캡춰, PDF저장, 이미지 편집, 사운드 파일등 ByteArray로 데이터처리하는 모든 것들을 즉시 파일로 저장가능하다.

public function saveAsImage(obj:UIComponent, name:String = ''):void {
FileReference fileReference = new FileReference();
var pngSource:BitmapData = new BitmapData (obj.width, obj.height);
pngSource.draw(obj);
var pngEncoder:PNGEncoder = new PNGEncoder();
var pngData:ByteArray = PNGEncoder.encode(pngSource); 
if(name=='') {
name = 'capture.png';
} else {
name += '.png';
}
fileReference.save(pngData, name); // 핵심
}

위는 내가 쓰는 화면캡춰 후 다운로드 하는 함수로 UIComponent와 파일 명을 인자로 주면 다운로드 하게 하는 함수다.
화면캡춰 후 as3corelib.swc 의 PNG라이브러리를 이용하는 것만 빼면 별달리 어려운 점이 없는 예제다.


 
저작자 표시 비영리 변경 금지
신고

EIS - Flex 개발 후기 및 팁

컴글 2011.07.08 15:26 posted by 배제군
이번 D사의 EIS - Flex 개발하고 느낀 후기 및 팁.

개발환경 : Flex4.1 SDK with Flash Builder4, SAP, WebService, for MDXQuery

 - 생각만큼 이벤트가 잘 먹히진 않는다 -
마우스 클릭 이벤트에서 동작하는 코드들이 제대로 돌아가지 않는다.
확인된 상황은 CPU에 부하가 많이 걸리는 상황이였고 callLater 를 걸어도 마찬가지. -0-
처리한 방식은 Timer 로 300밀리초 정도의 이벤트를 발생시켜 이벤트 처리 함수에서 동작하게 만들었다.

 - 모듈의 메모리 해제는 역시나 멍청한 짓이다 - 
각 페이지는 모듈로 만들었지만 멍청한 FLEX 는 역시나 메모리를 해제 시켜주지 않는다. Factory 클래스로 모듈을 호출하기 때문에 한번 생성한 객체는 계속 가지고 있고 재 호출시 이미 만들어진 객체를 리턴하고 addChild 시키는 방식을 사용했다. 페이지가 50페이지 정도라 그런지 2시간의 검증시간동안에도 큰 문제 없이 모든 페이지를 열어도 잘 소화해주었다.

 - 각 페이지 모듈은 Optimizer 하지 않음 -
프로젝트 관리에서 모듈을 메인 MXML에 옵티마이져를 하지 않았다. 빌드시간 너무 길어~!
뭐 상황에 따라 틀리기 때문. 참고
( http://sites.google.com/site/koreanflexdoc/4-0/usingflashbuilder/ws6f97d7caa66ef6eb1e63e3d11b6c4d0d21-7fdd/ws6f97d7caa66ef6eb1e63e3d11b6c4cffa4-7ff1 )

 - Webservice 에 http 인증이 있을때 잘 되지 않는다. -
WSDL 접근시 Base64로 인증코드를 헤더에 넣었지만 Fillder 로 확인해도 헤더에 바로 집어 넣어주지 않았다.(버그인듯) 해결한 방법은 WSDL을 파일로 저장하고 WSDL을 읽어 서비스호출을 했다. 이때는 HTTP 인증이 아주 잘 되었다. ㅡㅡ

 - Webservice 호출시 플렉스 자체 파서는 오류를 내 뿜는다. -
* Error #1085: 요소 유형 "Tuple"은(는) 일치하는 끝 태그 "</Tuple>"(으)로 끝나야 합니다. *
플래시빌더4(3도 안됨)에서 제공하는 Webservice 호출시 나타나는 오류다. 이 오류 말고도 Caption 도 있고 여타 XML 파싱오류가 나타난다. ㅡㅡ
XML API 자체 문제기 때문에 코드를 직접 수정할 수 없어 그냥 Object 형식으로 리턴받아 SOAP로 받은 XML을 통합적으로 사용할 수 있는 ArrayCollection 으로 변환하는 함수를 만들었다.

 - Object 객체의 프로퍼티는 입력순서를 가지지 않는다. -
아래와 같은 코드를 입력하면 콘솔에 어떤 결과가 나타날까?

var obj:Object = {'e':'1', 'd':'2', 'c':'3', 'b':'4', 'a':'5' }

for (var key:String in obj) {

trace('key='+key);

}

key=a

key=b

key=c

key=d

key=e

즉, xml 로 받은 컬럼 순서를 Object 로 넣으면 다시 가져올때의 순서를 보장받을 수 없다는 것이다. 그래서 Object 를 넣을때 Array 로 컬럼에 대한 순서정보를 입력시키는 방법으로 해결했다.

 - SAP 의 SOAP 결과의 XML은 완전 패턴이 없었다. -
딱부러지는 XML 이 없이 노드(Node)속에 노드로 있는 놈과 노드속에 속성(Attribute)로 있는 놈도 있고 컬럼명의 목록이 다중행으로 나오는 놈도 있다. ㅡㅡ;; 컬럼명이 없는 놈도 있고 이중인 놈도 있고.. OTL... 해결한 방법은 컬럼명이 없는 놈은 header0~숫자 형식으로 무조건 지정받게 했다. 그리고 컬럼명이 1행이상인 것들은 언더바(_)로 구분지어 컬럼명을 바꾸었고  '합계_매출' '합계_금액' 이렇게 입력된 컬럼명은
 합계
 매출 금액 
처럼 그룹헤더 컬럼을 자동생성되게 만들었다.
그리고 컬럼명이 없어 header0과 같이 만든 컬럼의 제목열은 속성을 Object 로 받아 제목, 길이 등 컬럼속성을 추가 할 수 있게 해서 데이터와 제목열을 구분했다.
결과적으로 특이한 DataGrid가 아닌 이상은 데이터만 잘주어지면 컬럼태그를 직접쳐서 넣지 않았기 때문에 자동으로 잘 보여졌다.

 - 동기, 비동기 두가지 방식으로 구현 - 
Webservice 태그에 concurrency 를  single 로 하고 동기방식으로 처리해서 여러 질의를 순차적으로 받게 한 것과 multiple 로 지정하고 비동기방식으로 처리하는 2가지 방식으로 만들었다. 동기방식은 최초 데이터(처음 전송한 질의)가 매우 빠르게 보이기 때문에 시각상으로는 매우 빠르게 느껴지나 전체 시간으로 보면 느리고 비동기방식은 한꺼번에 전송하나 데이터 처리시점에 많은 CPU 부하가 걸려 버벅일 수 있다는 점이 있다. 최종적으로 선택한건 역시 비동기 동시질의! (한.. 1년 후에 보면.. 쩝)

 -  개념적으로 C언어에서 말하는 포인터를 알아야 데이터 가공이 용이하다. -
이미 난 XML을 공통적인 ArrayCollection 으로 받아와서 DataGrid의 DataProvider 에 넣어 사용하게 했다. 그런데 보여지는 형식을 다르게 보여달라고 하면? 프로젝트에 따라 다르겠지만 EIS에서는 보여주는 데이터가 최종이기 때문에 나의 경우 오리지널데이터를 가공했다.
예를들면 MDXQuery 에서 20110606으로 넘어 올때 2011.06.06으로 보이게 해달라고 하면 여타 아이템렌더러를 사용할 수 있지만 EIS에서는 2011.06.06이 최종이기때문에 데이터 자체를 2011.06.06으로 변경했다. 이렇게 변경할때 포인터 개념을 알면 쉽게 변경할 수 있다.

var ac:ArrayCollection = new ArrayCollection([

{'e':'1', 'd':'2', 'c':'20110606', 'b':'4', 'a':'5' },

{'e':'11', 'd':'22', 'c':'20110707', 'b':'44', 'a':'55' }

]);

for each(var obj:Object in ac) {
// obj 는 ac객체 내부 포인터이기 때문에 ac의 내부와 동일한 주소를 같는다.

obj['c'] = obj['c'].substr(0, 4)+'.'+obj['c'].substr(4, 2)+'.'+obj['c'].substr(6, 2);

}


trace('0번 c날짜='+ac[0]['c']);

trace('1번 c날짜='+ac[1]['c']);

결과
0번 c날짜=2011.06.06

1번 c날짜=2011.07.07

즉, 모든 데이터를 새로 작성할 필요 없이 루프를 돌며 데이터를 가공할 수 있다.
단, 반대로 ac객체와 별도로 Object값을 꺼낸후 사용할려면 ObjectUtil.copy 를 참고하면 포인터가 아닌 복사한 별도의 객체를 얻을 수 있다.

 - Object 에서 프로퍼티를 빼고 싶을때는 delete를 사용해라. -

var obj:Object = {'e':'1', 'd':'2', 'c':'3', 'b':'4', 'a':'5' }

delete obj['c']; ( or obj.c )
의 결과는
obj = {'e':'1', 'd':'2', 'b':'4', 'a':'5' }
가 된다.

이건 모르면 좀 골치가 아프다. ㄷㄷ;;

 - 엑셀형식, 화면캡춰, PDF 다운로드는 fileReference로 바로 다운 가능하다. -
 fileReference.save(데이터, 파일명) 으로 별도의 웹페이지에 접근할 필요없이 다운로드 가능하다. flex3 만 알던 나는 몰랐다능.. ㅡㅡ

  - 엑셀 다운로드는 DataGrid의 IViewCursor 를 사용하는 방식을 이용했다. -
IViewCursor는 DataGrid에 나오는 labelFunction 이나 DataProviderRender 와 같은 아이템렌더러까지 적용된 값을 가져오기 때문이다. 보통 공개된 HTML에서 위에 header0~숫자 형식와 '합계_금액' 형식의 colspan, rowspan의 구분도 처리 할 수 있었기 때문에 HTML 도 똑같은 머지가 되어 다운로드하게 만들었다.

 - 템플릿 컴포넌트와 싱글톤 클래스의 이용 -
판넬과 같은 창영역은 템플릿 컴포넌트로 만들고 공통으로 사용하는 서비스와 MDXQuery질의 같은 함수와 요소들은 싱글톤 클래스로 만들어 사용율을 최대화 했다.

 - 아이템런더러의 경우 공통요소가 아니면 태그내에 MXML로 만드는게 이롭다. -
공통적으로 사용하는 부분은 파일로 빼서 호출하게 하면 이해가 쉬운데 딱 하나의 DataGrid에 딱 하나의 컬럼에 쓰는 아이템 렌더러의 경우는 파일로 빼면 복잡하고 이해가 어려워 진다. 그냥 MXML 에 틀어 박았다. ㅡㅡ
 
= 총 평 =
개발하면서 느낀 건 왜 이리 생각만큼 잘 안 돌아가지? 하는 느낌이 제법 많이 들었다.
마우스 클릭, 웹서비스 인증이나 DataGrid에 1픽셀정도 아주 약간씩 어긋 나는 것, 머지시키고 스크롤 되면 어긋나는 것, 아이템렌더러에 화면 갱신 주기가 느려터지는 것... 넘 많다... ㅡㅡ;;
SAP는 첨이였지만 운영환경(Webservice, SAP GUI, MDXQuery등)적인 문제 보다는 Flex 버그수준의 저런 자잘한 문제에 부딪쳐 시간잡아 먹는게 대부분이였다. ㅡㅡ
이래서 계속 Flex 쓰겠나 싶기도 하지만 최종적으로는 사용자에게 만족할 만한 결과를 주는것 같다. 

  

 
신고