1.pom依赖
<!--pdf生成 start--> <!-- jfianl 依赖 --> <!-- https://mvnrepository.com/artifact/com.jfinal/jfinal --> <dependency> <groupId>com.jfinal</groupId> <artifactId>jfinal</artifactId> <version>3.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker 5.iText-Html-Freemarker渲染--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency> <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.11</version> </dependency> <!-- https://mvnrepository.com/artifact/com.itextpdf.tool/xmlworker iText-Html渲染--> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.11</version> </dependency> <!-- https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-pdf 6.Flying Saucer-CSS高级特性支持--> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf</artifactId> <version>9.1.5</version> </dependency> <!-- https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-pdf-itext5 6.Flying Saucer-CSS高级特性支持--> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf-itext5</artifactId> <version>9.1.5</version> </dependency> <!--pdf生成 end-->
2,接口文件
package com.rjj.wlqq.pdf; import java.io.OutputStream; import java.util.Map; /** * 生成pdf的接口 * 生成pdf都需要把一个字符串写成pdf文件输出到指定的地方 */ public interface PDF { /** * * @param data 输入到模板的数据 * @param htmlTmp 模版的地址 * @param out 输出【这里可以是输出到文件中,也可以输出到响应中】 * @return 输出成功失败 */ boolean writeToPDF(Map<String, Object> data, String htmlTmp, OutputStream out); }
3,基本实现类
package com.rjj.wlqq.pdf; import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.tool.xml.XMLWorkerFontProvider; import com.itextpdf.tool.xml.XMLWorkerHelper; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Map; public abstract class BasePDF implements PDF{ /*字体*/ private static String FONT = "static/pdf/font/simhei.ttf"; /** * 字体这里设置了默认的,如果使用其他字体需要倒入字体,然后通过这个方法设定字体 * @param FONT */ public static void setFont(String FONT) { BasePDF.FONT = FONT; } @Override public boolean writeToPDF(Map<String, Object> data, String htmlTmp, OutputStream out) { String content = templateToString(data, htmlTmp); return write(content,out); } /** * 准备生成pdf */ private boolean write(String content, OutputStream out){ // step 1 Document document = new Document(); // step 2 PdfWriter writer = null; try { writer = PdfWriter.getInstance(document, out); } catch (DocumentException e) { e.printStackTrace(); } // step 3 document.open(); // step 4 XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS); fontImp.register(FONT); try { XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(content.getBytes()), null, StandardCharsets.UTF_8, fontImp); } catch (IOException e) { e.printStackTrace(); return false; } // step 5 document.close(); return true; } /** * 要输出的字符串模板 */ public abstract String templateToString(Map<String, Object> data, String htmlTmp); }
4,代理
package com.rjj.wlqq.pdf; import java.lang.reflect.Proxy; /** * return Proxy.newProxyInstance(target.getClass().getClassLoader(), * target.getClass().getSuperclass().getInterfaces(), * new InvocationHandler() { * @Override * public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { * Object invoke = method.invoke(target, args); * return invoke; * } * }); * @param <T> */ public class PDFProxy<T> { private T target; PDFProxy(T target){ this.target = target; } /** * target.getClass().getSuperclass().getInterfaces()这个输出pdf的方法在父类中 * @return */ public Object getInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getSuperclass().getInterfaces(), (proxy, method, args) -> method.invoke(target, args)); } }
5,工厂方法
package com.rjj.wlqq.pdf; public class PDFFactory { public static PDF getPDF(Class<?> p){ PDF pdf = null; try { pdf = (PDF)p.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } PDFProxy<PDF> pdfProxy = new PDFProxy<>(pdf); return (PDF)pdfProxy.getInstance(); } }
6,jfinal模版实现类
package com.rjj.wlqq.pdf; import com.jfinal.template.Engine; import com.jfinal.template.Template; import org.springframework.util.ResourceUtils; import java.io.FileNotFoundException; import java.util.Map; public class TemplateToPDFJfinal extends BasePDF{ private static String path; private static Engine myEngine; /** * 这里在加载配置文件的时候就加载就好了,项目中启动时候就设置这个,那么,就会一只存在,直到项目停止 * @param myEngine 模版引擎 */ public static void setEngine(Engine myEngine) { TemplateToPDFJfinal.myEngine = myEngine; } static { try { path = ResourceUtils.getURL("classpath:templates/pdf/").getPath(); } catch (FileNotFoundException e) { e.printStackTrace(); } } @Override public String templateToString(Map<String, Object> data, String htmlTmp) { //这里需要改动,因为创建了,下次可以直接获取 //Engine myEngine = Engine.create("myEngine"); if(myEngine == null){ //自动使用jfinal默认模版引擎 myEngine = Engine.use(); System.out.println("模版引擎 == 【 null 】,使用默认的!"); //throw new RuntimeException("Did not setEngine(Engine myEngine), You must setEngine(Engine myEngine) after start program !!!"); } myEngine.setDevMode(true); myEngine.setEncoding("UTF-8"); //设置模板所在路径 myEngine.setBaseTemplatePath(path); Template template = myEngine.getTemplate(htmlTmp); return template.renderToString(data); } }
7,freemarker实模版现类
package com.rjj.wlqq.pdf; import freemarker.template.Configuration; import freemarker.template.Template; import org.springframework.util.ResourceUtils; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.util.Map; public class TemplateToPDFFreemarker extends BasePDF{ private static Configuration freemarkerCfg = null; private static String path; static { freemarkerCfg =new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); try { path = ResourceUtils.getURL("classpath:templates/pdf/").getPath(); //freemarker的模板目录,下边两个设置路径方式都可以 freemarkerCfg.setDirectoryForTemplateLoading(new File(path)); } catch (IOException e) { e.printStackTrace(); } //path = "/templates/pdf"; //freemarkerCfg.setClassForTemplateLoading(TemplateToPDFFreemarker.class,"/templates/pdf"); } @Override public String templateToString(Map<String, Object> data, String htmlTmp) { Writer out = new StringWriter(); try { // 获取模板,并设置编码方式 Template template = freemarkerCfg.getTemplate(htmlTmp,"UTF-8"); //template.setEncoding("UTF-8"); // 合并数据模型与模板 //将合并后的数据和模板写入到流中,这里使用的字符流 template.process(data, out); out.flush(); return out.toString(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException ex) { ex.printStackTrace(); } } return ""; } }
8,velocity模版实现类
package com.rjj.wlqq.pdf; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import java.io.StringWriter; import java.util.Map; public class TemplateToPDFVelocity extends BasePDF{ private static String path = "templates/pdf/"; private static VelocityEngine ve = new VelocityEngine(); static { ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); ve.init(); } @Override public String templateToString(Map<String, Object> data, String htmlTmp) { Template t = ve.getTemplate(path + htmlTmp); VelocityContext ctx = new VelocityContext(data); StringWriter sw = new StringWriter(); t.merge(ctx, sw); return sw.toString(); } }
9,测试类
private static final String DESTJfinal = "target/pdfJfinal.pdf"; private static final String DESTFreemarker = "target/pdfFreemarker.pdf"; private static final String DESTVelocity = "target/pdfVelocity.pdf"; public static void main(String[] args) throws FileNotFoundException { Engine myEngine = Engine.create("myEngine"); TemplateToPDFJfinal.setEngine(myEngine); test("templateJfinal2.html", TemplateToPDFJfinal.class,new FileOutputStream(new File(DESTJfinal))); //test("templateFreemarker.html",TemplateToPDFFreemarker.class,new FileOutputStream(new File(DESTFreemarker))); //test("templateVelocity.html",TemplateToPDFVelocity.class,new FileOutputStream(new File(DESTVelocity))); } /** * 简单写个方法测试 生成pdf * * @param templateName 模板名称 * @param pdfClass 使用的是哪个实现类 */ private static void test(String templateName, Class<?> pdfClass, OutputStream outputStream) { String FONT = "static/pdf/font/simhei.ttf"; BasePDF.setFont(FONT); PDF pdf = PDFFactory.getPDF(pdfClass); Map<String, Object> map = new HashMap<>(); map.put("name", "中国社会主义价值核心观"); map.put("imgUrl", "/Users/renjianjun/Downloads/我的/斗图/mao.jpg"); boolean b = pdf.writeToPDF(map, templateName, outputStream); System.out.println("输出结果:" + b); }
10,java目录结构
11,所需要的静态文件【字体】需要自己下载
链接: https://pan.baidu.com/s/17Y_h-pSP1HuLK-8-tAskQA 密码: 0n67
12,html模版文件
jfinal
<!--要求比较严格,html中的标签必须有开始结束标签, 但标签需要加 / 比如:<meta charset="UTF-8" /> --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>jfinal模板使用</title> <style> body { /*如果使用的字体没有,那么中文不会显示*/ font-family: SimHei,serif; } .pos { position: absolute; left: 200px; top: 5px; width: 200px; font-size: 10px; } .table-one { width: 700px; text-align: center; border-collapse: collapse; } /*细调试*/ .title-big{ font-size: 20px; } .title-middle{ font-size: 16px; } .title-small{ font-size: 13.33px; } .red{ background-color: #E11B22; } .black{ background-color: black; color: white; } </style> </head> <body> <div class="pos"> <!--图片--> <table class="table-one"> <tr> <td colspan="5"> <img alt="tp" style=" 153px;margin-left: 300px" src="#(imgUrl)"/> <!--图片路径自己写,根据自己的实际路径写--> </td> </tr> <tr> <td colspan="5"> jfinal模版使用#取值 #(name) </td> </tr> </table> <table border="1" class="table-one"> <tr> <td colspan="5" class="title-big black">20px标题</td> </tr> <tr class="title-middle"> <td class="red" rowspan="3"> <table> <tr><td>红色</td></tr> <tr><td>红色</td></tr> <tr><td>红色</td></tr> </table> </td> <td colspan="4">数据</td> </tr> <tr class="title-middle"> <!-- <td class="red">红色</td>--> <td colspan="4">数据</td> </tr> <tr class="title-middle"> <!-- <td class="red">红色</td>--> <td colspan="4">数据</td> </tr> <tr class="title-middle black"> <td colspan="5">16px二级标题</td> </tr> <tr class="title-small"> <td>13px标题</td> <td>13px数据</td> <td>13px数据</td> <td>13px数据</td> <td>13px数据</td> </tr> <tr class="title-small"> <td>13px标题</td> <td>13px数据</td> <td>13px数据</td> <td>13px数据</td> <td>13px数据</td> </tr> <tr class="title-small"> <td>13px标题</td> <td>13px数据</td> <td colspan="2">13px数据</td> <td>13px数据</td> </tr> <tr> <td class="title-middle">16px标题</td> <td colspan="4" class="title-small">13px数据</td> </tr> <tr> <td class="title-middle">16px标题</td> <td colspan="4" class="title-small">13px数据</td> </tr> <tr> <td class="title-middle">16px标题</td> <td colspan="4" class="title-small">13px数据</td> </tr> <tr> <td class="title-middle">16px标题</td> <td colspan="4" class="title-small">13px数据</td> </tr> <tr> <td class="title-middle">16px标题</td> <td colspan="4" class="title-small">13px数据</td> </tr> </table> </div> </body> </html>
freemarker
<!--要求比较严格,html中的标签必须有开始结束标签, 但标签需要加 / 比如:<meta charset="UTF-8" /> --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>jfinal模板使用</title> <style> body{ font-family:SimHei; } .color{ color: green; } .pos{ position:absolute; left:200px; top:5px; width: 200px; font-size: 10px; } </style> </head> <body> <div class="blue pos"> 你好,${name} freemarker </div> </body> </html>
volecity
<!--要求比较严格,html中的标签必须有开始结束标签, 但标签需要加 / 比如:<meta charset="UTF-8" /> --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>jfinal模板使用</title> <style> body{ font-family:SimHei; } .color{ color: green; } .pos{ position:absolute; left:200px; top:5px; width: 200px; font-size: 14px; } </style> </head> <body> <div class="blue pos"> 你好,${name} velocity </div> </body> </html>
13,jfinal的文件输出展示