本文主要是记录一下最近写前后台导出excel花费的一些心得。
前台: 通过一个同步的请求,同步等待数据,拿到数据以后,构建blob( new Blob)下载excel
后台:利用java pio读取Excel,配合java反射,写了一个万能的excel导出模板,只要设置表头一个数组,和你的数据模型(可能会有潜在bug,但是目前使用正常)
主要是为了大家以后避免一些坑,拿来即用
贴上前后台代码 ,代码里面很详细
先贴前台
点击按钮
前台请求后台方法
export function downloadExcel(pageNum, pageSize, groupName, iterVersion, searchKey, pageInfoKey, personInfoKey, microServices) {
return request({
url: '/excel/download',
responseType: 'blob', //这里需注意,以前写ajax请求老是习惯性的写成返回json,这里是不行的必须blob
method: 'get',
params: {
pageNum,
pageSize,
groupName,
iterVersion,
searchKey,
pageInfoKey,
personInfoKey,
microServices
},
data: {
}
})
}
// 点击按钮调用的方法 导出数据 - 调用接口函数
async exportExcel() {
const queryParam = {
...this.interfaceQueryInfo,
...this.pageInfo
}
// 请求后台获取数据
var res = await downloadExcel(queryParam.pageNum, queryParam.pageSize, queryParam.groupName, queryParam.iterInfo, queryParam.searchKey.trim(), queryParam.pageInfoKey, queryParam.personInfoKey, queryParam.microServices)
this.downloads(res)
},
// 拿到数据以后 通过 new Blob对象 创建excel
downloads(response) {
if (!response) {
return
}
const date = new Date()
const time = moment(date).format('YYYYMMDDHHmmss')
const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' })
const downloadElement = document.createElement('a')
const href = window.URL.createObjectURL(blob)
downloadElement.href = href
downloadElement.download = time + 'UNB接口.xlsx'
document.body.appendChild(downloadElement)
downloadElement.click()
document.body.removeChild(downloadElement) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
},
后台代码: 里面注释很详细
使用的话 该一下表头 然后把你的数据模型变一下即可
org.apache.poi poi 3.14
package com.huawei.solution.controller; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; import com.huawei.solution.dao.EnvProjectAuthDao; import com.huawei.solution.model.Env; import com.huawei.solution.services.InterfacesService; import com.huawei.solution.utils.ResultUtil; import com.huawei.solution.utils.page.PageData; import com.huawei.solution.utils.page.PageParams; import com.huawei.solution.vo.InterfacesVO; import lombok.extern.slf4j.Slf4j; import org.apache.poi.xssf.usermodel.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; /** * @ClassNme UserGroupController * @Author x84104122 * @Date 2018/11/16 15:53 * @Description 配合poi 和 通过java底层反射读取构建万能的excel模板 */ @RestController @RequestMapping("/excel") @Slf4j public class ExcelController { @Autowired private InterfacesService interfacesService; @RequestMapping("/download") public Object downloadExcel(HttpServletResponse response, Integer pageNum, Integer pageSize, String groupName, String iterVersion, String microServices, String searchKey, String pageInfoKey, String personInfoKey) throws IOException { SimpleDateFormat dateFormat = new SimpleDateFormat("YYYYMMDDhhmmss"); String now = dateFormat.format(new Date()); String exportFileName = "UNB_接口" + now + ".xlsx"; String[] headers = {"接口id", "接口url", "所属服务", "接口请求body", "小组名字", "接口返回body", "参数请求描述ID", "接口返回描述ID", "创建者id", "创建者员工编号", "接口所属的组", "接口前后台责任人", "所属页面", "接口描述", "属于的迭代版本", "接口的Servicekey", "http的请求方法", "接口状态(0表示正在开发1表示开发完成)", "接口最近一次修改人员工编号", "接口最近一次修改时间", "接口创建时间", "请求参数描述", "返回数据描述参数"};//导出的Excel头部,这个要根据自己项目改一下 PageDatainterfacesVOPageData = interfacesService.filterQuery(groupName, iterVersion, microServices, PageParams.build(pageSize, pageNum), searchKey, pageInfoKey, personInfoKey); //下面的完全不动就行了(Excel数据中不包含图片) // 声明一个工作薄 XSSFWorkbook workbook = new XSSFWorkbook(); // 生成一个表格 XSSFSheet sheet = workbook.createSheet(); // 设置表格默认列宽度为15个字节 // sheet.setDefaultColumnWidth((short) 18); for (int i = 0; i < headers.length; i++) { int colWidth = sheet.getColumnWidth(i) * 2; if (colWidth < 255 * 256) { sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth); } else { sheet.setColumnWidth(i, 6000); } } XSSFRow row = sheet.createRow(0); for (short i = 0; i < headers.length; i++) { XSSFCell cell = row.createCell(i); XSSFRichTextString text = new XSSFRichTextString(headers[i]); cell.setCellValue(text); } //遍历集合数据,产生数据行 Iterator it = interfacesVOPageData.getList().iterator(); int index = 0; while (it.hasNext()) { index++; row = sheet.createRow(index); InterfacesVO objectValue = (InterfacesVO) it.next(); //利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值 Field[] fields = objectValue.getClass().getDeclaredFields(); for (short i = 0; i < fields.length; i++) { // 这里遍历fields 每个属性 XSSFCell cell = row.createCell(i); Field field = fields[i]; String fieldName = field.getName(); String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); // 提取getName() 这样方法 try { Class tCls = objectValue.getClass(); Method getMethod = tCls.getMethod(getMethodName, new Class[]{}); Object value = getMethod.invoke(objectValue, new Object[]{}); // 通过底层invoke 开启bug拿到值 String textValue = null; // 对于日期的值 转为日期 非日期的值当做字符串处理 if (value instanceof Date) { Date date = (Date) value; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); textValue = sdf.format(date); } else { //其它数据类型都当作字符串简单处理 if (value == null) { textValue = ""; } else { textValue = value.toString(); } } // XSSFRichTextString richString = new XSSFRichTextString(textValue); // XSSFFont font3 = workbook.createFont(); // font3.setColor(HSSFColor.BLUE.index);//定义Excel数据颜色 // richString.applyFont(font3); cell.setCellValue(textValue); } catch (Exception e) { e.printStackTrace(); } } } response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.ms-excel;charset=utf-8");// 设置contentType为excel格式 response.setHeader("Content-disposition", "attachment;filename=" + exportFileName);//默认Excel名称 response.flushBuffer(); workbook.write(response.getOutputStream()); return ResultUtil.success(); } }