JQuery 1.6의 가장 큰 변화! .prop() 함수.


  실제 프로젝트에서 jQuery를 적용중입니다. 기존 순수 Javascript를 사용할 때 보다 코드 양이 많이 줄어드는 것 때문에 저는 jQuery를 선호하는 편입니다. 그런데 1.4를 쓰다가 1.6대로 변경된 적이 있는데 이상하게 적용이 안되는 부분이 있었습니다.
  checkbox의 상태를 변경하거나 읽어올 때 '.attr()'함수를 이용했었는데 어느 순간부터인가 적용이 잘 안되었습니다. 단순 오류라고 생각하고
jObject[0].checked = "checked";
이렇게 javascript 객체로 변경해서 진행했습니다. (적용이 안되니 어떻게든 되게 해야져 ^^;;)
그런데 우연한 구글신과의 만남중에 정말로 우연히 1.6에서 변화가 있었다는 것을 알게되었습니다. 사용하고 있던 api가 이렇게 변경될 줄이야!!
  기존의 attr()로 처리되었던 것을 attr()과 prop()로 분리되어 처리되게 되었습니다.

.prop()
 


다음은 .attr()과 .prop()사용에 관한 구분입니다.
(출처:서디의 다락방:jQuery 1.6.1 릴리즈, 성능 , 버그 픽스 내용

Attribute/Property

.attr()

.prop()

accesskey

align

async

autofocus

checked

class

contenteditable

defaultValue


draggable

href

id

label

location *

multiple

nodeName


nodeType


readOnly

rel

selected

selectedIndex


src

style

tabindex

tagName


title

type

width **

저작자 표시

'Programming > jQuery' 카테고리의 다른 글

JQuery 1.6의 가장 큰 변화! .prop() 함수.  (2) 2011/12/20

Write your message and submit

MS-SQL서버를 iBatis와 사용할 때 <selectKey>사용시 유의사항


MS-SQL 서버를 iBatis를 사용할 때 insert처리하고 바로 identity값을 얻고자할 때 <selectKey>태그를 이용합니다. 이 때 SCOPE_IDENTITY()를 이용할 것을 권장합니다. 그러면서 대부분의 설명이 다음과 같이 되어 있습니다.

<insert id="createProjectBasicInfo" parameterClass="prjIdx">

        INSERT INTO PRJ_INFO (

            ...

        ) VALUES (

             ...

        )
    <selectKey keyProperty="prj_info_seq" resultClass="int"> 

        SELECT SCOPE_IDENTITY()

    </selectKey>

</insert>


하지만 위와같이 처리하면 다음과 같은 exception 발생합니다.

Exception in thread "main" com.ibatis.common.beans.ProbeException:Could not set property 'prj_info_seq' to value 'null' for domain.ProjectInfo. Cause: java.lang.IllegalArgumentException


위 오류를 해결하기 위해 상당수의 시간을 소비하였고 결국은 다음과 같이 해야 문제가 발생하지 않고 올바로 수행한다는 것을 발견했습니다.

<insert id="createProjectBasicInfo" parameterClass="prjIdx">

    <selectKey keyProperty="prj_info_seq" resultClass="int"> 

        INSERT INTO PRJ_INFO (

            ...

        ) VALUES (

             ...

        ) 

        SELECT SCOPE_IDENTITY()

    </selectKey>

</insert>


위에서 처럼 'SELECT SCOPE_IDENTITY()'를 사용하지 않고 'SELECT IDENT_CURRENT('table')'를 사용한다면 최상단의 로직으로 수행해도 잘 수행이 됩니다. 하지만 SELECT IDENT_CURRENT은 여러 사용자가 동시에 접속해서 사용하는 시스템은 값을 절대 보장할 수 없기 때문에 SCOPE_IDENTITY() 사용을 권장하고 있습니다. 


 
저작자 표시
  • 이거 없었음 완전 머리 깨질 뻔했습니다
    어이 없지만 왜 다른지 모르겠네요.. 하여간 이것때문에 문제를 쉽게 해결해서 기쁩니다.

    • ^^ 도움이돼셨다니 기분 좋네요. 그동안 로그인 암호를 몰라 이제야 댓글을 남깁니다 ^^

Write your message and submit

대용량 데이터 엑셀파일 생성


 엑셀 다운로드는 지원하는 라이브러리가 여럿 존재하기 때문에 어디서든 예제를 참고할 수 있다. 하지만 데이터량이 많을 경우 엑셀 파일 자체가 커지므로 메모리 문제가 발생하게 된다. 대용량의 엑셀을 생성하는 예제는 찾아보기 힘들었다. 그리고 여담이지만 대용량의 데이터를 엑셀로 생성하는 것은 하지 않는 것이 좋을 듯 싶다. 
 이번 요구사항에서 db 내용을 엑셀파일로 다운로드 할 수 있게 해 달라는 요구 사항이 있었다. 물로 우려한 대로 대용량이다. 그래서 찾은 예제가 다음 사이트에서 소개 되고 있다.
대용량 엑셀은 'xlsx'.

 라이브러리는 일단 apache의 POI를 사용하게 된다. 대용량 엑셀은 MS 엑셀 2007부터 지원하는 'xlsx'확장명으로 한다. 대략 설명하면 xlsx는 xml파일들을 압축형태로 구성된 파일이다. 이 참고 예제에서는 data를 xml 파일로 작성하고 이후에 파일 압축을 통해 처리한다. 

Row단위로 fetch마다 파일 작성.

 또한 고려해야 할 부분이 현재 ibatis를 db framework으로 사용하는데 모든 data를 조회해서 fetch후 메모리에 올린 다음에 엑셀 파일을 쓰는 형태로 한다면 당연히 메모리 문제가 발생할 것이다. 그래서 각 row를 fetch할 때 마다 엑셀파일을 써 내려가는 형태가 되어야 한다. 이 때 사용할 수 있는 것이 ibatis에서 지원하는 RowHandler를 이용한다. RowHandler을 구현하면 각 row단위로 fetch하면서 처리할 수 있게 할 수 있다.

참고 예제

 적용된 공통 소스를 첨부한다. 정리가 되지 않은 상태로 급하게 작성하느라 좀 부끄러운 소스다.


DAO내에서 다음과 같이 사용한다.
public class ExclDAOImpl extends BaseBigExcelDownDAO implements ExclDAO {

...
    @Override
    public void getDiaryExcelData(StatisticsVO pVo, String targetSheetFilePath,
            String templeteSheetFilePath) throws RuntimeException {
        LinkedHashMap<String, String> sheetMap  = new LinkedHashMap<String, String>();
        sheetMap.put("buzYy"            , "년도"        );
        sheetMap.put("buzYNo"           , "기수"        );
        sheetMap.put("centNm"           , "센터명"        );
        sheetMap.put("mngrNm"           , "사례관리자"        );
        sheetMap.put("userNm"           , "참여자"        );
        sheetMap.put("cnslMakeStatDesc" , "초기상담지"        );
        sheetMap.put("cnslDt"           , "상담일자"        );
        sheetMap.put("cnslDueDt"        , "상담예정일"        );
        sheetMap.put("cnslTypeDesc"     , "상담유형"        );
        sheetMap.put("cnslWayDesc"      , "상담방법"        );
        sheetMap.put("cnslPlace"        , "상담장소"        );
        sheetMap.put("cnslTime"         , "상담시간"        );
        sheetMap.put("cnslTopic"        , "상담주제"        );
        sheetMap.put("cnslCentNm"       , "상담센터명"        );
        sheetMap.put("cnslMngrNm"       , "상담사례관리자"        );
        
        createSheetFile("Excl.getDiaryExcelData", pVo, sheetMap, targetSheetFilePath, templeteSheetFilePath);
    }

...
}

"Excl.getDiaryExcelData" : ibatis에 명시한 query id
pVo: 조회조건을 갖고 있는 vo
sheetMap : 상단에 정의 했듯이 excel의 첫 라인에 작성될 header명과 query의 컬럼명
targetSheetFilePath : 실제 작성될 결과물 xlsx 파일 path
templeteSheetFilePath : 현재 예제를 통해서 xlsx파일을 작성할 때는 temp파일이 필요한데 바로 그 파일의 path정보.

마무리...

 공통소스라고 첨부한 파일의 소스는 이번 글에서 명시 하지 않는다. POI라이브러리 사용과 RowHandler를 사용하는 등의 내용이 주이다. 다음에 상황이 될 때 공통 소스를 설명할 기회가 있을지 모르겠지만 아무튼 일단 좀더 상세 내용은 다음으로 미룬다.

저작자 표시

Write your message and submit

사용하고 있는 오라클 시스템의 버젼을 확인 하는 방법


다음의 쿼리를 수행하면 버전을 확인 할 수 있다.

SELECT * FROM V$VERSION;

수행 결과는 다음과 같이 출력된다.


저작자 표시

Write your message and submit

[안드로이드] ListView 사용법 (Item추가, custom Adapter 작성)


  ListView는 Adapter를 통해서 Item을 제어합니다. Adapter를 custom 으로 작성하면 item의 구성 및 기타 스타일 또한 일일히 변경가능합니다. 다음과 같이 ArrayAdapter을 상속한 custom adapter을 작성합니다. Activity 내에 다음과 같은 inner class로 작성을 했습니다.

        private SearchItemAdapter adapter;

        ... 
        adapter = new SearchItemAdapter(this, R.layout.searcharitemsrow, arItems);
        resultListView.setAdapter(adapter);
        resultListView.setDividerHeight(1);
        ...

    private class SearchItemAdapter extends ArrayAdapter<CustomItem> {
        
        public Vector<CustomItem> items ;
        private int textViewResourceId;
        
        public SearchItemAdapter(Context context, int textViewResourceId, Vector<CustomItem> items) {
            super(context, textViewResourceId, items);
            this.items = items;
            this.textViewResourceId = textViewResourceId;
        }
        
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            
            View view = convertView;
            if (view == null) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = vi.inflate(this.textViewResourceId, null);
            }
            
            if(items!=null && items.size() > 0) {
                CustomItem item = items.get(position);
                if(item != null) {
                    TextView nmView = (TextView) view.findViewById(R.id.searchRow_nm);
                    nmView.setText(item.getName());
                }
            }
            
            return view;
        }
    }

