核心流程
无论采用哪种方案,基本流程都大同小异:

- 接收文件:通过 Web 接口(如 Spring Boot 的
MultipartFile)接收用户上传的 Excel 文件。 - 读取并解析:使用 Java 库(如 Apache POI)读取 Excel 文件内容。
- 格式转换:将解析出的内容转换为目标预览格式(如 HTML)。
- 前端展示:将转换后的 HTML 返回给前端,前端通过
<iframe>或直接渲染来展示预览。
使用 Apache POI + 自定义 HTML 转换(最灵活)
这是最核心也是最灵活的方法,你可以完全控制 HTML 的输出样式,但需要自己编写转换逻辑。
添加依赖
在你的 pom.xml 文件中添加 Apache POI 的依赖,建议使用较新的版本以获得更好的性能和兼容性。
<dependencies>
<!-- Spring Boot Web Starter (用于构建Web服务) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Apache POI for Excel -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
<!-- Lombok (简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
编写转换工具类
这个工具类负责将 Excel 的 Sheet 转换为 HTML 字符串。
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Iterator;
public class ExcelToHtmlConverter {
public static String convert(MultipartFile file) throws IOException {
// 1. 创建 Workbook 对象
try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) {
StringBuilder html = new StringBuilder();
// 2. 开始构建 HTML
html.append("<html><head><meta charset=\"UTF-8\"><style>")
.append("table { border-collapse: collapse; width: 100%; }")
.append("th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }")
.append("th { background-color: #f2f2f2; }")
.append("</style></head><body>")
.append("<table>");
// 3. 遍历所有 Sheet
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
Sheet sheet = workbook.getSheetAt(i);
if (i > 0) {
html.append("<br/>"); // 多个 sheet 之间用换行分隔
}
// 4. 获取行迭代器
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
html.append("<tr>");
// 5. 遍历单元格
Iterator<Cell> cellIterator = row.iterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
// 设置单元格标签 (th 或 td)
String cellTag = row.getRowNum() == 0 ? "th" : "td";
html.append("<").append(cellTag).append(">");
// 获取单元格值
switch (cell.getCellType()) {
case STRING:
html.append(cell.getStringCellValue());
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
html.append(cell.getDateCellValue());
} else {
html.append(cell.getNumericCellValue());
}
break;
case BOOLEAN:
html.append(cell.getBooleanCellValue());
break;
case FORMULA:
html.append(cell.getCellFormula());
break;
default:
html.append("");
}
html.append("</").append(cellTag).append(">");
}
html.append("</tr>");
}
}
// 6. 结束 HTML
html.append("</table></body></html>");
return html.toString();
}
}
}
创建 Controller
创建一个 Spring Boot Controller 来处理文件上传和转换。

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@RestController
@RequestMapping("/api/excel")
public class ExcelPreviewController {
@PostMapping("/preview")
public ResponseEntity<String> previewExcel(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body("请上传一个有效的文件");
}
try {
// 1. 调用转换工具类
String htmlContent = ExcelToHtmlConverter.convert(file);
// 2. 设置响应头,告诉浏览器返回的是 HTML
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_HTML);
headers.setContentLength(htmlContent.getBytes(StandardCharsets.UTF_8).length);
// 3. 返回转换后的 HTML
return ResponseEntity.ok()
.headers(headers)
.body(htmlContent);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("文件处理失败: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("发生未知错误: " + e.getMessage());
}
}
}
前端调用
前端可以使用一个简单的表单来上传文件,并用 <iframe> 来展示返回的 HTML。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">Excel 在线预览</title>
</head>
<body>
<h1>上传 Excel 文件进行预览</h1>
<form id="uploadForm" enctype="multipart/form-data">
<input type="file" id="fileInput" name="file" accept=".xls,.xlsx" />
<button type="submit">预览</button>
</form>
<hr>
<h2>预览区域</h2>
<iframe id="previewFrame" style="width: 100%; height: 600px; border: 1px solid #ccc;"></iframe>
<script>
document.getElementById('uploadForm').addEventListener('submit', function(e) {
e.preventDefault();
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
const previewFrame = document.getElementById('previewFrame');
if (!file) {
alert('请先选择一个文件!');
return;
}
const formData = new FormData();
formData.append('file', file);
// 使用 fetch API 发送文件
fetch('/api/excel/preview', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(html => {
// 将返回的 HTML 写入 iframe
const blob = new Blob([html], { type: 'text/html' });
previewFrame.src = URL.createObjectURL(blob);
})
.catch(error => {
console.error('Error:', error);
alert('预览失败,请检查控制台。');
});
});
</script>
</body>
</html>
使用现成的库(更简单,但依赖第三方)
如果你不想自己写转换逻辑,可以使用一些现成的 Java 库来完成这个任务。
推荐库:easypoi
EasyPoi 是一个功能强大的 Excel 导入导出工具,它内置了将 Excel 转换为 HTML 的功能。
添加依赖
<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- EasyPoi 核心包 -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies>
编写 Controller
使用 EasyPoi 的 ExcelToHtmlUtil 非常简单。
import cn.afterturn.easypoi.excel.ExcelToHtmlUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
@RequestMapping("/api/excel")
public class ExcelPreviewControllerEasyPoi {
@PostMapping("/preview-easypoi")
public ResponseEntity<String> previewExcelWithEasyPoi(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body("请上传一个有效的文件");
}
try {
// 1. 设置导入参数
ImportParams params = new ImportParams();
params.setTitleRows(1); // 标题行数
params.setHeadRows(1); // 表头行数
// 2. 使用 EasyPoi 进行转换
String html = ExcelToHtmlUtil.excelToHtml(file.getInputStream(), params);
// 3. 返回 HTML
return ResponseEntity.ok()
.contentType(MediaType.TEXT_HTML)
.body(html);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("文件处理失败: " + e.getMessage());
}
}
}
优点:
- 极其简单:几行代码就能实现,无需关心底层细节。
- 样式保留较好:能较好地保留 Excel 的单元格样式(如背景色、字体等)。
- 功能强大:除了转 HTML,还支持图片、公式等复杂内容。
缺点:
- 依赖第三方:项目引入了新的外部依赖,可能存在版本兼容性或安全风险。
- 定制性差:如果需要对生成的 HTML 进行深度定制(如添加特定 class、修改 CSS 结构),会比较困难。
纯前端方案(无需后端处理)
Excel 文件已经存在于服务器上(有公开的 URL),可以使用纯前端库来预览,完全无需后端进行转换。
推荐库:SheetJS (xlsx)
这是一个非常流行的 JavaScript 库,可以在浏览器中直接解析和渲染 Excel 文件。
引入库
在 HTML 页面中引入 SheetJS 的 CDN。
<script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"></script>
编写前端代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">Excel 在线预览 (纯前端)</title>
<style>
#drop-area {
border: 2px dashed #ccc;
border-radius: 8px;
padding: 25px;
text-align: center;
font-family: sans-serif;
margin: 20px;
}
#drop-area.highlight {
border-color: purple;
}
#excel-table {
margin: 20px auto;
border-collapse: collapse;
}
#excel-table th, #excel-table td {
border: 1px solid #ddd;
padding: 8px;
}
#excel-table th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<h1>拖放或点击上传 Excel 文件进行预览</h1>
<div id="drop-area">
<p>拖放 Excel 文件到这里,或者 <span id="file-input-label">点击选择文件</span></p>
<input type="file" id="file-input" accept=".xls,.xlsx" style="display: none;" />
</div>
<div id="result-container"></div>
<script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"></script>
<script>
const dropArea = document.getElementById('drop-area');
const fileInput = document.getElementById('file-input');
const fileInputLabel = document.getElementById('file-input-label');
const resultContainer = document.getElementById('result-container');
// 点击标签触发文件选择
fileInputLabel.addEventListener('click', () => fileInput.click());
// 监听文件选择
fileInput.addEventListener('change', handleFiles);
// 拖放事件
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropArea.classList.add('highlight');
}
function unhighlight() {
dropArea.classList.remove('highlight');
}
dropArea.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles({ target: { files: files } });
}
function handleFiles(e) {
const files = e.target.files;
if (files.length) {
const file = files[0];
const reader = new FileReader();
reader.onload = function(e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
// 获取第一个 sheet
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
// 将 sheet 转换为 HTML
const html = XLSX.utils.sheet_to_html(worksheet);
// 显示结果
resultContainer.innerHTML = html;
};
reader.readAsArrayBuffer(file);
}
}
</script>
</body>
</html>
优点:
- 无后端负担:所有处理都在浏览器完成,减轻了服务器压力。
- 用户体验好:拖放上传,即时预览,响应迅速。
- 部署简单:只需要一个静态 HTML 文件即可。
缺点:
- 文件大小限制:浏览器内存有限,大文件(如 50MB+)可能会导致页面卡顿或崩溃。
- 安全性:直接在浏览器中处理用户文件,虽然现代浏览器有沙箱机制,但仍需注意。
- 功能限制:对于 Excel 中复杂的公式、宏、图表等支持有限。
方案对比与选择建议
| 方案 | 实现复杂度 | 性能 | 样式保留 | 定制性 | 适用场景 |
|---|---|---|---|---|---|
| 方案一: POI + 自定义 | 高 | 好 | 需手动实现 | 极高 | 对预览效果有严格要求,需要深度定制样式和结构的场景。 |
| 方案二: EasyPoi | 低 | 好 | 较好 | 低 | 快速实现,对样式有一定要求,不想自己编写转换逻辑的项目。 |
| 方案三: 纯前端 | 中 | 受限 | 一般 | 中 | 文件较小,追求极致用户体验,希望减轻服务器负担的场景。 |
如何选择?
- 如果你是个人项目或快速原型:推荐 方案二 (EasyPoi),简单快速,效果也不错。
- 如果你是企业级应用,对预览效果和性能有高要求:推荐 方案一 (POI + 自定义),虽然前期投入大,但可控性最强,可以做出非常完美的预览效果。
- 如果你的 Excel 文件都较小,且是用户本地预览:推荐 方案三 (纯前端),用户体验最好,也最省心。
希望这个详细的指南能帮助你实现 Java 在线预览 Excel 的功能!
