Springboot + EasyExcel + Vue 实现excel下载功能

一、添加EasyExcel依赖

 <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>3.3.2</version>
 </dependency>

二、后端代码示例

controller:

    @GetMapping("/download")
    public void download(HttpServletResponse response) throws IOException {
        String dataFormat = new SimpleDateFormat("yyyyMMdd").format(new Date());
        //xlsx格式:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet  xls格式:application/vnd.ms-excelExport
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("满意度调查信息导出表" + dataFormat, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel
                .write(response.getOutputStream(), ScorePsnExcelDTO.class)
                .registerWriteHandler(EasyExcelUtils.getStyle())//引用样式
                .registerWriteHandler(new CustomCellWriteWidthConfig())//自适应列宽
                .registerWriteHandler(new CustomCellWriteHeightConfig())//自适应行高
                .sheet("调查表")
                .doWrite(data());//业务数据
    }

DTO(模板数据):

package cn.hsa.pss.pw.web.thirdinterface.excelExport.dto;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 * 医疗机构评价 -评价人DTO
 *
 * @Author:
 * @Date:2024-01-23 16:46
 * @Description:
 */
@Data
public class ScorePsnExcelDTO {

    @ExcelProperty(value = "序号", index = 0)
    private Integer no;

    //定点统筹区(参保人统筹区
    @ExcelProperty(value = "定点统筹区", index = 1)
    private String areaCode;

    //医药机构编码
    @ExcelProperty(value = "医药机构编码", index = 2)
    private String medInsCode;

    //医药机构名称
    @ExcelProperty(value = "医药机构名称", index = 3)
    private String medInsName;

    //医药机构类型
    @ExcelProperty(value = "医药机构类型", index = 4)
    private String medInsType;

    //医疗类别
    @ExcelProperty(value = "医疗类别", index = 5)
    private String medType;

    //就医人次
    @ExcelProperty(value = "就医人次", index = 6)
    private Integer medNum;

    //参与调查人次
    @ExcelProperty(value = "参与调查人次", index = 7)
    private Integer scoreNum;

    //很不满意
    @ExcelProperty(value = {"评价分布", "很不满意"}, index = 8)
    private Integer scoreOne;

    //不满意
    @ExcelProperty(value = {"评价分布", "不满意"}, index = 9)
    private Integer scoreTwo;

    //一般
    @ExcelProperty(value = {"评价分布", "一般"}, index = 10)
    private Integer scoreThree;

    //比较满意
    @ExcelProperty(value = {"评价分布", "比较满意"}, index = 11)
    private Integer scoreFour;

    //很满意
    @ExcelProperty(value = {"评价分布", "很满意"}, index = 12)
    private Integer scoreFive;

    //参与调查率
    @ExcelProperty(value = "参与调查率", index = 13)
    private Double scoreRate;

    //满意度
    @ExcelProperty(value = "满意度", index = 14)
    private String goodRate;
}

关键点1:响应头设置

//如果前端接收xlsx格式,则
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

//如果前端接收xls格式,则
        response.setContentType("application/vnd.ms-excelExport");

关键点2:ScorePsnExcelDTO 

1、 @ExcelProperty(value = "序号", index = 0) 

value对应的导出excel的列名,index代表顺序

2、如果涉及到单元格合并,可以这么写:

@ExcelProperty(value = {"评价分布", "很不满意"}, index = 8)

 @ExcelProperty(value = {"评价分布", "一般"}, index = 10)

效果如下:

关键点3:

要使用get方法

自适应行高:

package cn.hsa.pss.pw.web.thirdinterface.excelExport.config;

import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;

import java.util.Iterator;

/**
 * 自适应行高
 *
 * @Author:
 * @Date:2024-02-01 14:00
 * @Description:
 */
public class CustomCellWriteHeightConfig extends AbstractRowHeightStyleStrategy {

    /**
     * 默认高度
     */
    private static final Integer DEFAULT_HEIGHT = 300;

    @Override
    protected void setHeadColumnHeight(Row row, int relativeRowIndex) {

    }

    @Override
    protected void setContentColumnHeight(Row row, int relativeRowIndex) {
        Iterator<Cell> cellIterator = row.cellIterator();
        if (!cellIterator.hasNext()) {
            return;
        }
        // 默认为 1行高度
        int maxHeight = 1;
        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();
            if (cell.getCellTypeEnum() == CellType.STRING) {
                String value = cell.getStringCellValue();
                int len = value.length();
                int num = 0;
                if (len > 50) {
                    num = len % 50 > 0 ? len / 50 : len / 2 - 1;
                }
                if (num > 0) {
                    for (int i = 0; i < num; i++) {
                        value = value.substring(0, (i + 1) * 50 + i) + "\n" + value.substring((i + 1) * 50 + i, len + i);
                    }
                }
                if (value.contains("\n")) {
                    int length = value.split("\n").length;
                    maxHeight = Math.max(maxHeight, length) + 1;
                }
            }
        }
        row.setHeight((short) ((maxHeight) * DEFAULT_HEIGHT));
    }


}

