웹 개발/IBSheet8

[IBSheet] IBSheet8 활용 데이터 출력

cha430 2025. 6. 4. 11:10

 

 

 

** 일단 IBSheet 를 사용할 때

npm install @ibsheet/loader

 

패키지를 프로젝트에 설치하고

import loader from '@ibsheet/loader'

 

패키지를 코드에서 사용하겠다고 선언해야 한다.

 

 


 

 

● Controller에서 데이터를 map에 담아 보냈을 때

 

 

MainRestController.java

map.put("Data", list); // ← 프론트로 보내는 데이터
map.put("Result", 1);  // ← 성공 여부
return map;

 

 

main.vue

Data: res.data.Data || []

 

Spring 에서 보낸 데이터를 이렇게 받아서 출력할 수 있다.

|| [] 는 null 일 경우 빈 배열 줘서 에러 방지

axios.post()로 받은 데이터 res.data 중에서 map에 담은 Data라는 키에 Spring 서버에서 받은 실제 리스트가 들어있다.

 

 

만약 개발 테스트용일 경우

 

Data: createData(50) 으로 임시 데이터 더미를 만들고

아래 for문의 결과를 넣어서 데이터를 확인할 수 있다.

(count만큼 데이터 만들어서 data배열에 넣는 )

for (var i = 0; i < count; i++) {
        data.push({
          sCompany: company[Math.floor(Math.random() * 10)],
          sCountry: country[Math.floor(Math.random() * 10)],
          sSaleQuantity: Math.floor(Math.random() * 100000),
          sSaleIncrease: Math.floor(Math.random() * 10000),
          sPrice: Math.floor(Math.random() * 10000000),
          sSatisfaction: Math.floor(Math.random() * (100 - 50 + 1) + 50),
        });
      }

 

createData() 는 정의해야 쓸 수 있다.

 

예시

function createData(count) {
  const data = [];

  for (let i = 0; i < count; i++) {
    data.push({
      accountTitle: `계정과목 ${i + 1}`,
      assetCode: `AC-${1000 + i}`,
      assetName: `자산명 ${i + 1}`,
      acqQty: Math.floor(Math.random() * 100 + 1),
      acqPrice: Math.floor(Math.random() * 1000000 + 10000)
    });
  }

  return data;
}

 


 

 

IBSheet8 홈페이지 매뉴얼 -> 임시데이터 출력 전체코드

 

<div id='estTime'>데이터 로딩: 0 ms / 0 초</div></div>

HTML에 이렇게 id를 주어서,  estTime 사용됨

