SpringBoot项目中使用poi-tl打成jar包后常见问题及解决

news2024/11/24 6:46:04

目录

前言

一、场景描述

1、打成jar包运行后模板找不到

2、文件只能下载一次

二、正确示范

1、Controller下载方法定义

2、文档生成

总结


前言

        在前面的博客中,介绍了如何在Java中根据模板动态写入数据到word模板中,原文地址:Java使用poi-tl1.9.1生成Word文档的几个小技巧。这里给出的案例是直接生成到本地目录中,在实际项目开发过程中,一般会采用web请求的方式,动态的将数据设置到Word中,同时将文件下载到本地。

        在基于SpringBoot的开发环境中,我们经常会将实际部署的包打包成jar包的形式进行部署。在以上的场景开发中,不知道您是否会遇到以下的问题。比如会遇到模板找不到报错,还有请求智能点击一次的问题产生。

        本文将针对以上两种情况,分析并解决在SpringBoot环境中,将Poi-tl应用打包成jar后的实际运行问题进行解决。如果在平常开发过程中也遇到这种问题,可以试试博文的方案,看是否可以解决您的问题。

一、场景描述

1、打成jar包运行后模板找不到

java.io.FileNotFoundException: class path resource [report/temp.docx] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/ROOT/xxx.jar!/BOOT-INF/lib/xxx-2.1.jar!/report/temp.docx 
    at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:217) 
    at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:154) 
   ...

        通常来说,如果遇到上述的这种异常错误信息,一般都是因为获取docx模板的代码不对导致的,知道了问题的关键就可以针对性进行解决。

解决方案

        在springboot项目中,对于打成jar包后的项目,如果想正常访问resource目录下的文件,建议采用以下的代码进行修复。

InputStream is = this.getClass().getClassLoader().getResourceAsStream("report/temp.docx");

        在word模板写入的时候,可以采用以下的代码:

template = XWPFTemplate.compile(is).render(map);

XWPFTemplate模板在写出的时候,可以支持直接对一个输入流进行内容写入。

2、文件只能下载一次

        在使用poi-tl生成word的时候,可能会遇到第一次请求下载文件是正常的,但是在第二次需要下载时浏览器则失去响应,就像假死一样。可能前端的小伙伴还会把锅刷到浏览器头上。这里需要注意的是,在进行IO读写的时候,千万要记得关流。

        如果你也遇到这种失去响应的情况,通常是因为忘记关流了。这里分享一段错误的代码示范:

