ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

文件是怎么变成预览页的:kkFileView 核心链路深度拆解

文件是怎么变成预览页的:kkFileView 核心链路深度拆解 文件是怎么变成预览页的kkFileView 核心链路深度拆解【免费下载链接】kkFileViewUniversal File Online Preview Project based on Spring-Boot项目地址: https://gitcode.com/GitHub_Trending/kk/kkFileViewkkFileView 是一个基于 Spring Boot 的通用文件在线预览项目输入一个文件 URL它会把它下载、转换、缓存最后吐出一张浏览器能直接渲染的预览页。这篇文章不罗列 API而是从一次真实的点击开始沿着代码把docx 链接如何变成 PDF 页面这条路走一遍再拆出分派、异步转换、缓存三处关键设计最后给出新增文件类型和切换缓存后端的具体做法。点一个链接的瞬间请求在代码里走了哪几步结论先说一次预览请求在onlinePreview接口里被拆成解码 → 建属性 → 取处理器 → 执行四步每步失败都有明确的出口页面。入口在 OnlinePreviewController 的onlinePreview方法。参数url是调用方做了 Base64 URL 双重编码的字符串解码逻辑长这样String fileUrl; try { fileUrl WebUtils.decodeUrl(url, encryption); } catch (Exception ex) { return otherFilePreview.notSupportedFile(model, errorMsg); } FileAttribute fileAttribute fileHandlerService.getFileAttribute(fileUrl, req); FilePreview filePreview previewFactory.get(fileAttribute); return filePreview.filePreviewHandle(fileUrl, model, fileAttribute);关键在最后三行getFileAttribute把 URL 变成携带类型、缓存名、输出路径的FileAttribute对象previewFactory.get按类型换处理器filePreviewHandle是真正的干活方法。解码失败不抛异常而是直接落到OtherFilePreviewImpl.notSupportedFile的错误页——整条链路对坏输入的态度是降级展示而不是中断。下图把四步展开成组件间的时间线先看全貌再进设计细节FileAttribute是这条链路里的公共货币。在 FileHandlerService.getFileAttribute 里它还负责解析 URL 上夹带的控制参数forceUpdatedCache强制刷缓存、filePassword加密文件密码、officePreviewTypePDF 还是图片模式以及kk-proxy-authorization请求头。后续处理器只读这个对象不再碰原始 URL这是后面分派设计成立的前提。三个设计决策分派、异步与缓存各自解决什么问题这一节挑三处如果不这么做就会很难受的地方每处按问题 → 设计 → 实现讲。后缀名查表 枚举映射把是什么文件压成一次 HashMap 查询要解决的问题项目支持二十多种格式如果入口处写一长串 if-else每加一种格式都要改判断逻辑。设计是把识别和处理分开识别只产出一个枚举值处理交给枚举背后绑定的 Spring Bean。FileType 枚举的每个值都带一个 Bean 名静态块把后缀批量塞进映射表OFFICE(officeFilePreviewImpl), PDF(pdfFilePreviewImpl), CAD(cadFilePreviewImpl), // ...共23个枚举值 private static final MapString, FileType FILE_TYPE_MAPPER new HashMap(); static { for (String office : OFFICE_TYPES) { FILE_TYPE_MAPPER.put(office, FileType.OFFICE); } }读取侧有两个细节值得注意。typeFromUrl会先截掉?之后的查询参数、再取最后一段文件名防止 URL 尾部的参数污染后缀判断查表用getOrDefault(fileType, OTHER)未命中不报错而是落到OTHER类型由otherFilePreviewImpl兜底。工厂本体只有几行FilePreviewFactory.get 直接按枚举携带的 Bean 名从容器里取实例public FilePreview get(FileAttribute fileAttribute) { return context.getBean(fileAttribute.getType().getInstanceName(), FilePreview.class); }像前台接待一样它不关心客人是谁只按工牌号把人引到对应工位。所有处理器都实现同一个 FilePreview 接口方法签名统一为filePreviewHandle(String url, Model model, FileAttribute fileAttribute)返回值是 FreeMarker 视图名如pdf、compress、picture控制器因此可以完全不管具体类型。等待页 状态机把耗时的格式转换移出请求线程要解决的问题Office 转 PDF 依赖 LibreOffice 进程秒级起步。若在请求线程里同步做用户盯着空白页超时配置也扛不住大文件。设计是把转换拆成立即返回等待页 后台推进状态两段。以 OfficeFilePreviewImpl 的图片模式为例未命中缓存时它调用startAsyncOfficeConversionCompletableFutureListString conversionFuture CompletableFuture.supplyAsync(() - { FileConvertStatusManager.startConvert(cacheName); officeToPdfService.openOfficeToPDF(filePath, outFilePath, fileAttribute); // 需要图片模式时再走 pdf2jpg ... });请求线程这边则立即返回WAITING_FILE_PREVIEW_PAGEwaiting视图页面上带time刷新间隔。再次访问同一文件时checkAndHandleConvertStatus读 FileConvertStatusManager 的状态CONVERTING继续给等待页TIMEOUT/FAILED给失败页除非 URL 上带了forceUpdatedCachetrue清状态重转。状态机让转换进行中变成可查询、可重试的事实而不是一个不可见的后台过程。另有一条更粗粒度的通道/addTask接口把 URL 丢进队列由 FileConvertQueueTask 在PostConstruct阶段拉起消费线程专门做离线预转换while (true) { String url cacheService.takeQueueTask(); if (url ! null) { FileAttribute fileAttribute fileHandlerService.getFileAttribute(url, null); if (isNeedConvert(fileAttribute.getType())) { previewFactory.get(fileAttribute) .filePreviewHandle(url, new ExtendedModelMap(), fileAttribute); } } }注意isNeedConvert只放行COMPRESS、OFFICE、CAD三种类型——文本、图片这类无需转换的格式入队也会被跳过。循环体套在 try-catch 里异常后TimeUnit.SECONDS.sleep(10)再继续保证单条坏任务不会杀死消费线程。一个接口三种后端缓存层与存储介质解耦要解决的问题单机内存缓存在重启后丢失多实例部署又需要共享持久化则想要本地磁盘方案。三种诉求对应的存储完全不同。设计是 CacheService 接口定义操作契约service/cache/impl/下提供三套实现按配置装配实现类后端介质适用部署形态CacheServiceJDKImpl进程内 LRU 结构单机、轻量部署CacheServiceRedisImplRedis多实例共享缓存CacheServiceRocksDBImpl本地 RocksDB需要重启不丢转换记录接口里值得记住的常量是四组缓存键和队列名常量值存什么FILE_PREVIEW_PDF_KEYconverted-preview-pdf-file缓存名 → 转换后文件相对路径FILE_PREVIEW_IMGS_KEYconverted-preview-imgs-file压缩包内图片 URL 列表FILE_PREVIEW_PDF_IMGS_KEYconverted-preview-pdfimgs-filePDF 转图后的张数FILE_PREVIEW_MEDIA_CONVERT_KEYconverted-preview-media-file媒体转 mp4 的路径TASK_QUEUE_NAMEconvert-task转换任务队列容量默认值统一是DEFAULT_PDF_CAPACITY 500000这一档。缓存键本身由FileHandlerService.getCacheFileName按类型生成Office 在文件名后拼pdf或html表格走 html 视图CAD 拼配置的cadPreviewType压缩包内文件统一加_decompression前缀避免同名冲突。动手扩展加一种格式、换一套缓存、看懂兜底行为新增文件类型的三步操作以接入假想的demo格式为例改动集中在三处互不牵扯在 FileType 加枚举值DEMO(demoFilePreviewImpl)并在静态块里把demo放进FILE_TYPE_MAPPER在 service/impl/ 下新建DemoFilePreviewImpl implements FilePreview加Service注解实现filePreviewHandle返回一个视图名在resources的模板目录补同名 FreeMarker 页面接口里的视图名常量可参照 FilePreview 中已有的*_FILE_PREVIEW_PAGE定义。因为分派完全靠枚举 → Bean 名 → 容器查表控制器、工厂、队列消费线程一行都不用改。需要缓存转换产物时再决定挂到CacheService哪一组键上。切换缓存后端同理三套实现都实现同一个接口切换只动配置层的装配FileHandlerService与处理器代码无感。常见失败场景与系统的兜底行为失败场景代码位置兜底行为双重解码失败OnlinePreviewController渲染 notSupportedFile 错误页源文件下载失败DownloadUtils.downLoad 返回 isFailure走 otherFilePreview.notSupportedFile 带具体原因加密 Office 未给密码OfficeFilePreviewImpl返回 html 视图页面提示输入 filePassword转换超时或失败FileConvertStatusManager再次访问返回无法继续转换forceUpdatedCache 可重置后缀不在映射表FileType.to 的 getOrDefault归为 OTHER由 otherFilePreviewImpl 处理队列任务抛异常FileConvertQueueTasksleep 10 秒后继续消费下一条规律是统一的任何一步失败都不让请求线程崩掉而是收敛到一个错误视图 一句原因重试路径通过forceUpdatedCache参数显式提供。要点清单入口先做 Base64URL 双重解码后缀查 FILE_TYPE_MAPPER 定类型未命中后缀一律落 OTHER 兜底工厂按 Bean 名取处理器实例缓存键由 getCacheFileName 按类型拼队列只消费 COMPRESS/OFFICE/CAD缓存接口对应 JDK/Redis/RocksDB失败统一渲染 notSupportedFile 页【免费下载链接】kkFileViewUniversal File Online Preview Project based on Spring-Boot项目地址: https://gitcode.com/GitHub_Trending/kk/kkFileView创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表