用java实现word导出,如果不实现批量导出,可以只使用 word 替换工具,如果要实现批量导出,这里的解决办法是将所有的导出文件放入服务器临时文件,压缩后导出

1.依赖包

<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>3.9</version>
		</dependency>
		<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>

2. word模板替换工具

package com.**.**.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.util.Assert;
// 这是俩个常量包 BIAS = "/" , MSIE = "MSIE",TRIDENT = "Trident",MOZILLA = "Mozilla"
import com.***.***.core.constants.CoreConstant;  
import com.***.***.web.constants.EquipmentComputeConstants;

import cn.afterturn.easypoi.word.WordExportUtil;

public class ExportUtil {
	/**
	 * 导出word
	 * <p>
	 * 第一步生成替换后的word文件,只支持docx
	 * </p>
	 * <p>
	 * 第二步下载生成的文件
	 * </p>
	 * <p>
	 * 第三步删除生成的临时文件
	 * </p>
	 * 模版变量中变量格式:{{foo}}
	 * 
	 * @param templatePath
	 *            word模板地址
	 * @param temDir
	 *            生成临时文件存放地址
	 * @param fileName
	 *            文件名
	 * @param params
	 *            替换的参数
	 * @param request
	 *            HttpServletRequest
	 * @param response
	 *            HttpServletResponse
	 * @throws IOException
	 */
	public static void exportWord(String templatePath, String temDir, String fileName, Map<String, Object> params,
			HttpServletRequest request, HttpServletResponse response) throws IOException {
		Assert.notNull(templatePath, "模板路径不能为空");
		Assert.notNull(temDir, "临时文件路径不能为空");
		Assert.notNull(fileName, "导出文件名不能为空");
		Assert.isTrue(fileName.endsWith(".docx"), "word导出请使用docx格式");
		if (!temDir.endsWith(CoreConstant.BIAS)) {
			temDir = temDir + File.separator;
		}
		File dir = new File(temDir);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		FileInputStream in = null;
//		OutputStream out2 = null;
		try {
			XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params);
			String tmpPath = temDir + fileName;
			// 写在本地
			FileOutputStream fos = new FileOutputStream(tmpPath);
			doc.write(fos);

			/*
			 * ------------下载到本地------------ // 设置强制下载不打开
			 * response.setContentType("application/force-download"); // 设置文件名
			 * response.addHeader("Content-Disposition", "attachment;fileName="
			 * + fileName); OutputStream out = response.getOutputStream();
			 * doc.write(out); out.close();
			 */
			// -------浏览器下载--------------

			// 读取要下载的文件,保存到文件输入流
			in = new FileInputStream(tmpPath);
			// 获得浏览器代理信息
			final String userAgent = request.getHeader("USER-AGENT");
			// 判断浏览器代理并分别设置响应给浏览器的编码格式
			String finalFileName = null;
			if (StringUtils.contains(userAgent, EquipmentComputeConstants.MSIE) || StringUtils.contains(userAgent, EquipmentComputeConstants.TRIDENT)) {// IE浏览器
				finalFileName = URLEncoder.encode(fileName, "UTF8");
				System.out.println("IE浏览器");
			} else if (StringUtils.contains(userAgent, EquipmentComputeConstants.MOZILLA)) {// google,火狐浏览器
				finalFileName = new String(fileName.getBytes(), "ISO8859-1");
			} else {
				finalFileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
			}

//			// 缓存区
//			byte buffer[] = new byte[1024];
//			int len = 0;
//			// 循环将输入流中的内容读取到缓冲区中
//			while ((len = in.read(buffer)) > 0) {
//				out2.write(buffer, 0, len);
//			}
			// 关闭
			in.close();
//			out2.close();
			// 清空response
//			response.reset();
		} catch (Exception e) {
			e.printStackTrace();
		} 

		// 删除服务器上的临时文件
		File deleteFile = new File(temDir);
		deleteFile.delete();
		

	}
}

3.zip压缩导出工具

 package com.**.**.util;

import static org.springframework.util.StreamUtils.BUFFER_SIZE;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import com.**.**.exception.ResourceException;
import com.**.**.web.constants.Constants;

/** 
 * zip打包下载工具
 * @author ****
 * <p>2019年4月30日 上午9:53:21</p>  
 * @see
 * @version 1.0 
 */ 
public class ZipExportUtil {
	
	/** 
	* 打包
	* @param path 文件夹路径
	*/
	public static void zipExport(String path, HttpServletResponse response){
		try {
			response.setContentType("application/DOWLOAD");
			 response.setHeader("Content-Disposition", "attachment; filename="
			 + DateUtils.dateToString(new Date()) + ".zip");
			ServletOutputStream out = response.getOutputStream();
			toZip(path, out, true);
			DelAllFileUtil.delAllFile("F:\\annualAeport");
		} catch (Exception e) {
			throw new ResourceException(Constants.EXCEPTION_CODE_500, e.getMessage());
		}
	}
	/**
	 * 打压缩包导出
	 * 
	 * @param srcDir
	 * @param out
	 * @param keepDirStructure
	 * @throws RuntimeException
	 */
	public static void toZip(String srcDir, OutputStream out, boolean keepDirStructure) throws RuntimeException {
		ZipOutputStream zos = null;
		try {
			zos = new ZipOutputStream(out);
			File sourceFile = new File(srcDir);
			compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
		} catch (Exception e) {
			throw new RuntimeException("zip error from ZipUtils", e);
		} finally {
			if (zos != null) {
				try {
					zos.close();
				} catch (IOException e) {
					throw new ResourceException(Constants.EXCEPTION_CODE_500, e.getMessage());
				}
			}
		}
	}