private String createReport() throws Exception{
		String reportDir = RuoYiConfig.getProfile() + "/report";
		InputStream is = null;
		XWPFTemplate template = null;
		FileOutputStream out = null;
		try {
			is = this.getClass().getClassLoader().getResourceAsStream("report/temp.docx");
			Map<String, Object> map = new HashMap<String,Object>();
	        map.put("score", "28");
	        map.put("title", "测试任务");
	        map.put("type", "上半年综合测评");
	        map.put("status", "已完成");
	        map.put("time", "2023-07-18");
	        map.put("locpicture", new PictureRenderData(400, 300, "D:/image.jpg"));
	        map.put("urlImg", Pictures.ofUrl("https://p1.itc.cn/images01/20230418/5d13ab4a86c04a8dac668bf4129e1f0c.png", PictureType.PNG).size(400, 300).create());
	        ChartMultiSeriesRenderData sbqk = Charts
	                .ofMultiSeries("十六市区县情况", new String[] { "济南","青岛","烟台","威海"})
	                .addSeries("上报情况", new Double[] { 15.0,20.6,42.6,90.1})
	                .addSeries("查出情况", new Double[] { 12.0,15.3,28.6,80.1})
	                .create();
	        map.put("sbqk", sbqk);
	 
	        ChartMultiSeriesRenderData sjzlpm = Charts
	                .ofMultiSeries("医院综合排名", new String[] { "山东大学齐鲁医院","山东省泰山医院","山东省第二人民医院","山东省第三医院"})
	                .addSeries("数据质量排名", new Double[] { 70.5,40.6,22.7,85.4})
	                .addSeries("价格质量排名", new Double[] { 80.5,75.6,72.7,85.4})
	                .create();
	 
	        map.put("sjzlpm", sjzlpm);
	        ChartMultiSeriesRenderData qst = Charts
	                .ofMultiSeries("任务趋势", new String[] { "06-10","06-11","06-12","06-13","06-14","06-15"})
	                .addSeries("微信端", new Double[] { 70.5,40.6,22.7,85.4,700.0,40.8})
	                .addSeries("PC端", new Double[] { 80.5,50.6,62.7,45.4,200.0,140.8})
	                .addSeries("小程序端", new Double[] { 120.5,520.6,362.7,405.4,300.0,340.8})
	                .create();
	        map.put("qst", qst);
	        //柱状图、折线图共存
	        List<SeriesRenderData> seriesRenderData = new ArrayList<SeriesRenderData>(3);
	        SeriesRenderData series1 = new SeriesRenderData("GDP", new Double[] {70.5,40.6,22.7,85.4,700.0,40.8});
	        series1.setComboType(SeriesRenderData.ComboType.BAR);
	        seriesRenderData.add(series1);
	        SeriesRenderData series2 = new SeriesRenderData("人口", new Double[] {80.5,50.6,62.7,45.4,200.0,140.8});
	        series2.setComboType(SeriesRenderData.ComboType.BAR);
	        seriesRenderData.add(series2);
	        SeriesRenderData series3 = new SeriesRenderData("指数", new Double[] {0.6,0.6,0.7,0.4,0.7,0.8});
	        series3.setComboType(SeriesRenderData.ComboType.LINE);
	        seriesRenderData.add(series3);
	        ChartMultiSeriesRenderData hntb = Charts
	                .ofMultiSeries("某省社会排名", new String[] { "城市1","城市2","城市3","城市4","城市5","城市6"})
	                .create();
	        hntb.setSeriesDatas(seriesRenderData);
	        
	        map.put("hntb", hntb);
	        template = XWPFTemplate.compile(is).render(map);
	        File reportDirFile = new File(reportDir);
	        if(!reportDirFile.exists()) {
	        	reportDirFile.mkdir();
	        }
	        out = new FileOutputStream(new File(reportDir + "/生成报告结果.docx"));
	        template.write(out);
	        out.flush();
		} catch (Exception e) {
		}finally {
			if(null != out)out.close();
			if(null != template) template.close();
			//if(null != is)is.close();
		}
		return reportDir + "/生成报告结果.docx";
	}

        这里将is的流关闭一行注释掉,模拟流未关闭的情况。此时在浏览器中进行文件下载,大概率会得到一个无法下载的错误。

二、正确示范

        为了方式大家在复制的过程中遇到错误的示范问题,这里给出一段参考代码,其中已经将核心敏感的数据进行处理掉,但具体的业务逻辑不变,供参考,模板信息如下。

1、Controller下载方法定义

        在基于Ruoyi的SpringBoot项目开发中,需要定义一个用于接收前台请求的下载对象及处理方法,参考代码如下:

package com.ruoyi.project.demo.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.ChartMultiSeriesRenderData;
import com.deepoove.poi.data.Charts;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.PictureType;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.data.SeriesRenderData;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.RuoYiConfig;
import com.ruoyi.framework.web.controller.BaseController;

@Controller
@RequestMapping("/demo/wordownload")
public class WordDownLoadController extends BaseController{

	@GetMapping("/test")
    public void test(HttpServletResponse response) throws Exception {
        String realFileName = "生成报告结果.docx";
        String filePath = this.createReport();
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        FileUtils.setAttachmentResponseHeader(response, realFileName);
        FileUtils.writeBytes(filePath, response.getOutputStream());
    }

}

2、文档生成

