利用velocity + itextpdf 实现动态html转p
2018-10-30 本文已影响0人
MyIreland
1. 书写html排版(你想要导出的pdf的样式模板),注意这边写html不能使用到几个css样式属性(position,folat,font等)具体有哪些自己写了就清楚了,因为itext转pdf的时候这几种样式不能识别。
2.写完html样式排版后把他改写成velocity模板引擎的.vm文件,使用velocity的语法填充该.vm文件
image.png3. 初始化模板引擎配置
public class VelocityHelper {
private static VelocityEngine ve = new VelocityEngine();
private static void initVelocityEngine(String path){
ve.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, path);// 这是模板所在路径
ve.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
ve.setProperty(Velocity.INPUT_ENCODING, "UTF-8");//指定编码格式,避免生成模板就造成乱码,影响到转pdf后的文件
ve.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
ve.init();
}
/**
* 得到模板引擎渲染数据后的文件流
* @param templatePath 模板所在位置
* @param out 得到输出流
* @param paramMap 模板数据k-y
* @param dataList 模板数据集合
* @return 流
*/
public static Writer getWriterByTemplate(String templatePath, OutputStream out, Map paramMap, List dataList){
File file = new File(templatePath);
String path = file.getParent();
initVelocityEngine(path);
Template template = ve.getTemplate(file.getName(), "utf-8");
VelocityContext ctx = new VelocityContext();
ctx.put("paramMap", paramMap);
ctx.put("dataList", dataList);
ctx.put("dateformat", new DateUtil());
Writer bw;
if(null != out)
bw = new BufferedWriter(new OutputStreamWriter(out));
else
bw = new StringWriter();
template.merge(ctx, bw);
return bw;
}
}
4. 得到流对象先放着,因为itext的方法parseXHtml查看源码
/**
* @param writer 备用写对象
* @param doc 创建的document对象
* @param in 转pdf的输入流文件
* @param charset 编码格式
* @throws IOException if the {@link InputStream} could not be read.
*/
public void parseXHtml(final PdfWriter writer, final Document doc, final InputStream in, final Charset charset) throws IOException {
parseXHtml(writer,doc,in, XMLWorkerHelper.class.getResourceAsStream("/default.css"), charset);
}
/**
* @param writer the writer to use
* @param doc the document to use
* @param in the {@link InputStream} of the XHTML source.
* @param in the {@link CssFiles} of the css files.
* @param charset the charset to use
* @throws IOException if the {@link InputStream} could not be read.
*/
public void parseXHtml(final PdfWriter writer, final Document doc, final InputStream in, final InputStream inCssFile, final Charset charset, final FontProvider fontProvider) throws IOException {
CssFilesImpl cssFiles = new CssFilesImpl();
if (inCssFile != null)
cssFiles.add(getCSS(inCssFile));
else
cssFiles.add(getDefaultCSS());
StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
HtmlPipelineContext hpc = new HtmlPipelineContext(new CssAppliersImpl(fontProvider));
hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(getDefaultTagProcessorFactory());
HtmlPipeline htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(doc, writer));
Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
XMLWorker worker = new XMLWorker(pipeline, true);
XMLParser p = new XMLParser(true, worker, charset);
if (charset != null)
p.parse(in, charset);
else
p.parse(in);
}
所以这边我们要准备(PdfWriter对象,document对象,html流文件,编码)四个元素对象。所以第五步准备原料
5.准备元素
- 准备Document和PdfWriter
#都是itextpdf包的对象
Document document = new Document();
PdfWriter pdfWriter = PdfWriter.getInstance(document, outputStream);// outputStream可以自己指定位置或者是HttpServletResponse得到的输出流
pdfWriter.setTagged();
document.open();
- 准备html输入流文件,因为第三步得到的writer对象,我们可以进一步把他转换成输入流
Writer writer = VelocityHelper.getWriterByTemplate(path, null, map, dtoList);
// log.info("转换的文本内容为===============" + writer.toString());
//输出转输入流
InputStream in = new ByteArrayInputStream(writer.toString().getBytes(Charset.defaultCharset()));
使用完之后记得关闭流剩下编码直接指定编码就好了(Charset.forName("UTF-8"))
6.调用方法
XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document, inputStream, Charset.forName("UTF-8"));
如果文件带中文的话解决中文不显示问题要使用这个方法
//解决中文不显示问题
XMLWorkerFontProvider fontProvider = getFontProvider();
XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document, inputStream,
null, Charset.forName("UTF-8"), fontProvider);
getFontProvider方法如下:
private static XMLWorkerFontProvider getFontProvider(){
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider() {
@Override
public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color) {
//你的字体文件的位置
//这里把所有字体都设置为宋体了,可以根据fontname的值设置字体
String yaHeiFontName = getClass().getClassLoader().getResource("font/msyh.ttc").toString();//系统文字文件地址位置,我这边直接放在项目里面了
yaHeiFontName += ",1";//如果文件是.ttc结尾文件要加上这个,如果不是可以去掉
Font yaHeiFont;
Font font = null;
try {
font = new Font(com.itextpdf.text.pdf.BaseFont.createFont(yaHeiFontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED));
font.setStyle(style);
font.setColor(color);
if (size>0){
font.setSize(size);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return font;
}
};
return fontProvider;
}
7.关闭文档对象即可输出流对象
document.close();
然后后面的样式是怎样的你们自己确定调整就好了