2021-09-28

poi功能完善 页码显示 请结合上部分 重点 createFotter方法

 <poi.version>4.1.0</poi.version>
<dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <!--word转换pdf-->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-scratchpad</artifactId>
      <version>${poi.version}</version>
    </dependency>

替换一个段落中的多个值
方法:通过得到段落字体的大小计算一行中可以放置多少字符或汉字,然后计算每个段需要的字段多少才能显示需要的效果,得到实际数据库中字段的大小,超出截取,不够补位就可以实现样式控制‘拒绝段落入值打乱布局的效果

package common.redis.utils;

import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlToken;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.*;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DocUtils {

    public DocMen docMen = new DocMen();

    /**
     * 如果传值方法数据太长可以使用JSONObject或 Map类型进行传递参数
     * 启动运行类
     * 由于事先对序号做了截取分段,避免了static序号错乱 追加的问题
     * 可以使用多线程操作生成
     * 对于一次性生成多种类型表格可以使用多线程,同一表格操作使用多线程
     * 导致原有的有序数据错乱
     * 如果使用同步操作相当于串行这样多线程和单线程运行性能没啥区别,锁的出现,可能比单线程运行速度更慢
     * @param file
     * @param params
     * @param details
     * @param isStatus
     * @param strings
     * @param start
     * @param end
     * @throws IOException
     */
    public void start(File file, Map<String, Object> params, List<Map<String, Object>> details, Boolean isStatus, String[] strings, int start, int end, int columns) throws Exception {
        List<XWPFDocument> list = documents(file,params,details,isStatus,strings,start,end,columns);
        if(!CollectionUtils.isEmpty(list)){
            saveFiles(list,null);
        }
    }

    /**
     * 生成复杂的数据表 续表数据启动方法
     * @param mainFile
     * @param detailFile
     * @param params
     * @param detailData
     * @param strings
     * @param mainStart
     * @param mainEnd
     * @param mainColumns
     * @param isTrue
     * @param detailStart
     * @param detailEnd
     * @param columns
     */
    public void start(File mainFile, File detailFile, Map<String,Object> params, List<Map<String,Object>>detailData,String[] strings,Integer mainStart, Integer mainEnd,Integer mainColumns,Boolean isTrue,Integer detailStart,Integer detailEnd,Integer columns) throws Exception {
        Integer sear = 0;
        //判断明细数据大小 如果明细数据等于或小于主表中明细列
        if(detailData.size() == mainColumns || detailData.size() < mainColumns){
            start(mainFile, params, detailData, isTrue, strings, mainStart, mainEnd, mainColumns);
        }else {
            //计算序号
            List<XWPFDocument> list = documents(mainFile,params,detailData.subList(0,mainColumns),isTrue,strings,mainStart,mainEnd,mainColumns);
            List<XWPFDocument> characters = characters(detailFile, params, detailData, isTrue, strings, detailStart, detailEnd, columns, mainColumns + 1);
            List<XWPFDocument> collect = Stream.of(list, characters).flatMap(Collection::stream).collect(Collectors.toList());
            saveFiles(collect,null);
        }
    }

    /**
     * 执行保存操作,保存文件到本地操作 使用 ByteArrayOutputStream 输入流可以提高性能
     * @param list
     * @param path
     * @throws XmlException
     * @throws IOException
     */
    public void saveFiles(List<XWPFDocument> list, String path) throws Exception {
        XWPFDocument xmd = list.get(0); //默认获取第一个作为模板
        for (int i=0;i<list.size()-1;i++) {
            if(list.get(i) != null){
                xmd = docMen.mergeWord(xmd,list.get(i+1)); //相继合并
            }
        }
        docMen.createFooters(xmd,1,10);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        xmd.write((OutputStream)byteArrayOutputStream);
        long l = System.currentTimeMillis();
        OutputStream outputStream = new FileOutputStream("C:\\Users\\31034\\Desktop\\"+l+".docx");
        outputStream.write(byteArrayOutputStream.toByteArray());
        outputStream.close();
        //collector中传入HttpServletResponse 直接调用 IOUtils.copy(inputStream,response.getOutputStream);
        // 可以直接保存本地电脑 貌似该框架无法实现该功能
        // InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        // IOUtils.copy(inputStream,outputStream);
    }

    /**
     * 续页表格的操作生成实现,先判断明细数据是否小于或等于主表信息数据,如果符合这些信息 则不需要附表直接生成主表信息
     * 明细数据大于主表存储数据则计算需要明细表的数量, 同时计算明细表开始下标
     * @param file
     * @param params
     * @param details
     * @param isState
     * @param strings
     * @param start
     * @param end
     * @param columns
     * @param serial
     * @return
     * @throws Exception
     */
    public List<XWPFDocument> characters(File file, Map<String, Object> params, List<Map<String, Object>> details, Boolean isState, String[] strings, Integer start, Integer end,int columns,Integer serial) throws Exception {
        List<XWPFDocument> list = new LinkedList<>();
        Integer num = 1;
        if(isState){
            num = details.size() / columns;
            //先取余数后取模
            Integer IntegerNum = details.size() % columns;
            if(IntegerNum>0) num++;
        }
        for(int i = 0; i < num; i++){
            if(i == 1){
                serial = columns+i;
            }else if(i==0){
                serial = serial;
            }else{
                serial = columns+serial;
            }
            XWPFDocument xwpfDocument = docMen.replaceInTable(new XWPFDocument(new FileInputStream(file)), params, details, isState, strings, start, end, serial,i+1,num);
            list.add(xwpfDocument);
        }
        return list;
    }

    /**
     * 执行生成表格数据操作
     * 同时对数据序号进行分段,同时根据明细数据进行表格数量的计算 foreach调用获取表格最后调取sava进行合并本地保存等操作
     * @param file
     * @param params
     * @param details
     * @param isState
     * @param strings
     * @param start
     * @param end
     * @param columns
     * @return
     * @throws Exception
     */
    public List<XWPFDocument> documents(File file, Map<String, Object> params, List<Map<String, Object>> details, Boolean isState, String[] strings, Integer start, Integer end,int columns) throws Exception {
        List<XWPFDocument> list = new LinkedList<>();
        Integer num = 1;
        Integer serial = 0;
        if(isState){
            num = details.size() / columns;
            //先取余数后取模
            Integer IntegerNum = details.size() % columns;
            if(IntegerNum>0) num++;
        }
        for(int i = 0; i < num; i++){
            if(i == 1){
                serial = columns+i;
            }else if(i==0){
                serial = 1;
            }else{
                serial = columns+serial;
            }
            XWPFDocument xwpfDocument = docMen.replaceInTable(new XWPFDocument(new FileInputStream(file)), params, details, isState, strings, start, end, serial,i+1,num);
            list.add(xwpfDocument);
        }
        return list;
    }

    public class DocMen extends Doc implements word{

        /**
         * 对表格数据进行追加
         * @param document
         * @param docDocument2
         * @return
         * @throws XmlException
         */
        @Override
        public XWPFDocument mergeWord(XWPFDocument document, XWPFDocument docDocument2) throws XmlException {
            //会导致分页 空白页的出现
            /*XWPFDocument src1Document =document ;
            XWPFParagraph p = src1Document.createParagraph();
            //设置分页符
            p.setPageBreak(true);
            CTBody src1Body = src1Document.getDocument().getBody();
            XWPFDocument src2Document = docDocument2;
            CTBody src2Body = src2Document.getDocument().getBody();
            XmlOptions optionsOuter = new XmlOptions();
            optionsOuter.setSaveOuter();
            String appendString = src2Body.xmlText(optionsOuter);
            String srcString = src1Body.xmlText();
            String prefix = srcString.substring(0,srcString.indexOf(">")+1);
            String mainPart = srcString.substring(srcString.indexOf(">")+1,srcString.lastIndexOf("<"));
            String sufix = srcString.substring( srcString.lastIndexOf("<") );
            String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
            CTBody makeBody = CTBody.Factory.parse(prefix+mainPart+addPart+sufix);
            src1Body.set(makeBody);
            return src1Document;*/

            //设置分页符---当刚好一页数据时,会导致出现空白页,后面出现分页符导致格式有一点差异
            //解决方法是,在模板头上增加分页符
            //XWPFParagraph p = document2.createParagraph();
            //p.setPageBreak(true);
            CTBody src1Body = document.getDocument().getBody();
            CTBody src2Body = docDocument2.getDocument().getBody();
            XmlOptions optionsOuter = new XmlOptions();
            optionsOuter.setSaveOuter();
            String appendString = src2Body.xmlText(optionsOuter);
            String srcString = src1Body.xmlText();
            String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
            String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
            String sufix = srcString.substring(srcString.lastIndexOf("<"));
            String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
            CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);
            src1Body.set(makeBody);
            return document;
        }

        /**
         * 读取明细行数据
         * 如果段落中的数据读取完成以后则设置 以下内容空白提示
         * @param para 段落
         * @param params 明细参数信息
         * @param index 第几行
         * @param key
         * @param tableFontsize
         * @param column
         */
        @Override
        public void replaceInPara(XWPFParagraph para, List<Map<String, Object>> params, Integer index, String key, int tableFontsize, Integer column) {
            List<XWPFRun> runs;
            runs = para.getRuns();
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.toString();
                if(index < params.size()){
                    runText = String.valueOf(params.get(index).get(key));
                    run.setText(runText, 0);
                    run.setFontSize(tableFontsize);
                } else  if(index == params.size()){
                    if(column == 1){
                        runText = "以下内容空白";
                        run.setText(runText, 0);
                        run.setFontSize(tableFontsize);
                    }else {
                        runText = "";
                        run.setText(runText, 0);
                        run.setFontSize(tableFontsize);
                    }
                } else {
                    runText = "";
                    run.setText(runText, 0);
                    run.setFontSize(tableFontsize);
                }
            }
        }

        /**
         * 替换段落中的数据信息 如果序号大于列则不对列做取值操作 直接把列内容赋值为null
         * @param para
         * @param index
         * @param tableFontsize
         * @param column
         */
        @Override
        public void replaceInPara(XWPFParagraph para, Integer index, int tableFontsize, Integer column) {
            List<XWPFRun> runs;
            runs = para.getRuns();
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                if(column < index){
                    String runText = run.toString();
                    runText = "";
                    run.setText(runText, 0);
                }else {
                    String runText = run.toString();
                    runText = String.valueOf(index);
                    run.setText(runText, 0);
                    run.setFontSize(tableFontsize);
                }
            }
        }

        /**
         * 替换表格之外的段落数据信息
         * 注:doc.getTablesIterator(); 只能读取表格内的东西 表格外的数据无法获取
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         * @throws Exception
         */
        @Override
        public void changeText(XWPFDocument document, Map<String, Object> textMap) throws Exception {
            //获取段落集合
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            for (XWPFParagraph paragraph : paragraphs) {
                //判断此段落时候需要进行替换
                replaceInPara(paragraph,textMap,document);
            }
        }

        /**
         * 替换表格中的数据信息
         * @param doc    要替换的文档
         * @param params 参数
         * @param details
         * @param isStatus
         * @param strings
         * @param start
         * @param end
         * @param serial
         * @return
         * @throws Exception
         */
        @Override
        public XWPFDocument replaceInTable(XWPFDocument doc, Map<String, Object> params, List<Map<String, Object>> details, Boolean isStatus, String[] strings, int start, int end,int serial,int page,int total) throws Exception {
            changeText(doc, params);
            Iterator<XWPFTable> iterator = doc.getTablesIterator();
            XWPFTable table;
            Integer index = 0;
            List<XWPFTableRow> rows;
            List<XWPFTableCell> cells;
            List<XWPFParagraph> paras;
            while (iterator.hasNext()) {
                table = iterator.next();
                rows = table.getRows();
                for (int i = 0; i< rows.size(); i++){
                    if(isStatus){
                        if(i == start){
                            for (i = start; i < end; i++){
                                cells = rows.get(i).getTableCells();
                                for (int n = 0; n < cells.size(); n++){
                                    paras = cells.get(n).getParagraphs();
                                    for (int j = 0; j < paras.size(); j++) {
                                        if(n==0){
                                            replaceInPara(paras.get(j),serial,8,details.size());
                                        }else {
                                            replaceInPara(paras.get(j), details, serial-1,strings[n-1],8,n);
                                            index++;
                                        }
                                        if(index == strings.length){ index = 0; }
                                    }
                                }
                                serial++;
                            }
                            if(i >= rows.size()){
                               break;
                            }
                        }
                    }
                    cells = rows.get(i).getTableCells();
                    for (int n = 0; n < cells.size(); n++){
                        paras = cells.get(n).getParagraphs();
                        for (int j = 0; j < paras.size(); j++) {
                            replaceInPara(paras.get(j), params,doc);
                        }
                    }
                }
            }
            return doc;
        }

        /**
         * 正则表达式判断读取数据是否否合正则表达式
         * @param str
         * @return
         */
        @Override
        public Matcher matcher(String str) {
            Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
            Matcher matcher = pattern.matcher(str);
            return matcher;
        }

        /**
         * 替换段落数据
         * matcher正则读取段落数据,
         * 如果段落中有符合正则的数据则从map集合中读取数据并且赋值
         * @param para   要替换的段落
         * @param params 参数
         * @param doc
         * @throws Exception
         */
        @Override
        public void replaceInPara(XWPFParagraph para, Map<String, Object> params,XWPFDocument doc) throws Exception {
            List<XWPFRun> runs;
            Matcher matcher;
            if (matcher(para.getParagraphText()).find()) {
                runs = para.getRuns();
                for (int i = 0; i < runs.size(); i++) {
                    XWPFRun run = runs.get(i);
                    String runText = run.toString();
                    matcher = matcher(runText);
                    if (matcher.find()) {
                        if("${price}".equals(runText)){
                            InputStream stream = covInputStream("https://img-blog.csdnimg.cn/img_convert/b26750936b8d00e60053e7dda335f9aa.png");
                            aroundImage(run,stream,65,65);
                            break;
                        }else if("${gcmc}".equals(runText)){
                            String val = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
                            runText = String.format("%-30s", val);
                            run.setText(runText, 0);
                            run.setFontSize(10);
                        }else if("${jlbh}".equals(runText)){
                            String val = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
                            runText = String.format("%-26s", val);
                            run.setText(runText, 0);
                            run.setFontSize(10);
                        }else {
                            while ((matcher = matcher(runText)).find()) {
                                runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
                            }
                            run.setText(runText, 0);
                            run.setFontSize(10);
                        }
                    }
                }
            }
        }

        /**
         * 流转换 根据网络图片地址转换为inputStream输出流
         * @param url
         * @return
         * @throws IOException
         */
        @Override
        InputStream covInputStream(String url) throws IOException {
            URL path = new URL(url);
            HttpURLConnection conn = (HttpURLConnection)path.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5 * 1000);
            InputStream inputStream = conn.getInputStream();//通过输入流获取图片数据
            //最终返回处理好的数据
            return inputStream;
        }

        /**
         * 插入图片 给段落中插入图片并设置图片的宽高
         * 使用
         * //int priceId = priceType(doc, "png");
         * //replaceImg(run,stream,"https://img-blog.csdnimg.cn/img_convert/b26750936b8d00e60053e7dda335f9aa.png");
         * @param run
         * @param stream
         * @param path
         * @throws IOException
         * @throws InvalidFormatException
         */
        @Override
        void replaceImg(XWPFRun run,InputStream stream,String path) throws IOException, InvalidFormatException {
            XWPFPicture xwpfPicture = run.addPicture(stream, XWPFDocument.PICTURE_TYPE_PNG, path, Units.toEMU(60), Units.toEMU(60));// 100x100 pixels
            stream.close();
            run.setText("  ",0);
        }

        /**
         * 根据 图片的后坠名判断图片的属性值
         * @param docx
         * @param suffix
         * @return
         */
        @Override
        public int priceType(XWPFDocument docx,String suffix) {
            int res = docx.PICTURE_TYPE_PICT;
            if (suffix != null) {
                if (suffix.equalsIgnoreCase("png")) {
                    res = docx.PICTURE_TYPE_PNG;
                } else if (suffix.equalsIgnoreCase("dib")) {
                    res = docx.PICTURE_TYPE_DIB;
                } else if (suffix.equalsIgnoreCase("emf")) {
                    res = docx.PICTURE_TYPE_EMF;
                } else if (suffix.equalsIgnoreCase("jpg") || suffix.equalsIgnoreCase("jpeg")) {
                    res = docx.PICTURE_TYPE_JPEG;
                } else if (suffix.equalsIgnoreCase("wmf")) {
                    res = docx.PICTURE_TYPE_WMF;
                }
            }
            return res;
        }

        /**
         * 使用方法
         *int priceId = priceType(doc, "png"); 图片属性id
         *String Id = doc.addPictureData(stream,priceId); 图片id
         *rangImag(run,Id,priceId,200,200);
         * @param run
         * @param blipId
         * @param id
         * @param width
         * @param height
         */
        @Override
        public void rangImag(XWPFRun run,String blipId,int id,int width, int height) {
            final int EMU = 9525;
            width *= EMU;
            height *= EMU;
            //String blipId = getAllPictures().get(id).getPackageRelationship().getId();

            CTInline inline =run.getCTR().addNewDrawing().addNewInline();

            String picXml = "" +
                    "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
                    "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                    "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                    "         <pic:nvPicPr>" +
                    "            <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
                    "            <pic:cNvPicPr/>" +
                    "         </pic:nvPicPr>" +
                    "         <pic:blipFill>" +
                    "            <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
                    "            <a:stretch>" +
                    "               <a:fillRect/>" +
                    "            </a:stretch>" +
                    "         </pic:blipFill>" +
                    "         <pic:spPr>" +
                    "            <a:xfrm>" +
                    "               <a:off x=\"0\" y=\"0\"/>" +
                    "               <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
                    "            </a:xfrm>" +
                    "            <a:prstGeom prst=\"rect\">" +
                    "               <a:avLst/>" +
                    "            </a:prstGeom>" +
                    "         </pic:spPr>" +
                    "      </pic:pic>" +
                    "   </a:graphicData>" +
                    "</a:graphic>";

            //CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
            XmlToken xmlToken = null;
            try {
                xmlToken = XmlToken.Factory.parse(picXml);
            } catch(XmlException xe) {
                xe.printStackTrace();
            }
            inline.set(xmlToken);
            //graphicData.set(xmlToken);

            inline.setDistT(0);
            inline.setDistB(0);
            inline.setDistL(0);
            inline.setDistR(0);

            CTPositiveSize2D extent = inline.addNewExtent();
            extent.setCx(width);
            extent.setCy(height);

            CTNonVisualDrawingProps docPr = inline.addNewDocPr();
            docPr.setId(id);
            docPr.setName("Picture " + id);
            docPr.setDescr("Generated");
            run.setText("  ",0);
        }

        @Override
        public void aroundImage(XWPFRun run,InputStream stream,int width,int height) throws IOException, InvalidFormatException {
            Random random = new Random();
            //产生随机数
            int number = random.nextInt(999) + 1;
            run.addPicture(stream, Document.PICTURE_TYPE_PNG, "Seal"+number, Units.toEMU(62), Units.toEMU(62));
            stream.close();
            // 2. 获取到图片数据
            CTDrawing drawing = run.getCTR().getDrawingArray(0);
            CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();

            //拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
            CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "Seal"+number,
                    Units.toEMU(width), Units.toEMU(height),//图片大小
                    Units.toEMU(0), Units.toEMU(0), false);//相对当前段落位置 需要计算段落已有内容的左偏移
            drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
            drawing.removeInline(0);//删除行内属性
            run.setText("  ",0);
        }

        public void createFooters(XWPFDocument document,int page,int total) throws IOException {
            XWPFFooter footer = document.createFooter(HeaderFooterType.DEFAULT);
            XWPFParagraph paragraph = footer.createParagraph();
            paragraph.setAlignment(ParagraphAlignment.CENTER);
            CTTabStop tabStop = paragraph.getCTP().getPPr().addNewTabs().addNewTab();
            tabStop.setVal(STTabJc.RIGHT);
            int twipsPerInch =  60;
            tabStop.setPos(BigInteger.valueOf(6 * twipsPerInch));
            //设置偏移量 页码右
            // int twipsPerInch =  1440;
            // tabStop.setPos(BigInteger.valueOf(6 * twipsPerInch));

            XWPFRun run = paragraph.createRun();
            run = paragraph.createRun();
            run.setText("第");
            setXWPFRunStyle(run,"仿宋",10);

            run = paragraph.createRun();
            CTFldChar fldChar = run.getCTR().addNewFldChar();
            fldChar.setFldCharType(STFldCharType.Enum.forString("begin"));

            run = paragraph.createRun();
            CTText ctText = run.getCTR().addNewInstrText();
            ctText.setStringValue("PAGE  \\* MERGEFORMAT");
            ctText.setSpace(SpaceAttribute.Space.Enum.forString("preserve"));
            setXWPFRunStyle(run,"仿宋",10);

            fldChar = run.getCTR().addNewFldChar();
            fldChar.setFldCharType(STFldCharType.Enum.forString("end"));

            run = paragraph.createRun();
            run.setText("页 总共");
            setXWPFRunStyle(run,"仿宋",10);

            run = paragraph.createRun();
            fldChar = run.getCTR().addNewFldChar();
            fldChar.setFldCharType(STFldCharType.Enum.forString("begin"));

            run = paragraph.createRun();
            ctText = run.getCTR().addNewInstrText();
            ctText.setStringValue("NUMPAGES  \\* MERGEFORMAT ");
            ctText.setSpace(SpaceAttribute.Space.Enum.forString("preserve"));
            setXWPFRunStyle(run,"仿宋",10);

            fldChar = run.getCTR().addNewFldChar();
            fldChar.setFldCharType(STFldCharType.Enum.forString("end"));

            run = paragraph.createRun();
            run.setText("页");
            setXWPFRunStyle(run,"仿宋",10);
        }

        /**
         * 设置页脚的字体样式
         *
         * @param r1 段落元素
         */
        private void setXWPFRunStyle(XWPFRun r1,String font,int fontSize) {
            r1.setFontSize(fontSize);
            CTRPr rpr = r1.getCTR().isSetRPr() ? r1.getCTR().getRPr() : r1.getCTR().addNewRPr();
            CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
            fonts.setAscii(font);
            fonts.setEastAsia(font);
            fonts.setHAnsi(font);
        }

        /**
         * @param ctGraphicalObject 图片数据
         * @param deskFileName      图片描述
         * @param width             宽
         * @param height            高
         * @param leftOffset        水平偏移 left
         * @param topOffset         垂直偏移 top
         * @param behind            文字上方,文字下方
         * @return
         * @throws Exception
         */
        public CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject, String deskFileName, int width, int height, int leftOffset, int topOffset, boolean behind) {
            System.out.println(">>width>>"+width+"; >>height>>>>"+height);
            String anchorXML =
                    "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
                            + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
                            + "<wp:simplePos x=\"0\" y=\"0\"/>"
                            + "<wp:positionH relativeFrom=\"column\">"
                            + "<wp:posOffset>" + leftOffset + "</wp:posOffset>"
                            + "</wp:positionH>"
                            + "<wp:positionV relativeFrom=\"paragraph\">"
                            + "<wp:posOffset>" + topOffset + "</wp:posOffset>" +
                            "</wp:positionV>"
                            + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>"
                            + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>"
                            + "<wp:wrapNone/>"
                            + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>"
                            + "</wp:anchor>";

            CTDrawing drawing = null;
            try {
                drawing = CTDrawing.Factory.parse(anchorXML);
            } catch (XmlException e) {
                e.printStackTrace();
            }
            CTAnchor anchor = drawing.getAnchorArray(0);
            anchor.setGraphic(ctGraphicalObject);
            return anchor;
        }

    }

    protected abstract class Doc{

        /**
         * 文件对象进行追加
         * @param document
         * @param docDocument2
         * @return
         * @throws Exception
         */
        abstract XWPFDocument mergeWord(XWPFDocument document, XWPFDocument docDocument2) throws XmlException;

        /**
         * 替换明细字段数据库自取字段信息 (明细表操作)
         * @param para 段落
         * @param params 明细参数信息
         * @param index 第几行
         * @param key
         */
        abstract void replaceInPara(XWPFParagraph para, List<Map<String, Object>> params,Integer index,String key,int tableFontsize,Integer column);

        /**
         * 替换明细数据字段为 serial 序号 (明细表操作)
         * @param para
         * @param index
         */
        abstract void replaceInPara(XWPFParagraph para,Integer index,int tableFontsize,Integer column);

        /**
         * 替换段落文本
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         */
        abstract void changeText(XWPFDocument document, Map<String, Object> textMap) throws Exception;

        /**
         * 替换表格里面的变量 (表格操作)
         *
         * @param doc    要替换的文档
         * @param params 参数
         */
        abstract XWPFDocument replaceInTable(XWPFDocument doc, Map<String, Object> params,List<Map<String,Object>> details,Boolean isStatus,String[] strings,int start,int end,int serial,int page,int total) throws Exception;

        /**
         * 正则匹配字符串 (主表变量操作)
         */
        abstract Matcher matcher(String str);

        /**
         * 替换段落里面的变量 (主表操作)
         *
         * @param para   要替换的段落
         * @param params 参数
         */
        abstract void replaceInPara(XWPFParagraph para, Map<String, Object> params,XWPFDocument doc) throws Exception;

        /**
         * 网络文件转换为InputStream
         * @param url
         * @return
         */
        abstract InputStream covInputStream(String url) throws IOException;

        /**
         * 替换表格中的图片
         * @param xwpfRun
         */
        abstract void replaceImg(XWPFRun xwpfRun,InputStream stream,String path) throws FileNotFoundException, IOException, InvalidFormatException;
    }

    protected interface word {

        /**
         * 获取图片属性
         *
         * @param suffix
         * @return
         */
        int priceType(XWPFDocument docx, String suffix);

        /**
         * 给run添加图片
         * @param run
         * @param blipId
         * @param id
         * @param width
         * @param height
         */
        void rangImag(XWPFRun run,String blipId,int id,int width, int height);

        /**
         * 环绕插入图片 注: 此方法不存在顶出外边
         * @param run
         * @param stream
         * @param width
         * @param height
         */
        void aroundImage(XWPFRun run,InputStream stream,int width,int height) throws IOException, InvalidFormatException;

        /**
         * 添加word页脚
         * @param doc
         */
        void createFooters(XWPFDocument doc,int page,int total) throws IOException;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pursue?????

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值