	/**
	 * 执行压缩
	 * 
	 * @param sourceFile
	 * @param zos
	 * @param name
	 * @param keepDirStructure
	 * @throws Exception
	 */
	private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean keepDirStructure)
			throws Exception {
		byte[] buf = new byte[BUFFER_SIZE];
		if (sourceFile.isFile()) {
			// 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
			zos.putNextEntry(new ZipEntry(name));
			// copy文件到zip输出流中
			int len;
			FileInputStream in = new FileInputStream(sourceFile);
			while ((len = in.read(buf)) != -1) {
				zos.write(buf, 0, len);
			}
			// Complete the entry
			zos.closeEntry();
			in.close();
		} else {
			File[] listFiles = sourceFile.listFiles();
			if (listFiles == null || listFiles.length == 0) {
				// 需要保留原来的文件结构时,需要对空文件夹进行处理
				if (keepDirStructure) {
					// 空文件夹的处理
					zos.putNextEntry(new ZipEntry(name + "/"));
					// 没有文件,不需要文件的copy
					zos.closeEntry();
				}
			} else {
				for (File file : listFiles) {
					// 判断是否需要保留原来的文件结构
					if (keepDirStructure) {
						// 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
						// 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
						compress(file, zos, name + "/" + file.getName(), keepDirStructure);
					} else {
						compress(file, zos, file.getName(), keepDirStructure);
					}
				}
			}
		}
	}
}

4.模板样例  文档中的替换样例用{{}}

 

5.模板在resources下,此处路径本地下载没问题,服务器下载要配置服务器绝对路径 (本地相对路径:/templates   服务器绝对路径:打包后web路径会加入/WEB-INF/classes 这俩层结构)

 6. 控制层使用void 不return结果,否则会报错(因需求已实现,且中途改过工具,不确定,问题应该未解决)

@AspectLog(description = "批量导出word")
	@ApiOperation("批量导出word")
	@RequestMapping(value = "/datereporting/export", method = RequestMethod.GET)
	public void export(HttpServletRequest request, HttpServletResponse response, String ids) {
		try {
			dateReportingService.batchExport(ids, request, response);
		} catch (Exception e) {
			logger.error(Constants.CONTROLLER_GET_ERROR_LOG, e.getMessage());
		}
	}

7. 调用替换word工具

// Map<String, Object> everyMap 为 要替换的导出数据  Map<String, Object> data 中的 键 为模板文档中的对应变量
private void exportSocialPerformanceAnalysisReport(Map<String, Object> everyMap, HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		String year = everyMap.get("YEAR") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("YEAR").toString();
		String tableName = everyMap.get("TABLE_NAME") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("TABLE_NAME").toString();
		String deviceName = everyMap.get("DEVICE_NAME") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("DEVICE_NAME").toString();
		String equipmentNo = everyMap.get("EQUIPMENT_NO") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("EQUIPMENT_NO").toString();
		String name = everyMap.get("DEVICE_NAME") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("DEVICE_NAME").toString();
		String dept = everyMap.get("APPLY_DEPARTMENT") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("APPLY_DEPARTMENT").toString();
		String evaluate = everyMap.get("EVALUATE") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("EVALUATE").toString();
		String presentation = everyMap.get("ANALYSIS") == null ? EquipmentComputeConstants.EXPORT_EMPTY
				: everyMap.get("ANALYSIS").toString();
		/* 模板文本替换 */
		Map<String, Object> data = new HashMap<String, Object>(16);
		data.put("year", year);
		data.put("name", name);
		data.put("dept", dept);
		data.put("usage_situation", evaluate);
		data.put("presentation", presentation);
// 拼接文件名
		StringBuilder fileName = new StringBuilder();
		fileName.append(year);
		fileName.append(deviceName);
		fileName.append(tableName);
		fileName.append("(");
		fileName.append(equipmentNo);
		fileName.append(")");
		fileName.append(".docx");
		StringBuilder path = new StringBuilder();
		path.append(templates);
		path.append("/EquipmentPerformanceAnalysisTemplate4.docx");
		ExportUtil.exportWord(path.toString(), annualAeportPath, fileName.toString(), data, request, response);
	}

Map<String, Object> everyMap 为 要替换的导出数据  Map<String, Object> data 中的 键 为模板文档中的对应变量

 ExportUtil.exportWord(path.toString(), annualAeportPath, fileName.toString(), data, request, response);

方法参数说明:第一个是路径,第二个是服务器或本地临时文件路径(导出文件位置),第三个是导出文件名(批量执行,文件名一致会覆盖)

8.替换后执行浏览器压缩导出

/* zip打包导出 */
		ZipExportUtil.zipExport(annualAeportPath, response);
		/* 删除临时文件 */
		DelAllFileUtil.delAllFile(annualAeportPath);

9.测试结果

 --------------------------------------------------------------------------------------------------

补充文件删除工具类:DelAllFileUtil

package com.***.util;

import java.io.File;

/**
 * 删除服务器文件工具

 */
public class DelAllFileUtil {
    /**
     * 删除文件夹及子文件
     *
     * @param path 文件夹绝对路径
     * @return
     */
    public static boolean delAllFile(String path) {
        boolean flag = false;
        File file = new File(path);
        if (!file.exists()) {
            return flag;
        }
        if (!file.isDirectory()) {
            return flag;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            } else {
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件
                delFolder(path + "/" + tempList[i]);// 再删除空文件夹
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 删除文件夹
     *
     * @param folderPath 文件夹绝对路径
     */
    public static void delFolder(String folderPath) {
        try {
            delAllFile(folderPath); // 删除完里面所有内容
            String filePath = folderPath;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            myFilePath.delete(); // 删除空文件夹
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

更多推荐