Java后端与Vue前端导出Excel表格文件并解决乱码和文件打不开
Java 需要用到 poi 两个依赖包,Maven如下:<!-- https://mvnrepository.com/artifact/org.apache.poi/poi --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId>&
·
Java 需要用到 poi 两个依赖包,Maven如下:
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
Java后端实现
所有的代码都在这个 Controller 中,在实际的场景中,最好进行封装,比如:表格样式、表格的数据收集与整理等等。
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @author 江湖人称小程
*/
@RestController
@RequestMapping("export")
public class ExportExcelController {
@GetMapping("data")
public void exportData(HttpServletResponse response) {
// 1. 创建工作空间
Workbook workbook = new XSSFWorkbook(); // .xlsx 用 XSSFWorkbook
// Workbook workbook = new HSSFWorkbook(); // .xls 用 HSSFWorkbook
// 2. 创建工作表
Sheet sheet = workbook.createSheet("学生信息");
// 2.1 创建标题行(第一行)
Row headerRow = sheet.createRow(0);
/* 3. 定义一个字体(建议将定义字体这段代码,提取出来进行封装,后续可以定义各式各样的的字体) */
// 3.1 创建字体
Font headerFont = workbook.createFont();
// 3.2 14号大小
headerFont.setFontHeightInPoints((short) 14);
// 3.3 黑色字体
headerFont.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
// 3.4 宋体
headerFont.setFontName("宋体");
/* 4. 声明样式 CellStyle,并设置 */
// 4.1 创建 style
CellStyle style = workbook.createCellStyle();
// 4.2 将字体设置进 style 对象中
style.setFont(headerFont);
// 4.3 水平和垂直居中
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
/* 设置列宽和表头样式 */
String[] headers= {"姓名", "性别", "年龄", "班级" , "联系方式" , "家庭住址"};
for (int i = 0; i < headers.length; i++) {
// 设置每一列的宽度
sheet.setColumnWidth(i, 230*30);
// 设置每一列的 style 和 标题
Cell headerCell = headerRow.createCell(i);
headerCell.setCellStyle(style);
headerCell.setCellValue(headers[i]);
}
/* 模拟数据 */
List<Student> students = new ArrayList<>();
students.add(new Student("小明", "男", 17, "三年二班", "1524215241", "牛牛村"));
students.add(new Student("小红", "女", 16, "三年二班", "1524215241", "牛牛村"));
students.add(new Student("小张", "女", 17, "三年二班", "1524215241", "牛牛村"));
students.add(new Student("小李", "男", 18, "三年二班", "1524215241", "牛牛村"));
students.add(new Student("小王", "nv", 16, "三年二班", "1524215241", "牛牛村"));
/* 遍历 */
for (int j = 0; j < students.size(); j++) {
Row row = sheet.createRow(j + 1);
for(int i = 0;i < headers.length ;i++){
Cell cell = row.createCell(i);
// 每一列的数据与表头对应上
if(i == 0){
cell.setCellValue(students.get(j).getName());
}else if(i == 1){
cell.setCellValue(students.get(j).getSex());
}else if(i == 2){
cell.setCellValue(students.get(j).getAge());
}else if(i == 3){
cell.setCellValue(students.get(j).getClassName());
}else if(i == 4){
cell.setCellValue(students.get(j).getPhone());
}else {
cell.setCellValue(students.get(j).getAddress());
}
// 这里将每一数据行的样式设置成和表头样式一样的,建议将 style 样式进行封装,根据不同的需求获取不同的样式
cell.setCellStyle(style);
}
}
try (OutputStream osOut = response.getOutputStream()){
// 设置响应类型与编码
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("学生表.xlsx","UTF-8"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); // .xlsx 用这个
// response.setContentType("application/vnd.ms-excel;charset=utf-8"); // .xls 用这个
response.setCharacterEncoding("utf-8");
// 将指定的字节写入此输出流
workbook.write(osOut);
// 刷新此输出流并强制将所有缓冲的输出字节被写出
osOut.flush();
// 关闭流
osOut.close();
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
此时,后端的代码已全部实现,由于是 Get 请求,所以我们可以直接在浏览器访问URL进行下载:
下载后的文件,是我们设置的学生表
名。
打开文件,查看内容
前端实现
在函数中写入:
// 导出Excel的函数
exportFunc() {
exportData().then(response => {
let blob = new Blob([response.data], {
// 这里一定要和后端对应,不然可能出现乱码或者打不开文件
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, fileName)
} else {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = '学生表.xlsx'; // 在前端也可以设置文件名字
link.click();
//释放内存
window.URL.revokeObjectURL(link.href)
}
}).catch(response => {})
}
对exportData
的封装:
export function exportData({
return request({
url: '/export/data',
method: 'get',
responseType: 'blob', // 设置响应数据类型为 blob。这句话很重要!!!
})
}
在前端做个按钮,点击时调用exportFunc
函数就可以触发下载了。
问题
对于文件下载后打开乱码,很有可能是以下两个问题:
- 文件格式与响应类型对不上,前端后端都得对上
- 没有设置编码 UTF-8
对于文件损坏,提示无法打开,很有可能是:
- 文件格式与响应类型对不上,前端后端都得对上
总结
Java端
- 在创建
Workbook
的时候,要确认是用.xlsx
格式还是用.xls
,并使用对应的XSSFWorkbook
和
HSSFWorkbook
来创建正确的工作空间 - 字体的创建和列样式CellStyle都建议单独封装。
- 设置响应头的时候,如果中文文件名乱码,可以使用
URLEncoder
进行UTF-8
编码。 - 响应类型
ContentType
一定要根据不同的文件格式,设置正确的响应类型 - 最后记得
flush
一下,并关闭流。
前端
- 创建
Blob
的时候,type
最好和Java的响应类型保持一致 - 一定要设置响应数据类型为 blob:
responseType: 'blob'
技 术 无 他, 唯 有 熟 尔。
知 其 然, 也 知 其 所 以 然。
踏 实 一 些, 不 要 着 急, 你 想 要 的 岁 月 都 会 给 你。
更多推荐
已为社区贡献2条内容
所有评论(0)