Java导出word文档

492 阅读2分钟

记录

最近接到一个需求,将信息按照指定模板导出成word文档。基于SpringBoot,实现如下。

引入依赖

<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>3.0.3</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>3.0.3</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>3.0.3</version>
</dependency>

准备word模板

image.png

准备好模板,将模板放在resource的static目录下

编写业务逻辑并导出到模板

此处参考了大佬的笔记java如何导出word和wps文档,但在发布运行的时候出现了问题,问题出现以下代码中。

    String path = "";
    try {
        //取到模板所在系统中的静态资源位置
        path = ResourceUtils.getFile("classpath:static/wps/handleTip.docx").getPath();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    ExportWord.exportWord(path,"test", "HandleTip.docx", hashMap,request,response);

在idea本地环境启动时,程序可以通过模板路径拿到模板资源。但在jar包运行的过程中,路径会发生变化,此时程序根据路径找不到对应的模板,就会发生NPE。此时需要将模板通过输入流的形式进行传参,而不是资源路径

InputStream is = null;
try {
    //取到模板所在系统中的静态资源的输入流
    ClassPathResource resource = new ClassPathResource("static/test.docx");
    is = resource.getInputStream();
} catch (Exception e) {
    e.printStackTrace();
}

同时对应的工具类也需要根据传参进行相应的修改。原工具类中通过路径获取到模板对象完成属性设置,此时只需要根据InputStream进行相同操作即可。

原:

XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params);

现:

WordExportUtil.exportWord07(new MyXWPFDocument(is), params);

完整的业务逻辑如下:


public void exportWord(String id, HttpServletRequest request, HttpServletResponse response) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Organization model = this.selectById(id);
    //处理模板需要的参数信息
    Map<String, Object> hashMap = Maps.newHashMap();
    //通过反射完成所有参数值的设置
    Field[] fields = OrganizationListReflectionDto.class.getDeclaredFields();
    for (Field field : fields) {
        String fieldName = field.getName();
        Object value = OrganizationList.class.getDeclaredMethod("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1)).invoke(model);
        hashMap.put(fieldName, value);
    }
    
    hashMap.put("title", "测试");
    InputStream is = null;
    try {
        //取到模板所在系统中的静态资源的输入流
        ClassPathResource resource = new ClassPathResource("static/specialOrg.docx");
        is = resource.getInputStream();
    } catch (Exception e) {
        e.printStackTrace();
    }

    //导出word
    ExportWordUtil.exportWord(is,"test", "test.docx", hashMap, request, response);
}

工具类

public static void exportWord(InputStream is, String temDir, String fileName, Map<String,Object> params, HttpServletRequest request, HttpServletResponse response){
    Assert.notNull(temDir,"临时文件路径不能为空");
    Assert.notNull(temDir,"导出文件名不能为空");
    Assert.isTrue(fileName.endsWith(".docx"),"word导出请使用docx格式");
    FileOutputStream fos = null;
    OutputStream out = null;
    if (!temDir.endsWith("/")){
        temDir = temDir+ File.separator;
    }
    File dir = new File(temDir);
    if (!dir.exists()){
        dir.mkdirs();
    }
    try {
        String userAgent = request.getHeader("user-agent").toLowerCase();
        if (userAgent.contains("msie")||userAgent.contains("like gecko")){
            fileName = URLEncoder.encode(fileName,"UTF-8");
        }else {
            fileName = new String(fileName.getBytes("utf-8"),"ISO-8859-1");
        }
        WordExportUtil.exportWord07(new MyXWPFDocument(is), params);
        String tmpPath = temDir + fileName;
        fos = new FileOutputStream(tmpPath);
        doc.write(fos);
        //设置强制下载不打开
        response.setContentType("application/force-download");
        //设置文件名
        response.addHeader("Content-Disposition","attachment;fileName=" + fileName);
        out = response.getOutputStream();
        doc.write(out);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        try {
            assert out != null;
            out.close();
            fos.close();
            delFileWord(temDir,fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}