Java导出docx文件

docx

docx是Microsoft Office2007之后版本使用的,用新的基于XML的压缩文件格式取代了其目前专有的默认文件格式,在传统的文件名扩展名后面添加了字母“x”(即“.docx”取代“.doc”、“.xlsx”取代“.xls”、“.pptx”取代“.ppt”)。

如何做导出

docx是一个压缩文件,所以要导出docx就必须要先进行解压,然后进行模板替换。再压缩为docx。


image.png

目录结构如下:


TIM图片20190320123606.png

踩坑记录:
导入的图片后缀必须为jpeg

代码实现

压缩解压代码

package com.hengyi.docxdemo;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 *
 * @author dongzp
 * @date 2019-03-20
 * @version 1.0
 */
public class ZipUtils {

    /**
     * 使用GBK编码可以避免压缩中文文件名乱码
     */
    private static final String CHINESE_CHARSET = "GBK";

    /**
     * 文件读取缓冲区大小
     */
    private static final int CACHE_SIZE = 1024;

    /**
     * 

* 压缩文件 *

* * @param sourceFolder 压缩文件夹 * @param zipFilePath 压缩文件输出路径 * @throws Exception */ public static void zip(String sourceFolder, String zipFilePath) throws Exception { OutputStream out = new FileOutputStream(zipFilePath); BufferedOutputStream bos = new BufferedOutputStream(out); ZipOutputStream zos = new ZipOutputStream(bos); // 解决中文文件名乱码 // zos.setEncoding(CHINESE_CHARSET); File file = new File(sourceFolder); String basePath = null; if (file.isDirectory()) { basePath = file.getPath(); } else { basePath = file.getParent(); } zipFile(file, basePath, zos); zos.closeEntry(); zos.close(); bos.close(); out.close(); } /** *

* 递归压缩文件 *

* * @param parentFile * @param basePath * @param zos * @throws Exception */ private static void zipFile(File parentFile, String basePath, ZipOutputStream zos) throws Exception { File[] files; if (parentFile.isDirectory()) { files = parentFile.listFiles(); } else { files = new File[1]; files[0] = parentFile; } String pathName; InputStream is; BufferedInputStream bis; byte[] cache = new byte[CACHE_SIZE]; for (File file : files) { if (file.isDirectory()) { zipFile(file, basePath, zos); } else { pathName = file.getPath().substring(basePath.length() + 1); is = new FileInputStream(file); bis = new BufferedInputStream(is); zos.putNextEntry(new ZipEntry(pathName)); int nRead = 0; while ((nRead = bis.read(cache, 0, CACHE_SIZE)) != -1) { zos.write(cache, 0, nRead); } bis.close(); is.close(); } } } /** *

* 解压压缩包 *

* * @param zipFilePath 压缩文件路径 * @param destDir 压缩包释放目录 * @throws Exception */ /** * 解压文件 * @param zipPath 要解压的目标文件 * @param descDir 指定解压目录 * @return 解压结果:成功,失败 */ public static boolean unZip(String zipPath, String descDir) { File zipFile = new File(zipPath); boolean flag = false; File pathFile = new File(descDir); if(!pathFile.exists()){ pathFile.mkdirs(); } ZipFile zip = null; try { zip = new ZipFile(zipFile, Charset.forName("gbk"));//防止中文目录,乱码 for(Enumeration entries = zip.entries(); entries.hasMoreElements();){ ZipEntry entry = (ZipEntry)entries.nextElement(); String zipEntryName = entry.getName(); InputStream in = zip.getInputStream(entry); //指定解压后的文件夹+当前zip文件的名称 String outPath = (descDir+zipEntryName).replace("/", File.separator); //判断路径是否存在,不存在则创建文件路径 File file = new File(outPath.substring(0, outPath.lastIndexOf(File.separator))); if(!file.exists()){ file.mkdirs(); } //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压 if(new File(outPath).isDirectory()){ continue; } //保存文件路径信息(可利用md5.zip名称的唯一性,来判断是否已经解压) System.err.println("当前zip解压之后的路径为:" + outPath); OutputStream out = new FileOutputStream(outPath); byte[] buf1 = new byte[2048]; int len; while((len=in.read(buf1))>0){ out.write(buf1,0,len); } in.close(); out.close(); } flag = true; zip.close(); } catch (IOException e) { e.printStackTrace(); } return flag; } public static void main(String[] args){ //1.压缩一个文件 try { unZip("E:\\zzzz.zip","E:\\zzzz\\"); System.out.println("压缩完成"); } catch (Exception e) { e.printStackTrace(); } } }

最终实现

/**
 * Created:2019/3/20
 * Time:9:32
 * Author:dongzp
 * Email:[email protected]
 * Project:docx-demo
 * Use:
 */
public class WordDocxExportUtil {

    /*
     * 实现文件的拷贝
     * @param srcPathStr
     *          源文件的地址信息
     * @param desPathStr
     *          目标文件的地址信息
     */
    private static String copyFile(String srcPathStr, String desPath,String newFileName) {
        newFileName = "image" + newFileName + ".jpeg";
        desPath = desPath + File.separator + newFileName;
        try{
            //2.创建输入输出流对象
            FileInputStream fis = new FileInputStream(srcPathStr);
            FileOutputStream fos = new FileOutputStream(desPath);

            //创建搬运工具
            byte datas[] = new byte[1024*8];
            //创建长度
            int len = 0;
            //循环读取数据
            while((len = fis.read(datas))!=-1){
                fos.write(datas,0,len);
            }
            //3.释放资源
            fis.close();
            fos.close();
            return newFileName;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 清空媒体文件
     * @param media
     */
    private static void clearMediaFile(File media){
        System.out.println("meida:" + media.isDirectory());
        if(media.isDirectory()){
            File[] fileList = media.listFiles();
            if(fileList != null){
                for(File file : fileList)
                    if(file.exists())
                        file.delete();
            }
        }
    }


    /**
     * 模板替换
     * @param templateFile
     * @param distFile
     */
    private static void templateReplace(String templateDir,String templateFile,String distFile,Map data)throws Exception{
        Configuration config = new Configuration();
        config.setDirectoryForTemplateLoading(new File(templateDir));
        config.setObjectWrapper(new DefaultObjectWrapper());
        Template template = config.getTemplate(templateFile, "UTF-8");

        FileOutputStream fos = new FileOutputStream(distFile);
        Writer out = new OutputStreamWriter(fos, "UTF-8");
        template.process(data, out);
        out.flush();
        out.close();
    }

    /**
     * 导出Docx
     * @param outFile           导出的目录
     * @param template          模板文件根目录
     * @param documentFtl       document模板文件
     * @param documentRelsFtl   documentRels模板文件
     * @param data              document数据
     * @param images            documentRles数据
     * @return
     * @throws Exception
     */
    public static  void exportDocx(File outFile,File template,File documentFtl,File documentRelsFtl,Map data,List> images, HttpServletResponse response)throws Exception{
        /**获取document.xml文件路径*/
        File document = new File(template.getAbsolutePath() + File.separator + "word","document.xml");
        System.out.println("获取document.xml:" + document.getAbsolutePath());

        /**获取document.xml.rels文件路径*/
        File documentRels = new File(template.getAbsolutePath() + File.separator + "word" + File.separator + "_rels","document.xml.rels");
        System.out.println("获取document.xml.rels:" + documentRels.getAbsolutePath());

        /**获取media目录*/
        File mediaDir = new File(template.getAbsolutePath() + File.separator + "word" + File.separator + "media" + File.separator);
        if(!mediaDir.exists())
            throw new RuntimeException("media不存在");
        // TODO: 2019/3/20 清空media 模板
        clearMediaFile(mediaDir);

        templateReplace(documentFtl.getParent(),documentFtl.getName(),document.getAbsolutePath(),data);

        for(Map image : images){
            String newFileName = copyFile(image.get("image"),mediaDir.getAbsolutePath(),image.get("index"));
            if(newFileName == null)
                image.put("image","image.jpeg");
            else
                image.put("image",newFileName);
        }

        Map rels = new HashMap<>();
        rels.put("relsList",images);

        templateReplace(documentRelsFtl.getParent(),"document.xml.rels.ftl",documentRels.getAbsolutePath(),rels);

        /**压缩模板文件生成docx*/
        ZipUtils.zip(template.getAbsolutePath(),outFile.getAbsolutePath());


        /**导出*/
        InputStream is = new FileInputStream(outFile);
        response.reset();
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8");
        String docFileName = outFile.getName();
        docFileName = new String(docFileName.getBytes("utf-8"),"iso-8859-1");
        response.addHeader("Content-Disposition", "attachment;filename="+docFileName);

        byte[] b = new byte[1024];
        int len;
        while ((len=is.read(b)) >0) {
            response.getOutputStream().write(b,0,len);
        }
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }
}

你可能感兴趣的:(Java导出docx文件)