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

本文介绍了如何通过Java技术,利用Apache POI库导出学生成绩到Excel,包括SQL数据库操作、Spring MVC与MyBatis配合、Excel文件生成工具的使用,并解决了前端Vue通过Axios下载文件时的乱码问题。
摘要由CSDN通过智能技术生成

一、应用背景:

导出学生成绩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形式

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

Vue2中实现从服务器请求数据并将其导出Excel的功能,通常需要借助一些前端库如`js-xlsx`、`xlsx-style`以及`axios`来完成。以下是一个简单的步骤概述: 1. **安装所需库**: - 首先,你需要在项目中安装`axios`用于处理HTTP请求: ``` npm install axios ``` - 然后,安装用于生成Excel文件的库,例如`js-xlsx`和`xlsx-style`(如果还未安装): ``` npm install xlsx xlsx-style ``` 2. **请求数据**: 使用`axios`发起GET请求到服务器,获取需要的数据。假设你的API路径是`'/export-excel'`,可以这样做: ```javascript import axios from 'axios'; exportExcel() { axios.get('/export-excel') .then(response => { // response.data 包含了服务器返回的json数据 }) .catch(error => { console.error('Error fetching data:', error); }); } ``` 3. **转换为表格数据**: 将获取到的JSON数据转换成适合导出Excel的二维数组。 4. **生成Excel文件**: 使用`js-xlsx`创建一个新的工作簿,并将数据添加到工作表中: ```javascript const XLSX = require('xlsx'); const workbook = XLSX.utils.book_new(); const worksheet = XLSX.utils.json_to_sheet(data); // `data`是之前转换得到的表格数据 // 将工作表添加到工作簿 XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1"); // 生成下载链接 const fileURL = XLSX.writeFile(workbook, 'output.xlsx'); // 'output.xlsx' 是导出文件名 this.$http.download(fileURL, 'download.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // 这里可能需要自定义下载方法 ``` 5. **考虑异步下载**: 如果你希望用户立即看到文件正在下载的提示,而不是直接跳转到下载地址,可以使用`blob`对象实现异步下载。 注意:这只是一个基础示例,实际应用中你可能还需要处理错误、文件命名和内容格式化等问题。另外,部分浏览器对某些操作可能会有安全限制,确保你的服务器配置允许跨域访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0rta1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值