Frameworks and eGovFrame
Ready-made viewer and designer components for React, Vue 3, Svelte 5 and Angular, and an eGovFrame 4.3 (Spring, JSP, MyBatis) sample project to download.
The core works in any framework: create the viewer or designer when the component mounts and destroy it when it unmounts. Ready-made components are published on npm: @freereportjs/react, @freereportjs/vue (Vue 3), @freereportjs/svelte (Svelte 5) and @freereportjs/angular, each with a viewer and a designer. Install the core alongside the wrapper, for example npm i @freereportjs/core @freereportjs/react.
- React: <FreeReportViewer> and <FreeReportDesigner>. The viewer ref is { viewer, report }; the designer takes onChange and onSave.
- Vue: the viewer exposes viewer and report; the designer supports v-model:definition and emits change, update:definition and save.
- Svelte: viewer.getViewer() / getReport() and designer.getDesigner(), or onReady.
- Angular: <free-report-viewer> and <free-report-designer> (standalone). The designer emits (definitionChange), so [(definition)] works, and (save).
definition, data, params and zoom update the viewer in place; other props recreate it. Both components default to height: 100% with a 480px minimum.
// 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>eGovFrame sample project
The sample is an eGovFrame 4.3 project (Spring 5.3, MyBatis, JDK 8+) that shows report viewing, printing, PDF and Excel and an output log. The server returns only the report definition and the data as JSON; layout, printing and files are made in the browser, with no report server, ActiveX or installer. For eGovFrame 3.x, change the imports and the groupId from org.egovframe.rte to egovframework.rte.
| Route | Returns | Description |
|---|---|---|
GET /report/view.do?name=sales | JSP | Viewer page (reportView.jsp) |
GET /report/designer.do?name=sales | JSP | Designer page (reportDesigner.jsp) |
GET /report/def/{name}.do | JSON | Report definition: the copy saved in REPORT_DEF, or classpath:reports/{name}.json |
POST /report/def/{name}.do | JSON | Saves the definition from the designer |
GET /report/data/sales.do | JSON | Report data (Service → MyBatis) |
POST /report/log.do | JSON | Records the viewer onOutput event in REPORT_OUTPUT_LOG |
GET /report/logs.do | JSP | The latest 100 output log entries |
Download the eGovFrame sample project (ZIP) eGovFrame 4.3 · Maven · JSP · MyBatis · HSQLDB — unzip and run mvn jetty:run (see README.md).