프로그래밍/전자정부프레임워크(eGov)

JQGrid 전자정부프레임워크에 적용하기 - (3)

Jay22 2017. 3. 26. 15:11
반응형

이제 저장과 삭제를 해 볼 것이다.


저번 포스팅때 프로퍼티의 위치가 좀 틀려서 다시 정리하자면

(없는 것들은 이제 만들 것이다)


jqgridTable 안의 프로퍼티 

init

searchData에서 goSearch로바꾸자.

saveData

selectData

deleteData

ajaxFn


gridFunc 안의 프로퍼티

addRow

rowBtn

delRow

clearGrid


CommonJsUtil 안의 프로퍼티

isEmpty

isNumeric


조금 더 알맞게 나누려고 위치를 수정하였다. 코드의 변경은 없으므로 프로퍼티 위치 변경할 때는 그냥 잘라서 붙여넣기 하면 된다.


먼저 조건 하나를 추가해보자. 안해도 상관없다.


CommonJsUtil에서 프로퍼티하나를 더 만들어보자.

슬래시 안은 정규식을 의미한다. ^ 는 부정의 의미이다. 즉 ^0-9는 숫자가 없다면 이라는 의미이다.

1
2
3
4
5
6
7
isNumeric : function(val) {
            if (/[^0-9]/.test(val)) {
                return false;
            } else {
                return true;
            }
        }
cs

gridValid를 적용해보자. 이것은 사용자 마음대로 조건을 거는 곳이다.

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
gridValid : function() {
    
                var trObj = $("#jqGrid").find("tr");
    
                for (var i = 0; i < trObj.length; i++) {
    
                    var $this = $(trObj[i]);
    
                    if ($this.hasClass("edited")) {
    
                        var rowId = $this.prop("id");
                        var phone = $("#jqGrid").getCell(rowId, "phone");
                        alert(phone);
                        if (!CommonJsUtil.isNumeric(phone)) {
    
                            alert(rowId + "째 행 전화번호는 숫자만 입력가능합니다.");
    
                            return false;
    
                            break;
                        }
                    }
                }
    
                return true;
            },
cs


예를들어 이렇게 한다면 우리가 처음에 만든 전화번호 부분에 숫자가 없다면 다음 이벤트를 실행시키지 못하게 만드는 것이다. 

line 9 : edited라는 클래스가 tr 에 생긴다는 것은 편집하려고 마우스를 누른 후

이런식으로 커서가 생길 때 edited 속성이 생기는 것이다. if문안을 타는 것은 편집을 하려고 마우스를 클릭했을 때이다. 그럼 전화번호를 가지고 와서 isNumeric함수에 넣어서 검증을 한다. 




자 그럼 본격적으로 저장을 해보자.



1
2
3
4
5
6
7
8
9
saveData : function() {
              alert("dddd");
               if(!this.gridValid()) return false;
               
               var param1 = this.selectData('save');
               alert("저장선택");
              this.ajaxFn(param1, '저장');
       
               },
cs


저기 selectData에서 문자열을 받아서 저장인지 삭제인지 구분한다. 즉, 저장 삭제가 하나의 함수에서 이루어지게 한다.

그리고 밑에 ajaxFn은 좀 이따 설명하겠다.


selectData부분을 보자. 매우 중요하다.



function()안의 인자로 'save'를 받는다.

3항 연산자로 save이면 저장을 넣고 아니면 삭제를 넣는다.

