Java 操作Word 模板实现动态数据输出


2010. 11 1 引言 随着信息技术尤其是数据库技术和网络技术的进步, 很多 企事业单位管理内部数据的手段和方式都发生了重大变化。 绝 大部分单位将数据存储在数据库中, 并将某些公共信息在网上 发布。 然而在实际工作中, 有时又需要将数据库中的数据以某 种 常 见 的 文 件 (如 Word) 形式进行展示或编辑。 比 如 : 在 人事部门的日常工作中, 有时需要将一部分职工信息提取出 来 , 然后按照某种固定的 Word 版 式 打 印 输 出 , 或 在 网 上 提 供自由下载, 如图 1 所示。 若要完成以上所述的工作, 需 要 进 行 以 下 操 作 : 其 一 , 按照特定要求提取数据库中的数据; 其二, 读取 Word 模板; 其三, 将提取的数据填充到 Word 模 板中, 生成 Word 文件。 那 么 , 如何实现数据库数据动态填充 Word 模 板 文 件 , 从而实现数据按照某种特定格式的动态输出呢? 本 文 将 以 NEATBEANS6.1 为 开 发 环 境 , 具 体 讨 论 在 Java 环 境 下 读 取 Word 模板, 进行 数 据 填 充, 并 通 过 JSP 提 供 Word 文 件 下 载 的基本方法。 2 关键术语解析 首先介绍本文涉及的几个关键术语(Word 模板、JSF 和 Net- Beans)。 Word 模 板 本 文 所 讨 论 Word 模板是事先编辑好的一个 RTF 格式 Word 文件, 该文件内部可以包含表格。 与普通 Word 文件的不同之处在于其内部一般包含一些特殊的符号 (如:$或 &),由这些符号限定的部分可以被数据库中的数据替换,一旦 替换完成,Word 模板文件就成为具有实际数据的普通 Word 文 件了。 文中涉及到的 Word 模板如图 2 所示。 JSF 是由 Sun 公司推出的一种用来开发 Web 应用程序的技 术, JSF 和传统的 Web 技术有着本质上的差别。 JSF 提供了事 件驱动的页面导航模型, 该模型使应用程序开发人员能够设计 应用程序的页面流, 所有的页面流信息都定义在 JSF 的配置文 件 “faces-config.xml” 中, 而并非硬编码在应用程序中, 这在 很大程度简化了应用程序的开发。 NetBeans 是由 Sun Microsystems 公司建立的开放源代码的 软 件 开 发 工 具 , 内 嵌 了 GlassFish 和 Tomcat 服 务 器 以 及 JSF、 Struts 等多种 Web 软件开发框架, 可用于多种不同类型软件的 开发,尤其适用于基于 Java 平台的 Web 程序开发。 3 系统目标及运行界面 本系统的目标是: 用户通过下拉列表选择部门数据, 然后 单击 “创建名单” 命令后, 系统自动生成数据, 并将数据填充 到 Word 模板中生成 Word 文件, 提供给用户下载。 当用户单 Java 操作 Word 模板实现动态数据输出 刘永立 周 莉 摘 要: 利用 JSF 框架, 在 NETBEANS6.1 开发环境中, 构建出了一个简单的动态数据输出系统。 以该系统为蓝本, 具体给出了 Java 语言读取 Word 模板文件的实现方法; 利用 MySQL 数据库中的 数据填充 Word 模板动态输出数据的实现方法及 JSP 提供 Word 文件下载的基本方法等。 关键词: JSF; NETBEANS; Word 模板 46 2010. 11 击下载图标后, 出现 “文件下载/文件打开” 提示框。 图 3 是 用户选择打开生成的 Word 文件之后的效果。 为了便于论述以及系统的推广, 笔者在设计系统的过程中 力求使其简单、 实用, 读者只需在此基础上稍作修改, 即可扩 充系统的功能并将其应用于实际情况。 4 程序的设计 4.1 数据库 系统采用 MySql Server 数据库管理系统。 首先建立一个数 据库, 名称是 “mydb”, 然后在数据库中建立一个数据表 “em- ployee”, 并输入几条记录。 数据表 “employee” 的定义如下: USE `mydb`; CREATE TABLE `employee` ( `ID` varchar(30) NOT NULL default '' COMMENT' 职工 ID', `name` varchar(60) NOT NULL default ' 姓名 ' COMMENT' 姓名 ', `sex` varchar (4) NOT NULL default ' 男 ' COMMENT' 性别 ', `departmentID` varchar(11) default NULL COMMENT' 部门 ID', `departmentName` varchar (30) default NULL COMMENT' 部门名称 ', PRIMARY KEY (`ID`) ); 4.2 程序的配置 首先, 启动 NetBeans6.1 开发环境, 建立一个 Web 应用程 序, 命名为 “WordModelApp”。 创建过程中注意: Web 服务器 选 择 采 用 “GlassFish”; Web 程 序 框 架 选 择 采 用 “JavaServer Faces”; 将默认生成的欢迎页面重命名为 “index.jsp”。 Web 程序创建完成后, 在程序根目录下创建两个文件夹 “downLoad”、“model”, 并将 Word 模板文件 “模板.rtf” 存放 在 “model” 文件夹中, 文件夹 “downLoad” 用来存放临时下载 文件。 Web 程序的文件夹结构以及包含的库文件如图 4 所示。 然 后, 打 开 Web.XML 配 置 文 件 , 在 标 签之间添加如下代码: Faces Servlet javax.faces.webapp.FacesServlet 1 Faces Servlet /faces/* faces/index.jsp 最后, 打开 “faces-config.xml” 文件, 在标签 和之间添加如下代码: 数据库 47 2010. 11 manageReport myClass.ManageReport session db myClass.DbBean session 至此, 完成系统的创建和配置工作。 当然, 配置工作也可 以在系统开发过程中随时进行补充和修改。 4.3 页面设计 本示例程序只需要一个 JSP 页面 “index.jsp”。 该页面中主 要包含一个 selectOneMenu 下拉列 表 控 件、 一 个 commandLink 命令控件, 一个 outputLink 控件和若干个 outputLabel 信息输出 控件。 另外, 为了使得这些控件能够正常工作, 需要在页面中 引进 JSF 的标签库。“index.jsp” 页面的代码如下: <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> JSP 操作 Word 模板


用户单击页面“index.jsp”中的“创 建 名 单”命 令 后,由 后 台 JavaBean “manageReport”的 “createRecords”方 法 完 成 数 据 的 检 索并将检索到的数据填充到 Word 模 板 中 , 生 成 可 供 下 载 的 Word 文件。 Word 文件的路径和文件名分别由“manageReport”的 “targetPath”和“targetFile”两个属性提供。 特别注意,在定义后台 JavaBean 的属性时一定要同时定义好 GET 方法和 SET 方法,详 细内容参见文后面的代码部分。 4.4 代码 在系统中定义一个 Java 包:“myClass”, 在该包中定义 3 个 Java 类 文 件, 分 别 是:“Employee.java”,“ManageReport. java”,“ DbBean.java”, 如 表 1 所 示 。 限 于 篇 幅 , 只 给 出 “ManageReport.java”,“DbBean.java” 类中的核心代码。 类“ManageReport.java”的核心代码如下: package myClass; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; 48 2010. 11 import java.io.InputStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.faces.event.ValueChangeEvent; import javax.servlet.ServletContext; public class ManageReport { //局部变量定义 private String selectedDepartmentID = ""; private boolean createSuccess = false; private String targetFile = ""; private String targetPath = "/WordModelApp/downLoad/"; /* 以下 getAppPath 函数的作用:获取程序真实根路径 */ public String getAppPath(){ String appRealPath = ""; FacesContext context = FacesContext.getCurrentIn- stance(); appRealPath = ((ServletContext) context.getExternal- Context().getContext()).getRealPath("/"); return appRealPath; } /* 以下 departmentMenuListener 函数的作用: 是下拉列 表控件的监听函数 */ public void departmentMenuListener(ValueChangeEvent event) { this.createSuccess = false; String myParam = (String) event.getNewValue(); this.selectedDepartmentID = myParam; } /* 以下 createRecords 函数的作用:接收用户申请,搜索数 据库,将数据填充到 Word 模板中。 本函数是系统核心函数,需 要调用其他几个函数以便完成记录的创建工作。 */ public void createRecords(ActionEvent event) { //变量 map 用来暂存数据库数据。 HashMap map = new HashMap(); map.put("departmentID", this.getSelectedDepartmen- tID()); String id = ""; String name = ""; String sex = ""; //查询数据库,将记录暂存在 employees 变量中 ArrayList employees = new DbBean().getEmployees (this.getSelectedDepartmentID()); if (employees == null || employees.size () <= 0) {re- turn;} int count = employees.size(); //将记录从 employees 变量转存到 map 变量中,为填充 //Word 模板做准备 for (int i = 1; i <= count; i++) { Employee e = (Employee) (employees.get(i - 1)); id = e.getId(); name = e.getName(); sex = e.getSex(); map.put("id" + i, id); map.put("name" + i, name); map.put("sex" + i, sex); }//end of for /**** 不妨假定当前 Word 模板中最多存储 25 条记录。 若 employees 中记录不足 25 条,可将 map 变量其他位置设置 为空 ****/ for (int j = count + 1; j <= 25; j++) { map.put("id" + j, ""); map.put("name" + j, ""); map.put("sex" + j, ""); } this.targetFile = getSelectedDepartmentID() + ".rtf"; //targetFile 是填充目标文件 //sourceFilename 是源文件,即将要填充的模板文件 String sourceFilename = this.getAppPath() + "/model/ 模板.rtf"; //将 map 变量中的数据写入模板中,并存储在指定路径下 replaceModel(this.getAppPath() + "downLoad/" + tar- getFile, sourceFilename, map); this.setCreateSuccess(true); //设置创建成功标志 } /* 以下 replaceModel 函数的作用: 将 map 中的数据写入 模板文件 sFileName 中, 并将改写后的数据存储在 tFileName 文件中 */ public void replaceModel(String tFileName, String sFile- Name, HashMap data) { String sourcecontent = ""; InputStream ins = null; try { ins = new FileInputStream(sFileName); byte[] b = new byte[1024]; if (ins == null) { System.out.println("源 模 板 文 件 不 存在");} int bytesRead = 0; while (true) { //读取源文件,将其暂时存储变量 b 中 bytesRead = ins.read(b, 0, 1024); if (bytesRead == -1) {System.out.println("读取模板 文件结束"); break; } //将读取的信息转换为字符串,暂存到变量 sourcecontent 中 sourcecontent += new String(b, 0, bytesRead); } 数据库 49 2010. 11 } catch (Exception e) {e.printStackTrace();} //填充 Word 模板文件开始 String targetcontent = ""; String oldText = ""; Object newValue; try { Iterator keys = data.keySet().iterator(); while (keys.hasNext()){ oldText = (String) keys.next();//获取模板数据 newValue = data.get(oldText);//获取替换数据 String newText = (String) newValue; //将数据转换为字符串 //用字符串 newText 替换 sourcecontent 中的模板数 //据 oldText,并暂存到 targetcontent 中 targetcontent = replaceRTF (sourcecontent, oldText, newText); }//while 循环结束 } catch (Exception e) {e.printStackTrace();} //填充 Word 模板文件结束 //以下操作将填充结果 targetcontent 输出到目标文件 tFileName try { FileWriter fw = new FileWriter(tFileName, true); //创建目标文件 PrintWriter out = new PrintWriter(fw);//创建输出流 if (targetcontent.equals("") || targetcontent == null) { //若没有填充任何内容,则原样输出到目标文件 out.println(sourcecontent); } else { //若成功进行了填充,则将填充结果输出到目标文件 out.println(targetcontent); } out.close();fw.close();//关闭输出流和文件 } catch (IOException e) {e.printStackTrace();} }//end of replaceModel /* 以 下 replaceRTF 函 数 的 作 用 : 完成字符串的整理和修正 */ public String replaceRTF (String content, String mark- Content, String replaceContent){ String rc = strToRtf(replaceContent); //将 replaceContent 转换为 RTF 格式 String target = ""; markContent = "$" + markContent + "$"; //$是模板中的特殊标记,用来标记被替换的内容 //进行字符串替换;用 rc 替换 markContent target = content.replace(markContent, rc); return target; }//end of replaceRT /* 以 下 strToRtf 函 数 的 作 用 : 将 字 符 串 content 转 换 为 RTF 格式 */ public String strToRtf(String content){ try {content = new String(content.getBytes(), "gbk");} catch (UnsupportedEncodingException e) {e. printStackTrace();} char[] digital = "0123456789ABCDEF".toCharArray(); StringBuffer sb = new StringBuffer(""); byte[] bs = null; bs = content.getBytes(); int bit; for (int i = 0; i < bs.length; i++) { bit = (bs[i] & 0x0f0) >> 4; sb.append("\\'"); sb.append(digital[bit]); bit = bs[i] & 0x0f; sb.append(digital[bit]); }//end of for return sb.toString(); } /* 局部变量的 GET 和 SET 函数 定义开始 */ public boolean isCreateSuccess () { return createSuc- cess;} public void setCreateSuccess (boolean createSuccess){ this.createSuccess = createSuccess;} public String getTargetFile() {return targetFile;} public void setTargetFile(String targetFile) {this.targetFile = targetFile;} public String getSelectedDepartmentID () {return se- lectedDepartmentID;} public void setSelectedDepartmentID(String selectedDe- partmentID) {this.selectedDepartmentID = selectedDepartmentID;} public String getTargetPath() {return targetPath;} public void setTargetPath(String targetPath) {this.target- Path = targetPath;} /* 局部变量的 GET 和 SET 函数 定义结束 */ }// 类 ManageReport 定义结束 下面是类“DbBean.java”的核心代码: package myClass; import java.sql.*; import java.util.*; import javax.faces.model.SelectItem; public class DbBean { //局部变量定义 String jdbcDriver = "com.mysql.jdbc.Driver"; public String dbUrl; Connection connection; /* 以下函数是创建数据库连接 */ public void CreateConnection(){ try {Class.forName(jdbcDriver).newInstance(); connection = DriverManager.getConnection ("jdbc: mysql://localhost:3306/mydb", "root", "root"); } catch (Exception e) { System.out.println(e.getMessage 50 2010. 11 ());} }//end of CreateConnection /* 以下函数是释放数据库连接 */ public void CloseConnection(){ try { this.connection.close();} catch (Exception e) { System.out.println (e.getMes- sage());} }//end of CloseConnection /* 以下函数返回数据库中部门列表 */ public List getDepartmentList(){ List departmentNameList = new ArrayList(); try { //建立数据连接,并为查询做必要的准备 this.CreateConnection(); Statement s = this.connection.createStatement(); ResultSet res; String sql = "select DISTINCT departmentID,depart- mentName from employee"; res = s.executeQuery(sql); //将部门列表暂存在变量中 if (res == null) { return departmentNameList;} for (; res.next();) {departmentNameList.add(new Selec- tItem(res.getString(1), res.getString(2)));} res.close();//关闭数据连接 s.close(); this.CloseConnection(); } catch (Exception e) { System.out.println (e.getMes- sage());} return departmentNameList; }//end of getDepartmentList /* 以下函数返回数据库中职工列表 */ public ArrayList getEmployees(String departmentID){ ArrayList employeeList = new ArrayList(); try { //建立数据连接,并为查询做必要的准备 this.CloseConnection(); this.CreateConnection(); Statement s = this.connection.createStatement(); ResultSet res; String sql = "select * from employee where depart- mentID=" + "'" + departmentID + "'"; res = s.executeQuery(sql); if (res == null) { return employeeList;} //将职工列表暂存在变量中 for (; res.next();){ Employee e = new Employee(); e.setId(res.getString("ID")); e.setName(res.getString("name")); e.setSex(res.getString("sex")); e.setDepartmentID(res.getString("departmentID")); e.setDepartmentName (res.getString ("department- Name")); employeeList.add(e); }//end of for //关闭数据连接 res.close(); s.close(); this.CloseConnection(); } catch (Exception e) { System.out.println(e.getMessage ());} return employeeList; }//end of getEmployees }//类 DbBean 定义结束 5 系统的发布与运行 一般情况下, 利用 NeatBeans6.1 开发工具生成的 Web 程 序会自动保存在系统根目录下的 dist 子文件夹中, 其扩展名为 “war”。 启动 GlassFish Web 服 务 器, 然 后 在 Web 服 务 器 的 管 理 控 制 台 中 单 击 “部 署 …” 按 钮 (管理控制台可以在 Neat- Beans 环境下启动, 也可以在浏览器中输入 http://localhost:4848 来启动), 即可将生成的程序文件 “WordModelApp.war” 部署 到服务器中。 若程序部署成功, 且 Web 服务器 GlassFish v2 和数据库系 统 mysql server 5.0 正常运行, 数据库定义完成后, 任选下面一 种方式运行系统即可: 方式一: 在 NETBEANS 开发环境中选定项目 “WordMode- lApp”, 单击 【F6】。 方 式 二 : 在浏览器地址栏中输入: http://localhost:8080/ WordModelApp/。 6 结语 基于 NeatBeans6.1 开发环境, 一方面讨论了基于 JSP 技术 的 Web 程序开发的主要步骤,另一方面针对“Java 操作 Word 模 板”的技术难点进行了仔细分析并给出了核心代码。 希望通过本 文的论述,能够抛砖引玉,为读者在设计与开发基于JSP 技术的 Web 程序时提供参考。 参考文献 [ 1] http://www.mastertheboss.com/en/web -interfaces/124 -jboss - RichFaces-tutorial.html. [2] http://www.onjava.com/pub/a/onjava/2005/07/13/jsfupload.html,2005. [3] The Java EE 5 Tutorial. http://java.sun.com/javaee/5/docs/tu- torial/doc/index.html. [4] 刘永立, 白地动. 基于 JAVA 平台的网上成绩管理系统的 设计与实现[J]. 中国教育信息化, 2010,1:48~52. [5] 刘永立. B/S 结构教学管理系统的设计 [J] . 电脑编程技巧 与维护, 2009,18:121~123. 数据库 51
还剩5页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享pdf获得金币 ] 3 人已下载

下载pdf

pdf贡献者

allen3106

贡献于2011-12-31

下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf