首页 > 代码库 > 利用ItextPdf、core-renderer-R8 来生成PDF

利用ItextPdf、core-renderer-R8 来生成PDF

最近由于工作上的需要,需要做一个简历产品的下载功能,而下载的形式要去为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()>  
<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页面的代码:
@RequestMapping(value = http://www.mamicode.com/"/createPdf.s", method = {RequestMethod.POST,RequestMethod.GET})>
前半段关于数据的封装等的代码可以不管,填上自己的数据就行了。

生成页面有就是读取相关页面,并生成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 = http://www.mamicode.com/JsonUtil.object2json(jsonObjOutPut);>
这里需要注意的两点是: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;
        }
    }
这里的注意点是:注意下载文件中文标题乱码问题

至此,以上总体的代码大概是这样,需要的人,可以多看看,如果有什么问题,欢迎随时私信、留言等交流。