사실 요번 편은 foreach문이 주인공이 아니다.

where절에 foreach문을 쓰고 싶은데 넘어온 파라미터가 배열이 아닐 때 배열형으로 만들어 주는 함수를 구현해본다.

 

[html]

<form name="frm" method="post">

<input type="checkbox" name="p_codes" value="01">신축

<input type="checkbox" name="p_codes" value="02">보수

<input type="checkbox" name="p_codes" value="03">증축

</form>

이 세 개의 체크박스를 모두 체크하고 submit을 했다고 치자.

 

code값이 01이거나 02이거나 03인것을 갖고 오는 쿼리문을 작성한다고 할 때 웬지 foreach문이 쓰고 싶다면 

아래함수를 만들어 배열로 구현해준다.

[Utils.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
public static  List <String> makeForeach (String s, String gb){
    List<String> list =   new ArrayList<String>();
    String[] aCode = s.split(gb);
 
    if (s == null || "".equals(s)) {
        return null;
    }
    for(int i=0; i< aCode.length; i++){
        list.add(aCode[i].toString());
    }
 
    return list;
}
cs

 

이제 파라미터를 받아서 배열로 변경해보자. logger로 찍어보면 배열로 찍힐 것이다.

1
List<String> list p_codes = Utils.makeForeach(Utils.nullToStr(parms.get("p_codes")), ","); //여기서 콤마는 구분자임. 다른 구분자로도 사용가능
cs

 

 

그리고 마무리로 foreach를 사용한 쿼리문

[query.xml]

1
2
3
4
5
6
<if test='p_codes !=null'> 
AND CODE IN
<foreach collection="p_codes" item="code" index="index" separator="," open="(" close=")">
        #{code}
</foreach>
</if>
cs

숫자 타입은 사실 별건 없다.

xtype을 numberfield로만 지정해주면 특별할건 없지만서도...그리드에서는 숫자끼리 연산이 일어날 수 있으니 이 예제까지 구현해 보려고 한다. (원가 * 갯수라든가...)

 

1. 일반

1
2
3
4
5
6
7
8
9
10
11
12
{
    xtype : 'numberfield',
    name : 'con_amt',
    id : 'con_amt',
    emptyText : '0',
    labelAlign : 'right',
    fieldLabel: '공사대금',
    labelWidth: 80,
    width : 180,
    maxValue: 1000000000//최고값
    minValue: 10000 //최저값
}
cs

2. 그리드

1
2
3
4
5
6
7
8
9
10
11
12
{
    header: '단가',
    dataIndex : 'COST',
    align : 'right',
    width : 120,
    editor: new fm.NumberField({
        allowBlank: false,
        maxValue: 999999999//
        minValue: 0 //최저값
    }),
    renderer : Ext.util.Format.number(value, "0,000") //표현 식
}
cs

 

3. 그리드 셀값 연산

단가 COST값과 수량 QTY값을 곱해서  금액 AMOUNT에 셋팅해주는 코드이다.

editor안에 listeners를 정의하고 그 안에 change함수를 써서 값이 변할 때마다 이벤트가 발생한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
{
    header: '수량',
    dataIndex : 'QTY',
    align : 'center',
    width : 80,
    editor: new fm.NumberField({
        allowBlank: false,
        maxValue: 999999999,
        minValue: 0,
        listeners : {
            change : function(f, e, g) {
                var grid = f.up("grid");
                var row = grid.getSelection()[0]; //현재 행
                var cost = row.get("COST");       //현재 행의 COST값
                var qty = e;                      //선택한 셀의 값
                var amount = 0;
 
                if(cost == null || cost == "") cost = 0;
                if(qty == null || qty == "") qty = 0;
 
                amount = qty * cost;
 
                row.set("AMOUNT", amount);      //현재 행의 AMOUNT에 계산된 값을 셋팅
            }
        }
    }),
    renderer : Ext.util.Format.number(value, "0,000")
},{
    header: '단가',
    dataIndex : 'COST',
    align : 'right',
    width : 120,
    editor: new fm.NumberField({
        allowBlank: false,
        maxValue: 999999999,
        minValue: 0,
        listeners : {
            change : function(f, e, g) {
                var grid = f.up("grid");
                var row = grid.getSelection()[0]; //현재 행
                var cost = e;                      //선택한 셀의 값
                var qty = row.get("QTY");         //현재 행의 QTY값
                var amount = 0;
 
                if(cost == null || cost == "") cost = 0;
                if(qty == null || qty == "") qty = 0;
 
                amount = qty * cost;
 
                row.set("AMOUNT", amount);
            }
        }
    }),
    renderer : Ext.util.Format.number(value, "0,000")
},{
    header: '금액',
    dataIndex : 'AMOUNT',
    align : 'right',
    width : 120,
    editor: new fm.NumberField({
        allowBlank: false,
        maxValue: 999999999,
        minValue: 0
    }),
    renderer : Ext.util.Format.number(value, "0,000")
}
cs

 

- 끝 -

'extjs' 카테고리의 다른 글

ExtJs 셀렉트박스, 콤보박스 xtype:combobox  (0) 2019.09.02
ExtJs 날짜타입 xtype : datefield  (0) 2019.09.02
ExtJs grid panel 기본구조 및 listener  (0) 2019.08.30
ExtJs 초간단 소개  (0) 2019.08.30

extjs에서 셀렉트박스를 쓰려면 xtype combobox를 쓴다.

콤보박스는 필수적으로 store가 필요한데 이는 store에 직접 데이터를 정의해도 되고 ajax통신으로 db에서도 가져올 수 있다. 

이번 편에서는 data store정의와 이를 이용한 콤보박스 구현을 해보겠다.

 

우선 store를 살펴보자

1번 storeCodeList는 스토어정의부분에 데이터를 직접 정의했다.

2번 storeBigCate는  getBigCateList.do라는 java단을 호출하여 ajax로 DB에서 데이터를 가져오도록 하고 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//1. store에 데이터를 직접 정의
var storeCodeList = Ext.create('Ext.data.Store', {
    fields: ['code','code_nm''b_cate''s_cate'],
    data: [
        {code: '01', code_nm: '신축', b_cate:1, s_cate : '1101'},
        {code: '02'code_nm'보수', b_cate:2, s_cate : '1202'},
        {code: '03'code_nm'증축', b_cate:3, s_cate : '1301'}
    ]
});
 
//2. ajax통신으로 db에서 데이터를 불러옴
var storeBigCate = Ext.create('Ext.data.Store', {
    autoLoad : true,
    fields: ['b_cate','cate_nm'],
    proxy : {
            type : 'ajax',
            actionMethods : {
                read : 'POST'
            },
            url : 'getBigCateList.do',
            reader : {
                type : 'json',
                rootProperty : 'list' //getBigCateList.do에서 list라는 이름으로 데이터를 셋팅해줘야함. ex) parms.put("list", cateList);
            }
    }
});
cs

 

그럼 본격적으로 콤보박스 구현을 해보자

이번에도 일반적인 구현과 grid위에 구현하는 방법 두가지를 소개한다.

 

1. 일반

1
2
3
4
5
6
7
8
9
10
11
12
{
    xtype : 'combobox',
    editable : true,
    queryMode: 'local',
    name : 's_code'//객체명
    id : 's_code',
    emptyText : '코드선택..',
    displayField: 'code_nm'//코드명
    valueField: 'code'//코드값
    width : 160,
    store : storeCodeList
}
cs

이 콤보박스의 이름과 id는 s_code이며 옵션값은 code, 표시되는 내용에는 code_nm이 들어갈 것이다.  값을 선택 전에는 '코드선택..'이라고 표시가 된다.

2. 그리드패널

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    header: '대분류',
    dataIndex : 'BIG_CATE',
    align : 'center',
    width : 160,
    editor: new Ext.form.ComboBox({ //콤보박스 구현
        displayField: 'cate_nm',
        valueField: 'b_cate',
        editable: true,
        forceSelection: true,
        mode: 'local',
        store: storeBigCate,
        triggerAction: 'all'
    }),
    renderer: function(val) { //선택한 값 selected로 보여주기
        var recordIndex = storeBigCate.find('b_cate', val); 
 
        if (recordIndex === -1) {
            return '선택';
        }
 
        return storeBigCate.getAt(recordIndex).get('cate_nm'); 
    }
}
cs

