poi根据模版生成word(包括导出)

根据word模版生成新的word直接把流输出 下载
进行改造的作为笔记 记录一下 大佬勿喷!!!

下面展示完整的代码

1.controller层
@RequestMapping(value = "/report",method = RequestMethod.POST)
    @ApiOperation(value = "生成word",notes = "生成word")
    @ResponseBody
    public ResponseVo report(@RequestBody WordReportVo wordReportVo, HttpServletResponse response) throws IOException {
        dataQdService.report(wordReportVo,response);
        return new ResponseVo();
    }

2.service层
提前把模版设计好放到resources
 @Override
    public void report(WordReportVo wordReportVo, HttpServletResponse response) throws IOException {

        if (StringUtils.isEmpty(wordReportVo.getXmName()) || StringUtils.isEmpty(wordReportVo.getTzdName())
                || StringUtils.isEmpty(wordReportVo.getTzdCode()) || StringUtils.isEmpty(wordReportVo.getContent())) {
            throw new BaseException(CoreErrorCode.REQUIRED_PARAM_EMPTY.getCode());
        }
        InputStream resourceAsStream = DataQdServiceImpl.class.getResourceAsStream("/xxx.docx");
        XWPFDocument document = new XWPFDocument(resourceAsStream);
        Map<String, Object> map = new HashMap<>();
        map.put("xmName", wordReportVo.getXmName());
        map.put("tzdName", wordReportVo.getTzdName());
        map.put("tzdCode", wordReportVo.getTzdCode());
        map.put("content", wordReportVo.getContent());
        //这里复选框直接写死了
        map.put("tzData", "0".equals(wordReportVo.getTzData()) ? "YES ☑ NO□" : "YES□ NO ☑");
        // 处理文档数据
        WordReportUtils.parseDocument(document, map);
        DataQdServiceImpl.downloadFile(document, response);
    }
3.是前端传过来的 我直接定义vo
@Data
public class WordReportVo {
    /**
     * 项目名称
     */
    private String xmName;
    /**
     * 提资单名称
     */
    private String tzdName;
    /**
     * 提资单编码
     */
    private String tzdCode;
    /**
     * 资料内容
     */
    private String content;

    /**
     * 是否包含假定提资数据
     * 是 0 否 1
     */
    private String tzData;

}

4.用到的工具类自己定义WordReportUtils有一些方法没有用到
public class WordReportUtils { 
    /**
     * @param document 文档文件
     * @param dataMap  数据Map集合
     * @return java.lang.String
     * @description:
     * @author GPeng
     * @time 2022/11/09 15:34
     **/
    public static String parseDocument(XWPFDocument document, Map<String, Object> dataMap) {

        // 获取文档中所有对象 (段落 + 表格)
        List<IBodyElement> bodys = document.getBodyElements();
        // 模板文件(段落 + 表格) 总个数
        int templateSize = bodys.size();
        // 最终结果
        String result = "";
        // 遍历文档内容
        // 当前操作表格对象的索引
        int curT = 0;
        // 当前操作段落对象的索引
        int curP = 0;
        for (int i = 0; i < templateSize; i++) {
            // 单个 段落 或 表格
            IBodyElement body = bodys.get(i);
            // 表格类型
            try {
                if (BodyElementType.TABLE.equals(body.getElementType())) {
                    // 处理表格内容
                    table(body, curT, dataMap);
                } else if (BodyElementType.PARAGRAPH.equals(body.getElementType())) {
                    paragraph(body, curP, dataMap);
                }
            } catch (Exception e) {
                e.printStackTrace();
                result = e.getMessage();
            }
        }
        result = "文档内容处理完成";
        return result;
    }

