** 일단 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 를 구하는것
'웹 개발 > IBSheet8' 카테고리의 다른 글
| [IBSheet] 시트 내 이미지 삽입 / 반환타입과 파라미터요청, JSON요청(1) (3) | 2025.08.01 |
|---|---|
| [IBSheet] onClick(), onDblClick(), onAfterClick() 이벤트로 수정, 삭제 시 열이름 클릭 제외 (0) | 2025.06.30 |
| [IBSheet] Excel 내보내기 (1) | 2025.06.24 |
| [IBSheet] 단일 행 수정 (JS 동적 속성 접근, 요청/응답) (1) | 2025.06.10 |
| [IBSheet] loader (0) | 2025.06.04 |