版权声明:个人博客:yjz.life 欢迎前来交流!~本篇文章未经同意请勿转载! https://blog.csdn.net/m0_38072683/article/details/82990629
最近有一个需求是:
将jqGrid表格中的数据生成报表Excel文件返回给用户。
我的想法是获取jqGrid中的数据然后生成json数据,传给后端,生成文件流,响应到前端,保存为excel文件。
ajax为什么不能够实现下载文件
ajax的返回值类型是json,text,html,xml类型,或者可以说ajax的接收类型只能是string字符串,不是流类型,所以无法实现文件下载。
但用ajax仍然可以获得文件的内容,该文件将被保留在内存中,无法将文件保存到磁盘。这是因为JavaScript无法和磁盘进行交互,否则这会是一个严重的安全问题,js无法调用到浏览器的下载处理机制和程序,会被浏览器阻塞。
并且 我用ajax实现的时候出现了很多bug。
在网上参考好多博客,经过不断的调试,我还是选择了原生的XMLHttpRequest对象进行post请求。
blob(HTML5 新特性)
二进制大对象,是一个可以存储二进制文件的容器。
作用
Js一直以来都没有比较好的可以直接处理二进制的方法。而Blob的存在,允许我们可以通过JS直接操作二进制数据。
Blob对象可以看做是存放二进制数据的容器,此外还可以通过Blob设置二进制数据的MIME类型。
BLOB是一个大文件,典型的BLOB是一张图片或一个声音文件,由于它们的尺寸,必须使用特殊的方式来处理(例如:上传、下载或者存放到一个数据库)。
重点应用
- 目前做的通过URL下载文件。
- 分片上传文件(将大文件分片,轮询向后台提交各文件片段)。
后端代码
/**
* 生成Excel报表
* Error:存在问题
* 1. 前端表格中没有Student对象的一些属性,生成报表时不必要显示的属性字段在Excel中显示。
* solve:加判断控制。
* 2. (由于blob是HTML5新出的)兼容性问题:chrome、firefox、opera无问题,
* 3. 检测grid表格中有无字段名称冲突问题。
* solve:细心检查即可
* 4. 下载完Excel,打开出现"文件已损坏 无法打开"问题,这是因为office受保护试图导致(安全问题)
* solve:在office选项里边修改一下即可(客户端问题)
* @param list
* @param response
*/
@RequestMapping(value = "/exstudent",consumes = "application/json;charset=utf-8")
public void export (@RequestBody List<Student> list, HttpServletResponse response){
OutputStream out = null;
String name = "学生信息管理表";
for (Student stu:list) {
System.out.println(stu.getStudentname());
}
try {
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" +URLEncoder.encode(name, "UTF-8")+".xlsx");
out = response.getOutputStream();
//调用老师自己写的库,本篇文章不详细说生成Excel文件的事情。
TExcel.exportExcel(name,Student.class,list,out);
System.out.println("下载ok");
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
}
}
前端代码:
//导出按钮被点击之后,将按钮制为无效(防止多次生成)
function abideBtn(){
console.log("禁止按钮......");
$("#download").attr({"href":"#"});
$("#download").css("cursor","not-allowed");
}
//下载过程中出错误,
function downloadError(){
console.log("发生错误,下载失败");
alert("下载中出现错误!请重试");
$("#download").attr({"href":"javascript:exportData();"});
$("#download").css("cursor","pointer");
}
//导出表格数据
//注意:下面获取jqGrid中所有行数据的前提是分页在前端,而不是后端。
//如果你是在后端分页,那么你会发现,你会将所有数据都显示出来。
function exportData() {
var grid = jQuery("#grid");
//获取当前显示的数据
var rowNum = grid.jqGrid('getGridParam', 'rowNum'); //获取显示配置记录数量
var total = grid.jqGrid('getGridParam', 'records'); //获取查询得到的总记录数量
//设置rowNum为总记录数量并且刷新jqGrid,使所有记录现出来调用getRowData方法才能获取到所有数据
grid.jqGrid('setGridParam',{rowNum: total,}).trigger('reloadGrid');
var rows = o.jqGrid('getRowData');
grid.jqGrid('setGridParam',{rowNum: rowNum,}).trigger('reloadGrid');
postToPOM(rows);
}
//发送post请求
function postToPOM(rows) {
console.log(rows);
var url = "../student/exstudent";
var xhr = new XMLHttpRequest();
xhr.open('POST',url,true);
xhr.responseType = "blob";
xhr.setRequestHeader("Content-Type"
, "application/json;charset=utf-8");
//添加监听事件。
xhr.addEventListener("load",abideBtn,false);
xhr.addEventListener("error",downloadError,false);
xhr.onload = function (){
if(this.status === 200){
//创建Bolb对象
var blob = this.response;//html5新出的
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function(e){
//创建a标签,构造下载弹窗
var a = document.createElement("a");
a.id = "downloadTag";
a.download = '学生信息管理表.xlsx';
a.href = e.target.result;
$("body").append(a);
a.click();
$("#downloadTag").remove();
console.log("下载完成!");
//恢复按钮
$("#download").attr({"href":"javascript:exportData();"});
$("#download").css("cursor","pointer");
}
}
};
xhr.send(JSON.stringify(rows));
}