使用itext将xml转换为pdf(二)

文章目录

    • xml配置
      • dtd文件的编码及说明
        • dtd文件
        • dtd文件说明
      • xml编码及说明
        • NewFile.xml
        • test-include.xml
        • xml说明
    • xml数据模型
      • BaseMapBean
      • Tablepage
      • Table
      • Title
      • Tr
      • Td
    • 数据装配
    • 一个调用的示例
    • 待改进的地方

使用itext将xml转换为pdf(一)主要是一个探索的过程,所以使用Java project来立项。现在经过将近一个月的整理和整合,在web项目中已经渐近成熟。再总结一下。

基本上分为三个模块
- xml的配置
- xml数据结构
- xml解析与数据装配
类似于mvc结构,即xml配置为前端展现view,数据装配为controller,xml对应的数据模型为model。

用到了dom4j的相关jar,还有就是jaxb2,这个主要是借鉴网上的。

xml配置

主要是dtd约束及xml的编写

dtd文件的编码及说明

dtd的主要作用是用来约束xml的编写规范。

dtd文件

	<!ELEMENT tablepage (title,tables,include)>
	<!ELEMENT tables (table,include)>
	<!ELEMENT table (trs,include)>
	<!ELEMENT trs (tr)>
	<!ELEMENT tr (tds)>
	<!ELEMENT tds (td)>
	<!ELEMENT td (text)>
	
	<!ATTLIST include file	CDATA	#IMPLIED>
	
	<!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 tr foreach CDATA "false"
				 entities CDATA "">
	<!ATTLIST td align CDATA "center"
				 v-align CDATA "middle"
				 rowspan CDATA #IMPLIED
				 colspan CDATA "微软雅黑">

dtd文件说明

xml-config中配置的是每个pdf对应的xml,下边是参数的dtd文档说明

tablepage是xml的root节点,有且只有一个
tablepage的子节点为title和tables


//tablepage下可以有多个table,多个table用tables包裹,其子节点用有且只有一个trs


//table子节点能且只能是trs


//table下可以有多个tr,多个tr用trs包裹


//tr子节点能且只能是tds


//tds子节点能且只能是td



//包含文件,其中file只得是xml-config下的文件路径,不包含xml-config,但要包含.xml后缀,file不能为空.
//被包含文件不能有根节点tablepage

//下边是每个标签的熟悉,属性名可以参考html,如有不懂之处,请上网搜索


>
			 entities CDATA "">

xml编码及说明

NewFile.xml



<tablepage file-name="">



	<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>
		<include file="test-include.xml"/>
	tables>
tablepage>

test-include.xml




<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 foreach="true" entities="">
			<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>

xml说明

这里的主要问题是


在使用itext将xml转换为pdf(一)中使用SYSTEM发现,需要在两个位置配置tablepage.dtd的位置,在web中也一样需要在两个位置,但位置比较奇怪,而且SYSTEM后边也不能简单的写"tablepage.dtd"就可以了,java项目xml使用自定义dtd位置问题中有说明。

后来在同事的探索中,更新了使用方法,即使用PUBLIC方式,但这中方式就不能使用本地文件,需要将文件放在网络可以访问的位置,虽然比较成功,但是在开发中还是不够完美:首先就是必须能访问到,这就意味着如果是localhost的话,必须启动服务,而且每个人的端口不同,需要每个人自己去改动;再就是每次上线都要做改动,比较麻烦。不过暂时这么做也比较合理。就这样先放着,后边有好的解决方法再补充。

xml数据模型

这个就是java中对应xml的bean了

因为后边数据装配中需要对数据的格式做一些规范,所以bean都需要继承一个基类。

BaseMapBean

package com.ufgov.util.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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.ufgov.util.StringUtil;

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

	/**
	 * 转化为Map
	 * 
	 * @param digit
	 *            BigDecimal的转换精度
	 * @return
	 */
	public List> toMap(Integer digit) {
		if (digit == null || digit < 0) {
			digit = 2;
		}
		Map map = new HashMap();
		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) {
							// TODO:这个地方是不是要把精度做成可选?
							value = StringUtil.numberFormat((BigDecimal) value, digit);
						} else {
							System.out.println(value.getClass().toString());
						}
					}
					map.put(key, value);
				}

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

		List> list = new ArrayList>();
		list.add(map);
		return list;
	}
}