var ib = ib || {}
ib = {
  //시트 초기화 구문
  init: {
    //공통기능 설정 부분
    Cfg: {
      SearchMode: 0,
      CustomScroll: 0,
    },
    Def: {
      Col: {
        RelWidth: 1,
      },
    },
    //틀고정 좌측 컬럼 설정
    LeftCols: [
      {
        Header: "No.",
        Name: "SEQ",
        Type: "Int",
        RelWidth: 0,
        Width: 80,
        Align: "Center",
      },
    ],
    //중앙(메인) 컬럼 설정
    Cols: [
      {
        Header: "회사",
        Name: "sCompany",
        Type: "Text",
        MinWidth: 150,
        Align: "Center",
      },
      {
        Header: "판매 국가",
        Name: "sCountry",
        MinWidth: 100,
        Type: "Text",
        Align: "Center",
      },
      {
        Header: "판매 수량",
        Name: "sSaleQuantity",
        Type: "Int",
        MinWidth: 100,
      },
      {
        Header: "판매 증가량",
        Name: "sSaleIncrease",
        Type: "Int",
        MinWidth: 100,
      },
      {
        Header: "가격",
        Name: "sPrice",
        Type: "Int",
        MinWidth: 150,
        Format: "#,##0원",
      },
      {
        Header: "만족도",
        Name: "sSatisfaction",
        Type: "Int",
        MinWidth: 100,
        Format: "#\\%",
      },
    ],
  },
  //시트 이벤트
  event: {
    onDataLoad: function (evtParam) {
      console.log(evtParam.eventName + " 발생")
      var leDate = new Date()

      estTime.textContent =
        "데이터 로딩: " +
        (leDate - lsDate) +
        " ms / " +
        (leDate - lsDate) / 1000 +
        " 초"
      sheet.hideMessage()
    },
    onSearchFinish: function (evtParam) {
      console.log(evtParam.eventName + " 발생")
      var leDate = new Date()

      estTime.textContent +=
        " (총 렌더링: " +
        (leDate - lsDate) +
        " ms / " +
        (leDate - lsDate) / 1000 +
        " 초)"
    },
  },
  //시트객체 생성
  create: function () {
    var options = this.init

    options.Events = this.event
    IBSheet.create({
      id: "sheet", // 생성할 시트의 id
      el: "sheetDiv", // 시트를 생성할 Dom 객체 및 id
      options: options, // 생성될 시트의 속성
      data: [],
    })
  },
  //화면 기능
  sampleBtn: function () {
    setTimeout(function () {
      sheet.showMessage("데이터 조회 중...", 4, 1)
    }, 1)
    setTimeout(function () {
      dataTime.textContent = "데이터 생성중입니다."
      sheet.loadSearchData(
        createData(document.getElementById("massData").value),
      )
    }, 50)
  },
  //조회 데이터
  data: "해당 화면에서는 데이터가 동적으로 생성됩니다.",
}
ib.create()
var createData = function (count) {
  var start = new Date()
  var data = []
  var company = [
    "Google",
    "Apple",
    "삼성전자",
  ]
  var country = [
    "미국",
    "일본",
    "한국",
  ]

  for (var i = 0; i < count; i++) {
    data.push({
      sCompany: company[Math.floor(Math.random() * 10)],
      sCountry: country[Math.floor(Math.random() * 10)],
      sSaleQuantity: Math.floor(Math.random() * 100000),
      sSaleIncrease: Math.floor(Math.random() * 10000),
      sPrice: Math.floor(Math.random() * 10000000),
      sSatisfaction: Math.floor(Math.random() * (100 - 50 + 1) + 50),
    })
  }
  var cols = sheet.getCols()

  for (var i = 0; i < cols.length; i++) {
    if (sheet.Cols[cols[i]].Visible == 0) {
      cols.splice(i, i + 1)
    }
  }

  dataTime.textContent =
    "데이터 생성 (" +
    (cols.length * data.length).toLocaleString() +
    " 셀): " +
    (new Date() - start) +
    " ms / " +
    (new Date() - start) / 1000 +
    " 초"

  // 데이터 구문 처리
  var showData = []

  for (var i = 0; i < data.length && i < 20; i++) {
    showData.push(data[i])
  }
  var _data = JSON.stringify(showData, null, 2)

  if (data.length > 20) {
    _data = _data.substring(0, _data.length - 1) + "...\n]"
  }
  try {
    myTabs.contents
      .items(1)
      .setContents(
        '<pre><code class="language-json">' + _data + "</code></pre>",
      )

    hljs.initHighlighting.called = false
    hljs.initHighlighting()
  } catch (e) {
    console.log("IBTab 이 존재하지 않습니다.")
  }
  window.lsDate = new Date()

  return data
}

 

 

● IBSheet8 홈페이지 내 매뉴얼에 있는 출력 코드 -> 한 줄씩 주석

 

 

var ib = ib || {}

// 이미 선언된 ib 가 있으면 그대로 쓰고 없으면 새 객체로 초기화


