记录一次使用poi-tl将数据填充到docx中并下载(单独下载docx,批量下载zip)

话不多说,直接上代码:

  • 相关代码

配置文件application.yml中关于路径的配置

public void exportExperimentalData(ExportExperimentalDataReqVo reqVo, Long userId, HttpServletResponse response, HttpServletRequest request) {
    List<String> experimentalIds = reqVo.getExperimentalIds();
    List<ExperimentalDataIndex> list = new ArrayList<>();
    for (String experimentalId : experimentalIds) {
        ExperimentalDataIndex experimentalDataIndex = searchService.searchExperimentalById(experimentalId, EsIndexEnum.EXPERIMENTAL_DATA_INDEX.getIndexName());
        list.add(experimentalDataIndex);

        // 新增用户下载记录
        UserDownloadRecord downloadRecord = new UserDownloadRecord();
        downloadRecord.setUserId(userId);
        downloadRecord.setLiteratureId(experimentalId);
        downloadRecord.setTitle(experimentalDataIndex.getExperimentalTopic());
        downloadRecord.setSummary(experimentalDataIndex.getExperimentalConclusion());
        downloadRecord.setAuthor(experimentalDataIndex.getRecorder());
        downloadRecord.setDataType(2);//实验数据
        downloadRecord.setFinishTime(experimentalDataIndex.getFinishTime());
        downloadRecord.setCreateId(userId);
        downloadRecord.setCreateTime(new Date());
        userDownloadRecordMapper.insert(downloadRecord);
    }

    // 如果是单条下载 则下载为word  批量下载是zip格式
    if (list.size() == 1) {
        ExperimentalDataIndex experimentalDataIndex = list.get(0);
        String filePath = fileRoot;
        this.downloadExperimentalSingle(experimentalDataIndex, filePath, response, request);
    } else {
        String filePath = fileRoot + File.separator + "zip_path" + System.currentTimeMillis() + File.separator;
        this.downloadExperimentalBatch(list, filePath, response, request);
    }
}

/**
 * 批量下载
 *
 * @Param  list   
 * @Param  filePath   
 * @Param  response   
 * @Param  request     
 * @Return void
 **/
