使用poi操作word文档实现套打功能

使用poi操作word文档实现套打功能

本文目的是为了分享一个实现套打功能,但是不同于简单的word的文本替换而是采用poi对word的文本框就行操作实现的功能:

  • poi中各种jar的说明
  • 套打的实现思路
  • poi操作word文本框中的数据
  • *代码实现

POI各个jar的说明以及本文使用jar包

这里引用一个表格,只要看一下这个表格就知道自己需要哪个jar包了,本文中需要引入的是如下几个jar包(maven项目导入方式)。

<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.11</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.11</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.1</version>
        </dependency>

        <!-- word poi-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.9</version>
        </dependency>
项目价格
Computer$1600
Phone$12
Pipe$1

可以使用冒号来定义对齐方式:

ComponentApplication typeMaven artifactIdNotes
POIFSOLE2 FilesystempoiRequired to work with OLE2 / POIFS based files
HPSFOLE2Property Setspoi
HSSFExcel XLSpoiFor HSSF only, if common SS is needed see below
HSLFPowerPointPPTpoi-scratchpad
HWPFWord DOCpoi-scratchpad
HDGFVisio VSDpoi-scratchpad
HPBFPublisher PUBpoi-scratchpad
HSMFOutlook MSGpoi-scratchpad
OpenXML4JOOXMLpoi-ooxmlplus one of
poi-ooxml-schemasooxml-schemasOnly one schemas jar is needed, see below for differences
XSSFExcel XLSXpoi-ooxml
XSLFPowerPoint PPTXpoi-ooxml
XWPFWord DOCXpoi-ooxml
Common SSExcel XLS and XLSXpoi-ooxmlWorkbookFactory and friends all require poi-ooxml, not just core poi

套打实现思路

既然是套打,那么打印的文本一定有一个固定的格式,如果通过前端的html的css去控制,那么有个问题就是可能出现预留长度不够那么打印出来的排版就会出现问题,如果使用word文档的空格和tab去实现格式,然后用打印的文本去替换模板文件中的内容也同样会出现css一样的问题,那现在有一个方法就是将需要打印的内容放到word文档的文本框中,不管预留的长度是否足够,都不会出现整个布局乱套的问题,因为word文档中的文本框的布局是固定的。有可能有人会问,这么简单不就直接使用replaceText就可以替换了么?那就很可能是因为你小看了word的文本框。
这篇博客讲解了poi操作word,我认为讲的已经很详细了(但是没有对文本框的操作),再加上本文,那么你就掌握了poi对word操作的大部分技能。

POI操作word文本框

word文档其实也是一种特殊的xml文件,有其他的方法操作word文档的时候是先要将word转换成xml文档,然后在对xml文档进行操作。同样的,poi操作word文档内部实现其实也是讲word文档转换成了xml文档(只不过该步骤不需要我们手动去完成,poi帮助我们自动完成了)。既然要解析xml,所以本文中的代码就需要用到poi的解析xml的jar包了(ooxml-schemas)。既然poi是对xml文件操作,那文本框也一定是解析成了xml的一部分,我们只要找到文本框对应的xml标签,然后找到文本在使用替换文本的方式,是不是就可以实现文本框的套打功能了。那如何才能找到文本框的标签呢,那就是游标,poi操作word文档的游标便可实现。

代码如下 

