JEE应用系统生成PDF表格的解决方案
2012-04-29陈本士,付立平
陈本士,付立平
摘要: PDF形式的输出格式愈来愈多地被商业客户所接受.由于PDF文件具有格式整洁,所占空间小等特点,很多电子商务应用系统用PDF文件做为在线表格的打印与存储.在基于JEE技术设计的系统中,利用iText( JAVA开源代码库), Java reflection特性来生成PDF文件是一种有效的方法。
关键词:JEE应用;PDF表格
中图分类号:TP311文献标识码:A文章编号:1009-3044(2012)02-0318-04
1定义
1) WEB表格:用户从电子商务网站的网页定义的表格输入UI界面。
2) PDF表格(文件):由系统后端处理并在网页UI界面显示的PDF表格。
3) PDF模板:定义PDF表格的外观,及表格数据所要填写的field(域名)。
2商务案例(Use Case)
学生从学校网页上输入注册信息:姓名,生日,性别,入学时间,专业,院/系,联系方式,住址,父母联系方式等项目名。
学生点击”提交”按钮,将所填写的表格存入系统。
学生点击”打印”或”保存”按钮, WEB登记表格会以PDF文件格式显示在当前窗口中。
我们所讨论的方案要求有以下几个条件:
1)预先设计好的PDF表格模版所定义的field和WEB表格所定义的field必须确保以下所定义的关系:
{PDF Form: fieldA_1, fieldA_2, fieldA_3,…, fieldA_n}?{Web Form: fieldB_1, fieldB_2, fieldB_3…fieldB_n }
fieldA_i 1 : 1 fieldB_j
注: PDF field不必和WEB表格的field名字同名, PDF表格不一定包含所有的WEB表格field
2)WEB表格数据已输入并提交或已经存入系统数据库中。
3)iText JAVA库itext-1.4.4.jar文件已从http://itextpdf.com/网站下载, itext-1.4.4.jar文件的PATH加在系统环境变量CLASS_ PATH定义中。
3方案设计
3.1系统处理流程
如图1所示。
3.2 JEE Design Pattern
本系统设计采用了以下JEE design pattern:
MVC
Session Fa?ade
Wrapper
Transfer Object
DAO
3.3 Class Diagram
如图2所示。
图1
图2
3.4 Sequence Diagram
如图3所示。
图3
3.5编程细节
3.5.1 iText类库
我们的设计将使用到以下iText所定义的类:
com.lowagie.text.Document
com.lowagie.text.DocumentException
com.lowagie.text.PageSize
com.lowagie.text.pdf.AcroFields
com.lowagie.text.pdf.PdfContentByte
com.lowagie.text.pdf.PdfImportedPage
com.lowagie.text.pdf.PdfReader
com.lowagie.text.pdf.PdfStamper
com.lowagie.text.pdf.PdfWriter
3.5.2 Value Object
·StudentFormVO class,此CLASS用于存取WEB表格主要学生数据
Private String studentID;
Private String FirstName;
Private String LastName;
Private String Birthdate;
Private String Gender;
Private String major;
Private ContactVO studentContact;//embedded class
Private ContactVO parentContact; embedded class
…
//定义每个类成员变量的getters, setters…
·ContactVO class此CLASS用于存取WEB表格学生联系信息数据
·Private String phoneNumber;
·Private String cellPhoneNumber;
·Private String email;
//定义每个类成员变量的getters, setters…
StudentPdfFormVO
此CLASS继承StudentFormVO class,用于存取最后生成的PDF表格数据. StudentPdfFormVO
可能要定义更多的类成员变量.让我们以RADIO按钮field为例,如RADIO field有3项选择,那么在StudentFormVO只需一个类成员变量即可,而其对应的StudentPdfFormVO则要定义3个类成员变量。
3.5.3 ViewStudentPDFFormAction class
·viewStudentForm method
功能:根据caller所传递的学生ID,从数据库中读取该学生的登记表,再把所得到的表格数据转换成PDF格式,并写到HTTPServeletResponse输出流中.参数: String studentId,返回数据类型:无
主要编程逻辑如下:
//step1: call StudentServiceSessionBean:: StudentServiceSessionBean()
method to retrieve student submitted form data and fill data in PDF template
//Step2: get filled pdf formbyte array variable pdf
//step3: write pdf byte array into http servlet response stream, see code below:
response.setContentType("application/pdf");
if(pdf != null && pdf.length > 0)
{
response.setContentLength(pdf.length);}
response.setHeader("Cache-Control", "cache, must-revalidate");
response.setHeader("Pragma", "public");
response.setHeader("content-transfer-encoding", "binary");
response.setHeader("content-disposition", "inline + ; filename=" + "STUDENT_REGISTRATION_FORM.pdf");
response.flushBuffer();
ByteArrayInputStream fileStream =
new ByteArrayInputStream(pdf);
//copy fileStream to response outputStream
3.5.4 StudentFormWrapper class
此class主要封装StdentPdfFormVO,及将所接收的WEB表格数据(StudentFormVO参数)转换成PDF表格在JAVA程序中对应的StudentPdfFormVO. StudentFormWrapper还定义了很关键的子程序。
getFieldValue.pdfFieldsMap class variable
此变量用于定义PDF模板表格field name与web表格field name的对应关系。
HushMap key: PDF模板中所定义的filed名, value: StudentPdfFormVO对应的filed名.
private static Map
PdfFieldsMap的初始化:
Static
{
pdfFieldsMap.put(“first_name”,“firstName”);
pdfFieldsMap.put(“last_name”,“lastName”);
pdfFieldsMap.put(“student_id”,“studentID”);
...
pdfFieldsMap.put(“student_tel”,“studentContact.phoneNumber”);
pdfFieldsMap.put(“studentt_cell”,“studentContact.cellPhoneNumber”);
pdfFieldsMap.put(“student_email”,“studentContact.email”);
...
}
getFieldValue() method
此method主要用JAVA Reflection特性以获得PdfFormVO的某一property值
注: StudentPdfFormVO file必须和PDF表格模板保持1:1的对应关系.
此外对JAVA嵌套定义的value object对象,我们必须用”.”来定义层次关系,
请参看ContactVO property : studentContact.cellPhoneNumber
功能:返回所接受的PDF表格的field(pdfFieldName)的值
参数: String pdfFieldName, StudentPdfFormVO pdfForm
返回数据类型: String
主要编程逻辑如下:
String fieldName = pdfFieldsMap.get(pdfFieldName);
String fieldVal = "";
...
try
{fieldVal = BeanUtils.getProperty(pdfForm, fieldName); }
...
return fieldVal;
3.6 PDFFormServiceSessionBean class
·populatePdfFields() method
功能:将所接受的StudentFormWrapper中所含的StudentPdfFormVO数据,填写到PDF表格模板中
参数: StudentFormWrapper wrapper, String templatePdf,返回数据类型: PdfReader,主要编程逻辑如下:
ByteArrayOutputStream tempOut = new ByteArrayOutputStream();
try
{
FileInputStream fin = new FileInputStream(new File(templatePdf));
PdfStamper stamp = new PdfStamper(new PdfReader(fin), tempOut);
AcroFields afields = stamp.getAcroFields();
for(Iterator iter = afields.getFields().keySet().iterator();
iter.hasNext();)
{ String fieldName = (String)iter.next();
String fieldValue = wrapper.getFieldValue(fieldName);
if(fieldName != null && fieldValue != null)
{afields.setField(fieldName, fieldValue); } }
stamp.setFormFlattening(true);
stamp.close();}
// catch block…
// finally block…
final PdfReader filledForm = new PdfReader(
new ByteArrayInputStream(tempOut.toByteArray()));
tempOut.reset();
return filledForm;
4总结
本文所讨论的方法是利用iText和JAVA reflection的特性来解决电子商务中一个普遍的功能需求.它具有代码优化,易于维护和移植等优点.我们只需修改和value object : StudentFormWrapper类中的pdfFieldsMap类成员变量即可.
参考文献:
[1]王勇.Java编程基础、实例与进级[M].北京.清华大学出版社,2011.
[2]王知强.管理信息系统[M].北京.哈尔滨工业大学出版社,2011.