private String createReport() throws Exception{
		String reportDir = RuoYiConfig.getProfile() + "/report";
		InputStream is = null;
		XWPFTemplate template = null;
		FileOutputStream out = null;
		try {
			is = this.getClass().getClassLoader().getResourceAsStream("report/temp.docx");
			Map<String, Object> map = new HashMap<String,Object>();
	        map.put("score", "28");
	        map.put("title", "测试任务");
	        map.put("type", "上半年综合测评");
	        map.put("status", "已完成");
	        map.put("time", "2023-07-18");
	        map.put("locpicture", new PictureRenderData(400, 300, "D:/image.jpg"));
	        map.put("urlImg", Pictures.ofUrl("https://p1.itc.cn/images01/20230418/5d13ab4a86c04a8dac668bf4129e1f0c.png", PictureType.PNG).size(400, 300).create());
	        ChartMultiSeriesRenderData sbqk = Charts
	                .ofMultiSeries("十六市区县情况", new String[] { "济南","青岛","烟台","威海"})
	                .addSeries("上报情况", new Double[] { 15.0,20.6,42.6,90.1})
	                .addSeries("查出情况", new Double[] { 12.0,15.3,28.6,80.1})
	                .create();
	        map.put("sbqk", sbqk);
	 
	        ChartMultiSeriesRenderData sjzlpm = Charts
	                .ofMultiSeries("医院综合排名", new String[] { "山东大学齐鲁医院","山东省泰山医院","山东省第二人民医院","山东省第三医院"})
	                .addSeries("数据质量排名", new Double[] { 70.5,40.6,22.7,85.4})
	                .addSeries("价格质量排名", new Double[] { 80.5,75.6,72.7,85.4})
	                .create();
	 
	        map.put("sjzlpm", sjzlpm);
	        ChartMultiSeriesRenderData qst = Charts
	                .ofMultiSeries("任务趋势", new String[] { "06-10","06-11","06-12","06-13","06-14","06-15"})
	                .addSeries("微信端", new Double[] { 70.5,40.6,22.7,85.4,700.0,40.8})
	                .addSeries("PC端", new Double[] { 80.5,50.6,62.7,45.4,200.0,140.8})
	                .addSeries("小程序端", new Double[] { 120.5,520.6,362.7,405.4,300.0,340.8})
	                .create();
	        map.put("qst", qst);
	        //柱状图、折线图共存
	        List<SeriesRenderData> seriesRenderData = new ArrayList<SeriesRenderData>(3);
	        SeriesRenderData series1 = new SeriesRenderData("GDP", new Double[] {70.5,40.6,22.7,85.4,700.0,40.8});
	        series1.setComboType(SeriesRenderData.ComboType.BAR);
	        seriesRenderData.add(series1);
	        SeriesRenderData series2 = new SeriesRenderData("人口", new Double[] {80.5,50.6,62.7,45.4,200.0,140.8});
	        series2.setComboType(SeriesRenderData.ComboType.BAR);
	        seriesRenderData.add(series2);
	        SeriesRenderData series3 = new SeriesRenderData("指数", new Double[] {0.6,0.6,0.7,0.4,0.7,0.8});
	        series3.setComboType(SeriesRenderData.ComboType.LINE);
	        seriesRenderData.add(series3);
	        ChartMultiSeriesRenderData hntb = Charts
	                .ofMultiSeries("某省社会排名", new String[] { "城市1","城市2","城市3","城市4","城市5","城市6"})
	                .create();
	        hntb.setSeriesDatas(seriesRenderData);
	        
	        map.put("hntb", hntb);
	        template = XWPFTemplate.compile(is).render(map);
	        File reportDirFile = new File(reportDir);
	        if(!reportDirFile.exists()) {
	        	reportDirFile.mkdir();
	        }
	        out = new FileOutputStream(new File(reportDir + "/生成报告结果.docx"));
	        template.write(out);
	        out.flush();
		} catch (Exception e) {
		}finally {
			if(null != out)out.close();
			if(null != template) template.close();
			if(null != is)is.close();
		}
		return reportDir + "/生成报告结果.docx";
	}

