有关后端使用Springboot导出Excel,前端使用vue实现Excel下载的功能实现

36 篇文章 0 订阅
接到一个需求 ,是有关Excel导出的功能,用户通过页面的数据,进行批量的导出操作。话不多说,直接上代码:
后端
package com.ly.travelaround.cms.common.utils;

import org.apache.poi.hssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 导出实体到Excel的工具类
 * @Date 2021/9/2 10:17
 */
public class ExportEntityToExcel {
    private static final Logger logger = LoggerFactory.getLogger(ExportEntityToExcel.class);

    public static <T> void export(String excelName, List<T> list, LinkedHashMap<String, String> fieldMap, HttpServletResponse response, HttpServletRequest request) {

        // 设置默认文件名为当前时间:年月日时分秒
        if (excelName == null || excelName == "") {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
            String defaultName = sdf.format(new Date());
            excelName = defaultName;
        }
        try {
            String fileName = new String(excelName.getBytes("gb2312"), "ISO8859-1") + ".xls";
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel"); // 改成输出excel文件
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "No-cache");
            // 设置response头信息
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

        } catch (Exception e1) {
            logger.info(e1.getMessage());
        }

        try {
            //创建一个WorkBook,对应一个Excel文件
            HSSFWorkbook workbook = new HSSFWorkbook();
            //在Workbook中,创建一个sheet,对应Excel中的工作薄(sheet)
            HSSFSheet sheet = workbook.createSheet(excelName);
            //创建单元格,并设置值表头 设置表头居中
            HSSFCellStyle style = workbook.createCellStyle();
            //创建一个居中格式
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            // 填充工作表
            fillSheet(sheet, list, fieldMap, style);
            //将文件输出
            OutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            logger.info("导出Excel失败!");
            logger.error(e.getMessage());
        }
    }

    /**
     * 根据字段名获取字段
     */
    public static Field getFieldByName(String fieldName, Class<?> clazz) {
        // 获取所有字段
        Field[] selfFields = clazz.getDeclaredFields();
        // 如果本类中存在该字段,则返回
        for (Field field : selfFields) {
            //如果本类中存在该字段,则返回
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }

        // 否则,查看父类中是否存在此字段,如果有则返回
        Class<?> superClazz = clazz.getSuperclass();
        if (superClazz != null && superClazz != Object.class) {
            //递归
            return getFieldByName(fieldName, superClazz);
        }

        // 如果本类和父类都没有,则返回空
        return null;
    }

    /**
     * 根据字段名获取字段值
     */
    public static Object getFieldValueByName(String fieldName, Object o) throws Exception {
        Object value = null;
        //根据字段名得到字段
        Field field = getFieldByName(fieldName, o.getClass());

        //如果该字段存在,则取出该字段的值
        if (field != null) {
            field.setAccessible(true);//类中的成员变量为private,在类外边使用属性值,故必须进行此操作
            value = field.get(o);//获取当前对象中当前Field的value
        } else {
            throw new Exception(o.getClass().getSimpleName() + "类不存在字段名: " + fieldName);
        }

        return value;
    }

    /**
     * 根据带路径或不带路径的属性名获取属性值,即接受简单属性名,
     * 如userName等,又接受带路径的属性名,如student.department.name等
     */
    public static Object getFieldValueByNameSequence(String fieldNameSequence, Object o) throws Exception {
        Object value = null;
        // 将fieldNameSequence进行拆分
        String[] attributes = fieldNameSequence.split("\\.");
        if (attributes.length == 1) {
            value = getFieldValueByName(fieldNameSequence, o);
        } else {
            // 根据数组中第一个连接属性名获取连接属性对象,如student.department.name
            Object fieldObj = getFieldValueByName(attributes[0], o);
            //截取除第一个属性名之后的路径
            String subFieldNameSequence = fieldNameSequence.substring(fieldNameSequence.indexOf(".") + 1);
            //递归得到最终的属性对象的值
            value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj);
        }
        return value;

    }

    /**
     * 向工作表中填充数据
     */
    public static <T> void fillSheet(HSSFSheet sheet, List<T> list, LinkedHashMap<String, String> fieldMap, HSSFCellStyle style) throws Exception {
        // 定义存放英文字段名和中文字段名的数组
        String[] enFields = new String[fieldMap.size()];
        String[] cnFields = new String[fieldMap.size()];

        // 填充数组
        int count = 0;
        for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
            enFields[count] = entry.getKey();
            cnFields[count] = entry.getValue();
            count++;
        }
        //在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
        HSSFRow row = sheet.createRow((int) 0);
        // 填充表头
        for (int i = 0; i < cnFields.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellValue(cnFields[i]);
            cell.setCellStyle(style);
            sheet.setColumnWidth(i, 3000);//设置表格宽度
        }
        // 填充内容
        for (int index = 0; index < list.size(); index++) {
            row = sheet.createRow(index + 1);
            // 获取单个对象
            T item = list.get(index);
            for (int i = 0; i < enFields.length; i++) {
                Object objValue = getFieldValueByNameSequence(enFields[i], item);
                String fieldValue = objValue == null ? "" : objValue.toString();
                row.setRowStyle(style);
                row.createCell(i).setCellValue(fieldValue);
            }
        }
    }
}
/**
*对应着导出的Excel实体信息 
*/
//略
/**
*控制层
*/
@RestController("excel")
public class ExcelExportController {
    @PostMapping(value = "downLoadExcel")
    public void downLoadExcel(HttpServletResponse response, HttpServletRequest request, @RequestBody() List<ExcelPo> dataList) {
        if (null == dataList || dataList.size() <= 0) {
            return ;
        }
        response.setCharacterEncoding("utf-8");
        String excelName = "酒店列表";
        LinkedHashMap<String, String> fieldMap = new LinkedHashMap<>();
        fieldMap.put("order", "排序值");
        fieldMap.put("cityId", "城市ID");
        fieldMap.put("hotelId", "商品ID");
        fieldMap.put("hotelName", "商品名称");
        fieldMap.put("start", "星级");
        fieldMap.put("score", "评分");
        fieldMap.put("commentTotal", "点评数量");
        fieldMap.put("price", "价格");
        fieldMap.put("filterName", "商圈名称");
        new ExportEntityToExcel().export(excelName, dataList, fieldMap, response, request);
    }
}
其中后端代码是使用的—参考链接—的代码。
前端
   <el-button :disabled="isActive" @click="exportChoosed" type="info"
        >导出数据</el-button>
   exportChoosed() {
      // 利用a标签自定义下载文件名
      const link = document.createElement("a");
      //let choosedList = this.multipleSelection.map((item) => {
        //return item;
      //});
      //这里的choosedList是你需要导出的数据集合 我这里是我的具体使用场景 你需要什么就传什么
      console.log("chooosedList", choosedList);
      //请求后端接口 进行excel的导出
      hotelList
        .exportChoosedToExcel(choosedList)
        .then((res) => {
          let blob = new Blob([res], { type: "application/vnd.ms-excel" }); // res就是接口返回的文件流了
          let objectUrl = URL.createObjectURL(blob);
          debugger;
          link.href = objectUrl;
          link.download = "酒店列表"; // 自定义文件名
          link.click(); // 下载文件
          // window.location.href = objectUrl;
          window.URL.revokeObjectURL(objectUrl); // 释放内存
        })
        .catch((err) => {
          console.log("被catch到了", err);
          return {
            code: 500,
            success: false,
            msg: err,
          };
        });
        }
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,那么您可以使用Apache POI库来实现Excel导出,同时将生成Excel文件的字节数组(即Blob)封装到一个JsonObject对象中,然后返回该对象给前端。 具体实现步骤如下: 1. 后端使用Apache POI库创建Excel文件并写入数据。 2. 在Controller中定义一个导出Excel的接口,使用JsonObject对象来封装Excel文件的字节数组和其他相关信息。 3. 将JsonObject对象转换成字符串后,使用ResponseEntity将其写入响应体中,并设置Content-Type为application/json,这样前端就可以通过解析响应体得到Excel文件的字节数组和其他相关信息。 4. 如果导出Excel遇到异常,可以使用try-catch语句捕获异常,并将异常信息封装到JsonObject对象中返回给前端。 下面是一个简单的示例代码,仅供参考: ```java @RestController public class ExcelController { @GetMapping("/exportExcel") public ResponseEntity<String> exportExcel() { JsonObject result = new JsonObject(); try { // 使用Apache POI创建Excel文件并写入数据 Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("sheet1"); Row row = sheet.createRow(0); Cell cell = row.createCell(0); cell.setCellValue("Hello World!"); ByteArrayOutputStream out = new ByteArrayOutputStream(); wb.write(out); // 将生成Excel文件的字节数组封装到JsonObject对象中 result.addProperty("success", true); result.addProperty("message", "导出Excel成功"); result.addProperty("fileName", "example.xls"); result.addProperty("fileContent", Base64.getEncoder().encodeToString(out.toByteArray())); // 将JsonObject对象转换成字符串并返回给前端 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return new ResponseEntity<>(result.toString(), headers, HttpStatus.OK); } catch (Exception e) { // 如果导出Excel遇到异常,将异常信息封装到JsonObject对象中返回给前端 result.addProperty("success", false); result.addProperty("message", "导出Excel失败:" + e.getMessage()); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return new ResponseEntity<>(result.toString(), headers, HttpStatus.INTERNAL_SERVER_ERROR); } } } ``` 在前端中,您可以使用axios或其他HTTP库来调用后端导出Excel接口,例如: ```javascript axios.get('/exportExcel') .then(response => { if (response.data.success) { // 导出Excel成功,使用Blob对象创建一个URL并下载Excel文件 let url = URL.createObjectURL(base64ToBlob(response.data.fileContent)); let link = document.createElement('a'); link.style.display = 'none'; link.href = url; link.setAttribute('download', response.data.fileName); document.body.appendChild(link); link.click(); } else { // 导出Excel失败,展示错误信息 console.error(response.data.message); alert('导出Excel失败'); } }) .catch(error => { // 调用导出Excel接口失败,展示错误信息 console.error(error); alert('调用导出Excel接口失败'); }); function base64ToBlob(base64String) { let byteCharacters = atob(base64String); let byteNumbers = new Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } let byteArray = new Uint8Array(byteNumbers); return new Blob([byteArray]); } ``` 这样就可以实现生成Excel文件的字节数组封装到JsonObject对象中,然后返回该对象给前端功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

还算善良_

如果对你的工作有所帮助,拜托啦

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

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

打赏作者

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

抵扣说明:

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

余额充值