ib = {

// 시트 초기화. ib라는 객체 안에 시트 초기화, 이벤트, 생성, 조회 기능을 묶어둔 구조

// loader를 써서 옵션을 직접 정의할 수도 있다.


  init: {
// 시트 설정
    Cfg: {

// 공통 설정
      SearchMode: 0,
      CustomScroll: 0,
    },
    Def: {
      Col: {
        RelWidth: 1,
      },
    },
    LeftCols: [
      {
        Header: "No.",
        Name: "SEQ",
        Type: "Int",
        RelWidth: 0,
        Width: 80,
        Align: "Center",
      },
    ],


// 중앙(메인) 컬럼 설정
    Cols: [
      {
        Header: "회사",
        Name: "sCompany",
        Type: "Text",
        MinWidth: 150,
        Align: "Center",
      },
      {
        Header: "판매 국가",
        Name: "sCountry",
        MinWidth: 100,
        Type: "Text",
        Align: "Center",
      },
      {
        Header: "판매 수량",
        Name: "sSaleQuantity",
        Type: "Int",
        MinWidth: 100,
      },
      {
        Header: "판매 증가량",
        Name: "sSaleIncrease",
        Type: "Int",
        MinWidth: 100,
      },
      {
        Header: "가격",
        Name: "sPrice",
        Type: "Int",
        MinWidth: 150,
        Format: "#,##0원",
      },
      {
        Header: "만족도",
        Name: "sSatisfaction",
        Type: "Int",
        MinWidth: 100,
        Format: "#\\%",
      },
    ],
  },

  event: {
    onDataLoad: function (evtParam) {
      console.log(evtParam.eventName + " 발생")
      var leDate = new Date()

      estTime.textContent =

// 메시지 출력 (HTML 에서 id를 estTime 으로 줘서 이렇게 


        "데이터 로딩: " +
        (leDate - lsDate) +
        " ms / " +
        (leDate - lsDate) / 1000 +
        " 초"
      sheet.hideMessage()
    },
    onSearchFinish: function (evtParam) {
      console.log(evtParam.eventName + " 발생")
      var leDate = new Date()

      estTime.textContent +=
        " (총 렌더링: " +
        (leDate - lsDate) +
        " ms / " +
        (leDate - lsDate) / 1000 +
        " 초)"
    },
  },

  create: function () {

// create는 함수. ib 객체 안에 정의된 시트 생성용 함수. 


    var options = this.init

// this.init 은 ib.init을 의미. 초기화 설정값을 가져오는 것 (맨처음에 ib= { init = { 한 것)

// 그 초기화 설정값을 options 변수에 담아서 IBSheet생성 때 사용

    options.Events = this.event
    IBSheet.create({

// 실제 시트를 DOM에 생성


      id: "sheet", 


      el: "sheetDiv", 

// 시트를 생성할 Dom 객체 및 id


      options: options, 

// 생성될 시트의 속성
      data: [],
    })
  },


// 아래는 화면 기능


  sampleBtn: function () {

// sampleBtn 버튼 클릭 시 데이터 생성 및 시트 로딩


    setTimeout(function () {
      sheet.showMessage("데이터 조회 중...", 4, 1)
    }, 1)

// 조회 중 메시지 표시하는 것. 1ms후 실행


    setTimeout(function () {
      dataTime.textContent = "데이터 생성중입니다."
      sheet.loadSearchData(
        createData(document.getElementById("massData").value),

// loadSearchData() 로 가짜 데이터 만들어 로딩


      )
    }, 50)
  },
  //조회 데이터
  data: "해당 화면에서는 데이터가 동적으로 생성됩니다.",
}
ib.create()
var createData = function (count) {

// createData 함수 생성


  var start = new Date()


  var data = []
  var company = [
    "Google",
    "Apple",
    "삼성전자",
  ]
  var country = [
    "미국",
    "일본",
    "한국",
  ]

  for (var i = 0; i < count; i++) {
    data.push({
      sCompany: company[Math.floor(Math.random() * 10)],
      sCountry: country[Math.floor(Math.random() * 10)],
      sSaleQuantity: Math.floor(Math.random() * 100000),
      sSaleIncrease: Math.floor(Math.random() * 10000),
      sPrice: Math.floor(Math.random() * 10000000),
      sSatisfaction: Math.floor(Math.random() * (100 - 50 + 1) + 50),
    })
  }

// 임시 데이터 계산해서 넣기

 

  var cols = sheet.getCols()
// 시트의 모든 컬럼 이름 배열을 가져온다.


  for (var i = 0; i < cols.length; i++) {

// 컬럼 개수만큼 반복


    if (sheet.Cols[cols[i]].Visible == 0) {

// 컬럼이 .Visible == 0   숨김상태면


      cols.splice(i, i + 1)
    }
  }
// cols 배열에서 제거


  dataTime.textContent =
    "데이터 생성 (" +
    (cols.length * data.length).toLocaleString() +     " 셀): " +

// 컬럼 수 * 행 수 = 전체 셀 개수

// toLocaleString() 은 숫자를 천 단위 콤마로 표시


    (new Date() - start) +     " ms / " +

// 지금 시간 - 시작 시간 = 소요된 시간 을 밀리초로 보여줌

    (new Date() - start) / 1000 +     " 초"

// 밀리초를 초로 변경해서 보여줌

출력 예시

 


// 아래는 데이터 구문 처리


  var showData = []
// 보여줄 데이터를 담을 showData 배열을 초기화


  for (var i = 0; i < data.length && i < 20; i++) {

    showData.push(data[i])

// 최대 20개까지 복사해서 showData에 저장
  }


  var _data = JSON.stringify(showData, null, 2)
// showData를 2칸 들여쓰기해서 JSON 문자열로 변환

// JSON.stringify(객체, null, 들여쓰기숫자)

// null 부분은 필터


  if (data.length > 20) {
    _data = _data.substring(0, _data.length - 1) + "...\n]"
// 만약 데이터 길이가 20 초과하면 출력에 ... 문자열 붙이기

 

}
  try {
    myTabs.contents
      .items(1)

// 탭UI의 두 번째 탭에
      .setContents(
        '<pre><code class="language-json">' + _data + "</code></pre>",
      )
// JSON 데이터를 코드 블록으로 출력

// <pre> : 줄바꿈 유지

// <code> : HTML 에서 코드 처럼 표시


    hljs.initHighlighting.called = false
    hljs.initHighlighting()

// 하이라이트 JS를 재실행해서 JSON 을 예쁘게 표시하기 위함

// 하이라이트 라이브러리 : 프로그래밍 코드에 색을 넣어서 예쁘게 만듦


  } catch (e) {
    console.log("IBTab 이 존재하지 않습니다.")

// myTabs가 없으면 에러나니까 try-catch 로 잡음
  }
  window.lsDate = new Date()
// 최종 로딩 완료 시각을 전역변수로 저장

// new Date() : 지금 시각

// window.lsData : 브라우저 전체 어디서든 접근할 수 있는 전역 변수

// 나중에 onSearchFinish 등에서 시간 계산용으로 쓸 수 있다.   

-> 이 부분 설명

 

  return data;

// 최종 생성된 데이터 배열 반환
}

 

 


 

 

 

 

