使用到的依賴:
<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}));
}