    /**
     * @param body    单个表格个体
     * @param index   表格所处文档索引
     * @param dataMap 所有数据内容
     * @return java.lang.String
     * @description: 处理表格内容
     * @author GPeng
     * @time 2022/11/09 16:18
     **/
    public static String table(IBodyElement body, int index, Map<String, Object> dataMap) {
        // 通过tables集合获取对应索引位置table
        List<XWPFTable> tables = body.getBody().getTables();
        XWPFTable table = tables.get(index);

        if (table != null) {
            // 获取所有行
            List<XWPFTableRow> rows = table.getRows();
            // 表格标题不容更改,只需替换相关内容
            for (XWPFTableRow row : rows) {
                // 获取单元格
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    // 判断单元格是否有需要替换数据
                    // 有,返回相关段落位置   没有,返回0
                    // 记录段落位置,防止对所需更换数据进行样式、格式操作时,对模板中设置好的段落文字进行改动
                    List<Integer> integers = checkText(cell);
                    List<XWPFParagraph> paragraphs = cell.getParagraphs();
                    for (int i = 0; i < paragraphs.size(); i++) {
                        if (integers.contains(i)) { // 存在的段落更换文本
                            List<XWPFRun> runs = paragraphs.get(i).getRuns();
                            for (XWPFRun run : runs) {
                                run.setFontFamily("宋体"); // 设置字体
                                run.setFontSize(12); // 小五号字体 如需其他字体自行查对应大小
                                Object ob = changeValue(run.toString(), dataMap);// 替换内容
                                if (ob instanceof String) {
                                    run.setText((String) ob, 0);
                                } else if (ob instanceof Map) {
                                   // run.setText("", 0); //清空段落文字内容,方便填充图片`
                                    Map o = (Map) ob;
                                    // 获取元素
                                    int width = (int) o.get("width");
                                    int height = (int) o.get("height");
                                    int picType = getPictureType((String) o.get("type"));
                                    byte[] bs = (byte[]) o.get("con");
                                    try {
                                        // 写入图片
                                       // run.addPicture(new ByteArrayInputStream(bs), picType, "Xiong.jpg", width, height);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        return "元素替换失败:" + e.getMessage();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        return "元素替换完成";
    }

    /**
     * @param body    单个段落个体
     * @param index   段落所处文档索引
     * @param dataMap 所有数据内容
     * @return java.lang.String
     * @description: 处理段落内容
     * @author GPeng
     * @time 2022/11/09 16:19
     **/
    public static String paragraph(IBodyElement body, int index, Map<String, Object> dataMap) {
        // 目前我个人需求未接触段落,后期补充
        return null;
    }

    /**
     * @param type 图片类型
     * @return int
     * @description: 获取各类型图片对应字典值
     * @author GPeng
     * @time 2022/11/10 11:17
     **/
    private static int getPictureType(String type) {
        int res = XWPFDocument.PICTURE_TYPE_PICT;
        if (type != null) {
            if (type.equalsIgnoreCase("png")) {
                res = XWPFDocument.PICTURE_TYPE_PNG;
            } else if (type.equalsIgnoreCase("dib")) {
                res = XWPFDocument.PICTURE_TYPE_DIB;
            } else if (type.equalsIgnoreCase("emf")) {
                res = XWPFDocument.PICTURE_TYPE_EMF;
            } else if (type.equalsIgnoreCase("jpg") || type.equalsIgnoreCase("jpeg")) {
                res = XWPFDocument.PICTURE_TYPE_JPEG;
            } else if (type.equalsIgnoreCase("wmf")) {
                res = XWPFDocument.PICTURE_TYPE_WMF;
            }
        }
        return res;
    }

    /**
     * @param value      模板需要替换的区域
     * @param dataSource 传入信息集合
     * @return java.lang.String 模板需要替换区域信息集合对应值
     * @description: 更换模板中所需替换信息
     * @author GPeng
     * @time 2022/11/09 16:47
     **/
    private static Object changeValue(String value, Map<String, Object> dataSource) {
        Set<Map.Entry<String, Object>> entries = dataSource.entrySet();
        Object val = "";
        for (Map.Entry<String, Object> entry : entries) {
            // 匹配格式 ${key}
            String key = "${" + entry.getKey() + "}";
            // 判断是否存在可替换内容
            if (value.indexOf(key) != -1) {
                val = entry.getValue();
            }
            // 判断该区域是否有需替换内容 (大概率无用,checkText()已综合所需替换段落)
//            if (value.indexOf("$") == -1) {
//                value = "";
//            }
        }
        return val;
    }

    /**
     * @param cell 单元格
     * @return void
     * @description: 判断是否有数据需要进行更换
     * @author GPeng
     * @time 2022/11/09 16:31
     **/
    private static List<Integer> checkText(XWPFTableCell cell) {
        List<Integer> integers = new ArrayList<>();
        List<XWPFParagraph> paragraphs = cell.getParagraphs();
        int par = 0; // 记录段落位置
        for (XWPFParagraph paragraph : paragraphs) {
            // 获取段落文本
            String text = paragraph.getText();
            // 段落如有 $ 标明 , 则需更换数值
            if (text.indexOf("$") != -1) {
                // 记录段落位置
                integers.add(par);
            }
            par++;
        }
        return integers;
    }

    /**
     * @param imageUrl 图片文件路径地址
     * @return byte[]
     * @description: 将图片转换为字节数组
     * @author GPeng
     * @time 2022/11/10 10:52
     **/
    public static byte[] getImageByteArray(String imageUrl) {
        try {
            File file = new File(imageUrl);
            InputStream in = new FileInputStream(file);
            byte[] bytes = IOUtils.toByteArray(in);
            // 可以打印输出查看是否有误
//            System.out.println(Arrays.toString(bytes));
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

5.我直接输出这个文件

public static String downloadFile(XWPFDocument document, HttpServletResponse response) {
        OutputStream out = null;
        try {
            response.setStatus(200);
            //配置导出的word名称&后缀
            response.addHeader("Content-Disposition", "attachment; filename=" + "xxx.docx");
//            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setContentType("application/octet-stream");
            out = response.getOutputStream();
            document.write(out);
        } catch (Exception e) {
            e.printStackTrace();
//            response.setContentType("application/json;charset=utf-8");
        } finally {
            try {
                if (document != null) {
                    document.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return "下载成功";
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用JavaPOI来根据模板导出Word,你需要进行以下步骤: 1. 首先,你需要准备好Word模板文件,它将包含一些占位符,用于在运行时将数据填充到模板中。 2. 然后,你需要使用JavaPOI来读取模板文件,并将其加载到内存中。 3. 接下来,你需要使用JavaPOI来查找并替换模板中的占位符。可以使用Apache POI中提供的XWPFDocument类来代表Word文档。 4. 最后,你需要使用JavaPOI生成Word文档保存到磁盘上。 下面是一个示例代码,它将读取一个Word模板文件,将占位符替换为实际数据,并将生成的文档保存到磁盘上: ```java import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.HashMap; import java.util.Map; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; public class WordTemplateExample { public static void main(String[] args) throws Exception { // Load the Word template file FileInputStream fis = new FileInputStream("template.docx"); XWPFDocument document = new XWPFDocument(fis); // Replace the placeholders with actual data Map<String, String> data = new HashMap<>(); data.put("name", "John Doe"); data.put("address", "123 Main St."); replacePlaceholders(document, data); // Save the generated Word document FileOutputStream fos = new FileOutputStream("output.docx"); document.write(fos); fos.close(); // Close the document document.close(); } private static void replacePlaceholders(XWPFDocument document, Map<String, String> data) { for (XWPFParagraph paragraph : document.getParagraphs()) { for (XWPFRun run : paragraph.getRuns()) { String text = run.getText(0); if (text != null) { for (Map.Entry<String, String> entry : data.entrySet()) { if (text.contains(entry.getKey())) { text = text.replace(entry.getKey(), entry.getValue()); run.setText(text, 0); } } } } } } } ``` 在这个示例中,我们定义了一个名为 `replacePlaceholders()` 的方法,它将查找并替换Word文档中的占位符。我们使用 `XWPFDocument` 类来代表Word文档,使用 `XWPFParagraph` 和 `XWPFRun` 来访问文档中的段落和文本内容。我们将占位符和实际数据存储在一个 `Map` 中,并使用 `replacePlaceholders()` 方法将占位符替换为实际数据。 请注意,这只是一个简单的示例,你需要根据自己的需求进行适当的修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

高空二踢脚

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

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

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

打赏作者

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

抵扣说明:

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

余额充值