利用ItextPdf、core-renderer-R8 来生成PDF
来源:互联网 发布:java快速入门 pdf 编辑:程序博客网 时间:2024/06/04 21:56
来源:http://blog.csdn.net/jessonlv/article/details/36657093。
目录(?)[+]
最近由于工作上的需要,需要做一个简历产品的下载功能,而下载的形式要去为PDF,内容要求为整个简历的内容,而且格式上要求和简历的格式排版时一致的!前期调研、开发,最后测试上线,差不多花了7天的时间,当然,期间主要完成了主体功能,现在的话,该功能已经相当完善。下面,我主要是总结下我在这个开发的过程中遇到的问题和总结的心得,希望能帮组有这方面需要的人。
原创文章,转载请注明出处:http://blog.csdn.net/jessonlv
前期调研
前期调研的时候,在网上看了很多关于转pdf的相关文章和技术框架,详细的我不想在此一一赘述,总体给我的感觉就是,第一:国外的相关技术框架做的就是好,关于这方面的,基本都是国外的技术,最多也就是国内牛人改改源码,来适应中文等相关的本土化需要。第二:国内有关生产pdf的需求一般都很简单,要么就是简单文本,复杂的最多也就是相关报表等,基本么有自己想要实现的那么复杂的内容、排版。尤其是生成的内容要和也也面上的内容完全一致,样式排版完全一致!
需求和思路
具体需求就是:
1、产品是一个简历产品,简历上展示的所有数据都是通过动态获取的。
2、要求内容一致,并保持样式排版一致!
首先大家可以看下我们这个产品的下载功能的应用,网址:www.mojianli.com 右上角的下载功能。
思路
大体思路:取出简历所有数据-->通过freemarker生成静态页面-->将html静态页面转换成PDF
这样的思路主要是保证pdf的样式要和页面样式一致。
1、首先通过相关功能接口,取出这个简历的所有数据。
2、通过freemarker排版输出的html静态页面。静态页面的样式决定了生成的pdf的样式。
3、读取html静态页面,转换成pdf。
4、将pdf输出在浏览器,实现下载功能。
开发过程
第一步:取出相关简历的所有数据
这个是和项目相关的,就不再此赘述,换成你自己想要生成的pdf内容即可。
第二步:通过freemarker生成静态页面。
首先,利用了freemarker框架,对此框架不熟悉的请自行学习,本问的重点是生成pdf,为了让大家明白此功能的应用场景,所有写了很多,但用到的pdf之外的相关技术,请大家自行学习。
freemarker模板代码:
[java] view plain copy
- <#assign freemarkerTool= "com.shengao.mojianli.util.FreemarkerTool"?new()>
- <html>
- <head>
- <title>mojianli</title>
- <style>
- @font-face {
- font-family: 'Microsoft YaHei';
- font-family: 'Arial';
- }
- html, body, p {
- margin: 0;
- padding: 0;
- }
- span {
- line-height: 1px;
- }
- body {
- font-family: 'Microsoft YaHei';
- font-size: 11px;
- color: #666666;
- }
- .wrapper {
- width: 900px;
- margin: 0 auto;
- }
- .block {
- margin-top: 20px;//+2
- }
- .align-center {
- text-align: center;
- margin-left: 252px;
- width: 200px;
- }
- #name {
- font-size: 25px;
- margin-top: 0px;
- color: #333333;
- margin-bottom: 0;
- }
- #phone {
- font-size: 12px;
- margin-top: 12px;
- font-family: "Arial";
- }
- #email {
- font-size: 11px;
- margin-top: 4px;
- font-family: "Arial";
- }
- .timestamp {
- display: inline-block;
- width: 110px;
- }
- .title {
- font-size: 13px;
- }
- .simple-module {
- margin-bottom: 10px;
- font-size: 11px;
- }
- .simple-module-item{
- font-size: 11px;
- margin-right: 16px;
- }
- .simple-item {
- font-size: 11px;
- margin-right: 16px;
- }
- .item_thing {
- font-size: 11px;
- margin-right: 6px;
- line-height: 18px;
- }
- .label {
- background: #666;
- border-radius: 1px;
- color: white;
- font-size: 7px;
- position: relative;
- top: -1px;
- line-height: 7px;
- }
- .product {
- margin-left: 150px;
- margin-bottom: 5px;
- margin-top: 4px;
- width:750px;
- }
- .capacity-block {
- margin-left: 22px;
- }
- .things {
- padding-left: 12px;
- margin-top: 5px;
- background: url(img/dot.png) left top no-repeat;
- }
- .tag {
- background: #333333;
- border-radius: 1px;
- color: white;
- font-size: 11px;
- padding: 0 1px 1px 1px;
- margin-right: 4px;
- border-radius: 1px;
- }
- .enterprise{
- margin-bottom: 9px;
- }
- .enterprise .simple-item {
- margin-bottom: 5px;
- }
- .capacity-group {
- margin-top: 5px;
- width: 520px;
- }
- .paragraph {
- line-height: 16px;
- font-size: 11px;
- margin-bottom: 10px;
- width: 700px;
- }
- .h-seperator {
- border-color: #666;
- margin-top: 7px;
- height: 0;
- border-top: none;
- border-bottom: 1px solid;
- margin-bottom: 6px;
- }
- .company,.department,.title{
- color: #333;
- }
- </style>
- </head>
- <body>
- <#escape x as x!""></#escape>
- <div class="wrapper">
- <div class="block align-center" id="contact">
- <p id="name">${name}</p>
- <p id="phone">${phone}</p>
- <p id="email">${email}</p>
- </div>
- <div class="block" id="education">
- <span class="title">${exp}</span>
- <div class="h-seperator"></div>
- <#list education as education>
- <p class="simple-module">
- <span class="timestamp simple-module-item">${education.start_date} ~ ${education.end_date}</span>
- <span class="simple-module-item"><#if education.university??>${education.university}</#if></span>
- <span class="simple-module-item"><#if education.colleges??>${education.colleges}</#if> · <#if education.major??>${education.major}</#if></span>
- <span class="simple-module-item"><#if education.degree??>${education.degree}</#if></span>
- <span class="simple-module-item"><#if education.explain??>${education.explain}</#if></span>
- </p>
- </#list>
- </div>
- <!--under-->
- <!--割一割-->
- <div class="block" id="experience">
- <span class="title">${project}</span>
- <div class="h-seperator"></div>
- <!--项目模板代码开始-->
- <!--项目经历开始-->
- <#list experience as experiences>
- <div class="enterprise">
- <span class="timestamp simple-item">${experiences.experience.start_date} ~ ${experiences.experience.end_date}</span>
- <span class="simple-item company">${experiences.experience.company}</span>
- <span class="simple-item department">${experiences.experience.department}</span>
- <span class="simple-item title">${experiences.experience.title}</span>
- <!--项目名称开始-->
- <#list experiences.projects as projects>
- <div class="product">
- <span class="simple-item">${projects.project.name}</span>
- <span class="simple-item">${projects.project.phase}</span>
- <span class="simple-item">${projects.project.core_goal}</span>
- <!--标签、事情开始-->
- <#list projects.tags as tags>
- <div class="capacity-block">
- <div class="capacity-group">
- <!--标签开始-->
- <#list tags.tags as tag>
- <span class="tag">${tag.base_tag_name}</span>
- </#list>
- <!--标签结束-->
- <!--事情开始-->
- <#list tags.items as item>
- <div class="things">
- <#list item.labels as label>
- <span class="label">${label.base_label_name}</span>
- <span class="item_thing">${label.content}</span>
- </#list>
- </div>
- </#list>
- <!--事情结束-->
- </div>
- </div>
- </#list>
- <!--标签、事情结束-->
- </div>
- </#list>
- <!--项目名称结束-->
- </div>
- </#list>
- <!--项目名称结束-->
- <!--项目模板代码结束-->
- </div>
- <!--割一割-->
- <div class="block" id="honor">
- <span class="title">${awards}</span>
- <div class="h-seperator"></div>
- <#list awardses as awardses>
- <p class="simple-module">
- <span class="simple-item timestamp">${awardses.start_date} ~ ${awardses.end_date}</span>
- <span class="simple-item"><#if awardses.name??>${awardses.name}</#if></span>
- <span class="simple-item"><#if awardses.level??>${awardses.level}</#if></span>
- <span class="simple-item"><#if awardses.rank??>${awardses.rank}</#if></span>
- <span class="simple-item"><#if awardses.number??>${awardses.number}</#if></span>
- </p>
- </#list>
- </div>
- <div class="block" id="evaluation">
- <span class="title">${evaluate}</span>
- <div class="h-seperator"></div>
- <#list evaluates as evaluates>
- <p class="paragraph">${freemarkerTool(evaluates.content)}</p>
- </#list>
- </div>
- </div>
- </body>
- </html>
模板相关的数据填充,调用java方法的做法等,网上很多,我也是现学现用的。
利用此模板生成的静态页面的样式,就是你想要的pdf的样式。
然后是读取此模板,生成html页面的代码:
[java] view plain copy
- @RequestMapping(value = "/createPdf.s", method = {RequestMethod.POST,RequestMethod.GET})
- public void getAllResumeInfoById(HttpServletRequest request, HttpServletResponse response,
- @RequestParam(value="id", required = true) Long id) {
- String perName = "";
- String positionName = "";
- long resumeId = id;
- //获取所有的数据
- //个人基本信息
- ResumeInfoBean resumeInfo = new ResumeInfoBean();
- //教育经历
- List<EducationBean> eduList = new ArrayList<EducationBean>();
- //获奖经历
- List<AwardsBean> awardsList = new ArrayList<AwardsBean>();
- //个人评价
- List<EvaluateBean> evaList = new ArrayList<EvaluateBean>();
- //项目经历
- List<PdfExperience> pdfExperience = new ArrayList<PdfExperience>();
- try {
- Map<String, Object> map = resumeInfoService.getAllResumeInfoById(id);
- resumeInfo = (ResumeInfoBean)map.get("resumeInfo");
- eduList = (List<EducationBean>)map.get("education");
- awardsList = (List<AwardsBean>)map.get("awards");
- evaList = (List<EvaluateBean>)map.get("evaluates");
- pdfExperience = (List<PdfExperience>)map.get("experiences");
- System.out.println("finish...pdfExperience.size=="+pdfExperience.size());
- } catch (Exception e) {
- log.warn(e);
- JsonUtil.errorToClient(response, 400, e.getMessage());
- return;
- }
- //工程路径
- String path = request.getSession().getServletContext().getRealPath("/");
- try {
- Configuration cfg = new Configuration();
- cfg.setDirectoryForTemplateLoading(new File(getPath(request,response)));
- cfg.setObjectWrapper(new DefaultObjectWrapper());
- cfg.setDefaultEncoding("UTF-8"); //这个一定要设置,不然在生成的页面中会乱码
- //设置对象包装器
- cfg.setObjectWrapper(new DefaultObjectWrapper());
- //设计异常处理器
- cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
- //准备魔简历数据
- Map<String, Object> ResumeMap = new HashMap<String, Object>();
- //头部信息bean对象
- String name = resumeInfo.getName();
- perName = name;
- positionName = resumeInfo.getBase_position_name();
- String phone = resumeInfo.getMobile();
- String email = resumeInfo.getEmail();
- ResumeMap.put("name",name);
- ResumeMap.put("phone",phone);
- ResumeMap.put("email",email);
- //定义四个模块标题
- ResumeMap.put("exp","教育经历");
- ResumeMap.put("project","项目经历");
- ResumeMap.put("awards","获奖经历");
- ResumeMap.put("evaluate","个人评价");
- //封装教育经历对象数据
- ResumeMap.put("education", eduList);
- String streducationlist = JsonUtil.list2json(eduList);
- //封装项目经历数据
- ResumeMap.put("experience", pdfExperience);
- String strEx= JsonUtil.list2json(pdfExperience);
- System.out.print(strEx);
- //封装获奖经历数据
- ResumeMap.put("awardses",awardsList);
- String strawardsList = JsonUtil.list2json(awardsList);
- //封装个人评价数据
- ResumeMap.put("evaluates",evaList);
- String strevaList = JsonUtil.list2json(evaList);
- //获取指定模板文件
- Template template = cfg.getTemplate("mojianli.ftl");
- //控制台打印
- template.process(ResumeMap, new PrintWriter(System.out));
- //定义输入文件,默认生成在工程根目录
- String s = getPath(request,response);
- path = s+id+"_mojianli.html";
- Writer out = new OutputStreamWriter(new FileOutputStream(path),"UTF-8");
- //最后开始生成
- template.process(ResumeMap, out);
- System.out.println("create the html successful!!!"+"path="+request.getSession().getServletContext().getRealPath("/"));
- }catch (Exception e){
- e.printStackTrace();
- jsonObjOutPut.clear();
- jsonObjOutPut = JsonUtil.createJsonObject(MSG.STATUS_RESPONSE_FAIL_201, MSG.MSG_RESPONSE_FAIL_201);
- stringOutPutData = JsonUtil.object2json(jsonObjOutPut);
- JsonUtil.jsonStringToClient(response,stringOutPutData);
- }
- boolean boo = false;
- try {
- boo = html2Pdf(request,response,perName,resumeId,positionName);
- }catch (Exception e){
- e.printStackTrace();
- jsonObjOutPut.clear();
- jsonObjOutPut = JsonUtil.createJsonObject(MSG.STATUS_RESPONSE_FAIL_201, MSG.MSG_RESPONSE_FAIL_201);
- stringOutPutData = JsonUtil.object2json(jsonObjOutPut);
- JsonUtil.jsonStringToClient(response,stringOutPutData);
- }
- }
前半段关于数据的封装等的代码可以不管,填上自己的数据就行了。
生成页面有就是读取相关页面,并生成pdf的代码
[java] view plain copy
- //html转成pdf
- private boolean html2Pdf(HttpServletRequest request,HttpServletResponse response,String name,long id,String postionName) throws IOException, DocumentException, ParserConfigurationException {
- boolean bl = false;
- //工程路径
- /*String separator = File.separator;
- String root = request.getSession().getServletContext().getRealPath("");
- String path = root+separator+"WEB-INF"+separator+"resources"+name+"_"+id+"_mojianli.html";*/
- String path = getPath(request,response)+id+"_mojianli.html";
- //获取已经生成的html页面的路径
- //String path = "F:\\tomcat_myeclipse\\webapps\\mojianli\\WEB-INF\\resources\\mojianli.html";
- //读取html
- FileInputStream fis =new FileInputStream(path);
- StringWriter writers = new StringWriter();
- InputStreamReader isr = null;
- String string = null;
- //此处将io流转换成String
- try {
- isr = new InputStreamReader(fis,"utf-8");//包装基础输入流且指定编码方式
- //将输入流写入输出流
- char[] buffer = new char[2048];
- int n = 0;
- while (-1 != (n = isr.read(buffer))) {
- writers.write(buffer, 0, n);
- }
- }catch (Exception e){
- e.printStackTrace();
- } finally {
- if (isr != null)
- try {
- isr.close();
- } catch (IOException e) {
- e.printStackTrace();
- jsonObjOutPut.clear();
- jsonObjOutPut = JsonUtil.createJsonObject(MSG.STATUS_RESPONSE_FAIL_201, MSG.MSG_RESPONSE_FAIL_201);
- stringOutPutData = JsonUtil.object2json(jsonObjOutPut);
- JsonUtil.jsonStringToClient(response,stringOutPutData);
- }
- }
- if (writers!=null){
- string = writers.toString();
- }
- System.out.print(string);
- //利用renderer来准备数据
- ITextRenderer renderer = new ITextRenderer();
- ITextFontResolver fontResolver = renderer.getFontResolver();
- //设置创建PDF的时候要用的字体,此字体必须要和简历模板的字体保持一致!!
- fontResolver.addFont(getPath(request, response)+"msyh.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
- fontResolver.addFont(getPath(request, response)+"arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
- //get font family name
- BaseFont font = null;
- BaseFont font2 = null;
- try {
- font = BaseFont.createFont(getPath(request, response)+"msyh.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
- font2 = BaseFont.createFont(getPath(request, response)+"arial.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
- } catch (DocumentException e) {
- e.printStackTrace();
- jsonObjOutPut.clear();
- jsonObjOutPut = JsonUtil.createJsonObject(MSG.STATUS_RESPONSE_FAIL_201, MSG.MSG_RESPONSE_FAIL_201);
- stringOutPutData = JsonUtil.object2json(jsonObjOutPut);
- JsonUtil.jsonStringToClient(response,stringOutPutData);
- }
- //fontFamilyName‘s value is the key for font-family
- String fontFamilyName = TrueTypeUtil.getFamilyName(font2);
- System.out.println("fontFamilyName222="+fontFamilyName);
- //设置pdf内容!!
- renderer.setDocumentFromString(string);
- //设置图片的绝对路径
- renderer.getSharedContext().setBaseURL("file:"+getPath(request,response)+"\\img");
- System.out.println(getPath(request,response)+"img");
- renderer.layout();
- //create the pdf
- //String pdfPath = path+"WEB-INF\\resources\\"+name+"_mojianli.pdf";
- String pdfPath = getPath(request, response)+id+"_mojianli.pdf";
- FileOutputStream outputStream = new FileOutputStream(pdfPath);//文件输出根目录下
- renderer.createPDF(outputStream);
- //Finishing up
- //renderer.finishPDF();
- System.out.println("created the pdf !!");
- //下载
- try{
- //downloadPdf(response,request,name,outputStream);
- downLoadPdf(request,response,name,id,postionName);
- }catch (Exception e ){
- e.printStackTrace();
- }
- bl = true;
- return bl;
- }
这里需要注意的两点是:1、设置中文字体,以及中文字体文件的引用2、引用图片的问题。 仔细看代码注释,上面都有!
生成pdf以后,就是推送到浏览器的问题:
[java] view plain copy
- public void downLoadPdf(HttpServletRequest request, HttpServletResponse response,String name,long id,String postionName) {
- try {
- String separator = File.separator;
- String root = request.getSession().getServletContext().getRealPath("");
- String filePath = root+separator+"WEB-INF"+separator+"resources";
- String headerName = new String(name.getBytes("utf-8"),"iso8859_1");//解决下载文件中文标题乱码问题
- String postion = new String(postionName.getBytes("utf-8"),"iso8859_1");
- response.setCharacterEncoding("UTF-8");
- response.setContentType("application/pdf");
- response.setHeader("Content-Disposition", "attachment; filename="+headerName+"-"+postion+".pdf");
- OutputStream outputStream = response.getOutputStream();
- InputStream inputStream = new FileInputStream(filePath + separator+id+"_mojianli.pdf");
- byte[] buffer = new byte[1024];
- int i = -1;
- while ((i = inputStream.read(buffer)) != -1)
- {
- outputStream.write(buffer, 0, i);
- }
- outputStream.flush();
- //outputStream.close();
- inputStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- log.warn(e);
- JsonUtil.errorToClient(response, 400, e.getMessage());
- return;
- }
- }
至此,以上总体的代码大概是这样,需要的人,可以多看看,如果有什么问题,欢迎随时私信、留言等交流。
阅读全文
0 0
- 利用ItextPdf、core-renderer-R8 来生成PDF
- 利用ItextPdf、core-renderer-R8 来生成PDF
- itextPDF生成PDF
- 用itextpdf生成水印来代替pdf的替换问题
- pdf文档的生成利用itextpdf jar包 二维码生成利用goole zing包 jar包可以在网上收
- 使用html2canvas截屏,利用itextpdf转为pdf保存到数据库
- java-pdf-itext7、itextpdf 生成pdf 文档,使用pdf模板生成(支持中文字体)
- itextpdf输出PDF笔记
- 使用itextpdf操作pdf
- 如何利用Crystal Report程序来生成PDF版本?(
- 如何利用Crystal Report程序来生成PDF版本
- 【JAVA生成PDF】利用模板生成PDF
- java 使用itextpdf.jar和itext-asian.jar根据pdf模板填写数据后生成一个新的pdf文件
- 利用iText生成PDF文档
- 利用PDFLib生成PDF文档
- 利用iText生成PDF报表
- 利用Django生成PDF文档
- 利用PDFLib生成PDF文档
- Html中的document对象和window对象
- 2.数据完整性
- JSP技术
- Win7设置VPN连接
- JVM相关知识点
- 利用ItextPdf、core-renderer-R8 来生成PDF
- 单例设计模式----懒汉式
- CSS 下拉菜单
- ajax 后台取不到form表单post传递的值,get可以取到
- 初识c#---StringBuilder和集合
- 3.数据库基本操作
- 小白记录Linux常用命令
- windows 消息
- Linux下执行useradd命令添加用户时提示:"command not found"