docx4j操作实战记录-1

利用书签替换word中的文字

模版自己提供,类似下图:
在这里插入图片描述
框住的书签部分是需要被替换的

最后实现的效果:
在这里插入图片描述
上代码

第一步:依赖:

      <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
            <version>8.3.11</version>
        </dependency>
    **gradle的自己找对应的依赖导入**
    **本项目demo用的是JDK1.8的,对应docx4j的依赖是8.3.11,如果是更高版本的项目,去docx4j的官网找他们的最新依赖 **

第二步 word工具类

import org.docx4j.Docx4J;
import org.docx4j.XmlUtils;
import org.docx4j.convert.out.FOSettings;
import org.docx4j.dml.Graphic;
import org.docx4j.dml.GraphicData;
import org.docx4j.dml.picture.Pic;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.wml.*;

import javax.xml.bind.JAXBElement;
import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 模板word内容替换工具类
 */
public class Tool {

    /**
     * 在标签处插入替换内容
     *
     * @param bm
     * @param
     * @param object
     * @throws Exception
     */
    public static void replaceText(CTBookmark bm, Object object) throws Exception {


        if (object == null) {
            return;
        }
        if (bm.getName() == null){
            return;
        }
        String value = object.toString();
        try {
            List<Object> theList = null;
            ObjectFactory factory = Context.getWmlObjectFactory();
            ParaRPr rpr = null;
            if (bm.getParent() instanceof P) {
                PPr pprTemp = ((P) (bm.getParent())).getPPr();
                if (pprTemp == null) {
                    rpr = null;
                } else {
                    rpr = ((P) (bm.getParent())).getPPr().getRPr();
                }
                theList = ((ContentAccessor) (bm.getParent())).getContent();
            } else {
                return;
            }
            int rangeStart = -1;
            int rangeEnd = -1;
            int i = 0;
            for (Object ox : theList) {
                Object listEntry = XmlUtils.unwrap(ox);
                if (listEntry.equals(bm)) {
                    if (((CTBookmark) listEntry).getName() != null) {
                        rangeStart = i + 1;
                    }
                } else if (listEntry instanceof CTMarkupRange) {
                    if (((CTMarkupRange) listEntry).getId().equals(bm.getId())) {
                        rangeEnd = i - 1;
                        break;
                    }
                }
                i++;
            }
            int x = i - 1;
            for (int j = x; j >= rangeStart; j--) {
                theList.remove(j);
            }

           // ObjectFactory factory = Context.getWmlObjectFactory();
            R run = factory.createR();
            Text t = factory.createText();

            t.setValue(value);

            RPr rpr1 = factory.createRPr();
            {

            RFonts rf = factory.createRFonts();

            HpsMeasure size = new HpsMeasure();
            size.setVal(BigInteger.valueOf(2*14));
            rpr1.setSz(size);
            rpr1.setSzCs(size);
            rpr1.setRFonts(rf);
            }

            // 将 RPr 对象应用到 R 对象上
            run.setRPr(rpr1);
            run.getContent().add(t);
            theList.add(rangeStart, run);
        } catch (ClassCastException cce) {

        }
    }

