Word 打包 zip 并提供下载

简介:

1. 后台处理的java 方法

    首先将所有的word生成到uploadword目录下面,然后指定被压缩的文件夹为uploadword,

    并将生成的zip指定到uploadzip文件夹(在配置目录路径的时候记得注意几种不同的服务器路径写法),

    当时也考虑过在同一个文件夹下面生成word ,然后压缩为一个 zip,但很可惜压缩出来的文件,

    总是莫名奇妙的迭代了很多相同的压缩包,可能是将生成的压缩包,也作为了文件不断循环在压缩,所以果断分开文件夹。

    在将文件循环压缩入压缩包中后,删除原uploadword文件夹中的文件,所以当程序正确执行完后,

    服务器中的uploadword这个文件夹都是清空的(毕竟这个功能是管理员进行的操作,只有一个超级管理员,没有考虑多用户并发生成压缩包的情况)

    根据 word 模版生成 word 文书的方法,我已经在前面的博客中总结过,可以看 java动态生成复杂word文件

    压缩方法上代码:

  View Code

2. Sping MVC框架实现下载遇到的“坑” 

    可能以前做过这功能朋友的会产生疑问,为什么要跳转到前端的下载页面去,不直接在后端生成下载流,

    放入HttpServletResponse对象,返回给前端直接弹出下载框。当时我也是这样想的,但事实总是很残酷。

    原来实现的代码是这样的:

  View Code

    加入后台这段代码后,并没有达到我想要的效果,可能是我对Spring Mvc理解的不够,还请各位看官赐教。

    2016.06.17

    经手后续项目时发现,是可以在后端将文件读入为字节流并放入 response 输出流当中,页面会弹出文件下载框,而且在各个浏览器都表现不错。 