自适应列宽:

package cn.hsa.pss.pw.web.thirdinterface.excelExport.config;

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;

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

/**
 * 自适应列宽
 *
 * @Author:
 * @Date:2024-02-01 13:38
 * @Description:
 */
public class CustomCellWriteWidthConfig extends AbstractColumnWidthStyleStrategy {

    private final Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            Map<Integer, Integer> maxColumnWidthMap = CACHE.computeIfAbsent(writeSheetHolder.getSheetNo(), k -> new HashMap<>());

            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
            // 单元格文本长度大于60换行
            if (columnWidth >= 0) {
                if (columnWidth > 60) {
                    columnWidth = 60;
                }
                Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                    Sheet sheet = writeSheetHolder.getSheet();
                    sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
                }
            }
        }
    }

    /**
     * 计算长度
     *
     * @param cellDataList
     * @param cell
     * @param isHead
     * @return
     */
    private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData<?> cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        // 换行符(数据需要提前解析好)
                        int index = cellData.getStringValue().indexOf("\n");
                        return index != -1 ?
                                cellData.getStringValue().substring(0, index).getBytes().length + 1 : cellData.getStringValue().getBytes().length + 1;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }


}

字体样式工具类:

package cn.hsa.pss.pw.web.thirdinterface.excelExport.utils;

import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;

import java.util.ArrayList;

/**
 * 设置excel工具类
 *
 * @Author:wangguangxing
 * @Date:2024-02-01 14:18
 * @Description:
 */
public class EasyExcelUtils {

    public static HorizontalCellStyleStrategy getStyle() {
//自定义表头样式  浅橙色 居中
        WriteCellStyle headCellStyle = new WriteCellStyle();
        headCellStyle.setFillForegroundColor(IndexedColors.TAN.getIndex());  //表头颜色
        headCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);    //文本居中
        //字体
        WriteFont writeFont = new WriteFont();
        writeFont.setFontName("微软雅黑");                                   //字体
        writeFont.setFontHeightInPoints((short) 10);                         //字体大小
        headCellStyle.setWriteFont(writeFont);
        // 自动换行
        headCellStyle.setWrapped(true);

        //内容样式
        WriteCellStyle contentCellStyle = new WriteCellStyle();
        contentCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); //文本居中
        contentCellStyle.setWriteFont(writeFont);
        //设置边框
        contentCellStyle.setBorderLeft(BorderStyle.THIN);                    //左边框线
        contentCellStyle.setBorderTop(BorderStyle.THIN);                     //顶部框线
        contentCellStyle.setBorderRight(BorderStyle.THIN);                   //右边框线
        contentCellStyle.setBorderBottom(BorderStyle.THIN);                  //底部框线
        ArrayList<WriteCellStyle> contentCells = new ArrayList<>();
        contentCells.add(contentCellStyle);
        //样式策略
        HorizontalCellStyleStrategy handler = new HorizontalCellStyleStrategy();
        handler.setHeadWriteCellStyle(headCellStyle);                        //表头样式
        handler.setContentWriteCellStyleList(contentCells);                  //内容样式
        return new HorizontalCellStyleStrategy(headCellStyle, contentCells);
    }
}

三、前端代码示例

1、
     exportFile() {
          
                this.downLoading = true
                exportScoreList().then((res) => {
                    this.downLoading = false
                    const str = res.headers["content-disposition"]
                    const fileName = decodeURI(str.substr(str.indexOf("%")))
                    this.downloadFile(res.data, fileName)
                }).catch((err) => {
                    this.downLoading = false
                })
            }


