记录一次导出word文档踩的坑

项目中需要导出word文档,没写过就上网上搜了下,因为导出的word是有一定格式的,所以选择了依据模板导出的文章。为什么要在记录一遍呢,一是可以加深记忆,以后好找,二是因为踩了坑,在这里记录下来。
首先将实现代码记录下来:
工具类:

/**
 * 导出word文档工具类
 *
 * @Author: ljp
 * @CreateDate: 2021/1/27 10:20
 */
@Component
public class WordUtil {
    /**
     * description:
     * 导出word模板
     *
     * @param params:模板中需要替换的参数可多个传递 比如 若想文字能够多行,在参数Map<String,Object>中的Object放入List<string>
     * @param filename:导出的word文件名
     * @param response:
     * @return void
     * @Author any
     * @Date 2020/8/10 15:29
     */
    public void exportWord(Map<String, Object> params, String filename, HttpServletResponse response) throws IOException, InvalidFormatException {
        //固定模板
        InputStream is = new ClassPathResource("/templates/" + "temp.docx").getInputStream();
        XWPFDocument doc = new XWPFDocument(is);
        iterateTable(params, doc);
        OutputStream os = response.getOutputStream();
        //设置导出的内容是doc
        response.setContentType("application/octet-stream; charset=utf-8");
        response.setHeader("Content-disposition", "attachment; filename=" + filename);
        doc.write(os);
        close(os);
    }

    //开始遍历文档中的表格
    private void iterateTable(Map<String, Object> params, XWPFDocument doc) {
        List<XWPFTableRow> rows = null;
        List<XWPFTableCell> cells = null;
        List<XWPFTable> tables = doc.getTables();
        //遍历这个word文档的所有table表格
        for (XWPFTable table : tables) {
            rows = table.getRows();
            //遍历这个表格的所有行
            for (XWPFTableRow row : rows) {
                cells = row.getTableCells();
                //遍历这一行的单元格
                for (XWPFTableCell cell : cells) {
                    //判断该单元格的内容是否是字符串字段
                    if (strMatcher(cell.getText()).find()) {
                        //替换字符串 字符串可以多行 也可以一行
                        replaceInStr(cell, params);
                        continue;
                    }
                }
            }
        }
    }


    //返回模板中变量的匹配Matcher类
    private Matcher strMatcher(String str) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }

    //替换模板Table中相应字段为对应的字符串值
    private void replaceInStr(XWPFTableCell cell, Map<String, Object> params) {
        //两种数据类型  一种是直接String  还有一种是List<String>
        String key = cell.getText().substring(2, cell.getText().length() - 1);
        Integer datatype = getMapStrDataTypeValue(params, key);
        List<XWPFParagraph> parags = cell.getParagraphs();
        //先清空单元格中所有的段落
        for (int i = 0; i < parags.size(); i++) {
            cell.removeParagraph(i);
        }
        if (datatype.equals(0)) {
            return;
        } else if (datatype.equals(2)) {
            //如果类型是2 说明数据类型是List<String>
            List<String> strs = (List<String>) params.get(key);
            Iterator<String> iterator = strs.iterator();
            while (iterator.hasNext()) {
                XWPFParagraph para = cell.addParagraph();
                XWPFRun run = para.createRun();
                run.setText(iterator.next());
            }
        } else if (datatype.equals(3)) {
            String str = params.get(key).toString();
            cell.setText(str);
        }
    }

    //处理模板中的变量名字,去掉${}  然后根据这个变量名在参数map中查找对应的Value值
    private Integer getMapStrDataTypeValue(Map<String, Object> params, String key) {
        if (params.get(key) == null) {
            return 0;
        } else if (params.get(key) instanceof List) {
            return 2;
        } else if (params.get(key) instanceof String) {
            return 3;
        } else {
            throw new RuntimeException("Str data type error!");
        }

    }


    /**
     * 关闭输入流
     *
     * @param is
     */
    private void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭输出流
     *
     * @param os
     */
    private void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

控制器代码实现:

 @Autowired
    private WordUtil wordUtil;

    @GetMapping("/download")
    public void download(HttpServletResponse response) throws IOException, InvalidFormatException {
        Map<String, Object> paramMap = new HashMap<>(16);
        paramMap.put("projectName", "张三");
        paramMap.put("workSegment", "李四");
        //模板的导出文件名字
        String filename = "test.docx";
        wordUtil.exportWord(paramMap, filename, response);
    }

文档中的模板变量需要使用${}来包裹,如下图:
在这里插入图片描述
以上就是简单的实现,讲讲我遇到的坑,需求中的文档长这样:
在这里插入图片描述
最开始我是按照这个编辑的文本,因为有两层表格,所以读不到里面表格的内容,所以每次导出里面的变量都没有成功替换,一直纳闷跟人家写的一模一样,debug走了一遍才找到原因,去掉外边那一层边框以后就正常了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值