SpringBoot 导出Excel表格,并实现前端Vue+Axios下载文件不跳转页面

一、应用背景:

导出学生成绩Excel表


二、准备工作:

  • pom.xml 导入相应依赖包
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>4.0.1</version>
		</dependency>

		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>4.0.1</version>
		</dependency>
  • 准备需要导出学生成绩的SQL数据库表
    在这里插入图片描述
    在这里插入图片描述

两张表进行联合查询,形成含姓名的学生成绩表 (ps: 我是一个项目多个表中都需要使用学生姓名,所以使用多表联查实现表拼接,单独测试导出excel功能,可以直接在学生成绩表中直接添加一个学生姓名字段,单独查学生成绩表就行了)


三、代码实现:(注释有详细说明)

1. Controller 层:

/**
    *@ClassName: StudentController
    *@Description: 导出学生成绩excel
    *@Params:
    *@Return:
    *@Author xxw
    *@Date 2020/12/26
    */

    @GetMapping("/exportStuScoresExcel")
    public void exportStuScoreExcel(HttpServletResponse response) {
    
    

        List<?> allStuScoresList = studentService.getStuScores();

        // 反射获取实体类属性的对象
        Class<?> entityClass = allStuScoresList.get(0).getClass();
        Field[] declaredFields = entityClass.getDeclaredFields(); // 获取所有属性

        String[] titles = new String[declaredFields.length];
        for (int i = 0; i < titles.length; i++) {
    
    
            titles[i] = declaredFields[i].getName();
        }

        byte[] Excel = ExportExcelUtil.exportExcel("学生成绩", titles, allStuScoresList); // 调用工具类

        // 响应设置
        response.addHeader("Content-Disposition", "attchement;filename=/" + "studentScores.xlsx");
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/vnd.ms-excel");

        ServletOutputStream outputStream = null;

        try{
    
    
            response.setStatus(HttpStatus.OK.value());
            outputStream = response.getOutputStream();
            outputStream.write(Excel);
        }catch (IOException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            try {
    
    
                outputStream.close();
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }

2. Service 层:

public List<?> getStuScores() {
    
    
        try {
    
    
            List<StudentScores> stuScores = studentMapper.findStuScores();
            return stuScores;
        } catch (Exception e){
    
    
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

2. mapper层:

package com.xxw.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

@Repository
@Mapper
public interface StudentMapper {
    
    
    //查询所有学生成绩
    List<StudentScores> findStuScores();
}

4. ExportExcelUtil 工具类: (本人已对关键代码进行详细注释,还不懂请私信)

package com.xxw.utils;


import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
* 导出excel文件
* */
public class ExportExcelUtil {
    
    

    /**
     * @ClassName: ExportExcelUtil
     * @Description: 导出excel文件
     * @Params: title:列名 list:要插入的数据 sheetTitle:主题
     * @Return:
     * @Author xxw
     * @Date 2020/12/26
     */

    public static byte[] exportExcel(String sheetTitle, String[] title, List<?> list) {
    
    

        HSSFWorkbook wb = new HSSFWorkbook();

        // 创建工作区
        Sheet sheet = wb.createSheet(sheetTitle);

        // 创建表头
        Row row = sheet.createRow(0);
        row.setHeightInPoints(20);//行高

        // 第0行用于设置文件主题叫什么
        Cell cell = row.createCell(0);
        cell.setCellValue(sheetTitle);

        // 设置标题: 第1行用于设置字段名
        Row rowTitle = sheet.createRow(1);
        rowTitle.setHeightInPoints(20);
        // 字段名一一赋值, 比如: 姓名,年龄 ....
        Cell fillCell;
        for (int i = 0; i < title.length; i++) {
    
    
            fillCell = rowTitle.createCell(i);
            fillCell.setCellValue(title[i]);
        }

        byte result[] = null;
        ByteArrayOutputStream output = null; // 字符输出流

        try {
    
    
            // 创建表格数据
            Field[] fields;
            int i = 2; // 第0行和第1行已经被使用了

            for (Object rowObj : list) {
    
     // 获取List集合的每个对想


                // 反射获取对象数组
                fields = rowObj.getClass().getDeclaredFields();

                Row rowBody = sheet.createRow(i); // 创建行
                rowBody.setHeightInPoints(20); // 设置行高

                int j = 0;
                for (Field field : fields) {
    
     // 获取一个实体类对象的属性名

//                    System.out.println(field);

                    field.setAccessible(true); // 如果类中的成员变量为private,必须进行此操作
                    Object entityObj = field.get(rowObj); // 获得对应实体类对象对应属性名的值,比如: field = id, 则 entityObj 就是 id对应的值

                    // 如果取的值为null,则置"", 否则导出出现异常
                    if (entityObj == null) {
    
    
                        entityObj = "";
                    }

                    fillCell = rowBody.createCell(j); // 创建单元格
                    fillCell.setCellValue(entityObj.toString());

                    j++;
                }
                i++;
            }
            output = new ByteArrayOutputStream();
            wb.write(output); // 生成的excel写入字符流中
            result = output.toByteArray(); // 转换成字节数组
        } catch (Exception ex) {
    
    
            Logger.getLogger(ExportExcelUtil.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
    
    
            try {
    
    
                if (null != output) {
    
    
                    output.close();
                }
            } catch (IOException ex) {
    
    
                Logger.getLogger(ExportExcelUtil.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
    
    
                try {
    
    
                    wb.close();
                } catch (IOException ex) {
    
    
                    Logger.getLogger(ExportExcelUtil.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return result;
    }
}

5. Mapper.xml 映射文件:

<select id="findStuScores" resultType="StudentScores">
        select * from student stu, stuAchievement sta where stu.stuId = sta.stuId order by TotalScore desc
    </select>

6. application.yml 配置文件:

spring:
  servlet:
    multipart:
      max-file-size: 1000MB        #上传文件大小
      max-request-size: 1000MB     #下载文件大小

四、前端Vue+Axios下载文件不跳转页面

  • 使用Vue + Axios 实现下载文件时,不会跳出下载文件,而是响应一堆乱码字符串…
    在这里插入图片描述

传统方式解决下载文件响应乱码字符串问题:(使用超链接 href来实现)
在这里插入图片描述

使用超链接的方式,实际上走的是href的形式,浏览器跳转到指向的URL,发现是一个文件的话,就去下载,,如果URL出现了问题报 500,404,浏览器就会跳到这个URL页面,前端页面显示空白, 并不人性化,本应该就算URL请求报错,也还是停留在原网页。

  • 原因分析: 后端响应文件是 blob 对象,axios发送请求需要先配置 responseType: 'blob',然后发送请求才能实现当前页面下载文件,否则无法现在,响应体是一串乱码字符串,实际就是掉接口走 blob形式

  • 解决方法: (不懂的私信,随时在线)
    在这里插入图片描述
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/haduwi/article/details/112303700