Java實(shí)現(xiàn)Word、Excel、PDF文件在線預(yù)覽幾種實(shí)現(xiàn)方式
在線預(yù)覽文檔通常有幾種方案:轉(zhuǎn)換為HTML、轉(zhuǎn)換為PDF再預(yù)覽、使用專(zhuān)門(mén)的預(yù)覽服務(wù)等。下面我將介紹幾種實(shí)現(xiàn)方式。
方案一:使用開(kāi)源庫(kù)轉(zhuǎn)換為HTML預(yù)覽
1. 添加Maven依賴
<dependencies>
<!-- Word處理 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<!-- Excel處理 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.2.3</version>
</dependency>
<!-- PDF處理 -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.27</version>
</dependency>
<!-- 文件類(lèi)型檢測(cè) -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.4.1</version>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>2. 文件預(yù)覽服務(wù)實(shí)現(xiàn)
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
@Service
public class FilePreviewService {
/**
* 預(yù)覽Word文檔(轉(zhuǎn)換為HTML)
*/
public String previewWord(File file) throws Exception {
String fileName = file.getName().toLowerCase();
if (fileName.endsWith(".doc")) {
return convertDocToHtml(file);
} else if (fileName.endsWith(".docx")) {
return convertDocxToHtml(file);
} else {
throw new IllegalArgumentException("不支持的Word格式");
}
}
/**
* 預(yù)覽Excel文檔(轉(zhuǎn)換為HTML表格)
*/
public String previewExcel(File file) throws Exception {
String fileName = file.getName().toLowerCase();
Workbook workbook;
try (FileInputStream fis = new FileInputStream(file)) {
if (fileName.endsWith(".xls")) {
workbook = new HSSFWorkbook(fis);
} else if (fileName.endsWith(".xlsx")) {
workbook = new XSSFWorkbook(fis);
} else {
throw new IllegalArgumentException("不支持的Excel格式");
}
return convertExcelToHtml(workbook);
}
}
/**
* 預(yù)覽PDF文檔(提取文本內(nèi)容)
*/
public String previewPdf(File file) throws Exception {
try (PDDocument document = PDDocument.load(file)) {
PDFTextStripper stripper = new PDFTextStripper();
String text = stripper.getText(document);
// 簡(jiǎn)單的HTML包裝
return "<html><body><pre>" + escapeHtml(text) + "</pre></body></html>";
}
}
/**
* 通用文件預(yù)覽方法
*/
public String previewFile(File file) throws Exception {
String fileName = file.getName().toLowerCase();
if (fileName.endsWith(".doc") || fileName.endsWith(".docx")) {
return previewWord(file);
} else if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
return previewExcel(file);
} else if (fileName.endsWith(".pdf")) {
return previewPdf(file);
} else {
throw new IllegalArgumentException("不支持的文件格式");
}
}
// 私有方法:具體轉(zhuǎn)換實(shí)現(xiàn)
private String convertDocToHtml(File file) throws Exception {
try (HWPFDocument document = new HWPFDocument(new FileInputStream(file))) {
WordToHtmlConverter converter = new WordToHtmlConverter(
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
);
converter.processDocument(document);
Document htmlDocument = converter.getDocument();
return convertDocumentToString(htmlDocument);
}
}
private String convertDocxToHtml(File file) throws Exception {
try (XWPFDocument document = new XWPFDocument(new FileInputStream(file))) {
StringWriter writer = new StringWriter();
XHTMLConverter.getInstance().convert(document, writer, null);
return writer.toString();
}
}
private String convertExcelToHtml(Workbook workbook) {
StringBuilder html = new StringBuilder();
html.append("<html><body><table border='1'>");
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
Sheet sheet = workbook.getSheetAt(i);
html.append("<tr><th colspan='10'>").append(sheet.getSheetName()).append("</th></tr>");
for (Row row : sheet) {
html.append("<tr>");
for (Cell cell : row) {
html.append("<td>");
switch (cell.getCellType()) {
case STRING:
html.append(escapeHtml(cell.getStringCellValue()));
break;
case NUMERIC:
html.append(cell.getNumericCellValue());
break;
case BOOLEAN:
html.append(cell.getBooleanCellValue());
break;
default:
html.append(" ");
}
html.append("</td>");
}
html.append("</tr>");
}
}
html.append("</table></body></html>");
return html.toString();
}
private String convertDocumentToString(org.w3c.dom.Document doc) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "html");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
return writer.toString();
}
private String escapeHtml(String text) {
return text.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'");
}
}3. Spring Boot控制器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Controller
public class FilePreviewController {
@Autowired
private FilePreviewService filePreviewService;
private final Path rootLocation = Paths.get("upload-dir");
@GetMapping("/")
public String index() {
return "upload";
}
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, Model model) {
try {
// 創(chuàng)建上傳目錄
if (!Files.exists(rootLocation)) {
Files.createDirectories(rootLocation);
}
// 保存文件
Path destinationFile = rootLocation.resolve(
Paths.get(file.getOriginalFilename()))
.normalize().toAbsolutePath();
file.transferTo(destinationFile.toFile());
// 預(yù)覽文件
String htmlContent = filePreviewService.previewFile(destinationFile.toFile());
model.addAttribute("previewContent", htmlContent);
model.addAttribute("fileName", file.getOriginalFilename());
return "preview";
} catch (Exception e) {
model.addAttribute("error", "文件預(yù)覽失敗: " + e.getMessage());
return "upload";
}
}
@GetMapping("/preview/{filename:.+}")
@ResponseBody
public ResponseEntity<String> previewFile(@PathVariable String filename) {
try {
Path file = rootLocation.resolve(filename);
String htmlContent = filePreviewService.previewFile(file.toFile());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "text/html; charset=utf-8")
.body(htmlContent);
} catch (Exception e) {
return ResponseEntity.badRequest().body("預(yù)覽失敗: " + e.getMessage());
}
}
@GetMapping("/download/{filename:.+}")
@ResponseBody
public ResponseEntity<Resource> downloadFile(@PathVariable String filename) {
try {
Path file = rootLocation.resolve(filename);
Resource resource = new UrlResource(file.toUri());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
} catch (Exception e) {
return ResponseEntity.notFound().build();
}
}
}4. HTML模板
src/main/resources/templates/upload.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>文件上傳預(yù)覽</title>
</head>
<body>
<h2>文件上傳預(yù)覽</h2>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file" accept=".doc,.docx,.xls,.xlsx,.pdf">
<button type="submit">上傳并預(yù)覽</button>
</form>
<div th:if="${error}" style="color: red;">
<p th:text="${error}"></p>
</div>
</body>
</html>src/main/resources/templates/preview.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>文件預(yù)覽</title>
<style>
.preview-container {
border: 1px solid #ccc;
padding: 20px;
margin: 20px 0;
max-height: 600px;
overflow: auto;
}
.actions {
margin: 10px 0;
}
</style>
</head>
<body>
<h2>文件預(yù)覽: <span th:text="${fileName}"></span></h2>
<div class="actions">
<a th:href="@{'/download/' + ${fileName}}" rel="external nofollow" >下載原文件</a> |
<a href="/" rel="external nofollow" >返回上傳</a>
</div>
<div class="preview-container" th:utext="${previewContent}">
<!-- 預(yù)覽內(nèi)容將在這里顯示 -->
</div>
</body>
</html>方案二:使用第三方服務(wù)(推薦用于生產(chǎn)環(huán)境)
對(duì)于生產(chǎn)環(huán)境,建議使用專(zhuān)門(mén)的文檔預(yù)覽服務(wù):
使用Microsoft Office Online Server
使用Google Docs預(yù)覽服務(wù)
使用專(zhuān)業(yè)的文檔預(yù)覽SDK(如GroupDocs、Aspose等)
使用Google Docs預(yù)覽的示例:
public String previewWithGoogleDocs(String fileUrl) {
// 將文件上傳到可訪問(wèn)的URL,然后使用Google Docs預(yù)覽
return "https://docs.google.com/gview?url=" + URLEncoder.encode(fileUrl, "UTF-8") + "&embedded=true";
}方案三:使用專(zhuān)業(yè)的Java庫(kù)(Aspose)
// 需要購(gòu)買(mǎi)許可證
import com.aspose.words.Document;
import com.aspose.words.HtmlSaveOptions;
public String previewWithAspose(File file) throws Exception {
Document doc = new Document(file.getAbsolutePath());
HtmlSaveOptions options = new HtmlSaveOptions();
options.setExportImagesAsBase64(true);
StringWriter writer = new StringWriter();
doc.save(writer, options);
return writer.toString();
}啟動(dòng)類(lèi)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FilePreviewApplication {
public static void main(String[] args) {
SpringApplication.run(FilePreviewApplication.class, args);
}
}配置說(shuō)明
在application.properties中添加:
# 文件上傳大小限制 spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=10MB # thymeleaf配置 spring.thymeleaf.cache=false spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html
使用說(shuō)明
啟動(dòng)應(yīng)用后訪問(wèn) http://localhost:8080
上傳Word、Excel或PDF文件
系統(tǒng)會(huì)自動(dòng)轉(zhuǎn)換為HTML格式進(jìn)行預(yù)覽
注意事項(xiàng)
性能考慮:大文件轉(zhuǎn)換可能耗時(shí),建議添加進(jìn)度提示
內(nèi)存管理:處理大文件時(shí)注意內(nèi)存使用,建議使用流式處理
格式兼容性:復(fù)雜格式可能無(wú)法完美轉(zhuǎn)換
安全性:對(duì)上傳文件進(jìn)行病毒掃描和類(lèi)型驗(yàn)證
緩存策略:對(duì)已轉(zhuǎn)換的文件進(jìn)行緩存以提高性能
這種方案適合中小型項(xiàng)目的文檔預(yù)覽需求,對(duì)于企業(yè)級(jí)應(yīng)用,建議使用專(zhuān)業(yè)的文檔預(yù)覽服務(wù)。
總結(jié)
到此這篇關(guān)于Java實(shí)現(xiàn)Word、Excel、PDF文件在線預(yù)覽幾種實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)Java在線預(yù)覽Word、Excel、PDF內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot actuator應(yīng)用后臺(tái)監(jiān)控實(shí)現(xiàn)
這篇文章主要介紹了Springboot actuator應(yīng)用后臺(tái)監(jiān)控實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Spring之兩種任務(wù)調(diào)度Scheduled和Async詳解
這篇文章主要介紹了Spring之兩種任務(wù)調(diào)度Scheduled和Async,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Spring?Security中如何獲取AuthenticationManager對(duì)象
有時(shí)需要使用AuthenticationManager(以下簡(jiǎn)稱(chēng)Manager)對(duì)象,可是這個(gè)對(duì)象不是Bean,沒(méi)有直接保存在Spring的Bean庫(kù)中,那么如何獲取Spring Security中的這個(gè)對(duì)象呢,需要的朋友可以參考下2022-11-11
@JsonFormat處理LocalDateTime失效的問(wèn)題
這篇文章主要介紹了關(guān)于@JsonFormat處理LocalDateTime失效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
SpringBoot部署在tomcat容器中運(yùn)行的部署方法
這篇文章主要介紹了SpringBoot部署在tomcat容器中運(yùn)行的部署方法,需要的朋友可以參考下2018-10-10
MyBatis寫(xiě)入Json字段以及Json字段轉(zhuǎn)對(duì)象示例詳解
這篇文章主要給大家介紹了關(guān)于MyBatis寫(xiě)入Json字段以及Json字段轉(zhuǎn)對(duì)象的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
詳細(xì)總結(jié)各種排序算法(Java實(shí)現(xiàn))
下面小編就為大家?guī)?lái)一篇詳細(xì)總結(jié)各種排序算法(Java實(shí)現(xiàn))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09