private void downloadExperimentalBatch(List<ExperimentalDataIndex> list, String filePath, HttpServletResponse response, HttpServletRequest request) {

    try {
        for (ExperimentalDataIndex experimentalDataIndex : list) {
            Map<String, Object> wordDataMap = new HashMap<>(32);
            wordDataMap.put("experimentalTopic", experimentalDataIndex.getExperimentalTopic());
            wordDataMap.put("recorder", userMapper.selectById(Long.parseLong(experimentalDataIndex.getRecorder())).getNickName());
            wordDataMap.put("major", experimentalDataIndex.getMajor());
            wordDataMap.put("classes", experimentalDataIndex.getClasses());
            wordDataMap.put("analyticalMethods", experimentalDataIndex.getAnalyticalMethods());
            wordDataMap.put("finishTime", experimentalDataIndex.getFinishTime());
            wordDataMap.put("experimentalIndicators", experimentalDataIndex.getExperimentalIndicators());
            wordDataMap.put("testConditions", experimentalDataIndex.getTestConditions());
            wordDataMap.put("experimentalScheme", experimentalDataIndex.getExperimentalScheme());
            // 实验附图
            List<ExperimentalDataImg> experimentalDataImgList = experimentalDataImgMapper.selectList(new
                    LambdaQueryWrapper<ExperimentalDataImg>().eq(ExperimentalDataImg::getExperimentalId,
                    experimentalDataIndex.getId()));

            // 附图导出封装类
            List<ExperimentalDataImgExportVo> imgExportVos = new ArrayList<>();

            int code = 1;
            for (ExperimentalDataImg experimentalDataImg : experimentalDataImgList) {
                ExperimentalDataImgExportVo experimentalDataImgExportVo = BaseDtoConvert.tToV(experimentalDataImg, ExperimentalDataImgExportVo.class);
                experimentalDataImgExportVo.setCode(code);
                if (StringUtils.isEmpty(experimentalDataImgExportVo.getRemarks())) {
                    experimentalDataImgExportVo.setRemarks("无");
                }
                imgExportVos.add(experimentalDataImgExportVo);
                code++;
            }
            wordDataMap.put("experimentalImg", imgExportVos);
            wordDataMap.put("experimentalConclusion", experimentalDataIndex.getExperimentalConclusion());

            String downloadFileName =
                    experimentalDataIndex.getExperimentalTopic() + System.currentTimeMillis() + ".docx";
            String savePath = filePath + downloadFileName;
            if (!FileUtil.exist(filePath)) {
                FileUtil.mkdir(filePath);
            }
            // 添加配置 循环表格行(实验附图)
            LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
            Configure config = Configure.builder()
                    .bind("experimentalImg", policy).build();
            //渲染文件
            XWPFTemplate compile = XWPFTemplate.compile("./template/实验数据导出模板_template.docx", config);
            compile.render(wordDataMap);
            compile.writeToFile(savePath);
        }

        // 设置压缩后的文件名
        String zipFileName = "实验数据.zip";
        // 压缩文件保存的路径
        String toPath = fileRoot + zipFileName;
        // 要压缩的文件目录
        String zipPath = filePath;
        ZipUtil.zip(zipPath, toPath);
        // 压缩完之后删除原文件
        FileUtils.deleteDirectory(new File(zipPath));

        try {
            File file = new File(toPath);
            String fileName = URLEncoder.encode(file.getName(), "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/zip");
            response.setContentLength((int) file.length());

            try (InputStream inputStream = new FileInputStream(file);
                 OutputStream outputStream = response.getOutputStream()) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    } catch (Exception e) {
        throw new ServiceException("下载实验数据失败!!" + e.getMessage());
    }
}

/**
 * 单独下载
 *
 * @Param  experimentalDataIndex  
 * @Param  filePath   
 * @Param  response   
 * @Param  request     
 * @Return void
 **/
private void downloadExperimentalSingle(ExperimentalDataIndex experimentalDataIndex, String filePath, HttpServletResponse response, HttpServletRequest request) {
    Map<String, Object> wordDataMap = new HashMap<>(32);
    wordDataMap.put("experimentalTopic", experimentalDataIndex.getExperimentalTopic());
    wordDataMap.put("recorder", userMapper.selectById(Long.parseLong(experimentalDataIndex.getRecorder())).getNickName());
    wordDataMap.put("major", experimentalDataIndex.getMajor());
    wordDataMap.put("classes", experimentalDataIndex.getClasses());
    wordDataMap.put("analyticalMethods", experimentalDataIndex.getAnalyticalMethods());
    wordDataMap.put("finishTime", experimentalDataIndex.getFinishTime());
    wordDataMap.put("experimentalIndicators", experimentalDataIndex.getExperimentalIndicators());
    wordDataMap.put("testConditions", experimentalDataIndex.getTestConditions());
    wordDataMap.put("experimentalScheme", experimentalDataIndex.getExperimentalScheme());
    // 实验附图
    List<ExperimentalDataImg> experimentalDataImgList = experimentalDataImgMapper.selectList(new
            LambdaQueryWrapper<ExperimentalDataImg>().eq(ExperimentalDataImg::getExperimentalId,
            experimentalDataIndex.getId()));

    // 附图导出封装类
    List<ExperimentalDataImgExportVo> imgExportVos = new ArrayList<>();

    int code = 1;
    for (ExperimentalDataImg experimentalDataImg : experimentalDataImgList) {
        ExperimentalDataImgExportVo experimentalDataImgExportVo = BaseDtoConvert.tToV(experimentalDataImg, ExperimentalDataImgExportVo.class);
        experimentalDataImgExportVo.setCode(code);
        if (StringUtils.isEmpty(experimentalDataImgExportVo.getRemarks())) {
            experimentalDataImgExportVo.setRemarks("无");
        }
        imgExportVos.add(experimentalDataImgExportVo);
        code++;
    }
    wordDataMap.put("experimentalImg", imgExportVos);
    wordDataMap.put("experimentalConclusion", experimentalDataIndex.getExperimentalConclusion());

    String downloadFileName =
            experimentalDataIndex.getExperimentalTopic() + System.currentTimeMillis() + ".docx";
    String savePath = filePath + downloadFileName;
    if (!FileUtil.exist(filePath)) {
        FileUtil.mkdir(filePath);
    }

    try {
        // 添加配置 循环表格行(实验附图)
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        Configure config = Configure.builder()
                .bind("experimentalImg", policy).build();
        //渲染文件
        XWPFTemplate compile = XWPFTemplate.compile("./template/实验数据导出模板_template.docx", config);
        compile.render(wordDataMap);
        compile.writeToFile(savePath);
        this.httpDownload(response, request, downloadFileName, savePath);
    } catch (Exception e) {
        throw new ServiceException("下载实验数据失败!!" + e.getMessage());
    }
}

private void httpDownload(HttpServletResponse response, HttpServletRequest request,
                          String downloadFileName, String savePath) throws IOException {
    InputStream is = new FileInputStream(savePath);
    OutputStream os = response.getOutputStream();
    String userAgent = request.getHeader("user-agent").toLowerCase();
    if (userAgent.contains("msie") || userAgent.contains("like gecko")) {
        // win10 ie edge 浏览器 和其他系统的ie
        downloadFileName = URLEncoder.encode(downloadFileName, "UTF-8");
    } else {
        //其他的浏览器
        downloadFileName = new String(downloadFileName.getBytes(StandardCharsets.UTF_8),
                StandardCharsets.ISO_8859_1);
    }
    response.setContentType(FileSuffixConstants.DOC);
    response.setCharacterEncoding("UTF-8");
    response.setHeader("content-disposition",
            "attachment;filename=" + downloadFileName);
    response.setHeader("Access-Control-Expose-Headers", "content-disposition");
    IOUtils.copy(is, os);
    is.close();
    os.close();
    os.flush();
}

下载模板 :

下载效果:

docx

zip(包含两个测试文档)

踩过的坑:

1.poi-tl的依赖跟xalan.jar有冲突,同时存在会报错 

java.lang.IllegalArgumentException: 不支持:http://javax.xml.XMLConstants/property/accessExternalStylesheet

已知:poi-ti中已排除 xalan.jar

注:我的项目中引入的docx4j,docx4j中包含xalan.jar;删除docx4j相关依赖,不再报上述错误

2.poi-tl的版本号必须用最新版 (因为我需要在docx中插入图片,需要用到其附件功能)

否则会报错 Caused by: java.lang.NoSuchMethodError: org.apache.poi.xwpf.usermodel.XWPFRun.getFontSizeAsDouble()Ljava/lang/Double;
报的poi的方法找不到

最新版的poi-tl用的poi版本是:

我的工程中其他模块引入了poi-ooxml,所以也要对其做一个版本的升级

参考文档:Poi-tl Documentation 

以上,就是整个使用poi-tl导出docx文档的全部细节以及注意事项。

  • 26
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
确保您已经在项目的pom.xml文件添加了poi-tl库的依赖: ```xml <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.12.0</version> </dependency> ``` 然后,您可以按照以下步骤使用poi-tl库来合并表格并下载Word文档: 1. 创建一个Word模板文件,其包含您要合并的表格。您可以使用Microsoft Word或其他编辑器创建模板文件,并确保在模板文件使用`${}`标记来标记需要替换的文本。 2. 创建一个Java类来处理导出请求。例如,创建一个名为WordExportController的类。 ```java import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.data.TableRenderData; import com.deepoove.poi.data.TextRenderData; import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; @Controller public class WordExportController { @GetMapping("/export") public ResponseEntity<InputStreamResource> exportWord() throws IOException { // 加载Word模板文件 XWPFTemplate template = XWPFTemplate.compile("templates/template.docx") .render(getTemplateData()); // 将生成的Word文档转换为字节数组 ByteArrayOutputStream out = new ByteArrayOutputStream(); template.write(out); byte[] documentBytes = out.toByteArray(); // 设置下载响应的头信息 HttpHeaders headers = new HttpHeaders(); headers.setContentDispositionFormData("attachment", "merged_table.docx"); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 创建一个包含Word文档字节数组的InputStreamResource InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(documentBytes)); // 返回响应实体 return ResponseEntity.ok() .headers(headers) .body(resource); } private Map<String, Object> getTemplateData() { Map<String, Object> data = new HashMap<>(); // 创建表格数据 TableRenderData tableData = new TableRenderData(); tableData.setHeader(new TextRenderData("FFFFFF", "Header 1")); tableData.setRow(new TextRenderData("FFFFFF", "Cell 1"), new TextRenderData("FFFFFF", "Cell 2")); // 将表格数据存储到模板数据 data.put("tableData", tableData); return data; } } ``` 3. 在resources目录下创建一个名为`template.docx`的Word模板文件,并按照您的需求设置表格样式和内容。在模板文件,您可以使用`${tableData}`来标记需要替换的表格数据。 4. 启动您的Spring Boot应用程序,并访问导出请求的URL(例如:http://localhost:8080/export)。将会自动下载名为`merged_table.docx`的Word文档,其包含合并表格的内容。 请确保按照您的需求修改代码,并根据模板文件的位置进行相应的调整。 希望对您有所帮助!如果您有任何其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值