POI導入和導出到excel

使用到的依賴:

	<dependency>
		<groupId>org.apache.poi</groupId>
		<artifactId>poi</artifactId>
		<version>3.8</version>
	</dependency>
	<dependency>
		<groupId>org.apache.poi</groupId>
		<artifactId>poi-ooxml</artifactId>
		<version>3.8</version>
	</dependency>

版本自己控制。
兩種導出方式,HSSF和XSSF,其中HSSF是將數據一次性寫入到內存裏,再一次性寫出到excel,對於內存消耗比較大,數據量太大的話會導致內存溢出,但是效率比較快,最大值63556。
XSSF是讀一部分再寫一部分,再讀再寫,內存消耗會小一些,但是效率比HSSF慢。
使用的時候,HSSF加入poi的依賴就可以使用,而XSSF需要加上面兩個依賴。

HSSF只操作.xls文件(97–03版excel)一個sheet中行有限制,最大是65536(將數據一次性寫入內容,再寫出)

1、使用HSSF導出到excel

public class WirteExcelHSSFTest {
    public static void main(String[] args) throws Exception{
        //創建文件輸出流
        FileOutputStream out = new FileOutputStream("E:\\upload\\test.xls");
        //創建一個工作簿
        Workbook wb = new HSSFWorkbook();
        for(int j = 0; j< 10; j++){
            //創建sheet--工作表
            Sheet sheet = wb.createSheet();
            wb.setSheetName(j,"sheet"+ j);//指定sheet得名稱
            for(int rowNum = 0; rowNum < 65536; rowNum++){
                //創建一行
                Row row = sheet.createRow(rowNum);//創建第一行
                //一行創建10個單元格
                for(int cellNum = 0; cellNum < 10; cellNum++){
                    //在行裏創建單元格
                    Cell cell = row.createCell(cellNum);
                    //向單元格中寫入數據
                    cell.setCellValue(cellNum);
                }
            }
        }


        wb.write(out);//輸出文件內容

    }

}

2、使用XSSF導出數據到excel

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.io.FileOutputStream;
import java.io.IOException;

public class WriteEexceXSSFTest {
    public static void main(String[] args) throws Exception {
        //創建SXSSFworkBook(關閉自動刷新並在內存中積累所有的行)
        SXSSFWorkbook wb = new SXSSFWorkbook(-1);
        //創建一個sheet
        Sheet sheet = wb.createSheet();
        for(int rownum = 0; rownum < 100000;rownum++){
            //創建一行
            Row row = sheet.createRow(rownum);
            //創建單元格
            for(int cellNum = 0; cellNum < 10; cellNum++){
                Cell cell = row.createCell(cellNum);
                //單元格地址
                String address = new CellReference(cell).formatAsString();
                cell.setCellValue(address);
            }
            //達到一萬行後就向磁盤寫入一次
            if(rownum % 10000 == 0){
                //保留最後100行並沖洗所有的其他行
                ((SXSSFSheet)sheet).flushRows(100);
            }
        }
        FileOutputStream out = new FileOutputStream("E:\\upload\\test.xls");
        wb.write(out);//將臨時文件合併,寫入最終文件
        out.close();
    }
}

3、使用HSSF將excel數據插入到數據庫

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import java.io.FileInputStream;
import java.io.InputStream;

public class ReadExcelHSSF {
    public static void main(String[] args) throws Exception{
        ReadExcelHSSF readExcelHSSF = new ReadExcelHSSF();
        readExcelHSSF.readXls();
    }
    public void readXls() throws Exception{
        //文件輸入流
        InputStream is = new FileInputStream("E:/upload/test.xls");
        //創建workBook--工作簿
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is);
        //解析workbook的內容
        for(int numSheet = 0; numSheet < hssfWorkbook.getNumberOfSheets(); numSheet++){
            //得到workBook中某個sheet(序號是從0開始)
            HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(numSheet);
            if(hssfSheet == null){
                continue;
            }
            //遍歷循環row
            for(int rowNum = 1; rowNum <= hssfSheet.getLastRowNum();rowNum++){
                //讀取每一行數據,rowNum指定行下標從0開始
                HSSFRow hssfRow = hssfSheet.getRow(rowNum);
                //讀取單元格內容
                for(int cellNum= 0; cellNum <= hssfRow.getLastCellNum(); cellNum ++){
                    //讀取一行中的某個單元格的內容(cellNum指定單元格的下標,從0開始)
                    HSSFCell cell = hssfRow.getCell(cellNum);
                    if(cell == null){
                        continue;
                    }
                    //插入到數據庫,我這裏就不演示了,直接打印
                    System.out.println(cell.getStringCellValue());
                }
            }
        }
    }
}

