花了一个下午的时间。磨出来的一个东西..感觉好不错。。拿来分享下。。哈哈。。
?
大体功能是:根据Excel的内容和Word模板的内容生产Word文档
?
?业务1:excle 有 1000 个人..需要打印出 1000 个人的通知书。(单个的打印、分开管理)
?业务2:excle 有 1000 个人..需要连续打印出 1000 个人的通知书。
?
大体思路:
?
?? *??? 1、定义一个标签格式..本例中是:$(xxx)
?? *??? 2、在 word 中编辑好模板样式..另存为html模板。(也可以存为其他格式。但是注意编码问题。不然会乱码)
?? *??? 3、读取 excel 中的内容并封住为一个容器: list<map<String,String>>
?? *??? 4、读取html模板,并根据标签替换内容。再重新写个文件。
?? *???
?
开始都一路顺风...后面再连续的分页word文档的时候。遇到麻烦了.开始以为只要在每次循环的地方加上word的分页符就好了。。是的。思路是没错。。问题就出在了怎么加。。。。下面我在唠叨下我的经过:
?
?????我一次就是直接读取模板..替换..在循环的地方加上分页代码..结果失败了...效果是word..只看到了excel 第一条记录。开始我还以为是我的代码写错了。。后面在跟踪断点、查看源码才发现..其实循环的没错.....错在每次读模板的时候都有html的头部.等等代码....于是我仔细的查看了单个文件的源码。
?
???? 当我们把 word 模板另存为 html 的时候。。源码大致分为如下格式:
???? 头部:
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40"> <head> ···································省略
?
?? 中间:
??
<body lang=ZH-CN style='tab-interval:21.0pt;text-justify-trim:punctuation'> <div class=Section1 style='layout-grid:15.6pt'> <p class=MsoNormal align=center style='text-align:center'><b style='mso-bidi-font-weight: normal'><span lang=EN-US style='font-size:14.0pt;font-family:黑体'><o:p> </o:p></span></b></p> ·························省略
</div><!-- 我故意把这个 结束的 div 分开..是为了让你们注意到..哈哈..后面还讲到.. --->
?
?? 底部
??
</body> </html>
?
??? 嘿嘿...经过这么仔细的分析...我估计这下没问题了...于是我把 模板分为 三块...只循环中间的 部分.....满心期待的结果出来。。结果我打开一看 。。。。所有的数据都在一个word里面是...是没错....可是没分页...本来第二页的内容在第一页尾巴上面...
???? 额。。我开始还怀疑是不是 分页代码 写错了。。。我就手动下了一个测试word 另存为html 加上分页代码。在还原回 word? ...结果是 分页的....郁闷中.....反复的思考刚才的操作...是不是我的?分页代码放错地方了.....
?
??? 于是我在测试了下。。这次我把 分页代码 放到了 中部代码的 div 中间。。。O(∩_∩)O哈哈~...结果分页成功..
?
最后我在模板中插入了一个分页符(是分页符不是回车到第二页啊)
?
大体思路:
???*??? 1、定义一个标签格式..本例中是:$(xxx)
?? *??? 2、在 word 中编辑好模板样式..另存为html模板。但是这里要注意,我们要打开 html 的源码,
?? *?????? 分解源码为:头部和中间、底部等三部分。(底部模板简单。所以我就写在代码中了),
?? *??? 3、读取 excel 中的内容并封住为一个容器: list<map<String,String>>
?? *??? 4、读取html头部和中间、底部模板,并根据标签替换中间模板内容。替换完后,在加底部文件。重写文件。生成一个连续的有分页符的word
?? *???
?
? 下面的我的代码,附件中我也将上传我的类和文件:
?? excel操作类:
?
package cn.xsbiz.main; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import jxl.Cell; import jxl.Sheet; import jxl.Workbook; import jxl.read.biff.BiffException; /** * 业务:java读取Excel * * * @author 妞见妞爱 * */ public class OperatorExcel { /** * 读取Excel文件的内容 * * @param file * 待读取的文件 * @return */ public static String readExcel(File file) { StringBuffer sb = new StringBuffer(); Workbook wb = null; try { // 构造Workbook(工作薄)对象 wb = Workbook.getWorkbook(file); } catch (BiffException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (wb == null) return null; // 获得了Workbook对象之后,就可以通过它得到Sheet(工作表)对象了 Sheet[] sheet = wb.getSheets(); if (sheet != null && sheet.length > 0) { // 对每个工作表进行循环 for (int i = 0; i < sheet.length; i++) { // 得到当前工作表的行数 int rowNum = sheet[i].getRows(); for (int j = 0; j < rowNum; j++) { // 得到当前行的所有单元格 Cell[] cells = sheet[i].getRow(j); if (cells != null && cells.length > 0) { // 对每个单元格进行循环 for (int k = 0; k < cells.length; k++) { // 读取当前单元格的值 String cellValue = cells[k].getContents(); sb.append(cellValue + "\t"); } } sb.append("\r\n"); } sb.append("\r\n"); } } // 最后关闭资源,释放内存 wb.close(); return sb.toString(); } /** * * 读取 excel 返回 List<Map> * * @param file --待读取的文件 * @return */ public static List<Map<String, String>> readExcelReList(File file) { Workbook wb = null; try { // 构造Workbook(工作薄)对象 wb = Workbook.getWorkbook(file); } catch (BiffException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (wb == null) return null; // 获得了Workbook对象之后,就可以通过它得到Sheet(工作表)对象了 Sheet[] sheet = wb.getSheets(); List<Map<String, String>> list = new ArrayList<Map<String, String>>(); if (sheet != null && sheet.length > 0) { // 对每个工作表进行循环 for (int i = 0; i < sheet.length; i++) { // 得到当前工作表的行数 int rowNum = sheet[i].getRows(); for (int j = 0; j < rowNum; j++) { // 得到当前行的所有单元格 Cell[] cells = sheet[i].getRow(j); if (cells != null && cells.length > 0) { // 因为只需要单元格的部分内容...所以指定读取当前单元格的值 Map<String, String> map = new HashMap<String, String>(); String cellValue = cells[0].getContents().trim(); map.put("town", cellValue); cellValue = cells[1].getContents().trim(); map.put("village", cellValue); cellValue = cells[2].getContents().trim(); map.put("name", cellValue); cellValue = cells[11].getContents().trim(); map.put("tel", cellValue); cellValue = cells[10].getContents().trim(); map.put("dw", cellValue); cellValue = cells[12].getContents().trim(); map.put("money", cellValue); list.add(map); } } } } // 最后关闭资源,释放内存 wb.close(); return list; } public static void main(String[] args) { OperatorExcel excel = new OperatorExcel(); File filepath = new File("f://test//test.xls"); String str = excel.readExcel(filepath); System.out.println(str); } }
?
?
? word操作类:
?
package cn.xsbiz.main; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * 业务:java读取word的模板内容动态生成word * * 思路: * 先用word编辑好模板格式再另存为html;在读取html的内容进行替换。最后保持为word格式 * * 开始我也另存为word自带的模板老是乱码,,不知道什么原因。。 * 后面改为xml 乱码问题是没了。。但是提示xml内容错误打不开。。 * 最后不得不改为html。测试成功 * * * 标签:$(xxx) * * @author 妞见妞爱 * */ public class OperatorWord { /** * 替换文档的可变部分 * * @param content * 原来的文本 * @param markersign * 标记符号 * @param replacecontent * 替换的内容 用replacecontent替换markersign * @return */ public String replaceModel(String content, String markersign, String replacecontent) { String rc = replacecontent; String target = ""; markersign = "$(" + markersign + ")"; target = content.replace(markersign, rc); return target; } /** * * 生产单个的word 文档 * * @param inputPath --模板的路径 * @param outPath --生成文档的路径 * @param data --传入的数据 */ public void replaceTemplate(String inputPath, String outPath, Map<String, String> data) { /* 字节形式读取模板文件内容,将结果转为字符串 */ String sourcecontent = readTemplate(inputPath); /* 修改变化部分 */ String targetcontent = ""; String oldText = ""; Object newValue; /* 结果输出保存到文件 */ try { Iterator keys = data.keySet().iterator(); int keysfirst = 0; while (keys.hasNext()) { oldText = (String) keys.next(); newValue = data.get(oldText); String newText = (String) newValue; if (keysfirst == 0) { targetcontent = replaceModel(sourcecontent, oldText, newText); keysfirst = 1; } else { targetcontent = replaceModel(targetcontent, oldText, newText); keysfirst = 1; } } //System.out.println("=======输出========="); //System.out.println(targetcontent); FileWriter fw = new FileWriter(outPath, true); PrintWriter out = new PrintWriter(fw); if (targetcontent.equals("")) { out.println(sourcecontent); } else { out.println(targetcontent); } out.close(); fw.close(); System.out.println(outPath + " 生成文件成功"); } catch (IOException e) { e.printStackTrace(); } } /** * 读取模板的内容 * * @param inputPath --模板的路径 * @return */ public String readTemplate(String inputPath){ /* 字节形式读取模板文件内容,将结果转为字符串 */ String sourname = inputPath; StringBuffer sourcecontent = new StringBuffer(); InputStream ins = null; try { ins = new FileInputStream(sourname); byte[] b = new byte[2048];// 可以修改[2048]提高对于文件的读取速度; int bytesRead = 0; while (true) { bytesRead = ins.read(b, 0, 2048); if (bytesRead == -1) {// end of InputStream break; } sourcecontent.append(new String(new String(b, 0, bytesRead).getBytes(), "GBK")); // 转换字符串的 编码格式 } // sourcecontent = new String(sourcecontent.getBytes(),"UTF-8"); //System.out.println(sourcecontent); } catch (Exception e) { e.printStackTrace(); } return sourcecontent.toString(); } /** * * 生产一个内容连续的 word 文档 * * @param topPath --模板的头部内容路径 * @param inputPath --模板的主体内容路径 * @param outPath --生成的文件路径 * @param list --传入的数据 */ public void replaceTemplateAll(String topPath,String inputPath, String outPath, List<Map<String, String>> list) { /* 字节形式读取模板文件内容,将结果转为字符串 */ String stringTop = readTemplate(topPath); String stringCenter = readTemplate(inputPath); StringBuffer targetcontent = new StringBuffer(); targetcontent.append(stringTop); /* 修改变化部分 */ String tempcontent = ""; String oldText = ""; Object newValue; /* 结果输出保存到文件 */ try { //日期 SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日"); String date = sdf.format(new Date()); for(int i=0;i<list.size();i++){ Map<String, String> data = list.get(i); data.put("date", date); Iterator keys = data.keySet().iterator(); int keysfirst = 0; while (keys.hasNext()) { oldText = (String) keys.next(); newValue = data.get(oldText); String newText = (String) newValue; if (keysfirst == 0) { tempcontent = replaceModel(stringCenter, oldText, newText); keysfirst = 1; } else { tempcontent = replaceModel(tempcontent, oldText, newText); keysfirst = 1; } } targetcontent.append(tempcontent); } //模板的尾部 targetcontent.append("</div></body></html>"); //System.out.println("=======输出========="); //System.out.println(targetcontent.toString()); FileWriter fw = new FileWriter(outPath, true); PrintWriter out = new PrintWriter(fw); if (targetcontent.length() == 0) { out.println("没有内容!"); } else { out.println(targetcontent); } out.close(); fw.close(); System.out.println(outPath + " 生成文件成功"); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMddHHmmss"); Date current = new Date(); String targetname = sdf.format(current)+".doc"; OperatorWord word = new OperatorWord(); // ***************************************** // 利用HashMap读取数据库中的数据 HashMap map = new HashMap(); map.put("username", "杨攀"); map.put("sex", "男"); map.put("idcard", "431228198701174625"); // ****************************************** word.replaceTemplate("F://test//test.htm", "F://test//" + targetname, map); } }
??
? 测试类(把excel转为word):
?
?
package cn.xsbiz.main; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; import sun.java2d.pipe.SpanShapeRenderer.Simple; /** * * 功能:读取 excel 的内容根据wrod模板动态生产 wrod 文档 * * 标签:$(xxx) * * author 妞见妞爱 * */ public class RxlsWdocMain { public static void main(String[] args) { OperatorWord word = new OperatorWord(); OperatorExcel excel = new OperatorExcel(); File filepath = new File("f://xsjsj//tmp001.xls"); List<Map<String, String>> list = excel.readExcelReList(filepath); System.out.println("共:"+list.size()); /* * **************************************************************** * 下面的循环生产单个 word 的代码.. * * 业务:excle 有 1000 个人..需要打印出 1000 个人的通知书。(单个的打印、分开管理) * * 功能:如果excle 中有 1000条 记录,那么就生成 1000 个word * * 思路: * 1、定义一个标签格式..本例中是:$(xxx) * 2、在 word 中编辑好模板样式..另存为html模板。(也可以存为其他格式。但是注意编码问题。不然会乱码) * 3、读取 excel 中的内容并封住为一个容器: list<map<String,String>> * 4、读取html模板,并根据标签替换内容。再重新写个文件。 * * **************************************************************** * */ StringBuffer sb = new StringBuffer(); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日"); for (int i = 0; i < list.size(); i++) { Map<String, String> map = list.get(i); sb.append(map.get("town")).append("-").append(map.get("village")).append("-").append(map.get("name")); map.put("date", sdf.format(date)); word.replaceTemplate("f://xsjsj//template.htm", "f://xsjsj//doc//"+sb.toString()+".doc", map); sb.setLength(0); } /* * **************************************************************** * 下面的一个内容连续的 word 的代码.. * * 业务:excle 有 1000 个人..需要连续打印出 1000 个人的通知书。 * * 功能:如果excle 中有 1000条 记录,那么就生成一个 1000 也的 word, * * 思路: * 1、定义一个标签格式..本例中是:$(xxx) * 2、在 word 中编辑好模板样式..另存为html模板。但是这里要注意,我们要打开 html 的源码, * 分解源码为:头部和中间、底部等三部分。(底部模板简单。所以我就写在代码中了), * 3、读取 excel 中的内容并封住为一个容器: list<map<String,String>> * 4、读取html头部和中间、底部模板,并根据标签替换中间模板内容。替换完后,在加底部文件。重写文件。生成一个连续的有分页符的word * * * **************************************************************** * */ //word.replaceTemplateAll("f://xsjsj//tem_top.htm","f://xsjsj//tem_center.htm", "f://xsjsj//doc2//jisj.doc", list); } }
?
?
? 真是辛苦...我发现些文档比代码辛苦多了。。。。哈哈。。。我在上传工程和测试的文档。。。。
?
? 需要的下载啊。。。里面的测试文件数据均为测试数据。。如果运行程序..注意文件的名称修改一致。。。。
?
? 注意路径问题。。我没有判断啊。。O(∩_∩)O哈哈~