생성자를 구성하고 getView(...) method를 구현합니다. 이 때 CustomItem는 각 Item에 적용할 data를 보유하고 있는 객체입니다. getView는 각 item을 어떻게 구성 할 것인지를 구현합니다.

adapter = new SearchItemAdapter(this, R.layout.searcharitemsrow, arItems);
이 부분에서 adapter 객체를 생성하고 ListView에 adapter로 등록하고 사용하면 됩니다. "searcharitemsrow"는 layout을 구성한 xml 명입니다. row한 단위의 layout을 지정해 놓습니다.

이렇게 구성된 ListView에서 row(Item)을 변경한다면 adapter의 객체를 조작하면 됩니다.

adapter.clear() -  ListView의 모든 row가 제거됨.
adapter.add(customItem) - ListView에 row를 추가
CustomItem adapter.getItem(int position) - 해당 index의 item 객체 얻기

등의 작업을 통해 제어 할 수 있습니다. adapter의 기타 method를 통해 더 다양한 처리가 가능합니다.
저작자 표시

Write your message and submit

오라클 문자컬럼에서 숫자타입이 아닌 문자가 존재하는 컬럼 구하기


  프로젝트 진행 중에 VARCHAR2 컬럼에 숫자값을 입력하는 경우가 존재하는데 숫자가 아닌 문자가 들어간 DATA를 걸러내야 할 때가 있다. 다음과 같이 하면 양수의 숫자만 들어간 컬럼만 찾아낼 수 있다. 
  오라클 함수중에 REGEXP_INSTR(...)이 있는데 정규식을 이용해서 해당 컬럼의 원하는 정규식 pattern의 자리수를 얻어오는 것이다.