4、使用XSSF將excel數據讀取到數據庫

import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.record.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ReadExcelXSSFTest implements HSSFListener {
    private SSTRecord sstrec;

    /**
     * This method listens for incoming records and handles them as required.
     *
     * @param record
     *            The record that was found while reading.
     */
    public void processRecord(Record record) {

        switch (record.getSid()) {
            // the BOFRecord can represent either the beginning of a sheet or the
            // workbook
            case BOFRecord.sid:
                BOFRecord bof = (BOFRecord) record;
                if (bof.getType() == bof.TYPE_WORKBOOK) {
                    System.out.println("Encountered workbook");
                    // assigned to the class level member
                } else if (bof.getType() == bof.TYPE_WORKSHEET) {
                    System.out.println("Encountered sheet reference");
                }
                break;
            case BoundSheetRecord.sid:
                BoundSheetRecord bsr = (BoundSheetRecord) record;
                System.out.println("New sheet named: " + bsr.getSheetname());
                break;
            case RowRecord.sid:
                RowRecord rowrec = (RowRecord) record;
                System.out.println("Row found, first column at "
                        + rowrec.getFirstCol() + " last column at "
                        + rowrec.getLastCol());
                break;
            case NumberRecord.sid:
                NumberRecord numrec = (NumberRecord) record;
                System.out.println("Cell found with value " + numrec.getValue()
                        + " at row " + numrec.getRow() + " and column "
                        + numrec.getColumn());
                break;
            // SSTRecords store a array of unique strings used in Excel.
            case SSTRecord.sid:
                sstrec = (SSTRecord) record;
                for (int k = 0; k < sstrec.getNumUniqueStrings(); k++) {
                    System.out.println("String table value " + k + " = "
                            + sstrec.getString(k));
                }
                break;
            case LabelSSTRecord.sid:
                LabelSSTRecord lrec = (LabelSSTRecord) record;
                System.out.println(lrec.getRow()+"String cell found with value "
                        + sstrec.getString(lrec.getSSTIndex()));
                break;
        }
    }

    /**
     * Read an excel file and spit out what we find.
     *
     * @param args
     *            Expect one argument that is the file to read.
     * @throws IOException
     *             When there is an error processing the file.
    官方例子讀取大數據量xls文件沒有內存溢出問題
     */
    public static void main(String[] args) throws IOException {
        // create a new file input stream with the input file specified
        // at the command line
        FileInputStream fin = new FileInputStream("E:\\upload\\test.xls");
        // create a new org.apache.poi.poifs.filesystem.Filesystem
        POIFSFileSystem poifs = new POIFSFileSystem(fin);
        // get the Workbook (excel part) stream in a InputStream
        InputStream din = poifs.createDocumentInputStream("Workbook");
        // construct out HSSFRequest object
        HSSFRequest req = new HSSFRequest();
        // lazy listen for ALL records with the listener shown above
        //添加一個事件驅動
        req.addListenerForAllRecords(new ReadExcelXSSFTest());
        // create our event factory
        HSSFEventFactory factory = new HSSFEventFactory();
        // process our events based on the document input stream
        factory.processEvents(req, din);
        // once all the events are processed close our file input stream
        fin.close();
        // and our document input stream (don't want to leak these!)
        din.close();
        System.out.println("done.");
    }
}

5、實戰中將poi封裝成一個工具類,項目中直接調用類中的方法,返回下載的鏈接地址:

import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.java.pojo.Ypxx;

/**
 * excel導出的封裝類
 */
public class ExcelExportSXXSSF {

	// 定義工作表
	private SXSSFWorkbook wb;

	/**
	 * 定義工作表中的sheet
	 */
	private Sheet sh;


	/**
	 * 定義保存在內存中的數量,-1表示手動控制
	 */
	private int flushRows;
	/** 導出文件行數 */
	private int rownum;
	/** 導出文件列數 */
	private int colnum;