url = AAA + '/downloadFile?fileId='123456789';
复制代码
    @RequestMapping(value = "/downloadFile", method = RequestMethod.GET)
    public void downloadFile(@RequestParam String fileId, HttpServletResponse response) {
        try {
            UploadfileVO uploadfileVO = queryer.find(UploadfileVO.class, "id='" + fileId + "'");
            if (uploadfileVO == null) {
                return;
            }
String fileName = java.net.URLEncoder.encode(uploadfileVO.getOldname(), "utf-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName); response.setContentType("application/x-msdownload"); long fileLength = uploadfileVO.getPath().length(); String length = String.valueOf(fileLength); response.setHeader("content_Length", length); response.setCharacterEncoding("utf-8"); OutputStream servletOutPutStream = response.getOutputStream(); FileInputStream fileInputStream = new FileInputStream(uploadfileVO.getPath()); byte bytes[] = new byte[1024];//设置缓冲区为1024个字节,即1KB int len; while ((len = fileInputStream.read(bytes)) != -1) { servletOutPutStream.write(bytes, 0, len); } servletOutPutStream.close(); fileInputStream.close(); } catch (Exception e) { e.printStackTrace(); } }
复制代码

3. 生成zip包成功,在前端跳转下载页面

    既然后端不能直接返回下载流,并弹出下载框,在前端接受返回的下载所需(zippath,zipFileName,serverName)的关键参数,跳转到下载JSP页面。

    相应跳转(跳转方式多种多样,这里采用表单提交到download.jsp页面):

复制代码
var theParam = {};
theParam.zippath = data.zippath;
theParam.zipFileName =data.zipFileName;
Param.serverName =data.serverName;

var formStr = "<form action='..../download.jsp' method='post' id='form' style='display:none'>";
$.each(theParam, function(key, value) {
formStr += "<input type='hidden' name='" + key + "' value='" + value + "'/>";
});
formStr += "</form>";
$("body").append(formStr);
$("#form").submit();
复制代码

下载页面:

复制代码
<%@page import="java.io.OutputStream"%>
<%@page import="java.net.URLEncoder"%>
<%@page import="java.io.FileInputStream"%>
<%@page language="java" contentType="application/x-msdownload" pageEncoding="UTF-8"%>
<%
try {
//关于文件下载时采用文件流输出的方式处理:
//加上response.reset(),并且所有的%>后面不要换行,包括最后一个;
response.reset();//可以加也可以不加
response.setContentType("application/x-download");
String filedownload = request.getParameter("zippath");
String filedisplay = request.getParameter("zipFileName");
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filedisplay, "UTF-8"));

OutputStream outp = response.getOutputStream();
FileInputStream in = new FileInputStream(filedownload);
byte[] b = new byte[1024];
int i = 0;
while ((i = in.read(b)) > 0) {
outp.write(b, 0, i);
}
outp.flush();
outp.close();
in.close();
//Tomcat 需要添加这两局来避免 getOutputStream() 方法,已被调用的异常,weblogic做特殊判断
if(request.getParameter("serverName").equals("TOMCAT")){
out.clear();
out = pageContext.pushBody();
}
} catch (Exception e) {
e.printStackTrace();
}
%>
复制代码

4. 流在不同web容器的妥善处理

    刚开始程序在tomcat 上跑时,总出现报错:

    org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response

    百度一番,发现Body()的作用是保存当前的out对象,并更新PageContext中Page范围内Out对象。

    JSP容器在处理完成请求后会调用releasePageConter方法释放所有的PageContestObject,并且同时调用getWriter方法。

    由于getWriter方法与在JSP页面中使用流相关的getOutputStream方法冲突,解决方法也很简单,重新生成PageContext中Page范围内Out对象。

    在代码最后添加 :

    out.clear();

    out = pageContext.pushBody();

    好了,自己本地测试不会报错了,将项目打包到weblogic,出现报错:

    Servlet failed with Exception java.lang.IllegalStateException: Response already committed at weblogic.servlet.internal.ServletResponseImpl.objectIfCommitted

    虽然不影响功能的使用,还是看着不爽,继续百度,发现是自己添加的上两句的的原因(tomcat 和 weblogic 容器的差异性,应该是weblogic并不会调用releasePageConter方法释放所有的PageContestObject)

    这就是下载页面出现这几行代码的原因:

//Tomcat 需要添加这两局来避免 getOutputStream() 方法,已被调用的异常,weblogic做特殊判断
if(request.getParameter("serverName").equals("TOMCAT")){
out.clear();
out = pageContext.pushBody();
}

    如果能判断是在哪个web容器中,然后进行特殊判断就好了,portal-kernel.jar中的类ServerDetector.java 能完美判断多达10种以上的容器类型,

    但我又不想将这个jar 引入到项目中(俺就用一个类,引一个jar,太亏了),然后Jd-Gui反编译,单独拉出这个类,修改修改添加到我的项目中。

    修改完的代码,不依赖任何类,可以拿来直接用:

  View Code

    到此完美解决了 Spring MVC 中zip包下载、避开后端直接写入前端下载流、妥善解决各web容器的差异性。


本文转自Orson博客园博客,原文链接:http://www.cnblogs.com/java-class/p/4798204.html,如需转载请自行联系原作者

相关文章
|
3月前
|
Linux Python Windows
Python PDF文件转Word格式,只需要3秒(附打包)
Python PDF文件转Word格式,只需要3秒(附打包)
83 3
Python PDF文件转Word格式,只需要3秒(附打包)
|
4月前
|
运维 Serverless 数据库
如何使用zipfile模块解压zip文件并返回解压后的结果
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
3月前
Pandoc——使用ZIP方式安装
Pandoc——使用ZIP方式安装
54 0
|
6月前
zip,with-core-zip,selfcontained这些都是什么意思?
zip,with-core-zip,selfcontained这些都是什么意思?
112 0
|
Java 关系型数据库 MySQL
SpringBoot 导出多个Excel文件,压缩成.zip格式下载
SpringBoot 导出多个Excel文件,压缩成.zip格式下载
884 0
SpringBoot 导出多个Excel文件,压缩成.zip格式下载
|
前端开发
生成pdf文件并打包zip下载
使用itextpdf生成pdf文件,使用ant的org.apache.tools.zip生成zip包,并下载
186 0
|
前端开发 Java
如何使用zip工具类打包下载压缩图片?
如何使用zip工具类打包下载压缩图片?
如何使用zip工具类打包下载压缩图片?
|
Python
Python 技术篇-用zipfile库进行zip文件的压缩与解压实例演示,python压缩本地文件夹为zip文件并保留目录结构
Python 技术篇-用zipfile库进行zip文件的压缩与解压实例演示,python压缩本地文件夹为zip文件并保留目录结构
356 0
Python 技术篇-用zipfile库进行zip文件的压缩与解压实例演示,python压缩本地文件夹为zip文件并保留目录结构
|
JavaScript Java
【Auto.js】[zip压缩] 将文件夹压缩成zip包
【Auto.js】[zip压缩] 将文件夹压缩成zip包
424 0
|
Python
python-批量把文件和文件夹同时压缩成ZIP文件
1.通过某种方式获得一个文件(文件夹)列表作为一个list(例如wxpython的wx.FileDialog方法,在下面的代码中我们跳过文件夹列表的获取方法)。 2.选择一个压缩文件的输出目录和压缩文件的输出名字(下面代码中选择输出默认路径为程序根目录) 3.把文件list里的文件,先统一放在一个临时文件夹里,然后把该临时文件夹压缩成ZIP文件,最后删掉临时文件夹
333 0