项目思路:由于使用的是freemarker所以要先将ftl转化成html文件然后再将HTML转化成pdf文件,所以思路就来了!
1、在ftl文件的界面显示echarts图并且在每个table下面初始化一个统计图。(关于统计图的初始化这里就不在赘述),其次是动态加载数据由于使用js加载界面的所以必须要从后台拿到一个json集合然后再遍历代码如下:
let studentsXinlv = data.xinlvs;
for (let i = 0; i < studentsXinlv.length; i++) {
if (studentsXinlv[i].showName === '合计' && studentsXinlv[i].gender === '男') {
xloption.series[0].data[0] = studentsXinlv[i].zhengchanglv;
xloption.series[0].data[1] = studentsXinlv[i].guohuanlv;
xloption.series[0].data[2] = studentsXinlv[i].guosulv;
xloption.series[0].data[3] = studentsXinlv[i].zayinlv;
} else if (studentsXinlv[i].showName === '合计' && studentsXinlv[i].gender === '女') {
xloption.series[1].data[0] = studentsXinlv[i].zhengchanglv;
xloption.series[1].data[1] = studentsXinlv[i].guohuanlv;
xloption.series[1].data[2] = studentsXinlv[i].guosulv;
xloption.series[1].data[3] = studentsXinlv[i].zayinlv;
}
}
现在图生成了那如何拿到生成统计图的图片呢?这就用到了
let imgs = echarts.getDataURL({type: 'png'});
获取到每个echarts的base64位的png图片!
强烈建议!!!如果在后台下载并将文件放在header中存储,在前端显示下载,这样的问题千万千万别用ajax发请求!!!因为ajax发送的请求后返回的是json对象,也就是字符流,而文件是二进制保存的所以就会出现乱码一样的东西,不是你想要的文件!
解决这类问题需要发送表单!那如何携带多图片发送表单呢?代码如下:
$("#allimg").append($("<input type='hidden' name='imgs' value='" + imgs + "'/>"));
需要在body里面申明一个form
<div>
<form id="allImgSubmit" action="${base}/manage/control/jiancebaogao/tongjiimg" method="post">
<input type="hidden" name="year" value="${currentYear!}"/>
<input id="allimg" type="hidden" name="schoolId" value="${(school.id?c)!}"/>
</form>
</div>
最后别忘了submit()表单!
重头戏来了!!!!!!
java后端:
首先是关于参数接收的问题:其他参数传什么用什么来接(一般是string但是传的和接收的名字需要一致)
图片接收需要的是一个字符数组String[] allimg保证能接收到!
那接收到任何如何转换呢?这些别人博客上面也有,我也是抄的博客上面的修修改改,是好几天前的了所以就不一个个去找了,在这里我直接粘代码,有和别人一样的请见谅!
将base64位的图片转成正常图片并保存在文件中:上干货!
maven依赖:
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.12</version>
</dependency>
图片64位转png图片
import sun.misc.BASE64Decoder;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* 描述:将64位字节转换为图片类型存储
* @author tuoxw
* imgPath :存储图片的路径
*dateUrl:64为字节的图片 类似于:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgA。。。
* imgName 自定义的图片名称
* */
public class Base64ToImg {
public static void base64ToImg(String imgPath,String imgName,String dateUrl) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
String[] split = dateUrl.split(",");
byte[] bytes = decoder.decodeBuffer(split[1]);
for (int i = 0; i < bytes.length; ++i) {
if (bytes[i] < 0) {
// 调整异常数据
bytes[i] += 256;
}
}
OutputStream out = new FileOutputStream(imgPath + "/"+imgName+".png");
out.write(bytes);
out.flush();
out.close();
}
}
多图片?那好办!!
for (int i = 0; i < imgs.length; i++) {
String name = "" + i;
pngs [i] = imgBasePath +File.separator + name + ".png";
Base64ToImg.base64ToImg(imgBasePath, name, imgs[i]);
}
那个pngs是做铺垫,后面能用得上记得给申明一下哈!
好了图片拿到了,那pdf呢?这要用到文件流了(在这里拿到的pdf是处理过的,也就是前端页面转换的时候一定要留够空白页这样好将图片插进去)
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import java.io.FileOutputStream;
import java.io.IOException;
public class AddImgToPDF {
public static void addSeal(int []pages, String savePdf, String []pngs, String sealPdf) throws IOException {
int marginLeft = 400;// 左边距
int marginBottom = 50;// 底边距
PdfReader pdfreader = new PdfReader(savePdf);
// 获得PDF总页数
int pdfPage = pdfreader.getNumberOfPages();
for (int i = 0; i < pages.length; i++) {
if (pages[i] <= 0 || pages[i] > pdfPage) {
System.out.println("pdf文件无当前页");
}
}
// 获取指定页的宽和高
if (pdfreader != null)
pdfreader.close();
PdfReader pdf = new PdfReader(savePdf);
PdfStamper stamper = null;
Document document = null;
try {
stamper = new PdfStamper(pdf, new FileOutputStream(sealPdf));// 生成的PDF
for (int i = 0; i < pngs.length; i++) {
document = new Document(pdfreader.getPageSize(pages[i]));
PdfContentByte overContent = stamper.getOverContent(pages[i]);
Image image = Image.getInstance(pngs[i]);// 图片名称
// image.setAbsolutePosition(75,marginBottom);// 左边距、底边距
image.setAbsolutePosition(75,marginBottom);// 左边距、底边距
image.scalePercent(50, 75);
overContent.addImage(image);
overContent.stroke();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (document != null){
document.close();
}
if (null != stamper) {
stamper.close();
}
if (pdf != null) {
pdf.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
这里要对该方法说明一下:
1、[]pages:你拿到pdf的空白页的页码(多个空白页)。
2、savepdf:是你需要处理的pdf文件(全路径:*******.pdf)
3、pngs是你拿到的图片(全路径*******.png,前面的铺垫用上了传进来就行)
4、后面那个是pdf输出路径(全路径:*****.pdf)
方法参数说明: image.scalePercent(50, 75);是等比例缩放图片
遗留问题:虽然导出来了带图片的pdf文件但是那个pdf的空白页码总是是写死的感觉不爽那怎么办?这个本人搜了好多资料暂未解决!!有知道的小伙伴可以私聊我!我的解决方法是这样的:
既然每一页是确定的(空白页和图片)我需要得到最后一页pdf页码然后依次去减就能得到每一页的空白页
int[] emptyPdfPage = new int[]{(pages-23),(pages-21),(pages-19),(pages-17),(pages-15),(pages-13),(pages-11),(pages-8),(pages-6),(pages-4),pages};
这样就能实现动态的赋值,问题是如果统计表的数据多少不确定那么这个方法就不可行!!
附加:获取pdf页码的代码:
import com.itextpdf.text.pdf.PdfReader;
import java.io.IOException;
import java.io.InputStream;
public class EmptyPagesToPDF {
public static Integer pages(String inpdfPath) throws IOException {
InputStream inputStream = InputStreamUtil.getInputStream(inpdfPath);
byte[] pdfbyte = InputStreamUtil.toByteArray(inputStream);
PdfReader reader = new PdfReader(pdfbyte);
// 获取页码
int pages = reader.getNumberOfPages();
reader.close();
return pages;
}
}
声明:以上代码有众多是借鉴的别人代码,然后修改的!!此次主要是分享个人心得以及对于该类问题的一种思路!希望对需要帮助的人有用!