SELECT COL FROM (
    SELECT '12.0' AS COL FROM DUAL
    UNION ALL SELECT '52/0' FROM DUAL
    UNION ALL SELECT '52U0' FROM DUAL
    UNION ALL SELECT '%2U0' FROM DUAL
) T 
WHERE  REGEXP_INSTR(T.COL , '[^{.1234567890}]') <= 0

수행 결과는 다음과 같다.

COL
----
12.0

저작자 표시

Write your message and submit

ORA-01009:필수 매개변수가 없습니다.


  회사 업무처리중에 오라클 오류메시지를 만났습니다. ‘ORA-01009’! 필수 매개변수가 없다고 하는데 쿼리에는 특별히 문제가 없었습니다. 구글신에게 물어봤습니다. 구글신은 쿼리에 주석을 달때 이 런문제가 생긴수 있다는 말이 있었습니다. 주석 중에 /* */ 사이에 주석 내용을 입력할 때 한칸씩 떼어야 한다던가 -- 문제 다음에 한칸을 반드시 떼어야 한다는 내용이었습니다. 다음과 같이 말이죠.
/* 주석내용 */
-- 주석 내용
그래서 살펴봤더니 주석이 존재하고 있었습니다. 그런데 -- 다음에 한칸이 떨어진 정상적인 상태였습니다. 그래서 아주 주석을 삭제하고 처리해 봤지만 마찬가지로 오류가 발생했습니다. 구글신은 그 다음의 TIP을 주지 못했습니다. 무려 5시간 끝에 해결했습니다.

