#使用POI实现word模板导出
笔者的word模板没有存在的OSS中,因为模板不多,故我是在Spring boot项目中的resources中创建了一个专门用于存放word模板的文件夹
首先创建一个word模板
通过ctrl+F9编辑域空间 格式为${name}
InputStream in = null;
FileOutputStream out =null;
String filename ="";
/*
wordTemplate/ 是resources下创建的模板文件夹
*/
//读取模板
ClassPathResource classPathResource = new ClassPathResource("wordTemplate/" + "分析模板.docx");
String path = classPathResource.getPath();
in = this.getClass().getClassLoader().getResourceAsStream(path);
//获取context
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
IContext context = report.createContext();
FieldsMetadata fm = report.createFieldsMetadata();
//获取图片
fm.addFieldAsImage("one");
//这里我是获取的阿里OSS的线上图片
//不想使用线上的可以直接获取到路径上的图片即可
InputStream one= Downimage.steamToFile(lineImgUrl);
context.put("one",one);
//获取列表
fm.load("line",ImpactAnalysis.class,true);
List<ImpactAnalysis> analysisList = new ArrayList<>();
if (null!=mapNewLineRoad){
String repeatLine = mapNewLineRoad.getRepeatLine();
if(null!=repeatLine){
String[] split = repeatLine.split(";");
for (int i = 0; i < split.length; i++) {
ImpactAnalysis analysis = new ImpactAnalysis();
analysis.setAffectedLine(split[i]);
analysisList.add(analysis);
}
}
}
context.put("line",analysisList);
//这部分代码既是生成到当前项目的上一级工作空间
//这里是获取到当前项目的根
String property = System.getProperty("user.dir");
//当前项目根的上一级
property = property.substring(0, property.lastIndexOf(File.separator));
log.info("获取当前项目的相对路径,改路径为",property);
filename =property+"/新增路线分析表"+format+".docx";
out = new FileOutputStream(new File(filename));
report.process(context, out);
//------------------上面这部分代码则可以生成在一份word----------------------
//------------------将word发送到浏览器下面这部分----------------------------
/* response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
report.process(context, response.getOutputStream());
*/
one.close();
}catch (IOException e) {
log.error("读取Word模板异常",e);
} catch (XDocReportException e) {
log.error("word模板生成失败",e);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//不需要将word转换成PDF这里可不要
if (filename!=null){
try{
Word2PdfAsposeUtil.pdf(filename,response,0);
}catch (Exception e){
e.getMessage();
}
}
}
public static BufferedInputStream steamToFile(String destUrl) {
FileOutputStream fos = null;
BufferedInputStream bis = null;
HttpURLConnection httpUrl = null;
URL url = null;
int BUFFER_SIZE = 1024;
byte[] buf = new byte[BUFFER_SIZE];
int size = 0;
String dir="E://";
String filename = String.valueOf(System.currentTimeMillis())+".png";
try {
url = new URL(destUrl);
httpUrl = (HttpURLConnection) url.openConnection();
httpUrl.connect();
bis = new BufferedInputStream(httpUrl.getInputStream());
} catch (IOException e) {
} catch (ClassCastException e) {
} finally {
try {
fos.close();
bis.close();
httpUrl.disconnect();
} catch (IOException e) {
} catch (NullPointerException e) {
}
}
return bis;
}
@Data
public class ImpactAnalysis {
//影响线路
private String affectedLine;
//重复系数
private String repeatabilityFactor;
//影响客流预测(人次/天)
private String people;
}
#这部分是将word转换成PDF的代码
这里主要是用了aspose
这里是将jar包下载下来,然后导入到项目中,如何导入可以百度一下
这里需要注意一点就是,本地导入的jar包,发布在测试服可能会出现读取不到这个jar包的情况。倘若出现这种情况则需要在pom文件中加入这个
<build>
<finalName>finalName</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<!-- 如果没有该配置,devtools不会生效 -->
<!--设置为true,以便把本地的system的jar也包括进来-->
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
jar包加入到lib中,需要maven导入进来
<dependency>
<groupId>com.aspose.words</groupId>
<artifactId>aspose-words</artifactId>
<version>words-15.8.0-jdk16</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/aspose-words-18.6-jdk16-crack.jar</systemPath>
</dependency>
#最后这里存在一个问题,就是导出预览的时候,左上角的标题是存放在Google的临时空间的,这里找了一个pdfbox来修正
##这是maven坐标
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>1.8.8</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
<version>1.8.8</version>
</dependency>
public static boolean getLicense() {
boolean result = false;
try {
ClassPathResource classPathResource = new ClassPathResource("wordTemplate/" + "license.xml");
String path = classPathResource.getPath();
InputStream is = Word2PdfAsposeUtil.class.getClassLoader().getResourceAsStream(path);
License aposeLic = new License();
aposeLic.setLicense(is);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static String doc2pdf(String inPath, String outPath) {
if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生
return null;
}
FileOutputStream os = null;
try {
String path = outPath.substring(0, outPath.lastIndexOf(File.separator));
log.info("第二次获取当前项目的相对路径,改路径为",path);
long old = System.currentTimeMillis();
File file = new File(path); // 新建一个空白pdf文档
if (!file.exists()) {
file.mkdirs();
}
file = new File(outPath);
os = new FileOutputStream(file);
Document doc = new Document(inPath); // Address是将要被转化的word文档
doc.save(os, SaveFormat.PDF);// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,
// EPUB, XPS, SWF 相互转换
long now = System.currentTimeMillis();
os.close();
log.info("pdf转换成功,共耗时:" + ((now - old) / 1000.0) + "秒"); // 转化用时
} catch (Exception e) {
e.printStackTrace();
}finally {
if (os != null) {
try {
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return outPath;
}
public static void pdf(String url, HttpServletResponse response,Integer number) throws Exception {
if (StringUtils.isBlank(url)) {
return;
}
File file = null;
String property = System.getProperty("user.dir");
System.out.println("第二次获取到的相对路径:"+property);
// 文件后缀
String suffix = url.substring(url.lastIndexOf(".") + 1);
if ("doc".equals(suffix) || "docx".equals(suffix)) {
file = new File(Word2PdfAsposeUtil.doc2pdf(url, property + "线路新增审核" + ".pdf"));
}
try {
InputStream stream = new FileInputStream(file);
ServletOutputStream out = response.getOutputStream();
byte buff[] = new byte[1024];
int length = 0;
//开始写入文件
while ((length = stream.read(buff)) > 0) {
out.write(buff, 0, length);
}
/*
* 这里存在一个问题,就是导出到浏览器预览,名称没有了
*
* */
// response.setContentType("application/msword");
/* log.info("----------------filename--------------"+file.getName());
String fileName = new String(file.getName().getBytes("UTF-8"), "ISO8859-1");
log.info("----------------fileName--------------"+fileName);
response.reset();
response.setContentType("application/pdf;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + file.getName());
response.addHeader("Content-Length", "" + file.length());
if (number==0){
response.setHeader("Content-Disposition", "attachment;filename="+fileName
.concat(String.valueOf(URLEncoder.encode("线路新增审核", "UTF-8"))));
}
if (number==1){
response.setHeader("Content-Disposition", "attachment;filename="+fileName
.concat(String.valueOf(URLEncoder.encode("线路调整审核", "UTF-8"))));
}
if (number==2){
response.setHeader("Content-Disposition", "attachment;filename="+fileName
.concat(String.valueOf(URLEncoder.encode("线路撤销审核", "UTF-8"))));
}*/
/* Thread.sleep(500);
//这里采取在读一次硬盘中的文件,在将字节流返回
//获取到PDF保存路径
String path =file.getPath();
File pdfFile = new File(path);
InputStream fis = new BufferedInputStream(new FileInputStream(pdfFile));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
response.reset();
response.setContentType("application/pdf;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + new String(file.getName().getBytes()));
response.addHeader("Content-Length", "" + file.length());
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
toClient.write(buffer);
toClient.flush();
toClient.close();*/
//使用PDFdocument设置
File pdffile = new File(file.getPath());
try (
OutputStream outputStream = response.getOutputStream();
//加载pdf附件到PDF流中
PDDocument document = PDDocument.load(new FileInputStream(file))) {
response.setCharacterEncoding("UTF-8");
String showName = pdffile.getName();
//showName = URLEncoder.encode(showName, "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename="+showName.concat(String.valueOf(URLEncoder.encode(showName, "UTF-8"))));
//response.setHeader("Content-Disposition", "inline;fileName=" + new String(showName.getBytes()) + ";fileName*=UTF-8''" + new String(showName.getBytes()));
//从PDF流中获得PDF文档属性对象
PDDocumentInformation info = document.getDocumentInformation();
//设置PDF文档属性对象的文件名称(最重要的环节)
info.setTitle(showName);
document.setDocumentInformation(info);
//修改完直接输出到响应体中
document.save(outputStream);
} catch (Exception e) {
log.error( e.getMessage());
}
stream.close();
out.close();
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
#总结一下,这真的是峰回路转,主要是一开始需求不明确,开始只是导出word,结果后面要求把word转换成PDF,没办法aspose的document好像只能读取文件路径而不是流文件,就只能通过读取生产好的word进行转换,又因为这样转换到前端的名字不对,最后只能生产出来PDF不发给前端,保存在服务器中再次读取,重新设置好名称什么的发给前端。