프레임워크와 전자정부
React, Vue 3, Svelte 5, Angular용 뷰어·디자이너 컴포넌트와, 내려받아 바로 실행하는 전자정부 표준프레임워크 4.3(Spring, JSP, MyBatis) 예제 프로젝트입니다.
코어는 어떤 프레임워크에서든 씁니다. 컴포넌트가 붙을 때 뷰어나 디자이너를 만들고 떨어질 때 destroy하면 됩니다. 바로 쓰는 컴포넌트가 npm에 배포되어 있습니다: @freereportjs/react, @freereportjs/vue(Vue 3), @freereportjs/svelte(Svelte 5), @freereportjs/angular. 각각 뷰어와 디자이너를 제공하며, npm i @freereportjs/core @freereportjs/react처럼 코어와 함께 설치합니다.
- React: <FreeReportViewer>, <FreeReportDesigner>. 뷰어 ref는 { viewer, report }이고, 디자이너는 onChange, onSave를 받습니다.
- Vue: 뷰어는 viewer, report를 노출하고, 디자이너는 v-model:definition을 지원하며 change, update:definition, save 이벤트를 보냅니다.
- Svelte: viewer.getViewer() / getReport(), designer.getDesigner() 또는 onReady.
- Angular: <free-report-viewer>, <free-report-designer>(standalone). 디자이너는 (definitionChange)를 보내 [(definition)]이 동작하고, (save)도 보냅니다.
definition, data, params, zoom은 뷰어를 그대로 두고 갱신하고, 나머지 속성은 뷰어를 다시 만듭니다. 두 컴포넌트 모두 기본 높이는 100%, 최소 480px입니다.
// npm i @freereportjs/core @freereportjs/react
import { useRef, useState } from 'react';
import { FreeReportDesigner, FreeReportViewer, type ReportDefinition } from '@freereportjs/react';
import '@freereportjs/core/styles.css';
export function SalesReport({ definition, rows }) {
const ref = useRef(null); // { viewer, report }
return <FreeReportViewer ref={ref} definition={definition} data={{ rows }} lang="ko" style={{ height: 720 }} />;
}
export function SalesDesigner({ initial, rows, save }) {
const [def, setDef] = useState<ReportDefinition>(initial);
return <FreeReportDesigner definition={def} data={{ rows }} onChange={setDef} onSave={save} />;
}<!-- npm i @freereportjs/core @freereportjs/vue -->
<script setup>
import { ref } from 'vue';
import { FreeReportDesigner, FreeReportViewer } from '@freereportjs/vue';
import '@freereportjs/core/styles.css';
const props = defineProps(['initial', 'rows']);
const def = ref(props.initial);
const viewer = ref(null); // viewer.value.viewer / viewer.value.report
const save = d => fetch('/api/reports/sales', { method: 'PUT', body: JSON.stringify(d) });
</script>
<template>
<FreeReportViewer ref="viewer" :definition="def" :data="{ rows }" lang="ko" :height="720" />
<FreeReportDesigner v-model:definition="def" :data="{ rows }" @save="save" />
</template><!-- npm i @freereportjs/core @freereportjs/svelte (Svelte 5) -->
<script>
import { FreeReportDesigner, FreeReportViewer } from '@freereportjs/svelte';
import '@freereportjs/core/styles.css';
let { initial, rows, save } = $props();
let def = $state(initial);
let viewer; // viewer.getViewer(), viewer.getReport()
</script>
<FreeReportViewer bind:this={viewer} definition={def} data={{ rows }} lang="ko" style="height: 720px" />
<FreeReportDesigner definition={def} data={{ rows }} onChange={d => (def = d)} onSave={save} />// npm i @freereportjs/core @freereportjs/angular
// angular.json "styles": ["node_modules/@freereportjs/core/dist/styles.css"]
import { Component } from '@angular/core';
import { FreeReportDesignerComponent, FreeReportViewerComponent } from '@freereportjs/angular';
@Component({
selector: 'app-sales-report',
imports: [FreeReportViewerComponent, FreeReportDesignerComponent],
template: `
<free-report-viewer [definition]="def" [data]="data" lang="ko" [height]="720" />
<free-report-designer [(definition)]="def" [data]="data" (save)="save($event)" />`,
})
export class SalesReportComponent {
def = initialDefinition;
data = { rows: [] };
save(def) { /* PUT the JSON to your server */ }
}<%-- reportView.jsp: the viewer in an eGovFrame (Spring + JSP) page --%>
<link rel="stylesheet" href="<c:url value='/static/freereport/freereport.css'/>">
<div id="viewer" style="height: 760px" data-ctx="${fn:escapeXml(pageContext.request.contextPath)}"></div>
<script src="<c:url value='/static/freereport/freereport.min.js'/>"></script>
<script>
var ctx = document.getElementById('viewer').dataset.ctx;
Promise.all([
fetch(ctx + '/report/def/sales.do').then(function (r) { return r.json(); }), // report JSON
fetch(ctx + '/report/data/sales.do').then(function (r) { return r.json(); }) // { rows: [...] } from MyBatis
]).then(function (res) {
FreeReport.createViewer(document.getElementById('viewer'), {
definition: res[0], data: res[1], lang: 'ko',
onOutput: function (e) { /* POST to the output log controller */ }
});
});
</script>전자정부 표준프레임워크 예제 프로젝트
예제는 전자정부 표준프레임워크 4.3(Spring 5.3, MyBatis, JDK 8 이상) 프로젝트로, 보고서 조회·인쇄·PDF·엑셀 출력과 출력 이력 관리까지 담았습니다. 서버는 보고서 정의와 데이터를 JSON으로만 내려 주고, 화면 구성·인쇄·파일 생성은 브라우저에서 처리하므로 별도 리포트 서버, ActiveX, 설치 프로그램이 필요 없습니다. 3.x 프로젝트는 import 문과 groupId를 org.egovframe.rte에서 egovframework.rte로 바꾸면 됩니다.
| 주소 | 응답 | 설명 |
|---|---|---|
GET /report/view.do?name=sales | JSP | 뷰어 화면 (reportView.jsp) |
GET /report/designer.do?name=sales | JSP | 디자이너 화면 (reportDesigner.jsp) |
GET /report/def/{name}.do | JSON | 보고서 정의: REPORT_DEF 저장본, 없으면 classpath:reports/{name}.json |
POST /report/def/{name}.do | JSON | 디자이너에서 저장한 정의 저장 |
GET /report/data/sales.do | JSON | 보고서 데이터 (Service → MyBatis) |
POST /report/log.do | JSON | 뷰어 onOutput 이벤트를 REPORT_OUTPUT_LOG에 기록 |
GET /report/logs.do | JSP | 출력 이력 최근 100건 |
전자정부 예제 프로젝트 내려받기 (ZIP) 전자정부 표준프레임워크 4.3 · Maven · JSP · MyBatis · HSQLDB — 압축을 풀고 mvn jetty:run으로 실행합니다 (README.md 참고).