This article walks you through creating a Spring Boot 3.5.7 web application that serves an Aspose.Cells GridJs backend and a lightweight HTML/JavaScript front‑end. The demo demonstrates how to:
- Generate a Spring Boot project with the required dependencies.
- Configure GridJs server options (
GridJsOptions). - Expose GridJs controller endpoints for loading spreadsheets, updating cells, handling images, OLE objects, and file download.
- Build a client UI using the
gridjs-spreadsheetnpm package and auxiliary libraries (jQuery, jQuery‑UI, JSZip). - Load a workbook, interact with it, and persist changes back to the server.
All code snippets are complete, ready to compile, and can be run locally.
{{% alert color="primary" %}}
Prerequisite: You must have a valid Aspose.Cells GridJs license (or use a 30‑day evaluation). Place the license file (Aspose.Cells.GridJs.lic) under src/main/resources and load it in the Spring Boot application startup (not shown here for brevity).
{{% /alert %}}
- Open https://start.spring.io/.
- Select Spring Boot 3.5.7 and Java 17.
- Fill the Project Metadata (e.g.,
groupId: com.example,artifactId: gridjs-demo). - Add the Spring Web dependency.
- Click Generate, unzip the archive, and open it in your IDE.
The generated project already contains the basic Spring Boot starter class.
Edit pom.xml and add the Aspose.Cells GridJs and Gson libraries:
<!-- pom.xml -->
<project>
<!-- ... existing content ... -->
<dependencies>
<!-- Aspose.Cells core -->
<dependency>
<groupId>com.aspose</groupId>
<artifactId>aspose-cells</artifactId>
<version>25.11</version>
</dependency>
<!-- Aspose.Cells GridJs classifier -->
<dependency>
<groupId>com.aspose</groupId>
<artifactId>aspose-cells</artifactId>
<classifier>gridjs</classifier>
<version>25.11</version>
</dependency>
<!-- Gson for JSON handling -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<!-- Spring Web (already added by Spring Initializr) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- Aspose.Cells repository -->
<repositories>
<repository>
<id>AsposeJavaAPI</id>
<name>Aspose Java API</name>
<url>https://repository.aspose.com/repo/</url>
</repository>
</repositories>
</project>Run mvn clean install to download the new libraries.
Create a configuration class that registers a GridJsOptions bean.
// src/main/java/com/example/gridjsdemo/config/GridJsConfig.java
package com.example.gridjsdemo.config;
import com.aspose.gridjs.GridJsOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configures Aspose.Cells GridJs options.
*/
@Configuration
public class GridJsConfig {
@Bean
public GridJsOptions gridJsOptions() {
GridJsOptions options = new GridJsOptions();
// Directory where temporary files (e.g., JSON cache) are stored
options.setFileCacheDirectory("D:/storage/Aspose.Cells.GridJs/");
// Base route used by the GridJs controller
options.setBaseRouteName("/GridJs");
return options;
}
}Add component scanning for the Aspose GridJs package.
// src/main/java/com/example/gridjsdemo/GridJsDemoApplication.java
package com.example.gridjsdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* Entry point of the GridJs demo application.
*/
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.gridjsdemo", "com.aspose.gridjs"})
public class GridJsDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GridJsDemoApplication.class, args);
}
}Extend GridJsControllerBase to expose the required endpoints.
// src/main/java/com/example/gridjsdemo/controller/GridJsController.java
package com.example.gridjsdemo.controller;
import com.aspose.gridjs.GridJsJakartaControllerBase;
import com.aspose.gridjs.GridJsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
/**
* REST controller exposing GridJs operations.
*/
@RestController
@RequestMapping("/GridJs")
public class GridJsController extends GridJsJakartaControllerBase {
@Autowired
public GridJsController(GridJsService gridJsService) {
super(gridJsService);
}
/**
* Loads a spreadsheet (JSON representation) for the client.
*/
@GetMapping("/LoadSpreadsheet")
public ResponseEntity<String> loadSpreadsheet(
@RequestParam String filename,
@RequestParam String uid) {
String fullFilePath = getFullFilePath(filename);
StringBuilder result = _gridJsService.detailFileJsonWithUid(fullFilePath, uid);
return ResponseEntity.ok()
.header("Content-Type", "text/plain; charset=UTF-8")
.body(result.toString());
}
/**
* Helper to resolve the absolute file system path.
* <p>
* Adjust the base directory according to your environment.
*/
private String getFullFilePath(String filename) {
// Example: store all demo spreadsheets under src/main/resources/spreadsheets
return System.getProperty("user.dir") + "/src/main/resources/spreadsheets/" + filename;
}
// -------------------------------------------------------------------------
// The remaining endpoints simply delegate to the base implementation.
// -------------------------------------------------------------------------
@PostMapping("/UpdateCell")
public ResponseEntity<String> updateCell(HttpServletRequest request) {
try {
return super.updateCell(request);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body(e.getMessage());
}
}
@PostMapping("/AddImage")
public ResponseEntity<String> addImage(
@RequestParam(value = "image", required = false) MultipartFile file,
@RequestParam("uid") String uid,
@RequestParam("p") String p,
@RequestParam(value = "control", required = false) String isControl) {
return super.addImage(file, uid, p, isControl);
}
@PostMapping("/CopyImage")
public ResponseEntity<String> copyImage(HttpServletRequest request) {
return super.copyImage(request);
}
@PostMapping("/AddImageByURL")
public ResponseEntity<String> addImageByUrl(HttpServletRequest request) {
return super.addImageByUrl(request);
}
@GetMapping("/Image")
public ResponseEntity<InputStreamResource> getImage(HttpServletRequest request) {
return super.getImage(request);
}
@GetMapping("/ImageUrl")
public ResponseEntity<String> getImageUrl(@RequestParam String id, @RequestParam String uid) {
return super.getImageUrl(id, uid);
}
@GetMapping("/Ole")
public ResponseEntity<?> getOle(HttpServletRequest request) {
return super.getOle(request);
}
@GetMapping("/GetFile")
public ResponseEntity<?> getFile(@RequestParam("id") String id) {
return super.getFile(id);
}
@PostMapping("/Download")
public ResponseEntity<String> download(HttpServletRequest request) {
return super.download(request);
}
@GetMapping("/Index")
public ResponseEntity<String> index() {
// Simple health endpoint or optional UI starter page.
return ResponseEntity.ok("GridJs service is running.");
}
}Note: Place any sample Excel files you wish to test under
src/main/resources/spreadsheets.
Ensure the directoryD:/storage/Aspose.Cells.GridJs/exists or update the path inGridJsConfig.
All static resources are located under src/main/resources/static.
<!-- src/main/resources/static/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GridJs Demo – Load Spreadsheet</title>
<!-- jQuery and jQuery‑UI -->
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet"
href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"/>
<!-- JSZip (required for export) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js"></script>
<!-- GridJs Spreadsheet UI -->
<link rel="stylesheet"
href="https://unpkg.com/gridjs-spreadsheet/xspreadsheet.css"/>
<script src="https://unpkg.com/gridjs-spreadsheet/xspreadsheet.js"></script>
<!-- Demo specific script -->
<script src="./gridjs-demo.js"></script>
<style>
body {font-family: Arial, sans-serif; margin: 20px;}
#gridjs-demo-uid {width: 100%; height: 800px;}
</style>
</head>
<body>
<h1>GridJs Spreadsheet Demo</h1>
<!-- Container for the GridJs UI -->
<div id="gridjs-demo-uid"></div>
<!-- Simple UI to pick a file from the server -->
<div style="margin-top:20px;">
<label for="filename">Spreadsheet file (in server folder): </label>
<input type="text" id="filename" value="Sample.xlsx"/>
<button id="loadBtn">Load Spreadsheet</button>
</div>
</body>
</html>// src/main/resources/static/gridjs-demo.js
/**
* GridJs Demo – client side logic.
* Loads a workbook from the server, displays it, and enables server‑side updates.
*/
$(function () {
// -------------------------------------------------------------
// 1. Define URLs used by the demo
// -------------------------------------------------------------
const queryJsonUrl = "/GridJs/LoadSpreadsheet";
const updateUrl = "/GridJs/UpdateCell";
const fileDownloadUrl = "/GridJs/Download";
const oleDownloadUrl = "/GridJs/Ole";
const imageUrl = "/GridJs/ImageUrl";
const imageUploadUrl1 = "/GridJs/AddImage";
const imageUploadUrl2 = "/GridJs/AddImageByURL";
const imageCopyUrl = "/GridJs/CopyImage";
// -------------------------------------------------------------
// 2. Global GridJs instance placeholder
// -------------------------------------------------------------
let xs; // will hold the x_spreadsheet instance
// -------------------------------------------------------------
// 3. Helper to generate a UUID (used as unique session id)
// -------------------------------------------------------------
function generateUUID() {
// RFC4122 version 4 compliant UUID
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
// -------------------------------------------------------------
// 4. Load Spreadsheet button click handler
// -------------------------------------------------------------
$("#loadBtn").on("click", function () {
const filename = $("#filename").val().trim();
if (!filename) {
alert("Please enter a file name.");
return;
}
const uid = generateUUID(); // unique identifier for this session
// Build request URL with query parameters
const requestUrl = `${queryJsonUrl}?filename=${encodeURIComponent(filename)}&uid=${uid}`;
// ---------------------------------------------------------
// 5. AJAX request to obtain the JSON representation of the workbook
// ---------------------------------------------------------
$.ajax({
url: requestUrl,
method: "GET",
dataType: "text", // server returns plain text JSON
success: function (responseJsonString) {
const jsondata = JSON.parse(responseJsonString);
const option = {
updateMode: 'server',
updateUrl: updateUrl,
local: 'en' // UI language
};
loadWithOption(jsondata, option, uid);
},
error: function (xhr, status, err) {
console.error("Failed to load spreadsheet:", err);
alert("Error loading file: " + err);
}
});
});
// -------------------------------------------------------------
// 6. Function that creates the GridJs UI and binds all URLs
// -------------------------------------------------------------
function loadWithOption(jsondata, option, uniqueId) {
// Clear any previous instance
$('#gridjs-demo-uid').empty();
const sheets = jsondata.data;
const filename = jsondata.filename;
// Initialise the GridJs UI
xs = x_spreadsheet('#gridjs-demo-uid', option)
.loadData(sheets)
.updateCellError((msg) => console.error(msg));
// Hide sheet tabs if server says not to show them
if (!jsondata.showtabs) {
xs.bottombar.hide();
}
// Associate the unique identifier and file name
xs.setUniqueId(uniqueId);
xs.setFileName(filename);
// ---------------------------------------------------------
// Set the active sheet & cell (fallback to first sheet)
// ---------------------------------------------------------
let activeSheetName = jsondata.actname;
if (xs.bottombar.dataNames.includes(activeSheetName)) {
xs.setActiveSheetByName(activeSheetName)
.setActiveCell(jsondata.actrow, jsondata.actcol);
} else {
// If the requested sheet is hidden or a chart sheet, use the first sheet
activeSheetName = xs.bottombar.dataNames[0];
xs.setActiveSheetByName(activeSheetName).setActiveCell(0, 0);
}
// ---------------------------------------------------------
// Bind auxiliary URLs (image handling, OLE, file download, etc.)
// ---------------------------------------------------------
xs.setImageInfo(imageUrl, imageUploadUrl1, imageUploadUrl2, imageCopyUrl, true);
xs.setFileDownloadInfo(fileDownloadUrl);
xs.setOleDownloadInfo(oleDownloadUrl);
xs.setOpenFileUrl("/"); // optional: opens home page
}
});Explanation of the client flow
| Step | Description |
|---|---|
| 1 | Define all server‑side endpoints (load, update, image, OLE, download). |
| 2 | Create a global variable xs that will hold the GridJs instance. |
| 3 | Generate a UUID per session – used by the server to cache workbook JSON. |
| 4 | When the Load Spreadsheet button is clicked, an AJAX GET request fetches the workbook JSON. |
| 5 | The returned JSON is parsed and fed to x_spreadsheet(...).loadData(...). |
| 6 | After the UI is created, set the unique id, file name, active sheet/cell, and bind all ancillary URLs (image upload, download, …). |
-
Start the Spring Boot application
./mvnw spring-boot:run
-
Open the UI in a browser:
http://localhost:8080/index.html -
Enter the name of a spreadsheet located under
src/main/resources/spreadsheets(e.g.,Sample.xlsx) and click Load Spreadsheet. -
The workbook appears inside the
#gridjs-demo-uidcontainer. Edit cells, add images, or download the updated file – all changes are persisted on the server via the GridJs REST API.
{{% alert color="primary" %}}
If you encounter a 404 on the JSON load request, verify that the file name is correct and that the getFullFilePath method points to the proper directory.
{{% /alert %}}
| Step | Screenshot |
|---|---|
| A – Application home page with file input | ![]() |
| B – Loaded workbook displayed in GridJs UI | ![]() |
| C – Editing a cell (server side update) | ![]() |
| D – Downloading the modified file | ![]() |
- Aspose.Cells GridJs Java API Reference – https://reference.aspose.com/cells/java/com.aspose.gridjs
- GridJs‑spreadsheet NPM package – https://www.npmjs.com/package/gridjs-spreadsheet
- Demo Source – https://github.com/aspose-cells/Aspose.Cells.Grid-for-Java/tree/main/Examples.GridJs.Simple
- Spring Boot Official Documentation – https://spring.io/projects/spring-boot