그리드에서는 editor로 콤보박스를 구현하고 renderer로 선택된 그리드의 값을 보여준다.

일반 패널에서 쓸때와 grid패널에서 쓸때가 살짝 차이가 있어서 두 가지로 정리해보겠다.

 

1. 일반

1
2
3
4
5
6
7
8
9
10
11
12
13
{
    xtype: 'datefield',
    name'record_dt',
    id : 'record_dt',
    emptyText: '등록일자',
    labelAlign : 'right',
    align : 'center',
    width : 130,
    format: 'Y-m-d',
    submitFormat:'Y-m-d',
    value: new Date("1980-01-01"), //디폴트 날짜 셋팅. 안하면 빈 값이다.
    renderer : Ext.util.Format.date(new Date(value), "Y-m-d"//표시되는 날짜 형식
}
cs

 

2. grid 패널

그리드패널은 조금 선언을 다르게 해줘야한다. 그리드의 데이터 컬럼 안에서 편집을 하는 것이기 때문에 editor로 선언해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
columns :[
    {
        header: '등록일자',
        dataIndex : 'record_dt',
        align : 'center',
        width : 100,
        readOnly : true,
        format: 'Y-m-d',
        submitFormat:'Y-m-d',
        editor: new fm.DateField({
             xtype: 'datefield',
             format: 'Y-m-d'
        }),
        renderer : Ext.util.Format.date(new Date(value), "Y-m-d")//표시되는 날짜 형식
    }
]
cs

그리드의 경우는 그리드데이터를 가져온다. 대신 쿼리에서 표시하고 싶은 형식을 맞춰 줘야한다.

record_dt컬럼의 데이터 타입이 varchar2라면 '2019-05-25'로 저장을 하거나 to_date(record_dt, 'YYYY-MM-DD')로 변환해서 가져온다. datetime으로 저장되어있다면 to_char(record_dt, 'YYYY-MM-DD')로 가져오는게 좋을 것 같다.

 

이리하여 끝이면 좋겠지만 여러분의 DB 테이블의 record_dt컬럼의 데이터 타입이 datetime이 아니고 string형(char나 varchar)이라면 조금 귀찮아진다. 

datefield는 선택된 날짜를 string형이 아닌 date타입으로 넘겨준다. 때문에 넘겨주기 전에 string형으로 바꿔주는 작업이 필요하다. 아래의 예제를 보면 두 가지 경우가 나와있는데 seachBtn은 일반적인 경우, saveGridRow는 그리드에서 넘어온 경우로 보면 된다. 둘 다 큰 차이 점은 없고 store의 파라미터로 셋팅을 해주냐 저장할 row데이터에 다시 값을 셋팅해주느냐 정도의 차이로 보면 된다. 필요한 부분을 보고 갖다 쓰시길.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
var controller = Ext.create('Ext.app.ViewController', {
     /**
     * 검색버튼 클릭
     */
     searchBtn : function(btn) {
        var store = storeList;
        var view = this.getView();
        var record_dt = view.down("[name=record_dt]").getValue(); //패널에 있는 record_dt값을 가져온다.
        
        var dt = new Date();
        var tmp_m, tmp_d, conv_date;
 
        dt = new Date(record_dt);
        tmp_m = dt.getMonth()+1;
        tmp_d = dt.getDate();
        conv_date = dt.getFullYear().toString() +(tmp_m >9?tmp_m:"0"+tmp_m.toString()) + (tmp_d>9?tmp_d:"0"+tmp_d.toString());
        record_dt = conv_date; //string형으로 변환
        
        store.getProxy().setExtraParam("record_dt",record_dt); //스토어 파라미터값에 셋팅
        store.removeAll();
        store.currentPage = 1;
        store.load(); //스토어 리로딩
     }
    ,/**
    * 저장
    */    
    saveGridRow : function(btn) {
        var grid = btn.up("grid");
        var store = btn.up("grid").getStore();
        var saveRow = grid.getSelection(); //변동이 있는 row 가져옴 ->저장대상
        
        if(saveRow.length > 0 ){
            for (var i = 0; i < saveRow.length; i++) {
                if( saveRow[i].data.record_dt != "" && saveRow[i].data.record_dt !=  undefined) {
                    var dt = new Date(saveRow[i].data.record_dt.toString());
                    var tmp_m = dt.getMonth()+1;
                    var tmp_d = dt.getDate();
                    var comp_date = dt.getFullYear() +"-" + (tmp_m >9?tmp_m:"0"+tmp_m) +"-" + (tmp_d>9?tmp_d:"0"+tmp_d);
 
                    saveRow[i].data.record_dt =  comp_date; //string형으로 변환된 값을 saveRow에 다시 셋팅
                }
            }
        }
        
    }
});
cs

 

오랜만에 블로그를 하니 세상이 좋아졌다.

블로그의 기본 소스 수정 없이 코드만 넣으면 태그까지 생성해서 클립보드에 복사해주는 세상이라니!

 

https://colorscripter.com/

 

Color Scripter

Simple & Flexible Syntax HighLighter

colorscripter.com

위 사이트에 접속해서 본인의 소스코드만 넣어주면 알아서 예쁘게 태그를 생성해준다.

그러면 편집모드를 html로 하고 붙여넣기만 하면 끝!

언어선택하면 언어별로 이쁘게 만들어주기도 한다.

 

여기서 주의할점! 

* 탭키가 먹지 않는다 : 코드 정리한답시고 블럭지정하고 탭키 누르는 순간 님의 소스가 다 날아가는 것을 보게 될 것이다.

* ctrl+z 도 먹지 않는다 : 당황했다고 컨트롤 제트를 백번 눌러봤자 복구되지 않는다. 그냥 백업이 답임.

* 이 사이트는  에디터가 아님을 항상 명심하고 최종 소스 붙여넣기만 하는 것으로 한다.

 

'기타' 카테고리의 다른 글

bat파일 작업스케줄러 걸기  (0) 2015.01.08
facebook 공유링크 캐쉬 삭제  (0) 2014.06.16
SNS 링크걸기  (0) 2014.06.09
티스토리에 소스코드 넣기  (0) 2013.12.13

그리드 기본 구조는 아래와 같다.
controller, store, panel이 정의가 되어있어야 함.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
Ext.onReady(function(){
    //Main Controller
    var controllerList = Ext.create('Ext.app.ViewController', {
        alias : 'controller.useList',
        /**
        * 최초데이터로드
        */    
        onLoadData : function() {
            var store = storeList;
            store.removeAll();
            store.load();
        },
        clickBtn : function(btn){
            //버튼클릭 이벤트
        }
    });
    
    var storeList = Ext.create('Ext.data.Store', {
        fields: ['code','cate_nm''b_cate''s_cate'],
        data: [
            {code: '01', cate_nm: '신축', b_cate:1, s_cate : '1101'},
            {code: '02', cate_nm: '보수', b_cate:2, s_cate : '1202'},
            {code: '03', cate_nm: '증축', b_cate:3, s_cate : '1301'}
        ]
    });
    
    var storeBigCate = Ext.create('Ext.data.Store', {
        fields: ['b_cate','code_nm'],
        data: [
            {b_cate: 11, cate_nm: '대분류1'},
            {b_cate: 12, cate_nm: '대분류2'},
            {b_cate: 13, cate_nm: '대분류3'}
        ]
    });
    
    var storeSmallCate = Ext.create('Ext.data.Store', {
        fields: ['b_cate''s_cate','code_nm'],
        data: [
            {b_cate: 11, s_cate: '1101', code_nm: '대분류1_소분류1'},
            {b_cate: 11, s_cate: '1102', code_nm: '대분류1_소분류2'},
            {b_cate: 12, s_cate: '1201', code_nm: '대분류2_소분류1'},
            {b_cate: 12, s_cate: '1202', code_nm: '대분류2_소분류1'},
            {b_cate: 12, s_cate: '1203', code_nm: '대분류2_소분류3'},
            {b_cate: 13, s_cate: '1301', code_nm: '대분류3_소분류1'}
        ]
    });
        
    var mainPanel = Ext.create('Ext.grid.Panel', {
             iconCls: 'x-fa fa-archive',
             title : "자산목록",
             renderTo: document.getElementById('body-text'),  //html페이지 안에 id가 body-text인 div에 이 panel이 그려짐
             frame: true,
             height: 700,
             width: 1300,
             controller: controllerList,  //controrller 지정
             disabled : false,
             selModel: {
                    type: 'checkboxmodel'
             },
             plugins: {
                ptype: 'cellediting',
                clicksToEdit: 1
             },
             viewConfig : {
                emptyText : '데이터가 존재하지 않습니다'
             },
             border: true,
             listeners : {
               boxready : function(){
                   controllerList.onLoadData(); //panel이 로딩될때 호출되는 함수 
               },
               rowclick : function(btn){
                   //rowclick시 발생 이벤트
               },
               cellclick : function(grid, record){
                  //cell click시 발생이벤트
               },
               beforeedit : function(f, c){
                  //편집 전 수행하는 이벤트
               }
             },
             store : storeList, //이 grid의 데이터
             tbar : [
                 //grid 상단. 주로 검색기능을 넣는다
             ],
             columns : [
                 //grid 데이터 출력
                 { 
                      xtype: 'rownumberer'
                      width : 50 
                 },{ 
                      header: '코드'
                      dataIndex : 'code'
                      align : 'center'
                      width : 110 
                 },{ 
                      header: '코드명'
                      dataIndex : 'code_nm'
                      align : 'center'
                      width : 110 
                 },{                       
                      header: '대분류'
                      dataIndex : 'b_cate'
                      align : 'center'
                      width : 110 
                      editor: new Ext.form.ComboBox({
                            displayField: 'cate_nm',
                            valueField: 'b_cate',
                            editable: false,
                            forceSelection: true,
                            mode: 'local',
                            store: storeBigCate,
                            triggerAction: 'all'
                      }),
                      renderer: function(val) {
                            var recordIndex = storeBigCate.find('b_cate', val);
                            if (recordIndex === -1) {
                                return '선택';
                            }
                            return storeBigCate.getAt(recordIndex).get('cate_nm');
                      }
                 },{                       
                      header: '소분류'
                      dataIndex : 's_cate'
                      align : 'center'
                      width : 110 
                 }
             ],
               bbar : { //grid 하단. 주로 페이징을 넣는다.
                     xtype: 'pagingtoolbar',
                     displayInfo: true,
                    // displayMsg: 'Page {0} - {1} of {2}',
                     displayMsg: '',
                     emptyMsg: "No Data"
               }
    });
});
cs

우선 이번 포스트에선 listeners의 기능을 살펴보도록한다.

listeners는 뭔가 액션이 있을 때 이벤트를 설정해 줄 수 있는 기능이다.

소개할 이벤트 들은 boxready, rowclick, cellclick, beforeedit이다.

 

boxready : 말 그대로 panel이 로딩되었을 때 실행하는 함수다. 보통은 grid이므로 불러올 store(데이터)를 로딩한다.
               아래 소스는 controllerList에 정의되어있는 onLoadData()라는 함수를 호출하라는 것인데 이 함수에는 grid 
               에 뿌려줄 storeList를 로딩하라고 되어있을것이다 아마도...

1
2
3
boxready : function(){ 
        controllerList.onLoadData(); //panel이 로딩될때 호출되는 함수  
}
cs

 

rowclick : grid의 row를 클릭했을 때 발생하는 이벤트이다. 선택한 행의 정보를 갖고 올 수 있다.

1
2
3
4
5
6
7
8
9
rowclick : function(btn){
    var grid = btn.up("grid"); 
    var row = grid.getSelection()[0]; //선택한 행 객체
    var thisdidx = btn.lastFocused.rowIdx; // 선택한 행의 인덱스. 이 코드에서는 쓰이지 않지만 다른데서 이 인덱스 값으로 선택한 행을 컨트롤 할 수 있음.
    var idx = row.get("IDX");         //선택한 행에서 IDX라는 컬럼의 값을 가져옴
 
    $("#pkid").val(idx);    
    $("#frm").attr("action""Detial.do").submit(); //상세페이지로 넘어간다.
cs

 

cellclick : grid의 셀을 클릭했을 때 발생하는 이벤트이다. 선택한 셀의 정보를 갖고 올 수 있다. 예를 들면 코드값을

             클릭했을 때  controller에 있는 clickBtn함수를 호출하고 싶다 했을 때  아래와 같이 구현할 수 있다.

1
2
3
4
5
cellclick : function(grid, e, c, r){
    if(c == 2){ //code는 두번쨰 컬럼이므로 2
        controllerList.clickBtn(e);
    }
}
cs

나중에 rowclick과 cellclick을 이용하여 팝업(모달창)을 띄워 데이터를 주고받는 소스를 구현해 보겠다.

 

beforeedit : 마지막으로 소개할 beforeedit은 그리드안의 셀을 편집하기 전에 로딩이 되는 함수이다. 

사실 이 포스팅은  이 함수를 소개하기 위해 썼다해도 과언이 아니다. b_cate가 대분류고 s_cate가 소분류이고 둘 다 에디터는 combobox이다.  b_cate값을 선택할 때마다 s_cate의 콤보박스가 변경된다고 가정해보자.

이 함수가 실행되는 것은 s_cate셀을 선택했을 때이다.  이 때 같은 row의 b_cate값을 가져와서 storeSmallCate에 파라미터를 날려 새로 로딩을 한다. 그리고 s_cate는 콤보박스 에디터로 변경을 해준다.

예를 들어 대분류1을 선택했다면 b_cate값이 11이므로 b_cate값이 11인 1101,1102 소분류만 불러와서  s_cate 콤보박스 에디터에 셋팅이 될것이다. 

* storeSmallCate는 실제로는 DB단의 쿼리로 구현해야한다. 위의 코드에 정의되어있는 store로는 실행되지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
beforeedit: function(f, c) {
    var s_cate_obj = this.columns[4]; //소분류카테 객체
 
    var thisdidx = c.rowIdx; //선택한 row 인덱스
    var row = mainPanel.getStore().getAt(thisdidx, true); //선택한 row 객체
 
    var b_cate = row.get("b_cate"); //선택한 row의 b_cate값
 
    //소분류카테 store 리로드 * 소스상에는 그냥 로데이터로 store 셋팅이 되어있지만 실제로는 db에서 쿼리문 조건절에 b_cate값으로 질의할 수 있다고 가정
    var store = storeSmallCate;
    store.getProxy().setExtraParam("b_cate", b_cate);
    store.removeAll();
    store.load();
 
    //소분류카테객체 에디터셋팅
    var s_cateEditor = new Ext.form.ComboBox({
        displayField: 'code_nm',
        valueField: 's_cate',
        editable: false,
        forceSelection: false,
        mode: 'local',
        store: storeSmallCate, //위에서 대분류값으로 리로딩된 소분류 store
        triggerAction: 'all',
        renderer: function(val) {
            var recordIndex = storeSmallCate.find('s_cate', val);
 
            if (recordIndex === -1) {
                return '선택';
            }
 
            return storeSmallCate.getAt(recordIndex).get('code_nm');
        }
    });
 
    s_cate_obj.setEditor(s_cateEditor); //셋팅된 에디터를 소분류카테 객체에 셋팅한다.
}
cs

 

위의 소스 코드의 store들은 실제로 쓰인 코드가 아니라 이 포스팅을 위해 임의로 작성한 것이다.

그래서 실제로 돌려보면 돌아가지 않을 수 있다. 이 점 참고하길 바라며 본인들 소스에 맞게 잘 수정해서 쓰시길 바람.

extjs는 자바스크립트로 된 프레임워크이다.  

extjs 프레임워크에 대한 자세한 설명이나 강좌는 구글링하면 나올테고 내가 그걸 설명할 만큼 잘 알지 못하므로 패스한다. 

이 카테고리는 extjs의 강좌가 아닌 extjs를 사용하면서 필요한 잔기술들을 기록할 예정이고 앞으로 작성될 글의 기준 버전은 6.0이상이므로 이전 버전에서는 작동하지 않을 확률이 크니 이 점 참고하시길 바람.

 

extjs는 크게 controller, store, panel로 이루어져있는데

controller는 말그대로 컨트롤단

store는 데이터

panel은 view단이다.

 

내가 주로 다룰 부분은 panel이고 아마도 제일 많이 쓰이는 grid(표)를 하게 될 것 같다.

extjs의 매뉴얼은 잘 되어있으나 영어이고 예제가 생각보다 많지 않아 이러 저리 구글링하여 찾아낸 것들 위주로 글을 올릴 예정임.

참고로 https://fiddle.sencha.com 이 사이트에가면 예제도 많고 직접 테스트도 해볼 수 있음.

이 포스트는 ;나 ,등의 구분자로 여러 개의 값을 가진 컬럼으로 다른 테이블 정보를 조회하여 다시 한 컬럼의 값으로 합치는 방법을 설명하고 있다. 바쁘신 분은 최종 쿼리만 보시면 됨.

 

 

tbl_space라는 테이블이 있다고 하자.

이 테이블은 건물의 사무실공간 정보를 갖고 있다.

대충 스키마를 그려보자면 

 

<tbl_space : 공간정보 테이블>

컬럼명 타입 설명
space_cd number 공간코드
space_name varchar2 공간명
space_use_dept varchar2 사용부서

insert into tbl_space values(1, '302호', '1001,1052');

 

<tbl_dept : 부서정보 테이블>

컬럼명 타입 설명
dept_cd varchar2 부서코드
dept_name varchar2 부서명

insert into tbl_dept values('1001', '경영지원');

insert into tbl_dept values('1052', '인사');

insert into tbl_dept values('1042', '마케팅');

 

tbl_space테이블을 다시 살펴보자.

302호 사무실을 쓰는 부서는 경영지원팀과 인사팀이다.

내가 리스트에 뿌려주고 싶은 값이  '1001,1052'가 아니라 '경영지원, 인사'라면 어떻게 가져오는게 좋을까?

  공간코드 공간명 사용부서
원하는 결과 1 302호 경영지원, 인사
실제 결과 1 302호 1001, 1052

                                         (원하는 결과의 모양)

 

 

우선 tbl_dept에서 '1001'과 '1052'값을 가진 부서명을 가져오면 아래처럼 나올것이다.

select dept_name from tbl_dept where dept_cd in ('1001', '1052');

dept_name
경영지원
인사

얘네를 먼저 한 컬럼으로 만들어야겠다. 그렇다면 LISTAGG를 써보자

(오라클11g부터, 9g는 WM_CONCAT를 쓰라고한다.)

형식은  LISTAGG(컬럼명 , 구분자) 이다.

select LISTAGG(dept_name, ',') within group (order by dept_name) dept_name

   from tbl_dept

   where dept_cd in ('1001', '1052');

 

이제 원하던 대로 나올 것이다.

dept_name
경영지원, 인사

그런데! 조건절 where dept_cd in ('1001', '1052') 을 어떻게 구현하느냐 하는 난관에 봉착했다.

space_use_dept의 값은 '1001, 1052'이니깐 대충 생각하면 1001, 1052를 ','로 split해서 배열로 만들어주면 될 것 같은데...이걸 어떻게 구현?

 

이제 여기서는 REGEXP_SUBSTR라는 정규식을 써보도록 한다. (10g이상)

REGEXP_SUBSTR(대상문자열, '[^구분자]+'(정규표현식), 시작위치, 찾는위치)

'1052'를 뽑고싶다면 구분자는 콤마니까 구분자에 ,를 넣어주고 두번째 데이터니 찾는위치에 2를 넣어서

REGEXP_SUBSTR('1001, 1052', '[^,]+', 1,2) 이렇게 써주면 된다.

그렇다면...우리는 space_use_dept값에 있는 데이터를 다 찾아야 하니 하나씩 갖고오도록 해보자

 

WITH TT AS ( SELECT '1' FROM DUAL)
           SELECT TRIM(REGEXP_SUBSTR('1001, 1052', '[^,]+', 1, LEVEL)) AS space_use_dept
                FROM TT
           CONNECT BY INSTR('1001, 1052', ',', 1, LEVEL - 1) > 0;

 

with connect를 이용하여 1개씩 갖고오도록 하는 쿼리문이다. (with connect는 따로 설명하려면 길어질듯하니인터넷에서 잘 찾아보도록하자) 이렇게 질의를 하면 아래와 같이 예쁘게 split된 데이터로 가져온다.

space_use_dept
1001
1052

자 대망의 최종 Query문임.

select space_cd, 
         space_name,
         (select LISTAGG(dept_name, ',') within group (order by dept_name) dept_name
                from tbl_dept d
                where dept_cd in (WITH TT AS ( SELECT '1' FROM DUAL)  
                                    SELECT TRIM(REGEXP_SUBSTR(s.space_use_dept, '[^,]+', 1, LEVEL)) AS space_use_dept
                                    FROM TT 
                                    CONNECT BY INSTR(s.space_use_dept, ',', 1, LEVEL - 1) > 0)) space_use_dept_str
      from tbl_space s;

 

그리고 최종 결과

space_cd space_name space_use_dept_str
1 302호 경영지원, 인사

참...쉽쥬?

javax.el.PropertyNotFoundException에러가 나는 이유는 스펠링이 틀리거나 공백이 있어서가 대부분이지만


그렇지 않을 경우도 있다. 눈씻고 찾아봐도 공백이나 틀린철자가 없다면 다음내용을 확인해보자.


DTO정의 시 GuestTelNo라는 필드가 있다고 할 때 이렇게 가져오면 에러가 난다.


<input name="GuestTelNo"     id="GuestTelNo"       type="hidden" value="<c:out value='${vo.GuestTelNo}'/>" />


이 때 첫번째 문자를 소문자로 해주면 에러가 나지않는다. 즉 ${vo.GuestTelNo}를 ${vo.guestTelNo}로 바꿔 주어야 한다는 것!

DB : 오라클

프레임워크 : 전자정부 프레임워크 (java+spring+mybatis 등등)


보통은  select문을 써서 원하는 값을 가져오곤하는데 다른사람이 작성한 프로시져로 값을 받아와야하는 상황이 생겼다. 우선 sqlquery맵부터 작성해보자


sqlmap.xml


inParam01, inParam02 두 값을 던져서 outParam01, outParam02, outParam03라는 값을 받고 싶어하는 단순한 프로시져이다.

그럼 Controller를 작성해보자.  (Service와 DAO는 생략함)


testController.java


여기까지 하고 실행했을 때 NullpointException이 난다.

왜일까?.....왜일까....왜일까...
분명 result로 받았는데 왜 resultVo는 null일까...

그것은 바로 return이 resultVo로 오는게 아니라 parameter로 넘겼던 vo에 담기는 것이기 때문이었다. (왜 그런지는 다음에...)


자 이제 제대로된 소스를 작성해보자


sqlmap.xml

testController.java


sqlmap.xml에 있던 resultType을 삭제했다. 필요없으니까.

testController에서는 resultVo로 받는 것이 아니라 그냥 vo객체를 출력한다. testService.getValues(vo);를 호출함으로해서 vo에 값이 이미 담겼으니까.



+ Recent posts