Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions server/src/main/java/cn/keking/model/FileAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class FileAttribute {
private String filePassword;
private boolean usePasswordCache;
private String officePreviewType = ConfigConstants.getOfficePreviewType();
private boolean officePreviewTypeSpecified;
private String tifPreviewType;
private Boolean skipDownLoad = false;
private Boolean forceUpdatedCache = false;
Expand Down Expand Up @@ -49,6 +50,7 @@ public FileAttribute(FileType type, String suffix, String name, String url, Stri
this.name = name;
this.url = url;
this.officePreviewType = officePreviewType;
this.officePreviewTypeSpecified = true;
}

public boolean isCompressFile() {
Expand Down Expand Up @@ -81,6 +83,16 @@ public String getOfficePreviewType() {

public void setOfficePreviewType(String officePreviewType) {
this.officePreviewType = officePreviewType;
this.officePreviewTypeSpecified = true;
}

/**
* 判断 Office 预览类型是否由请求或调用方显式指定。
*
* @return {@code true} 表示显式指定,{@code false} 表示使用系统默认配置
*/
public boolean isOfficePreviewTypeSpecified() {
return officePreviewTypeSpecified;
}

public FileType getType() {
Expand Down
43 changes: 38 additions & 5 deletions server/src/main/java/cn/keking/service/FileHandlerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,12 @@ public FileAttribute getFileAttribute(String url, HttpServletRequest req) {
// 处理逻辑:抛出异常、记录日志、返回错误等
throw new IllegalArgumentException("文件名超过系统限制");
}
boolean isHtmlView = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv") || suffix.equalsIgnoreCase("xlsm") || suffix.equalsIgnoreCase("xlt") || suffix.equalsIgnoreCase("xltm") || suffix.equalsIgnoreCase("et") || suffix.equalsIgnoreCase("ett") || suffix.equalsIgnoreCase("xlam");
String officePreviewType = req == null ? null : req.getParameter("officePreviewType");
if (StringUtils.hasText(officePreviewType)) {
attribute.setOfficePreviewType(officePreviewType);
}
boolean isHtmlView = isHtmlPreview(suffix, attribute.getOfficePreviewType(),
attribute.isOfficePreviewTypeSpecified());
String cacheFilePrefixName = null;
try {
cacheFilePrefixName = originFileName.substring(0, originFileName.lastIndexOf(".")) + suffix + "."; //这里统一文件名处理 下面更具类型 各自添加后缀
Expand All @@ -293,12 +298,8 @@ public FileAttribute getFileAttribute(String url, HttpServletRequest req) {
attribute.setSuffix(suffix);
attribute.setUrl(url);
if (req != null) {
String officePreviewType = req.getParameter("officePreviewType");
String forceUpdatedCache = req.getParameter("forceUpdatedCache");
String usePasswordCache = req.getParameter("usePasswordCache");
if (StringUtils.hasText(officePreviewType)) {
attribute.setOfficePreviewType(officePreviewType);
}
if (StringUtils.hasText(compressFileKey)) {
attribute.setCompressFile(isCompressFile);
attribute.setCompressFileKey(compressFileKey);
Expand Down Expand Up @@ -327,6 +328,38 @@ public FileAttribute getFileAttribute(String url, HttpServletRequest req) {
return attribute;
}

/**
* 判断电子表格是否需要生成 HTML 预览缓存。
* 未显式指定预览类型时保留原有行为;显式指定时仅 {@code html} 模式生成 HTML。
*
* @param suffix 文件后缀
* @param officePreviewType Office 预览类型
* @param previewTypeSpecified 是否由请求或调用方显式指定预览类型
* @return 是否生成 HTML 预览缓存
*/
static boolean isHtmlPreview(String suffix, String officePreviewType, boolean previewTypeSpecified) {
return isSpreadsheet(suffix)
&& (!previewTypeSpecified || "html".equalsIgnoreCase(officePreviewType));
}

/**
* 判断文件后缀是否属于支持 HTML 预览的电子表格类型。
*
* @param suffix 文件后缀
* @return 是否为电子表格类型
*/
private static boolean isSpreadsheet(String suffix) {
return suffix.equalsIgnoreCase("xls")
|| suffix.equalsIgnoreCase("xlsx")
|| suffix.equalsIgnoreCase("csv")
|| suffix.equalsIgnoreCase("xlsm")
|| suffix.equalsIgnoreCase("xlt")
|| suffix.equalsIgnoreCase("xltm")
|| suffix.equalsIgnoreCase("et")
|| suffix.equalsIgnoreCase("ett")
|| suffix.equalsIgnoreCase("xlam");
}

/**
* 获取缓存的文件名
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,14 @@ public String filePreviewHandle(String url, Model model, FileAttribute fileAttri
return convertStatusResult;
}

if (!officePreviewType.equalsIgnoreCase("html")) {
if (ConfigConstants.getOfficeTypeWeb().equalsIgnoreCase("web")) {
if (suffix.equalsIgnoreCase("xlsx")) {
model.addAttribute("pdfUrl", KkFileUtils.htmlEscape(url)); //特殊符号处理
return XLSX_FILE_PREVIEW_PAGE;
}
if (suffix.equalsIgnoreCase("csv")) {
model.addAttribute("csvUrl", KkFileUtils.htmlEscape(url));
return CSV_FILE_PREVIEW_PAGE;
}
if (shouldUseWebPreview(fileAttribute)) {
if (suffix.equalsIgnoreCase("xlsx")) {
model.addAttribute("pdfUrl", KkFileUtils.htmlEscape(url)); //特殊符号处理
return XLSX_FILE_PREVIEW_PAGE;
}
if (suffix.equalsIgnoreCase("csv")) {
model.addAttribute("csvUrl", KkFileUtils.htmlEscape(url));
return CSV_FILE_PREVIEW_PAGE;
}
}

Expand Down Expand Up @@ -136,6 +134,29 @@ public String filePreviewHandle(String url, Model model, FileAttribute fileAttri
isHtmlView, userToken, filePassword);
}

/**
* 判断 xlsx 或 csv 文件是否应直接使用前端 Web 预览。
* 未显式指定预览类型时保留系统原有 Web 预览行为;显式指定时仅文件类型同名模式
* ({@code xlsx} 或 {@code csv})使用 Web 预览,避免 {@code pdf} 请求被错误路由。
*
* @param fileAttribute 文件属性
* @return 是否使用 Web 预览
*/
static boolean shouldUseWebPreview(FileAttribute fileAttribute) {
if (!ConfigConstants.getOfficeTypeWeb().equalsIgnoreCase("web")) {
return false;
}
String suffix = fileAttribute.getSuffix();
boolean webPreviewFile = suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv");
if (!webPreviewFile || "html".equalsIgnoreCase(fileAttribute.getOfficePreviewType())) {
return false;
}
if (!fileAttribute.isOfficePreviewTypeSpecified()) {
return true;
}
return suffix.equalsIgnoreCase(fileAttribute.getOfficePreviewType());
}

/**
* 启动异步Office转换
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cn.keking.service;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class FileHandlerServiceTests {

@Test
void pdfPreviewDoesNotCreateHtmlForXlsx() {
assertThat(FileHandlerService.isHtmlPreview("xlsx", "pdf", true)).isFalse();
}

@Test
void htmlPreviewCreatesHtmlForXlsx() {
assertThat(FileHandlerService.isHtmlPreview("xlsx", "html", true)).isTrue();
}

@Test
void configuredPreviewTypeKeepsLegacySpreadsheetCacheTarget() {
assertThat(FileHandlerService.isHtmlPreview("xlsx", "pdf", false)).isTrue();
}

@Test
void htmlPreviewDoesNotChangeNonSpreadsheetOutput() {
assertThat(FileHandlerService.isHtmlPreview("docx", "html", true)).isFalse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cn.keking.service.impl;

import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class OfficeFilePreviewImplTests {

@BeforeEach
void setUp() {
ConfigConstants.setOfficeTypeWebValue("web");
}

@Test
void usesWebPreviewWhenPreviewTypeWasNotExplicitlySpecified() {
FileAttribute attribute = new FileAttribute(FileType.OFFICE, "xlsx", "report.xlsx", "http://localhost/report.xlsx");

assertThat(OfficeFilePreviewImpl.shouldUseWebPreview(attribute)).isTrue();
}

@Test
void explicitPdfDoesNotUseWebPreview() {
FileAttribute attribute = new FileAttribute(FileType.OFFICE, "xlsx", "report.xlsx", "http://localhost/report.xlsx", "pdf");

assertThat(OfficeFilePreviewImpl.shouldUseWebPreview(attribute)).isFalse();
}

@Test
void explicitXlsxUsesWebPreview() {
FileAttribute attribute = new FileAttribute(FileType.OFFICE, "xlsx", "report.xlsx", "http://localhost/report.xlsx", "xlsx");

assertThat(OfficeFilePreviewImpl.shouldUseWebPreview(attribute)).isTrue();
}

@Test
void explicitHtmlDoesNotUseWebPreview() {
FileAttribute attribute = new FileAttribute(FileType.OFFICE, "xlsx", "report.xlsx", "http://localhost/report.xlsx", "html");

assertThat(OfficeFilePreviewImpl.shouldUseWebPreview(attribute)).isFalse();
}
}
Loading