File file = new File(filePath + File.separator + fileName);
        InputStream is = new FileInputStream(file);
        XWPFDocument doc = new XWPFDocument(is);
        List<XWPFParagraph> paragraphList = doc.getParagraphs();
        String startTime = home.getIntBd();
        String endTime = home.getIntDl();
        String apprTime = home.getApprDt();
        //开始日期
        Calendar calendar = Calendar.getInstance();
        Date bdDt = DateUtil.string2Date(startTime, DateUtil.FORMAT0);
        calendar.setTime(bdDt);
        String y1 = String.valueOf(calendar.get(Calendar.YEAR));
        String m1 = String.valueOf(calendar.get(Calendar.MONTH));
        String d1 = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
        //结束日期
        Date dlDt = DateUtil.string2Date(endTime, DateUtil.FORMAT0);
        calendar.setTime(dlDt);
        String y2 = String.valueOf(calendar.get(Calendar.YEAR));
        String m2 = String.valueOf(calendar.get(Calendar.MONTH));
        String d2 = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
        //提交日期
        Date apprDt = DateUtil.string2Date(apprTime, DateUtil.FORMAT0);
        calendar.setTime(apprDt);
        String y3 = String.valueOf(calendar.get(Calendar.YEAR));
        String m3 = String.valueOf(calendar.get(Calendar.MONTH));
        String d3 = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));

        String sb = “测试数据”;
        Field[] fields = home.getClass().getDeclaredFields();
        for (XWPFParagraph paragraph : paragraphList) {
            CTP ctp = paragraph.getCTP();
            List<CTR> object = ctp.getRList();
            for (int i = 0; i < object.size(); i++) {
                XmlObject xo = object.get(i);
                //在此处数据xo的字符串文本(xml文本),借助xml格式化工具格式化xml文本,然后通过标签移动游标找到需要替换的值
                XmlCursor cursor = xo.newCursor();
                if (cursor.isStart() || cursor.isAttr() || cursor.isProcinst()) {
                    cursor.toChild(1);
                    cursor.toChild(0);
                    cursor.toChild(0);
                    cursor.toChild(0);
                    cursor.toChild(8);
                    cursor.toChild(0);
                    cursor.toChild(0);
                    cursor.toChild(2);
                    cursor.toChild(0);
                    cursor.toChild(0);
                    cursor.toChild(1);
                    cursor.toChild(1);
                    String textValue = cursor.getTextValue();
                    switch (textValue) {
                        case "y1":
                            cursor.setTextValue(y1);
                            break;
                        case "m1":
                            cursor.setTextValue(m1);
                            break;
                        case "d1":
                            cursor.setTextValue(d1);
                            break;
                        case "y2":
                            cursor.setTextValue(y2);
                            break;
                        case "m2":
                            cursor.setTextValue(m2);
                            break;
                        case "d2":
                            cursor.setTextValue(d2);
                            break;
                        case "y3":
                            cursor.setTextValue(y3);
                            break;
                        case "m3":
                            cursor.setTextValue(m3);
                            break;
                        case "d3":
                            cursor.setTextValue(d3);
                            break;
                        case "abb":
                            cursor.setTextValue(abb);
                            break;
                        case "nb":
                            cursor.setTextValue(nb);
                            break;
                        case "no":
                            cursor.setTextValue(no);
                            break;
                    }

                    for (Field field : fields) {
                        field.setAccessible(true);
                        String name = field.getName();
                        Object ov = field.get(home);
                        String value = "";
                        if (null != ov) {
                            value = ov.toString();
                        }
                        if (null != textValue && textValue.equalsIgnoreCase(name)) {
                            cursor.setTextValue(value);
                            break;
                        }
                    }
                }
            }
        }
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName=" + home.getWrpNm() + "-" + fileName);
        OutputStream os = response.getOutputStream();
        doc.write(os);
        is.close();
        os.close();
 <w:r>
              <w:rPr>
                <w:noProof/>
              </w:rPr>
              <mc:AlternateContent>
                <mc:Choice Requires="wps">
                  <w:drawing>
                    <wp:anchor distT="0" distB="0" distL="114300" distR="114300" simplePos="0" relativeHeight="251680004" behindDoc="0" locked="0" layoutInCell="1" allowOverlap="1" wp14:anchorId="79BA2A69" wp14:editId="75F9FABF">
                      <wp:simplePos x="0" y="0"/>
                      <wp:positionH relativeFrom="column">
                        <wp:posOffset>4561840</wp:posOffset>
                      </wp:positionH>
                      <wp:positionV relativeFrom="page">
                        <wp:posOffset>2543175</wp:posOffset>
                      </wp:positionV>
                      <wp:extent cx="752475" cy="396240"/>
                      <wp:effectExtent l="0" t="0" r="0" b="3810"/>
                      <wp:wrapNone/>
                      <wp:docPr id="13" name="abb"/>
                      <wp:cNvGraphicFramePr>
                        <a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"></a:graphicFrameLocks>
                      </wp:cNvGraphicFramePr>
                      <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                        <a:graphicData uri="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
                          <wps:wsp>
                            <wps:cNvSpPr>
                              <a:spLocks noChangeArrowheads="1"/>
                            </wps:cNvSpPr>
                            <wps:spPr bwMode="auto">
                              <a:xfrm>
                                <a:off x="0" y="0"/>
                                <a:ext cx="752475" cy="396240"/>
                              </a:xfrm>
                              <a:prstGeom prst="flowChartProcess">
                                <a:avLst/>
                              </a:prstGeom>
                              <a:noFill/>
                              <a:ln>
                                <a:noFill/>
                              </a:ln>
                            </wps:spPr>
                            <wps:txbx>
                              <w:txbxContent>
                                <w:p w:rsidR="003A7D59" w:rsidRPr="008A7CBF" w:rsidRDefault="00ED4204" w:rsidP="00987190">
                                  <w:pPr>
                                    <w:jc w:val="center"/>
                                    <w:rPr>
                                      <w:rFonts w:ascii="宋体" w:hAnsi="宋体"/>
                                      <w:szCs w:val="21"/>
                                    </w:rPr>
                                  </w:pPr>
                                  <w:r w:rsidRPr="008A7CBF">
                                    <w:rPr>
                                      <w:rFonts w:ascii="宋体" w:hAnsi="宋体" w:hint="eastAsia"/>
                                      <w:szCs w:val="21"/>
                                    </w:rPr>
                                    <w:t>abb</w:t>
                                  </w:r>
                                </w:p>
                              </w:txbxContent>

