最近在做一個基於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表格功能:
若有什么不明白的,可以評論留言,我會盡量解答。