优化二、XWPFDocument 生成doc、docx 功能优化(循环数据可不用手动添加)可在表格中插入图片

接上一篇文章

注:Consts 类放到了 第三篇文章里面

**

一、优化点:

**
优化过后 直接调用 CreateWordPoiUtils 中listToArray 方法 即可;
参数为 对象集合 优化过后增加的动态数据表格 比如有两个 则 对象中 只能有两个字段,不然可能会漏数据等问题

//这是之前的 增加循环数据 需要手动添加
// 插入数据构建
ArrayList<String[]> addList = new ArrayList<>();

addList.add(new String[]{"【插入11】", "【插入12】"});
addList.add(new String[]{"【插入21】", "【插入22】"});
// 插入数据构建
ArrayList<String[]> addList1 = new ArrayList<>();
addList1.add(new String[]{"【插入11】", "【插入12】"});
addList1.add(new String[]{"【插入21】", "【插入22】"});
addList1.add(new String[]{"【插入31】", "【插入32】"});
//map的key为第几个表格
Map<Integer, List<String[]>> map1 = new HashMap<>();
map1.put(2, addList);
map1.put(3, addList1);

//优化过后 直接调用 CreateWordPoiUtils 中listToArray 方法 即可 参数为 对象集合 优化过后增加的动态数据
//表格 比如有两个 则 对象中 只能有两个字段,不然可能会漏数据等问题
//map的key为第几个表格
Map<Integer, List<String[]>> map = new HashMap<>();
map.put(2, CreateWordPoiUtils.listToArray(vos));
map.put(3, CreateWordPoiUtils.listToArray(fileVos));

二、新增功能(全部代码 懒得写)图片可插入表格

1、jar包:以前的jar包就可以去掉了,只用这个就行

<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.6.0</version>
</dependency>

2、动态数据 对象类(我需要新增的表个就两个 就两个字段就好了 切记不可多)

package com.zjjw.jxtest.mode.vo;

import lombok.Data;

/**
 * @author: chenjiaxiang
 * @create: 2022/9/29 14:11
 **/
@Data
public class TestFileVo {

    private String name;
    private String remark;
}

三、全新代码 下面3条 很重要!!!

1)支持插入的图片为 图片的 URL
2)支持插入的图片 为 base64。
3)目前如需插入图片 则需要 在 设置map 的 Key时 如图片为 URL 则key中必须包含 file 或 File ,如为图片为base64时,则 map的key名称 必须包含 base64 或 Base64

/**
 * 生成word 工具类
 *
 * @author: chenjiaxiang
 * @create: 2022/9/29 11:27
 **/
@Slf4j
public class CreateWordPoiUtils {


    private static final String FILE = "file";
    private static final String FILE_F = "File";
    private static final String BASE64 = "base64";
    private static final String BASE64_B = "Base64";
    /**
     * 文件路径
     */
    private static final String FOP = "/Users/chenjx/Downloads/zipceshi/cc.docx";

    private static final String PATH = "/Users/chenjx/Downloads/zipceshi/";