저번 시간에 했던 부분과 추가 된 부분이 있다. 이것이 최종본이므로 이것을 참고하면 되겠다.


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
selectData : function(gubun) {
                
                var gubunText = gubun == 'save' ? '저장' : '삭제';
                var checkData = $("#jqGrid").getGridParam("selarrrow"); // 체크된 로우들을 담는다.
    
                if (checkData.length == 0) {
                    alert("저장할 데이터를 선택해 주세요");
                    return;
                }
                if (confirm("선택한 데이터를" + gubunText + " 하시겠습니까?"== false) {
                    return false;
                }            
                var iCnt = 0;
                var jsonArray1 = new Array();
    
                for (var i = 0; i < checkData.length; i++) {
                    var jsonObj = {}; // jsonObject 생성
                    var seq = $("#jqGrid").getCell(checkData[i], "seq");
                    var editType = "";
    
                    if (!CommonJsUtil.isEmpty(seq)) { // 행추가가 아니라면
                        editType = "D"// 삭제
                    } else {
                        editType = "I"// 행추가라면 insert
                    }
    
                    jsonObj.editType = editType;
                    jsonObj.seq = seq;
    
                    jsonObj.name = $("#jqGrid").getCell(checkData[i], "name");
                    jsonObj.phone = $("#jqGrid").getCell(checkData[i], "phone");
                    jsonObj.address = $("#jqGrid").getCell(checkData[i], "address");
                    jsonObj.etcc = $("#jqGrid").getCell(checkData[i], "etcc");
                    jsonObj.gender = $("#jqGrid").getCell(checkData[i], "gender");
    
                    jsonArray1[iCnt] = jsonObj; // 배열에 json을 넣는다. 배열에 하나씩 모으는 것
    
                    iCnt++;
                }
    
                var param1 = JSON.stringify(jsonArray1);
    
                return param1;
            },
cs


getGridParam을 다시 살펴보자.


jqgrid에서 선택된 줄의 정보를 사용해서 처리해야 하는 역할을 한다고 저번 시간에 보았다.

getGridParam("selrow")를 쓰면 현재 선택되어있는 줄의 아이디값을 반환한다. 선택된 줄이 없다면 null을 반환한다.

그런데 우리는 multiselect를 설정했었다. 다중선택이 가능한것이다. 다중선택하고 selrow를 쓰게 되면 마지막에 선택된 줄의 id값을 반환한다.

line 7 : 우리는 여러줄을 쓰므로 selarrow를 인자로 넣어준 것이다. 

checkData에 그것이 들어가 있다. 

line 9 : 만약 checkData의 길이가 0이라면 선택안된것이므로 alert찍어주고 return한다.


line 17 : confirm창이다. alert처럼 띄워져서 취소누르면 돌아가고 확인을 누르면 다음으로 진행한다.


line 20 : json을 넣을 배열을 선언한다. 


line 23 : 선택된 row 수 만큼 for문을 돈다. 

jsonObj를 생성한다. 이것은 jsonObject를 생성한다는 것이다. 그리고 $("#jgGrid").getCell(checkData[i], "seq"); 를 하는데 getCell은 cell의 정보를 가져오는 것이다. 첫 번재 인자는 checkData의 첫 번째 값(0번인덱스이다) 이다. 위에서 아이디값을 반환한다고 했으니 7번째 줄을 눌렀을 때는 7이 들어가 있을 것이다. 즉 7번째 위치의 cell의 "seq"값을 가져오라는 것이다. 


var editType은 저장인지 삭제인지 구분하는 것이다. 여기서 잘 보아야 한다. 중요하다. seq는 우리가 조작하는 값이 아니다.

seq는 여기 동그라미 친 부분이다. 이것이 표시된다는 것은 db에서 값을 가져왔다는 의미가된다. 위의 코드에서는 이값이 비어있는지를 체크한다.

!CommonJsUtil.isEmpty(seq)로 말이다. 비어있다는 말은 행추가를 누른것이다. 행추가를 누르면 seq부분에 숫자가 표시되지 않는다. 즉 행추가가 아니라면 editType은 D 즉 삭제가 된다. 그렇지 않고 행추가라면 I Insert가 된다.


이 정보를 이제 json에 하나씩 담을거다. 먼저 D, I 정보를 editType으로 넣는다. 그다음에 seq, name, phone 등 한 줄의 정보를 다담는다. 담았으면,


line 43 : 배열에 넣는다. iCnt는 숫자 세어주는 변수이고 차례대로 넣고 iCnt를 증가시켜준다.


line 48 : param1에 만들어진 이 배열을 stringify를 한다. stringify는 js객체를 json형태의 문자열로 변환하는 것이다. 이를 이용하여 js객체를 브라우저->다른 앱으로 전송가능하다. 참고로 JSON.parse()는 json객체를 브라우저가 사용가능한 js객체로 변환한다.

이제 이 것을 return한다.


selectData를 호출한 쪽은 saveData쪽이다. this.selectData('save')의 리턴값으로 param1에 넣었다. 

this.ajaxFn(param1, '저장'); 을 한다. '저장'을 넘겨주는 것도 하나의 컨트롤러에서 저장과 삭제를 처리하기 위해서이다.


이제 ajaxFn을 정의할 차례이다.

파라미터로 json이 들어있는 배열과 저장 혹은 삭제인지 구분하는 텍스트가 넘어간다.


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
ajaxFn : function(param1, gubun) {
    
                $.ajax({
    
                    type : "POST",
                    url : "saveJqgrid.do",
                    data : {
                        "param1" : param1
                    },
                    async : false,
                    beforeSend : function(xhr) {
    
                        // 전송 전 Code
                    },
                    success : function(result) {
    
                        if (result == "SUCCESS") {
    
                            alert("성공적으로 삭제하였습니다.");
    
                            jqgridTable.goSearch();
                        }
                    },
                    error : function() {
    
                        alert("Error 발생");
                    }
                });
            }
cs


ajax통신이다. typepost로 보내고 urlsaveJqgrid.do로 보낸다. 이것은 이제 바로 컨트롤러를 만들어서 맵핑시켜줄 것이다. data는 param1로 아까 받은 json배열을 넣는다. async 의 기본값은 true인데 비동기적으로 처리하지 않고 ajax통신 이후에 다른 코드가 실행될 것이 있다면 false 동기로 해준다. 

beforSend는 request전에 호출되는 이벤트이다. 이 안에서 return false를 주게 되면 ajax 이벤트가 취소된다.

success는 통신이 성공하면 호출되는 함수이다.

error는 통신중 실패했을 경우 호출된다.



자 이제 대망의 컨트롤러를 보자. 아 그전에 삭제도 구현하고 가자. 통합 함수를 타게 했으므로 


1
2
3
4
5
6
7
        deleteData : function() {
                
                var param1 = this.selectData('del');
    
                this.ajaxFn(param1, '삭제');
    
            },
cs


이거면 끝이다.


컨트롤러를 saveJqgrid.do 아까 ajax url로 맵핑해준다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RequestMapping(value="saveJqgrid.do")
    @ResponseBody
    public String saveJqgrid(@RequestParam String param1) throws Exception {
        String result = "";
        try {
            param1 = param1.replaceAll("&quot;""\"");
            
            JSONArray jsonArray = new JSONArray(param1);
                                            
            jqgridService.saveJqGridTx(jsonArray);
            
            result = "SUCCESS";
                    
        } catch (Exception e) {
            result = "FAIL";
        }
        
        return result;
    }
cs


@Responsebody는 @RequestParam의 param1이 json이기 때문에 설정해준 것이다. jackson라이브러리를 메이븐에 넣어서 할 수 있지만,

스프링 4.0부터는 기본적으로 jackson라이브러리가 포함되어 있다. 그래서 기존의 jackson라이브러리를 메이븐에 추가해주는 작업을 하지 않아도 된다.

4.0부터 @RestController 를 사용할 수 있다. @Responsebody를 안붙여도 알아서 json방식으로 파싱된다. 저거 안써주면 인자로 받아오는 param1에서 에러가 터지게 된다.


result변수는 스크립트쪽에 응답할 때 넣을 문자열이다. (성공인지 실패인지) 

JSON배열을 만든다. 그리고 서비스를 타게한다.

탄 이후에는 result success를 스크립트쪽으로 넘겨준다.


jqgridService.saveJqGridTx(jsonArray); Tx는 트랜잭션을 담당하는 이름이다. 트랜잭션에 대한 설명은 이 포스팅에서 하겠다. 참고하기 바란다.


서비스쪽에 void saveJqGridTx(JSONArray jsonArray) throws Exception; 가 있어야 하겠고 서비스,임플,맵퍼를 만드는 것은 이전 포스팅이나 다른 글들을 참고하기 바란다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
    public void saveJqGridTx(JSONArray jsonArray) throws Exception {
        int iLength1 = jsonArray.length();
        
        try {
            for(int i=0; i<iLength1; i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
 
                Map<StringObject> param = JsonUtil.JsonToMap(jsonObject.toString());
                System.out.println(param.get("editType"));
                if("I".equals(param.get("editType"))) {
                    jqgridMapper.insertJqgridList(param);
                } else if ("D".equals(param.get("editType"))) {
                    jqgridMapper.deleteJqgridList(param); 
                }
            }
        } catch (Exception ex) {
            throw ex;
        }
    }
 
cs


서비스 임플쪽에서 정보를 뜯게 된다. jsonArray의 길이를 구하고 (iLenght1) for문을 돌게 된다.

json배열에서 jsonObject들을 하나씩 뽑게 된다.


line 9 : 저번 포스팅에서 본 JsonUtil클래스안의 메서드이다. json을 맵으로 변환시켜준다. 왜? sql에서 parametertype이 map이니까

param을 찍어보면



이렇게 = (equal) 형태로 맵이 되게 된다. 원래는 : 형태로 json이었다. 데이터는 아무거나 넣은 것이다.


맵퍼에 void insertJqgridList(Map<String, Object> param) throws Exception; 를 넣고 SQL 쿼리를 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<insert id="insertJqgridList" parameterType="map">
        <selectKey resultType="String" keyProperty="seq" order="BEFORE">
        SELECT NVL(MAX(SEQ),0)+1AS seqNo
        FROM jqgrid_start
        </selectKey>
        INSERT INTO jqgrid_start
        (SEQ
         ,NAME
         ,PHONE
         ,ADDRESS
         ,ETCC
         ,GENDER)
        VALUES
        (#{seq},
        #{name},
        #{phone},
        #{address},
        #{etcc},
        #{gender})
    </insert>
cs


아까말한 map으로 parametertype을 설정하였고 밑에 selectKey라는 태그가 생겼다. keyProperty가 생겼는데 저 안의 쿼리를 수행하고 저 이름으로 담겠다라는 뜻이다. 타입은 String이고 order는 before인데 이것은 밑의 쿼리보다 먼저 수행되기 때문에 before로 한 것이다. 밑에 형광색쳐진 부분의 seq가 위에서 만든 seq이다. 즉, 데이터 넣을 건데 seq를 구해야 할것 아닌가? 그래서 저런식으로 넣는것이다.


SELECT NVL(MAX(SEQ),0)+1 AS seqNo FROM jqgrid_start 이부분의 nvl은 max(seq)가 null이라면 (즉 초기상태인경우) 0으로 설정하라는 것이다. 여기다가 1을 더해야 다음 seq가 구해질 것이다. Max는 최댓값이다. 즉 제일 끝번호를 찾아서 1을 더하는 것이다.


삭제 쿼리는 간단한다.

1
2
3
<delete id ="deleteJqgridList" parameterType="map">
        DELETE FROM jqgrid_start WHERE SEQ=#{seq}
</delete>
cs


그냥 받아온 seq 날리면 된다.


자 이제 실행을 해서 이런식으로 데이터를 체크박스에 체크해서 저장하든지 삭제하든지 하면 된다.



다음 포스팅에서는 조건을 몇 개 추가해보고 잔 버그같은것들을 고쳐보자.




도움이 되셨다면 공감눌러주시고 궁금한전 댓글남겨주세요~


반응형