【SpringBoot高级篇】springboot实现上传doc&docx文件格式转html在线预览v2.0

  • pom
  • 上传路径工具类
  • SpringMvc虚拟路径映射
  • doc转html工具类
  • domain
  • service
  • controller
  • 前端html
  • 效果

由于上一遍文章
springboot实现上传doc&docx文件格式转pdf在线预览使用documents4j依赖只能在windows服务器(远程API)或者安装了offices实现效果。部署到linux服务器中就会转换失败。这篇文章介绍如何解决这个问题。我们可以把doc & docx文件格式转成html文件,然后以流的方式输出到浏览器就可以实现在线预览doc和docx文件的效果。话不多说,上才艺

pom

doc&docx转html的依赖

<!-- 文件预览 -->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.15</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>3.15</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.15</version>
</dependency>
<dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>xdocreport</artifactId><version>1.0.6</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>3.15</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.3</version>
</dependency>

上传路径工具类

根据不同的系统环境区分不同的上传目录,Windows环境为\,而Linux环境为/,这里主要根据程序当前路径创建了upload/document目录存放文档和upload/images目录存放图片

  • 使用System.getProperty(“os.name”);获取当前系统名
  • 使用System.getProperty(“user.dir”);获得程序当前路径
@Slf4j
public class UploadPathUtil {public static ArrayList<String> getSystemRoot() {/*** 存放doc,docx,pdf 文件上传路径* 存放images 文件上传路径*/ArrayList<String> list = new ArrayList<>(2);String osName = System.getProperty("os.name");// windows目录String windowsUpload = System.getProperty("user.dir")+"\\upload\\";// linux目录String linuxUpload = System.getProperty("user.dir")+"/upload/";log.info("当前系统为: "+osName);if (osName.toLowerCase().startsWith("linux")) {list.add(linuxUpload+"document/");list.add(linuxUpload+"images/");return list;} else if (osName.toLowerCase().startsWith("windows")) {list.add(windowsUpload+"document\\");list.add(windowsUpload+"images\\");return list;} else {throw new RuntimeException("错误目录");}}public static void main(String[] args) {ArrayList<String> systemRoot = UploadPathUtil.getSystemRoot();System.out.println(systemRoot);}
}

SpringMvc虚拟路径映射

application.yml中添加静态资源路径

在spring mvc配置类中使用@Value获取配置文件的值,并把静态资源路径和虚拟路径映射关联。

前端访问/api/static/document/****表示任意目录文件。虚拟映射到程序当前路径的upload目录的document目录下。

前端访问/api/static/images/****表示任意目录文件。虚拟映射到程序当前路径的upload目录的images目录下。

@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {// 文档上传路径@Value("${file.staticAccessDocumentPath}")private String staticAccessDocumentPath;// 图片上传路径@Value("${file.staticAccessImagesPath}")private String staticAccessImagesPath;@Overridepublic void addViewControllers(ViewControllerRegistry registry) {// 登录请求访问登录页面registry.addViewController("/toLogin").setViewName("login.html");}/*** 虚拟路径映射* @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {ArrayList<String> systemRoot = UploadPathUtil.getSystemRoot();log.info("systemRoot: "+systemRoot);// 在yml配置文件中读取路径registry.addResourceHandler(staticAccessDocumentPath).addResourceLocations("file:"+systemRoot.get(0));registry.addResourceHandler(staticAccessImagesPath).addResourceLocations("file:"+systemRoot.get(1));}
}

doc转html工具类

public class Doc2Html {// 上传路径public static final ArrayList<String> uploadPath = UploadPathUtil.getSystemRoot();/*** doc转换为html* @param fileName docx文件路径(如果你的是存到文件服务器的,直接用路径,如果是直接将文件流存到数据库的,转为InputStream )* @param outPutFile  html输出文件路径* @throws TransformerException* @throws IOException* @throws ParserConfigurationException*/public static void doc2Html(String fileName, String outPutFile)throws TransformerException, IOException, ParserConfigurationException {long startTime = System.currentTimeMillis();// HWPFDocument wordDocument = new HWPFDocument(fileName);HWPFDocument wordDocument = new HWPFDocument(new FileInputStream(fileName));WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());wordToHtmlConverter.setPicturesManager(new PicturesManager() {public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches,float heightInches) {// 设置虚拟访问路径return "/api/static/images/" + suggestedName;}});wordToHtmlConverter.processDocument(wordDocument);// 保存图片List<Picture> pics = wordDocument.getPicturesTable().getAllPictures();if (pics != null) {for (int i = 0; i < pics.size(); i++) {Picture pic = (Picture) pics.get(i);String suggestFullFileName = pic.suggestFullFileName();System.out.println(suggestFullFileName);try {File windowsImageUpload = new File(uploadPath.get(1));if (!windowsImageUpload.exists()){windowsImageUpload.mkdirs();}pic.writeImageContent(new FileOutputStream(windowsImageUpload +"\\"+ pic.suggestFullFileName()));} catch (FileNotFoundException e) {e.printStackTrace();}}}Document htmlDocument = wordToHtmlConverter.getDocument();ByteArrayOutputStream out = new ByteArrayOutputStream();DOMSource domSource = new DOMSource(htmlDocument);StreamResult streamResult = new StreamResult(out);TransformerFactory tf = TransformerFactory.newInstance();Transformer serializer = tf.newTransformer();serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");serializer.setOutputProperty(OutputKeys.INDENT, "yes");serializer.setOutputProperty(OutputKeys.METHOD, "html");serializer.transform(domSource, streamResult);out.close();writeFile(new String(out.toByteArray()), outPutFile);System.out.println("Generate " + outPutFile + " with " + (System.currentTimeMillis() - startTime) + " ms.");}/*** 写文件** @param content* @param path*/public static void writeFile(String content, String path) {FileOutputStream fos = null;BufferedWriter bw = null;try {File file = new File(path);fos = new FileOutputStream(file);bw = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"));bw.write(content);} catch (FileNotFoundException fnfe) {fnfe.printStackTrace();} catch (IOException ioe) {ioe.printStackTrace();} finally {try {if (bw != null)bw.close();if (fos != null)fos.close();} catch (IOException ie) {}}}/*** docx格式word转换为html** @param fileName*            docx文件路径(如果你的是存到文件服务器的,直接用路径,如果是直接将文件流存到数据库的,转为InputStream )* @param outPutFile*            html输出文件路径* @throws TransformerException* @throws IOException* @throws ParserConfigurationException*/public static void docx2Html(String fileName, String outPutFile)throws TransformerException, IOException, ParserConfigurationException {String fileOutName = outPutFile;long startTime = System.currentTimeMillis();XWPFDocument document = new XWPFDocument(new FileInputStream(fileName));//XWPFDocument document = new XWPFDocument(fileName);XHTMLOptions options = XHTMLOptions.create().indent(4);// 导出图片File imageFolder = new File(uploadPath.get(1));options.setExtractor(new FileImageExtractor(imageFolder));// URI resolver//options.URIResolver(new FileURIResolver(imageFolder));// 设置虚拟访问路径 docx导出图片会另外创建/word/media目录不影响虚拟访问options.URIResolver(new BasicURIResolver("/api/static/images/"));File outFile = new File(fileOutName);outFile.getParentFile().mkdirs();OutputStream out = new FileOutputStream(outFile);XHTMLConverter.getInstance().convert(document, out, options);System.out.println("Generate " + fileOutName + " with " + (System.currentTimeMillis() - startTime) + " ms.");}public static void main(String[] args) throws Exception {Doc2Html.docx2Html("F:\\2017-2020级学生2021-2022学年缴费通知.docx","F:\\cs.html");}}

domain

@Data
@TableName("tb_interface_doc")
public class InterfaceDoc extends SuperEntity{@TableField("url_address")private String urlAddress;@TableField("doc_name")private String docName;@TableField("suffix")private String suffix;@TableField("project_id")private Integer projectId;
}

service

我这里是直接把构建生成的randomNumber + extensionrandomNumber.html保存到了数据库中,然后在前端以超链接打开一个窗口的方式显示,以实现pdf和doc&docx在线阅读的效果。当然还可以以流的方式输出到浏览器直接显示。根据自己需求选择

/*** 上传接口文档* @param multipartFile* @param req* @param id* @return*/@Overridepublic Boolean uploadInterfaceWord(MultipartFile multipartFile, HttpServletRequest req, Integer id) throws Exception {//使用UUID生成唯一标识文件名String randomNumber = UUID.randomUUID().toString().replace("-", "");//获取文件的原始名String oldFilename = multipartFile.getOriginalFilename();//获取文件后缀 .pdf/.docx/.docString extension = oldFilename.substring(oldFilename.lastIndexOf("."));//生成新的文件名String newFileName = randomNumber + extension;// 文档上传路径File documentUpload = new File(systemRoot.get(0));if (!documentUpload.exists()) {//判断目录是否存在,不存在则直接创建documentUpload.mkdirs();}try {multipartFile.transferTo(new File(documentUpload, newFileName));} catch (IOException e) {e.printStackTrace();}// InputStream input = null;// OutputStream out = null;// 虚拟路径String invented_address = null;// 文件后缀,方便前端判断String fileSuffix = null;// 构建doc和docx新的文件名String docAndDocxNewFileName =  randomNumber + ".html";if (extension.equals(".pdf")){// 上传文件为.pdf后缀的虚拟访问路径invented_address  = req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort() + "/api/static/document/" + newFileName;// 添加后缀fileSuffix = extension.substring(extension.indexOf(".") + 1);} else// 在线预览//获取文件路径if (extension.equals(".docx")) {Doc2Html.docx2Html(systemRoot.get(0) + newFileName, systemRoot.get(0) + docAndDocxNewFileName);// 上传文件为.pdf后缀的虚拟访问路径invented_address  = req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort() + "/api/static/document/" + docAndDocxNewFileName;// 添加后缀fileSuffix = extension.substring(extension.indexOf(".") + 1);//                input = new FileInputStream(systemRoot.get(0) + docAndDocxNewFileName);
//                response.setContentType("text/html;charset=UTF-8");// 解决页面显示乱码
//                out = response.getOutputStream();} else if (extension.equals(".doc")) {Doc2Html.doc2Html(systemRoot.get(0) + newFileName, systemRoot.get(0) + docAndDocxNewFileName);// 上传文件为.pdf后缀的虚拟访问路径invented_address  = req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort() + "/api/static/document/" + docAndDocxNewFileName;// 添加后缀fileSuffix = extension.substring(extension.indexOf(".") + 1);//                input = new FileInputStream(systemRoot.get(0) + docAndDocxNewFileName);
//                response.setContentType("text/html;charset=UTF-8");// 解决页面显示乱码
//                out = response.getOutputStream();}InterfaceDoc interfaceDoc = new InterfaceDoc();interfaceDoc.setProjectId(id);interfaceDoc.setUrlAddress(invented_address);interfaceDoc.setSuffix(fileSuffix);interfaceDoc.setDocName(oldFilename);interfaceDocMapper.insert(interfaceDoc);return true;// 以流的方式输出到浏览器
//        if (extension.equals(".docx") || extension.equals(".doc")) {//            FileInputStream fis = new FileInputStream(systemRoot.get(0) + docAndDocxNewFileName);
//            byte[] b = new byte[fis.available()];
//            if (out != null) {//                if (input != null) {//                    input.read(b);
//                    out.write(b);
//                } else {//                    System.out.println("InputStream为空。。。");
//                }
//            } else {//                System.out.println("OutputStream为空。。。");
//            }
//
//            out.flush();
//            input.close();
//            out.close();
//        }}

controller

@PostMapping("/project/upload/{id}")
public ResultVO<?> fileupload(MultipartFile file, HttpServletRequest req,@PathVariable Integer id) throws FileNotFoundException {Boolean bool = projectService.uploadInterfaceWord(file, req, id);return bool ?  ResultVO.ok("上传成功") : ResultVO.fail("上传失败");
}

前端html

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>查看接口文档</title><link rel="stylesheet" th:href="@{/component/pear/css/pear.css}" />
</head>
<body class="pear-container"><div><div class="layui-row layui-col-space10"><div class="layui-col-xs6 layui-col-md3" th:each="item:${InterfaceDocList}"><div class="layui-card top-panel"><div class="layui-card-header">[[${item.docName}]]</div><div class="layui-card-body"><div class="layui-row layui-col-space5"><div class="layui-col-xs8 layui-col-md8 top-panel-number" style="color: #28333E;"><a th:href="@{${item.urlAddress}}" target="_blank"><img th:src="@{'/admin/images/'+${item.suffix}+'.png'}" alt="查看详情"  style="width: 100px;height: 100px;border-radius: 5px;" /></a></div></div></div></div></div></div></div>
</body>
<script th:src="@{/component/layui/layui.js}"></script>
<script th:src="@{/component/pear/pear.js}"></script>
</html>

效果

1、上传接口文件

2、上传相关接口文档

3、查看所有接口文档


4、查看接口详情

【SpringBoot高级篇】springboot实现上传docdocx文件格式转html在线预览v2.0相关推荐

  1. java 调用 swf 文件上传_java SpringMvc 实现文件在线预览(openoffice+swftools+flexpaper)

    项目需求:服务器接受的文件当下只能下载之后才能浏览内容,现需要后台能在线浏览到文件内容,避免繁琐无用文件下载操作. 通过几天网上资料搜索,目前免费的在线预览开发技术使用最多还是(openoffice+ ...

  2. 微信小程序上传图片及文件(上传、下载、删除及预览)

    微信小程序上传附件 上传文件及图片 下载,预览.删除 自定义封装组件 哪儿用哪儿调用即可 wxml代码 <!-- <view>上传文件(我是子组件)</view> --& ...

  3. SpringBoot实现本地上传Word文档并在线预览

    所需依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</art ...

  4. vue二维码解码器(增加上传二维码之后弹窗预览)

    对之前的二维码解码器做的功能扩展, 增加上传成功时弹框显示二维码图片预览,弹框使用vant ui 实现 vanr ui 文档地址 https://youzan.github.io/vant/#/zh- ...

  5. fastdfs+nginx+keepalived+openoffice+lua 实现文件上传、下载、水印、预览(word、excel、ppt、txt),feign文件上传

    前言 最近刚刚实现的文件服务中心,记录一下,为没做过的人提供一下思路,由于本人技术有限,不足之处欢迎批评指正,共同学习,共同进步. 目录 Fastdfs集群搭建 搭建keepalived 实现ngxi ...

  6. 微信小程序上传文件及图片(可以预览)

    最近在写小程序项目,碰到了一个需求,需要用户可以上传各种类型的文件和图片,展示在页面上,并且点击还可以进行预览,就找了找微信小程序官网,写了一个例子,分享一下 直接看代码: wxml: <vie ...

  7. php仿微信多图片预览上传,PHP仿微信多图片预览上传功能

    [html] view plain copy 在CODE上查看代码片派生到我的代码片 plupload上传 [javascript] view plain copy 在CODE上查看代码片派生到我的代 ...

  8. bootstrap上传插件(fileinput.js)预览显示删除图标问题

    预览时显示和不显示上传和删除图标,主要是通过 uploadUrl:"/..." 来控制,如果注释掉就会不显示 $(".fileupload").fileinpu ...

  9. 本地如何预览php文件上传,如何实现js上传图片本地预览同时支持预览截图的功能...

    在项目中经常会用到js上传图片本地预览的效果,同时需要在预览图上直接预览截图的范围. 下面是我写的简单的demo,是用js结合cropper.js模拟实现此项前端的功能,后台则不考虑. 准备:引入文件 ...

最新文章

  1. JavaScript权威指南--window对象
  2. leetcode 646. Maximum Length of Pair Chain | 646. 最长数对链(暴力递归->傻缓存->dp)
  3. 资源 | Deeplearning.ai课程与笔记汇总
  4. redis集群3种模式
  5. python可迭代对象,迭代器,生成器
  6. DatabaseMetaData information is not known for server DB2/xxx by this version of JDBC driver
  7. 墙裂推荐!2020Android阿里腾讯百度字节美团网易爱奇艺校招面试汇总
  8. vue获取接口id_05vue2.0-vue中_接口的调用
  9. 通过 Bitmap Font Generator 生成 fnt 与 png 文件供 cocos2d-x 中 LabelBMFont 使用达到以图片表现数字
  10. 【软考】专栏导读(软考全面介绍、资格报考建议)
  11. 【MMD动作+镜头】Bo Peep Bo Peep
  12. 立创开源 | 基于555定时器的电子琴设计
  13. In-band network telemetry
  14. 云时代,最好用的MySQL客户端工具推荐
  15. excel数据个数统计问题
  16. 基于(ztmap)BIM的数字孪生建造智慧机房管理后台展示系统
  17. Linux系统安装Anaconda3保姆级教程
  18. 使用Foxmail定制自己的邮件模板
  19. Python数据可视化——图型参数介绍
  20. 基于腾讯x5封源库,提高60%开发效率

热门文章

  1. java分隔符读取文件_java – 在读取文件时使用分隔符
  2. 零基础怎么学习视频剪辑?这篇初剪辑学者指南你一定不要错过
  3. 数字 一阶低通滤波器 详细分析 冰三点水
  4. VM安装CentOS虚拟机详细教程
  5. InnoDB:page_cleaner:1000ms intended loop 解决
  6. unity3d场景导入webgl/three.js
  7. 如何才能成为一个程序员
  8. C++中的引用变量详解
  9. 【机试】判断两个数互质
  10. 苹果ipa安装包分发下载教程