实现方案:
一、itext5 java实现
二:vue html2Canvas+jspdf 组件实现
一、java实现
1.实现思路
绘制table 每行列设计样式处理、图片需要独立处理、正常业务场景下有合并列 合并行场景
ps:后端实现样式需要花费时间调整
2、pom依赖
com.itextpdf
itextpdf
5.5.11
com.itextpdf.tool
xmlworker
5.5.11
com.itextpdf
itext-asian
5.2.0
org.xhtmlrenderer
flying-saucer-pdf-itext5
9.1.16
net.sf.jtidy
jtidy
r938
3、代码实现
public static void main(String[] args) throws Exception {
String id = UUID.randomUUID().toString().replace("-", "");
//临时文件目录
FileOutputStream fos = new FileOutputStream("/Users/hll/Downloads/" + id + ".pdf");
//1.打开文档并设置基本属性
Document document = new Document();
//writer
PdfWriter writer = PdfWriter.getInstance(document, fos);
writer.setViewerPreferences(PdfWriter.PageModeUseThumbs);
writer.setPageSize(PageSize.A4);
document.open();
//标题一
Paragraph title = new Paragraph("编号:" + id, getPdfChineseFont(14));
//标题样式
title.setPaddingTop(0.1f);
document.add(title);
//第一表格列宽
float[] firtWidths = {200, 200, 200, 200};
float[] firtWidths2 = {200, 200, 200};
float[] firtWidths3 = {200, 200};
PdfPTable table1 = new PdfPTable(firtWidths);
table1.setTotalWidth(800);
table1.setHorizontalAlignment(Element.ALIGN_LEFT);
//表格数据
//mock数据
Object[][] datas = {
{"名称", "ts", "日期", "2022-10-19 00:00:00"},
{"姓名", "张三", "地址", "xxxxxx"},
{"联系人", "李四2", "性别", "男"},
{"备注", "备注xxx"}
};
//table数据填充
for (int i = 0; i < datas.length; i++) {
for (int j = 0; j < datas[i].length; j++) {
//选好cell处理数据
PdfPCell pdfCell = new PdfPCell();
//合并单元格
if (i == 3 && j == 1) {
pdfCell.setRowspan(1);
pdfCell.setColspan(3);
}
setTableStyle(table1, pdfCell);
Paragraph paragraph = new Paragraph(String.valueOf(datas[i][j]), getPdfChineseFont(8));
pdfCell.setPhrase(paragraph);
table1.addCell(pdfCell);
}
}
document.add(table1);
//标题
Paragraph title2 = new Paragraph("基本信息", getPdfChineseFont(14));
//标题样式
title2.setPaddingTop(0.1f);
document.add(title2);
//mock数据
Object[][] datas2 = {
{"姓名", "李四", "性别", "男"},
{"身份证号", "32088000000000", "联系地址", "x x x x"},
{"联系方式", "1700000000", "民族", "汉"},
{"经济来源", "补助金", "居住情况", "独居"},
{"联系人", "王四", "文化程度", "大学"},
{"设备卡号", "1111111", "医疗费用支付方式", "自费"},
{"备注", "备注11111"}
};
PdfPTable table2 = new PdfPTable(firtWidths);
table2.setTotalWidth(800);
table2.setHorizontalAlignment(Element.ALIGN_LEFT);
//table数据填充
for (int i = 0; i < datas2.length; i++) {
for (int j = 0; j < datas2[i].length; j++) {
//选好cell处理数据
PdfPCell pdfCell = new PdfPCell();
//合并单元格
if (i == 6 && j == 1) {
pdfCell.setRowspan(1);
pdfCell.setColspan(3);
}
setTableStyle(table2, pdfCell);
Paragraph paragraph = new Paragraph(String.valueOf(datas2[i][j]), getPdfChineseFont(8));
pdfCell.setPhrase(paragraph);
table2.addCell(pdfCell);
}
}
document.add(table2);
setEvaluationMaterials(document);
document.close();
//输出pdf、上传oss、删除临时文件
}
/**
* pdf中文字体设置
*
* @return
* @throws Exception
*/
public static Font getPdfChineseFont(Integer fontSize) throws Exception {
if (fontSize == null) {
//默认11
fontSize = 11;
}
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",
BaseFont.NOT_EMBEDDED);
Font fontChinese = new Font(bfChinese, 12, Font.NORMAL);
fontChinese.setColor(BaseColor.BLACK);
fontChinese.setSize(fontSize);
return fontChinese;
}
public static void setTableStyle(PdfPTable table, PdfPCell cell) {
// 设置表格样式
table.setLockedWidth(true);
table.setTotalWidth(500);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
// 设置单元格样式
cell.setMinimumHeight(35);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setBackgroundColor(BaseColor.WHITE);
cell.setBorder(0);
cell.setBorderWidthTop(0.1f);
cell.setBorderWidthBottom(0.1f);
cell.setBorderWidthLeft(0.1f);
cell.setBorderWidthRight(0.1f);
cell.setBorderColorBottom(BaseColor.BLACK);
cell.setBorderColorLeft(BaseColor.BLACK);
cell.setBorderColorRight(BaseColor.BLACK);
cell.setBorderColorTop(BaseColor.BLACK);
cell.setPadding(3);
}
private static void setEvaluationMaterials2(Document document) throws Exception {
}
/**
* 评估材料和签名数据
*
* @param document
*/
private static void setEvaluationMaterials(Document document) throws Exception {
//标题
Paragraph title6 = new Paragraph("附件资料", getPdfChineseFont(14));
//标题样式
title6.setPaddingTop(0.1f);
document.add(title6);
//固定列数量
float[] widths = {200, 200, 200, 200};
//mock数据
String imgUrl = "https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=baidu&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined©right=undefined&cs=1733628663,1513811979&os=1048688745,503314157&simid=3515359309,406107883&pn=0&rn=1&di=7146857200093233153&ln=1660&fr=&fmq=1666232917406_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fgimg0.baidu.com%252Fgimg%252Fsrc%253Dhttp%25253A%25252F%25252Fgdown.baidu.com%25252Fimg%25252F0%25252F200_200%25252F1c7d0637ca01803040e087fb44e47654.png%2526app%253D2008%2526size%253Db219%252C219%2526n%253D0%2526g%253D0n%2526sec%253D1641061390%2526t%253Dff5bb46aea0e7600d807a2558b448b20%26refer%3Dhttp%253A%252F%252Fgimg0.baidu.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1668824917%26t%3D287ed81b8be205074eb331a279ed95dc&rpstart=0&rpnum=0&adpicid=0&nojc=undefined&dyTabStr=MCwyLDMsMSw2LDUsNCw3LDgsOQ%3D%3D";
String imgUrl2 = "https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=baidu&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined©right=undefined&cs=1733628663,1513811979&os=1048688745,503314157&simid=3515359309,406107883&pn=0&rn=1&di=7146857200093233153&ln=1660&fr=&fmq=1666232917406_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fgimg0.baidu.com%252Fgimg%252Fsrc%253Dhttp%25253A%25252F%25252Fgdown.baidu.com%25252Fimg%25252F0%25252F200_200%25252F1c7d0637ca01803040e087fb44e47654.png%2526app%253D2008%2526size%253Db219%252C219%2526n%253D0%2526g%253D0n%2526sec%253D1641061390%2526t%253Dff5bb46aea0e7600d807a2558b448b20%26refer%3Dhttp%253A%252F%252Fgimg0.baidu.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1668824917%26t%3D287ed81b8be205074eb331a279ed95dc&rpstart=0&rpnum=0&adpicid=0&nojc=undefined&dyTabStr=MCwyLDMsMSw2LDUsNCw3LDgsOQ%3D%3D";
Object[][] soureData = {
{"签名", "", "签名", ""},
{"地址", "xxxxx"},
{"确认人", "", "图片", ""},
{"备注", "这是备注"}
};
PdfPTable table4 = new PdfPTable(widths);
table4.setHorizontalAlignment(Element.ALIGN_LEFT);
//table数据填充
for (int i = 0; i < soureData.length; i++) {
for (int j = 0; j < soureData[i].length; j++) {
//选好cell处理数据
PdfPCell pdfCell = new PdfPCell();
setTableStyle(table4, pdfCell);
//合并单元格
if (i == 1 && (j == 1)) {
pdfCell.setColspan(3);
}
if (i == 1 && j > 1) {
continue;
}
if (i == 3 && (j == 1)) {
pdfCell.setColspan(3);
}
if (i == 3 && j > 1) {
continue;
}
if (i == 0 && (j == 1 || j == 3)) {
addImageToPdf(pdfCell, imgUrl);
table4.addCell(pdfCell);
continue;
}
if (i == 2 && (j == 1 || j == 3)) {
addImageToPdf(pdfCell, imgUrl2);
table4.addCell(pdfCell);
continue;
}
Paragraph paragraph = new Paragraph(String.valueOf(soureData[i][j]), getPdfChineseFont(8));
pdfCell.setPhrase(paragraph);
table4.addCell(pdfCell);
}
}
document.add(table4);
}
//插入图片
private static void addImageToPdf(PdfPCell pdfCell, String imageUrl) throws Exception {
byte[] remote;
//读文件流
if (imageUrl.contains("https")) {
remote = FileUtil.getFromRemote(imageUrl);
} else {
remote = FileUtil.getFromRemote(imageUrl);
}
Jpeg jpeg = new Jpeg(remote);
pdfCell.setImage(jpeg);
pdfCell.setFixedHeight(20);
}
这样文件就能生成了
4、实现效果图
ps:样式需要进一步调整
二、vue html2Canvas+jspdf
1、安装vue依赖
npm install --save html2canvas,jspdf
2、封装工具js
htmlToPdf.js
// 导出页面为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
install(Vue, options) {
Vue.prototype.getPdf = function() {
const title = this.htmlTitle;
const scale = 2;
html2Canvas(document.querySelector('#pdfDom'), {
allowTaint: true, // 开启跨域
scale // 提升画面质量,但是会增加文件大小
}).then(function(canvas) {
const contentWidth = canvas.width / scale;
const contentHeight = canvas.height / scale;
const PDF = new JsPDF('', 'pt', [contentWidth, contentHeight]);
const pageData = canvas.toDataURL('image/jpeg', 1.0);
PDF.addImage(pageData, 'JPEG', 0, 0, contentWidth, contentHeight);
PDF.save(title + '.pdf');
})
}
}
}
3、实际调用
html
内容
点击下载
4、实现效果
最终样式需要自己慢慢调整