一、整体思路
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边框有细微的距离,这个不知道怎么解决