내가 만든 Spring 연동 데이터 전체 코드

 

 

<template>
    <div>
        <div class="klozSheet" id="klozSheet" style="width: 1000px; height: 600px;"></div>
    </div>
</template>

<script setup>
import { onMounted } from 'vue'
import loader from '@ibsheet/loader'
import axios from 'axios'

onMounted(() => {
    loader.config({
        registry: [{
            name: 'ibsheet',
            baseUrl: '/sheet',
            theme: 'mint',
            locales: ['ko', 'en'],
            plugins: ['common', 'dialog', 'excel']
        }]
    });
    loader.load();

    setTimeout(async () => {
        try {
            const res = await axios.post('http://localhost:8080/main/main.do'); // 스프링에서 받은 실제 데이터

            const initOptions = {
                Cfg: {
                    SearchMode: 0,
                    CustomScroll: 0,
                    HeaderCheck: 1
                },
                Def: {
                    Col: {
                        RelWidth: 1
                    }
                },
                LeftCols: [
                    { Header: "No.", Name: "SEQ", Type: "Int", RelWidth: 0, Width: 80, Align: "Center" }
                ],
                Cols: [
                    { Header: "계정과목", Name: "accountTitle", Type: "Text", MinWidth: 150, Align: "Center" },
                    { Header: "자산코드", Name: "assetCode", Type: "Text", MinWidth: 100, Align: "Center" },
                    { Header: "자산명", Name: "assetName", Type: "Text", MinWidth: 120 },
                    { Header: "취득수량", Name: "acqQty", Type: "Int", MinWidth: 100 },
                    { Header: "취득금액", Name: "acqPrice", Type: "Int", MinWidth: 150, Format: "#,##0원" }
                ],
                Events: {
                    onDataLoad: function (evtParam) {
                        console.log(evtParam.eventName + ' 발생');
                    },
                    onSearchFinish: function (evtParam) {
                        console.log(evtParam.eventName + ' 발생');
                    }
                },
                Data: res.data.Data || [] // 스프링 서버에서 받은 실제 데이터 삽입
            };

            const sheet = await loader.createSheet({
                id: 'mySheet',
                el: 'klozSheet',
                options: initOptions
            });

            console.log("✅ IBSheet 생성 완료", sheet);
        } catch (err) {
            console.error("❌ 데이터 호출 또는 IBSheet 생성 실패", err);
        }
    }, 300);
});
</script>