	/** 導出文件的存放路徑 */
	private String filePath;
	/** 下載導出文件的路徑 */
	private String fileWebPath;
	/**文件名稱前綴*/
	private String filePrefix;
	/**導出文件全路徑*/
	private String fileAllPath;
	/** 導出文件列標題 */
	private List<String> fieldNames;
	/**導出文件每列代碼,用於反射獲取對象屬性值*/
	private List<String> fieldCodes;

	private ExcelExportSXXSSF() {

	}

	/**
	 * 開始導出方法
	 * 
	 * @param filePath
	 *            導出文件存放物理路徑
	 * @param fileWebPath
	 *            導出文件web下載路徑
	 * @param filePrefix
	 *            導出文件名的前綴          
	 * @param flushRows
	 *            存放在內存的數據量
	 * @param fieldNames
	 *            導出文件列標題
	 * @param fieldCodes
	 * 			  導出數據對象的字段名稱     
	 * @param flushRows
	 * 			寫磁盤控制參數
	 * @return
	 */
	public static ExcelExportSXXSSF start(String filePath, String fileWebPath,String filePrefix,
			List<String> fieldNames,List<String> fieldCodes, int flushRows) throws Exception {
		ExcelExportSXXSSF excelExportSXXSSF = new ExcelExportSXXSSF();
		excelExportSXXSSF.setFilePath(filePath);
		excelExportSXXSSF.setFileWebPath(fileWebPath);
		excelExportSXXSSF.setFilePrefix(filePrefix);
		excelExportSXXSSF.setFieldNames(fieldNames);
		excelExportSXXSSF.setFieldCodes(fieldCodes);
		excelExportSXXSSF.setWb(new SXSSFWorkbook(flushRows));//創建workbook
		excelExportSXXSSF.setSh(excelExportSXXSSF.getWb().createSheet());//創建sheet
		excelExportSXXSSF.writeTitles();
		return excelExportSXXSSF;
	}

	/**
	 * 設置導入文件的標題
	 * 開始生成導出excel的標題
	 * @throws Exception
	 */
	private void writeTitles() throws Exception {
		rownum = 0;//第0行
		colnum = fieldNames.size();//根據列標題得出列數
		Row row = sh.createRow(rownum);
		for (int cellnum = 0; cellnum < colnum; cellnum++) {
			Cell cell = row.createCell(cellnum);
			cell.setCellValue(fieldNames.get(cellnum));
		}
	}

	/**
	 * 嚮導出文件寫數據
	 * 
	 * @param datalist
	 *            存放Object對象,僅支持單個自定義對象,不支持對象中嵌套自定義對象
	 * @return
	 */
	public void writeDatasByObject(List datalist) throws Exception {

		for (int j = 0; j < datalist.size(); j++) {
			rownum = rownum + 1;
			Row row = sh.createRow(rownum);
			for (int cellnum = 0; cellnum < fieldCodes.size(); cellnum++) {
				Object owner = datalist.get(j);
				Object value = invokeMethod(owner, fieldCodes.get(cellnum),
						new Object[] {});
				Cell cell = row.createCell(cellnum);
				cell.setCellValue(value!=null?value.toString():"");
			}

		}

	}
	/**
	 * 嚮導出文件寫數據
	 * 
	 * @param datalist
	 *            存放字符串數組
	 * @return
	 */
	public void writeDatasByString(List<String> datalist) throws Exception {
			rownum = rownum + 1;
			Row row = sh.createRow(rownum);
			int datalist_size = datalist.size();
			for (int cellnum = 0; cellnum < colnum; cellnum++) {
				Cell cell = row.createCell(cellnum);
				if(datalist_size>cellnum){
					cell.setCellValue(datalist.get(cellnum));
				}else{
					cell.setCellValue("");
				}
				
			}
	}

	/**
	 * 手動刷新方法,如果flushRows爲-1則需要使用此方法手動刷新內存
	 * 
	 * @throws Exception
	 */
	public void flush(int flushNum) throws Exception {
		((SXSSFSheet) sh).flushRows(flushNum);
	}

	/**
	 * 導出文件
	 * 
	 * @throws Exception
	 */
	public String exportFile() throws Exception {
		String filename = filePrefix+"_"+System.currentTimeMillis() + ".xlsx";
		FileOutputStream out = new FileOutputStream(filePath + filename);
		wb.write(out);
		out.flush();
		out.close();
		setFileAllPath(fileWebPath + filename);
		return fileWebPath + filename;
	}

