웹 개발/IBSheet8

[IBSheet] 단일 행 수정 (JS 동적 속성 접근, 요청/응답)

cha430 2025. 6. 10. 10:47

 


 

 

 

IBSheet 에서 단일 행 수정하는 방법이다.

 

등록 Dialog를 통해 수정하는 건 큰 어려움 없이 했는데

IBSheet를 통해 수정하는 건 왜이렇게 어렵던지 ... 특히 Date형을 자꾸 TimeStamp 로 변경해버려서 너무 힘들었다 ....

백에서 JsonFormat ... 프론트에서 Format.. 뭘 해도 에러 ..에러 ....!!

 

onMounted 에서 Events 주고,

컬럼 변경하는 함수 생성하고 .. 난리를 쳐보았는데.

 

그러지 말고 진작 이것 저것 다 콘솔 찍어보고

IBSheet8 매뉴얼을 보고

천천히 생각해볼 걸 그랬다..

너무 급하게 타자 먼저 치면서 에러 잡기에만 몰두했다 ... 

 

IBSheet가 제공하는 함수를 이용하면 간단하다.

 

행 전체 데이터를 수정할 때는 onAfterEdit() 을 쓸 수 있고

행 한 개 데이터를 수정할 때는 onAfterChange() 를 쓸 수 있다.

 

                    onAfterChange: async function (evtParam) {
                        console.log('onAfterChange 발생');
                        console.log('evtParam:', evtParam);

                        const rowData = evtParam.row;
                        const rowIndex = rowData.OrgIndex ?? rowData.HasIndex;

                        const colName = evtParam.col;
                        const newValue = evtParam.val; // 수정된 값
                        // 기존 값은 IBSheet 내부 속성 중 하나를 써야 함
                        const oldValue = rowData[colName + 'BeforeVal'] ?? rowData[colName + 'Orig'] ?? null;

                        console.log('수정된 행 인덱스:', rowIndex);
                        console.log('수정된 컬럼명:', colName);
                        console.log('새로운 값:', newValue);
                        console.log('기존 값:', oldValue);
                        console.log('행 데이터:', rowData);

                        if (newValue === oldValue) return;

                        const changedData = {
                            assetCode: rowData.assetCode,
                            col: colName,
                            value: newValue
                        };

                        console.log('서버로 전송하는 데이터:', JSON.stringify(changedData));

                        axios.post(`http://localhost:8080/main/updateColAsset.do`, changedData)
                            .then(res => {
                                if (res.data.result === 1) {
                                    console.log('단일 셀 수정 성공');
                                } else {
                                    console.error('단일 셀 수정 실패:', res.data);
                                }
                            }).catch(err => {
                            console.error('단일 셀 수정 중 오류:', err);
                        });
                    },

 

 

에러 체크하려고 console을 얼마나 많이 찍어보았던가 ..ㅎㅎ

 

어제 11시간 동안 모니터를 들여다본 끝에 성공하고 얼마나 기쁘던지 ..!

코딩하다가 손목이 아팠던 건 이번이 처음이다.

 

어쨌든, GPT한테도 많이 물어보고 매뉴얼 보고 따라해보면서 바꾸다가 얻어걸린 거라 한 줄씩 공부를 해야겠다.

 

 


 

 

한 줄씩 주석 공부

 

** 일단 IBSheet에서 셀 하나를 수정했을 때

 

1. 무슨 셀이 바뀌었는지

2. 기존 값은 뭐였고, 새로운 값은 뭔지

3. 어떤 행(row)이 수정됐는지

 