    /**
     * 替换image
     * @param wPackage
     * @param bm
     * @param file
     */
    public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String file){

        // 新增image
        ObjectFactory factory = Context.getWmlObjectFactory();
        P p = (P) (bm.getParent());
        R run = factory.createR();
        byte[] bytes ;
        Long newCx = 0L;
        Long newCy = 0L;
        String newRelId = null;
        try {
            bytes =inputStremToBytes(new FileInputStream(file));
            BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage,bytes);
            Inline newInline = imagePart.createImageInline(null, null, 0, 1, false,0);

            // 获取CX 、CY
            newCx = newInline.getExtent().getCx();
            newCy = newInline.getExtent().getCy();

            // 获取relId
            Graphic newg = newInline.getGraphic();
            GraphicData graphicdata = newg.getGraphicData();
            Object o = graphicdata.getAny().get(0);
            Pic pic = (Pic)XmlUtils.unwrap(o);
            newRelId = pic.getBlipFill().getBlip().getEmbed();

        } catch (Exception e) {
            e.printStackTrace();
        }

        // 获取模板图片的CX 、CY 、relId
        Object parent = (P) bm.getParent();
        List<Object> rList = getAllElementFromObject(parent, R.class);
        for (Object robj: rList){
            if (robj instanceof R){
                R r = (R) robj;
                List<Object> drawList = getAllElementFromObject(r, Drawing.class);
                for (Object dobj: drawList){
                    if (dobj instanceof Drawing){
                        Drawing d = (Drawing) dobj;
                        Inline inline = (Inline)d.getAnchorOrInline().get(0);
                        // 获取CX 、CY
                        Long cx = inline.getExtent().getCx();
                        Long cy = inline.getExtent().getCy();

                        // 获取relId
                        Graphic g = inline.getGraphic();
                        GraphicData graphicdata = g.getGraphicData();
                        Object o = graphicdata.getAny().get(0);
                        Pic pic = (Pic)XmlUtils.unwrap(o);
                        String relId = pic.getBlipFill().getBlip().getEmbed();

                        // 替换relId
                        pic.getBlipFill().getBlip().setEmbed(newRelId);
                        // 处理CX、CY
                        Map<String,Long> map = dealCxy(cx, cy, newCx, newCy);

                        // 更改cx、cy
                        inline.getExtent().setCx(map.get("setCx"));
                        inline.getExtent().setCy(map.get("setCy"));

                    }
                }
            }
        }
    }

    /**
     * 处理图片适应大小
     * @param cx
     * @param cy
     * @param newCx
     * @param newCy
     */
    public static Map<String, Long> dealCxy(Long cx, Long cy, Long newCx, Long newCy){
        Map<String, Long> map = new HashMap<>();
        Long setCx;
        Long setCy;

        if (newCx > cx){
            if (newCy <= cy){
                setCx = cx;
                setCy = newCy/(newCx/cx);
            } else {
                if ((newCx/cx) > (newCy/cy)){
                    setCx = cx;
                    setCy = newCy/(newCx/cx);
                } else {
                    setCy = cy;
                    setCx = newCx/(newCy/cy);
                }
            }
        } else {   // newCx < cx
            if (newCy > cy) {
                setCx = cx;
                setCy = newCy * (cx/newCx);
            } else {
                if ((cx/newCx) > (cy/newCy)) {
                    setCx = cx;
                    setCy = newCy *(cx/newCx);
                } else {
                    setCy = cy;
                    setCx = newCy * (cy/newCy);
                }
            }
        }
        map.put("setCx",setCx);
        map.put("setCy",setCy);
        return map;
    }


    /**
     * 得到指定类型的元素
     * @param obj
     * @param toSearch
     * @return
     */
    public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
        List<Object> result = new ArrayList<>();
        if (obj instanceof JAXBElement)
            obj = ((JAXBElement<?>) obj).getValue();
        if (obj.getClass().equals(toSearch))
            result.add(obj);
        else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }
        return result;
    }

    /**
     * word 转换 pdf (实际是没有用到的)
     * @param docxPath
     * @param pdfPath
     * @throws Exception
     */
    public static void convertDocxToPDF(String docxPath, String pdfPath) throws Exception {
        OutputStream os = null;
        try {
            WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(new File(docxPath));
            Mapper fontMapper = new IdentityPlusMapper();
            fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
            fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
            fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
            mlPackage.setFontMapper(fontMapper);

            os = new java.io.FileOutputStream(pdfPath);

            FOSettings foSettings = Docx4J.createFOSettings();
            foSettings.setWmlPackage(mlPackage);
            Docx4J.toFO(foSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);

        }catch(Exception ex){
            ex.printStackTrace();
        }finally {
            os.flush();
            os.close();
        }
    }

    /**
     * 下载PDF文件(实际是没有用到的)
     * @param wordMLPackage
     * @param os
     * @throws Exception
     */
    public  void pdfFile(WordprocessingMLPackage wordMLPackage,OutputStream os) throws Exception {

        String regex = null;
        Mapper fontMapper = new IdentityPlusMapper();
        wordMLPackage.setFontMapper(fontMapper);
        PhysicalFont font = PhysicalFonts.get("Arial Unicode MS");
        String directory = "D:\\upload\\pdf";
        String fileName = "OUT_ConvertInXHTMLURL.pdf";
        File f = new File(directory,fileName);
        if(f.exists()) {
            // 文件已经存在,输出文件的相关信息
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getName());
            System.out.println(f.length());
        } else {
            //  先创建文件所在的目录
            f.getParentFile().mkdirs();
        }
        File file = new File(directory+"/"+fileName);
        OutputStream os34 = new java.io.FileOutputStream(file);
        Docx4J.toPDF(wordMLPackage, os34);
        os.flush();
        os.close();
        wordMLPackage = null;
    }

    public static byte[] inputStremToBytes(InputStream is) throws IOException{
        //将输入流 转换为字节数组
        byte[] buffer=new byte[1024];
        int len=0;
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        while((len=is.read(buffer))!=-1){
            bos.write(buffer,0,len);
        }
        bos.flush();
        return bos.toByteArray();
        /**这里可以直接将字节数组new成字符窜*/

        //Bitmap类可以直接将byte数组转换成一张图片
    }
}