重点:游标的移动规则,在打印出xml之后,需要将xml的文本copy出来借助xml格式化工具,格式化之后便可以分析游标的移动步骤,第一层是0,然后依次进入子标签。例如:有这么一段xml

 <w:r w:rsidRPr="008A7CBF">
  <w:rPr>
    <w:rFonts w:ascii="宋体" w:hAnsi="宋体" w:hint="eastAsia"/>
    <w:szCs w:val="21"/>
  </w:rPr>
  <w:t>abb</w:t>
</w:r>

现在我需要替换abb,那么游标移动的顺序则是
cursor.toChild(1);因为标签“w:rPr”的索引是0,“w:t”的索引则是1.在游标的移动分析中才是对文本框操作的重点,需要自己按照上面的规则测试分析。祝您好运。

已标记关键词 清除标记
相关推荐
简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除,从账户中取出amt,如果amt>账户余额抛出异常,一个实体Bean可以表示不同的数据实例,我们应该通过主键来判断删除哪个数据实例…… ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现 ,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口函数得到远程接口的引用,用远程接口的引用访问EJB。 EJB中JNDI的使用源码例子 1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上直接地使用它,但是它的主要作用是供程序使用的。本规范尝试满足大型主机、微型主机、个人工作站、和TACs 的不同需求。例如,容易实现协议的设计。 Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密   Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。   设定字符串为“张三,你好,我是李四”   产生张三的密钥对(keyPairZhang)   张三生成公钥(publicKeyZhang)并发送给李四,这里发送的是公钥的数组字节   通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 同上 java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数的因子 如题。 Java生成密钥的实例 1个目标文件 摘要:Java源码,算法相关,密钥   Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从文件中得到公钥编码的字节数组、如何从字节数组解码公钥。 Java数据压缩与传输实例 1个目标文件 摘要:Java源码,文件操作,数据压缩,文件传输   Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲
一、Server-U的安装 1、安装Server-U英文版 在Server-U安装文件所在目录,执行安装文件(ServUSetup.exe),出现以下界面,根据屏幕提示直至安装完成(安装完成后,在系统托盘上,将出现Server-U的小图标)。 2、Server-U英文版的汉化 1)先结束Server-U的守护进程 在系统托盘中Server-U的小图标上按右键,选择退出 2)安装汉化包 执行汉化包目录下的汉化文件(注意不要装上网助手)。 3、Server-U的注册 1) 先复制注册文件到Server-U的安装目录(可能为D:\Program files\Serv-U) 2)执行该注册文件 二、Server-U的配置和管理 1、启动Server-U 依次但击 [开始菜单/Serv-U FTP Server/Tray Monitor], 执行后在系统托盘上,将出现Server-U的小图标 2、启动Server-U管理员程序 在系统托盘中Server-U的小图标上按右键,选择[启动管理员] 启动后可能会出现配置向导,单击[取消]按钮取消 3、新建域 新建一个名为JSJX的域(域IP地址不用指定,域名输入JSJX,其他默认值即可) 4、新建用户 新建匿名用户,用户名为:anonymous, 没有密码,主目录可设为F:\FTPROOT 注意,匿名用户名必须为anonymous,匿名用户在登陆时不必输用户名和密码,匿 名一般只具有浏览和下载权限 新建一个名为ftpadmin的用户,密码与用户名相同,主目录也可设为F:\FTPROOT 此用户将来可给予较多的权限 说明:主目录也可根据需要设,但最好设为F:\FTPROOT,将来只要把其他目录映 射为该目录下的虚拟目录即可。 4、设置用户权限 选中一个用户,点击右边的[目录访问]卡片,再在下面的目录列表框中,选择一个目录,可设置该用户对该目录的访问权限,用户可以对不同目录拥有不同权限。注意:设置完成后请单击 [应用]按钮 使设置生效 5、虚拟目录设置 设置虚拟目录需要经过以下两个步骤来完成 1)在[JSJX域]中单击[设置],在右边选中[常规]卡片,再单击[添加]按钮,按提 示完成设置操作,设置完成后的结果如下图所示: 2)选中一个用户,单击右下的[添加]按钮,添加要映射的目录,如下图所示: 6、其它设置 下面的设置,请自己思考如何完成  最大上传/下载速度的设置  同时连接的最大用户数设置  磁盘配额的设置  消息设置  端口号设置  IP访问规则设置  超时连接时间设置 六、在客户机上安装LeapFTP 1、安装LeapFTP 2、注册 七、访问FTP服务器 1、使用匿名用户下载 2、使用ftpadmin上传和下载 八、使用LeapFTP往Web站点上传网页和从Web站点下载网页 把WWW服务器的主目录映射为FTP服务器的一个虚拟目录,即可在远离WWWW服务器的地方维护WWW服务器上的网页。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页