java导出word套打

 这篇文档手把手教你完成导出word套打,有这个demo,其他word套打导出都通用。

 1、主要依赖

        
        
            cn.hutool
            hutool-all
            5.3.0
        

        
            cn.hutool
            hutool-core
            5.3.0
        

        
            org.apache.poi
            poi-ooxml
            4.1.2
        

        
            repository.org.projectlombok
            lombok
            1.16.22
        
        
            repository.org.apache.commons
            commons-lang3
            3.9
        

 2、模板excel见附件。

java导出word套打_第1张图片

3、以下为导出代码逻辑:

package com.example.demo.excel;

import cn.hutool.poi.word.PicType;
import lombok.Data;

/**
 * 图片对象
 * @author xiajun
 */
@Data
public class WordImage {
    /**
     * 图片宽度
     */
    private int width = 100;

    /**
     * 图片高度
     */
    private int height = 100;

    /**
     * 图片地址
     * resource资源相对路径
     */
    private String path;

    /**
     * 字节流
     */
    private byte[] source;

    /**
     * 图片类型
     * 默认PNG
     *
     */
    private PicType imageType = PicType.PNG;


}

package com.example.demo.excel;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.word.Word07Writer;
import cn.hutool.poi.word.WordUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * word导出
 * @author xiajun
 */
@Slf4j
@RestController
@RequestMapping("mvc/word")
public class WordExport {
    @GetMapping(path = "/export")
    public void export(HttpServletResponse response) throws IOException {

        //1、============================模拟数据===============================
        Map params = new HashMap<>();
        params.put("${name}", "张三");
        params.put("${sex}", "男");
        params.put("${birth}", "1999.11");
        params.put("${age}", "25");
        params.put("${nation}", "汉族");
        params.put("${npn}", "四川成都");
        params.put("${bpn}", "四川成都");
        params.put("${pt}", "2017.02");
        params.put("${workTime}", "2016.03");
        params.put("${hn}", "健康");
        params.put("${beFawts}", "打篮球");
        params.put("${proTec}", "高级工程师");
        params.put("${degree}", "大学本科");
        params.put("${education}", "文学学士");
        params.put("${school}", "北京大学文院");
        params.put("${major}", "语言学");
        params.put("${dutyDegree}", "研究生毕业");
        params.put("${dutyEducation}", "其他");
        params.put("${dutySchool}", "四川大学土木学院");
        params.put("${dutyMajor}", "工程造价");
        params.put("${jobName}", "党委书记,组织部长,宣传部部长");

        //图片设置
        WordImage wordImage = new WordImage();
        wordImage.setHeight(150);
        wordImage.setWidth(100);
        byte[] imageBytes = FileUtil.readBytes("templates/fm.png");
        wordImage.setSource(imageBytes);
        params.put("@{photo}", wordImage);

        //一段长文本拆分,按照分行进行展示,例如简历这种
        String resume = "2017.08--2018.08  北京大学光华管理学院工商管理就读研究生\r2023.05--2023.09  简历测试职务\r2023.05--2023.09  外部人员挂职职务\r2023.09--         图书档案资料人员";
        params.put("${resume}", resume);

        //2、============================获取word模板===============================
        Word07Writer writer = WordUtil.getWriter(FileUtil.file("templates/mb.docx"));
        XWPFDocument document = writer.getDoc();//获取模板文档

        //3、============================获取模板文本的段落===============================
        Iterator paragraphStrings = document.getParagraphsIterator();
        while (paragraphStrings.hasNext()) {
            XWPFParagraph paragraph = paragraphStrings.next();
            log.info("文本段落文字:{}", paragraph.getText());
        }

        //4、============================获取模板表格的段落===============================
        Iterator tableIterator = document.getTablesIterator();
        while (tableIterator.hasNext()) {
            XWPFTable table = tableIterator.next();
            Iterator rows = table.getRows().listIterator();
            while (rows.hasNext()) {
                XWPFTableRow row = rows.next();
                Iterator cells = row.getTableCells().listIterator();
                while (cells.hasNext()) {
                    XWPFTableCell cell = cells.next();
                    List paragraphCells = cell.getParagraphs();
                    //只去表格中的一个段落
                    XWPFParagraph paragraph = CollectionUtil.isNotEmpty(paragraphCells) ? paragraphCells.get(0) : null;
                    if(paragraph != null){
                        String paragraphString = paragraph.getText();//段落中的文字
                        //占位符替换
                        TemplateProcessor.matchTemplate(paragraphString, params, paragraph);
                    }
                }
            }
        }

        //5、======================输出文件====================================
        // 设置content—type
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset:utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=data.docx");

        // 设置标题
        //Content-disposition是MIME协议的扩展,MIME协议指示MIME用户代理如何显示附加的文件。
        ServletOutputStream outputStream = response.getOutputStream();

        //将Writer刷新到OutPut
        writer.flush(outputStream, true);
        outputStream.close();
    }
}
package com.example.demo.excel;

import cn.hutool.poi.word.PicType;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;

/**
 * word模板处理
 * @author xiajun
 */
@Slf4j
public class TemplateProcessor {


    final static Pattern patternString = Pattern.compile("\\$\\{[^{}]+}");//匹配文字
    final static Pattern patternTable = Pattern.compile("#\\{[^{}]+}");//匹配表格
    final static Pattern patternImg = Pattern.compile("@\\{[^{}]+}");//匹配照片