总结

        以上就是本文的主要内容,文章主要讲解了在SpringBoot中使用Poi-tl进行模板生成时,容易遇到的两个异常场景,以及针对性的给出了相应的解决方案。以上代码经过实际代码运行测试,可以正常使用。行文仓促,如有不当,尽请批评指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1009953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Solidity 小白教程:15. 异常

Solidity 小白教程&#xff1a;15. 异常 这一讲&#xff0c;我们介绍solidity三种抛出异常的方法&#xff1a;error&#xff0c;require和assert&#xff0c;并比较三种方法的gas消耗。 异常 写智能合约经常会出bug&#xff0c;solidity中的异常命令帮助我们debug。 Error …

企业如何实时监管员工聊天红包转账记录?

1 你还在担心员工飞单吗&#xff1f; 2 你还在担心员工私单吗&#xff1f; 3 你还在担心员工辱骂删除客户吗&#xff1f; 4 你还在担心员工工作量无法统计吗&#xff1f; 5 你还在担心员工离职带走客户资源吗&#xff1f; 。。。。。。 互联网时代&#xff0c;微信应用…

QCustomPlot绘图类详解(大白话)

本文假定你会使用Qt开发&#xff0c;但未接触过QCustomPlot绘图类或者是刚接触。 如何往Qt中引入QCustomPlot 首先&#xff0c;去官网下载最新版本的源码&#xff0c;注意是QCustomPlot.tar.gz这个文件&#xff0c;里面包含源码和示例。实际上&#xff0c;我们只需要qcustompl…

Hadoop-Hive

1. hive安装部署 2. hive基础 3. hive高级查询 4. Hive函数及性能优化 1.hive安装部署 解压tar -xvf ./apache-hive-3.1.2-bin.tar.gz -C /opt/soft/ 改名mv apache-hive-3.1.2-bin/ hive312 配置环境变量&#xff1a;vim /etc/profile #hive export HIVE_HOME/opt/soft/hive…

【深度学习 AIGC】stablediffusion-infinity 在无界限画布中输出绘画 Outpainting

代码&#xff1a;https://github.com/lkwq007/stablediffusion-infinity/tree/master 启动环境&#xff1a; git clone --recurse-submodules https://github.com/lkwq007/stablediffusion-infinity cd stablediffusion-infinity conda env create -f environment.yml conda …

笔记(三)传统图机器学习的特征工程-节点

1、不同种类的任务 2、传统图机器学习的几个层面 &#xff08;人工特征工程机器学习&#xff09; 3、属性特征-节点本身的特征 4、连接特征-节点的结构信息 5、训练-预测 6、好模型需要好数据 -人工构造的特征&#xff08;特征工程&#xff09;-节点、连接、全图-无向图 7、节…

算法训练 第二周

一、赎金信 本题给出了两个字符串ransomNote和magazine&#xff0c;需要让我们判断ransomNote中的字符能不能由magazine中的字符构成&#xff0c;也就是说我们需要将所有ransomNote中的字符找到一个在magazine中与这个字符相同的字符&#xff0c;且每个字符只能使用一次&#x…

openssl websockets

1. HTTPS通信的C实现 - 知乎

【干货】Anaconda导出环境配置文件

【干货 | 项目导出安装环境要求】 方法yml文件req.txt文件 参考 方法 yml文件 激活虚拟环境&#xff08;fyp是我的虚拟环境名称&#xff0c;请根据你自己的名称进行修改&#xff09; conda activate fyp运行此代码 conda env export > environment.ymlreq.txt文件 激活…

runtime过程中,常见jar问题解决

io.netty java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator.<init>此类问题报错&#xff0c;主要是io.netty 多个jar 冲突导致。、 使用以下命令查看同一个jar 有哪些版本 mvn dependency:resolve -Dclassifiersources对一些不愿意引入的依赖加上…

VIGC:自问自答,高质量视觉指令微调数据获取新思路

