實際專案中使用poi匯出excel(spring+springMVC+Mybatis環境下)
阿新 • • 發佈:2018-12-27
1,需要匯出的原始資料.即根據實際需求查詢得到的結果集作為原始資料.可能是一個list,map...看你封裝成什麼樣了(這裡是封裝成list了)
2,將原始的資料轉換到excel中,具體根據資料形式不同,寫法也會不同.不過這些都是大同小異的.
3,將生產好的excel檔案寫到一個路徑下(這裡都是放到tomcat伺服器目錄下的download下).
4,根據上一步的路徑找到excel檔案進行下載操作(就是檔案下載...網上一大片)
下面看各個層的程式碼,以及excel工具類.具體步驟,程式碼中註釋已經寫到很明白了.
Controller層程式碼:
service層程式碼:/** * 匯出新聞方案 * @param Integer[] newsScheme方案id陣列 * @throws Exception */ @RequestMapping(value = "newsSchemes/export/{newsSchemesId}",method = RequestMethod.POST) public void exportNewsScheme(@PathVariable("newsSchemesId") Integer newsSchemesId) throws Exception{ System.err.println("匯出的方案的id:"+newsSchemesId); //切換到rsdb資料庫 DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSDB); //查詢的結果集,list為需要在表格中展示的資料 List<NewsMediaCategory> list = this.newsMediaCategoryService.listNewsMediaCateBySid(new NewsMediaCategory(newsSchemesId)); //迴圈將自定義媒體對應的新聞源集合存入到list中. if(list != null && list.size()>0){ for(int i=0;i<list.size();i++){ //切換到rsdb資料庫 DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSDB); //獲取site_id陣列 Integer[] sIds = this.newsMediaCategoryService.listSidsByNewsMediaCateId(list.get(i).getId()); //切換到RSNews資料庫 DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSNEWS); List<Site> siteList = this.siteService.listBySids(new Site(sIds)); //List<Site> site = this.siteMapper.listBySids(null) list.get(i).setSiteList(siteList); list.get(i).setSids(sIds); } } for(NewsMediaCategory nmc : list){ System.err.println(nmc.getName()+"--------"+nmc.getSiteList().size()); } //切換到rsdb資料庫 DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSDB); //根據方案id查詢方案基本資訊,主要是為了獲取匯出時候的預設名為(當前方案名+時間戳) NewsSchemes newsScheme = this.newsSchemesService.selNewsSchemesBySchemesId(newsSchemesId); //獲取欲下載的檔案路徑 String filePath =this.newsSchemesService.createNewSchemesExcel(newsScheme,list,this.request); //執行下載操作 ExcelUtils.download(filePath , this.request , this.response); }
這裡需要說明下:步驟大體是這麼搞,但是樣式需要根據不同需求來設定,其中的邏輯也會不一樣的.此處匯出的樣式如下圖:
程式碼如下:
excel的工具類:(等讀者熟悉了,自己寫自己合適的工具類這裡多有東西只是起到指引作用)./** * 方法描述:生產方案excel檔案,並寫到指定位置.將該檔案的絕對路徑返回<br> * 返回型別:String<br> * 作者:GQ<br> * 建立時間:2016年12月30日14:41:52<br> * @param request request請求<br> * @param newsSchemeId 新聞方案id<br> * @param list NewsMediaCategory集合<br> */ @Override public String createNewSchemesExcel(NewsSchemes newsScheme,List<NewsMediaCategory> list,HttpServletRequest request) { // 第一步,建立一個workbook,對應一個Excel檔案 HSSFWorkbook wb = new HSSFWorkbook(); // 第二步,在workbook中新增一個sheet,對應Excel檔案中的sheet HSSFSheet sheet = wb.createSheet("新聞方案表"); //獲取單元格格式的樣式,一些基本屬性 HSSFCellStyle cellStyle = ExcelUtils.getCellStyle(wb); //獲取標題格式 HSSFCellStyle titleStyle = ExcelUtils.getTitleStyle(wb); //建立表頭.第一行.第一列的資料 ExcelUtils.createCell(sheet, 0, 0, titleStyle, "方案具體資訊表"); //合併單元格CellRangeAddress構造引數依次表示起始行,截至行,起始列, 截至列 ExcelUtils.mergedRegion(sheet , 0 , 0 , 0 , 2); //第二行,弟1,2,3列對應的數值,建立行"自定義媒體名稱,備註資訊,包含站點源個數". ExcelUtils.createMultiCell(sheet , 1 , new Integer[]{0,1,2} , cellStyle , new String[]{"自定義媒體名稱","備註資訊","包含站點源個數"}); //記錄第一個總資訊表真實資料行數,真實資料新增的起始行應該是(rCounts-1)為真是資料起始行. int rCounts=3; //將真實資料插入到excel表中去. for (int r = 0; r < list.size(); r++) { //獲取真實資料 NewsMediaCategory nmc = list.get(r); //每次填充同一行的,前三個單元格.呼叫同時填充(同一行的多個單元格的方法). ExcelUtils.createMultiCell(sheet , r+2 , new Integer[]{0,1,2} , cellStyle , new String[]{nmc.getName(),nmc.getRemark(),String.valueOf(nmc.getSiteList().size())}); //每次加1,為了得到下一個表的表頭位置. rCounts++; } //設定分割那一行,將他創建出來,但是不賦值任何資料,用於匯入時候的區分點. ExcelUtils.createRow(sheet , rCounts-1); //System.err.println("rowNullde的單元格個數:"+rowNull.getPhysicalNumberOfCells()); //設定'自定義媒體型別具體資訊表',表頭 ExcelUtils.createCell(sheet, rCounts, 0, titleStyle, "自定義媒體型別具體資訊表"); //累計,判斷合併時候用.確定每一個單元格 int m=0; for (int r = 0; r < list.size(); r++) { //迴圈控制有幾個媒體型別 NewsMediaCategory nmc = list.get(r); //合併自定義媒體名稱那一行,m控制合併的起止位置. ExcelUtils.mergedRegion(sheet , rCounts+1 , rCounts+1 , m , m+2); //設定自定義媒體名稱那一行,每一個單元格名稱. ExcelUtils.createMultiCell(sheet , rCounts+1 , new Integer[]{m,m+1,m+2} , cellStyle , new String[]{nmc.getName(),"",""}); //迴圈出媒體名稱下面的哪一行,"新聞源id,新聞源站點名稱,url" ExcelUtils.createMultiCell(sheet , rCounts+2 , new Integer[]{m,m+1,m+2} , cellStyle , new String[]{"新聞源id","新聞源站點名稱","url"}); //填充,每一個自定義媒體型別下,所擁有的新聞源具體資訊.. for(int i=0;i<nmc.getSiteList().size();i++){ //迴圈媒體型別對應的新聞源id陣列 Site s = nmc.getSiteList().get(i); //迴圈出具體新聞源id,站點名稱,url的資料庫具體資訊 ExcelUtils.createMultiCell(sheet , rCounts+3+i , new Integer[]{m,m+1,m+2} , cellStyle , new String[]{String.valueOf(s.getSite_ID()),s.getSite_Des(),s.getSite_URL()}); } m=m+3; } //合併'自定義媒體型別具體資訊表'行,根據自定義媒體型別個數決定的. ExcelUtils.mergedRegion(sheet , rCounts , rCounts , 0 , m-1); //控制列數 for(int i=0;i<m;i++){ //設定自動使用寬度 //這裡寫死,10箇中文字元 sheet.setColumnWidth(i,10 * 512); } //(匯出的預設檔名為當前匯出方案名+時間戳) String fileName=newsScheme.getName()+DateUtil.createTimeStemp(new Date()) + ".xls"; //獲取匯出的路徑.就是將檔案匯出到哪個資料夾下.(級別到資料夾) String filePath = request.getSession().getServletContext().getRealPath("/")+"WEB-INF/download"; //將檔案存到指定位置,實際就是將生產好的excel檔案寫到某個位置,為了下一步下載. ExcelUtils.writeExcelToLocation(wb , filePath + "/" + fileName); //返回檔案生成後儲存的絕對路徑.即為路徑+檔名稱. return filePath + "/" + fileName; }
前臺需要注意:package com.rs.sys.utils; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import org.springframework.web.multipart.MultipartFile; /** * <b>處理excel檔案的工具類</b> * @author GQ * @date 2016年12月27日 上午10:39:56 * @status */ public class ExcelUtils { /** * 方法描述:用於下載檔案,根據存在的檔案絕對路徑下載.<br> * 返回型別:void<br> * 作者:GQ<br> * 建立時間:2016年12月27日上午10:51:17 * @param filePath 欲下載的檔案絕對路徑.<br>如:"F:\apache-tomcat-7.0.70\webapps\Rs_sys\WEB-INF\download\xxx.xls" * @param request request請求 * @param response response請求<br> */ public static void download(String filePath,HttpServletRequest request,HttpServletResponse response){ HSSFWorkbook workbook=null; ServletOutputStream sos=null; try { File file = new File(filePath); if (!file.exists()) { response.sendError(404, "File not found!"); return; } BufferedInputStream br = new BufferedInputStream(new FileInputStream( filePath)); String downLoadName = null; String agent = request.getHeader("USER-AGENT"); if (null != agent && -1 != agent.indexOf("MSIE")) // IE { downLoadName = java.net.URLEncoder.encode(file.getName(), "UTF-8"); } else if (null != agent && -1 != agent.indexOf("Mozilla")) // Firefox { downLoadName = new String(file.getName().getBytes("UTF-8"), "iso-8859-1"); } else { downLoadName = java.net.URLEncoder.encode(file.getName(), "UTF-8"); } byte[] buf = new byte[1024]; int len = 0; response.reset(); response.setContentType("application/vnd.ms-excel;charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=" + downLoadName); OutputStream out = response.getOutputStream(); while ((len = br.read(buf)) > 0) { out.write(buf, 0, len); } br.close(); out.close(); }catch (Exception e) { e.printStackTrace(); }finally{ try { if (null != workbook) { workbook.close(); } if(null!=sos){ sos.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * 方法描述:獲取單元格中的資料,根據儲存的值的型別不同,呼叫相應的方法獲取資料,最後返回一個字串型別的資料<br> * 返回型別:String<br> * 作者:GQ<br> * 建立時間:2016年12月28日下午6:24:00 * @param cell 單元格 * @return<br> */ public static String getCellValue(Cell cell) { String cellValue = ""; //DecimalFormat df = new DecimalFormat("#"); switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_STRING: cellValue = cell.getRichStringCellValue().getString().trim(); break; case HSSFCell.CELL_TYPE_NUMERIC: cellValue = String.valueOf(new Integer((int)cell.getNumericCellValue())); break; case HSSFCell.CELL_TYPE_BOOLEAN: cellValue = String.valueOf(cell.getBooleanCellValue()).trim(); break; case HSSFCell.CELL_TYPE_FORMULA: cellValue = cell.getCellFormula(); break; default: cellValue = ""; } return cellValue; } /** * 方法描述:檔案寫入<br> * 返回型別:void<br> * 作者:GQ<br> * 建立時間:2016年12月30日下午1:41:24 * @param file 為獲得到的檔案(也就是要講這個檔案寫到哪裡) * @param filePath 檔案寫入的位置 * @param fileName<br> 檔案的名 */ public static void write(MultipartFile file,String filePath,String fileName){ //在指定目錄下建立一個空的檔案,作用:別的file檔案往裡寫入 File targetFile = new File(filePath, fileName); if(!targetFile.exists()){ targetFile.mkdirs(); } //儲存 try { //將前臺傳過來的file檔案寫到targetFile中. file.transferTo(targetFile); } catch (Exception e) { e.printStackTrace(); } } /** * 方法描述:建立行,rowNum控制建立第幾行.sheet控制在哪個工作簿上建立<br> * 返回型別:HSSFRow<br> * 作者:GQ<br> * 建立時間:2017年1月3日下午4:58:09 * @param sheet 工作簿 * @param rowNum 行數(下標從0開始) * @return<br> */ public static HSSFRow createRow(HSSFSheet sheet,int rowNum) { return sheet.getRow(rowNum)!=null?sheet.getRow(rowNum):sheet.createRow(rowNum); } /** * 方法描述:建立一個cell,樣式,值.<br> * 返回型別:void<br> * 作者:GQ<br> * 建立時間:2017年1月3日下午4:02:32<br> * @param cellnum 第幾個cell,下標從0開始,即0代表第一個<br> * @param value 該cell的值<br> * @param row 行<br> * @param style 樣式(採用哪個樣式)<br> */ public static HSSFCell createCell(HSSFSheet sheet, int rowNumm, int cellNum, HSSFCellStyle style, String value) { HSSFRow row = createRow(sheet,rowNumm); HSSFCell cell = row.createCell((short) cellNum); cell.setCellValue(new HSSFRichTextString(value)); cell.setCellStyle(style); return cell; } /** * 方法描述:建立多個單元格.必須是同一行的.並賦值上相應資料<br> * 返回型別:HSSFCell<br> * 作者:GQ<br> * 建立時間:2017年1月3日下午5:21:52 * @param sheet 工作簿 * @param rowNumm 行數 * @param cellNums 要建立的單元格下標陣列 * @param style 樣式 * @param values 單元格下標對應的值,一個對應一個,順序不能亂 */ public static List<HSSFCell> createMultiCell(HSSFSheet sheet, int rowNumm, Integer[] cellNums, HSSFCellStyle style, String[] values) { List<HSSFCell> cellList = new ArrayList<HSSFCell>(); for(int i=0;i<cellNums.length;i++){ HSSFCell cell = createCell(sheet , rowNumm , cellNums[i] , style , values[i]); cellList.add(cell); } return cellList; } /** * 方法描述:建立自定義cell單元格的基礎樣式.<br> * 返回型別:HSSFCellStyle<br> * 作者:GQ<br> * 建立時間:2017年1月3日下午4:04:02 * @param workbook */ public static HSSFCellStyle getCellStyle(HSSFWorkbook workbook) { /*//設定字型; HSSFFont font = workbook.createFont(); //設定字型大小; font.setFontHeightInPoints((short) 5); //設定字型名字; font.setFontName("Courier New");*/ //font.setItalic(true); //font.setStrikeout(true); //設定樣式; HSSFCellStyle style = workbook.createCellStyle(); //設定底邊框; style.setBorderBottom(HSSFCellStyle.BORDER_THIN); //設定底邊框顏色; style.setBottomBorderColor(HSSFColor.BLACK.index); //設定左邊框; style.setBorderLeft(HSSFCellStyle.BORDER_THIN); //設定左邊框顏色; style.setLeftBorderColor(HSSFColor.BLACK.index); //設定右邊框; style.setBorderRight(HSSFCellStyle.BORDER_THIN); //設定右邊框顏色; style.setRightBorderColor(HSSFColor.BLACK.index); //設定頂邊框; style.setBorderTop(HSSFCellStyle.BORDER_THIN); //設定頂邊框顏色; style.setTopBorderColor(HSSFColor.BLACK.index); //在樣式用應用設定的字型; //style.setFont(font); //設定自動換行; style.setWrapText(true); //設定水平對齊的樣式為居中對齊; style.setAlignment(HSSFCellStyle.ALIGN_CENTER); //設定垂直對齊的樣式為居中對齊; style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); return style; } /** * 方法描述:自定義設定標題樣式,只有下邊框<br> * 返回型別:HSSFCellStyle<br> * 作者:GQ<br> * 建立時間:2017年1月3日下午4:20:42<br> * @param workbook<br> */ public static HSSFCellStyle getTitleStyle(HSSFWorkbook workbook){ HSSFCellStyle style = workbook.createCellStyle(); style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 建立一個居中格式 // 設定標題只有下邊框 style.setBorderBottom(HSSFCellStyle.BORDER_THIN); return style; } /** * 方法描述:合併單元格<br> * 返回型別:int<br> * 作者:GQ<br> * 建立時間:2017年1月4日上午10:45:20<br> * @param sheet 工作簿<br> * @param firstRow 合併起止行(下標從0開始)<br> * @param lastRow 合併截止行(下標從0開始)<br> * @param firstCol 合併起止列(下標從0開始)<br> * @param lastCol 合併截止列(下標從0開始)<br> */ public static int mergedRegion(HSSFSheet sheet,int firstRow, int lastRow, int firstCol, int lastCol){ return sheet.addMergedRegion(new CellRangeAddress(firstRow,lastRow,firstCol,lastCol)); } /** * 方法描述:將生成好的excel檔案,寫入到指定路徑下的檔案中.<br> * 返回型別:void<br> * 作者:GQ<br> * 建立時間:2017年1月4日上午10:57:04<br> * @param wb 一個workbook,對應一個Excel檔案<br> * @param absolutePath excel檔案的絕對路徑<br> */ public static void writeExcelToLocation(HSSFWorkbook wb,String absolutePath){ try { FileOutputStream fout = new FileOutputStream(absolutePath); wb.write(fout); fout.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 方法描述:獲取workbook,將檔案轉換為workbook物件<br> * 返回型別:Workbook<br> * 作者:GQ<br> * 建立時間:2017年1月4日下午5:12:20<br> * @param absolutePath 檔案的絕對路徑(excel檔案)<br> * @return<br> */ public static Workbook getWorkBook(String absolutePath){ FileInputStream fis =null; Workbook wb = null; try{ // 獲取一個絕對地址的流 fis = new FileInputStream(absolutePath); wb = new HSSFWorkbook(fis); }catch(IOException e){ // TODO Auto-generated catch block e.printStackTrace(); } return wb; } }
用的是表單提交.程式碼如下:
<form id="news_scheme_manage_excel_export">
<input type="hidden" value=""></input>
</form>
js程式碼:
//返回被選中的行資料,沒有則返回空var rows = $('#news_scheme_manage').datagrid('getSelections');
if(rows!=null && rows.length==1){
var row = $('#news_scheme_manage').datagrid('getSelected');
//id用於查詢方案對應的型別
var id=row.id;
console.log("id:"+id);
//到彈出框中進行編輯
//類選擇器獲取表單.
var form = $( "#news_scheme_manage_excel_export" );
//設定表單中的相應屬性
//設定提交方式為post.
form.attr( "method", "post" );
//設定提交按鈕跳轉地址
form.attr( "action", "newsSchemes/export/"+id );
//若以上判斷返回非false則表單提交.
form.submit();
}else{ //選中多條或者沒有選則彈出提示資訊 $.messager.alert("提示資訊","有且只能選擇一條資料!","info"); }
特殊宣告:博主第一次寫,格式什麼的不要介意,只是自己的一個筆記,有些地方可能說的不是很明白,可能存在很多漏洞或者bug,還望多多包涵.希望會給剛入門的同學一點點啟示作用.謝謝