    /**
     * 根据docx模版生成docx文件 适用于做测试用的 main
     *
     * @param templateName  模版路径名称
     * @param insertTextMap ${} 字符替换
     * @param map           表格数据需循环新增 动态数据
     * @param filePath      输出到本地的文件路径
     */
    public static void generateWord(String templateName, Map<String, Object> insertTextMap, Map<Integer, List<String[]>> map, String filePath) {
        InputStream inputStream = null;
        //获取docx解析对象
        XWPFDocument xwpfDocument = null;
        FileOutputStream fileOutputStream = null;
        try {
            String fileLocal = String.format("%s%s.docx", filePath, UUID.randomUUID());

            // 设置模板输入和结果输出
            fileOutputStream = new FileOutputStream(fileLocal);

            inputStream = Files.newInputStream(new File(templateName).toPath());
            //获取docx解析对象
            xwpfDocument = new XWPFDocument(inputStream);
            // 处理所有文段数据,除了表格
            handleParagraphs(xwpfDocument, insertTextMap);
            // 处理表格数据
            handleTable(xwpfDocument, insertTextMap, map);
            //二进制OutputStream
//            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //文档写入流
            xwpfDocument.write(fileOutputStream);
            log.info("word生成成功");
            //OutputStream写入InputStream二进制流
//            return new ByteArrayInputStream(baos.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (xwpfDocument != null) {
                    xwpfDocument.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }


    /**
     * 根据docx模版生成docx文件
     *
     * @param templateName  模版路径名称
     * @param insertTextMap ${} 字符替换
     * @param map           表格数据需循环新增 动态数据
     */
    public static InputStream generateWord(String templateName, Map<String, Object> insertTextMap, Map<Integer, List<String[]>> map) {
        ClassPathResource classPathResource = new ClassPathResource(templateName);
        InputStream inputStream = null;
        //获取docx解析对象
        XWPFDocument xwpfDocument = null;
        ByteArrayOutputStream baos = null;
        try {
            inputStream = classPathResource.getInputStream();
            //获取docx解析对象
            xwpfDocument = new XWPFDocument(inputStream);
            // 处理所有文段数据,除了表格
            handleParagraphs(xwpfDocument, insertTextMap);
            // 处理表格数据
            handleTable(xwpfDocument, insertTextMap, map);
            //二进制OutputStream
            baos = new ByteArrayOutputStream();
            //文档写入流
            xwpfDocument.write(baos);
            log.info("word生成成功");
            //OutputStream写入InputStream二进制流
            return new ByteArrayInputStream(baos.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (xwpfDocument != null) {
                    xwpfDocument.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 处理需要替换的数据和 需要表格新增的数据
     *
     * @param xwpfDocument  docx
     * @param insertTextMap ${} 数据
     * @param map           表格数据
     */
    public static void handleTable(XWPFDocument xwpfDocument, Map<String, Object> insertTextMap, Map<Integer, List<String[]>> map) {
        List<XWPFTable> tables = xwpfDocument.getTables();
        int tableIndex = 0;
        for (XWPFTable table : tables) {
            //表格坐标
            tableIndex++;
            List<XWPFTableRow> rows = table.getRows();
            if (rows.size() > 1) {
                if (isReplacement(table.getText())) {
                    // 替换数据
                    rows.stream().map(XWPFTableRow::getTableCells).forEach(tableCells -> {
                        tableCells.stream().filter(tableCell -> isReplacement(tableCell.getText())).forEach(tableCell -> {
                            List<XWPFParagraph> paragraphs = tableCell.getParagraphs();
                            //替换数据
                            paragraphs.stream().map(XWPFParagraph::getRuns).forEach(runs -> {
                                //获取map的key
                                runs.forEach(run -> {
                                    String key = matchesKey(tableCell.getText(), insertTextMap);
                                    if (Objects.isNull(insertTextMap.get(key))) {
                                        run.setText("", 0);
                                        return;
                                    }
                                    String string = insertTextMap.get(key).toString().replace("${", Consts.EMPTY_STRING).replace("}", Consts.EMPTY_STRING);
                                    try {
                                        if (key.contains(FILE) || key.contains(FILE_F)) {
                                            run.setText("", 0);
                                            for (String s1 : string.split(Consts.DEFAULT_SEPARATOR)) {
                                                //url转input
                                                //参数1:图片流数据 参数2:图片类型  参数3 图片名称  参数4:图片宽度  参数5:图片高度
                                                InputStream inputStream = getInputStream(s1);
                                                run.addPicture(inputStream, XWPFDocument.PICTURE_TYPE_PNG, UUID.randomUUID().toString(), Units.toEMU(128), Units.toEMU(128));
                                                inputStream.close();
                                            }
                                        } else if (key.contains(BASE64) || key.contains(BASE64_B)) {
                                            run.setText("", 0);
                                            for (String s1 : string.split(Consts.DEFAULT_SEPARATOR)) {
                                                //base64转input
                                                //参数1:图片流数据 参数2:图片类型  参数3 图片名称  参数4:图片宽度  参数5:图片高度
                                                InputStream inputStream = base64Input(s1);
                                                run.addPicture(inputStream, XWPFDocument.PICTURE_TYPE_PNG, UUID.randomUUID().toString(), Units.toEMU(128), Units.toEMU(128));
                                                inputStream.close();
                                            }
                                        } else {
                                            run.setText(insertTextMap.get(key).toString(), 0);
                                        }
                                    } catch (InvalidFormatException | IOException e) {
                                        throw new RuntimeException(e);
                                    }
                                });
                            });
                        });
                    });
                } else {
                    //处理新增表格数据
                    List<String[]> strings = map.get(tableIndex);
                    // 插入数据
                    IntStream.range(1, strings.size()).forEach(i -> table.createRow());
                    List<XWPFTableRow> rowList = table.getRows();
                    for (int i = 1; i < rowList.size(); i++) {
                        XWPFTableRow xwpfTableRow = rowList.get(i);
                        List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells();
                        for (int j = 0; j < tableCells.size(); j++) {
                            XWPFTableCell xwpfTableCell = tableCells.get(j);
                            xwpfTableCell.setText(strings.get(i - 1)[j]);
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换带有 ${}的数据
     *
     * @param wordValue 表格文本
     * @param map       数据
     * @return 数据
     */
    public static String matchesValue(String wordValue, Map<String, Object> map) {
        for (String s : map.keySet()) {
            String s1 = "${" + s + "}";
            if (s1.equals(wordValue)) {
                wordValue = String.valueOf(map.get(s));
            }
        }
        return wordValue;
    }

    /**
     * 判断是否有包含需替换的数据
     *
     * @param text 文本
     * @return boolean
     */
    public static boolean isReplacement(String text) {
        boolean check = false;
        if (text.contains(Consts.DOLLAR)) {
            check = true;
        }
        return check;
    }

    /**
     * 处理文段数据
     *
     * @param xwpfDocument  docx
     * @param insertTextMap ${}数据
     */
    public static void handleParagraphs(XWPFDocument xwpfDocument, Map<String, Object> insertTextMap) {
        xwpfDocument.getParagraphs().forEach(paragraph -> {
            String text = paragraph.getText();
            if (isReplacement(text)) {
                for (XWPFRun run : paragraph.getRuns()) {
                    // 判断带有${}的run
                    run.setText(matchesValue(run.text(), insertTextMap), 0);
                }
            }
        });

    }

    /**
     * base64转为输入流
     *
     * @param base64 编码
     * @return 输入流
     */
    public static InputStream base64Input(String base64) {
        BASE64Decoder decoder = new BASE64Decoder();
        InputStream inputStream;
        // Base64解码
        byte[] byteArr = new byte[0];
        try {
            byteArr = decoder.decodeBuffer(base64);
            inputStream = new ByteArrayInputStream(byteArr);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return inputStream;
    }

    /**
     * 【获取网络文件的输入流】
     *
     * @param filePath: 网络文件路径
     * @return java.io.InputStream
     */
    public static InputStream getInputStream(String filePath) throws IOException {
        InputStream inputStream = null;
        //创建URL
        URL url = new URL(filePath);
        //试图连接并取得返回状态码
        URLConnection urlconn = url.openConnection();
        urlconn.connect();
        HttpURLConnection httpconn = (HttpURLConnection) urlconn;
        int httpResult = httpconn.getResponseCode();
        if (httpResult == HttpURLConnection.HTTP_OK) {
            inputStream = urlconn.getInputStream();
        }
        return inputStream;
    }

    /**
     * 获取map的key
     */
    public static String matchesKey(String wordValue, Map<String, Object> map) {
        for (String s : map.keySet()) {
            String s1 = "${" + s + "}";
            if (s1.equals(wordValue)) {
                wordValue = s;
            }
        }
        return wordValue;
    }

    /**
     * 图片URL转Base64编码
     *
     * @param imgUrl 图片URL
     * @return Base64编码
     */
    public static String imageUrlToBase64(String imgUrl) {
        URL url = null;
        InputStream is = null;
        ByteArrayOutputStream outStream = null;
        HttpURLConnection httpUrl = null;
        try {
            url = new URL(imgUrl);
            httpUrl = (HttpURLConnection) url.openConnection();
            httpUrl.connect();
            httpUrl.getInputStream();

            is = httpUrl.getInputStream();
            outStream = new ByteArrayOutputStream();

            //创建一个Buffer字符串
            byte[] buffer = new byte[1024];
            //每次读取的字符串长度,如果为-1,代表全部读取完毕
            int len = 0;
            //使用输入流从buffer里把数据读取出来
            while ((len = is.read(buffer)) != -1) {
                //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
                outStream.write(buffer, 0, len);
            }
            // 对字节数组Base64编码
            return encode(outStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (outStream != null) {
                    outStream.close();
                }
                if (httpUrl != null) {
                    httpUrl.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * 图片转字符串
     *
     * @param image 图片Buffer
     * @return Base64编码
     */
    public static String encode(byte[] image) {
        BASE64Encoder decoder = new BASE64Encoder();
        return replaceEnter(decoder.encode(image));
    }

    /**
     * 字符替换
     *
     * @param str 字符串
     * @return 替换后的字符串
     */
    public static String replaceEnter(String str) {
        String reg = "[\n-\r]";
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(str);
        return m.replaceAll("");
    }

    /**
     * 将对象集合转为一个String[] 集合
     *
     * @param tList 对象集合
     * @param <T>   参数
     * @return 数组集合
     */
    public static <T> List<String[]> listToArray(List<T> tList) {
        ArrayList<String[]> arrayList = new ArrayList<>();
        tList.forEach(t -> {
            String[] filedName = getFiledName(t);
            List<String> to = Arrays.stream(filedName).map(s -> getFieldValueByName(s, t))
                    .map(fieldValueByName -> StringUtils.isEmpty(fieldValueByName) ? "" : String.valueOf(fieldValueByName)).collect(Collectors.toList());
            arrayList.add(to.toArray(new String[]{}));
        });
        return arrayList;
    }

    /**
     * 获取对象的 属性名
     *
     * @param o 对象名称
     * @return 属性数组
     */

    private static String[] getFiledName(Object o) {
        Field[] fields = o.getClass().getDeclaredFields();
        return Arrays.stream(fields).map(Field::getName).toArray(String[]::new);
    }

    /**
     * 根据字段名 获取该字段值
     *
     * @param fieldName 字段名
     * @param o         对象
     * @return 值
     */
    private static Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter);
            return method.invoke(o);
        } catch (Exception e) {
            log.error("获取属性值失败!" + e, e);
        }
        return null;
    }
}

**

四、举例子:

**

  /**
     * 模版文件路径
     */
    private static final String FOP = "/Users/chenjx/Downloads/zipceshi/cc.docx";

    private static final String PATH = "/Users/chenjx/Downloads/zipceshi/";

    public static void main(String[] args) {
        // 替换文本数据构建
        HashMap<String, Object> insertTextMap = new HashMap<>(16);
        String fileTwo = "https://img2.woyaogexing.com/2022/08/23/cc8909ab73204efd!400x400.png" +
                ",https://img2.woyaogexing.com/2022/08/23/cfcf821f37fa046e!400x400.jpg";
        String file = "https://img2.woyaogexing.com/2022/08/23/ea7f1d004fea3f11.jpg";
        String base64 = CreateWordPoiUtils.imageUrlToBase64(file);
        insertTextMap.put("orgName", "单位啊啊啊--");
        insertTextMap.put("base64", base64);
        insertTextMap.put("deptName", "我不听");
        insertTextMap.put("filePath", fileTwo);
        insertTextMap.put("nameBase64", base64);
        insertTextMap.put("nameFile", file);
        //模拟数据查出的数据 listOne
        List<TestFileVo> vos = new ArrayList<>();
        TestFileVo vo1 = new TestFileVo();
        vo1.setName("1");
//        vo1.setRemark("1");
        TestFileVo vo2 = new TestFileVo();
        vo2.setName("2");
        vo2.setRemark("2");
        TestFileVo vo3 = new TestFileVo();
        vo3.setName("3");
        vo3.setRemark("3");
        TestFileVo vo4 = new TestFileVo();
        vo4.setName("4");
        vo4.setRemark("4");
        vos.add(vo1);
        vos.add(vo2);
        vos.add(vo3);
        vos.add(vo4);
        //模拟数据查出数据 listTwo
        List<TestFileVo> fileVos = new ArrayList<>();
        TestFileVo fileVos1 = new TestFileVo();
        fileVos1.setName("5");
        fileVos1.setRemark("5");
        TestFileVo fileVos2 = new TestFileVo();
        fileVos2.setName("6");
        fileVos2.setRemark("6");
        TestFileVo fileVos3 = new TestFileVo();
        fileVos3.setName("7");
        fileVos3.setRemark("7");
        TestFileVo fileVos4 = new TestFileVo();
        fileVos4.setName("8");
        fileVos4.setRemark("8");
        TestFileVo fileVos5 = new TestFileVo();
        fileVos5.setName("9");
//        fileVos5.setRemark("");
        fileVos.add(fileVos1);
        fileVos.add(fileVos2);
        fileVos.add(fileVos3);
        fileVos.add(fileVos4);
        fileVos.add(fileVos5);
//        // 插入数据构建
//        ArrayList<String[]> addList = new ArrayList<>();
//
//        addList.add(new String[]{"【插入11】", "【插入12】"});
//        addList.add(new String[]{"【插入21】", "【插入22】"});
//        // 插入数据构建
//        ArrayList<String[]> addList1 = new ArrayList<>();
//        addList1.add(new String[]{"【插入11】", "【插入12】"});
//        addList1.add(new String[]{"【插入21】", "【插入22】"});
//        addList1.add(new String[]{"【插入31】", "【插入32】"});
//        //map的key为第几个表格
//        Map<Integer, List<String[]>> map1 = new HashMap<>();
//        map1.put(2, addList);
//        map1.put(3, addList1);

        //map的key为第几个表格
        Map<Integer, List<String[]>> map = new HashMap<>();
        map.put(2, CreateWordPoiUtils.listToArray(vos));
        map.put(3, CreateWordPoiUtils.listToArray(fileVos));
        CreateWordPoiUtils.generateWord(FOP, insertTextMap, map, PATH);
        log.info("word生成成功");
    }

五、效果:

模版存放位置:(可放到本地,也可放项目里,代码里有演示的)
模版:
在这里插入图片描述
导出效果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

C__jx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值