其他实体

Tablepage

package com.ufgov.util.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.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

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

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

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


	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}
	
	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;
	}

}

Table

package com.ufgov.util.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;
	}

}

Title

package com.ufgov.util.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;
	}

}

Tr

package com.ufgov.util.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;

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

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

	public String getEntities() {
		return entities;
	}

	public void setEntities(String entities) {
		this.entities = entities;
	}

	public String getForeach() {
		return foreach;
	}

	public void setForeach(String foreach) {
		this.foreach = foreach;
	}

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

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

}

Td

package com.ufgov.util.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;
	};

}

至此数据模型完毕

数据装配

这个就是纽带了

首先就是Jaxb2工具类,其中的converyToJavaBean就是xml转换为bean的核心

package com.ufgov.util.pdf.util;

import java.io.File;
import java.io.StringReader;
import java.util.List;

import javax.xml.bind.JAXBContext;

import org.apache.commons.collections.CollectionUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * Jaxb2工具类
 * xml转换成JavaBean核心方法
 * 
 * @author lihhz
 * @create 2018-4-9 下午2:40:14
 */
public class JaxbUtil {

	/**
	 * xml转换成JavaBean
	 * 
	 * @param xml
	 * @param c
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T converyToJavaBean(String xmlPath, Class<T> clazz) {
		try {
			// 根据指定的路径创建file对象
			File xmlFile = new File(JaxbUtil.class.getClassLoader().getResource("xml-config/" + xmlPath + ".xml").getFile());
			if (!xmlFile.exists()) {
				throw new Exception("文件xml-config/" + xmlPath + ".xml不存在!!!");
			}
			Document xmlDocument = (new SAXReader()).read(xmlFile);
			replInclude(xmlDocument.getRootElement());
			return (T) JAXBContext.newInstance(clazz).createUnmarshaller().unmarshal(new StringReader(xmlDocument.asXML()));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 这是一个递归
	 * 目的是替换文档中的include标签
	 * 还有一个tablepage的问题有待解决
	 * 该方法有待大量include测试
	 * 
	 * @param srcEle
	 * @throws Exception
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static void replInclude(Element srcEle) throws Exception {
		Element inc = srcEle.element("include");
		if (inc != null) {
			File file = new File(
					JaxbUtil.class.getClassLoader().getResource("xml-config/" + inc.attributeValue("file")).getFile());
			if (!file.exists()) {
				throw new Exception("文件" + inc.attributeValue("file") + "没有找到!!!");
			}
			// 使用文件中的内容替换include
			Element rootEle = (new SAXReader()).read(file).getRootElement();
			// TODO:这个被包含页面不能有tablepage标签的问题要解决一下
			if (rootEle.getName().equalsIgnoreCase("tablepage")) {
				throw new Exception("被包含页面不能有tablepage标签!!!");
			}
			replInclude(rootEle);
			List content = srcEle.content();// inc.getParent()
			content.set(content.indexOf(inc), rootEle);
		}

		List<Element> list = srcEle.elements();
		if (!CollectionUtils.isEmpty(list)) {
			for (Element element : list) {
				replInclude(element);
			}
		}
	}

	// /**
	// * 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;
	// }

}

而PageHelper则是数据–>pdf的封装

package com.ufgov.util.pdf.util;

import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
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.util.pdf.entity.Table;
import com.ufgov.util.pdf.entity.Tablepage;
import com.ufgov.util.pdf.entity.Td;
import com.ufgov.util.pdf.entity.Title;
import com.ufgov.util.pdf.entity.Tr;

/**
 * 导出pdf核心帮助类
 * xml与数据装配核心方法
 */
public class PdfHelper {

