将页面任意table内容导出为Excel

 主要思路是获取table中行与列封装为二维数组,传入后端解析后保存为Excel

<a-button @click="exportExcel" type="primary" icon="download" style="margin-left: 21px">导出</a-button>

定义导出按钮

//这个是页面按钮触发的方法
exportReport(this.$refs.table,this.title,3)
//触发方法调用的js
import { axios } from '@/utils/request'
import Vue from 'vue'
export function exportReport(table,excelName,headNum){
      if(!table){
        return
      }
      let tableObj =  table.$el.querySelector('table')
      let params = {}
      params.tableData = getTableArray(tableObj)
      params.tableName = excelName+'.xls'
      params.headNum = headNum
      let url = `${window._CONFIG['domianURL']}/controltotal/reportexport/export`
      downFile(url,params).then((data) => {
            if (!data || data.size === 0) {
                  Vue.prototype['$message'].warning('文件下载失败')
                  return
                }
                if (typeof window.navigator.msSaveBlob !== 'undefined') {
                  window.navigator.msSaveBlob(new Blob([data]), params.tableName)
                } else {
                  let url = window.URL.createObjectURL(new Blob([data]))
                  let link = document.createElement('a')
                  link.style.display = 'none'
                  link.href = url
                  link.setAttribute('download', params.tableName)
                  document.body.appendChild(link)
                  link.click()
                  document.body.removeChild(link) //下载完成移除元素
                  window.URL.revokeObjectURL(url) //释放掉blob对象
                }
      })

}
function downFile(url,parameter){
  return axios({
      url: url,
      method: 'post',
      data: parameter,
      responseType: 'blob'
      })
}
function getTableArray(table) {
   
    let rows =  table.querySelectorAll('tr')
    let rowsArr = []
    //第一次循环将要横向合并的单元格填充为空,同时考虑行列都有合并情况
    for(let rowsNumber = 0; rowsNumber < rows.length; rowsNumber++){
          let row = rows[rowsNumber]
          let colums = row.querySelectorAll('th, td')
          let columsArr = []
          for(let colNumber = 0; colNumber< colums.length; colNumber++){
                    let TableCell = {}
                    let cell = colums[colNumber]
                    TableCell.value = cell.textContent
                    TableCell.rowSpan = cell.getAttribute('rowspan')
                    TableCell.colSpan = cell.getAttribute('colspan')
                    if(cell.getAttribute('rowspan')){
                        let rowspan = cell.getAttribute('rowspan')
                        let leftNum = parseInt(rowspan)
                        TableCell.leftNum = leftNum
                    }
                    columsArr.push(TableCell)
                    if(cell.getAttribute('colspan')){
                      let colspan = cell.getAttribute('colspan')
                      let pushNum = parseInt(colspan)
                      for(let i=1;i<pushNum;i++){
                        let emp = {}
                        emp.value = ''
                        emp.rowSpan = null
                        emp.colSpan = null
                        if(TableCell.leftNum){
                           emp.leftNum = TableCell.leftNum
                        }
                        columsArr.push(emp)
                      }
                    }
          }
          rowsArr.push(columsArr)
    }

    //这次循环的目的是使每一行的单元格数量相等;并且考虑列合并
    for(let rowsNumber = 1; rowsNumber < rowsArr.length; rowsNumber++){
          let thisColumns = rowsArr[rowsNumber]
          let preColums = rowsArr[rowsNumber-1]
          let newArr = []
          let index = 0
          if(thisColumns.length != preColums.length){
                for(let i =0;i<preColums.length;i++){
                   let obj = preColums[i]
                   let emp = {}
                   emp.value = ''
                   emp.rowSpan = null
                   emp.colSpan = null
                   if(obj.leftNum){
                        let leftNum = obj.leftNum -1
                        if(leftNum > 1){
                              emp.leftNum =  obj.leftNum -1
                        }
                        newArr.push(emp)
                   }else{
                        if(thisColumns[index]){
                          newArr.push(thisColumns[index])
                        }else{
                          newArr.push(emp)
                        }
                        index++
                   }
                }
                rowsArr[rowsNumber] = newArr
          }
    }
    return rowsArr;
  }

后端就比较简单了,根据前端传来的数组,一行一行的创建单元格

@PostMapping(value = "/export")
    public void reportExport(@RequestBody ExportParam exportParam, HttpServletResponse response) {
         //这里的名字其实没有用的
        String excelName = "报表导出数据.xls";
        if (StringUtils.isNotBlank(exportParam.getTableName())) {
            excelName = exportParam.getTableName();
        }
        TableToExcelUtil util = new TableToExcelUtil();
        HSSFWorkbook workbook = util.createExcelFormTable(exportParam);
        response.setHeader("Content-Disposition", "attachment;filename="+excelName);
        response.setContentType("application/octet-stream");
        response.setStatus(HttpServletResponse.SC_OK);
        // 将 Excel 文件写入 response 输出流
        try {
            workbook.write(response.getOutputStream());
        }catch (IOException  e){
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }finally {
            try {
                workbook.close();
            }catch (IOException e){

            }
        }
    }

下面是工具类,内容主要都在循环中

 public HSSFWorkbook createExcelFormTable(ExportParam exportParam){
        JSONArray tableData = exportParam.getTableData();
        HSSFWorkbook wb = new HSSFWorkbook();
        CellStyle headStyle = this.createHeadStyle(wb);
        CellStyle bodyStyle = this.createBodyStyle(wb);
        HSSFSheet sheet = wb.createSheet("test");
        for (int rowNumber =0; rowNumber<tableData.size(); rowNumber++) {
            HSSFRow row = sheet.createRow(rowNumber);
            List<HashMap<String,String>> columData = (List<HashMap<String,String>>)tableData.get(rowNumber);
            for(int columNumber = 0; columNumber< columData.size(); columNumber++){
                row.createCell(columNumber);
                HSSFCell cell = row.getCell(columNumber);
                //判断是否为表头,使用对应的excel格式
                if(rowNumber < exportParam.getHeadNum()){
                    cell.setCellStyle(headStyle);
                }else{
                    cell.setCellStyle(bodyStyle);
                }
                HashMap<String,String> col = columData.get(columNumber);
                if(null != col.get("rowSpan")){
                    //纵向合并
                    CellRangeAddress cellAddresses = new CellRangeAddress(rowNumber, rowNumber+Integer.parseInt(col.get("rowSpan"))-1, columNumber, columNumber);
                    removeOverlappingMergedRegions(sheet, cellAddresses);
                    sheet.addMergedRegion(cellAddresses);
                }
                if (null != col.get("colSpan")) {
                    //横向合并
                    CellRangeAddress cellAddresses = new CellRangeAddress(rowNumber, rowNumber, columNumber, columNumber+Integer.parseInt(col.get("colSpan"))-1);
                    removeOverlappingMergedRegions(sheet, cellAddresses);
                    sheet.addMergedRegion(cellAddresses);
                }
                cell.setCellValue(col.get("value"));
            }
        }
        return wb;
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值