쿼리는 다음과 같은 형태였습니다.

WITH AAA AS (
   SELECT AAA FROM TABLE000
)
SELECT ... FROM AAA, BBB
WHERE ...

이렇게 된 쿼리를 JAVA에서 StringBuffer로 append 처리해서 쿼리 스트링을 구성하고 있었습니다. 해결은 다음과 같습니다.

SELECT * FROM (

   WITH AAA AS (
       SELECT AAA FROM TABLE000
   )
   SELECT ... FROM AAA, BBB
   WHERE ...

)

이렇게 WITH절이 가장 밖에 노출 되었던 형태를 한번 더 감싸서 SELECT 문을 단순 변경 했습니다. 그러고 나니 정상적으로 수행되었습니다.
참고로 Local에서 테스트 할 때는 문제 없었던 내용이었으나 Real 서버에 deploy한 뒤 발생한 문제였습니다. Local 환경과 Real 서버 환경은 다음과 같습니다.

Local :  Windows7, jdk 1.4.2 16, Tomcat 5.0
Real :  SonOs 5.9, jdk 1.4.2 16, Jeus 42

정말 이럴 때는 어떻게 처리해야 할 지... 이글 참고하시어 만일 이런일 이 생기셨을 때 저처럼 5시간 넘게 시달리지 마시길 빕니다.
저작자 표시
  • 혼자 주말근무 나와서 동일 메세지로 끙끙대던중
    이글이 도움이 되었습니다

    쿼리는 동일 방식을 사용하지만(유지보수를 위해서라나)
    전 주석만 고쳐서 해결이 된 케이스네요

    감사합니다

  • 도움이 되셨다니 기쁘네요 ^^

Write your message and submit

안드로이드:Activity 방향 고정 방법


안드로이드 초짜가 샘플소스를 테스트하는데 항상 가로로 수행이되더군요. 그래서 찾아봤습니다.

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

위의 부분이 바로 방향을 가로로 고정시킨 부분이었습니다. 
세로로 고정을 하고자 한다면 다음의 속성을 사용하면 됩니다.
ActivityInfo.SCREEN_ORIENTATION_PORTAIT


