前言
在最近的项目中,必须为后端提供用于下载Csv和Excel表单的接口。 此接口接收前端查询参数,并对这些参数查询数据库。 在Excel和Csv文件中生成查询结果,并将其作为字节流返回到前端。
前端得到这个流文件后,最初是在ajax上收到的,但是前端发出的请求被落在了浏览器cancel上。 后来,我发现发展这么久的Ajax不支持下载流文件。 后来,前端更改为最原始的XMLHttpRequest,修复了这个问题。
首先指示项目源代码的地址。 这是源代码。 欢迎大家来到star或提MR。
中央电视台
新建控制器
我先举个简单的例子。 首先,在控制器上创建一个新接口。
@获取映射(CSV ) ) ) ) )。
公共语音CSV (
http servlet请求请求,
http servlet响应资源
) throws IOException {
string filename=this.getfilename (请求,'测试数据. csv ' );
response.set content type (media type.application _ octet _ stream.tostring );
response.setheader (' content-disposition ',' attachment; filename='' fileName '';' );
linkedhashmapheader=newlinkedhashmap (;
linkedhashmapbody=newlinkedhashmap (;
header.put('1','名称');
header.put('2)、'年龄);
列表数据=new ArrayList (;
body.put('1','不安的季节);
body.put('2)、' jmdyb );
数据. add (header;
data.add (主体;
data.add (主体;
data.add (主体;
filecopy utils.copy (导出util.export CSV (data ),response.getOutputStream );
}
其中this.getfilename(request,'测试数据. csv ' )函数是用于检索导出文件名的函数。 之所以单独提交,是因为浏览器使用的默认编码不同。 例如,如果使用默认的UTF-8编码。 在chrome浏览器下载时会发生中文乱码。 代码如下。
专用网关名称(httpservletrequestrequest,String name ) throwsunsupportedencodingexception )。
string user agent=request.get header (用户代理);
return user agent.contains (' Mozilla '? newstring(name.getbytes )、' ISO8859-1 ' ) : name;
}
response.getOutputStream ()在导出csv文件的controller代码的末尾使用工具类文件复制函数将字节流写入输出流,并将csv文件以字节为字节
如果当前终端通过http请求访问服务器接口,则http中的所有请求信息都封装在http servlet request对象中。 例如,可以从此对象中获取请求的URL地址、请求方法、请求的客户机IP和完整主机名、Web服务器IP和完整主机名、请求行参数、请求标头参数等等
服务器会为每个HTTP请求自动创建与请求对象相对应的http servlet请求。 响应对象可以重定向当前请求、自定义响应体的头部以及设置返回流。
新建导出工具类
我们创建了一个新的导出工具类,专门用于导出各种格式的文件。 代码如下。
公共类导出util {
公共静态字节[ ]导出CSV {
bytearrayoutputstreamout=newbytearrayoutputstream (;
bufferedwriterbuffcvswriter=null;
try {
buffcvswriter=newbufferedwriter (new outpu
tStreamWriter(out, StandardCharsets.UTF_8));// 将body数据写入表格 for (Iterator> iterator = exportData.iterator(); iterator.hasNext(); ) {
fillDataToCsv(buffCvsWriter, iterator.next());
if (iterator.hasNext()) {
buffCvsWriter.newLine();
}
}
// 刷新缓冲 buffCvsWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源 if (buffCvsWriter != null) {
try {
buffCvsWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return out.toByteArray();
}
private static void fillDataToCsv(BufferedWriter buffCvsWriter, LinkedHashMap row) throws IOException {
Map.Entry propertyEntry;
for (Iterator propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
propertyEntry = propertyIterator.next();
buffCvsWriter.write(""" + propertyEntry.getValue().toString() + """);
if (propertyIterator.hasNext()) {
buffCvsWriter.write(",");
}
}
}
}
fillDataToCsv主要是抽离出来为csv填充一行一行的数据的。
运行
然后运行项目,调用http://localhost:8080/csv,就可以下载示例的csv文件。示例如下。
Excel
新建controller
新建下载xlsx文件的接口。
@GetMapping("xlsx")
public void xlsx(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
String fileName = this.getFileName(request, "测试数据.xlsx");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
response.setHeader("Content-Disposition", "attachment; filename="" + fileName + "";");
List> datas = new ArrayList<>();
LinkedHashMap data = new LinkedHashMap<>();
data.put("1", "姓名");
data.put("2", "年龄");
datas.add(data);
for (int i = 0; i < 5; i++) {
data = new LinkedHashMap<>();
data.put("1", "小青");
data.put("2", "坚强的百褶裙");
datas.add(data);
}
Map>> tableData = new HashMap<>();
tableData.put("日报表", datas);
tableData.put("周报表", datas);
tableData.put("月报表", datas);
FileCopyUtils.copy(ExportUtil.exportXlsx(tableData), response.getOutputStream());
}
补充工具类
上面新建的导出工具类中,只有导出csv的函数,接下来我们要添加导出xlsx的函数。
public static byte[] exportXlsx(Map>> tableData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建多个sheet for (Map.Entry>> entry : tableData.entrySet()) {
fillDataToXlsx(workbook.createSheet(entry.getKey()), entry.getValue());
}
workbook.write(out);
} catch (IOException e) {
e.printStackTrace();
}
return out.toByteArray();
}
/*** 将linkedHashMap中的数据,写入xlsx表格中** @param sheet* @param data*/
private static void fillDataToXlsx(HSSFSheet sheet, List> data) {
HSSFRow currRow;
HSSFCell cell;
LinkedHashMap row;
Map.Entry propertyEntry;
int rowIndex = 0;
int cellIndex = 0;
for (Iterator> iterator = data.iterator(); iterator.hasNext(); ) {
row = iterator.next();
currRow = sheet.createRow(rowIndex++);
for (Iterator propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
propertyEntry = propertyIterator.next();
if (propertyIterator.hasNext()) {
String value = String.valueOf(propertyEntry.getValue());
cell = currRow.createCell(cellIndex++);
cell.setCellValue(value);
} else {
String value = String.valueOf(propertyEntry.getValue());
cell = currRow.createCell(cellIndex++);
cell.setCellValue(value);
break;
}
}
if (iterator.hasNext()) {
cellIndex = 0;
}
}
}
fillDataToXlsx的用途与csv一样,为xlsx文件的每一行刷上数据。
运行
然后运行项目,调用http://localhost:8080/xlsx,就可以下载示例的csv文件。示例如下。
项目地址
最后再次给出项目地址,大家如果没有理解到其中的一些地方,不妨把项目clone下来,自己亲自操作一波。
参考
这是在解决请求被浏览器cancel掉的过程中,很重要的一个参考,分享给大家。