一、整体思路

1.因为项目中打印pdf多为表格,所以将所有组件统一使用表格处理。对单元格的边框做处理,达到普通文本的目的

2.xml定义表格的格式及普通文本内容,使用{{变量名称}}来表示需要使用变量替换。

3.考虑到一个pdf中可能有多个数据源,所以使用map来传递参数。

二、实现

1.xml及dtd定义。

这里有一个问题没有解决,那就是dtd文件的位置。先附上代码,待会说问题

我用eclipse新建的java project,新建文件夹xml-config并加入build path,然后在xml-config下直接存储xml文件,NewFile.xml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tablepage SYSTEM "tablepage.dtd">
<tablepage>
<!-- 	<title align="center" v-align="middle" font-family="STSong-Light"> -->
<!-- 		<text>测试标题</text> -->
<!-- 	</title> -->
	<tables>
		<table cols="12" font-family="STSong-Light" entity="cpafInfo" rotate="false">
			<title align="center" v-align="middle" font-family="STSong-Light">
				<text>事务所基本信息</text>
			</title>
			<trs>
				<tr>
					<tds>
						<td colspan="12" align="center" v-align="middle" border-width="1 1 1 1">
							<text>基本情况</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle" border-width="2 2">
							<text>名称</text>
						</td>
						<td colspan="10" align="left" v-align="middle">
							<text>{{cpafName}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle" border-width="3">
							<text>所属行政区划</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{divisionProvince}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle" border-width="0 0">
							<text>组织形式</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{orgForm}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>执业许可批准日期</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{approDate}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>统一社会信用代码</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{regisCno}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>执业许可批准文号</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{rna}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>执业证书编号</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{cpafCno}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" rowspan="2" align="left" v-align="middle">
							<text>注册资本(出资总额)(单位:万元)</text>
						</td>
						<td colspan="4" rowspan="2" align="left" v-align="middle">
							<text>{{totalInves}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>分所数量</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{cpafbNum}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>国际网络名称(如有)</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{internetName}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>经营场所</text>
						</td>
						<td colspan="10" align="left" v-align="middle">
							<text>{{officeLocation}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>通讯地址</text>
						</td>
						<td colspan="10" align="left" v-align="middle">
							<text>{{address}}</text>
						</td>
					</tds>
				</tr>
				
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>报备业务联系人</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{reporter}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>电子邮箱</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{email}}</text>
						</td>
					</tds>
				</tr>
				
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>报备业务联系电话</text>
						</td>
						<td colspan="10" align="left" v-align="middle">
							<text>{{phone}}</text>
						</td>
					</tds>
				</tr>
			</trs>
		</table>
		
		<table cols="12" font-family="STSong-Light" entity="cpafInfo" rotate="true">
			<title align="center" v-align="middle" font-family="STSong-Light">
				<text>测试横向页面</text>
			</title>
			<trs>
				<tr>
					<tds>
						<td colspan="12" align="center" v-align="middle">
							<text>基本情况</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>名称</text>
						</td>
						<td colspan="10" align="left" v-align="middle">
							<text>{{cpafName}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>所属行政区划</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{divisionProvince}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>组织形式</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{orgForm}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>执业许可批准日期</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{approDate}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>统一社会信用代码</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{regisCno}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>执业许可批准文号</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{rna}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>执业证书编号</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{cpafCno}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" rowspan="2" align="left" v-align="middle">
							<text>注册资本(出资总额)(单位:万元)</text>
						</td>
						<td colspan="4" rowspan="2" align="left" v-align="middle">
							<text>{{totalInves}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>分所数量</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{cpafbNum}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>国际网络名称(如有)</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{internetName}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>经营场所</text>
						</td>
						<td colspan="10" align="left" v-align="middle">
							<text>{{officeLocation}}</text>
						</td>
					</tds>
				</tr>
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>通讯地址</text>
						</td>
						<td colspan="10" align="left" v-align="middle">
							<text>{{address}}</text>
						</td>
					</tds>
				</tr>
				
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>报备业务联系人</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{reporter}}</text>
						</td>
						<td colspan="2" align="left" v-align="middle">
							<text>电子邮箱</text>
						</td>
						<td colspan="4" align="left" v-align="middle">
							<text>{{email}}</text>
						</td>
					</tds>
				</tr>
				
				<tr>
					<tds>
						<td colspan="2" align="left" v-align="middle">
							<text>报备业务联系电话</text>
						</td>
						<td colspan="10" align="left" v-align="middle" border-width='0 0.5 0 0'> 
							<text>{{phone}}</text>
						</td>
					</tds>
				</tr>
			</trs>
		</table>
		
	</tables>
</tablepage>

dtd文件内容如下

<!ELEMENT tablepage (title,tables)>
<!ELEMENT tables (table)>
<!ELEMENT table (trs)>
<!ELEMENT trs (tr)>
<!ELEMENT tr (tds)>
<!ELEMENT tds (td)>
<!ELEMENT td (text)>

<!ATTLIST title align CDATA "center"
				v-align CDATA "middle"
				font-family CDATA #IMPLIED>
<!ATTLIST table entity CDATA #REQUIRED
				rows CDATA #IMPLIED
				font CDATA "微软雅黑"
				rotate CDATA "false">
<!ATTLIST td align CDATA "center"
			 v-align CDATA "middle"
			 rowspan CDATA #IMPLIED
			 colspan CDATA "微软雅黑">

dtd主要是对xml内容的约束与检查。问题是,不管是单独将dtd放在xml-config,还是工程根目录下,都会报错,说在另一个位置找不到dtd,但是在两个位置都放dtd,则可以运行。至今不知道为什么。

2.将xml中的内容翻译为bean

Tablepage

package com.ufgov.pdf.entity;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

/**
 * 对应xml中的tablepage标签
 * 
 * @author lihh
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "tablepage")
@XmlType(propOrder = { "title", "tableList" })
public class Tablepage {

	@XmlElement(name = "title")
	private Title title;

	@XmlElementWrapper(name = "tables")
	@XmlElement(name = "table")
	private List<Table> tableList;

	public Title getTitle() {
		return title;
	}

	public void setTitle(Title title) {
		this.title = title;
	}

	public List<Table> getTableList() {
		return tableList;
	}

	public void setTableList(List<Table> tableList) {
		this.tableList = tableList;
	}

}

Title

package com.ufgov.pdf.entity;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = { "text" })
public class Title {

	@XmlElement(name = "text", required = true)
	private String text;

	@XmlAttribute(name = "align")
	private String align;

	@XmlAttribute(name = "v-align")
	private String vAlign;

	@XmlAttribute(name = "font-family")
	private String fontFamily;

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public String getAlign() {
		return align;
	}

	public void setAlign(String align) {
		this.align = align;
	}

	public String getvAlign() {
		return vAlign;
	}

	public void setvAlign(String vAlign) {
		this.vAlign = vAlign;
	}

	public String getFontFamily() {
		return fontFamily;
	}

	public void setFontFamily(String fontFamily) {
		this.fontFamily = fontFamily;
	}

}

Table

package com.ufgov.pdf.entity;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlType;

/**
 * 对应xml中的table标签
 * 
 * @author lihh
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "table", propOrder = { "title", "trList" })
public class Table {

	@XmlElement(name = "title")
	private Title title;

	@XmlElementWrapper(name = "trs")
	@XmlElement(name = "tr")
	private List<Tr> trList;

	@XmlAttribute(name = "cols")
	private String cols;
	@XmlAttribute(name = "font-family")
	private String fontFamily;

	@XmlAttribute(name = "entity")
	private String entity;

	@XmlAttribute(name = "rotate")
	private String rotate;

	public String getRotate() {
		return rotate;
	}

	public void setRotate(String rotate) {
		this.rotate = rotate;
	}

	public Title getTitle() {
		return title;
	}

	public void setTitle(Title title) {
		this.title = title;
	}

	public List<Tr> getTrList() {
		return trList;
	}

	public void setTrList(List<Tr> trList) {
		this.trList = trList;
	}

	public String getCols() {
		return cols;
	}

	public void setCols(String cols) {
		this.cols = cols;
	}

	public String getFontFamily() {
		return fontFamily;
	}

	public void setFontFamily(String fontFamily) {
		this.fontFamily = fontFamily;
	}

	public String getEntity() {
		return entity;
	}

	public void setEntity(String entity) {
		this.entity = entity;
	}

}

Tr

package com.ufgov.pdf.entity;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "tr",propOrder= {"tdList"})
public class Tr {

	@XmlElementWrapper(name = "tds")
	@XmlElement(name = "td")
	private List<Td> tdList;

	public List<Td> getTdList() {
		return tdList;
	}

	public void setTdList(List<Td> tdList) {
		this.tdList = tdList;
	}

}

Td

package com.ufgov.pdf.entity;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "td", propOrder = { "text" })
public class Td {

	@XmlAttribute(name = "rowspan")
	private String rowspan;

	@XmlAttribute(name = "border-width")
	private String borderWidth;

	@XmlAttribute(name = "colspan")
	private String colspan;

	@XmlAttribute(name = "align")
	private String align;

	@XmlAttribute(name = "v-align")
	private String vAlign;

	@XmlElement(name = "text")
	private String text;

	public String getBorderWidth() {
		return borderWidth;
	}

	public void setBorderWidth(String borderWidth) {
		this.borderWidth = borderWidth;
	}
	
	public String getSText() {
		return text;
	}

	public void setString(String text) {
		this.text = text;
	}

	public String getRowspan() {
		return rowspan == null ? "1" : rowspan;
	}

	public void setRowspan(String rowspan) {
		this.rowspan = rowspan;
	}

	public String getColspan() {
		return colspan == null ? "1" : colspan;
	}

	public void setColspan(String colspan) {
		this.colspan = colspan;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public String getAlign() {
		return align;
	}

	public void setAlign(String align) {
		this.align = align;
	}

	public String getvAlign() {
		return vAlign;
	}

	public void setvAlign(String vAlign) {
		this.vAlign = vAlign;
	};

}

上述实体需要用到XmlAccessorType等注解,不懂的话可以百度。

3.下边是工具类

a.xml转为bean

这个是从网上找的jaxb2的用法

package com.ufgov.pdf.util;

import java.io.StringReader;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

/**
 * Jaxb2工具类
 */
public class JaxbUtil {

	/**
	 * xml转换成JavaBean
	 * 
	 * @param xml
	 * @param c
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T converyToJavaBean(String xml, Class<T> c) {
		T t = null;
		try {
			JAXBContext context = JAXBContext.newInstance(c);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			t = (T) unmarshaller.unmarshal(new StringReader(xml));
		} catch (Exception e) {
			e.printStackTrace();
		}

		return t;
	}

//	/**
//	 * JavaBean转换成xml 默认编码UTF-8
//	 * 
//	 * @param obj
//	 * @param writer
//	 * @return
//	 */
//	public static String convertToXml(Object obj) {
//		return convertToXml(obj, "UTF-8");
//	}

//	/**
//	 * JavaBean转换成xml
//	 * 
//	 * @param obj
//	 * @param encoding
//	 * @return
//	 */
//	public static String convertToXml(Object obj, String encoding) {
//		String result = null;
//		try {
//			JAXBContext context = JAXBContext.newInstance(obj.getClass());
//			Marshaller marshaller = context.createMarshaller();
//			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//			marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
//
//			StringWriter writer = new StringWriter();
//			marshaller.marshal(obj, writer);
//			result = writer.toString();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//
//		return result;
//	}

}



b.数据库测试用类

package com.ufgov.pdf.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

public class DBHelper {

    /**
     * 将下划线风格替换为驼峰风格
     *
     * @param inputString
     * @return
     */
    private static String underlineToCamelhump(String inputString) {
        StringBuilder sb = new StringBuilder();

        boolean nextUpperCase = false;
        for (int i = 0; i < inputString.length(); i++) {
            char c = inputString.charAt(i);
            if (c == '_') {
                if (sb.length() > 0) {
                    nextUpperCase = true;
                }
            } else {
                if (nextUpperCase) {
                    sb.append(Character.toUpperCase(c));
                    nextUpperCase = false;
                } else {
                    sb.append(Character.toLowerCase(c));
                }
            }
        }
        return sb.toString();
    }
	public static Map<String, Object> getData(String sql) throws ClassNotFoundException, SQLException {
		Class.forName("oracle.jdbc.driver.OracleDriver");
		String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
		String user = "test";
		String password = "1";
		Connection conn = DriverManager.getConnection(url, user, password);
		Statement stmt = conn.createStatement();
		ResultSet rs = stmt.executeQuery(sql);
		ResultSetMetaData data = rs.getMetaData();
		Map<String, Object> map = null;
		while (rs.next()) {
			 map = new HashMap<String, Object>();
			for (int i = 1; i <= data.getColumnCount(); i++) {// 数据库里从 1 开始

				String c = data.getColumnName(i);
				String v = rs.getString(c);
				System.out.println(c + ":" + v + "\t");
				map.put(underlineToCamelhump(c), v);
			}
			System.out.println("======================");
		}
		rs.close();
		stmt.close();
		conn.close();
		return map;
	}
	
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		String sql  = "select * from cpa_cpaf_bir t where t.report_no ='CG201700042045'";
		System.out.println(getData(sql));
	}
}

c.核心转换类

package com.ufgov.pdf.util;

import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.ufgov.pdf.entity.Table;
import com.ufgov.pdf.entity.Tablepage;
import com.ufgov.pdf.entity.Td;
import com.ufgov.pdf.entity.Title;
import com.ufgov.pdf.entity.Tr;

/**
 * 到处pdf帮助类 Created by lihhz on 2017/10/16.
 */
public class PdfHelper {

	/**
	 * xml与数据装配页面<br>
	 * 核心方法,负责输出文档
	 * 
	 * @param tablepage
	 *            xml结构
	 * @param map
	 *            数据结构
	 * @throws Exception
	 */
	public static void convert(Tablepage tablepage, Map<String, Map<String, Object>> map) throws Exception {
		// TODO:这里要设置一个文件名称,暂时先写死
		// Title title = tablepage.getTitle();
		// String fileName = title.getText() + ".pdf";
		String fileName = "测试文档.pdf";
		BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
		Font font = new Font(baseFont, 10, Font.NORMAL);

		// TODO:这个地方如果拿到注会用的话,要改成使用response输出
		File file = new File(fileName);
		FileOutputStream out = new FileOutputStream(file);

		// TODO:这个A4要不要做配置?
		Rectangle rectPageSize = new Rectangle(PageSize.A4);
		Document document = new Document(rectPageSize, -50, -50, 10, 20);
		PdfWriter.getInstance(document, out);
		document.open();

		// PdfPTable table_title1 = new PdfPTable(1);
		// setTitle(document, title, table_title1);

		List<Table> tableList = tablepage.getTableList();

		// TODO:这个地方可以做成静态数据,也可以不做,只是为了输出的时候更简单
		Map<String, Integer> posMap = new HashMap<String, Integer>();
		posMap.put("center", Element.ALIGN_CENTER);
		posMap.put("left", Element.ALIGN_LEFT);
		posMap.put("right", Element.ALIGN_RIGHT);

		posMap.put("top", Element.ALIGN_TOP);
		posMap.put("middle", Element.ALIGN_MIDDLE);
		posMap.put("bottom", Element.ALIGN_BOTTOM);

		int size = tableList.size();
		if (tableList == null || size < 1) {
			return;
		}

		for (Table table : tableList) {
			String rotate = table.getRotate();
			Rectangle rect = new Rectangle(PageSize.A4);
			// 添加横向支持
			if (rotate.equals("true")) {
				document.setPageSize(rect.rotate());
			}
			document.newPage();
			PdfPTable table1 = new PdfPTable(12);
			// table1.addCell("测试一下");
			// table1.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
			// table1.setLockedWidth(true);
			Title t = table.getTitle();
			PdfPTable tableTitle = new PdfPTable(1);
			if (t != null && t.getText() != null) {
				setTitle(document, t, tableTitle);
			}

			List<Tr> trList = table.getTrList();
			String entity = table.getEntity();
			Map<String, Object> obj = map.get(entity);
			if (null == obj) {
				System.out.println("警告:出现空值!");
			}
			if (trList == null || trList.size() < 1) {
				document.add(table1);
				continue;
			}
			for (Tr tr : trList) {
				List<Td> tdList = tr.getTdList();
				if (tdList == null || tdList.size() < 1) {
					continue;
				}
				for (Td td : tdList) {

					String text = td.getText();
					if (text.startsWith("{{") && text.endsWith("}}")) {
						String key = text.replace("{{", "").replace("}}", "");
						text = obj.containsKey(key) && obj.get(key) != null ? obj.get(key).toString() : "";
					}
					PdfPCell cell = new PdfPCell(new Paragraph(text, font));

					String borderWidth = td.getBorderWidth();
					float[] borderArr = getBorder(borderWidth);
					if (borderArr != null) {
						cell.setBorderWidthTop(borderArr[0]);
						cell.setBorderWidthRight(borderArr[1]);
						cell.setBorderWidthBottom(borderArr[2]);
						cell.setBorderWidthLeft(borderArr[3]);
					}
					cell.setColspan(Integer.parseInt(td.getColspan()));
					cell.setRowspan(Integer.parseInt(td.getRowspan()));
					cell.setHorizontalAlignment(posMap.get(td.getAlign()));
					cell.setVerticalAlignment(posMap.get(td.getvAlign()));
					cell.setMinimumHeight(20f);
					table1.addCell(cell);
				}
			}
			document.add(table1);
		}
		document.close();
	}

	/**
	 * TODO:在这里设置边框。暂时没有什么好的方法
	 */
	private static float[] getBorder(String borderWidth) {
		if (borderWidth == null) {
			return null;
		}
		float[] borderArr = new float[4];
		String[] borderWidths = borderWidth.split("\\s+");
		// 校验边框
		int borderNum = borderWidths.length;
		switch (borderNum) {
		case 1:
			borderArr[0] = Float.parseFloat(borderWidths[0]);
			borderArr[1] = borderArr[0];
			borderArr[2] = borderArr[0];
			borderArr[3] = borderArr[0];
			break;
		case 2:
			borderArr[0] = Float.parseFloat(borderWidths[0]);
			borderArr[1] = borderArr[0];
			borderArr[2] = Float.parseFloat(borderWidths[1]);
			borderArr[3] = borderArr[2];
			break;
		case 3:
			borderArr[0] = Float.parseFloat(borderWidths[0]);
			borderArr[1] = Float.parseFloat(borderWidths[1]);
			borderArr[2] = Float.parseFloat(borderWidths[2]);
			borderArr[3] = 0;
			break;
		case 4:
			borderArr[0] = Float.parseFloat(borderWidths[0]);
			borderArr[1] = Float.parseFloat(borderWidths[1]);
			borderArr[2] = Float.parseFloat(borderWidths[2]);
			borderArr[3] = Float.parseFloat(borderWidths[3]);
			break;
		default:
			borderArr[0] = borderArr[1] = borderArr[2] = borderArr[3] = 1;
			break;
		}

		return borderArr;
	}

	private static void setTitle(Document document, Title title, PdfPTable tableTitle) throws Exception {
		PdfPCell cell = new PdfPCell(new Paragraph(title.getText(), new Font(
				BaseFont.createFont(title.getFontFamily(), "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), 17, Font.NORMAL)));
		// TODO:这个地方要设置标题的位置,暂时先不写
		cell.setHorizontalAlignment(Element.ALIGN_CENTER); // 设置单元格中文本位置(居中:ALIGN_CENTER;靠左:ALIGN_LEFT;靠右:ALIGN_RIGHT)
		cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 文本垂直方向位置(靠上:ALIGN_TOP;居中:ALIGN_MIDDLE;靠下:ALIGN_BOTTOM;)
		cell.setBorderWidth(0f); // 设置单元格边框,参数都为float
		cell.setPaddingBottom(20f); // 设置单元格文本内边距
		tableTitle.addCell(cell);

		document.add(tableTitle);
	}
}

其它测试类

package com.ufgov.pdf.util;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Locale;

/**
 * 测试用的工具类,在cpams中已经存在,可以删除了
 * @author lihh
 *
 */
public class CanDel {

	/**
	 * 
	 * @param number
	 *            要转换的数字
	 * @param digit
	 *            保留小数点位数
	 * @return
	 * @author zhangdand at 2018年3月1日下午4:10:52
	 */
	public static String numberFormat(BigDecimal number, int digit) {
		String result = "0";
		// 小数点后边的数字(不包括.)
		String digitStr = "";
		NumberFormat usFormat = NumberFormat.getIntegerInstance(Locale.US);
		if (number == null || number.compareTo(new BigDecimal(0)) == 0) {
			if (digit > 0) {
				for (int i = 0; i < digit; i++) {
					digitStr += "0";
				}
				result += "." + digitStr;
			}
		} else {
			// 保留两位小数
			usFormat.setMaximumFractionDigits(digit);
			result = usFormat.format(number);
			if (result.indexOf(".") < 0 && digit > 0) {
				for (int i = 0; i < digit; i++) {
					digitStr += "0";
				}
				result += "." + digitStr;
			} else if (result.indexOf(".") > 0) {
				String[] tmpArry = result.split("\\.");
				digitStr = tmpArry[1];
				// 处理小数点结尾0不显示的情况
				if (digitStr.length() < digit) {
					int tmpN = digit - digitStr.length();
					for (int i = 0; i < tmpN; i++) {
						digitStr += "0";
					}
					result = tmpArry[0] + "." + digitStr;
				}
			}
		}
		return result;
	}
}

4.实体基类

所有需要转pdf的实体继承基类,主要是toMap方法,不过在main方法中并没有用到

package com.ufgov.pdf.entity;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import com.ufgov.pdf.util.CanDel;

/**
 * pdf bean基类. 将需要转换为Map的bean继承自此抽象类
 * 如果所需要的类型在toMap方法中不存在,可以添加;
 * 如果基类的toMap方法实在不能满足您的需求,您可以重写此方法
 * 
 * @author lihh
 *
 */
public abstract class BaseMapBean {

	/**
	 * 转化为Map
	 * @return
	 */
	public Map<String, Object> toMap() {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			// 内省是 Java 语言对 Bean 类属性、事件的一种缺省处理方法。例如类 PersonBean中有属性 name, 那我们可以通过
			// getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。 Java
			// 中提供了一套 API 用来访问某个属性的 getter/setter 方法,通过这些 API 可以使你不需要了解这个规则(但你最好还是要搞清楚),这些
			// API 存放于包 java.beans 中。注意:
			// PersonBean中属性mN的getter/setter方法必须满足javaBean命名规范,即getmN,不能写作getMN,否则转换失败。
			BeanInfo beanInfo = Introspector.getBeanInfo(this.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();
				// 过滤class属性
				if (!key.equals("class")) {
					// 得到property对应的getter方法
					Method getter = property.getReadMethod();
					Object value = getter.invoke(this);
					if (value != null) {
						if (value instanceof BigDecimal) {
							value = CanDel.numberFormat((BigDecimal) value, 2);
						} else {
							System.out.println(value.getClass().toString());
						}
					}
					map.put(key, value);
				}

			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("transBean2Map Error " + e);
		}

		return map;
	}
}

main测试方法

package com.ufgov.pdf.util;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;

import com.ufgov.pdf.entity.Tablepage;

/**
 * 导出PDF的Main方法
 * 
 * @author lihh
 *
 */
public class ExportPdfImpl {

	/**
	 * 这个在注会中写成一个方法,该方法接受一个xml文件路径参数,一个map
	 * @param args
	 */
	public static void main(String[] args) {
		SAXReader sax = new SAXReader();// 创建一个SAXReader对象
		File xmlFile = new File("xml-config/NewFile.xml");// 根据指定的路径创建file对象
		try {
			// 获取document对象,如果文档无节点,则会抛出Exception提前结束
			Document document = sax.read(xmlFile);
			Tablepage tablepage = JaxbUtil.converyToJavaBean(document.asXML(), Tablepage.class);
			Map<String, Map<String, Object>> map = new HashMap<String, Map<String, Object>>();

			String sql = "select * from cpa_cpaf_bir t where t.report_no ='CG201700042045'";
			map.put("cpafInfo", DBHelper.getData(sql));
			PdfHelper.convert(tablepage, map);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	// public static void getRoot() {
	// SAXReader sax = new SAXReader();// 创建一个SAXReader对象
	// File xmlFile = new File("xml-config/NewFile.xml");// 根据指定的路径创建file对象
	// try {
	// // 获取document对象,如果文档无节点,则会抛出Exception提前结束
	// Document document = sax.read(xmlFile);
	// Element root = document.getRootElement();// 获取根节点
	// Tablepage tablepage = new Tablepage();
	// getNodes(root, tablepage);// 从根节点开始遍历所有节点
	// } catch (DocumentException e) {
	// e.printStackTrace();
	// }
	//
	// }
	//
	// /**
	// * 从指定节点开始,递归遍历所有子节点
	// *
	// * @author chenleixing
	// */
	// public static void getNodes(Element node, Tablepage tablepage) {
	// System.out.println("--------------------");
	// if (node.getName().equals("title")) {
	// tablepage.setTitle(node.getText());
	// } else if (node.getName().equals("table")) {
	// Table table = new Table();
	// }
	// // 当前节点的名称、文本内容和属性
	// System.out.println("当前节点名称:" + node.getName());// 当前节点名称
	// System.out.println("当前节点的内容:" + node.getTextTrim());// 当前节点名称
	// List<Attribute> listAttr = node.attributes();// 当前节点的所有属性的list
	// for (Attribute attr : listAttr) {// 遍历当前节点的所有属性
	// String name = attr.getName();// 属性名称
	// String value = attr.getValue();// 属性的值
	// System.out.println("属性名称:" + name + "属性值:" + value);
	// }
	//
	// // 递归遍历当前节点所有的子节点
	// List<Element> listElement = node.elements();// 所有一级子节点的list
	// for (Element e : listElement) {// 遍历所有一级子节点
	// // getNodes(e);// 递归
	// }
	// }

}

至此,整个项目结束

导出的pdf还有一个问题就是,在设置边框后,放大pdf,会看到设置的边框外侧和其它没有手动设置、正常的cell边框有细微的距离,这个不知道怎么解决