알아내서 서버에 보내야 한다.

 

 


 

 

 onAfterChange: async function (evtParam) {

// 사용자가 셀을 수정한 후 실행되는 IBSheet 이벤트


         console.log('onAfterChange 발생');
         console.log('evtParam:', evtParam);
// evtParam : 이벤트 파라미터. IBSheet 제공. 이벤트 발생 시 관련 정보를 evtParam 객체에 담아서 제공


         const rowData = evtParam.row;

// 수정된 행 데이터 전체를 rowData에 저장 (어떤 행 바뀜?)


         const rowIndex = rowData.OrgIndex ?? rowData.HasIndex;
// 수정된 행의 원래 인덱스 찾기

// rowData는 IBSheet에서 수정된 셀의 행 전체를 나타내는 객체

// OrgIndex : 원본 데이터 기준의 행 번호 (서버에서 처음 불러왔을 때 기존 데이터)

// HasIndex : 새로운 행이거나 OrgIndex 없을 때 대체하는 백업 인덱스

                       (HasIndex는 행 추가 안해도 IBSheet가 모든 row객체에 부여하는 내부 순번)

// ?? 연산자 : 왼쪽 값이 null, undefined 일 때 오른쪽 값 사용

        따라서 원래 있는 값이면 OrgIndex를 쓰고 새로 추가된 행이면 HasIndex를 써서 어떤 행인지 알 수 있다.


         const colName = evtParam.col;

// 수정된 컬럼명을 colName에 저장 (어떤 컬럼 바뀜?)

         const newValue = evtParam.val;

// 새로운 값을 newValue에 저장 (새로운 값이 뭐?)

 

    // 기존 값은 IBSheet 내부 속성 중 하나를 써야 함
         const oldValue = rowData[colName + 'BeforeVal'] ?? rowData[colName + 'Orig'] ?? null;

// 수정하기 전의 기존 값 가져오기

// IBSheet 가 제공하는 필드 : BeforeVal, Orig

// oldValue를 구할 때 사용 -> 방금 전 값 있으면 그거 쓰고, 없으면 서버에서 온 원래 값 쓰고, 없으면 null

// 진짜 수정된 게 맞는지 확인하기 위

// ?? 연산자 : 왼쪽 값이 null, undefined 일 때 오른쪽 값 사용

// colName + 'BeforeVal' 로 이전 값 접근하는 건 JavaScript 동적 속성 접근 방식

 

        console.log('수정된 행 인덱스:', rowIndex);
         console.log('수정된 컬럼명:', colName);
         console.log('새로운 값:', newValue);
         console.log('기존 값:', oldValue);
         console.log('행 데이터:', rowData);

         if (newValue === oldValue) return;
// oldValue가 null일 경우 newValue와 같지 않아 여기서 종료될 수 있기 때문에

// console.log를 if문 전 후로 찍어보는 게 도움이 된다.

 

         const changedData = {
                  assetCode: rowData.assetCode,
                  col: colName,
                  value: newValue
         };

// 기존 값의 assetCode, 컬럼명, 변경된 새 값을 changedData 에 담아서
         console.log('서버로 전송하는 데이터:', JSON.stringify(changedData));
// JSON.stringify() : JavaScript 객체(Object)를 문자열로 변환

// changedData를 JSON형식 문자열로 바꾸는 것 : 서버에 전송해야 하니까

         axios.post(`http://localhost:8080/main/updateColAsset.do`, changedData)
                  .then(res => {
                           if (res.data.result === 1) {
                                    console.log('단일 셀 수정 성공');
                           } else {
                                    console.error('단일 셀 수정 실패:', res.data);
                           }
                  }).catch(err => {
                           console.error('단일 셀 수정 중 오류:', err);
                  });
}

// 수정된 데이터만 서버로 보내는 것

// 서버에서 성공 시 result 에 1을 담아 보내기 때문에 res.data.result 가 1이면 성공, 아니면 실패

 


 

JavaScript 동적 속성 접근 방식

const colName = 'acqPrice';
const key = colName + 'BeforeVal'; // 결과: "acqPriceBeforeVal"
const oldValue = rowData[key]; // → rowData["acqPriceBeforeVal"]

 

rowData[colName + 'BeforeVal']
 =
rowData["acqPriceBeforeVal"]

 

같은 의미

[] 써서 접근 


 

● IBSheet 가 제공하는 필드

 

- evtParam

: 이벤트 파라미터. IBSheet 제공. 이벤트 발생 시 관련 정보를 evtParam 객체에 담아서 제공

 

-  evtParam.col

 : 현재 수정/클릭된 컬럼 이름

 

-  evtParam.row

 : 현재 수정/클릭된 행 전체 객체

 

-  evtParam.val

 : 사용자가 입력한 새로운 값 (**onAfterChange 등에서만)

 

-  OrgIndex

 : 원본 데이터 기준의 행 번호 (서버에서 처음 불러왔을 때 기존 데이터)

 

-  HasIndex

 : 행 추가 안해도 IBSheet가 모든 row객체에 부여하는 내부 순번

 

-  evtParam.row[컬럼명 + 'BeforeVal']

 : 해당 컬럼의 변경 직전 값

 

