我是靠谱客的博主 丰富钢铁侠,这篇文章主要介绍使用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文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!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文件说明

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
xml-config中配置的是每个pdf对应的xml,下边是参数的dtd文档说明 tablepage是xml的root节点,有且只有一个 tablepage的子节点为title和tables <!ELEMENT tablepage (title,tables)> //tablepage下可以有多个table,多个table用tables包裹,其子节点用有且只有一个trs <!ELEMENT tables (table)> //table子节点能且只能是trs <!ELEMENT table (trs)> //table下可以有多个tr,多个tr用trs包裹 <!ELEMENT trs (tr)> //tr子节点能且只能是tds <!ELEMENT tr (tds)> //tds子节点能且只能是td <!ELEMENT tds (td)> <!ELEMENT td (text)> //包含文件,其中file只得是xml-config下的文件路径,不包含xml-config,但要包含.xml后缀,file不能为空. //被包含文件不能有根节点tablepage <!ATTLIST include file CDATA #IMPLIED> //下边是每个标签的熟悉,属性名可以参考html,如有不懂之处,请上网搜索 <!ATTLIST title align CDATA "center" v-align CDATA "middle" font-family CDATA #IMPLIED> <!ATTLIST table entity CDATA #REQUIRED rows CDATA #IMPLIED font CDATA "微软雅黑" //rotate,false:正常A4,true:横向A4 rotate CDATA "false"> <!ATTLIST tr foreach CDATA "false" //foreach 用来指定是否是一个循环 //配合下边的entities,entities的数据结构为List<Map<String,Object>> entities CDATA ""> <!ATTLIST td align CDATA "center" v-align CDATA "middle" rowspan CDATA #IMPLIED //四个边框的宽度,其顺序按照上、右、下、左的顺序设置 //若只有一个值则为上、右、下、左 //若两个值则前一个值为上下,后一个值为左右 border-width CDATA "1 1 1 1" colspan CDATA "微软雅黑">

xml编码及说明

NewFile.xml

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE tablepage PUBLIC "tablepage" "http://localhost:8080/dtd/tablepage.dtd"> <tablepage file-name=""> <!-- <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> <include file="test-include.xml"/> </tables> </tablepage>

test-include.xml

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE tablepage PUBLIC "tablepage" "http://localhost:8080/dtd/tablepage.dtd"> <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说明

这里的主要问题是

复制代码
1
2
<!DOCTYPE tablepage PUBLIC "tablepage" "http://localhost:8080/dtd/tablepage.dtd">

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

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

xml数据模型

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

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

BaseMapBean

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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<Map<String, Object>> toMap(Integer digit) { if (digit == null || digit < 0) { digit = 2; } 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) { // 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<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); list.add(map); return list; } }

其他实体

Tablepage

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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的核心

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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的封装

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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与数据装配页面<br> * 核心方法,负责输出文档 * @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<Map<String,Object>>类型 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); } }

一个调用的示例

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
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,不知道会不会更好以下

暂时没有发现其它问题。

最后

以上就是丰富钢铁侠最近收集整理的关于使用itext将xml转换为pdf(二)的全部内容,更多相关使用itext将xml转换为pdf(二)内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(69)

评论列表共有 0 条评论

立即
投稿
返回
顶部