저작자 표시

Write your message and submit

Android 구조도




저작자 표시

'Programming > Android' 카테고리의 다른 글

Android 구조도  (0) 2010/09/10

Write your message and submit

오라클 사용자 예외처리 사용 방법


  PL-SQL 작성시 오라클 저장함수 RAISE_APPLICATION_ERROR를 사용하여 사용자 정의 예외를 다룰 수 있다. 우리히가 흔히 보는 'ORA-XXXXX'이런 코드를 작성해서 메시지와 함께 발생시킬 수 있다. 숫자 범위는 -20000부터 -20999의 범위 내에서 가능하다.

CREATE OR REPLACE FUNCTION FN_GET_MACHINE_NO(
       l_cd IN VARCHAR2
      ,m_cd IN VARCHAR2
      ,s_cd IN VARCHAR2
) RETURN VARCHAR IS  retval VARCHAR2(14);

  seqNextVal VARCHAR(7);
  lCdVal     VARCHAR(1);
  mCdVal     VARCHAR(2);
  sCdVal     VARCHAR(3);
  INPUT_ERR  EXCEPTION;
  OUTPUT_ERR EXCEPTION;

BEGIN
     seqNextVal := 0;
     lCdVal := TRIM(l_cd);
     mCdVal := TRIM(m_cd);
     sCdVal := TRIM(s_cd);
  
     BEGIN 
           -- 20100823 LCS 수정 : 소분류가 NULL이면 '99'기본값 설정.
           IF(sCdVal IS NULL) THEN
               sCdVal := '99';
           END IF;
         
           IF( lCdVal IS NULL OR mCdVal IS NULL ) THEN
               RAISE INPUT_ERR;
           ELSE
               SELECT SUBSTR( LPAD(DQ_DQMACHN_INDEX.NEXTVAL , 12, '0') , 6, 7)
                 INTO seqNextVal
               FROM DUAL  ;
     
               retval := lCdVal || mCdVal || sCdVal || TO_CHAR(SYSDATE, 'YY') || seqNextVal  ;
           END IF;
           
           IF LENGTH(retval) <> 14 THEN
              RAISE OUTPUT_ERR;
           END IF;
     
     EXCEPTION
     
         WHEN INPUT_ERR THEN

           IF( lCdVal IS NULL ) THEN
                -- 대분류코드값이 없을 때 Exception 발생
                RAISE_APPLICATION_ERROR(-20998,'전달된 파라미터(분류코드)에 문제가 있습니다(대분류 코드값이 없습니다.)');
           ELSIF( lCdVal IS NULL OR mCdVal IS NULL ) THEN
                -- 중분류코드값이 없을 때 Exception 발생
                RAISE_APPLICATION_ERROR(-20998,'전달된 파라미터(분류코드)에 문제가 있습니다(중분류 코드값이 없습니다.)');
           END IF;
           
         WHEN OUTPUT_ERR THEN
           --DBMS_OUTPUT.PUT_LINE('생성된 기기관리번호('||retval||')는 14자리가 아닙니다.');
           RAISE_APPLICATION_ERROR(-20999,'생성된 기기관리번호('||retval||')는 14자리가 아닙니다.');
         WHEN NO_DATA_FOUND THEN
           NULL;
         WHEN OTHERS THEN
           NULL;
     END;
     
RETURN retval;

END FN_GET_MACHINE_NO;

  위 예제에서 처럼 최상단에 exception을 선언하고 중간에 RAISE를 사용해서 특정 조건에 만족하면 Exception을 발생시키고 하단에 RAISE_APPLLICATION_ERROR(...) 함수를 사용해서 구체적인 에러코드와 메시지를 구성해서 발생시키면 된다.
  이렇게 사용하게되면 Application단에서 exception 다루는 방법 그대로 잡아낼 수 있다. ORA-20999 Exception이 발생하게 된다.
저작자 표시

Write your message and submit