VUE项目中使用EasyExcel下载复杂表格
前言
目前刚做完一个VUE的项目,前台菜单中有一个下载统计报表的功能,该表的结构比较复杂,没有采用传统的导出表头的那种方式,而是自己定义了一套表格模板,通过EasyExcel的方式去填充内容;现在项目已经上线,抽空在此记录一下实现过程,以后有类似的功能可以作为参考。
一、定义要下载的表格模板
业务需求提供的表格模板:
技术定义完字段后的表格模板:
二、代码实现
1.控制类
1.查询会商诊断表全部字段信息,这一步就是从数据库中遍历出所需要的字段值;
2.数据字典转码,这一步根据自身需要来定,我这里是从数据库查询到的值是code值,需要转成中文展示才进行转码;
3.把会商诊断表组装成Map,这一步基本上是需要的,因为表格模板中的定义字段是Map类型的,所以需要封装一下,不过这一步也可以直接在步骤1中实现,看个人选择了。
代码如下(示例):
package com.icbc.tech.ccrm.custlib.primary.controller;
import com.icbc.tech.ccrm.common.auth.utils.ExcelUtils;
import com.icbc.tech.ccrm.common.util.ExcelExportUtils;
import com.icbc.tech.ccrm.custlib.primary.entity.dto.CustlibPrimaryConDiaOutDTO;
import com.icbc.tech.ccrm.custlib.primary.entity.dto.CustlibPrimaryConDiaVO;
import com.icbc.tech.ccrm.custlib.primary.service.ICrmCCustlibPrimaryService;
import com.icbc.tech.ccrm.system.scommoncode.service.ICrmSCommonCodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 会商诊断表导出控制器
* @Date 2022/9/23
*/
@RestController
@Slf4j
@Validated
@RequestMapping("/c/primary/consultation-diagnosis")
public class CrmCCustlibPrimaryConDiaController {
@Autowired
private ICrmCCustlibPrimaryService iCrmCCustlibPrimaryService;
@Autowired
private ExcelUtils excelUtils;
@Autowired
private ExcelExportUtils excelExportUtils;
@GetMapping("/download/v1")
public void downloadOperational(@Valid CustlibPrimaryConDiaVO custlibPrimaryConDiaVO, HttpServletResponse response) throws IOException {
try {
List<CustlibPrimaryConDiaOutDTO> dictList1 = new ArrayList<>();
List<CustlibPrimaryConDiaOutDTO> dictList2 = new ArrayList<>();
//查询会商诊断表全部字段信息
CustlibPrimaryConDiaOutDTO custlibPrimaryConDiaOutDTO = iCrmCCustlibPrimaryService.findPrimaryConDiaInfo(custlibPrimaryConDiaVO);
dictList1.add(custlibPrimaryConDiaOutDTO);
//数据字典转码
dictList2 = excelExportUtils.convertDictCode(dictList1, CustlibPrimaryConDiaOutDTO.class, ICrmSCommonCodeService.class);
custlibPrimaryConDiaOutDTO = dictList2.get(0);
//把会商诊断表组装成Map
HashMap<String, Object> map = iCrmCCustlibPrimaryService.createConDiaInfoMap(custlibPrimaryConDiaOutDTO);
//excel模板路径
InputStream templateFileName = this.getClass().getClassLoader().getResourceAsStream("template/consultationDiagnosis.xlsx");
//调用Excel工具类导出功能
excelUtils.exportExcel(response, map, "ConDiaExcel", templateFileName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.Excel工具类导出
在网上找到的Excel Util工具类跟我的情况有点区别,所以自己写了一个工具类,这里可以适当参考;另外如果对表格的字体或者格式有特殊要求可以在前端处理,比如给导出的表格命名。
代码如下(示例):
package com.icbc.tech.ccrm.common.auth.utils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* Excel工具类,用于导出复杂xlsx文件
* 2022-9-22
*/
@Component
@Scope("prototype")
@Slf4j
public class ExcelUtils {
/**
* 导出复杂表头的Excel
* @param response
* @param map 单组数据Map
* @param outFileName 导出的Excel名称
* @param templateFileName Excel模板的路径名称
* @throws Exception
*/
public static void exportExcel(HttpServletResponse response, Map<String,Object> map,
String outFileName, InputStream templateFileName ) throws Exception{
//告诉response下载的是excel文件
response.setContentType("application/vnd.ms-excel");
//告诉response使用utf-8编码格式
response.setCharacterEncoding("utf-8");
//.withTemplate(templateFileName)就是读取模板
//.write(ExcelUtil.getOutputStream(outFileName, response))是将数据写入文件,并交给response
ExcelWriter excelWriter = EasyExcel.write(ExcelUtils.getOutputStream(outFileName, response)).withTemplate(templateFileName).build();
//创建Sheet
//设置excel Sheet为第几张并设置名称
//.writerSheet(0,"第一个")中前面的参数为sheetNo,就是第几张sheet
//第二参数为sheet名称
//不写就是默认
WriteSheet writeSheet = EasyExcel.writerSheet().build();
//这里是将一些普通数据放到map中,方便填入,可以看getStringObjectMap()。
//map的String是对应的名称,Object就是数据了。
//将数据填入
excelWriter.fill(map, writeSheet);
//关闭
excelWriter.finish();
}
/**
* 这是ExcelUtil.getOutputStream
* 这里就是将文件下载交给了浏览器
* @return
*/
public static OutputStream getOutputStream(String Name, HttpServletResponse response) throws Exception {
//这里是对文件的重命名
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
String date = sdf.format(new Date());
String fileName = new String(Name.getBytes(), StandardCharsets.UTF_8.toString()) + date + ".xlsx";
// 这里文件名如果涉及中文一定要使用URL编码,否则会乱码
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
return response.getOutputStream();
}
}
3.实现效果
后端从数据库查询到的结果经过封装和Excel Util类的处理后,导出的表格即可实现内容的填充,我的测试结果如下:
总结
前端的代码比较简单,不用过多展示了,后端的实现类也是基本的代码编写,上面的实现难点在于数据库查询,由于我的项目涉及到的字段较多,关联的表和遇到值多对一的情况,最终写了几百行的查询语句,当然这些都是跟项目相关的东西,最重要的是参考实现思路。