1. 程式人生 > >實際專案中使用poi匯出excel(spring+springMVC+Mybatis環境下)

實際專案中使用poi匯出excel(spring+springMVC+Mybatis環境下)

1,需要匯出的原始資料.即根據實際需求查詢得到的結果集作為原始資料.可能是一個list,map...看你封裝成什麼樣了(這裡是封裝成list了)

2,將原始的資料轉換到excel中,具體根據資料形式不同,寫法也會不同.不過這些都是大同小異的.

3,將生產好的excel檔案寫到一個路徑下(這裡都是放到tomcat伺服器目錄下的download下).

4,根據上一步的路徑找到excel檔案進行下載操作(就是檔案下載...網上一大片)

下面看各個層的程式碼,以及excel工具類.具體步驟,程式碼中註釋已經寫到很明白了.

Controller層程式碼:

/**
     * 匯出新聞方案
     * @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);
    }
service層程式碼:

這裡需要說明下:步驟大體是這麼搞,但是樣式需要根據不同需求來設定,其中的邏輯也會不一樣的.此處匯出的樣式如下圖:

程式碼如下:

/**
     * 方法描述:生產方案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;
    }
excel的工具類:(等讀者熟悉了,自己寫自己合適的工具類這裡多有東西只是起到指引作用).
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,還望多多包涵.希望會給剛入門的同學一點點啟示作用.謝謝