目录
项目需求
前端需要上传pptx文件,后端保存为图片,并将图片地址保存数据库,最后大屏展示时显示之前上传的pptx的图片。需求看上去是简单的,简单聊一下,不管是使用vue的elementui还是传统的layui都有很好的实现组件,这里我们重点不在前端,所以不去细说,感兴趣的同学可以了解一下。
后端接口实现
1、引入poi依赖
这里我使用的是最新的依赖,大家想要稳定一点可以用4.1.2的版本
java
<!-- excel解析工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
2、代码编写
一般工作中,后端都是提供接口给前端访问的,项目会有一定的分层
1、controller
我们主要用来接受参数,然后把参数带到service层去处理业务逻辑就行
这里我们需要接受的前端参数有2个:
MultipartFile:pptx文件对象
代码示例:
java@ResponseBody @RequestMapping("/admin/pheno/material/caseContentPhotoUpload") public ResultJson caseContentPhotoUpload(MultipartFile file, HttpServletRequest request) { return ResultJson.build(pheContentService.caseContentPhotoUpload(file,request)); }
2、service层
实际的业务代码编写,代码逻辑是比较简单的,先获取文件的输入流,将文件输入流转化为xmlslideshow()对象,这个就是poi的处理pptx文件的工具包了,在里面循环操作每一张pptx。pptx文件也就是xml文件,所以是用这个处理的,然后就是保存图片了,思路就是建一张画布,将文件画上去,最后保存到对应路径,本地数据库啥的。非常简单。IMAGE_SCALE 是一个常量,我给的是8,最后记得关闭不用的对象,回收一下内存。
javapublic ResultService caseContentPhotoUpload(MultipartFile file, HttpServletRequest request) { String serverPath=request.getSession().getServletContext().getRealPath("/"); ArrayList<Object> outPathUrlList = new ArrayList<>(); InputStream is = null; XMLSlideShow ppt = null; try { is = file.getInputStream(); ppt =new XMLSlideShow(is); Dimension pgSize = ppt.getPageSize(); for (XSLFSlide slide : ppt.getSlides()) { for(XSLFShape shape : slide.getShapes()){ if(shape instanceof XSLFTextShape) { XSLFTextShape tsh = (XSLFTextShape)shape; for(XSLFTextParagraph p : tsh){ for(XSLFTextRun r : p){ r.setFontFamily("宋体"); } } } } String url = toPNG(pgSize.width, pgSize.height, slide,serverPath,hrStaffSession); outPathUrlList.add(url); } } catch (IOException e) { log.debug("ppt转换图片失败,{}"+ e.getMessage()); throw new RuntimeException("ppt转换图片失败" + e.getMessage()); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (ppt != null) { ppt.close(); } } catch (IOException e) { e.printStackTrace(); } } return ResultService.buildSuccess(outPathUrlList); }
javaprotected String toPNG(int pgWidth, int pgHeight, XSLFSlide slide, String serverPath, HrStaffSession hrStaffSession) throws IOException { int imageWidth = (int) Math.floor(IMAGE_SCALE * pgWidth); int imageHeight = (int) Math.floor(IMAGE_SCALE * pgHeight); ResultService resultService =null; BufferedImage img = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB); Graphics2D graphics = img.createGraphics(); graphics.setPaint(Color.white); graphics.fill(new Rectangle2D.Float(0, 0, pgWidth, pgHeight)); graphics.scale(IMAGE_SCALE, IMAGE_SCALE); slide.draw(graphics); ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { bos = new ByteArrayOutputStream(); ImageIO.write(img, "png", bos); InputStream input = new ByteArrayInputStream(bos.toByteArray()); MultipartFile multipartFile = getMultipartFile(input,"ppt图片.png"); input.close(); resultService = fileService.fileUpload(multipartFile, serverPath, hrStaffSession); } finally { bos.close(); } SystemFileVO systemFileVO=(SystemFileVO)resultService.getObject(); return systemFileVO.getThumbPath(); }
测试出现的bug
不知道是poi对于pptx做的兼容不好还是啥原因,总之有很多的问题
1、文字问题,pptx使用的都是微软雅黑,但是转为图片时,文字会有溢出和下坠的变化,
所以我从4.1.2的包切到了新版本的5.2.0,解决了文字的溢出问题,然后我将微软雅黑统一设置成宋体,在window上是解决了,但是在linux上展现效果又有一定的差异,总的来说是解决了。
2、段落的首行缩进混乱,设置了首行缩进,但是缩进去了一行的最后面
最后只能不要这个样式,去手动添加空格
3、一些图标无法读取,当图标是组合式也就是拼接的时候,会出现读取不了的情况,也只能在写pptx的时候规避一下
4、在不同操作系统上展现效果有细微区别,测试也比较麻烦
。。。
小结
感觉在技术的选取上应该再参考一下,是否poi是这个需求最好的处理对象,是不是还有更好的处理方式。