<style scoped>
/* 필요시 스타일 */
</style>

 

 

 

 

 

● Spring 연동 코드 한 줄씩 주석

 

 

<script setup>
import { onMounted } from 'vue'

// Vue의 생명주기 훅 중 하나인 onMounted()를 import. 컴포넌트가 처음 화면에 나타날 때 실행할 코드 등록


import loader from '@ibsheet/loader'

// IBSheet를 동적으로 불러오기 위한 공식 로더 모듈을 가져오는 것. 시트 생성 시 필수

 

import axios from 'axios'
// 서버에 HTTP 요청을 보내기 위한 axios 모듈 가져옴.   POST 방식으로 데이터 받을 때 사용

 

onMounted(() => {

// 컴포넌트가 마운트된 직후! (=DOM에 붙은 뒤)에 실행할 함수 등록. 시트 만들 타이밍

 

    loader.config({

// IBSheet 가 사용할 설정을 미리 등록. 초기값 정의 (경로, 테마, 플러그인, 언어 등)

        registry: [{
            name: 'ibsheet',
            baseUrl: '/sheet',
            theme: 'mint',
            locales: ['ko', 'en'],
            plugins: ['common', 'dialog', 'excel']
        }]
    });
    loader.load();

    setTimeout(async () => {

// IBSheet 가 로딩 완료될 시간을 주기 위해  , 뒤의 밀리초만큼 시간을 줌

// setTimeout()자체는 비동기지만 async를 쓰면 {} 내부에 await 쓸 수 있다.


        try {
            const res = await axios.post('http://localhost:8080/main/main.do'); 

// 스프링에서 받은 실제 데이터..  Spring서버에 POST 요청을 보내고 응답 받은 것.


            const initOptions = {

// IBSheet 를 생성할 때 필요한 시트 구성 옵션을 모두 정의하는 것. Cfg, Cols, 이벤트, 데이터 등

 

                Cfg: {

// IBSheet의 기본 동작 설정. 스크롤 방식이나 헤더 체크 등
                    SearchMode: 0,
                    CustomScroll: 0,
                    HeaderCheck: 1
                },
                Def: {
                    Col: {

                        RelWidth: 1

                    }
                },
                LeftCols: [

// 이건 고정 컬럼
                    { Header: "No.", Name: "SEQ", Type: "Int", RelWidth: 0, Width: 80, Align: "Center" }
                ],
                Cols: [

// 컬럼 정보 (이름, 너비, 정렬, 포맷 등) 정의
                    { Header: "계정과목", Name: "accountTitle", Type: "Text", MinWidth: 150, Align: "Center" },
                    { Header: "자산코드", Name: "assetCode", Type: "Text", MinWidth: 100, Align: "Center" },
                    { Header: "자산명", Name: "assetName", Type: "Text", MinWidth: 120 },
                    { Header: "취득수량", Name: "acqQty", Type: "Int", MinWidth: 100 },
                    { Header: "취득금액", Name: "acqPrice", Type: "Int", MinWidth: 150, Format: "#,##0원" }
                ],
                Events: {

// IBSheet 이벤트 등록. 로그 찍기 등 가능
                    onDataLoad: function (evtParam) {
                        console.log(evtParam.eventName + ' 발생');
                    },
                    onSearchFinish: function (evtParam) {
                        console.log(evtParam.eventName + ' 발생');
                    }
                },
                Data: res.data.Data || [] 

// 스프링에서 받은 실제 데이터
            };

            const sheet = await loader.createSheet({

// 위에서 설정한 옵션대로 IBSheet 를 실제로 화면에 생성
                id: 'mySheet',
                el: 'klozSheet',

// el (요소)로 준 이름으로 <template> 에서 생성됨
                options: initOptions
            });

            console.log("✅ IBSheet 생성 완료", sheet);
        } catch (err) {
            console.error("❌ 데이터 호출 또는 IBSheet 생성 실패", err);
        }
    }, 300);
});
</script>

 

 


 

 