	/**
	 * 反射方法,通過get方法獲取對象屬性
	 * 
	 * @param owner
	 * @param fieldname
	 * @param args
	 * @return
	 * @throws Exception
	 */
	private Object invokeMethod(Object owner, String fieldname, Object[] args)
			throws Exception {

		String methodName = "get" + fieldname.substring(0, 1).toUpperCase()
				+ fieldname.substring(1);
		Class ownerClass = owner.getClass();

		Class[] argsClass = new Class[args.length];

		for (int i = 0, j = args.length; i < j; i++) {
			argsClass[i] = args[i].getClass();
		}

		Method method = ownerClass.getMethod(methodName, argsClass);
		return method.invoke(owner, args);
	}

	public SXSSFWorkbook getWb() {
		return wb;
	}

	public void setWb(SXSSFWorkbook wb) {
		this.wb = wb;
	}

	public Sheet getSh() {
		return sh;
	}

	public void setSh(Sheet sh) {
		this.sh = sh;
	}


	public int getFlushRows() {
		return flushRows;
	}

	public void setFlushRows(int flushRows) {
		this.flushRows = flushRows;
	}

	public String getFilePath() {
		return filePath;
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

	public String getFileWebPath() {
		return fileWebPath;
	}

	public void setFileWebPath(String fileWebPath) {
		this.fileWebPath = fileWebPath;
	}

	public List<String> getFieldNames() {
		return fieldNames;
	}

	public void setFieldNames(List<String> fieldNames) {
		this.fieldNames = fieldNames;
	}

	public List<String> getFieldCodes() {
		return fieldCodes;
	}

	public void setFieldCodes(List<String> fieldCodes) {
		this.fieldCodes = fieldCodes;
	}

	public int getRownum() {
		return rownum;
	}

	public String getFilePrefix() {
		return filePrefix;
	}

	public void setFilePrefix(String filePrefix) {
		this.filePrefix = filePrefix;
	}

	public int getColnum() {
		return colnum;
	}

	public String getFileAllPath() {
		return fileAllPath;
	}

	public void setFileAllPath(String fileAllPath) {
		this.fileAllPath = fileAllPath;
	}
}

6、將數據庫查詢出的列表數據導出到excel

//實現excel的導出功能
    @RequestMapping("/exportYpxxSubmit")
    @ResponseBody
    public SubmitResultInfo exportYpxxSubmit(YpxxQueryVo ypxxQueryVo) throws Exception{
        //調用封裝類執行導出
        //1.定義導出數據的title
        List<String> filedNames = new ArrayList<>();
        filedNames.add("流水號");
        filedNames.add("通用名");
        filedNames.add("劑型");
        filedNames.add("規格");
        filedNames.add("轉換系數");
        filedNames.add("生產企業");
        filedNames.add("商品名稱");
        filedNames.add("中標價格");
        filedNames.add("交易狀態");
        //2.告訴導出數據list中的對象的屬性,讓excelExportSXXSSF通過反射貨到對象的值
        List<String> fildCodes = new ArrayList<>();
        fildCodes.add("bm");        //藥品流水號
        fildCodes.add("mc");
        fildCodes.add("jx");
        fildCodes.add("gg");
        fildCodes.add("zhxs");
        fildCodes.add("scqymc");
        fildCodes.add("spmc");
        fildCodes.add("zbjg");
        fildCodes.add("jyzt");
        //3.開始到處
        String filePath = "E:\\upload";
        String filePrefix = "uploadypxx";
        int flushRows = 100;        //-1表示關閉自動刷新,手動控制寫入磁盤時機,其他數據表示 多少數據在內存中保存超過的就寫入到磁盤
        ExcelExportSXXSSF excelExportSXXSSF = ExcelExportSXXSSF.start(filePath,"http://localhost:80/",filePrefix, filedNames, fildCodes, flushRows);
        //導出得數據通過service取得
        List<YpxxCustom> list = ypxxService.findYpxxList(ypxxQueryVo);
        //執行導出
        excelExportSXXSSF.writeDatasByObject(list);
        //輸出文件,返回下載文件的http地址,已經包括目錄
        String webpath = excelExportSXXSSF.exportFile();
        System.out.println("下載路徑:" + webpath);
        //list就是查詢到的目錄列表    webpath就是下載地址
        return ResultUtil.createSubmitResult(ResultUtil.createSuccess(Config.MESSAGE,313,new Object[]{list.size(),webpath}));
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章