博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用ItextPdf、core-renderer-R8 来生成PDF
阅读量:6445 次
发布时间:2019-06-23

本文共 12434 字,大约阅读时间需要 41 分钟。

最近由于工作上的需要,需要做一个简历产品的下载功能,而下载的形式要去为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模板代码:
<#assign freemarkerTool= "com.shengao.mojianli.util.FreemarkerTool"?new()>      mojianli        <#escape x as x!"">

${name}

${phone}

${email}

${exp}
<#list education as education>

${education.start_date} ~ ${education.end_date} <#if education.university??>${education.university}

<#if education.colleges??>${education.colleges}
· <#if education.major??>${education.major}
<#if education.degree??>${education.degree}
<#if education.explain??>${education.explain}

${project}
<#list experience as experiences>
${experiences.experience.start_date} ~ ${experiences.experience.end_date}
${experiences.experience.company}
${experiences.experience.department}
${experiences.experience.title}
<#list experiences.projects as projects>
${projects.project.name}
${projects.project.phase}
${projects.project.core_goal}
<#list projects.tags as tags>
<#list tags.tags as tag>
${tag.base_tag_name}
<#list tags.items as item>
<#list item.labels as label>
${label.base_label_name}
${label.content}
${awards}
<#list awardses as awardses>

${awardses.start_date} ~ ${awardses.end_date} <#if awardses.name??>${awardses.name}

<#if awardses.level??>${awardses.level}
<#if awardses.rank??>${awardses.rank}
<#if awardses.number??>${awardses.number}

${evaluate}
<#list evaluates as evaluates>

${freemarkerTool(evaluates.content)}

模板相关的数据填充,调用java方法的做法等,网上很多,我也是现学现用的。
利用此模板生成的静态页面的样式,就是你想要的pdf的样式。
然后是读取此模板,生成html页面的代码:
@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
eduList = new ArrayList
(); //获奖经历 List
awardsList = new ArrayList
(); //个人评价 List
evaList = new ArrayList
(); //项目经历 List
pdfExperience = new ArrayList
(); try { Map
map = resumeInfoService.getAllResumeInfoById(id); resumeInfo = (ResumeInfoBean)map.get("resumeInfo"); eduList = (List
)map.get("education"); awardsList = (List
)map.get("awards"); evaList = (List
)map.get("evaluates"); pdfExperience = (List
)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
ResumeMap = new HashMap
(); //头部信息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的代码
//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以后,就是推送到浏览器的问题:
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;        }    }
这里的注意点是:注意下载文件中文标题乱码问题
至此,以上总体的代码大概是这样,需要的人,可以多看看,如果有什么问题,欢迎随时私信、留言等交流。

转载于:https://www.cnblogs.com/jessonlv/p/4387980.html

你可能感兴趣的文章
zookeeper NIOServerCnxn: Too many connections from
查看>>
mysql数据库-简述
查看>>
keepalived+nginx实现双机热备
查看>>
linux远程登录ssh免密码
查看>>
Dojo学习笔记(八):Dojo布局——面板
查看>>
linux挂载ntfs
查看>>
SQLServer判断指定列的默认值是否存在,并修改默认值
查看>>
heartbeat+drbd+mysql:实现最廉价的高可用组合
查看>>
解决NGINX+PHP-FPM failed to ptrace(PEEKDATA) Input/output error出错问题
查看>>
splice和sendfile
查看>>
基于rsync+inotify实现数据实时同步传输
查看>>
【No.11 默认实参的匹配】
查看>>
一键生成表结构说明文档的参考,数据字典生成方式参考
查看>>
CCNP课堂练习一:详解交换机vlan的介绍及通过交换机从逻辑上划分区域配置
查看>>
awk实际应用:文本合并
查看>>
Silverlight发布时的优化工作(2)
查看>>
Visual Studio 2010 Ultimate测试体系结构
查看>>
推荐《认知与设计——理解UI设计准则》读书笔记
查看>>
Windows 2003 AD升级至Windows 2012 AD之DHCP服务器迁移
查看>>
创建和管理表
查看>>