Creative Wrong Answer

ALL +51

일련변호를 생성 하거나 특정 자리수로 숫자 코드를 만들고자 할때 lpad , rpad 를 사용하여 자리수를 맞춘다. 


select lpad ('333' , 6, '0');  -- 결과 000333

select rpad ('333' , 6, '0');  -- 결과 333000


진수 변환이 필요한 경우 conv를 사용하여 진수 변환을 할 수 있다. 


select conv ('440' ,10,16) ; -- 1B8 : 10진수 440을 16진수로 변환

select conv ('1B8' ,16,10) ; -- 440 : 16진수 1B8을 10진수로 변환



의외로 간단한 항목이지만 여러군데에서 사용할 수 있다.


제품관리등의 항목을 만들때 제품번호를 일정한 자리수로 발급 해준다거나 하는 경우에 사용했었던걸로 기억된다. 

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 1

8년 정도 근무하던 회사가 문을 닫았다.

정확히는 회사가 전체 문을 닫은건 아니고 SI 쪽 사업을 포기했다.


SI 쪽 생태계가 큰회사들이 자회사를 만들고.. 그 자회사에서 하청을 주고 하청을 주고 하는 형태로 완전히 바뀌다 보니

중소 벤처 기업은 살아남기 점점 힘들어지는거같다.


생태계가 무너지는것 같은 느낌이다. 여전히 일은 있지만 대기업의 하청이 아니면 큰일을 따낼수가 없고..

큰일을 따낼 기회가 없으니 커질 수도 없다.


일단은 같이 일하던 후배3명과 함께 작업실을 하나 얻어서 간단한 수발주 프로그램을 개발중이다.

프리랜서와 실업자의 경계에 서서 당분간은 달려봐야 할것 같다.


올 연말은 유독 추울꺼같지만 따뜻한 봄을 위해서~



저작자 표시 비영리 동일 조건 변경 허락
신고

'Think Difficult' 카테고리의 다른 글

자유인? 실업자?  (0) 2015.12.17
안상수 의원은 누구의 대표인가?  (5) 2010.03.21
연아도 좀 쉬고 싶지 않을까?  (4) 2010.03.03

Comment 0

테이블 명세서등을 만들때 기존에 구축해놓은 데이터 베이스의 목록을 뽑아야 할 필요가 생긴다.


이때 사용하는 쿼리


SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE /* ETC */

FROM INFORMATION_SCHEMA.COLUMNS

WHERE TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql')

ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION;


Where의 not in 조건에 목록에서 빠져야하는 다른 디비가 있다면 쭉 적어주면 된다.


기본적으로 적혀있는 세개의 테이블은 기본 설정 테이블이라서 항상 적히게 된다. 



보통 칼럼을 적을때 사이즈를 같이 표시 하게 되는데 이때는


SELECT 

  TABLE_SCHEMA, 

  TABLE_NAME, 

  COLUMN_NAME, 

  CONCAT(DATA_TYPE,'(',IFNULL(CHARACTER_MAXIMUM_LENGTH,IFNULL(NUMERIC_PRECISION,'')),')') TYPE, 

  IS_NULLABLE

FROM INFORMATION_SCHEMA.COLUMNS

WHERE TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql', 'isb_stg', 'isb_prd')

ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION;


이런식으로 만들어주면 된다. 


나온 데이터를 전체 선택하고 export~

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0


인터넷에 돌아다니는 사진인데 모든 케이스에 적용되는거같다. 내경우는 디자인이나 개발쪽이겠지만.. ㅎㅎ


그동안 블로그가 뜸하긴 했었나보다.

오랬만에 로그인 하려고 했더니 휴면 계정이라고 그림보고 글씨 입력하라는 화면이 나오다니..


iBatis에서 myBatis로 마이그레이션하는 글이.. 쓰다가 말아서 임시저장된것도 있고...;;;;



요새는 개발보다는 PL 쪽 업무하면서 ER설계같은 쪽만 하다보니 아무래도 블로그에 쓸게 없어서 자주 안들어오게 되었는데...


뭔가 다른 주제로 글을 쓰는것도 괜찮을꺼같아서 뭘로 쓸지 고민중이다. 


초보 PL의 고민이라던지.. ER 설계라던지.. Workbench나 ERWin 같은 프로그램의 사용법이라던지.. 아니면 WordPress 라던지.. 

뭔가로 블로그를 살려놨으면 좋겠는데 뭐가 좋을지 고민중.. 


요새 꽂힌건 워드프레스이기는 한데.. 이걸로 글을 쓰면 뭘 써야 하나 고민도 되고.. 

이미 잘 정리된 블로그들이 많고.. 직접 다 해보고 글을 써야 하니 은근 시간을 많이 잡아먹을꺼같고.


조금만 더 생각해보고 하나씩 써봐야지.. 

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

실버라이트 4 관련책이 국내에 한권뿐이어서 보고나서 안타까움을 좀 느꼈는데.. 

MS에서 나온 정식한글 도움말 파일이 있다...;;;

 http://www.microsoft.com/downloads/ko-kr/details.aspx?FamilyID=b6127b9b-968c-46c2-8cb6-d228e017ad74 

chm 파일로 무려 80메가.. 


어도비에서는 플렉스4 도움말을 한글로 안만들어줘서 번역까지 하게 만들었는데.. 한글 도움말을 만나니 엄청 반갑네 -ㅅ-;;;

참고로 Silverlight 5 Beta 도움말은 아직 영문이다.. 정식버전이 릴리즈 되면 이것도 한글로 배포 해주면 좋을텐데.

저작자 표시 비영리 동일 조건 변경 허락
신고

'Silverlight' 카테고리의 다른 글

Silverlight 4 한글 도움말.  (0) 2011.04.22
VisualStudio 2010 한글판에 실버라이트5 설치하기  (1) 2011.04.22

Comment 0

이번에 실버라이트 프로젝트를 진행하게 되어서 실버라이트4에 대한 스터디를 하던중 5가 금방 정식 릴리즈 될듯 하니.. 5버전으로 프로젝트를 진행하는것도 테스트 해보자는 의견이 나왔다. 
Silverlight 5 Beta를 설치 하기 위해서 서비스팩1도 깔고 SilverLight Tool 5 를 받아서 설치 했으나.. 언어가 달라서 지원하지 않는다는 메시지만 나오는 문제가 발생..

구글링을 해보니.. 영문판에만 tool이 깔린다는 결론이 대부분이었다.
다른 직원에게 한글판을 삭제하고 영문판으로 새로 깔아서 실버라이트5를 올리는 것을 테스트 시켜보니 정상적으로 깔리고 프로젝트 생성 및 컴파일이 진행되는 것을 확인 하였다.

하지만 한글판에 설치하는 방법을 발견!! (하루를 이것저것 테스트 한 결과물)

테스트 환경은 윈도우7 / VisualStudio 2010 (한글) / Silverlight 4 tool / Silverlight 4 toolKit  / WCF Service가 이미 설치되어있는 상태.. 

 http://www.silverlight.net/getstarted/silverlight-5-beta/
 

실버라이트 공식사이트에 가면 다운로드 받을수 있게 되어있는 5 Beta가 크게 들어오지만 받아봐야 언어때문에 안깔린다. 

스크롤을 아래로 내려보면

 
오른쪽으로 Additional Downloads 라는 항목에 Runtime과 SDK만 따로 다운로드 받을수 있도록 되어있다.

Silverlight 5 SDK 시스템에 맞는 Runtime을 다운받아서 설치한다.

설치 완료 후에 VisualStudio 에서 새프로젝트 생성 - Silverlight 응용 프로그램을 선택하면 
 
Silverlight 5 버전이 선택된다.!!

확인을 선택하면.. 실버라이트 프로젝트 생성을 위해 툴을 받아야 한다고 알림 메시지가 뜨는데.. 이 툴은 Silverlight 4 tool 이다...

왜 이런식으로 진행되는지는 모르겠지만.. 실버라이트 4 툴을 새로 설치 하고 나면 실버라이트5 프로젝트를 생성해서 컴파일 할수 있게 된다.

 
아직은 Silverlight toolkit 5가 나오지 않은 관계로 4 프로젝트와 완벽한 호환성은 보장되지 않지만 조만간 나올듯 하니.. 미리 테스트 해보고싶은 사람들은 위 방법대로 설치 해보면 될듯 하다.

실제 프로젝트 테스트를 하면서 VisualStudio 2010 영문 버전에 설치한 기기와 한글버전에 위 방법으로 따로 설치한 기기에서 다른점이 발생하면 다시 포스팅 하겠다.

모두 성공하시길~ 

PS. 하드 용량이 넉넉하고 영문판도 따로 가지고 있는 분은 한글판을 언인스톨 하지 않고 그냥 영문판을 깔아버리면 옵션에서 한글 영문 선택할 수 있게 되고 Silverlight 5 tool 도 그냥 설치 된다.  이것도 참고!
 
저작자 표시 비영리 동일 조건 변경 허락
신고

'Silverlight' 카테고리의 다른 글

Silverlight 4 한글 도움말.  (0) 2011.04.22
VisualStudio 2010 한글판에 실버라이트5 설치하기  (1) 2011.04.22

Comment 1


데이터를 표시 하다보면 어쩔수 없이 버튼등으로 처리 하지 못하고 Text나 Label 등을 사용해서 보여줘야 하는 경우가 생긴다.

Text 데이터를 보여 주면서 외부 링크의 경우 htmlText에 직접 링크를 걸어주면 되지만 플렉스 내부에서 처리 해야 하는 경우에는 좀 곤란해지기도 하는데 이럴때 TextEvent로 htmlText의 링크를 체크 할수 있다.

TextEvent.LINK 와 TextEvent.TEXT_INPUT 두개밖에 없고 매우 간단하다

TextEvent () 생성자
public function TextEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false, text:String = "")

언어 버전:  ActionScript 3.0
런타임 버전:  AIR 1.0, Flash Player 9

텍스트 이벤트에 대한 정보가 포함된 Event 객체를 만듭니다. Event 객체는 매개 변수로 이벤트 리스너에 전달됩니다.

매개 변수
type:String — 이벤트 유형입니다. 이벤트 리스너는 상속된 type 속성을 통해 이 정보에 액세스할 수 있습니다. 사용할 수 있는 값은TextEvent.LINK 및 TextEvent.TEXT_INPUT입니다.
 
bubbles:Boolean (default = false) — Event 객체가 이벤트 흐름의 버블링 단계에 참여하는지 여부를 결정합니다. 이벤트 리스너는 상속된 bubbles속성을 통해 이 정보에 액세스할 수 있습니다.
 
cancelable:Boolean (default = false) — Event 객체를 취소할 수 있는지 여부를 결정합니다. 이벤트 리스너는 상속된 cancelable 속성을 통해 이 정보에 액세스할 수 있습니다.
 
text:String (default = "") — 사용자가 입력한 한 자 이상의 텍스트 문자입니다. 이벤트 리스너는 text 속성을 통해 이 정보에 액세스할 수 있습니다.


예제를 보면 첫번째 Google 링크는 외부 링크로 열리고 네이버 링크는 Flex 내부에서 처리해서 Alert을 띄운다.

[어플리케이션 스크립트소스]

private var text:TextLink;