	/**
	 * xml与数据装配页面
* 核心方法,负责输出文档 * @param filePath xml在xml-config下的路径不包括xml-config/及最后的.xml * @param dataMap 数据源 * @param response * @throws Exception */
public static void convert(String filePath,Map<String, List<Map<String, Object>>> dataMap, HttpServletResponse response) throws Exception { try { Tablepage tablepage = JaxbUtil.converyToJavaBean(filePath, Tablepage.class); String fileName = tablepage.getFileName(); // BaseFont baseFont = BaseFont.createFont("STSong-Light", // "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); // Font font = new Font(baseFont, 10, Font.NORMAL); if (StringUtils.isEmpty(fileName)) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmssSSS"); fileName = sdf.format(new Date()) + ".pdf"; System.out.println("文件名为空,将使用默认文件名:" + fileName); } // 设置response属性 response.reset(); response.setHeader("content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "utf-8")); response.setCharacterEncoding("utf-8"); response.setContentType("application/pdf"); // TODO:这个A4要不要做配置? Rectangle rectPageSize = new Rectangle(PageSize.A4); Document document = new Document(rectPageSize, -50, -50, 10, 20); // 这个地方如果拿到注会用的话,要改成使用response输出 // File file = new File(fileName); // FileOutputStream out = new FileOutputStream(file); // PdfWriter.getInstance(document, out); PdfWriter.getInstance(document, response.getOutputStream()); document.open(); // PdfPTable table_title1 = new PdfPTable(1); // setTitle(document, title, table_title1); List<Table> tableList = tablepage.getTableList(); // int size = tableList.size(); // if (tableList == null || size < 1) { // return; // } if (CollectionUtils.isEmpty(tableList)) { 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.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(); List<Map<String, Object>> list = dataMap.get(entity); if (CollectionUtils.isEmpty(list)) { System.out.println("警告:出现空值!"); } if (trList == null || trList.size() < 1) { document.add(table1); continue; } for (Tr tr : trList) { // 检测是否是list表格 if (!StringUtils.isEmpty(tr.getForeach()) && tr.getForeach().equalsIgnoreCase("true")) { String entities = tr.getEntities(); // 没有填充数据,不循环 if (StringUtils.isEmpty(entities) || !dataMap.containsKey(entities)) { System.out.println("entities设置不正确!"); continue; } // 强制转换为List>类型 List<Map<String, Object>> dataList = (List<Map<String, Object>>) dataMap.get(entities); if (CollectionUtils.isEmpty(list)) { System.out.println("entities为空哟!"); continue; } for (Map<String, Object> en : dataList) { renderTd(table1, tr, en); } } else { renderTd(table1, tr, list.get(0)); } } document.add(table1); } document.close(); } catch (Exception e) { e.printStackTrace(); } } private static void renderTd(PdfPTable table1, Tr tr, Map<String, Object> obj) throws DocumentException, IOException { BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, 10, Font.NORMAL); // 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); List<Td> tdList = tr.getTdList(); if (tdList == null || tdList.size() < 1) { return; } 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); // if (arr[2] != 0) { // cell.setFixedHeight(arr[2]); // } table1.addCell(cell); } } /** * 在这里设置边框。暂时没有什么好的方法 */ 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); } }

一个调用的示例


3.java代码中调用方法参考如下
@RequestMapping(value="/exportReport")
public void printBir(String reportNo ,HttpServletResponse response) throws Exception{
	//在xml-config下的文件名,如果嵌套有文件夹的话,要写上嵌套路径
	String fileName = "NewFile2" ;
	CpaCpafBir cpaCpafBir=caCpafBirService.selectByReportNo(reportNo);
	Map<String, List<Map<String, Object>>> map = new HashMap<String, List<Map<String, Object>>>();
	//toMap的参数为BigDecimal的精度
	map.put("cpaCpafBir", cpaCpafBir.toMap(null)) ;
	PdfHelper.convert(fileName, map, response);
}

如上。

待改进的地方

待改进的地方还是比较多的

首先是include的处理。定义include主要是为了分割xml文件,否则一个巨长的xml其可读性和维护性势必不好,但是发现在处理的时候对于根节点tablepage的处理有些问题。待处理

再就是xml的编写。虽然采用的是类html的方式,但是还是偏向于复杂。也许可以图形化配置。

还有就是dtd的位置问题。目前的方案似乎还不错。看网上很多说法都是Schema取代dtd,不知道会不会更好以下

暂时没有发现其它问题。

你可能感兴趣的:(开发语言,java,xml,pdf,dom4j)