한 줄씩 공부하면서 생긴 질문들

 

- Col과 Cols 차이

 

Col : 컬럼에 대한 기본 설정값 (공통값) 정의 RelWidth, Align 등

Cols : 시트에 실제 표시될 각 컬럼 개별 설정 (Header, Name, Type 등)

Def.Col 은 전체 공통, Def.Cols 는 각각 컬럼별 상세 정의

 

 

- 왜 res.data.Data인지 ?

 

axios.post 는 서버의 응답을 res라는 객체에 담는다.

res.data는 그 중 서버가 실제로 보낸 데이터의 본문 body에 해당한다.

Spring에서 Map을 return하면JSON이 되고 -> 이게 res.data로 받아짐

res는 전체 응답이고 그 중 JSON내용은 res.data가 되는 것.

전체 응답에는 body 본문 뿐만 아니라

res.status : HTTP 상태 코드 (200,404 등)

res.headers: 응답 헤어

res.config: 요청 당시 설정 정보

res.statusText: 상태메시지 (예 "OK")

같은 걸 사용할 수 있다.

 

 

- 근데 loader 쓸 때 install loader 로 하면 안되는지 ?

 

장난합니까 ?

install 과 import 둘 다 해야합니다.


 

 

toLocaleString()

숫자를 천 단위 콤마로 표시

 dataTime.textContent =
    (cols.length * data.length).toLocaleString()

 

 

 

 

substring(시작, 끝)

"문자열".substring(시작, 끝)


  if (data.length > 20) {
    _data = _data.substring(0, _data.length - 1) + "...\n]"

 

 

 

 

● JSON.stringify(객체, 필터, 들여쓰기)

 

 

- replacer : 어떤 속성(key)를 포함하는지 필터링하는 역할

                  null을 주면 필터 없음

                  함수, 배열도 가능

 

- space : 들여쓰기

               숫자도 되고 '\t' 처럼 탭도 가능

 

JSON.stringify(obj, replacer, space)
const data = {
  name: "홍길동",
  age: 30,
  job: "개발자"
};


<!-- name과 job만 출력하고 싶을 때  -->

const result = JSON.stringify(data, ['name', 'job'], 2);
console.log(result);


<!-- null 일 때 -->

var _data = JSON.stringify(showData, null, 2)


<!-- 함수 -->

JSON.stringify(obj, (key, value) => {
  if (key === "password") return undefined; // 비밀번호 제거
  return value;
});

 


 

 

● onSearchFinish() 시간 계산 설명

window.lsDate = new Date(); // 데이터 요청 시작 시간 저장
onSearchFinish: function(evtParam) {
  const now = new Date();
  const diff = now - window.lsDate;
  console.log("총 렌더링: " + diff + "ms");
}

 

onSearchFinish 는 데이터 렌더링이 끝났을 때 실행되는 함수로

둘을 빼서 소요시간 ms 를 구하는것