目的:使用POST请求导出Excel文档。
起因:在使用Java导出Excel时,笔者在上一篇文章中使用的导出POJO或者BSONDocument类型的Excel文档的方法,其实使用的是GET请求,因为当时前端传的参数也不多,并不会因为浏览器对GET请求参数的长度的限制而导致请求失败。
但是,在实际中,可能经常遇见过滤导出这种要求。比如,选择了过滤条件,导出过滤之后的数据,那么这个时候,如果不做前端导出,就有两种方式交给后端导出:①将过滤之后的表格数据全部传给后端 ,让后端导出②将过滤条件传给后端,后端解析并且自己搜索出所有的数据再导出。而无论是这两种的任何一种方式,GET请求都可能满足不了参数的长度,所以需要使用POST方式,在请求体中,把数据或者过滤条件传给后端。而如果继续使用笔者上一篇文章的导出方法,那么前端最后导出的就不再是文件,而会显示出一页乱码(乱码其实就是导出的数据,只是解析方式错误)。
解决方案:①:前端使用JS对后端返回的数据进行处理(最终还是变成了前端导出,数据量过大则为导致前端导出很卡,不建议使用)②:后端处理,其实笔者使用过两种后端处理方式,因为最近发现了第二种方式,充分让笔者认识到自己知识的不足、狭隘,才准备写这篇文章(说多了都是泪)。
在讲第二种方式之前,说下以前笔者如何处理过滤导出这种要用POST请求导出Excel类型的方法:利用缓存服务器,前端先调用post把数据或者过滤条件给后端,后端获取数据将数据存入redis,然后返回成功状态给前端,前端再调用GET请求,参数是redis里面的保存数据的key,这样,后端通过key再从redis获取数据并导出(现在笔者已经不忍直视了。。。。)
接下来就是第二种方式(超级无敌简单到爆),下面贴上一个关键代码:
response.setContenType("selfdefinition");内容类型设置为自定义类型,即不能与约定好的类型相同,随便输字符串,如:sbsbsbsbsbsbssb。关于这个响应头,在上一篇文章结尾处有比较详细的说明,包括作用。
/**
* 导出excel表格数据
* @param datas 需要导出的数据模型集合
* @param specialFields 需要特殊处理的字段,比如这个字段需要加上超链接
* @param excelName 导出Excel文件名
* @param tableHeaders 表格数据模型与表头信息键值对
* @param response 响应
* @param requestType 请求的方式
*/
public static <T> void excelExport(List<T> datas, List<KeyValueVO> specialFields, String excelName,
List<KeyValueVO> tableHeaders, HttpServletResponse response, String requestType)
{
//如果需要导出的数据或者表头信息为空等,则返回
if (null == datas || datas.isEmpty() || tableHeaders == null || tableHeaders.isEmpty())
{
return;
}
try
{
excelName = new String(excelName.getBytes("UTF-8"),"ISO-8859-1");
}
catch (Exception e1)
{
e1.printStackTrace();
}
if ("post".equals(requestType))
{
//笔者亲测,如果响应头设置响应类型为自定义类型,就是随便输一个字符串,
//不能与规定的相同,那么某些浏览器默认会表示下载文件,
//这样就能下载你返回的数据了,而不是显示乱码
response.setContenType("selfdefinition");
}
else
{
response.setContenType("application/vnd.ms-excel;charset=UTF-8");
}
response.setHeader("Content-disposition", "atachment;filename=" + excelName + ".xls");
response.setCharacterEncoding("utf-8");
try
{
writeExcel(datas,specialFields,excelName,tableHeaders,response);
}
catch (Exception e)
{
e.printStackTrace();
}
}
如果看过笔者上一篇文章的读者可能晓得,这里贴的代码和笔者上一篇导出的代码基本相同,只是方法多了一个参数,就是请求的类型,然后根据请求的类型,设置响应的请求头,如果是post请求,请求头的contentType这个值,就不要设置以前的值了,设置一个自定义的值就行。这样,部分浏览器因为识别不了这个类型,就会默认下载文件。于是,post请求,在前后端不做任何处理的情况下也能直接下载Excel了。
这里贴出部分浏览器对各种响应类型的反应:
另外,笔者使用的GOOGLE浏览器,该浏览器对无法识别的自定义类型也会出现下载文件。
最后,笔者想说的就是,其实HTTP协议,就是数据的传输,其他任何操作都是浏览器各种工具约定好的,HTTP协议只负责传输数据,至于这个数据如何解析,渲染,用什么方式,都是浏览器规定的,包括,我们常说的GET请求,参数不能过长,其实HTTP并没有约定GET请求参数的长度,你想多长就多长,只是浏览器约定了,如果是GET请求,就会对长度进行限制。