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,如需转载请自行联系原作者

相关文章
单笔转账报错PAYEE_NOT_EXIST(收款账户不存在)-排查方案
报错原因 接口中用户账户参数设置存在问题,导致显示用户收款账户不存在。 排查方案 1、检查payee_account, payee_type是否匹配,如匹配,请检查payee_account是否存在; (1)payee_type设置要求 ALIPAY_USERID:支付宝账号对应的支付宝唯一用户号。
4025 12
|
8月前
|
弹性计算 人工智能 运维
阿里云算力服务的稳定性演进
本文介绍了弹性计算稳定性技术的基础能力研究,涵盖稳定性底座、实例异常检测、变更异常检测、风险规避和故障处置等方面。重点讲解了阿里云在ECS稳定性方面的进展,包括高可用架构设计、故障演练验证、持续运行阶段的稳定性保障以及相关工具和功能。此外,还探讨了Confidential AI的最佳实践,解决了大模型场景下的系统级安全风险,并介绍了机密计算产品的能力规划。最后,文章阐述了ACK容器服务的稳定性演进,包括高可用架构、托管节点池、供应链安全、事件体系、全链路检测、版本升级和成本管理等功能,确保用户能够获得高效稳定的容器服务体验。
|
7月前
|
监控 数据可视化 搜索推荐
如何通过数据分析优化营销流程?
在当今竞争激烈的市场中,企业需构建高效的营销流程以整合资源、提升效率并实现业务增长。本文从目标设定、渠道选择、内容创作、数据分析及团队协作工具等方面详细探讨了如何优化营销流程,并指出了常见问题及改进方向。通过明确目标、精准选择渠道、创作高价值内容、用数据驱动决策以及提升团队协作效率,企业能够在激烈的市场竞争中脱颖而出,实现持续增长。
|
人工智能 运维 监控
现代云平台技术及其应用
在当今数字化时代,云平台技术正日益成为企业转型和创新的关键。本文将探讨现代云平台的定义、架构特点及其在不同行业中的应用案例,旨在帮助读者深入了解并有效应用这一技术。 【7月更文挑战第9天】
578 2
|
9月前
|
供应链 物联网 区块链
新技术浪潮下的变革:区块链、物联网与虚拟现实的融合与创新####
【10月更文挑战第21天】 本文深入剖析了当下三大前沿技术——区块链、物联网(IoT)与虚拟现实(VR)的最新发展趋势,并探讨了它们各自在实际应用中的突破性进展与交叉融合的创新潜力,特别是在提升数据安全、优化用户体验及推动行业数字化转型方面的贡献。通过实例分析,本文揭示了这些技术如何单独及协同作用,重塑传统行业格局,促进数字经济与实体经济深度融合,开启智能化、透明化与沉浸式体验的新纪元。 ####
351 27
|
10月前
|
机器学习/深度学习 人工智能 物联网
2024年软件开发趋势
【10月更文挑战第29天】本文概述了2024年软件开发领域的五大新趋势,涵盖人工智能与机器学习的深入整合、JAMstack架构的广泛采纳、对网络安全的强化关注、远程办公模式的持续影响,以及物联网技术的迅速扩张。这些趋势不仅反映了技术的进步,也展示了软件开发行业对效率、安全性和用户体验的不断追求。
|
Prometheus Cloud Native 网络安全
Prometheus+Grafana+Alertmanager部署教程(超详细)
Prometheus+Grafana+Alertmanager部署教程(超详细)
2900 0
Prometheus+Grafana+Alertmanager部署教程(超详细)
|
Linux 数据处理 开发工具
Linux命令repoquery详解
`repoquery`是Linux(尤其是RPM-based系统如CentOS, Fedora, RHEL)中的一个命令行工具,属于`yum-utils`,用于从Yum仓库查询RPM包信息,包括依赖、文件列表和描述。它不执行安装或卸载,而是帮助解决依赖问题和查找文件归属。主要参数有`-l`(列出文件)、`-i`(显示描述)、`--whatprovides`(查询提供文件的包)等。结合正则表达式和其他命令使用可提高效率。确保安装`yum-utils`并定期更新仓库以获取最新信息。
|
Cloud Native Java API
Java一分钟之-Micronaut:轻量级微服务框架
【6月更文挑战第16天】Micronaut是面向JVM的微服务框架,以其快速启动、低内存占用著称。文章探讨了配置管理、注解理解和AOT编译的挑战,提供了解决方案,并通过一个简单的HTTP服务示例展示了如何创建控制器和应用启动类。通过克服这些问题,开发者能更好地利用Micronaut构建高效微服务。
298 8
|
人工智能 Linux 云计算
【专访浪潮信息】构建开放公平的社区生态,中国服务器操作系统崛起进行时
服务器操作系统产业 2.0 时代,龙蜥社区和浪潮信息的创新、挑战与突破。