2、
 downloadFile(res, fileName) {
               
                let blob = new Blob([res], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
                if (!fileName) {
                    fileName = res.headers['content-disposition'].split('filename=').pop();
                }
                if ('msSaveOrOpenBlob' in navigator) {
                    window.navigator.msSaveOrOpenBlob(blob, fileName);
                } else {
                    const elink = document.createElement('a');
                    elink.download = fileName;
                    elink.style.display = 'none';
                    elink.href = window.URL.createObjectURL(blob);
                    document.body.appendChild(elink);
                    elink.setAttribute('href', elink.href)
                    elink.click();
                    document.body.removeChild(elink);
                    window.URL.revokeObjectURL(elink.href);

                }
            }

3、
export function exportScoreList() {
    return axios({
        url: `${path}/excel/download`,
        method: "get",
        responseType: "blob"
    });
}

关键点1:

responseType: "blob"    method: "get",

关键点2:

 let blob = new Blob([res], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}) 

要与后台响应头类型对应上。

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实现上传excel文件并将数据传输到数据库的步骤如下: 1. 前端实现文件上传功能:使用Vue.js开发前端页面,使用element-ui组件库实现文件上传组件。具体实现可以参考element-ui的文档和示例代码。 2. 后端实现文件上传功能:使用Spring Boot框架开发后端接口,使用Apache POI或者EasyExcel解析Excel文件并将数据存入数据库。具体实现可以参考Spring Boot官方文档和EasyExcel的官方文档。 3. 前后端交互:前端页面通过Ajax请求后端接口上传文件,并将文件数据以form-data格式传输到后端。后端接口接收到请求后,解析Excel文件并将数据存入数据库,最后返回上传结果给前端。 下面是一个简单的示例代码,仅供参考: 前端代码: ```vue <template> <el-upload class="upload-demo" drag action="/api/upload" :before-upload="beforeUpload" :on-success="onSuccess" :on-error="onError" > <i class="el-icon-upload"></i> <div class="el-upload__text">将 Excel 文件拖到此处,或点击上传</div> <div class="el-upload__tip" slot="tip">仅支持 .xls 和 .xlsx 格式的 Excel 文件</div> </el-upload> </template> <script> export default { methods: { beforeUpload(file) { const isExcel = file.type === 'application/vnd.ms-excel' || file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; if (!isExcel) { this.$message.error('只能上传 .xls 或 .xlsx 格式的 Excel 文件'); } return isExcel; }, onSuccess(response) { if (response.code === 0) { this.$message.success('上传成功'); } else { this.$message.error(`上传失败: ${response.msg}`); } }, onError(error) { this.$message.error(`上传失败: ${error.message}`); }, }, }; </script> ``` 后端代码: ```java @RestController @RequestMapping("/api") public class UploadController { @PostMapping("/upload") public Result<?> upload(@RequestParam("file") MultipartFile file) throws IOException { if (file.isEmpty()) { return Result.error("上传失败: 文件为空"); } String filename = file.getOriginalFilename(); String ext = FilenameUtils.getExtension(filename); if (!"xls".equals(ext) && !"xlsx".equals(ext)) { return Result.error("上传失败: 仅支持 .xls 或 .xlsx 格式的 Excel 文件"); } List<User> userList = new ArrayList<>(); Workbook workbook = WorkbookFactory.create(file.getInputStream()); Sheet sheet = workbook.getSheetAt(0); for (int i = 1; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); if (row == null) { continue; } User user = new User(); user.setName(row.getCell(0).getStringCellValue()); user.setAge((int) row.getCell(1).getNumericCellValue()); user.setGender(row.getCell(2).getStringCellValue()); userList.add(user); } userService.saveAll(userList); return Result.ok(); } } ``` 上述代码中,`UploadController`是一个Spring MVC的控制器类,用于处理上传文件的请求。`upload`方法接收一个`MultipartFile`类型的参数,即前端上传的文件数据。在方法中,我们首先判断文件是否为空,然后根据文件的扩展名判断是否为Excel文件。如果不是Excel文件,则返回上传失败的结果。否则,我们使用Apache POI库解析Excel文件,将数据转换成`User`对象并存入数据库。最后,返回上传成功的结果。 需要注意的是,上述代码中的`User`对象是一个自定义的Java类,用于存储Excel中的数据。在实际开发中,需要根据实际情况定义相应的Java类来存储数据。同时,还需要在Spring Boot的配置文件中配置数据库连接信息、数据源等相关信息。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值