从今年四月份开始&#xff0c;随着MiniGPT-4, LLaVA, InstructBLIP等多模态大模型项目的开源&#xff0c;大模型的火从NLP领域烧到了计算机视觉及多模态领域。 多模态大模型需要高质量的图文对话数据进行指令微调&#xff0c;而当前多模态指令微调数据多基于纯文本GPT-4构建&am…

【Purple Pi OH RK3566鸿蒙开发板】OpenHarmony音频播放应用,真实体验感爆棚!

本文转载于Purple Pi OH开发爱好者&#xff0c;作者ITMING 。 原文链接&#xff1a;https://bbs.elecfans.com/jishu_2376383_1_1.html 01注意事项 DevEco Studio 4.0 Beta2&#xff08;Build Version: 4.0.0.400&#xff09; OpenHarmony SDK API 9 创建工程类型选择Appli…

华为云云耀云服务器L实例评测 | 部署H5 一起来吃月饼游戏

文章目录 前言一、云服务器相对传统服务器有什么优势1.1、可伸缩性&#xff08;Scalability&#xff09;1.2、灵活性&#xff08;Flexibility&#xff09;1.3、高可用性&#xff08;High Availability&#xff09;1.4、备份和恢复&#xff08;Backup and Recovery&#xff09;1…

Golang Gorm 创建HOOK

创建的时候&#xff0c;在插入数据之前&#xff0c;想要做一些事情。钩子函数比较简单&#xff0c;就是实现before create的一个方法。 package mainimport ("gorm.io/driver/mysql""gorm.io/gorm" )type Student struct {ID int64Name string gorm:&q…

redis深度历险 千帆竞发 —— 分布式锁

分布式应用进行逻辑处理时经常会遇到并发问题。 比如一个操作要修改用户的状态&#xff0c;修改状态需要先读出用户的状态&#xff0c;在内存里进行修改&#xff0c;改完了再存回去。如果这样的操作同时进行了&#xff0c;就会出现并发问题&#xff0c;因为读取和保存状态这两个…

AUTOSAR-存储基础知识

1、存储基础知识 RAM 又称随机存取存储器&#xff0c;存储单元的内容可以按照需要随机取出或者存入&#xff0c;存取数据比较快。这种存储器在断电时&#xff0c;会丢失其存储内容&#xff0c;所以一般是 CPU运行时会把程序从 ROM 拷贝到 RAM 里面执行。所以一般 RAM 是作为和…

软件测试公式之如何高质量的做BUG分析?

对于BUG分析&#xff0c;测试人员再熟悉不过了。但如果是面对大量的BUG&#xff0c;要如何有效的分析呢&#xff1f;有什么好的方案和行动项&#xff1f;今天聊聊这个话题。 01 BUG分析简单可以分为两类&#xff1a;宏观BUG分析 和 微观BUG分析。 宏观BUG分析&#xff1a;在…

六、线程池的编写与解析 —— TinyWebServer

六、线程池的编写与解析 —— TinyWebServer 一、前言 经过上次数据库连接池的书写&#xff0c;大家也应该明白池的编写。 这里说一下不同点&#xff0c;和一些要注意的点。 为什么使用模板&#xff1f;为什么不用单例模式了&#xff1f;这里的线程池扮演的角色是什么&#x…

【PowerQuery】PowerBI 手动刷新数据内容

PowerBI的手动刷新方式和Excel基本一样&#xff0c;我们通过刷新数据源来实现数据的手动刷新&#xff0c;当然PowerBI 和Excel一样存在着单数据源刷新和全局数据源刷新两个操作。如果希望刷新单个数据源&#xff0c;我们可以在数据字段进行数据的刷新&#xff0c;具体的操作步骤…

阈值回归模型(Threshold Regression Model)及R实现

阈值回归模型是一类回归模型&#xff0c;其中预测变量与结果以阈值依赖的方式相关联。通过引入一个阈值参数&#xff08;也称为转折点&#xff09;&#xff0c;阈值回归模型提供了一种简单而优雅、可解释的方法来建立结果和预测变量之间某些非线性关系的模型。在生物医学领域中…