html转化成PDF
本文主要介绍了html转化PDF的方法以及代码,文章有点长请耐心阅读。
- jar 包准备
core-renderer.jar
httpmime-4.5.jar
itext-2.0.8.jar
itextpdf-5.0.6.jar
zxing-core.jar
- 字体准备
arialuni.ttf
msyh.ttc
msyhbd.ttc
simfang.ttf
simhei.ttf
simsun.ttf
- 上代码
@RequestMapping(value = "/xyxx/reportFileGenerate.jspx", method = RequestMethod.GET)
@ResponseBody
public RestResult reportFileGenerate1(String id, String code, String name, HttpServletRequest request, HttpServletResponse response, @RequestParam Map<String, Object> parameterMap, ModelMap model) throws Exception {
String tempPath = Global.getConfig("temp.path");
//报告下载数量(需要查询业务,此处我随便写的)
int reportDownloadCount = 10;
Date nowDate = new Date();
//报告编号
String reportNum = DateUtils.formatDate(nowDate, "yyyyMMddHHmmss") + String.format("%06d", reportDownloadCount + 1);
//报告水印背景的字
String waterText = "我是报告";
File dfile = new File(tempPath);
if (!dfile.exists()) {
dfile.mkdirs();
}
//报告生成存放得临时本地目录
String path = tempPath + "/" + reportNum + "_1.pdf";
String path_sy = tempPath + "/" + reportNum + ".pdf";
File file = null;
Map<String, String> map = new HashMap<>();
//报告中的业务数据
//begain
map.put("siteName", "生成报告");
map.put("siteUrl", "www.xxxx.com");
map.put("reportNum", reportNum);
map.put("downloadTime", DateUtils.formatDate(nowDate, "yyyy年MM月dd日 HH:mm:ss"));
//end
//生成报告
genPerviewReport(id, code, name, "L", reportNum, "/xyxx/creditReport.jspx", path, path_sy, request, waterText, map);
file = new File(path_sy); //要下载的文件绝对路径
String filePath="";
if (file.exists()) {
//此处我把报告上传到文件服务器去(根据自己实际情况)
filePath = FileUpLoadUtils.uploadFileAndGetPath("creditReport", file, reportNum);
}
//写入下载记录(根据自身情况)
ReportDownloadRecord reportDownloadRecord = new ReportDownloadRecord();
reportDownloadRecord.setFilePath(filePath);
reportDownloadRecord.setSiteName("站点1");
reportDownloadRecord.setCode(reportNum);
insertReportDownload(reportDownloadRecord);
//生成后把报告编号信息返回前端 (原则上只要能返回可以查到报告的数据即可)
return RestResult.success().setData(reportNum);
}
/**
* 生成pdf
*
* @param id 业务数据id
* @param m010101 业务数据
* @param name 业务数据
* @param baseCredit 业务数据
* @param reportNum 报告编号
* @param reportUlr 报告地址(html页面)
* @param path 报告存放路径
* @param path_sy 报告存放路径
* @param request
* @param waterText 水印字
* @param map 报告生成需要的数据
* @return
*/
public boolean genPerviewReport(String id, String m010101, String name, String baseCredit, String reportNum, String reportUlr, String path, String path_sy, HttpServletRequest request, String waterText, Map<String, String> map) {
String tempPath = Global.getConfig("temp.path");
File destPdf = new File(path);
if (destPdf.exists()) {
destPdf.delete();
}
File waterPdf = new File(path_sy);
if (waterPdf.exists()) {
waterPdf.delete();
}
try {
destPdf.createNewFile();
waterPdf.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String rootPath = tempPath + "/";
//背景图片地址
String imgpath = this.getClass().getResource("/") + "charts/backimg1.jpg";
//获取html 地址
String url = this.getReportHtmlUrl(request, reportUlr, id, m010101, name, baseCredit, reportNum);
//生成PDF文件 信用报告
this.genReport(rootPath, url, destPdf, map);
//给pdf添加图片水印
PdfExportNew.setWaterMarkForPDF(path, path_sy, imgpath, waterText);
destPdf.delete();
return true;
}
/**
* 获取html的url
*
* @param request
* @param reportUlr
* @param m010101
* @return
*/
public String getReportHtmlUrl(HttpServletRequest request, String reportUlr, String id, String m010101, String name, String baseCredit, String reportNum) {
return Global.getConfig("whSiteDomain") + "/" + reportUlr + "?baseCredit=" + baseCredit + "&id=" + id + "&code=" + m010101 + "&reportNum=" + reportNum + "&name=" + name;
}
/**
* 生成报告
* @param rootPath
* @param url
* @param outFile
* @param map
*/
public void genReport(String rootPath, String url, File outFile, Map<String, String> map) {
String html = ReportUtils2.getHtml(url, "UTF-8");
//生成pdf
ReportUtils2.genPdf(rootPath, outFile, html);
//添加页码
pdfExportNew.addPage(rootPath, outFile, outFile, map);
}
PDF 工具
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
public class PdfExportNew extends PdfPageEventHelper {
private PdfTemplate tpl;
private BaseFont bf;
private static String fontUrl = ReportUtils2.class.getResource("/") + "charts/";
public Font fontDetail = null;
public int presentFontSize = 8;
private String siteName;
private String siteUrl;
private String downloadTime;
private String reportNum;
public void addPage(String rootPath, File destFile, File srcFile, Map<String, String> map) {
siteName = map.get("siteName");
siteUrl = map.get("siteUrl");
downloadTime = map.get("downloadTime");
reportNum = map.get("reportNum");
Document document = new Document(PageSize.A4, 20, 20, 60, 60);
PdfReader reader = null;
FileOutputStream out = null;
FileInputStream input = null;
try {
input = new FileInputStream(srcFile);
reader = new PdfReader(input);
out = new FileOutputStream(destFile);
int pageOfCurrentReaderPDF = 0;
PdfWriter writer = PdfWriter.getInstance(document, out);
writer.setPageEvent(this);
document.open();
PdfContentByte cb = writer.getDirectContent();
while (pageOfCurrentReaderPDF < reader.getNumberOfPages()) {
document.newPage();
pageOfCurrentReaderPDF++;
PdfImportedPage page = writer.getImportedPage(reader, pageOfCurrentReaderPDF);
cb.addTemplate(page, 0, 0);
}
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
if (document != null) {
document.close();
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
try {
tpl = writer.getDirectContent().createTemplate(100, 100);
bf = BaseFont.createFont(fontUrl + "simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
BaseFont englishBf = null;
// 在每页结束的时候把“第x页”信息写道模版指定位置
try {
if (bf == null) {
bf = BaseFont.createFont(fontUrl + "simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
}
englishBf = BaseFont.createFont(fontUrl + "arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
if (fontDetail == null) {
fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
int pageS = writer.getPageNumber();
if (pageS != 1) {
//页码
String foot1 = "第 " + (pageS - 1) + " 页 共 ";
Phrase footer = new Phrase(foot1, fontDetail);
float len = bf.getWidthPoint(foot1, presentFontSize);
PdfContentByte cb = writer.getDirectContent();
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);
cb.addTemplate(tpl, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20);
//页眉
String imgpath = fontUrl + "XXXXX_logo.png";
try {
Image image = Image.getInstance(imgpath);
image.setAbsolutePosition(30, document.top() + 10);
cb.beginText();
cb.setColorFill(BaseColor.RED);
cb.setFontAndSize(bf, 20);
cb.addImage(image);
cb.setTextMatrix(70, document.top() + 23);
cb.showText(siteName);
cb.endText();
} catch (IOException | DocumentException e) {
e.printStackTrace();
}
cb.beginText();
cb.setColorFill(BaseColor.BLACK);
cb.setFontAndSize(bf, 8);
cb.setTextMatrix(document.right() - 140, document.top() + 25);
cb.showText("文件编号:" + reportNum);
cb.endText();
cb.beginText();
cb.setFontAndSize(bf, 8);
cb.setTextMatrix(document.right() - 140, document.top() + 13);
cb.showText("生成时间:" + downloadTime);
cb.endText();
cb.beginText();
cb.setColorFill(BaseColor.LIGHT_GRAY);
cb.setFontAndSize(bf, 8);
cb.setTextMatrix(30, document.top());
cb.showText("--------------------------------------------------------------------------------------------------------------------------------------");
cb.endText();
cb.beginText();
cb.setColorFill(BaseColor.DARK_GRAY);
cb.setFontAndSize(englishBf, 6);
cb.setTextMatrix(73, document.top() + 13);
cb.showText(siteUrl.replace("http://", "").toUpperCase());
cb.endText();
}
}
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
// 关闭document的时候获取总页数,并把总页数按模版写道之前预留的位置
tpl.beginText();
tpl.setFontAndSize(bf, presentFontSize);
tpl.showText(Integer.toString(writer.getPageNumber() - 2) + " 页");
tpl.endText();
tpl.closePath();// sanityCheck();
}
/**
* pdf文件添加 图片水印
*
* @param sourceFilePath 源文件路径
* @param fileWaterMarkPath 水印生成文件路径
* @return
* @throws Exception
*/
public static void setWaterMarkForPDF(String sourceFilePath, String fileWaterMarkPath, String imgpath, String waterMarkText) {
PdfReader reader;
try {
reader = new PdfReader(sourceFilePath, "PDF".getBytes());
PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(fileWaterMarkPath));
Image img = Image.getInstance(imgpath);
int pageSize = reader.getNumberOfPages();
BaseFont font = BaseFont.createFont(fontUrl + "simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//开始水印
for (int i = 1; i <= pageSize; i++) {
PdfContentByte under = stamp.getUnderContent(i);
img.setAbsolutePosition(0, 0);
under.addImage(img);
// under.beginText();
// under.setColorFill(new BaseColor(229, 229, 229));
// 文字水印 字体及字号
// under.setFontAndSize(font, 38);
// 文字水印 起始位置
// under.setTextMatrix(300, 500);
// under.showTextAligned(Element.ALIGN_CENTER, waterMarkText, 300, 500, 45);
// under.endText();
}
stamp.close();// 关闭
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
import com.lowagie.text.pdf.BaseFont;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
public class ReportUtils2 {
public static String stripNonValidXMLCharacters(String in) {
StringBuffer out = new StringBuffer(); // Used to hold the output.
char current; // Used to reference the current character.
if (in == null || ("".equals(in))) {
return ""; // vacancy test.
}
for (int i = 0; i < in.length(); i++) {
current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
if (current == 0x6) {
out.append("");
}
if (
(current == 0x9) ||
(current == 0xA) ||
(current == 0xD) ||
((current >= 0x20) && (current <= 0xD7FF)) ||
((current >= 0xE000) && (current <= 0xFFFD)) ||
((current >= 0x10000) && (current <= 0x10FFFF))) {
out.append(current);
}
}
return out.toString();
}
public static InputStream getHtmlInputStream(String url, String encoding) {
String html = null;
CloseableHttpResponse response = null;
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpUriRequest request = new HttpGet(url);
response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream input = entity.getContent();
return input;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public static String getHtml(String url, String encoding) {
String html = null;
CloseableHttpResponse response = null;
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpUriRequest request = new HttpGet(url);
response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream input = entity.getContent();
try {
html = IOUtils.toString(input, encoding);
html = stripNonValidXMLCharacters(html);
} finally {
input.close();
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return html;
}
public static void genPdf(String savePath, File outFile, String html) {
OutputStream fos = null;
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
ByteArrayInputStream bais = new ByteArrayInputStream(html.getBytes("UTF-8"));
Document doc = builder.parse(bais);
ITextRenderer renderer = new ITextRenderer();
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont(ReportUtils2.class.getResource("/") + "charts/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ReportUtils2.class.getResource("/") + "charts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ReportUtils2.class.getResource("/") + "charts/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ReportUtils2.class.getResource("/") + "charts/msyh.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ReportUtils2.class.getResource("/") + "charts/msyhbd.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.getSharedContext().setReplacedElementFactory(new Base64ImgReplacedElementFactory());
renderer.getSharedContext().getTextRenderer().setSmoothingThreshold(0);
renderer.setDocument(doc, null);
fos = new FileOutputStream(outFile);
renderer.layout();
renderer.createPDF(fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.flush();
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
String html = "<!DOCTYPE html>\n" +
"<html lang=\"zh-CN\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\"/>\n" +
"</head>\n" +
"<body>\n" +
"<div>111111111111111111111111111111</div>\n" +
"</body>\n" +
"</html>";
genPdf("D:/upload_file", new File("D:/upload_file"), html);
}
/**
* 图片base64支持,把图片转换为itext自己的图片对象
* @author Administrator
*
*/
public class Base64ImgReplacedElementFactory implements ReplacedElementFactory {
/**
* 实现createReplacedElement 替换html中的Img标签
*
* @param c 上下文
* @param box 盒子
* @param uac 回调
* @param cssWidth css宽
* @param cssHeight css高
* @return ReplacedElement
*/
@Override
public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac,
int cssWidth, int cssHeight) {
Element e = box.getElement();
if (e == null) {
return null;
}
String nodeName = e.getNodeName();
// 找到img标签
if (nodeName.equals("img")) {
String attribute = e.getAttribute("src");
FSImage fsImage;
try {
// 生成itext图像
fsImage = buildImage(attribute, uac);
} catch (BadElementException e1) {
fsImage = null;
} catch (IOException e1) {
fsImage = null;
}
if (fsImage != null) {
// 对图像进行缩放
if (cssWidth != -1 || cssHeight != -1) {
fsImage.scale(cssWidth, cssHeight);
}
return new ITextImageElement(fsImage);
}
}
return null;
}
/**
* 编解码base64并生成itext图像
*/
protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException,
BadElementException {
FSImage fiImg=null;
if (srcAttr.toLowerCase().startsWith("data:image/")) {
String base64Code= srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length(),
srcAttr.length());
// 解码
byte[] decodedBytes = Base64.decode(base64Code);
fiImg= new ITextFSImage(Image.getInstance(decodedBytes));
} else {
fiImg= uac.getImageResource(srcAttr).getImage();
}
return fiImg;
}
@Override
public void reset() {}
@Override
public void remove(Element arg0) {}
@Override
public void setFormSubmissionListener(FormSubmissionListener arg0) {}
}
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Scanner;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import sun.misc.BASE64Encoder;
/**
* 二维码生成
* @author wcs
*/
public class QRCodeUtils {
/**
* 私有不可更改的变量:生成二维码图片的颜色
*/
private static final int BLACK = 0xFF000000;
private static final int WHITE = 0xFFFFFFFF;
public QRCodeUtils() {
}
/**
* 生成二维码
*
* @param QRcodeURL
* @param width
* @param height
* @return
*/
public static String creatRrCode(String QRcodeURL, int width, int height) {
BASE64Encoder encoder = new sun.misc.BASE64Encoder();
// 生成二维码a
OutputStream out = null;
ByteArrayOutputStream os = null;
byte[] bytes = null;
try {// 生成二维码
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 按照指定的宽度,高度和附加参数对字符串进行编码
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
BitMatrix bitMatrix = multiFormatWriter.encode(QRcodeURL, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = toBufferedImage(bitMatrix);
if (image != null) {
os = new ByteArrayOutputStream();
ImageIO.write(image, "png", os);
bytes = os.toByteArray();
}
} catch (WriterException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.flush();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return encoder.encodeBuffer(bytes).trim();
}
/**
* 静态方法
* BufferedImage是Image的一个子类,BufferedImage生成的图片在内存里有一个图像缓冲区,利用这个缓冲区我们可以很方便的操作这个图片,
* 通常用来做图片修改操作如大小变换、图片变灰、设置图片透明或不透明等。
*
* @param matrix 编码形式
* @return
*/
public static BufferedImage toBufferedImage(BitMatrix matrix) {
//图片的宽度和高度
int width = matrix.getWidth();
int height = matrix.getHeight();
//BufferedImage.TYPE_INT_RGB将图片变为什么颜色
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
}
}
return image;
}
/**
* 静态方法 用于生成图片
*
* @param matrix 编码形式
* @param format 图片类型
* @param file 文件(图片路径,图片名称)
* @throws IOException
*/
public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, file)) {
throw new IOException("Could not write an image of format " + format + " to " + file);
}
}
/**
* 输出
*
* @param matrix
* @param format
* @param stream
* @throws IOException
*/
public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, stream)) {
throw new IOException("Could not write an image of format " + format);
}
}
public static void main(String[] args) {
try {
System.out.println("请输入您要生成二维码的信息");
Scanner input = new Scanner(System.in);
String content = input.next();
String path = "D:/";
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 按照指定的宽度,高度和附加参数对字符串进行编码
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
//生成二维码
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400, hints);
File file1 = new File(path, "test.jpg");
// 写入文件
QRCodeUtils.writeToFile(bitMatrix, "jpg", file1);
System.out.println("二维码图片生成成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
PS : 本文适合有开发经验的人阅读,以上代码仅供参考;为了能方便加载拿到字体资源,我把字体资源和报告背景、logo放在了项目的src目录下了
作者编写不容易,把jar包以及字体资源上传到了资源下,需要下载请移步