- 错误示范:
很多人会选择使用HttpServletResponse的输出流的方式
- 正确方式:
应该使用ResponseEntity返回,此处附上工具类:
/**
* @param fileName 文件名
* @param rowTitles 导出excel的标题
* @param exportList 需要导出的数据,最好全是字符串格式
* @param agent request.getHeader("USER-AGENT")
* @return ResponseEntity
*/
public static ResponseEntity<FileSystemResource> response(String[] rowTitles, List<List<String>> exportList,
String fileName, String agent) {
if (CollectionUtil.isEmpty(exportList) || ArrayUtils.isEmpty(rowTitles)) {
return null;
}
OutputStream out = null;
try {
final File distFile = new File(System.getProperty("java.io.tmpdir"), fileName);
Workbook workbook = ExcelUtil.downloadExcel(rowTitles, exportList);
out = new FileOutputStream(distFile);
// 写到临时文件
workbook.write(out);
out.flush();
final FileSystemResource fsr = new FileSystemResource(distFile);
return ResponseEntity.status(HttpStatus.OK)
.header("Content-Disposition", "attachment;filename=" + encodeFileName(fileName, agent))
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(fsr.contentLength())
.body(fsr);
} catch (Exception e){
return null;
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
其中encodeFileName代码(文末附上ExcelUtil.downloadExcel()):
private static String encodeFileName(String fileName, String agent) {
if(StringUtils.isEmpty(agent)) {
return fileName;
}
try {
// ie浏览器及Edge浏览器
if (agent.contains("MSIE") || agent.contains("Trident") || agent.contains("Edge")) {
return java.net.URLEncoder.encode(fileName, "UTF-8");
}
// 火狐, Chrome等浏览器
if (agent.contains("Mozilla")) {
return new String(fileName.getBytes("UTF-8"), "iso-8859-1");
}
} catch (Exception e) {
return null;
}
return null;
}
- 使用示例:
- 前端代码
如果小伙伴们写一些前端代码会遇到导出的时候参数很多不想使用get方式
get方式导出:
window.location.href =导出文件的接口地址
可以使用post的方式:
// params是post请求需要的参数,url是请求url地址
// 切记后端接收实体类不需要加任何注解
postExcelFile(params, url) {
let form = document.createElement("form");
form.style.display = "none";
form.action = url;
form.method = "post";
document.body.appendChild(form);
// 动态创建input并给value赋值
for (let key in params) {
let input = document.createElement("input");
input.type = "hidden";
input.name = key;
input.value = params[key];
form.appendChild(input);
}
form.submit();
form.remove();
}
上述方法无法解决需要传递请求头的场景,需自定义axios请求
ExcelUtil.downloadExcel代码:
- 依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
- 代码(仅供参考)
public static Workbook downloadExcel(String[] rowTitles, List<List<String>> rowDatas) throws IOException {
Workbook workbook = new HSSFWorkbook();
try {
// 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet
Sheet sheet = workbook.createSheet("外部案件导入模板");
// 第三步,在sheet中添加表头第0行
Row row = sheet.createRow(0);
// 第四步,创建单元格,并设置值表头 设置表头居中
CellStyle style = workbook.createCellStyle();
style.setAlignment(CellStyle.ALIGN_CENTER); // 创建一个居中格式
for (int i = 0; i < rowTitles.length; i++) {
Cell cell = row.createCell(i);
cell.setCellValue(rowTitles[i]);
cell.setCellStyle(style);
sheet.setColumnWidth(i, (25 * 256)); //设置列宽,50个字符宽
}
// 第五步,写入实体数据 实际应用中这些数据从数据库得到
if (rowDatas != null) {
for (int i = 0; i < rowDatas.size(); i++) {
row = sheet.createRow(i+1);
List<String> strings = rowDatas.get(i);
for (int j = 0; j < strings.size(); j++) {
Cell cell = row.createCell(j, Cell.CELL_TYPE_STRING);
cell.setCellValue(strings.get(j));
cell.setCellStyle(style);
if (StringUtils.isNotBlank(strings.get(j))) {
int columnWidth = (strings.get(j).length() * 2) * 256;
sheet.setColumnWidth(j, Math.max((25 * 256), columnWidth));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return workbook;
}