    /**
     * 模板占位符匹配
     *
     * @param template
     * @param variables
     * @return
     */
    public static void matchTemplate(String template, Map variables, XWPFParagraph paragraph) {
        //文字占位符替换
        Matcher matcher = patternString.matcher(template);
        while (matcher.find()) {
            String variable = matcher.group();//占位符
            dealXWPFRun(paragraph,variables,variable);//文档中占位符去除并设置套打文字
        }

        //图片占位符替换
        Matcher matcherImg = patternImg.matcher(template);
        while (matcherImg.find()) {
            String variable = matcherImg.group();//占位符
            dealXWPFRun(paragraph,variables,variable);//文档中占位符去除并设置套打图片

        }
    }

    /**
     * 获取文档占位符run,并且进行替换
     * @param paragraph
     * @param variables
     * @param variable
     */
    public static void dealXWPFRun(XWPFParagraph paragraph, Map variables, String variable){
        Object object = variables.get(variable);//需要替换的对象

        if (paragraph != null) {
            //获取占位符第一个
            String beginTag = variable.substring(0, 1);
            Iterator runs = paragraph.getRuns().listIterator();
            boolean flag = false;//是否开始拼接

            StringBuffer placeholder = new StringBuffer();
            List> allRuns = new ArrayList<>();//所有占位符涉及到的run
            List currentRuns = new ArrayList<>();//当前占位符涉及到的run
            while (runs.hasNext()) {
                XWPFRun run = runs.next();
                //开始符号处理
                if (run.text().contains(beginTag)) {
                    flag = true;
                }
                if (flag) {
                    String runString = run.text();
                    placeholder.append(runString);
                    currentRuns.add(run);
                }
                if (variable.equals(placeholder.toString())) {
                    allRuns.add(currentRuns);
                    currentRuns = new ArrayList<>();//重置list
                    flag = false;
                }
            }

            //将占位符涉及到的每个run list的第一个元素进行赋值,其他设置为空
            Iterator> iterator = allRuns.listIterator();
            while (iterator.hasNext()) {
                List runList = iterator.next();
                for (int i = 0; i < runList.size(); i++) {
                    if (i == 0) {
                        //文字处理
                        if(object instanceof String){
                            setRunText(runList.get(i),(String)object);
                        }
                        //图片处理
                        if(object instanceof WordImage){
                            setRunImg(runList.get(i),(WordImage)object);
                        }
                    } else {
                        runList.get(i).setText("", 0);
                    }
                }
            }
        }
    }

    /**
     * 设置Run中的图片
     * @param run
     * @param wordImage
     */
    private static void setRunImg(XWPFRun run, WordImage wordImage){
        PicType picType = wordImage.getImageType();
        try {
            run.setText("", 0);
            //往文档加入图片
            String picId = run.getDocument().addPictureData(wordImage.getSource(), picType.getValue());
            //将图片放在指定run中
            insertImageInRun(run, picId, run.getDocument().getNextPicNameNumber(picType.getValue()),
                    wordImage.getWidth(), wordImage.getHeight());
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置Run中的文本
     *
     * @param run
     * @param text
     */
    private static void setRunText(XWPFRun run, String text) {
        if (text.contains("\r")) {
            String[] split = text.split("\r");
            List contents = Arrays.asList(split);

            run.setText(contents.get(0), 0);
            XWPFParagraph paragraph =(XWPFParagraph)run.getParent();

            XWPFTableCell cell = (XWPFTableCell)paragraph.getBody();

            for (int i = 1; i < contents.size(); i++) {

                //替换的肯定有段落获取第一个段落
                XWPFParagraph newParagraph = cell.addParagraph();
                newParagraph.getCTP().setPPr(paragraph.getCTP().getPPr());
                XWPFRun newRun = newParagraph.createRun();

                newRun.getCTR().setRPr(run.getCTR().getRPr());
                String content = contents.get(i);
                newRun.setText(content);
            }
        } else {
            run.setText(text,0);
        }
    }

    /**
     * run中插入图片
     *
     * @param run
     * @param picId
     * @param id
     * @param width
     * @param height
     */
    private static void insertImageInRun(XWPFRun run, String picId, int id, int width, int height) {
        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
        CTInline inline = run.getCTR().addNewDrawing().addNewInline();

        String picXml = "" +
                "" +
                "   " +
                "      " +
                "         " +
                "            " +
                "            " +
                "         " +
                "         " +
                "            " +
                "            " +
                "               " +
                "            " +
                "         " +
                "         " +
                "            " +
                "               " +
                "               " +
                "            " +
                "            " +
                "               " +
                "            " +
                "         " +
                "      " +
                "   " +
                "";

        XmlToken xmlToken = null;
        try {
            xmlToken = XmlToken.Factory.parse(picXml);
        } catch (XmlException xe) {
//            xe.printStackTrace();
            throw new RuntimeException("图片XML解析失败");
        }
        inline.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");
    }
}

4、导出效果:

java导出word套打_第2张图片

注意事项:如果你调整了代码设置数据,但是没生效,把target目录下的class文件删除重启哈就生效了。

============================好用记得点个赞哟!!!==========================

你可能感兴趣的:(java,开发语言)