→ rowData['acqPriceBeforeVal'] 이런식으로 됨

 

-  evtParam.row[컬럼명 + 'Orig']

 : 해당 컬럼의 서버에서 처음 불러온 값

 

 

**

evtParam.row 는 객체라 rowData로 접근해도 되고 그냥 접근해도 됨

 

 


 

 

mapper.xml

    <update id="updateColAsset" parameterType="map">
        UPDATE tbl_asset
        <set>
            ${col} = #{value}
        </set>
        WHERE asset_code = #{assetCode}
    </update>

 

 

Controller

	@PostMapping("/updateColAsset.do")
	public MainDto updateColAsset(@RequestBody Map<String, Object> map) {
		try {
			Map<String, String> colMap = Map.of(
				"assetName", "asset_name",
				"assetPrice", "asset_price",
				"acqQty", "acq_qty",
				"acqDate", "acq_date",
				"acqPrice", "acq_price"
			);        String logicalCol = (String) map.get("col");
			String dbCol = colMap.get(logicalCol);

			if (dbCol == null) {
				throw new IllegalArgumentException("허용되지 않은 컬럼명입니다: " + logicalCol);
			}

			// DB에 사용할 컬럼명으로 치환
			map.put("col", dbCol);
			map.put("newValue", map.get("value")); // #{newValue}에 매핑

			int result = service.updateColAsset(map);

			System.out.println("서버로 전달된 매핑 후 파라미터: " + map);

			return MainDto.builder().result(result).build();
		} catch (Exception e) {
			e.printStackTrace();
			return MainDto.builder().result(-1).build();
		}
	}

 

 

1. public MainDto updateColAsset(@RequestBody Map<String, Object> map)

 

클라이언트에서 보내는 데이터 JSON을 map이라는 이름의 자바 Map으로 자동 변환해서 받는다.

ex) 

{
  "col": "acqPrice",
  "value": "300000",
  "assetCode": "KLOZAA00001"
}

 

 

** public MainDto updateColAsset(@RequestBody Map<string, object> map)

              Response 응답 출력            Request 요청 입력

 

 : 클라이언트가 보낸 JSON  을 Map으로 받아서 MainDto 로 응답하겠다

 

 

{
  "col": "acqPrice",
  "value": "300000",
  "assetCode": "KLOZAA00001"
}

이렇게 보내면

map.get("col")        → "acqPrice"  
map.get("value")      → "300000"  
map.get("assetCode")  → "KLOZAA00001"

서버에서 이렇게 받고
이걸 DB수정할 때 사용한 다음에 
처리 결과를 MainDto.builder().result(1).build()로 응답

 

 

 

 

2. Map<String, String> colMap = Map.of( ... );

 

프론트에서 사용하는 컬럼명과 DB의 컬럼명이 다르기 때문에 (코딩 컨벤션)  연결해주는 사전 Map을 만들어서 colMap에 저장

 

 

 

3. String logicalCol = (String) map.get("col");

 

프론트에서 보내준 수정한 컬럼명 col을 logicalCol 에 저장

ex)

map.get("col") → "acqPrice"

 

 

 

4. String dbCol = colMap.get(logicalCol);

 

colMap 사전을 보고 logicalCol을 DB 컬럼명으로 변경

 

 

5. if (dbCol == null) {
    throw new IllegalArgumentException("허용되지 않은 컬럼명입니다: " + logicalCol);
}

 

만약 colMap에 없는 컬럼명을 보내면 dbCol 이 null 이기 때문에 에러 던짐

(DB에 없는 컬럼명 저장 막을 목적)

 

 

6. map.put("col", dbCol);

 

map안의 "col"값을 DB용 컬럼명으로 덮어쓰기

col: "acqPrice" → col: "acq_price"로 바뀜

 

 

7. map.put("newValue", map.get("value"));

 

MaBatis XML 에서 사용할 #{newValue)에 대응되도록 value 도 저장

 

 

8. int result = service.updateColAsset(map);

 

service 메서드에 map 넣고 실행해서 실제로 값 업데이트하고 result 에 저장

성공하면 result 는 1, 실패하면 0  (성공적으로 1개가 처리되기 때문에 1 반환하면 성공이라는 의미)

 

 

9. return MainDto.builder().result(result).build();

 

Vue한테 빌더패턴 이용해서 응답