第三步 处理word



import org.docx4j.Docx4J;
import org.docx4j.TraversalUtil;
import org.docx4j.finders.RangeFinder;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class Docx4jOPWord {

    public static void main(String[] args) throws Exception {

        // 设置的标签
        ArrayList<String> bmList = new ArrayList<>();
        bmList.add("company");
        bmList.add("firstName");
        bmList.add("nbr");

        // 文件源目录
        String srcPath = "C:\\Users\\19207\\Desktop\\book1.docx";
        // 目标文件目录
        String destPath = "C:\\Users\\19207\\Desktop\\book2.docx";
        Map<String, String> map = new HashMap<>();
        map.put("firstName","张三aaaAAA");
        map.put("company","沈阳收车公司CCCCC");
        map.put("nbr","1542153256");





        // 打开一个存在的word
        WordprocessingMLPackage wPackage = WordprocessingMLPackage.load(new FileInputStream(srcPath));
        // 作word处理
        WordprocessingMLPackage wPackage1 = replaceContentByBookmark(wPackage, map, bmList);
        wPackage1.save(new File(destPath));
        Docx4J.toPDF(wPackage1,new FileOutputStream(new File("C:\\Users\\19207\\Desktop\\Docx4jBooks.pdf")));

    }


    public static  WordprocessingMLPackage  replaceContentByBookmark(WordprocessingMLPackage wPackage, Map<String, String> map, ArrayList<String> bmList)  {
        try {
            // 提取正文
            MainDocumentPart main = wPackage.getMainDocumentPart();
            Document doc = main.getContents();
            Body body = doc.getBody();

            // 获取段落
            List<Object> paragraphs  = body.getContent();

            List<CTBookmark> bookmarks = new ArrayList<>();
            List<CTMarkupRange> markupRanges = new ArrayList<>();

            // 提取书签并获取书签的游标
           // RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
            RangeFinder rt = new RangeFinder();
            new TraversalUtil(paragraphs, rt);

            // 遍历书签
            for (CTBookmark bm : rt.getStarts()) {
                // 替换文本内容
                for (String bmName: bmList) {
                    if (bm.getName().equals(bmName)){
                        Tool.replaceText(bm, map.get(bm.getName()));
                    }
                }
            }

        } catch (Exception e){
            System.out.println(e.getMessage());
        }

        return  wPackage;
    }
}

** 坑的地方: // 提取书签并获取书签的游标
// RangeFinder rt = new RangeFinder(“CTBookmark”, “CTMarkupRange”); 许多博客给的是有参数的代码,但是源码死无参构造,因此去掉参数即可。

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值