原创/朱季谦
以前做一个基于React+antd前端框架的Excel导出功能,我主要在后端做了处理,这个功能完成后,便总结成一篇技术分享文章,感兴趣的小伙伴可以参考该分享来做导出excle表格功能,以下步骤同样适用于vue框架,或者JSP页面的实现。
在做这类导出文件的功能,其实,在后端进行处理,会更容易些,虽然前端也可以进行处理,但还是建议后端来做,因为很多导出工具类基本都是很好用。
根据以下步骤,可以很容易就实现导出Excel表格数据的功能。
1.导出图标
按钮代码:
<Buttontype="primary"onClick={this.excelPort} >导出</Button>
2.按钮this.excelToPort的方法:
excelPort= () => { location.href="/test/export.do"}
3.建立Excel的Entity类(以下类可以直接复制用,无需做修改):
Excel Bean
packagecom.test; importlombok.Getter; importlombok.Setter; importorg.apache.poi.xssf.usermodel.XSSFCellStyle; @Getter@SetterpublicclassExcelBean { privateStringheadTextName; //列头(标题)名privateStringpropertyName; //对应字段名privateIntegercols; //合并单元格数privateXSSFCellStylecellStyle; publicExcelBean(StringheadTextName, StringpropertyName, Integercols) { super(); this.headTextName=headTextName; this.propertyName=propertyName; this.cols=cols; } }
映射到数据库里的User Bean
packagecom.bqs.data.dcm.bean; importlombok.Getter; importlombok.Setter; @Getter@SetterpublicclassUser { privateStringid; privateStringname; privateIntegerage; privateStringsex; }
4.建立Excel的工具类(无需修改可直接复制用)
1packagecom.test; 23importjava.beans.IntrospectionException; 4importjava.lang.reflect.InvocationTargetException; 5importjava.text.SimpleDateFormat; 6importjava.util.ArrayList; 7importjava.util.Date; 8importjava.util.List; 9importjava.util.Map; 1011importcom.test.ExcelBean; 12importorg.apache.poi.ss.util.CellRangeAddress; 13importorg.apache.poi.xssf.usermodel.XSSFCell; 14importorg.apache.poi.xssf.usermodel.XSSFCellStyle; 15importorg.apache.poi.xssf.usermodel.XSSFFont; 16importorg.apache.poi.xssf.usermodel.XSSFRow; 17importorg.apache.poi.xssf.usermodel.XSSFSheet; 18importorg.apache.poi.xssf.usermodel.XSSFWorkbook; 1920/** 21 * @author 朱季谦 22 * @version 23 */24publicclassExportUtil { 2526/** 27 * 导出Excel表 28 * @param clazz 数据源model类型 29 * @param objs excel标题以及对应的model字段 30 * @param map 标题行数以及cell字体样式 31 * @param sheetName 工作簿名称 32 * @return 33 * 34 */35publicstaticXSSFWorkbookcreateExcelFile( 36Class<?>clazz, 37List<Map<String,Object>>objs, 38Map<Integer,List<ExcelBean>>map, 39StringsheetName) throwsIllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException{ 40//创建新的工作簿41XSSFWorkbookworkbook=newXSSFWorkbook(); 42//创建工作表43XSSFSheetsheet=workbook.createSheet(sheetName); 44//设置excel的字体样式以及标题与内容的创建45createFont(workbook);//字体样式46createTableHeader(sheet,map);//创建标题47createTableRows(sheet,map,objs,clazz);//创建内容48System.out.println(workbook); 49returnworkbook; 50 } 51privatestaticXSSFCellStylefontStyle; 52privatestaticXSSFCellStylefontStyle2; 53privatestaticvoidcreateFont(XSSFWorkbookworkbook) { 54//表头55fontStyle=workbook.createCellStyle(); 56XSSFFontfont1=workbook.createFont(); 57font1.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD); 58font1.setFontName("黑体"); 59font1.setFontHeightInPoints((short) 12);//字体大小60fontStyle.setFont(font1); 61fontStyle.setBorderBottom(XSSFCellStyle.BORDER_THIN);//下边框62fontStyle.setBorderLeft(XSSFCellStyle.BORDER_THIN);//左边框63fontStyle.setBorderTop(XSSFCellStyle.BORDER_THIN);//右边框64fontStyle.setBorderRight(XSSFCellStyle.BORDER_THIN);//右边框65fontStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);//居中66//内容67fontStyle2=workbook.createCellStyle(); 68XSSFFontfont2=workbook.createFont(); 69font2.setFontName("宋体"); 70font2.setFontHeightInPoints((short)10); 71fontStyle2.setFont(font2); 72fontStyle2.setBorderBottom(XSSFCellStyle.BORDER_THIN);//下边框73fontStyle2.setBorderLeft(XSSFCellStyle.BORDER_THIN);//左边框74fontStyle2.setBorderTop(XSSFCellStyle.BORDER_THIN);//右边框75fontStyle2.setBorderRight(XSSFCellStyle.BORDER_THIN);//右边框76fontStyle2.setAlignment(XSSFCellStyle.ALIGN_CENTER);//居中77 } 78798081/** 82 * 根据ExcelMapping 生成列头(多行列头) 83 * @param sheet 工作簿 84 * @param map 每行每个单元格对应的列头信息 85 */86privatestaticvoidcreateTableHeader( 87XSSFSheetsheet, 88Map<Integer, List<ExcelBean>>map) { 89intstartIndex=0;//cell起始位置90intendIndex=0;//cell终止位置91for(Map.Entry<Integer,List<ExcelBean>>entry: map.entrySet()){ 92XSSFRowrow=sheet.createRow(entry.getKey()); //创建行93List<ExcelBean>excels=entry.getValue(); 94for(intx=0;x<excels.size();x++){ 95//合并单元格96if(excels.get(x).getCols()>1){ 97if(x==0){ 98endIndex+=excels.get(x).getCols()-1; 99//合并单元格CellRangeAddress构造参数依次表示起始行,截至行,起始列, 截至列100sheet.addMergedRegion(newCellRangeAddress(0, 0, startIndex, endIndex)); 101startIndex+=excels.get(x).getCols(); 102 }else{ 103endIndex+=excels.get(x).getCols(); 104sheet.addMergedRegion(newCellRangeAddress(0, 0, startIndex, endIndex)); 105startIndex+=excels.get(x).getCols(); 106 } 107XSSFCellcell=row.createCell(startIndex-excels.get(x).getCols()); 108//设置内容109cell.setCellValue(excels.get(x).getHeadTextName()); 110if(excels.get(x).getCellStyle() !=null){ 111//设置格式112cell.setCellStyle(excels.get(x).getCellStyle()); 113 } 114cell.setCellStyle(fontStyle); 115 }else{ 116XSSFCellcell=row.createCell(x); 117//设置内容118cell.setCellValue(excels.get(x).getHeadTextName()); 119if(excels.get(x).getCellStyle() !=null){ 120//设置格式121cell.setCellStyle(excels.get(x).getCellStyle()); 122 } 123cell.setCellStyle(fontStyle); 124 } 125 } 126 } 127 } 128129130/**131 * 为excel表中循环添加数据132 * @param sheet133 * @param map 字段名134 * @param objs 查询的数据135 * @param clazz 无用136 */137privatestaticvoidcreateTableRows( 138XSSFSheetsheet, 139Map<Integer,List<ExcelBean>>map, 140List<Map<String,Object>>objs, 141Class<?>clazz) 142throwsIntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 143introwindex=map.size(); 144intmaxkey=0; 145List<ExcelBean>ems=newArrayList<>(); 146for(Map.Entry<Integer,List<ExcelBean>>entry : map.entrySet()){ 147if(entry.getKey() >maxkey){ 148maxkey=entry.getKey(); 149 } 150 } 151ems=map.get(maxkey); 152List<Integer>widths=newArrayList<Integer>(ems.size()); 153for(Map<String,Object>obj : objs){ 154XSSFRowrow=sheet.createRow(rowindex); 155for(inti=0;i<ems.size();i++){ 156ExcelBeanem= (ExcelBean)ems.get(i); 157StringpropertyName=em.getPropertyName(); 158Objectvalue=obj.get(propertyName); 159XSSFCellcell=row.createCell(i); 160StringcellValue=""; 161if("valid".equals(propertyName)){ 162cellValue=value.equals(1)?"启用":"禁用"; 163 }elseif(value==null){ 164cellValue=""; 165 }elseif(valueinstanceofDate){ 166cellValue=newSimpleDateFormat("yyyy-MM-dd").format(value); 167 }else{ 168cellValue=value.toString(); 169 } 170cell.setCellValue(cellValue); 171cell.setCellType(XSSFCell.CELL_TYPE_STRING); 172cell.setCellStyle(fontStyle2); 173sheet.autoSizeColumn(i); 174 } 175rowindex++; 176 } 177178//设置列宽179for(intindex=0;index<widths.size();index++){ 180Integerwidth=widths.get(index); 181width=width<2500?2500:width+300; 182width=width>10000?10000+300:width+300; 183sheet.setColumnWidth(index, width); 184 } 185 } 186 }
5.导出Excel的controller类
/** * 导出excle表格 */@RequestMapping(value="/export") publicvoidexportTotal( HttpServletResponseresponse ) throwsException{ response.reset(); //清除buffer缓存//Map<String,Object> map=new HashMap<String,Object>();// 指定下载的文件名response.setContentType("application/vnd.ms-excel;charset=UTF-8"); StringexcleName="统计表格"+".xlsx"; response.setHeader("Content-Disposition","attachment;filename="+newString(excleName.getBytes(),"iso-8859-1")); //导出Excel对象XSSFWorkbookworkbook=sysExportExcelInfo.exportExcel(); OutputStreamoutput; try { output=response.getOutputStream(); BufferedOutputStreambufferedOutput=newBufferedOutputStream(output); bufferedOutput.flush(); workbook.write(bufferedOutput); bufferedOutput.close(); } catch (IOExceptione) { e.printStackTrace(); } }
6.导出Excel的service类
publicXSSFWorkbookexportExcel() throwsException{ //获取dao导出的list集合List<User>list=userService.exportUser(); List<Map<String,Object>>listMap=ListBeanToListMap(list); List<ExcelBean>excel=newArrayList<>(); Map<Integer,List<ExcelBean>>map=newLinkedHashMap<>(); //设置标题栏excel.add(newExcelBean("序号","id",0)); excel.add(newExcelBean("名字","name",0)); excel.add(newExcelBean("年龄","age",0)); map.put(0,excel); StringsheetName="统计表格"; //调用ExcelUtil方法XSSFWorkbookxssfWorkbook=ExportUtil.createExcelFile(DcmDemand.class, listMap, map, sheetName); System.out.println(xssfWorkbook); returnxssfWorkbook; }
注意:整块导出Excel代码,主要需要改动只是这一行代码:List<User> list=userService.exportUser(),这是调用dao层获取以列表list获得数据的查询。
下面三行代码里的“序号”,“名字”,“年龄”根据User属性来定义的,它将作为表格表头呈现在导出的表格里。这里的User表映射到数据库表t_user表,你需要导出User里哪些字段的数据,就以这样格式excel.add(new ExcelBean("序号","id",0))加到下面代码里:
excel.add(newExcelBean("序号","id",0)); excel.add(newExcelBean("名字","name",0)); excel.add(newExcelBean("年龄","age",0));
其中,以上代码需要把list<String>转换成List<Map<String,Object>>形式,转换方法如下,因为创建表格时需要这样List<Map<String,Object>>格式类型数据:
publicstaticList<Map<String, Object>>ListBeanToListMap(List<User>list) throwsNoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { List<Map<String, Object>>listmap=newArrayList<Map<String, Object>>(); for (Objectob : list) { listmap.add(beanToMap(ob)); } returnlistmap; }
按照以上代码步骤,可以实现在React+antd前端实现导出这样的Excel表格功能:
若有什么不明白的,可以评论留言,我会尽量解答。