private function init():void
{
 text = new TextLink();
 
 text.htmlText = "Google = http://google.com
Naver = http://naver.com"; text.addEventListener(TextEvent.LINK, checkLink); addChild(text); text.x = 100; text.y = 80; } private function checkLink(e:TextEvent):void { Alert.show(e.text+" 링크를 클릭했어요"); }

TextLink.as

package
{
 import flash.text.StyleSheet;
 import mx.controls.Text;

 public class TextLink extends Text
 {
  public function TextLink()
  {
   super();
  }
  
  override protected function createChildren():void
  {
   super.createChildren();
   
   var style:StyleSheet = new StyleSheet();
            style.setStyle("a:link", {color:"#0000ff", textDecoration:"underline"});
            style.setStyle("a:hover", {color:"#00ff00", textDecoration:"none"});
            style.setStyle("a:active", {color:"#0000ff", textDecoration:"underline"});
            textField.styleSheet = style;
  }
 }
}



TextLInk.as는 링크 컬러를 설정하기 위해서 Text를 상속받아서 만든 컴포넌트이다. Label, Text, TextArea, TextInput 등등 TextField를 가지고 있는 놈은 어떤것을 상속받더라도 상관없다.

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0


2010/11/02 - [Java & iBatis] - Java / iBatis에서 프로시저 호출하기
2010/11/05 - [Java & iBatis] - iBatis에서 myBatis로 개요 및 변경점

이 포스트를 읽기전에 이전글을 안읽었다면 한번 둘러보고 오는편이 좋을 것같아서 링크를 먼저 걸고 시작한다.
iBatis 에서 프로시저 호출하기의 myBatis 버전이다.

myBatis 에서 paramterMap을 더이상 사용하지 말자고 했기 때문에.. 이전처럼 프로시저를 호출하는 것은 무리가 있다.

Procedure 관련 체크해야할 변경사항은.. 일단 parameterMap이 사라진것.. 그리고 <procedure > 가 사라지고 type 으로 판단하게 된것이다.

parameterMap이 사라지고 MyBatis에서는 inlineStatement를 사용하라고 이야기 하고있다.  이것은 #{var}안에 직접 파라미터를 넣어서 사용하는 방법이다. 이방법에 따라서 이전 소스를 myBatis 버전으로 컨버팅 해보자.



iBatis 소스

<parametermap id="blParam" class="map">
<parameter property="p_latitude" jdbctype="VARCHAR" javatype="java.lang.String" mode="IN">
<parameter property="p_longitude" jdbctype="VARCHAR" javatype="java.lang.String" mode="IN">
<parameter property="p_utmx" jdbctype="DECIMAL" javatype="long" mode="OUT">
<parameter property="p_utmy" jdbctype="DECIMAL" javatype="long" mode="OUT">
</parameter></parameter></parameter></parameter></parametermap>
<procedure id="bl_to_utm" parametermap="blParam">
{call PROC_BL_TO_UTM(?,?,?,?)}
</procedure>



<procedure > 태그를 사용해서 프로시저를 정의 하고 들어오는 변수는 parameterMap에 정의해놓았다.

java 소스
Map map = new HashMap();
map.put("p_latitude",vo.getX_latitude());
map.put("p_longitude", vo.getX_longitude());
sqlMapper.update("VocIphone.bl_to_utm", map );
					
System.out.println(map.get("p_utmx").toString());
System.out.println(map.get("p_utmy").toString());


자바쪽에서는 map에 IN 타입 변수를 담아서 쿼리를 실행시키고 map의 OUT 타입 변수에 엑세스 해서 값을 가져온다.



MyBatis 소스

	{call PROC_BL_TO_UTM(#{latitude,mode=IN,jdbcType=VARCHAR},#{longitude,mode=IN,jdbcType=VARCHAR},#{utmx,mode=OUT,jdbcType=DECIMAL},#{utmy,mode=OUT,jdbcType=DECIMAL})}


statementType을 "CALLABLE"로 설정해주면 procedure를 호출하게 된다.  parameterType 에는 클래스 파일을 지정해주고 직접 파라미터 부분에 들어올 타입에 대한 세팅을 하게 된다.

vo.ProcVO.java
public class ProcVO {
	
	private String latitude = "";
	private String longitude = "";
	private String utmx = "";
	private String utmy = "";
	... 이하 getter/setter


이건 그냥 데이터를 옮기기위한 빈즈 파일

실제호출 java
ProcVO proc = new ProcVO();
proc.setLatitude("37.539421");
proc.setLongitude("127.047852");

session.update("myBatis.mappers.UserMapper.testProc", proc);

System.out.println("utmx : "+proc.getUtmx()+" utmy : "+proc.getUtmy());


자바쪽에서는 기존처럼 넘겨주면 된다. map 대신 클래스파일에 데이터를 담아주기만 하면 된다.
결과 코드 역시 자바클래스에서 getter로 받아오면 완료.

parameterMap으로 되어있는 기존의 소스들이 많다면 일일이 클래스를 만들어줘야 하기에 마이그레이션에 애로사항이 좀 있을수 있겠지만. 어차피 관리 측면에서도 빈파일로 관리하는쪽이 좋기 때문에. 이번기회에 싹 정리 하는것이 미래를 위해서는 좀더 낫지 않을까 싶다.

이전에 iBatis 에서 테스트 할때 자바빈파일로 파라미터를 매핑하는경우.. 프로시저가 정상적인 호출이 안되서 map으로 작업했던 거였는데.. iBatis가 원래 그런건지;; 내가 잘못했던 것인지 모르겠다...
정확한 답을 아시는분이 있다면 코멘트로~~~


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +6


저번 포스팅에서 iBatis 에서 myBatis로 넘어오면서 바뀐점들에 대해 적었었다.
2010/11/05 - [Java & iBatis] - iBatis에서 myBatis로 개요 및 변경점

이 포스트에서는 이전에 바뀐 것들을 바탕으로 기본 환경 설정을 확인 해본다.

프로젝트 환경 설정은 그림과 같다.


플렉스쪽이 더 있기는 하지만 그건 여기서는 중요한건 아니므로 패스 하고. Java, MyBatis 만 확인 해보자.

Configration.xml


<configuration>


<typealiases>
<typealias type="vo.UserVO" alias="User">
</typealias></typealiases>
<environments default="development">
<environment id="development">
<transactionmanager type="JDBC">
<datasource type="POOLED">
<property value="oracle.jdbc.driver.OracleDriver" name="driver"></property>
<property value="db_url" name="url"></property>
<property value="user" name="username"></property>
<property value="passwd" name="password"></property>
</datasource>
</transactionmanager></environment>
</environments>
<mappers>
<mapper resource="myBatis/mappers/UserMapper.xml">
</mapper></mappers>
</configuration>





빈즈(여기서는 플렉스와 맞추기위해서 VO로 작업했다)의 typeAlias 가 먼저 나오고 환경설정 그다음에 mapper가 나온다.  이 순서대로 넣지 않고 typeAlias를 environments 다음에 넣거나 하면 에러가 발생한다.
에러내용에 보면 순서 정의가 되어있고 그 순서에 맞춰서 넣어야 한다고 되어있다.

Description Resource Path Location Type
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,plugins?,environments?,mappers?)". Configuration.xml taskManager/WebContent/WEB-INF/classes/myBatis line 6 XML Problem

properties 에서 시작해서 mapper 까지 순서가 정해져 있는데 xml을 위에서 부터 읽어서 뒤에정의된 내용은 덮어 쓰게 되므로 설정파일에서는 미리정의 해놓은것 같다. (이전포스트에서 속성을 덮어쓰는 순서에 대해서 이야기 한적이 있다)

MyBatisManager.java

public class MyBatisManager {
	
	public static SqlSessionFactory sqlMapper = null;
	
	public static SqlSessionFactory getInstance(){
		if(sqlMapper == null) {
			try {
				String resource = "myBatis/Configuration.xml";
				Reader reader = Resources.getResourceAsReader(resource);
				sqlMapper = new SqlSessionFactoryBuilder().build(reader);
				reader.close();
				
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return sqlMapper;
	}
}


SqlSessionFactory는 어플리케이션과 같은 라이프사이클을 가지게 되므로 싱글톤으로 간단하게 구현해놓는다.
이후에 getInstance()를 호출해서 클래스의 참조를 받아오게 된다.
매니저로 구현하지 않고 그냥 java 파일의 상단에서 생성시켜도 별 상관은없다.

UserDao.java

public class UserDao {
	
	public static SqlSessionFactory sqlMapper = MyBatisManager.getInstance();
	
	public List getUserList() {
		
		List list = new ArrayList();
		
		SqlSession session = sqlMapper.openSession();
		try {
			list = session.selectList("myBatis.mappers.UserMapper.getUserList");
			
		} catch (Exception e){
			e.printStackTrace();
		} finally {
			session.close();
		}
		
		return list;
	}
}


상단에서 SqlSessionFactory 객체를 가져오고 SqlSession을 오픈하고 mapper의 네임스페이스를 호출해서 쿼리를 실행시킨다.

UserMapper.xml


<mapper namespace="myBatis.mapper.UserMapper">

<select id="getUserList" resulttype="User"> SELECT userID, name, phone, email, TO_CHAR(regdate,'YYYY-MM-DD HH24:MI') regdate, isuse, auth FROM TR_USER ORDER BY REGDATE DESC</select>
</mapper>

nameSpace가 풀 경로인것을 확인한다.  resultType에는 Configure.xml 에서 typeAlias에서 지정해놓은 shortName 으로 설정한다. 네임스페이스와 실행시킬 쿼리아이디를 합해서 UserDao.java에서 호출하게 된다.


순서를 살펴 보면..

UserDao가 실행되면서 MyBatisManager 에서 Configure.xml 파일의 설정을 참조해서 SqlSessionFactory를 생성하고 Factory에서 session을 열고 UserMapper의 쿼리를 실행시킨다.

플렉스에서 받아들이는쪽은 기존의 iBatis 설정과 같으니 패스 하기로 하고 마무리~
첨부된 소스는 위에서 설명된 파일들이다.

 src.zip


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 1


원래 마이그레이션 포스팅부터 다룰려고 했으나.. 이게 공식위키에서는 엄청 쉽게 이야기 한것과 달리 그냥 라이브러리 교체 정도로 끝나는게 아니라서 일단 바뀐 용어와 개요부터 정리를 좀 해야 할 필요성을 느꼈다.

myBatis로 바뀌면서 기본 용어들이 조금씩 차이가 나기 때문에.. 주의가 필요하다.

기존 SqlMapConfig은 Configration로 변경되었고 sqlMap은 mapper로 변경되었다. 다른 용어들이 변경된 상황이나.. 내부적으로 사용하는 것들(ex. isEqual 을 아에 if 로 바꾼거라던지)을 보면 좀더 범용적으로 알아보기 쉽게 바꿔가는 것을 목표로 가고있는 듯 하다.
익숙해지면 아무래도 코드 읽기도 만들기도 쉬울것으로 보인다.

큰 변화중 하나는 자바 애노테이션을 사용해서 xml을 사용하지 않고 모든것을 자바로만 할수 있게 되었다.
물론 Configration.xml 도 자바에서 직접 DataSource,  Environment 등을 선언해서 클래스화 시킬수 있다. xml 스트링으로 설정값등을 저장해야 한다는 것에 부담을 느꼈다면 좋은 변화라고 할수 있겠다.

주의할점은 xml로 Configure를 만들고 환경변수와 property를 클래스로도 만들었다면.. 클래스쪽이 나중에 읽어지게 되서 xml로 되어있는 세팅이 자바 클래스에서 선언해놓은것으로 덮어써지게 된다. 혼란을 줄수 있으니 한가지 방법만으로 프로젝트를 구성하는것이 좋을것이다.

그리고 Configuration configuration = new Con.... 형식으로 선언을 하고 나서는 mapper도 xml이 아니고 configuration.addMapper(UserMapper.class) 형식으로 추가 해야 하기 때문에 어느쪽으로 할것인지 확실하게 결정을 하고 나서 진행해야 한다.

네임스페이스
방식도 변경되었는데.. sqlMap 파일별로 줄여놓은 이름을 사용했다면 이제 풀경로로 사용하게 된다. 공식 설명서에서는 혼란을 줄이고 어떤것이 호출되는지 정확하게 알수 있으니 좋다라고 해놨지만 아무래도 길어지니 쓰기에 불편하기는 하다..
기존에 <sqlMap namespace="User"> 이렇게 쓰던것을
<mapper namespace="myBatis.mapper.UserMapper"> 이렇게 풀 경로로 쓰게 된다.

실제 자바쪽에서 호출할때도
list = session.selectList("myBatis.mappers.UserMapper.getUserList");

이렇게 길게 호출 하게 되는데.. 그냥 string 이라서 입력이 여간 불편하다.

이런 경우에 위에서 이야기한 자바 애노테이션 (@Select)을 사용해서 mapper 파일을 xml이 아니고 자바로 만들어놓으면 코드힌트까지 사용해서 편하게 쓸수있다.
UserMapper mapper = session.getMapper(UserMapper.class);
list = mapper.selectUserList();

권장사항은 xml 이라고 되어있었던거 같은데.. 편하기는 자바쪽이 편한 구조랄까..;;




기본 용어

SqlSessionFactory :  SqlMapClient가 SqlSessionFactory로 변경되었다. 어플리케이션과 같은 라이프사이클을 가지게 된다. 한번만 생성되면 되므로 Manager 클래스에서 싱글톤으로 구현하면 된다.

SqlSessionFactoryBuilder : 환경 값(디비 및 트랜잭션 설정등..)을 읽어와서 SqlSessionFactory 인스턴스를 만들어준다. 기존의 SqlMapClientBuilder 대신 사용된다.

String resource = "org/mybatis/example/Configuration.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMapper = new SqlSessionFactoryBuilder().build(reader);

SqlSession : SqlSessionFactory 에서 세션을 하나씩 열어서 개별 쓰레드 별로 사용한다. 세션을 열고나서 실제 쿼리를 수행하게 된다. 하나의 리퀘스트에 하나의 세션을 가지게 되고 사용후에는 꼭 닫아줘야 한다.

mapper : 기존의 sqlMap이 변경된 것이다. 실제 쿼리들이 들어있게 되고 위의 SqlSession을 열어야 호출할 수 있다. method scope를 가지게 되고 해당 메서드가 사용되고나면 사라진다. 별도로 닫거나 할 필요는 없고 SqlSession이 함께 관리 한다.
SqlSession session = sqlSessionFactory.openSession();
try {
    UserMapper mapper = session.getMapper(UserMapper.class);
    // do work
} finally {
    session.close();
}


변경되거나 추가된 속성들

기존에 조건에 따라 변하는 쿼리를 만들기 위해서 사용되던 태그들이 변경되었다. 조금더 직관적으로 바뀌었고 해당상황(Update, Select)등에 맞춰서 사용할 수 있는 태그들도 추가되었다.

parameterMap은 더이상 사용하지 않게 되었다. parameterMap과 parameterClass 대신 parameterType 하나로 사용한다.
resultMap은 여전히 남아있지만 resultClass 는 resultType 으로 변경되었다.
parameterType과 resultType에는 기본형(int, byte, .... )부터 클래스 명까지 기존처럼 사용할 수 있다.

기존에 procedure를 호출하기 위해 사용하던 <procedure>가 사라지고 statementType 속성이 생겼다. PREPARED, STATEMENT, CALLABLE 중에 하나를 선택할 수 있고 기본값은 PREPARED이다.

파라미터를 매핑하기위해서 사용하던 #var# 형태는 #{var} 로 바뀌었다. $var$ 역시 ${var} 형태로 사용하면 된다.
 
참고) #{var}와 ${var}의 차이는 prepredStatement의 파라미터로 사용할 것인가.. 그냥 String 값으로 때려박을것인가 하는 것이다. order by 같은 경우에 사용하기 위해서는 order by ${orderParam} 처럼 사용해야 한다. 이 방법을 사용하는 경우 myBatis가 자체적으로 쿼리의 적합성여부를 판단할 수 없기 때문에 사용자의 입력값을 그대로 사용하는 것보다는 개발자가 미리 정해놓은 값등으로 변경하도록 해서 정확한값이 들어올수 있도록 해야 한다.


sqlMap쪽에서 사용하던 typeAlias가 sqlMap이 바뀐 mapper 에서 사용되지 않고 Configration 파일에서 정의하도록 변경되었다.

<typeAliases>
    <typeAlias type="vo.UserVO" alias="User"/>
</typeAliases>

Configration 파일에 위의 형식처럼 Aliase를 정의하면 전체 mapper 에서 사용할 수 있다.



Dynamic Statement의 변화

<isEqual> , <isNull> 등의 구문이 <if>로 통합되었다. 이전보다는 확실히 직관적으로 쓸수 있을듯 하다.
<if test="userID != null"> 형태로 간단하게 사용할 수 있다. (스트럿츠2에서 사용하는 형태 처럼 보이는데..;;)

<dynamic > 형태로 해서 where 조건절이나 and , or 를 동적으로 만들던것이 <where>나 update에서 사용할 수 있는 <set> 등으로 변경되었다.

<select id="getUserList" resultType="User>
    SELECT * FROM TR_USER
        <where>
            <if test="isAdmin != null">
                authLevel = '1'
             </if>
          </where>
</select>

trim, foreach 태그가 새로 추가 되었다.
trim은 쿼리를 동적생성할때에 쿼리를 연결하기 위해서 컴마(,)를 사용한경우 마지막항목이 조건을 만족하지 못해서 생성된 쿼리 끝에 컴마가 붙어있다던가 하는 경우에 잘라낼 수 있다.
foreach는 반복적인 항목을 동적으로 넣을때 사용할 수 있다. ( ex. where 조건절에서 in 을 사용하는 경우)

공식홈페이지의 위키에 기존 iBatis를 myBatis로 바꿀때 확인해야 할 부분들이 있으니 꼭 참고 하자.
http://code.google.com/p/mybatis/wiki/DocUpgrade3

ps.
지금 있는것도 못하고 있는데 항상 새로운 버전이 쏟아지니 미칠꺼같다 -ㅅ-;;
Flex4도 정식으로 손대보지 못했는데 5 소식이라니.. ㅠㅠ
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +6

  • 재미있네요.. iBATIS를 안써본지 어언.... 6개월을 넘어서는거 같습니다만..
    나도 모르게 myBATIS가 나오다니요 ㅋ

    그나저나 프로필 사진은.... 너무 야윈거 아닌가요!?

    금새 홀쭉해지셨네....-ㅅ -; 모쪼록 추위 조심하시길..

    • 실물보다 더 좀 그렇게 나온거같아서 포샵이라도 할까 새로 사진을 찍어볼까 고민중이다 ㅎㅎ

      살이 좀 빠지긴 했지 운동은 안하고 -ㅅ- 짱박혀 있으니;

  • '-' 2011.03.08 14:41 신고

    담아갑니다! 감사합니다!

  • 좋은글이네요~ 잘봤습니다!

  • 희윤동모 2012.09.16 21:12 신고

    담아갑니다.. ^^ 좋은 글 감사합니다.

  • 콤콤 2013.10.02 16:47 신고

    혹시 order by ${orderParam} 이렇게 사용할 경우
    사용자가 지정한 값이 들어가게 설정해야 한다고 하셨는데
    어떤 방법이 있는지 알려주실수 있으신가요?ㅎㅎ;;




보통 자바환경에서 iBatis를 사용중이라면 log4j를 기본 로거로 많이 사용하게 되는데..
단순 자바 어플 만들면서 이것저것 추가하고 하는게 귀찮다면..

log4sql 을 사용해보자.

간단하지만 성능은 완벽!

PreparedStatement 에 파라미터가 어떻게 들어가서 실행되는지 확인 해보는 것에는 이것만큼 좋은게 없는것 같다.. trace 에서 출력되는 쿼리를 바로 실행할수 있고 어떤것이 파라미터이고 어떤것이 statement인지 구별할수 있는 구분자도 포함되어있다.

일단 다운로드

사용법

다운로드 받은 파일의 압축을 풀면 log4sql.jar 파일이 있다.. 로그확인이 필요한 프로젝트의 라이브러리에 등록한후에 드라이버 경로를 바꿔준다.

자바 내부에서 정의 했다면 String oracleDriver = "oracle.jdbc.driver.OracleDriver"; 형식으로 되어있을꺼고
iBatis를 사용한다면 <property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver"/> 이런식으로 컨피그 xml에 정의되어있을것이다.

이 경로를 'core.log.jdbc.driver.OracleDriver' 이렇게만 바꿔주면 끝..

별도의 설정을 할 수 있게 압축 파일 내부에 log4sql_conf.jsp 파일이 있어서 웹프로젝트일때는 동적으로 설정을 바꿀수 있도록 제공하지만 로그만 보기 위해서는 드라이버만 바꿔주면.. 쿼리 관련 로그들이 전부 출력된다.

세부 설정에서 내가 개발중인 패키지만 등록해서 해당 패키지에서 나오는 로그만 출력되도록 설정할수도 있고. SQL의 순수 실행시간만을 계산해주기 때문에 쿼리 자체의 퍼포먼스 테스트에도 유용하다.

MSSQL, Oracle, Cubrid, PostgreSql, Infomix 등등.. 현존하는 거의 모든 디비를 지원하고.. 비동기 모드도 지원한다.. 

참고]  http://log4sql.sourceforge.net/index_kr.html
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0



아이바티스가 3으로 버전업 되면서 구글그룹으로 합류하고 이름이 myBatis로 변경되었다.
공식 홈페이지도 http://www.mybatis.org/ 로 변경되었고.. 2010년 8 월에 3.02 버전이 나왔다.
이전에 DTD가 http://www.ibatis.com 으로 되어있어서 에러가 난다면.. http://apache.ibatis.com 으로 변경하면 된다고 한다.

기존 버전사용자의 마이그레이션은 간단하다고 하는데.. 기존에 운영하던 프로젝트를 버전업 해보고나서 포스팅 예정이다.


iBatis를 사용해서 프로시저를 호출하는 것은 다른 statement(select, update.. )를 호출하는 것처럼 간단하다..
문제는 파라미터의 세팅이다. 호출이야 <procedure> 태그만 적어주면 되는데 파라미터가 꽤나 귀찮게 하는 경우가 생긴다.

1. 자바에서 호출하는 경우

자바에서 호출하는 경우는 CallableStatement 를 사용하게 된다.

CallableStatement cstmt = conn.prepareCall("{call PROC_BL_TO_UTM(?,?,?,?)}");
cstmt.setString(1, "37.465687");
cstmt.setString(2, "127.249481");
cstmt.registerOutParameter(3, OracleTypes.FLOAT);
cstmt.registerOutParameter(4, OracleTypes.FLOAT);
cstmt.execute();
uTmx = cstmt.getFloat(3);
uTmy = cstmt.getFloat(4);

in 파라미터와 out 파라미터를 구분해서 넘겨주고 execute 시키면 가뿐하게 넘어온다.

2. iBatis에서 프로시저 호출하기

SqlMap 설정

<parameterMap class="map" id="blParam">
  <parameter property="p_latitude" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
  <parameter property="p_longitude" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
  <parameter property="p_utmx" jdbcType="DECIMAL" javaType="long" mode="OUT"/>
  <parameter property="p_utmy" jdbcType="DECIMAL" javaType="long" mode="OUT"/>
 </parameterMap>
  
 <procedure id="bl_to_utm" parameterMap="blParam">
  <![CDATA[
   {call PROC_BL_TO_UTM(?,?,?,?)}
  ]]>
 </procedure>


java 설정

Map map = new HashMap();
map.put("p_latitude",vo.getX_latitude());
map.put("p_longitude", vo.getX_longitude());
sqlMapper.update("VocIphone.bl_to_utm", map );

String utmx = map.get("p_utmx").toString();
String utmy = map.get("p_utmy").toString();


SqlMap 쪽에서 parameterMap 으로 설정해놓은 형식으로 프로시저에 전달되고 리턴은 데이터를 실어서 날렸던 맵으로 돌아온다..
sqlMapper를 실행시킬때 update / queryForObject / queryForList 를 사용할수 있으니 리턴 타입에 맞춰서 사용하면 된다.

out을 리스트로 받는 경우 resultMap을 설정해서 List 형태로도 받을수 있다.

<parameter property="result" jdbcType="ORACLECURSOR" javaType="java.sql.ResultSet" resultMap="resultParam" mode="OUT"/>

resultMap을 설정해주고 resultMap에서 property와 column이름을 설정해주고 class를 미리 만들어놓은 VO객체로 넣어주면 해당항목의 리스트로 프로시저 실행결과가 리턴된다.

3. 주의사항

sqlMap에서 프로시저를 호출할때

<procedure id="bl_to_utm" parameterMap="blParam">
   {
     call PROC_BL_TO_UTM(?,?,?,?)
    }
 </procedure>

위의 코드처럼 중괄호를 적어놓으면 에러가 난다..;; 괜히 보기 편하게 만든다고 했다가 삽질하게 된다.

파라미터의 타입

만약 프로시저의 파라미터가 Number 타입이라면.. OUT 파라미터 정의에서 Number라고 쓰면 에러가 난다.....;;;
오라클의 경우 프로시저 내부에서 Number를 BigDecimal로 변환해서 사용한다고 한다. 따라서 아래처럼 적으면 에러가 난다.

<parameter property="p_utmy" jdbcType="NUMBER" javaType="java.util.Number" mode="OUT"/>ERROR


<parameter property="p_utmy" jdbcType="DECIMAL" javaType="long" mode="OUT"/>

이런 형태로 적어줘야 정상적으로 실행된다. 이것때문에 하루를 꼬박 구글링과 삽질로 보냈다..
오라클 디비를 내가 만든것도 아니고 이런걸 어떻게 알지..-ㅅ-;;

iBatis로 할수 있는게 참 많다.. Result 를 받는 시점에서 rowHandler를 설정해서 xml 트리형태의 데이터를 한방에 가져올수도 있고... 복잡한 파라미터와 조건에 맞춘 쿼리도 쉽게 뽑아내준다..
iBatis 파이팅 -ㅅ-!?;;
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 1

  • bluebird 2011.11.22 00:06 신고

    궁금한게있습니다. 위예제에서 프로시저에서 넘어온 out 변수를 맵에 담았는데요
    자바빈즈에 프로퍼티명을줘서 자바빈즈에 담기게 할수는 없나요?

    <parameterMap class="패키지명.자바빈즈" id="blParam">
    <parameter property="빈즈 프로퍼티명" jdbcType="DECIMAL" javaType="long" mode="OUT"/>

    이런식으로 작성했을때 프로시저 호출은되도 out변수에 담긴값이 빈즈의 프로퍼티에 세팅이
    안되더라구요;;


플렉스에서 팝업에 관해서 가장 많이 나오는 질문중 하나가 팝업을 띄울때 어플리케이션의 데이터를 보내고 싶다거나 팝업이 닫힐때 데이터를 받아서 특정 함수를 실행시키고 싶다거나 하는 것이다.

이전에 쓴글 2010/02/17 - [Flex] - 커스텀이벤트 (Custom Event) 만들기 / 사용하기 를 보면 어느정도 알수 있지만 정확하게 팝업을 위해서 쓴 글이 아니기 때문에 실제 사용에 힘들어 하는 사람들을 보게 된다.

그래서 간단한 예제로 구현을 해보고자 한다.




예제를 보면 보낼 데이터에 rinn.kr 이 들어있고 팝업 띄우기를 클릭하면 팝업이 뜨면서 보낸 데이터가 보여진다.
팝업에 보낼데이터 필드에 들어있는 값이 어플리케이션에도 반영된다.

팝업으로 데이터를 보낼때에는 팝업컴포넌트의 public 변수에 그냥 값을 넘겨주기만 하면 되고. 팝업에서 데이터를 받을때에는 이벤트에 실어서 날려주면 된다.

팝업은 팝업을 띄우는 객체의 child로 취급되기 때문에 팝업에서 발생하는 이벤트를 어플리케이션에서 받을 수 있다. 기본적인 이벤트 전파만 이해 하면 사실 간단한 문제다.

워낙 간단하니 소스에 대한 설명은 생략하고 샘플 파일을 첨부하는 걸로 시마이~


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +7

플렉스의 레이아웃 컨테이너는 여러가지 종류가 있지만 가장 많이 사용되는 것은 Canvas, Box (VBox, HBox) 일것이다.

기본적으로 Canvas 는 absolute 기반으로 즉 좌표를 기반으로 절대위치를 결정해서 아이템을 배치 하게 되고 Box 계열은 vertical 이나 horozontal 정렬 방식으로 다른 아이템들과의 위치를 판단해서 전체적인 배치를 하게 된다.

어느것이 좋냐는 아빠가 좋냐 엄마가 좋냐 정도의 문제가 될수 있으니 일단 배제 하고..
아래 그림과 같은 레이아웃을 만든다고 가정하고 간단하게 구조를 잡아보자..


클릭해서 보면 상단,하단의 위아래로 나눠진 구조에 아래쪽은 좌,우로 나눠진 형태이다.

일반적인 사이트들의 레이아웃이고 관리자화면을 꾸밀때나 게시판 형식을 만들때 자주 보게 되는 형식일 것이다. (나만 이렇게 만드는건 아니겠지 -ㅅ-;)

상단은 높이가 고정되어있고 하단은 나머지 높이를 차지 하게 된다.
하단에서는 우측은 넓이가 고정되어있고 좌측은 우측을뺀 나머지 넓이를 차지하게 된다.

이런 형태의 레이아웃을 만들기 위해서 일반적으로 생각을 할때 위아래로 배치 되어야 하니까 어플리케이션은 vertical로 레이아웃을 설정하고 상단/하단 구분을 위해서 HBox 를 두개 배치 하고 하단 HBox 내부에 다시 데이터 그리드와 패널을 배치 하는 형태가 될것이다.
만약 데이터 그리드 위쪽에 정보를 보여주거나 설명을 위한 라벨만 하나 들어갈려고 해도 하단 VBox를 추가해서 라벨과 데이터 그리드를 넣어야 한다. 몇개 안되는 구조를 위해서 컨테이너가 꽤나 많이 사용되는 것이다.

이런 방법은 예전에 HTML 페이지에서 테이블로 구조를 만들어본 경험이있는 사람들이 즐겨 쓰는 방법이다. 지금은 HTML도 div를 사용해서 적절하게 겹치지 않도록 레이아웃을 하지만.. 전에는 중첩 테이블을 이용해서 td 안에 테이블 또 td 안에 테이블 이런 형태로 레이아웃을 구성했었다.

그렇게 만들었던 경험이 저런식으로 레이아웃을 만들게 되는 것이다.

중첩 구조로 만들때의 문제점은 Flex3 컨테이너가 모든 이벤트 처리 및 스크롤 등을 전부 가지고 있는 놈이라는 거다. 이벤트는 컨테이너를 따라 계속 버블링 되고 스크롤을 사용하던 사용하지 않던 이미 내부적으로는 맹렬하게 계산해서 처리를 하고 있다.

Flex4 에서는 Group이 추가 되면서 저런 문제가 줄어들겠지만 지금 Flex3를 주력으로 사용하고 있는 입장에서는 아무래도 중첩 구조는 퍼포먼스나 이후의 구조변경을 할때에도 부담이 될 수 밖에 없다.

하지만 브라우저 사이즈에 따라서 유동적으로 변경되는 레이아웃을 좌표계를 기반으로 만들기에는 좀 불편하다.

이 포스트에서 소개 하고자 하는것은 제한 레이아웃 생성자인 constraintRowsconstraintColumns 이다.
absolute 타입의 레이아웃에서 미리 화면을 제한해서 분할 하고 그 제한된 위치를 참고해서 레이아웃을 구성할 수 있게 해준다.
constraintRows는 상하단으로 구분을 할때 사용하고 constraintColumns는 좌우측을 구분할때 사용한다.

<mx:constraintRows>
      <mx:ConstraintRow id="title" height="30"/>
     <mx:ConstraintRow id="content" height="100%"/>
</mx:constraintRows>

이 코드는 absolute 로 정의된 어플리케이션의 공간을 상단을 높이 30 으로 하단은 나머지를 사용하도록 미리 분할한다. 분할된 선은 보이지 않는다 -ㅅ-;

<mx:constraintColumns>
      <mx:ConstraintColumn id="list" width="100%"/>
      <mx:ConstraintColumn id="sideBar" width="200"/>
</mx:constraintColumns>

이 코드는 constraintColumns 를 사용하여 좌측을 200으로 우측은 나머지를 사용하도록 분할한다.


컨테이너를 사용하지 않고도 화면을 미리 분할 해놓고 가상의 선을 기준으로 좌표를 지정할 수 있게 되는 것이다.

상단 전체, 하단 전체, 좌측 전체, 우측 전체, 1,2,3,4 로 나눠진 부분공간 모두를 사용해서 원하는 곳에 아이템들을 배치 할 수 있게 된다.
또한 어플리케이션이 absolute 이므로 고정좌표를 사용해서 특정 위치에 특정 아이템을 배치 하는 것도 물론 가능하다.

분할된 가상공간의 좌표를 지정할때는 id:좌표 형식으로 지정하게 된다.
제한 좌표를 사용할때는 top, left, right, bottom 속성으로 레이아웃의 크기를 설정 해주는것이 사용하기 편하다.

예를 들어 3번 위치에 가득차게 데이터 그리드를 배치하고 오른쪽 공간과 5px 정도 떨어져서 간격을 유지 하게 하고싶다면.

<mx:DataGrid  top="content:5" left="list:5" bottom="content:5" right="list:5">

이렇게 설정한다. 상대좌표를 잡을 constraintRow나 column의 아이디를 쓰고 거기서 얼마나 떨어져야 할지를 입력한다.
위 아래는 Row를 참조하고 좌우는 Column을 참조 해서 좌표를 잡게 된다.
저런 좌표를 디자인 뷰에서 직접 입력하기는 힘들지만 완성된 레이아웃은 디자인 뷰에서도 정상적으로 보이게 되니 처음 레이아웃을 잡을때 큰 틀을 설정해놓고 내부 아이템을 세팅해 내가는 형식으로 구성하면 된다.

이 방식으로 만들게 되면 단순 레이아웃을 위한 컨테이너의 중첩을 사용하지 않아도 되기 때문에 코드를 보기에도 깔끔해지고 중첩으로 인한 부담되는 이벤트 버블링도 방지 할 수 있다.

레이아웃만을 위해서 중첩된 컨테이너를 사용하는 것은 지양하자.


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +4

  • 아도겐~!!!ㅋㅋ

  • 엥 웬 관리자의 승인입니꽈!?

    게다가 자바스크립트 오류있어요~

  • 가변형 컨테이너는 편리하지만 동시에 독이죠.
    항상 느낌이 과거 html에서 유행하던 표안에 표안에 표의 느낌으로 레이아웃을 잡아가는 분위기입니다.

    세계적으로 뭔가 그리드에 대한 꽁수가 아니라 혁신적인 컨테이너 레이아웃에 대한 개발이 필요한 시기인듯합니다.

이전 포스팅에서 환경 세팅을 위한 파일을 받고나서 벌써 시간이 꽤 흘러버렸다..
2010/02/09 - [Flex/BlazeDS / iBatis] - Flex와 BlazeDS, iBatis를 사용하기 위한 환경 설정하기 - 다운로드

환경 세팅은 됐다고 치고 -ㅅ-;
프로젝트를 만들어보자...

포스팅 타겟은 초보자인데.. 어째 좀 불성실한 느낌이 들지만 기본 톰켓환경 세팅등은 다른곳에 워낙 잘 정리되어있으니 구글님을 참고 해서 세팅 하는걸로 하고 넘어간다.

이클립스에 플렉스 플러그인으로 설치되어있고 톰켓 5.5에 BlazeDS.war 파일도 가지고 있으니 이클립스에 서버를 세팅하고 플렉스 프로젝트를 만드는 과정을 그림과 함께 친절하게 따라가보자.

1. 이클립스를 실행한다.
[그림 생략]...

2. 서버를 만들자.
기본 톰켓 서버를 사용하지 않고 이클립스에 물려서 사용한다. 간단하게 켜고 끌수 있고 상황도 바로 바로 파악할 수 있는데다가 로그도 이클립스에 찍힌다. 처음 이클립스를 사용할때 되게 신기해 했던 기억이...
이클립스를 끄면 서버도 꺼지고 버전별로 관리도 되고 암튼 편하다..


프로젝트에서 new - other 클릭


Server - Server 선택 Next


본인 pc에 깔려있는 버전 선택.. 저기 나온다고 해서 안깔려있는 서버가 돌아가는건 아니니 깔려있는걸로 선택.
회사 프로젝트 때문에 톰켓 5.5를 사용하고 있기 때문에 5.5 선택하고 Finish~


프로젝트 네비게이터에 보면 만들어진 서버가 나오게 된다. 간단한 세팅도 할 수 있지만 그런건 다른데서 보기로 하고 여기서는 일단 만들었으니 서버는 끝~

3. 실제 돌아갈 프로젝트를 만든다.

new Project 를 만들고 나오는 창을 살펴보자


어플리케이션 서버 타입을 "J2EE" 를 선택한다.


만들어놓은 서버와 같은 타입을 선택한다. 여기서는 톰켓 5.5

이전 포스트에서 받은 BlazeDS 파일의 경로를 입력한다. ContextRoot 가 aaa 로 되어있는데 저건 신경쓰지 말고 원래의 프로젝트 이름으로 나오도록 그냥 가만히 놔두자 aaa로 고쳐버리면 낭패.. 스샷용으로 만들고 있는거니 일단 고치지 말고 진행하자.


BugReport 라는 프로젝트를 생성했고 프로젝트의 구조는 위의 그림과 같다.
flex_src 는 플렉스쪽 프로젝트가 들어가야 할 폴더이고 src 는 자바 소스 파일이다. 웹컨텐츠는 빌드를 했을때 파일이 나갈 곳이고 톰켓의 루트 폴더가 된다.

4. 프로젝트를 서버에 추가 하자

 하단 퍼스펙티브에 위에서 서버를 추가 했으므로 서버탭이 보이고 현재 서버의 상태가 보일것이다.
설치된 서버를 오른클릭해서 팝업메뉴를 불러서 Add and Remove Projects 를 선택한다.

만든 프로젝트를 오른쪽으로 옮기면 현재 서버에 프로젝트가 추가된다. 이제 생성된 프로젝트를 서버환경으로 테스트가 가능하게 된것이다.
여러개의 프로젝트를 서버에 띄워놓고 테스트가 가능하다. 경로는 http://localhost:8080/프로젝트이름/ 형식이 된다.


프로젝트를 등록했으니 오른쪽에 있는 스타트 버튼을 클릭하면 톰켓 서버가 시작된다.

5. 시작해보자~

생성한 프로젝트의 메인 파일을 F11을 눌러서 실행하게 되면. 서버에서 돌릴꺼냐 플렉스 프로젝트에서 돌릴꺼냐물어보는게 나오는데 그냥 플렉스 프로젝트로 돌리는걸 선택하면 된다.
Run on Server 를 선택하면 당연히 안된다-ㅅ-;;;


이 경로로 실행이 된다면 성공~!!!!

페이지를 찾지 못한다는 404 에러가 나오면 서버가 켜져 있지 않거나 컴파일 경로가 달라서 일것이다.
혹은 서버를 시작하면서 에러가 났다거나.. 등등..

프로젝트 설정에서 Flex build Path 쪽을 살펴 보면서 뭐가 틀렸는지 확인 해보자~

모두 성공하길... -ㅅ-~

ps. BugReport 라는 프로젝트를 하나 완성 시키면서.. 아이템 랜더러와 아이템 에디터 프로젝트 레이아웃이나 이벤트 등 잡다한 걸 묶어서 한방에 다 정리 해버릴까.. 생각 중이긴 한데.. (액션스크립트 트레이닝 책처럼.)
회사 일 하면서 하는거라 언제 완성 될지는 잘 모르겠다 -ㅅ-;;;

뭐 언젠가는 되겠지.

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

다른글을 준비 하고 있었는데 아무래도 정리가 안되는데다가..
명색이 개발블로그인데 사견이 들어있는글이 메인을 너무 오래 장식 하고 있는게 맘에 안들어서 또다른 사견을 한줄 적어본다..

개발을 하다보면 일정을 맞추기 위해서라던지 혹은 개발자가 좀 귀찮아서 라던지 어느정도 타협을 하게 되는 경우가 많이 있다.
이건 뭐 디자인 할때도 마찬가지였지만. "이정도 했으면 뭐 괜찮겠지", "개발비용 대비 이정도면 된거 아닌가" 하는 생각으로 어느정도 선에서 마무리 지어버리고 프로젝트 종료를 하게 되는 경우가 생긴다.

지나고 나서 생각해보면.. 혹은 수정사항이 나와서 다시 한번 전체 플로우를 살펴 보다 보면 이건 정말 내가 잘못 했구나 이건 좀 심했다는 생각을 한다.

지금 진행하고 있는 프로젝트에서도 비슷한 상황이 발생했다.

이건 순전히 내 잘못이라고도 할 수 있는데 일정을 맞춰야 하는 상황에서 업무량이 증가하니.. 사용자 편의성을 약간 희생시켜서 작업을 진행했다.
물론 PM과 이야기도 했고 컨펌을 받았다.

하지만!!!!!

인수테스트가 다가오고 PM이 결과물을 확인 하는 과정에서.. 불편하다는 것이었다.. 컨펌도 받았는데 -ㅅ-;;;
이야기 할때는 무슨생각을 하신거지! 생각했지만..
내가 생각해도 좀 불편하다 생각했기 때문에.. 추가된 작업까지 해서 새로 작업 중이다..

UX는 사용자 경험이다.
내가 생각하는 사용자 경험 디자인 이라는건 특정한 프로세스의 설명이 없이도.. (예를 들면 이 버튼은 뭘 하기 위한 버튼임니다.. 포멧 하려면 저쪽 빨간버튼을 누르세요 등) 원하는 목표지점에 도착 할 수 있는 것이 가장 기본적인 요건이라고 생각한다.

조금더 번거롭다고 해서 시간이 좀더 걸린다고 해서 사용편의성을 희생해서는 안될 것이다.
개발자가 번거로운 만큼 사용자는 편하게 사용할 수 있고.
디자이너가 번거로운 만큼 사용자는 편리한 화면을 볼 수 있다.

가슴에 새기고 있다고 생각했던 기본 마인드를 저버린 결과 고생중이다..  ㅠㅠ

--------------------
한줄 요약 :  할때 잘하자.

ps. 사견을 가리고자 쓴 글이 또 사견이 되어버렸지만.. 그나마 원래의 블로그와 관련이 있으니 괜찮지 않을까나 -ㅅ-;
저작자 표시 비영리 동일 조건 변경 허락
신고

'ux' 카테고리의 다른 글

귀차니즘과 사용자 편의성  (2) 2010.04.06
[책] - Web Form Design 웹폼 디자인  (3) 2010.03.16

Comment +2

  • 완성됬다고 생각되는 결과물에 손을 한번 더 댄다는 건 정말 귀찮을 일이겠죠.. 하지만 정말 하기싫은데 거의 등떠밀려서 한 기능 보완 작업이 주위로부터 기분좋은 소리를 듣게 해주는 경우도 많았던거 같아요.. 광고처럼 "조금더"라는게 많은걸 바꾸어 놓는거 같다는...결국엔 자기한테 좋은일 아닐까 생각합니다.

    • 사실 당연히 해야 하는 부분이지요
      매번 후배들한테 이야기 할때는.. 개발자는 원래 귀찮은 직업이다.
      조금 귀찮다고 해서 어느정도 선에서 타협하기 시작하면 막장으로 가는거다 이럼서 검내 갈구는데 -ㅅ-;;

      정작 제가 게으름을 피워버린거죠ㅎㅎ

      디자인할때도 그렇고 개발할때도 그렇고 막바지 보완 작업이 확실히 퀄러티가 올라가기는 하는거 같아요


문광부 장관님이 시끌시끌 하더니 요즘은 안상수 대표가 더 이슈가 되는거같다.

좌파 교육 발언으로.. 과연 정말 저게.. 진짜로 그렇게 생각해서 이야기 하는걸까.. 아님 그냥 당론으로 어떻게 몰아 갈려고 하는걸까.. 혹은.. 잠깐 딴생각하다가 걍 지껄였을까 고민을 하게 만들더니..

봉은사 직영사찰 전환 압력을 넣었단다.. [기사링크]
주지로 계시는 명진 스님을 두고 좌파스님이 봉은사 주지로 있게 해야 되것냐면서 이야기 했다는데.. 나는 솔직히 명진스님을 잘 몰랐다..
스님은 법정스님이 최고인가보다 했었는데.. 어째 안대표가 까는것이.. 괜찮은 어른이신가보구나 하는 생각이 들어 찾아봤따..

딴지일보에서 명진스님에 대해서 기사를 쓴게 있더라..

[이 어른을 소개 합니다 - 봉은사 주지 명진스님]

노무현 대통령 영결식을 진행하셨던 그 스님이시더군.. 그때도 천일기도 한다더니 깨고나왔다고 찌라시에서 검내 까댔었는데..
뭐 암튼 요즘은 사람들을 판단하기가 참 편해졌다.. 전에는 어떤 사람이 괜찮은 사람인지 알기 위해서는 이곳저곳 자료를 찾아보고 기사를 살펴보고 해야 하는데..

몇몇 매체나 사람들이 깐다 싶으면 괜찮은 사람이더라 -ㅅ-;;

안상수 의원이 꽤나 우리나라의 안보에 관심이 많은거 같아서 궁금해서 찾아봤다.. 노무현 정권 시절에 이런 말도 하셨더라.. 그때 노무현 대통령이 아마 군대 가서 썩는다라고 민간인이나 쓰던 표현을 썼었나보다.

안 의원은 27일 오전 평화방송 <열린 세상 오늘, 장성민입니다>에 출연, “헌법이 신성한 의무로 규정한 국방의 의무를 ‘군대 가서 썩는다’고 표현한 것은 헌법 위반”이라며 “대통령의 헌법 파괴적 발언에 우리 국민들이 모두 걱정하고 있다”고 말했다.

원문링크
http://news.naver.com/main/read.nhn?mode=LSD&mid=sec&sid1=100&oid=119&aid=0000017881

헌법이 신성한 의무로 규정한 국방의 의무를... 얼마나 존중하셨는지 한번 볼까..

더보기


아.. 누가 누구를 까는지 모르겠네 이거 -ㅅ-;
행방불명이라.. 쩝.. 우리나라 참 정치인 하기 좋은거 같다..
이거 나는 정치 하고 싶어도 너무 착하게 살아서 안될거같네..

마지막으로 버티던 마봉춘도 넘어가고.. 일본이 점령한 시절이 우리나라가 발전했으므로 일본에 감사해야 한다고 지껄여대는 뉴라이트 애들이 교과서를 만드는 시대에..
과연 더이상 바랄게 있을까..

잃어버린 10년이 꽤나 아쉬웠나보다.. 이제 도로 되찾아도 방법이 없게 만들기위해서 신문도.. 방송도.. 법원도 개혁(?) 하고 국토까지 파해쳐서 한탕 거하게 해먹고 나면..

뒤처리는 누가하나.. 너와 내가 내가 다 하지 못하면 내자식이 하게 되겠지.
저작자 표시 비영리 동일 조건 변경 허락
신고

'Think Difficult' 카테고리의 다른 글

자유인? 실업자?  (0) 2015.12.17
안상수 의원은 누구의 대표인가?  (5) 2010.03.21
연아도 좀 쉬고 싶지 않을까?  (4) 2010.03.03

Comment +5

진행하는 프로젝트가 SI 쪽이다 보니.. 엄청난 텍스트 인풋과 텍스트 에어리어, 콤보박스를 만나게 된다.
폼 자체의 비효율은 둘째치고 단지 화면에 배치 하는것만으로도 압박을 느낄 정도의 화면도 있다.


-엄청나다 -ㅅ-;
문제가 될 소지가 있기때문에 데이터를 삭제 하는데도 꽤나 시간이.. 걸렸다.

검색에서도 마찬가지인데.. 엄청나게 많은 검색 조건들의 압박에.. 검색폼을 통채로 밀어넣는 옵션을 가지고 있기도 하고.. 일부를 감추기도 하는등의 꼼수도 부려보지만.. 결국은 뭔가 다른 방법이 필요하지 않을까 고민하던중 뭔가 실마리를 줄수 있지 않을가 해서 선택하게 된 책이다.



미친듯한 속도로 받은날 완독하고 느낀점은...아.. 이런책도 있구나.. 였다.
폼의 사용성 테스트 라던지.
아이트래킹을 이용한 결과는 앞으로 어떤식으로 폼을 구성해야 할것인가에 대한 실마리를 주었다.

특히 서핑중에 폼을 만났을때의 감정에 대해서도 적어놓았다. 이책을 보면서 아 내가 웹에서 만났을때 당황스러운 느낌을 받았었는데 내가 만드는 것들도 그랬겠구나 생각이 들었다.

폼은 궁극적으로는 사람과 사람의 대화 방식이다. 서비스 제공자와 사용자의 대화, 물건을 팔려는 사람과 사려는 사람과의 대화. 상대방이 나와의 관계나 이야기 흐름에 맞지 않는 엉뚱한 질문을 해대거나, 말투가 무례하거나 이해할 수 없다면 대화는 길게 이어지지 않고 실패한다. 폼을 주의 깊게 살펴야 하는 이유다.

옮긴이가 적어놓은 서문중의 한 블럭이다.

주저리 주저리 책 내용을 적어봐야 스포일러만 되는거고 이 한 문단으로 이 책을 읽어봐야 할 필요성이 느껴진다.
느껴지지 않는 다면 뒤로가기 history.back(-1) ㄱㄱ~

하지만 가격은 다시 한번 읽어야 하는지 고려 하게 만든다.. -ㅅ-;;
무려 이만 사천원.. 책 사진에서 볼수 있겠지만 얇고 작은 책이다. 두께가 가격을 결정하지는 않지만.. 꽤나 비싼 책이다라는 느낌은 받을 수 밖에 없다.

1. 자기가 만들고 있는 폼에 문제가 있다고 생각한다.
2. 회원가입은 왜 이렇게 밖에 안되나 나도 이런 폼은 가입하기 싫겠다.
3. 내 대화가 무례하지 않았으면 좋겠다.
4. 어차피 회사에서 사주니 가격은 상관없다.
5. UX는 폼에서 더욱 중요하다.
6. 기본에 충실해야지 않을까

위 항목에 하나라도 걸린다면 한번 읽어보면 좋을것이다.
디자이너건 개발자건 기획자건 내가 뭘하고 있는지는 상관이 없다.. 지금 사용하는 폼에 문제가 있다고 느낀다면. 읽어보고 같이 일하는 사람과 공유 하라..

어차피 혼자서는 회원가입에 직업입력을 빼도 되는지 결정하지 못하는거 아닌가 -ㅅ-;
저작자 표시 비영리 동일 조건 변경 허락
신고

'ux' 카테고리의 다른 글

귀차니즘과 사용자 편의성  (2) 2010.04.06
[책] - Web Form Design 웹폼 디자인  (3) 2010.03.16

Comment +3

  • CTI인가봐요 -_-;
    사용자의 인지 능력과 정보의 제한에 대해 적잖은 고찰을 하게 되는 시스템.. -_-

    • 모르는게 없으시군요 ㅎㅎ
      스크린샷 때문에 고소당하거나 하지는 않것지 -ㅅ-;;
      폼 뿐인데!

    • 처음에 멋모르고 이것 저것 닥치는대로 하다보니 -_-;
      CTI 화면은 정말 개선이 어려운 것 같아요.
      유선 상에서의 질의에 즉각 응답해야하는 특성 상, 교육된 상담원 기준으로, 다수의 정보를 찾는데 걸리는 시간이 줄어들어야 하는데, 인간의 두뇌가 좀 빨라야 말이지요. ㅎㅎ
      하지만, 어렵다≠불가능하다. 개선 방안은 분명 있기 마련이니 힘내세요!




이니셜D가 보고싶어지는 동영상 -ㅅ-;

내가 출퇴근시에 이용하는 830번 버스(서울-일산)도.. 눈/비올때 자유로를 질주하면서.. "기사님 과속하지 마세요" 안내 멘트를 들을때면.. 손잡이를 잡은손에 힘이 들어가는데.. 이 동영상에 비하면 조족지혈이군요.
바다사나이의 위엄인가!!!
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

오늘 좀 한가하다 -ㅅ-;;;
덕분에 하나 더 올리게 되었다.

이번 포스팅은 이전 포스팅의 계량형이라고 할까.. 업그레이드 버전 정도 된다.
2010/03/09 - [Flex/Event] - 데이터 그리드 ListEvent / DatagridEvent 특정 칼럼만 에디트 하기

목적

이전 포스팅에서 더블클릭으로 아이템 에디트 모드로 들어가고 클릭으로 선택 하는 형식으로 만들었는데 이번에는 itemRenderer를 이용해서 에디트 버튼을 가지고 있는 데이터 그리드를 만든다.
그리고 디비에 데이터를 업데이트 한다고 할때 어느 시점에서 업데이트를 해야 하는지 CollectionEvent를 이용해서 알아본다.

										rinn				퍼플린				B										magis				들캔디				A										zzatung				짝퉁				??									.btnEditColumn{			upSkin: Embed(source="assets/edit.png");			overSkin: Embed(source="assets/edit_over.png");			downSkin: Embed(source="assets/edit.png");		}																


기본적으로 mxml 부분은 이전과 같다.
Datagrid 에 붙어있던 각종 이벤트 처리 부분이 랜더러로 빠져나가기 때문에 Datagrid 태그쪽만 좀 한가해졌다.

아이템랜더러는 엄청나게 많이 사용되고 질문또한 많이 올라오는 부분중에 하나이다. 간단하게 버튼을 넣는거 부터 복잡하게는 랜더러와 에디터를 따로 커스터마이징 해서 사용하는 경우까지 상황이 다양하지만. 기본적으로는 비슷하기 때문에 이 포스트에서 다루는 정도만 해도 기초적인것은 커버 될꺼라 생각한다.

위 소스 에서 <mx:DataGridColumn dataField="name" itemRenderer="renAddEditButton"> 이곳에 설정된 itemRenderer 로 사용되고 있는 renAddEditButton 이 이번 포스트의 핵심이다.

일단 소스 풀소스를 보자.

package{	import flash.events.MouseEvent;		import mx.containers.Canvas;	import mx.controls.Button;	import mx.controls.DataGrid;	import mx.controls.Label;	import mx.controls.dataGridClasses.DataGridColumn;	import mx.controls.dataGridClasses.DataGridListData;	import mx.controls.listClasses.BaseListData;	import mx.controls.listClasses.IDropInListItemRenderer;	import mx.core.ClassFactory;	public class renAddEditButton extends Canvas implements IDropInListItemRenderer	{		private var _btnEdit:Button;		private var _label:Label;		private var _listData:DataGridListData;				public function renAddEditButton()		{			super();		}				override protected function createChildren():void		{			super.createChildren();			this.horizontalScrollPolicy = "off";						_label = new Label();			addChild(_label);			_btnEdit = new Button();			_btnEdit.styleName = "btnEditColumn";			_btnEdit.visible = false;			addChild(_btnEdit);						_btnEdit.addEventListener(MouseEvent.CLICK, hBtnClick);						this.addEventListener(MouseEvent.MOUSE_OVER, hRollOver);			this.addEventListener(MouseEvent.MOUSE_OUT, hRollOut);		}				override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void		{			super.updateDisplayList(unscaledWidth, unscaledHeight);			_label.width = unscaledWidth-21;			_label.x = 3;			_label.y = 2;			_btnEdit.x = unscaledWidth-18;		}				private function hBtnClick(e:MouseEvent):void		{			var dg:DataGrid = DataGrid(listData.owner);			dg.editable = true;			dg.editedItemPosition = {columnIndex:1, rowIndex:listData.rowIndex};			trace("aa");		}				private function hRollOver(e:MouseEvent):void		{			_btnEdit.visible = true;		}				private function hRollOut(e:MouseEvent):void		{			_btnEdit.visible = false;		}				public function set listData(value:BaseListData):void		{			_listData = DataGridListData(value);			_label.text = listData.label;		}				public function get listData():BaseListData		{			return _listData;		}			}}


복잡해보이지만 별건 없다.
데이터 그리드의 아이템 랜더러를 사용하기 위해서 IDropInListItemRenderer를 구현한다. 저 인터페이스가 요구하는건 데이터 그리드의 listData를 엑세스 하기 위한 getter/setter 뿐이다.

기본흐름

createChildren을 override 해서 버튼과 라벨을 만들어준다.
updateDisplayList 에서는 위치를 잡아주고
데이터 그리드에 오버 했을때 버튼이 나타나도록 하기 위해서 해당 이벤트 핸들러를 등록한다.
랜더러 안에 있는 버튼을 클릭했을때 해당 데이터 그리드의 참조를 획득해서 editable = true 로 세팅해주고 이전 소스에서 나왔던 Datagrid.editedItemPosition 을 사용해서 해당 셀을 에디트 가능 상태로 만든다.

DataGrid 에는 itemEditEnd 이벤트를 걸어주고 아이템이 수정이 끝났을때 editable = false 로 다시 세팅해준다.

메인 mxml 부분의 스크립트를 보자.

import mx.events.CollectionEvent;import mx.collections.ArrayCollection;import mx.events.ListEvent;[Bindable]private var acData:ArrayCollection;private function init():void{	acData = new ArrayCollection(csData.node);	acData.addEventListener(CollectionEvent.COLLECTION_CHANGE, hCollectionChange);}private function hCollectionChange(e:CollectionEvent):void{	if(e.kind == "update")	{		if(e.items[0].property == "name")		{			trace(e.items[0].newValue);		}	}}


dataProvider로 사용하는 ArrayCollection 에 CollectionEvent를 받을수 있는 이벤트핸들러를 등록한다.
CollectionEvent는 ArrayCollection이나 XMLListCollection 같은 ListCollectionView를 구현하고 있는 넘들의 데이터의 변화 상황을 알려준다.

Inheritance : CollectionEvent Inheritance Event Inheritance Object

The mx.events.CollectionEvent class represents an event that is dispatched when the associated collection changes.

CollectionEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false, kind:String = null, location:int = -1, oldLocation:int = -1, items:Array = null)

아이템이 수정이 완료 되고 데이터 프로바이더에 반영되고나면 CollectionEvent가 발생하게 되고 이걸 캐치 하게 되면 수정사항이 반영된 ArrayCollection에 접근할 수 있다.

CollectionEvent.COLLECTION_CHANGE 이벤트의 핸들러인 hCollectionChange 함수에서 이벤트의 kind 를 확인 해서 업데이트가 된것인지 삭제가 된것인지등의 컬렉션의 변화 사항을 체크 한다.

e.kind 의 값은 "add", "update", "remove" 가 있고 update 일 경우 items 값은 mx.events.PropertyChangeEvent 가 된다.
정석으로 하려면 e.items 를 PropertyChangeEvent로 캐스팅 하고 거기에서 kind 값을 다시 받아서 "update"인지를 확인 하고 해야겠지만.. 어차피 이 데이터 그리드에서는 변경이 라벨 변경밖에 되지 않으니.. 그냥 0 으로 받고 변경된 property가 name 필드 인지만 확인 하는 정도로 하자.

trace(e.items[0].newValue);


에서 새로 입력된 값이 나오게 된다. 이 시점에서 디비에 수정된 사항을 업데이트 하는 정도로 구현하면 될것이다.

CollectionEvent는 이 경우 처럼 라벨을 수정하는 정도에서는 간단하게 처리가 되지만.
드래그앤 드랍이라던지. Tree에서 이용하기 위해서는 경우의 수가 많아진다.

따라서 그때는 CollectionEvent를 사용하지 않고 따로 업데이트 되는 시점을 체크 할 수 있는 방법이 필요하다.
드랍될때 데이터를 세팅한다거나 수정 할때 기본 itemEditor를 사용하지 않고 custom itemEditor를 사용해서 에디터 내부에서 변경된 값을 넘겨준다거나 하는 방식으로 하는것이 더 효율적일 수 있다.

하지만 CollectionEvent는 실제 작업을 할때 이용하지 않더라도 데이터 이동을 디버깅할때 여간 편하게 쓰이기 때문에 한번씩 사용해 보는것이 좋을 것이다.



ps.
이걸 만들면서도 뭔가 더 깔쌈한 방법이 있을꺼같은데 저정도 밖에 안되나 하는 생각이 들었는데. 좀더 나은 구현방법이 있으신분은 그냥 가지 마시고 꼭 댓글이나 트랙백을 달아주셔서 안목을 넓혀주셨으면 합니다.
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

데이터 그리드는 RIA 에서 빈번히 사용되는 컨트롤중 하나 이다.
관련된 이벤트도 많고 중요도도 높은 편이다.

데이터 그리드에서 editable = true 로 세팅 해주면 해당 칼럼을 그리드 내부에서 편집할 수 있다.
이것은 itemEditor를 통해서 가능해진다.

이 포스트에서는 특정 칼럼만 편집할 수 있도록 하고 몇가지를 더 추가 해서 완성하는 것을 해본다.

일단 mxml 부분 (태그 앞부분이 소문자로 나오는건 syntaxHighliter 때문이니 신경쓰지 않아도 된다)


	
		
			
				rinn
				퍼플린
				B
			
			
				magis
				들캔디
				A
			
			
				zzatung
				짝퉁
				??
			
		
	
	
		
			
			
			
		
	


아이디와 이름 혈액형을 model 로 데이터를 세팅하고 데이터 그리드에 바인딩 한다.
데이터 그리드에 연결되어있는 이벤트는 아래쪽에서 구현 예정이다.

아이디와 혈액형은 수시로 바뀌는게 아니기 때문에 여기서는 이름 필드만 편집 가능할 수 있도록 세팅 해보자.

여기서 사용 되는 것이 데이터그리드의 editedItemPosition 이다.
editedItemPosition property  
editedItemPosition:Object

The column and row index of the item renderer for the data provider item being edited, if any.

This Object has two fields, columnIndex and rowIndex, the zero-based column and row indexes of the item. For example: {columnIndex:2, rowIndex:3}

Setting this property scrolls the item into view and dispatches the itemEditBegin event to open an item editor on the specified item renderer.

The default value is null.

This property can be used as the source for data binding. When this property is modified, it dispatches the itemFocusIn event.


columnIndex와 rowIndex를 필드로 받고 아이템 에디트가 일어날때 그 값으로 세팅하게 되어있다.

아이템 에디트가 발생하게 되면 itemEditBegin 이벤트가 시작되고 이때 특정 칼럼만을 선택할 수 있도록 만들어준다.

private function dgEditBegin(e:DataGridEvent):void
{
	dg.editedItemPosition = {columnIndex:1, rowIndex:e.rowIndex};
}

columnIndex 를 1 로 고정하고 rowIndex 는 이벤트가 발생한 rowIndex 를 세팅 해주었으니 다른 칼럼을 선택하더라도 이름쪽만 에디트 될 수 있도록 바뀌게 된다.

하지만 매번 클릭시에 발생하게 되므로 사용하기에는 그리 모양새가 좋지 않다. 클릭 했을때는 해당 아이템이 선택되도록 하고 더블 클릭 했을때 수정 할 수있도록 수정하는것이 최종 목표이다.

더블 클릭을 사용할때 유의 할점은 일반 클릭도 함께 발생한다는 점이다.
마우스 클릭이 발생하게 되면 이게 더블클릭인지를 기다리는게 아니고 일단 마우스 이벤트는 진행이 되고 인터벌 안에 한번더 클릭이 들어오면 더블클릭으로 판단 하기 때문에 두가지 이벤트를 구분할수 있는 flag 를 세팅하고 아이템 에디트가 시작될때 클릭인지 더블클릭인지 확인하는 로직을 만들면 된다.

private var _isDClick:Boolean = false;

private function dgItemClick(e:ListEvent):void
{
	_isDClick = false;
}

private function dgDoubleClick(e:MouseEvent):void
{
	_isDClick = true;
}

private function dgEditBegin(e:DataGridEvent):void
{
	if(_isDClick)
		dg.editedItemPosition = {columnIndex:1, rowIndex:e.rowIndex};
	else
		e.stopImmediatePropagation();
}


isDClick 이라는 flag 를 itemClick 시에 false 로 세팅하고 doubleClick 시에 true 로 세팅해준다.
itemEditBegin 에서 flag 값에 따라서 이벤트를 블록 시킬 것인지 에디트를 진행할 것인지 결정하게 된다.



참고 사항

에디트 자체는 더블클릭일때만 활성화가 되지만 에디트를 하기 위해 더블클릭 하게 되면 itemClick 함수가 한번 실행 되게 된다.
이것을 클릭일때는 itemClick의 내용만 실행하고 더블 클릭일때는 에디트만 실행되도록 하기 위해서는 그냥 더블 클릭을 판단하는 로직자체를 타이머를 이용해서 구현하고 일반클릭일때는 더블클릭인지 판단하는 타이머가 끝날때 특정 행동을 수행하도록 수정해야 한다.

이 경우 그냥 클릭만 할때 바로 실행되지 않고 더블클릭인지 확인 하기 위해서 딜레이가 생기기 때문에 즉각적인 반응이 나오지 않아서 프로그램자체가 문제가 있지 않느냐는 평가를 받을 수도 있으므로 딜레이타임의 세팅에 세심한 주의가 필요하다.

이부분의 구현은 트랙백을 부탁한다.. -ㅅ-;;; 결코 귀찮아서가 아니다..;;


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +3

  • 이 포스트도 도움이 많이 되었습니다. 구글 검색하다보니 자꾸 이쪽 블로그로 오게 되네요.ㅋ
    밥이라도 한끼 사드려야 할듯..하군요..ㅋㅋ

    • 감사합니다 ㅎㅎ
      유입경로는 다 구글이더군요.
      다른 검색사이트(대표적으로 네이버)들은 자체 디비 검색을 우선하기 때문에 검색자체가 안되요

  • 신입개발자 2013.10.12 02:30 신고

    도움받아서 저도 글을 올립니다.
    많은 시간이 지나서 보실지 모르겠습니다.
    클릭 / dbl클릭의 구현에서 주기능은 타이머를 사용하지 않아도 됩니다.
    단지 그것을 위해서 사용하던 파라메터를 일정시간안에 초기화 해주는
    타이머 하나면 됩니다. 실제 컴퓨터에서 사용하는 더블클릭을 구현
    한다고 생각하면 편할듯 하고 이벤트는 ItemEditBegin을 이용하시면 일반 더블클릭과 동일한 결과물이 나옵니다.

어플리케이션에서 SWFLoader 를 사용하여 다른 도메인의 SWF 파일을 불러올때 나는 에러이다.

SecurityError: Error #2070: 보안 샌드박스 문제가 발생했습니다. 호출자 http://호출된domain/aaa.swf은(는) http://호출한domain/2008.swf이(가) 소유한 스테이지에 액세스할 수 없습니다.
    at flash.display::Stage/requireOwnerPermissions()
    at flash.display::Stage/addEventListener()
    at mx.flash::UIMovieClip/creationCompleteHandler()[E:\dev\flex\sdk\frameworks\projects\flash-integration\src\mx\flash\UIMovieClip.as:2432]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()


분명히 crossdomain.xml 도 확인 했고.. 재밌는건 에러를 무시 하고 나면 정상적으로 로딩이 된다. (이경우는 나만 그런건지도 모른다..)

독립적으로 돌아가는것을 확인 했고.. 스테이지를 왜 엑세스 할수 없다고 하는건지 전혀 감이 안잡혔는데.
구글링을 하던 도중 Embed 된 것들에 문제가 있는경우의 키워드를 획득!
css 부터 뒤지기 시작했다.

Embed 되는것은 어차피 컴파일 단계에서 swf 에 포함되는 것인데.. 왜 그것때문에 에러가 나는지 고민하던중 문제를 찾아냈다.

css 에서 이미지를 불러오면서 라이브러리 swc를 사용한 부분에서 에러가 났다.

보통 css 에서 이미지를 embed 시키는 경우 소스는.

.PanelTypeApp {

 borderSkin: Embed(source="../images/panelType01.png",
  scaleGridTop="171",scaleGridLeft="21",scaleGridRight="267",scaleGridBottom="180");
}


위와 같이 직접 소스에 이미지 경로를 넣게 된다.

플레시에서 스킨을 만들어서 export 해서 사용 하는경우는.

.PanelType1 {
	borderSkin: Embed(skinClass="Panel_borderSkin01");
}


이런식으로 swf의 클래스를 참조해서 가져오게 된다.
두 방식 다 Embed는 되지만 swc 같은 경우에는 라이브러리로 참조되어있어서 아마도 이 값을 다시 한번 찾는게 아닌가 싶다.
참조를 찾기 때문에 스테이지에 엑세스 할 수 없다고 에러가 나지만..
실제로는 Embed 되어있기 때문에 에러를 무시 하게 되면 이미지는 표시 되는 것이 아닌가 싶다.

이 에러는 오늘 처음 만난 에러라서 케이스가 이거 하나 뿐이라 정확한 이유는 아닐수도 있으니 비슷한 경우를 겪은 분이나 왜 저런식으로 문제가 해결 되는지 이유를 아시는 분은 댓글이나 트랙백을 남겨주셨으면 합니다.

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

블로그에서 사용하는 하이라이터가 mxml 이 제대로 표현이 안되서 그걸 찾다가..
에디트플러스용을 찾았다. -ㅅ-;;

블로그에서 사용할놈도 얼렁 찾아야 하는데!
혹시 mxml 이 제대로 표현되는 브러시를 가지고 계시거나.. 추천할만한 웹페이지용 하이라이터가 있으면 꼭좀 댓글을 남겨주시길 ㅠㅠ

에디트 플러스용 하이라이터

Tools - Preferences 에서 Files - setting/syntax 를 선택하고 add 를 눌러서 새로운 프리셋을 만든다.

Syntax File 과 Auto completion 에 첨부 파일 두개를 각각 세팅 해주면 끝.



나름 만족스러운 결과를 보여준다.


원저작자 블로그
http://ak33m.com/?p=27

다운로드 링크
http://ak33m.com/wp-content/uploads/2007/03/as3mxml.zip

혹시 모르니 업로드 링크도 하나

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

TabBar / TabNavigator / ButtonBar 등.. ViewStack 과 관련된 컨테이너들을 사용하면서 가장 많이 나오는 질문은 "두번째 탭에 있는 오브젝트를 엑세스 하려고 하니 null 이라고 해요" 이다.

분명이 mxml 에서 다 만들어져 있는데.. 왜 안된다고 하는것인지 모르겠다고 질문이 올라오면.
가장 많이 달리는 답변이. "creationPolicy = "all" 로 해주세요" 이다.

과연 맞을까?

분명 저렇게 하면 에러가 나지 않고 전부 만들어진다.
creationPolicy = "all" 은 생성 정책을 전부 만드는걸로 하겠다는 뜻이다.
탭이 세개가 있으면 탭 세개 안에 들어있는 컴포넌트 들을 처음 로딩시에 전부 만들겠다고 선언하는 것이다. 그럴리야 없겠지만 백개가 있으면 백개를 다 만들게 된다.

공지 사항 탭 / Q&A 탭 / FAQ 탭  이 있다고 했을때 아에 첨부터 세개탭의 데이터를 전부 가져와서 뿌려놓고. 탭을 이동하면 단지 보기만 하면 되도록 만든다면.. 초기 로딩은 좀 느려지겠지만 이후에는 그냥 이동만 하면 되니 괜찮지 않느냐고 이야기 하는 사람도 있을 것이다.

복잡하지 않은 경우 이렇게 처리 하는 것도 뭐 나쁘지는 않을 수 있다.

하지만 뒤쪽 탭을 보지 않는 다면 쓸데 없이 시간과 메모리를 낭비 하게 되는 것 아닌가.

<mx:TabBar id="tabNav" dataProvider="{stack}"/>
<mx:ViewStack id="stack" width="100%" height="100%">
    <mx:Canvas label="Tab 1" backgroundColor="#ff0000">
        <mx:Label id="lbTab1" />
    </mx:Canvas>
    <mx:Canvas label="Tab 2" id="can2" backgroundColor="#00ff00">
        <mx:Label id="lbTab2" />
    </mx:Canvas>
    <mx:Canvas label="Tab 3" backgroundColor="#0000ff">
        <mx:Label id="lbTab3" />
    </mx:Canvas>
</mx:ViewStack>

위 코드에서 뷰스택은 캔버스로 되어있고 캔버스 안에 각각 라벨이 하나씩 있다.
이 라벨값이 1,2,3 이라고 입력되도록 해야 한다.

creationComplete 될때 lbLabel2.text = "2" 하게 되면 해당 객체가 null 이라서 엑세스 할 수 없다는 에러가 발생한다.
ViewStack 의 creationPolicy = "all" 해주면 에러가 깔끔하게 사라진다.

이 방법은 메인에서 탭으로 데이터를 주입해주는 방식이다.

이걸 Event 방식으로 바꾸려면 탭이 선택 되면 그때 자기의 데이터를 가져가도록 바꾸면 된다. 텝이 선택되서 바뀌고 나서 발생하는 이벤트가 이 포스트의 제목인 IndexChangeEvent 이다.
private function init():void
{
	stack.addEventListener(IndexChangedEvent.CHANGE, navIndexChange);
}

private function navIndexChange(e:IndexChangedEvent):void
{
	trace("old : "+e.oldIndex);
	trace("new : "+e.newIndex);
	
	switch(e.newIndex)
	{
		case 0 : lbTab1.text = "텝 1 입니다"; break;
		case 1 : lbTab2.text = "텝 2 입니다"; break;
		case 2 : lbTab3.text = "텝 3 입니다"; break;
	}
}

뷰스텍의 selectedIndex가 변경되게 되면 IndexChangeEvent 가 캐치 된다. e.newIndex / e.oldIndex 값을 통해 이전 인덱스와 바뀐 인덱스 값을 알 수 있게 되므로 해당 페이지에 맞는 내용을 로드 할 수 있게 된다.

간단한 페이지의 경우에는 creationPolicy = "all" 해버리는 쪽이 편하다고 생각할 수 있으나 탭안에 들어가는 내용이 많아 지게 되면 이런 방식으로 바꾸지 않으면 비효율의 극치를 보게 될지도 모른다.

플렉스에서 탭방식으로 동작 하는 것들은 전부 처음 로딩시에 보이는 페이지만을 가져오게 되어있다. 가벼운 RIA 페이지를 위해서는 기본은 지켜서 코딩을 하는 습관을 들이는 쪽이 좋다.

레퍼런스참고
http://livedocs.adobe.com/flex/3/langref/mx/events/IndexChangedEvent.html
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +2

  • 최근 플렉스 프로젝트를 처음 진행하면서 퍼플린님 블로그에서 많은 도움을 얻고 있습니다. :)
    트랙백하나 남기고 갑니다~

    http://cliver.egloos.com/1986719

    • 도움이 돼셨다니 다행입니다.
      요즘 업무에 치여서 블로그 글쓰는게 좀 뜸해졌는데 열심히 써봐야지요.
      트랙백 감사합니다~


게임을 좋아하는데 저런차는 꼭 한번 타보고싶다.
돈주고 사기는 좀 아까울꺼같고.. 왠지 실제로 운전을 하고 있지만.. 게임하는 듯한 착각에 큰사고를 내더라도.. 세이브 포인트에서 다시 시작 할 수 있다는 생각이 들것 같군..


완전 자동차와 혼연 일체가 되어버린 인테리어.


뒷좌석에 탄사람도 배려하는 완벽한 시스템


주차 했을때는 모여서 즐길 수 있는 넓은 모니터 까지..
완벽 그 자체..

2006 샌디에고 모터쇼에 컨셉카로 나왔다는것 같은데.. 왜 이제 본거지 ... 나 인터넷 개통 된지 좀.. 오래됐는데..

꼭 한번 타보고 싶다.
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

mx.utils 에는 편하게 사용할 수 있는 api 가 담겨있다.

ObjectUtil.toString 같은 것은 많이 사용하고 꽤나 유용하게 쓰인다.

이 포스트에서 이야기 할 substitute 는 간단하게 이야기 하면 문자열을 치환 해주는 메서드이다.

간단히 코드를 보면 이해가 될것이다.

private var str:String = "select * from TABLE_NAME where userid='{0}' and menuid='{1}'";

private function build():void
{
	var query:String = StringUtil.substitute(str,"rinn","n002");
	trace(query);
	//select * from TABLE_NAME where userid='rinn' and menuid='n002'
}


위코드에서 보듯이 String 값에서 {n} 형식으로 중괄호로 묶여진 것들을 찾아서.
거기에 파라미터로 받은 값을 넣어준다.
n 값에 따라서 파라미터가 순서대로 들어가게 된다.

{0} 에는 첫번째가 {1}에는 두번째가 들어가고 문자열 안에서 등장하는 순서는 상관이 없다.

private var str2:String = "select * from TABLE_NAME where userid='{0}' and menuid=(select menuno from TABLE2 where userid='{0}' and menuid='{1}')";

private function build2():void
{
	var query:String = StringUtil.substitute(str2,"rinn","n002");
	trace(query);
	//select * from TABLE_NAME where userid='rinn' and menuid=(select menuno from TABLE2 where userid='rinn' and menuid='n002')
}


{0} 이 두번 나오면 두번다 파라미터 첫번째 값이 들어가게 되는 것이다.

이 방법의 좋은점은 대상이 되는 문자열을 파일로 저장해놓을 수 있다는 점이다.

기본 쿼리 같은 경우 파일로 저장해놓고 불러다가 치환해서 사용하게 되면.. 테이블 이름정도가 바뀐다거나 하는 것들은 간단하게 파일만 수정하는 것으로도 해결이 된다.

메뉴의 링크 정보를 저장하는 경우에도 편리하다. 권한 정보 같은것에 따라 파라미터가 바뀐다거나 하는 경우에.. 기본 링크 정보를 저장해놓으면 이후에 간단한 것은 컴파일 할 필요없이 수정해 줄수 있다.

사실 쿼리 같은 경우 iBatis 를 쓰는 것이 훨씬 간편하고 다이나믹 하게 쿼리를 생성할 수 있지만. 간단한 httpService 를 사용하는 경우에는 유용할 수 있겠다.

substitute 함수는 간단하게 구현되어있다.

public static function substitute(str:String, ... rest):String
{
    if (str == null) return '';
    
    // Replace all of the parameters in the msg string.
    var len:uint = rest.length;
    var args:Array;
    if (len == 1 && rest[0] is Array)
    {
        args = rest[0] as Array;
        len = args.length;
    }
    else
    {
        args = rest;
    }
    
    for (var i:int = 0; i < len; i++)
    {
        str = str.replace(new RegExp("\\{"+i+"\\}", "g"), args[i]);
    }

    return str;
}


간단하게 받아온 파라미터를 Array로 받고 for문 돌면서 정규식으로 찾아서 바꿔주는 구조이다.
사실 이런것은 필요한 경우에 그냥 만들어서 쓰게 되는데 이미 api 에서 제공하는 것을 귀찮게 만들어 쓸 필요가 있는가!!
그냥 있는 걸 쓰자.. -ㅅ-;

mx.utils 패키지 같은 경우에 간단 간단한 함수로 되어있기 때문에 api 소스를 보는 것 만으로도 초보 개발자에게는 공부가 된다. 결정적으로 그리 어렵지 않다..

시간날때 한번씩 뭐가 있는지 봐놓으면.. 나중에 뻔히 제공되는 메서드를 놔두고.. 개발하는 사태는 벌어지지 않을것이다..
우리는.. 그거 말고도 할일이 많지 않은가.. ㅠㅠ


아.. 주말도 출근 해야 하나.....

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

벤쿠버 올림픽이 끝나고 자랑스러운 우리 선수단들이 귀국했다.
이곳저곳 불려다는 곳도 많고.. 고생들이 많아 보인다.

메달을 목에 건 선수들도 수고했고. 이번에 아쉽게 실패한 선수들도 정말 수고가 많았다.
스포츠로 하나되는 세계인의 축제이지만 역시 메달을 목에 걸고 신기록을 세워야 주목받는 현실은 어쩔수가 없는것 같다.
메달 색깔이 중요한게 아니라 선수들의 땀방울이 더 값지고 귀중하다는 이야기는 일단 접어두자. 이건 글 잘쓰시는 다른 블로거들이 많이 이야기 했던 내용이니 굳이 나까지 주절주절 적어봐야 읽는 사람들 시간 낭비일것 같고.. 그냥 마음속에 간직해두기로 한다.

역시 화제의 중심은 김연아다.
후배 삼고 싶은 스타 1위에 뽑히고 스포츠면은 거의 김연아와 아사다마오의 소식으로 도배되었고 일본의 반응 부터 시작해서 세계 각국의 반응까지 비슷비슷한 내용으로 포털의 메인페이지를 장식하고 있다.


국민들에게 너무도 많은 기쁨을 준 피겨여왕 김연아..

평소와 달리 프리 연기를 마치고 눈물을 터뜨리는 모습은 그동안 얼마나 힘들었는지 알게 해주었다. 회사에서 핸드폰의 조그만 화면으로 프리를 보면서 얼마나 긴장을 했던지 연기가 끝나고 나서도 한참을 쳐다보고 있었다.

집에 와서 VOD 로 큰 화면으로 보면서도 또 긴장이 되더라.

보는 사람도 그정도인데 실제 연기를 하는 사람은 어땠을까. 국민들의 엄청난 기대치와 자기 자신의 목표까지.. 그 작은 몸이 느끼고 있던 중압감은 우리가 감히 상상하지 못할 정도였을 것이다.

금메달 소식이 연이어 발표 되면서 벌써 다음 올림픽을 하네 마네 이후에 어떻게 할꺼네 마오는 다음 올림픽도 나온다던데 연아는 안나오나 하는 등의 설레발들이 너무 많은거 같다.

지금은 그냥 좀 쉬게 놔두면 안될까.
이번 방한기간에도 집에 들를 시간도 없단다.

"자 그녀에게 시간을 주자. 저야 놀던 쉬던 잠자던 상관말고~"

노래 가사 처럼 그녀가 앞으로 어떻게 행로를 결정할지 그냥 좀 쉬면서 생각할 수 있는 시간을 주고 싶다.
내가 줄 수 있다면 꼭 주고 싶다!
어떻게 결정하던 우리 국민이 연아를 아끼고 사랑하는 마음은 변하지 않을테니까.. 그녀의 선택을 믿는다.

ps.
그리고 남는 관심을 곽민정에게도 가져보자..
곽민정선수도 치아교정이 끝나고 나면 연아만큼 실력도 얼굴도 이뻐질꺼같다.
연아도 치아교정이 끝나고 나서 세계를 재패하지 않았던가.
그런 점에서 다음 동계 올림픽의 주인공은 곽민정이 될것이다.
지금부터 관심을 가지고 지켜봐주자.
저작자 표시 비영리 동일 조건 변경 허락
신고

'Think Difficult' 카테고리의 다른 글

자유인? 실업자?  (0) 2015.12.17
안상수 의원은 누구의 대표인가?  (5) 2010.03.21
연아도 좀 쉬고 싶지 않을까?  (4) 2010.03.03

Comment +4

  • 곽민정 선수 이뻐 죽겠어요 ㅋㅋ
    프리 게임에서 점수 발표할 때, 천진난만한 웃음으로 전 세계를 미소짓게 했던 ㅎㅎ

    김연아 선수, 정말 감동적인 연기였어요. "품격이 다르죠~"
    이제는 전 세계로부터 너무나도 큰 기대와 관심을 받게 된 김연아. 그만큼 또 작은 실수 하나에도 큰 상처를받게 되진 않을까 걱정이 됩니다. 말씀하신 것처럼, 적절한 휴식과 안정을 취하면서, 이제와는 또다른, 진정한 월드 스타로서의 새 기반을 마련했으면하는 바람입니다. ㅎㅎ

    • 솔직히 곽민정이 기대가 많이 되더군요.
      지금도 우리나라에서 3회전을 뛰는 사람은 곽민정하고 연아뿐이라고 하던데요.
      진짜 귀엽게 생긴듯 ㅎㅎ

      연아는 그동안 기대에 부응해서 잘 해줬으니 안정을 좀 취하고 세계 선수권 남은거까지는 할꺼라고 발표가 났었던만큼 그거까지는 우승하고 쉬면서 차분히 미래를 생각했음 좋겠어요. 개인적인 생각으로는 연예계만 아니믄 될듯 -ㅅ-;;

    • 전 국내 연예계만 아니면 찬성 ㅎㅎ

    • 국내가 아니면 헐리웃!

      저는 헐리웃도 싫어요 -ㅅ-; 그냥 전설적인 스케이터로 남아주기를 바랍니다 ㅎㅎ

      운동선수는 운동을 해야지.. 연예계는 좀..안어울린달까요.. 물론 성공한 강호동이 있기는 하지만 ㅎㅎ

파이어폭스 3.6이 출시된지 꽤 지난거 같은데 뒤늦게 갈아타기로 결정했다.

IE가 꽤나 무거워서 부담스럽기도 했고.. 근래 들어서 자주 상태가 안좋아지는게 짜증도 났고.. 크롬은 뭔가 불편하고.. 아직 플러그인이 많이 없기도 하고..

결국 파이어폭스로 결정!!!!

써보니 역시 속도도 빠르고 좋다. 불러오는 속도도 빠르고 요즘 웹표준이 많이 지켜지는 편이라 전처럼 제대로 보이는 사이트보다 깨져서 보이는 사이트가 많은것도 아니고. 아주 만족스럽게 잘 쓰고 있다.


모양도 깔끔하고.. 테마도 괜찮은게 많이 있기 때문에 골라서 사용할 수 있다.

  • IE가 느려서 짜증난다.
  • 브라우저 스킨을 내가 원하는대로 바꾸고 싶다.
  • IE는 지겹고 크롬은 너무 앞서 가는거같다.
  • 속도 빠른게 최고다.
  • 이것저것 플러그인을 깔아서 편하게 사용하고싶다.
이런생각을 가지고 있다면. 당장 깔아서 사용해보기를 권한다.

모질라 파이어폭스 공식 사이트 (http://www.mozilla.or.kr/ko/)
스크린샷에 보이는 페르소나(테마) 링크

불여우와 함께 쾌적한 인터넷 환경으로 가보자~~

ps. 생각 같아서는 개발자용 플러그인 모음 정도의 포스트도 하나 써보고 싶지만.. 요즘 바빠서 -ㅅ-;;;

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0



1시즌 재밌게 봤었던 드라마.
2시즌은 완결이 안됐었는데.. 이제 다 나왔을려나..

광고 동영상 보니 막 보고싶어지는군요.

그림 완전 잘그려!!!




빅뱅이론 공식 홈페이지 CBS 바로가기.
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

Flash / Flex 에서 사용되는 이벤트는 종류도 많고 거의 필요한 모든 이벤트가 있다고 해도 과언이 아니다.
그런데 왜 커스텀 이벤트가 필요할까.

기본이벤트에서 제공하는 target 속성으로 이벤트를 발생시킨 객체의 정보를 가져올 수 있다고 하지만.. 그 객체의 속성이 아니라 다른 변수를 넘겨야 할 필요가 있다거나 하는 경우..
기본 이벤트가 발생했을때 그 이벤트를 멈추고 새로운 이벤트로 발생시켜서 상위의 객체로 통보하고 싶다거나 하는 경우등.
커스텀 이벤트를 사용하게 되면 이것 저것 편리한 작업들을 많이 할 수 있게 된다.

이번 포스트에서는 커스텀 이벤트를 만드는 방법에 대해서 살펴보자.

커스텀 이벤트는 Event 를 확장해서 만들어진다.

package csEvent
{
	import flash.events.Event;

	public class CustomEvent extends Event
	{
		public static var SEND_DATA:String = "sendData";
		public var csData:*;
		
		public function CustomEvent(type:String, csData:*, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
			this.csData = csData;
		}
		
		override public function clone():Event
		{
			return new CustomEvent(type, csData, bubbles, cancelable);
		}
		
		override public function toString():String
		{
			var str:String = "[CustomEvent type="+type+" bubbles="+bubbles+" cancelable="+cancelable
							+" eventPhase="+eventPhase+" csData 변수를 사용해서 넘어온 데이터를 사용하세요]";
			return str;
		}
	}
}


CustomEvent.SEND_DATA 형식으로 사용할 수 있도록 하기 위해서 static 으로 변수를 설정해준다.
이 이름은 편한대로 지어도 된다. string 값이 기존의 이벤트와 겹치지만 않으면 된다.

csData 변수로 이벤트에 데이터를 실어서 보내게 되는데. 데이터 전송 전용 이벤트 이기 때문에 받는 타입은 그냥 와일드카드(*)로 받도록 했다.
특별히 id 같은 string 값만을 전송한다면 타입을 지정해주는 것이 좋다.

csData 같은 경우 위의 예제에서는 public 으로 선언되어있지만 캡슐화를 위해서는 private 으로 선언하고 getter 를 구현해서 readonly로 사용하는 것이 정확하다.
외부에서 직접 변수를 엑세스 하는 경우에 특별한 경우가 아니면 public 보다는 private 으로 선언하고 getter/setter 로 엑세스 할수 있는 통로를 만드는 습관을 기르는 것이 좋다. (하지만.. 이게 귀차니즘 때문에 쉽지가 않다.. ㅠㅠ)

clone() 함수와 toString() 함수는 옵션이다. 둘다 오버라이드 해서 구현하지 않더라도 정상적으로 이벤트가 전파된다. 하지만 역시 구현해주는 것이 좋다.

clone()을 오버라이드 해서 구현 해야 하는 이유를 아래처럼 설명하고 있다.
Why do you need to override clone? Well, the clone method creates a copy of your event (or object - whatever object has the clone event; this isn't limited to Event objects). The default clone method inherited by the Event class or whatever class your custom class extends, will return an event object of the type of that class, not your custom event subclass. In the situations where a clone is needed, it is needed to be of the same type of your class, not the class it extends.

-Flex PMD event Rule


toString() 같은 경우는 나중을 위해서나 다른 사람과의 협업을 위해서라도 해당 이벤트가 하는 일이나 넘어오는 변수의 타입등이 지정되어있다면 그 데이터를 보여주도록 만들어놓는 편이 좋다.
커스텀 컴포넌트를 만들때에는 항상 toString 을 구현해놓는 습관을 들이는 것이 좋을것이다.

dispatchEvent(new CustomEvent(CustomEvent.SEND_DATA, "http://rinn.kr", true));


이벤트를 디스패치 할때 두번째 옵션인 csData 파라미터에 원하는 데이터를 실어서 보내면 된다.
이벤트 리스너에서 CustomEvent 가 캐치 되면 아래의 함수에서 처럼 데이터를 확인 할수 있다.

import csEvent.CustomEvent;

private function init():void
{
	this.addEventListener(CustomEvent.SEND_DATA, csEventHandler);
}

private function csEventHandler(e:CustomEvent):void
{
	trace(e.toString());
	trace(e.csData);
}

// trace ----------------
// [CustomEvent type=sendData bubbles=true cancelable=false eventPhase=3 csData 변수를 사용해서 넘어온 데이터를 사용하세요]
// http://rinn.kr


e.csData 형식으로 넘어온 데이터를 확인 할수 있다. 어떤 형식도 가능하고 여러개 보내는 것도 가능하다.

커스텀 이벤트를 만들어서 팝업으로 뜬 오브젝트에 데이터를 넘겨주고 닫힐때 변경된 내용을 메인 어플리케이션쪽으로 보내주고 하는 등의 작업이 가능하다.
이렇게 이벤트를 만들어서 사용하게 되면 컴포넌트를 만들어서 사용할때에 parent.publicFunction 형식으로 직접 접속해서 뭔가 하지 않아도 되기 때문에 독립적인 컴포넌트를 만들 수 있다.

보통은 컴포넌트를 만들때 해당 컴포넌트의 이벤트를 정리해서 한꺼번에 만드는 경우가 많다.

as3 에서 이벤트가 중요한 개념이듯이 이벤트를 본격적으로 사용하기 위해서는 커스텀 이벤트가 중요한 개념이라 하겠다.
이벤트를 잘 사용해서 프로젝트를 효율적으로 끝내보자!!
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +4

  • clone() 메소드의 경우, 이벤트 버블링이나, 타 컴포넌트에서 받은 이벤트를 릴레이 해줄 때 꼭 필요했던 것으로 기억하고 있어요.
    오래되서 자세히는 기억이 안 나지만, clone()을 제대로 구현하지 않으면 에러가 나는 상황이 있었던 것 같네요. 가물가물..

    • 처음에는 clone()을 구현을 해서 사용했었는데.
      완료되지 않은 작업중에 clone() 없이 그냥 테스트 하다가.. 동작에 이상이 없어서 그냥 놔둬버린 케이스가 있었지요.

      일단 수정은 해놔야 할것 같군요.. 아 습관이 중요한듯.. 귀차니즘을 이길수 있는건 좋은 습관뿐인거같아요..
      귀찮다 생각할 겨를도 없이 코딩이 자동으로 되버리는.. 그런 습관을 기르고 싶군요 ㅎㅎ

  • 뭐가 더 좋을 지는 저도 잘 모르겠어요.
    깨진 창문은 물론 피하는 것이 맞지만, 모든 창문을 항상 반짝이게 닦아놓는 것은, 때로는 도움이되고, 때로는 그렇지 않기도 하니까요. :')
    늘 상황에 맞춰서 그때 그때.. ㅎㅎ 다만, 미리 알아두는 것은 도움이 되겠지요. ㅎㅎ

    • 심오하군요..
      깨진 창문 이론.. 그건가요 ㅎㅎ
      사용하지 않더라도 일단은 알아두는것이 좋다는거에는 백프로 동감이에요~