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