對於Excel而言,Spring MVC所推薦的是使用AbstractXlsView,它實現了視圖接口,從其命名也可以知道它只是一個抽象類,不能生成實例對象。它自己定義了一個抽象方法——buildExcelDocument要去實現。其他的方法Spring的AbstractXlsView已經實現了,所以對於我們而言完成這個方法便可以使用Excel的視圖功能了
buildExcelDocument方法的主要任務是創建一個Workbook,它要用到POI的API,這需要我們自行下載並導入項目中。這里的參數在代碼中也給出了,在Spring MVC中已經對導出Excel進行了很多的封裝,所以很多細節我們並不需要關心。
<!-- poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency>
假設需要一個導出所有角色信息的功能,但是將來也許還有其他的導出功能。為了方便,先定義一個接口,這個接口主要是讓開發者自定義生成Excel的規則,如代碼清單15-46所示。
代碼清單15-46:自定義導出接口定義
package com.ssm.chapter15.view; import org.apache.poi.ss.usermodel.Workbook; import java.util.Map; public interface ExcelExportService { /*** * 生成exel文件規則 * @param model 數據模型 * @param workbook excel workbook */ public void makeWorkBook(Map<String, Object> model, Workbook workbook); }
有了這個接口還需要完成一個可實例化的Excel視圖類——ExcelView,對於導出而言還需要一個下載文件名稱,所以還會定義一個文件名(fileName)屬性,由於該視圖不是一個邏輯視圖,所以無須視圖解析器也可以運行它,其定義如代碼清單15-47所示。
代碼清單15-47:定義Excel視圖
package com.ssm.chapter15.view; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.util.StringUtils; import org.springframework.web.servlet.view.document.AbstractXlsView; public class ExcelView extends AbstractXlsView { //文件名 private String fileName = null; //導出視圖自定義接口 private ExcelExportService excelExpService = null; //構造方法1 public ExcelView(ExcelExportService excelExpService) { this.excelExpService = excelExpService; } //構造方法2 public ExcelView(String viewName, ExcelExportService excelExpService) { this.setBeanName(viewName); } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public ExcelExportService getExcelExpService() { return excelExpService; } public void setExcelExpService(ExcelExportService excelExpService) { this.excelExpService = excelExpService; } @Override protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { //沒有自定義接口 if (excelExpService == null) { throw new RuntimeException("導出服務接口不能為null!!"); } // 文件名不為空,為空則使用請求路徑中的字符串作為文件名 if (!StringUtils.isEmpty(fileName)) { //進行字符轉換 String reqCharset = request.getCharacterEncoding(); reqCharset = reqCharset == null ? "UTF-8" : reqCharset; fileName = new String(fileName.getBytes(reqCharset), "ISO8859-1"); // 設置下面文件名 response.setHeader("Content-disposition", "attachment;filename=" + fileName); } // 回調接口方法,使用自定義生成Excel文檔 excelExpService.makeWorkBook(model, workbook); } }
上面的代碼實現了生成Excel的buildExcelDocument方法,這樣就完成了一個視圖類。回調了自定義的接口方法可以根據需要進行自定義生成Excel的規則,接着我們需要在角色控制器中加入新的方法,來滿足導出所有角色的要求,如代碼清單15-48所示。
代碼清單15-48:使用ExcelView導出Excel
package com.ssm.chapter15.controller; import com.ssm.chapter15.pojo.PageParams; import com.ssm.chapter15.pojo.Role; import com.ssm.chapter15.pojo.RoleParams; import com.ssm.chapter15.view.ExcelExportService; import com.ssm.chapter15.view.ExcelView; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import java.util.ArrayList; import java.util.List; import java.util.Map; @Controller @RequestMapping("/excel") public class ExcelController { @RequestMapping(value = "/export", method = RequestMethod.GET) public ModelAndView export() { //模型和視圖 ModelAndView mv = new ModelAndView(); // Excel視圖,並設置自定義導出接口 ExcelView ev = new ExcelView(exportService()); //文件名 ev.setFileName("所有角色.xlsx"); // // 設置SQL后台參數 // RoleParams roleParams = new RoleParams(); // // 限制1萬條 // PageParams page = new PageParams(); // page.setStart(0); // page.setLimit(10000); // roleParams.setPageParams(page); // 查詢 // List<Role> roleList = roleService.findRoles(roleParams); List<Role> roleList = new ArrayList<>(); roleList.add(new Role(1l, "射手", "遠程物理輸出")); roleList.add(new Role(2l, "法師", "魔法輸出")); // 加入數據模型 mv.addObject("roleList", roleList); mv.setView(ev); return mv; } @SuppressWarnings({"unchecked"}) private ExcelExportService exportService() { // 使用Lambda表達式自定義導出excel規則 return (Map<String, Object> model, Workbook workbook) -> { // 獲取用戶列表 List<Role> roleList = (List<Role>) model.get("roleList"); // 生成Sheet Sheet sheet = workbook.createSheet("所有角色"); // 加載標題 Row title = sheet.createRow(0); title.createCell(0).setCellValue("編號"); title.createCell(1).setCellValue("名稱"); title.createCell(2).setCellValue("備注"); //便利角色列表,生成一行行的數據 for (int i = 0; i < roleList.size(); i++) { Role role = roleList.get(i); int rowIdx = i + 1; Row row = sheet.createRow(rowIdx); row.createCell(0).setCellValue(role.getId()); row.createCell(1).setCellValue(role.getRoleName()); row.createCell(2).setCellValue(role.getNote()); } }; } }
這樣就能夠導出Excel了,ExcelExportService接口的實現使用了Lambda表達式,因此Java版本是8及以上,Java 8以下的版本可以使用匿名類的方法去實現它。這里使用了ExcelExportService接口,就可以在自己的控制器上自定義導出規則,這樣就可以根據需要開發了。