最近项目要改做一个需求,需求内容就是做一个批量导出的pdf功能,没接触过,所以在网上搜了很多内容,也碰到很多坑,现在自己总结一下,方便以后项目碰到。
1、首先maven依赖选择 刚开是用的是flying-saucer-pdf,但是其中碰到的问题是其中的getBBox问题,原生jar包会存在getBBox(I)问题,因为该依赖会下载flying-saucer-pdf,flying-saucer-core,还有自带的itext2.1.7jar包,导致报错,后来选择flying-saucer-pdf-itext5。
2、因为客户端访问服务器的时候,如果你选择了文件夹导出,那么会导出在服务器端,而客户端不行,尤其是java的图形化界面JFileChooser,该控件慎重使用。所以后来把原来的开发改掉,现在使用生成pdf然后打包成zip下载。
3、HTML内部中文与参数中文之间会出很大问题
4、图片问题
5、中文包问题iTextAsian问题 路径与iTextpdf包不同步
最后经过一周的努力终于把整个的过程完成了,现在贴一个小demo。
MAVEN依赖
<dependency>
<groupId>org.xhtmlrenderergroupId>
<artifactId>flying-saucer-pdf-itext5artifactId>
<version>9.1.6version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
<version>2.3.23version>
dependency>
其中还有到了ant.jar,iText-2.0.8.jar,iTextAsian.jar
https://download.csdn.net/download/u012832579/10652048 下载链接
主代码
@RequestMapping(value = "pdfExport",method = RequestMethod.GET)
public void pdfExport(@RequestParam(value = "ids") String ids,Model model,HttpServletRequest request,HttpServletResponse response) throws IOException, DocumentException{
String filePath = customerTaskService.getWorkUrl() + "xwjys/src/main/Webapp/extjs/zip";
//删除zip包
File file=new File(filePath+ "/file.zip");
if(file.exists()){
file.delete();
}
String path = customerTaskService.getWorkUrl().replace('/', '\\') +"xwjys\\src\\main\\Webapp\\extjs\\zip\\file";
//删除本地zip以及残余pdf
customerTaskService.delAllFile(path); //删除完里面所有内容
String[] idss = ids.split(",");
System.out.println("生成本地pdf");
for(String id:idss){
Model models = getModel(Long.valueOf(id),model);
customerTaskService.pdfExport(models,filePath,id);
}
System.out.println("打包zip进行下载");
customerTaskService.zipDowload(filePath, request, response);
System.out.println("下载成功");
}
以下代码对应主代码方法调用
获取本地路径
//获取项目绝对路径
public String getWorkUrl(){
String t=Thread.currentThread().getContextClassLoader().getResource("").getPath();
int num=t.indexOf(".metadata");
return t.substring(1,num);
}
删除上次生成的pdf
public boolean delAllFile(String path) {
boolean flag = false;
File file = new File(path);
if (!file.exists()) {
return flag;
}
if (!file.isDirectory()) {
return flag;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
} else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
flag = true;
}
}
return flag;
}
HTML是一个模板,内容由自己的数据来填
生成pdf的内容 主要是看自己需要什么,用model来 存、html来取 将数据放在url中,看类型取,在html中用el表达式取 比如这个界面用${grcode.xxx}
model.addAttribute("qrcode", url);
比如你也可以把model换成date,然后HTML中用${name}来获取中文
Map<String,Object> data = new HashMap<String,Object>();
data.put("name","小红");
生成pdf 方法 pdfExport
public void pdfExport(Model model,String filePath,String id)throws IOException {
//模板
String HTML = "template_freemarker_fs.html";
//名称
String resource = filePath + "/file/" + id +".pdf";
String content = freeMarkerRender(model, HTML);
this.createPdf(content, resource);
}
合并数据以及模板
public String freeMarkerRender(Model data, String htmlTmp) {
Writer out = new StringWriter();
try {
// 获取模板,并设置编码方式
Configuration freemarkerCfg = new Configuration();
String workUrl = getWorkUrl().replace('/', '\\');
freemarkerCfg.setDirectoryForTemplateLoading(new File(workUrl+"xwjys\\src\\main\\webapp\\extjs\\templates"));
freemarkerCfg.setDefaultEncoding("UTF-8");
freemarkerCfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
Template template = freemarkerCfg.getTemplate(htmlTmp);
// 合并数据模型与模板
template.process(data, out); //将合并后的数据和模板写入到流中,这里使用的字符流
out.flush();
return out.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
return null;
}
本快主要的就是将pdf生成,其中设计图片,图片是在html中,setBaseURL代表的是该图片的绝对路径xxx/src/main/webapp/extjs/images/,如果你还需要别的图片,如果是同级目录的那么直接在html中写该图片的名称
public void createPdf(String content,String dest) throws IOException{
File file = new File(dest);
//建立数据输出通道
FileOutputStream fileOutputStream = new FileOutputStream(file);
ITextRenderer render = new ITextRenderer();
// 创建字体解析器
ITextFontResolver fontResolver = render.getFontResolver();
// 设置字体
try{
fontResolver.addFont(getWorkUrl()+ "xwjys/src/main/webapp/extjs/templates/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
}catch(Exception e){
e.printStackTrace();
}
// 解析html生成pdf
render.setDocumentFromString(content);
// 解决图片相对路径的问题
String myUrl = getWorkUrl();
render.getSharedContext().setBaseURL("file:/"+myUrl+"xwjys/src/main/webapp/extjs/images/bg_bz01.jpg");
render.layout();
try {
render.createPDF(fileOutputStream);
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
fileOutputStream.flush();
fileOutputStream.close();
}
然后开始将该pdf打包成zip 并提供浏览器下载
public void zipDowload(String filePath,HttpServletRequest request,HttpServletResponse response) throws IOException{
//打包文件的存放路径
ZipCompressorByAnt zc = new ZipCompressorByAnt(filePath+ "/file.zip");
//需要打包的文件路径
zc.compress(filePath+ "/file/");
//开始下载
String userAgent = request.getHeader("USER-AGENT");
//判断浏览器代理并分别设置响应给浏览器的编码格式
String finalFileName = null;
String fileZip = "file.zip";
if(StringUtils.contains(userAgent, "MSIE")||StringUtils.contains(userAgent,"Trident")){//IE浏览器
finalFileName = URLEncoder.encode(fileZip,"UTF8");
System.out.println("IE浏览器");
}else if(StringUtils.contains(userAgent, "Mozilla")){//google,火狐浏览器
finalFileName = new String(fileZip.getBytes(), "ISO8859-1");
}else{
finalFileName = URLEncoder.encode(fileZip,"UTF8");//其他浏览器
}
response.reset();
response.setContentType("application/x-octet-stream;charset=utf-8");
response.setHeader("Content-Disposition" ,"attachment;filename=\"" +finalFileName+ "\"");//下载文件的名称
ServletOutputStream servletOutputStream = null;
try {
servletOutputStream = response.getOutputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
DataOutputStream temps = new DataOutputStream(servletOutputStream);
DataInputStream in = new DataInputStream(
new FileInputStream(getWorkUrl().replace('/', '\\') +"xwjys\\src\\main\\Webapp\\extjs\\zip\\file.zip"));//浏览器下载文件的路径
byte[] b = new byte[4096];
try {
while ( (in.read(b)) != -1) {
temps.write(b);
}
temps.flush();
response.getOutputStream().flush();
if(response.getOutputStream()!=null) response.getOutputStream().close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(temps!=null) temps.close();
if(in!=null) in.close();
servletOutputStream.close();
}
}
ZipCompressorByAnt .java
package com.smarts.utils.fileupload;
import java.io.File;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Zip;
import org.apache.tools.ant.types.FileSet;
public class ZipCompressorByAnt {
private File zipFile;
public ZipCompressorByAnt(String pathName) {
zipFile = new File(pathName);
}
public void compress(String srcPathName) {
File srcdir = new File(srcPathName);
if (!srcdir.exists())
throw new RuntimeException(srcPathName + "不存在!");
Project prj = new Project();
Zip zip = new Zip();
zip.setProject(prj);
zip.setDestFile(zipFile);
FileSet fileSet = new FileSet();
fileSet.setProject(prj);
fileSet.setDir(srcdir);
//fileSet.setIncludes("**/*.java"); 包括哪些文件或文件夹 eg:zip.setIncludes("*.java");
//fileSet.setExcludes(...); 排除哪些文件或文件夹
zip.addFileset(fileSet);
zip.execute();
}
}
前台js部分代码
var link= document.createElement('a');
link.setAttribute("href", "../customertask/pdfExport?ids="+ids.toString());
link.setAttribute("download", `file.zip`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
template_freemarker_fs.html 支持换行,图片,中文
<html lang="en">
<head>
<meta content="text/html; charset=UTF-8"/>
<title>Titletitle>
<style>
body{
font-family:SimSun;
}
.color{
color: green;
}
.pos{
position:absolute;
left:200px;
top:5px;
width: 200px;
font-size: 10px;
}
style>
head>
<body>
<img src="bg_bz01.jpg" width="50px"/>
<img src="bg_bz02.jpg" width="50px"/>
<div class="color:red">
<strong>您好strong>, ${curBillInfo.ypName} 中啊是个回复爱国阿三帅哥俺是个啊个啊个十大个十大伽师瓜的阿三个的撒搞定撒个的撒个撒个撒个啊
个啊大哥 啊高大上搞定撒个
div>
body>
html>