IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue3+springboot 实现数据导出,多级表头,可设置表头宽度和数据内容单元格合并 -> 正文阅读

[JavaScript知识库]vue3+springboot 实现数据导出,多级表头,可设置表头宽度和数据内容单元格合并

项目场景:

数据导出或下载


主要实现逻辑

1、前端代码

1)数据导出按钮

<template>
        <div>
            <el-button type="primary" icon="download" @click="clickDownload()" style="float: right">导出或下载</el-button>
        </div>
</template>

<script setup>
    import {ElMessage} from 'element-plus'
    import {funDownloadData} from '@/api/ddd.js'     //引入ddd.js


    //下载--反映问题类型统计
    const clickDownload= () =>{
        let d={};  //接口参数根据自己业务需求
        funDownloadData(d).then(res => {
            if (!res.success) {
                ElMessage.error(res.message)
                return;
            }
            ElMessage.success("下载成功");
        });
    }


</script>

2)ddd.js 文件

import https from '@/utils/https';

/**
 * 下载数据
 * @param data
 * @returns {Promise<any> | PromiseLike<any>}
 */
export function funDownloadData(data){
    return https({
        url: '/admin/statistical/downloadData',            //输入后端请求数据的接口
        method: 'POST',
        responseType: 'blob',
        data
    }).then((res)=>{
        const fileName = "某某.xls"      //自定义文件名
        const link = document.createElement('a')
        link.href = window.URL.createObjectURL(res);
        link.download = fileName;
        link.click();
        window.URL.revokeObjectURL(link.href);
    })
}

2、后端代码?

1)先引入easyExcel依赖

<!-- easyExcel依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.0-beta2</version>
</dependency>

2)control层

package com.controller.admin;

import com.comm.Result;
import com.query.Query;
import com.service.IDataService ;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 统计控制层
 */
@RestController
@RequestMapping("admin/statistical")
public class StatisticalController {

  @PostMapping(value = "/downloadData",name = "下载反映问题类型情况统计数据")
    public Result downloadData(HttpServletRequest req, HttpServletResponse resp, @RequestBody @Validated Query query){  //Query 是用来接收参数,这是根据自己需求自定义的类
        return dataService.downloadData(req,resp,query);
    }

    @Autowired
    private IDataService dataService;
}

?3)service层代码

    @Override
    public Result downloadData(HttpServletRequest req, HttpServletResponse response, Query query) {
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/json;charset=utf-8");
            response.setCharacterEncoding("utf-8");
            String fileName = "某某";
            response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")+".xlsx");
            List<List<String>> headList= new ArrayList<>();  //headList 这是用来自定义表头内容
            headList.add(Lists.newArrayList( "姓名"));  //Lists.newArrayList( "性别")添加一个定义内容就是一级表头
            headList.add(Lists.newArrayList("性别", "男")); //Lists.newArrayList("性别", "男")添加两个定义内容就是有两级表头
            headList.add(Lists.newArrayList("性别", "女"));
            List<ExcelVO> list = getData(query);   //这个是请求获取的数据
            EasyExcel.write(out, ExcelVO.class).head(headList).sheet("某某").doWrite(list);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            return Result.failure(ResultCode.EXCEL_ERROR.getCode(),ResultCode.EXCEL_ERROR.getMessage());
        }finally {
            if (out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.success();
    }

?4)?ExcelVO 自定义类?

package com.vo;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.metadata.BaseRowModel;
import lombok.Data;

@Data
@HeadRowHeight(20)  //这个是设置行高
public class ExcelVO extends BaseRowModel {

    @ColumnWidth(20)  //这个是单元格宽度
    @ExcelProperty(index = 0,value = "姓名")
    private String name;//姓名

    @ColumnWidth(20)
    @ExcelProperty(index = 1,value = "男")
    private String sexMan;//男

    @ColumnWidth(20)
    @ExcelProperty(index = 1,value = "女")
    private String sexWoman;//女

}

5)上面的service 层还可以动态自定义表头,也不用自定义接收数据的类(如上面的ExcelVO)

    @Override
    public Result downloadData(HttpServletRequest req, HttpServletResponse response, Query query) {
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/json;charset=utf-8");
            response.setCharacterEncoding("utf-8");
            String fileName = "某某";
            response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")+".xlsx");
            List<List<String>> headList= new ArrayList<>();  //headList 这是动态定义掉头,拿到数据循环添加就行
            voS.forEach(v->{  //voS 是你根据请求获取的数据,然后循环添加到headList就可以了
                headList.add(Lists.newArrayList(v.getName(),v.getSex()));
                });
            List<List<String>> list = getData(query);   //这里请求获取的数据就要重新处理成List集合的数据,注意处理数据要对应动态表头
           EasyExcel.write(out).head(headList).registerWriteHandler(new SimpleColumnWidthStyleStrategy(20)).registerWriteHandler(new SimpleRowHeightStyleStrategy((short)40,(short)15)).sheet("某某").doWrite(list);  //registerWriteHandler 这个是可以设置表头样式,SimpleColumnWidthStyleStrategy 这个设置列宽,SimpleRowHeightStyleStrategy这个的第一参数是设置表头行高,第二个是设置内容数据的行高
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            return Result.failure(ResultCode.EXCEL_ERROR.getCode(),ResultCode.EXCEL_ERROR.getMessage());
        }finally {
            if (out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.success();
    }

6) 还可以数据内容单元格合并

//需要合并的列
int[] mergeColumeIndex = {0,1,2};
// 从第二行后开始合并
int mergeRowIndex = 2;
EasyExcel.write(out,ExcelVO.class).head(headList).registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeColumeIndex)).sheet("某某").doWrite(list);
//ExcelMergeHandler 自定义拦截处理器的类,主要用来处理合并数据

7)ExcelMergeHandler 类

package com.handler;

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

public class ExcelMergeHandler implements CellWriteHandler {
    private int[] mergeColumnIndex;
    private int mergeRowIndex;
    public ExcelMergeHandler() {
    }

    public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();

        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }


    /**
     * 当前单元格向上合并
     *
     * @param writeSheetHolder
     * @param cell             当前单元格
     * @param curRowIndex      当前行
     * @param curColIndex      当前列
     */
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
        // 将当前单元格数据与上一个单元格数据比较
        Boolean dataBool = preData.equals(curData);
        //此处需要注意:因为我是按照工程名称确定是否需要合并的,所以获取每一行第二列数据和上一行第一列数据进行比较,如果相等合并,getCell里面的值,是工程名称所在列的下标
        String s1 = cell.getRow().getCell(0).getStringCellValue();
        String s2 = cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue();
        /*BigDecimal d1 = new BigDecimal(cell.getRow().getCell(0).getNumericCellValue());
        BigDecimal d2 = new BigDecimal(cell.getSheet().getRow(curRowIndex - 1).getCell(0).getNumericCellValue());*/
        Boolean bool = s1.compareTo(s2) == 0 ? true:false;
        // 原始的
        // Boolean bool =  cell.getRow().getCell(1).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(1).getStringCellValue());
        if (dataBool && bool) {
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
                CellRangeAddress cellRangeAddr = mergeRegions.get(i);
                // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
                    sheet.removeMergedRegion(i);
                    cellRangeAddr.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellRangeAddr);
                    isMerged = true;
                }
            }
            // 若上一个单元格未被合并,则新增合并单元
            if (!isMerged) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
                sheet.addMergedRegion(cellRangeAddress);
            }
        }
    }
}

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 01:54:55  更:2022-09-15 01:56:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:14:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码