2018-01-22 09:29:41 huangchunxia_1 阅读数 4140
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

转载自:http://bbs.chinaunix.net/thread-3620272-1-1.html

说明:我的电脑 2.0CPU 2G内存 能够十秒钟导出 20W 条数据 ,12.8M的excel内容压缩后2.68M
我们知道在POI导出Excel时,数据量大了,很容易导致内存溢出。由于Excel 一个sheet允许的最大行数是65536这时我们想到分sheet进行导出;但是这种情况也不能解决内存溢出的问题。毕竟数据还是一次性在内存中进行保存的。这时我们想是不是可以导出多个excel呢?下面我就尝试着按照导出多个excel
首先:我们要确定数据量有多大,然后确定一个excel导出多少条数据,这样就可以确定导出的Excel的数量,于是我们就可以循环的导出excel并保存在任意的临时目录中。去这样如果内存不够的话虚拟机就会去进行回收已经保存的excel在内存中的空间。
假设我们我们已经成功的生成了多个excel,这时我们怎么把这N个excel文档传到客户端呢?其实一个一个的传也未尝不可,但是考虑那样对用户来说体验不够好,再次多个文件在网络上传输也比较慢。我们可以考虑对生成的几个文件进行压缩,然后传到客户端。
总结一下第一、分批次生成excel第二、压缩后到客户端

下面我把我的一个小实例贴上供大家参考

第一、Person.java 普通javabean

Javabean代码

  1. package bean;  
  2. /**  
  3. *   
  4. * @author QQ:三二8二4七6七六  
  5. *  
  6. */  
  7. public class Person {  
  8.   
  9.     private Integer id;  
  10.     private String name;  
  11.     private String address;  
  12.     private String tel;  
  13.     private Double money=0.0;  
  14.     public Double getMoney() {  
  15.         return money;  
  16.     }  
  17.     public void setMoney(Double money) {  
  18.         this.money = money;  
  19.     }  
  20.     public Person(Integer id, String name, String address, String tel,Double money) {  
  21.         super();  
  22.         this.id = id;  
  23.         this.name = name;  
  24.         this.address = address;  
  25.         this.tel = tel;  
  26.         this.money=money;  
  27.     }  
  28.     public Integer getId() {  
  29.         return id;  
  30.     }  
  31.     public void setId(Integer id) {  
  32.         this.id = id;  
  33.     }  
  34.     public String getName() {  
  35.         return name;  
  36.     }  
  37.     public void setName(String name) {  
  38.         this.name = name;  
  39.     }  
  40.     public String getAddress() {  
  41.         return address;  
  42.     }  
  43.     public void setAddress(String address) {  
  44.         this.address = address;  
  45.     }  
  46.     public String getTel() {  
  47.         return tel;  
  48.     }  
  49.     public void setTel(String tel) {  
  50.         this.tel = tel;  
  51.     }  
  52. }  
复制代码
第二、PersonService模拟业务逻辑循环生成100023个Person对象

模拟业务逻辑代码
  1. package service;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import bean.Person;  
  7. /**  
  8. *   
  9. * @author QQ:三二8二4七6七六  
  10. *  
  11. */  
  12. public class PersonService {  
  13.     public static List getPerson(){  
  14.         List<Person> list =new ArrayList<Person>();  
  15.         for(int i=0;i<100320;i++){  
  16.             list.add(new Person(i,"zhangsan"+i,"北京"+i,"13214587632",123123.12+i));   
  17.         }  
  18.         return list;  
  19.     }  
  20.   
  21. }  
复制代码
第三、业务处理Servlet

操作servlet代码
  1. package servlet;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.OutputStream;  
  8. import java.text.SimpleDateFormat;  
  9. import java.util.ArrayList;  
  10. import java.util.Date;  
  11. import java.util.List;  
  12.   
  13. import javax.servlet.ServletException;  
  14. import javax.servlet.http.HttpServlet;  
  15. import javax.servlet.http.HttpServletRequest;  
  16. import javax.servlet.http.HttpServletResponse;  
  17.   
  18. import org.apache.poi.hssf.usermodel.HSSFWorkbook;  
  19. import org.apache.poi.hssf.util.CellRangeAddress;  
  20. import org.apache.poi.ss.usermodel.Cell;  
  21. import org.apache.poi.ss.usermodel.CellStyle;  
  22. import org.apache.poi.ss.usermodel.Row;  
  23. import org.apache.poi.ss.usermodel.Sheet;  
  24. import org.apache.poi.ss.usermodel.Workbook;  
  25.   
  26. import bean.Person;  
  27.   
  28. import service.PersonService;  
  29.   
  30. /**  
  31. *   
  32. * @author QQ:三二8二4七6七六  
  33. *   
  34. */  
  35. public class PersonServlet extends HttpServlet {  
  36.     private String fileName;  
  37.   
  38.     public PersonServlet() {  
  39.         super();  
  40.     }  
  41.   
  42.     public void destroy() {  
  43.         super.destroy(); // Just puts "destroy" string in log  
  44.         // Put your code here  
  45.     }  
  46.   
  47.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  48.             throws ServletException, IOException {  
  49.         // 文件名获取  
  50.         Date date = new Date();  
  51.         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");  
  52.         String f = "Person-" + format.format(date);  
  53.         this.fileName = f;  
  54.         setResponseHeader(response);  
  55.         OutputStream out = null;  
  56.         try {  
  57.             out = response.getOutputStream();  
  58.             List<Person> list = PersonService.getPerson();  
  59.             toExcel(list,request,10000,f,out);  
  60.         } catch (IOException e1) {  
  61.             e1.printStackTrace();  
  62.         } finally {  
  63.             try {  
  64.                 out.flush();  
  65.                 out.close();  
  66.             } catch (IOException e) {  
  67.                 e.printStackTrace();  
  68.             }  
  69.         }  
  70.     }  
  71.   
  72.     /** 设置响应头 */  
  73.     public void setResponseHeader(HttpServletResponse response) {  
  74.         try {  
  75.             response.setContentType("application/octet-stream;charset=UTF-8");  
  76.             response.setHeader("Content-Disposition", "attachment;filename="  
  77.                     + java.net.URLEncoder.encode(this.fileName, "UTF-8")  
  78.                     + ".zip");  
  79.             response.addHeader("Pargam", "no-cache");  
  80.             response.addHeader("Cache-Control", "no-cache");  
  81.         } catch (Exception ex) {  
  82.             ex.printStackTrace();  
  83.         }  
  84.     }  
  85.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  86.             throws ServletException, IOException {  
  87.   
  88.         doGet(request, response);  
  89.     }  
  90.     public void init() throws ServletException {  
  91.         // Put your code here  
  92.     }  
  93.   
  94.     public void toExcel(List<Person> list, HttpServletRequest request,  
  95.             int length, String f, OutputStream out) throws IOException {  
  96.         List<String> fileNames = new ArrayList();// 用于存放生成的文件名称s  
  97.         File zip = new File(request.getRealPath("/files") + "/" + f + ".zip");// 压缩文件  
  98.         // 生成excel  
  99.         for (int j = 0, n = list.size() / length + 1; j < n; j++) {  
  100.             Workbook book = new HSSFWorkbook();  
  101.             Sheet sheet = book.createSheet("person");  
  102.   
  103.             double d = 0;// 用来统计  
  104.             String file = request.getRealPath("/files") + "/" + f + "-" + j  
  105.                     + ".xls";  
  106.   
  107.             fileNames.add(file);  
  108.             FileOutputStream o = null;  
  109.             try {  
  110.                 o = new FileOutputStream(file);  
  111.   
  112.                 // sheet.addMergedRegion(new  
  113.                 // CellRangeAddress(list.size()+1,0,list.size()+5,6));  
  114.                 Row row = sheet.createRow(0);  
  115.                 row.createCell(0).setCellValue("ID");  
  116.                 row.createCell(1).setCellValue("NAME");  
  117.                 row.createCell(2).setCellValue("ADDRESS");  
  118.                 row.createCell(3).setCellValue("TEL");  
  119.                 row.createCell(4).setCellValue("Money");  
  120.   
  121.                 int m = 1;  
  122.   
  123.                 for (int i = 1, min = (list.size() - j * length + 1) > (length + 1) ? (length + 1)  
  124.                         : (list.size() - j * length + 1); i < min; i++) {  
  125.                     m++;  
  126.                     Person user = list.get(length * (j) + i - 1);  
  127.                     Double dd = user.getMoney();  
  128.                     if (dd == null) {  
  129.                         dd = 0.0;  
  130.                     }  
  131.                     d += dd;  
  132.                     row = sheet.createRow(i);  
  133.                     row.createCell(0).setCellValue(user.getId());  
  134.                     row.createCell(1).setCellValue(user.getName());  
  135.                     row.createCell(2).setCellValue(user.getAddress());  
  136.                     row.createCell(3).setCellValue(user.getTel());  
  137.                     row.createCell(4).setCellValue(dd);  
  138.   
  139.                 }  
  140.                 CellStyle cellStyle2 = book.createCellStyle();  
  141.                 cellStyle2.setAlignment(CellStyle.ALIGN_CENTER);  
  142.                 row = sheet.createRow(m);  
  143.                 Cell cell0 = row.createCell(0);  
  144.                 cell0.setCellValue("Total");  
  145.                 cell0.setCellStyle(cellStyle2);  
  146.                 Cell cell4 = row.createCell(4);  
  147.                 cell4.setCellValue(d);  
  148.                 cell4.setCellStyle(cellStyle2);  
  149.                 sheet.addMergedRegion(new CellRangeAddress(m, m, 0, 3));  
  150.             } catch (Exception e) {  
  151.                 e.printStackTrace();  
  152.             }  
  153.             try {  
  154.                 book.write(o);  
  155.             } catch (Exception ex) {  
  156.                 ex.printStackTrace();  
  157.             } finally {  
  158.                 o.flush();  
  159.                 o.close();  
  160.             }  
  161.         }  
  162.         File srcfile[] = new File[fileNames.size()];  
  163.         for (int i = 0, n = fileNames.size(); i < n; i++) {  
  164.             srcfile[i] = new File(fileNames.get(i));  
  165.         }  
  166.         util.FileZip.ZipFiles(srcfile, zip);  
  167.         FileInputStream inStream = new FileInputStream(zip);  
  168.         byte[] buf = new byte[4096];  
  169.         int readLength;  
  170.         while (((readLength = inStream.read(buf)) != -1)) {  
  171.             out.write(buf, 0, readLength);  
  172.         }  
  173.         inStream.close();  
  174.     }  
  175. }  
  176. 最后还有个工具类package util;
  177. 压缩工具类代码  
  178. import java.io.FileInputStream;  
  179. import java.io.FileOutputStream;  
  180. import java.io.IOException;  
  181. import java.util.zip.ZipEntry;  
  182. import java.util.zip.ZipOutputStream;  
  183. /**  
  184. *   
  185. * @author QQ:三二8二4七6七六  
  186. *  
  187. */  
  188. public class FileZip {  
  189.     /**  
  190.      *   
  191.      * @param srcfile 文件名数组  
  192.      * @param zipfile 压缩后文件  
  193.      */  
  194.     public static void ZipFiles(java.io.File[] srcfile, java.io.File zipfile) {  
  195.         byte[] buf = new byte[1024];  
  196.         try {  
  197.             ZipOutputStream out = new ZipOutputStream(new FileOutputStream(  
  198.                     zipfile));  
  199.             for (int i = 0; i < srcfile.length; i++) {  
  200.                 FileInputStream in = new FileInputStream(srcfile[i]);  
  201.                 out.putNextEntry(new ZipEntry(srcfile[i].getName()));  
  202.                 int len;  
  203.                 while ((len = in.read(buf)) > 0) {  
  204.                     out.write(buf, 0, len);  
  205.                 }  
  206.                 out.closeEntry();  
  207.                 in.close();  
  208.             }  
  209.             out.close();  
  210.         } catch (IOException e) {  
  211.             e.printStackTrace();  
  212.         }  
  213.     }  
  214. }  

2011-11-17 14:42:05 hopestar2008 阅读数 648
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

说明:我的电脑 2.0CPU 2G内存 能够十秒钟导出 20W 条数据 ,12.8M的excel内容压缩后2.68M

我们知道在POI导出Excel时,数据量大了,很容易导致内存溢出。由于Excel 一个sheet允许的最大行数是65536这时我们想到分sheet进行导出;但是这种情况也不能解决内存溢出的问题。毕竟数据还是一次性在内存中进行保存的。这时我们想是不是可以导出多个excel呢?下面我就尝试着按照导出多个excel

首先:我们要确定数据量有多大,然后确定一个excel导出多少条数据,这样就可以确定导出的Excel的数量,于是我们就可以循环的导出excel并保存在任意的临时目录中。去这样如果内存不够的话虚拟机就会去进行回收已经保存的excel在内存中的空间。

假设我们我们已经成功的生成了多个excel,这时我们怎么把这N个excel文档传到客户端呢?其实一个一个的传也未尝不可,但是考虑那样对用户来说体验不够好,再次多个文件在网络上传输也比较慢。我们可以考虑对生成的几个文件进行压缩,然后传到客户端。

总结一下第一、分批次生成excel第二、压缩后到客户端

 

下面我把我的一个小实例贴上供大家参考

 

第一、Person.java 普通javabean

 

package bean;
/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class Person {

	private Integer id;
	private String name;
	private String address;
	private String tel;
	private Double money=0.0;
	public Double getMoney() {
		return money;
	}
	public void setMoney(Double money) {
		this.money = money;
	}
	public Person(Integer id, String name, String address, String tel,Double money) {
		super();
		this.id = id;
		this.name = name;
		this.address = address;
		this.tel = tel;
		this.money=money;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
}

 

第二、PersonService模拟业务逻辑循环生成100023个Person对象

 

package service;

import java.util.ArrayList;
import java.util.List;

import bean.Person;
/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class PersonService {
	public static List getPerson(){
		List<Person> list =new ArrayList<Person>();
		for(int i=0;i<100320;i++){
			list.add(new Person(i,"zhangsan"+i,"北京"+i,"13214587632",123123.12+i));	
		}
		return list;
	}

}

 

 第三、业务处理Servlet

 

package servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.CellRangeAddress;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import bean.Person;

import service.PersonService;

/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class PersonServlet extends HttpServlet {
	private String fileName;

	public PersonServlet() {
		super();
	}

	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
		// Put your code here
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 文件名获取
		Date date = new Date();
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
		String f = "Person-" + format.format(date);
		this.fileName = f;
		setResponseHeader(response);
		OutputStream out = null;
		try {
			out = response.getOutputStream();
			List<Person> list = PersonService.getPerson();
			toExcel(list,request,10000,f,out);
		} catch (IOException e1) {
			e1.printStackTrace();
		} finally {
			try {
				out.flush();
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/** 设置响应头 */
	public void setResponseHeader(HttpServletResponse response) {
		try {
			response.setContentType("application/octet-stream;charset=UTF-8");
			response.setHeader("Content-Disposition", "attachment;filename="
					+ java.net.URLEncoder.encode(this.fileName, "UTF-8")
					+ ".zip");
			response.addHeader("Pargam", "no-cache");
			response.addHeader("Cache-Control", "no-cache");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}
	public void init() throws ServletException {
		// Put your code here
	}

	public void toExcel(List<Person> list, HttpServletRequest request,
			int length, String f, OutputStream out) throws IOException {
		List<String> fileNames = new ArrayList();// 用于存放生成的文件名称s
		File zip = new File(request.getRealPath("/files") + "/" + f + ".zip");// 压缩文件
		// 生成excel
		for (int j = 0, n = list.size() / length + 1; j < n; j++) {
			Workbook book = new HSSFWorkbook();
			Sheet sheet = book.createSheet("person");

			double d = 0;// 用来统计
			String file = request.getRealPath("/files") + "/" + f + "-" + j
					+ ".xls";

			fileNames.add(file);
			FileOutputStream o = null;
			try {
				o = new FileOutputStream(file);

				// sheet.addMergedRegion(new
				// CellRangeAddress(list.size()+1,0,list.size()+5,6));
				Row row = sheet.createRow(0);
				row.createCell(0).setCellValue("ID");
				row.createCell(1).setCellValue("NAME");
				row.createCell(2).setCellValue("ADDRESS");
				row.createCell(3).setCellValue("TEL");
				row.createCell(4).setCellValue("Money");

				int m = 1;

				for (int i = 1, min = (list.size() - j * length + 1) > (length + 1) ? (length + 1)
						: (list.size() - j * length + 1); i < min; i++) {
					m++;
					Person user = list.get(length * (j) + i - 1);
					Double dd = user.getMoney();
					if (dd == null) {
						dd = 0.0;
					}
					d += dd;
					row = sheet.createRow(i);
					row.createCell(0).setCellValue(user.getId());
					row.createCell(1).setCellValue(user.getName());
					row.createCell(2).setCellValue(user.getAddress());
					row.createCell(3).setCellValue(user.getTel());
					row.createCell(4).setCellValue(dd);

				}
				CellStyle cellStyle2 = book.createCellStyle();
				cellStyle2.setAlignment(CellStyle.ALIGN_CENTER);
				row = sheet.createRow(m);
				Cell cell0 = row.createCell(0);
				cell0.setCellValue("Total");
				cell0.setCellStyle(cellStyle2);
				Cell cell4 = row.createCell(4);
				cell4.setCellValue(d);
				cell4.setCellStyle(cellStyle2);
				sheet.addMergedRegion(new CellRangeAddress(m, m, 0, 3));
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				book.write(o);
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				o.flush();
				o.close();
			}
		}
		File srcfile[] = new File[fileNames.size()];
		for (int i = 0, n = fileNames.size(); i < n; i++) {
			srcfile[i] = new File(fileNames.get(i));
		}
		util.FileZip.ZipFiles(srcfile, zip);
		FileInputStream inStream = new FileInputStream(zip);
		byte[] buf = new byte[4096];
		int readLength;
		while (((readLength = inStream.read(buf)) != -1)) {
			out.write(buf, 0, readLength);
		}
		inStream.close();
	}
}

最后还有个工具类package util;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class FileZip {
	/**
	 * 
	 * @param srcfile 文件名数组
	 * @param zipfile 压缩后文件
	 */
	public static void ZipFiles(java.io.File[] srcfile, java.io.File zipfile) {
		byte[] buf = new byte[1024];
		try {
			ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
					zipfile));
			for (int i = 0; i < srcfile.length; i++) {
				FileInputStream in = new FileInputStream(srcfile[i]);
				out.putNextEntry(new ZipEntry(srcfile[i].getName()));
				int len;
				while ((len = in.read(buf)) > 0) {
					out.write(buf, 0, len);
				}
				out.closeEntry();
				in.close();
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

OK全部内容完成



 

12.8M的excel内容压缩后2.68M,给力吧

以后记得代码加注释

 

亲,记得给个评论哦

2019-03-19 14:57:48 wanglizheng825034277 阅读数 2804
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

xls和xlsx

  1. xls是旧版Excel格式文件,xlsx是新版Excel格式文件;而xlsx新版格式其实是一系列文件压缩包,
    如图:
    在这里插入图片描述
  2. xls是以二进制的方式存储,这种格式不易被其他软件读取使用;而xlsx采用了基于XML的ooxml开放文档标准,ooxml使用XML和ZIP技术结合进行文件存储,XML是一个基于文本的格式,而且ZIP容器支持内容的压缩,所以其一大优势是可以大大减小文件的尺寸;
  3. 使用POI来读写Excel文件有两种方式,一种用户模式(UserModel),读取时消耗大量内存,造成OOM问题;一种事件模式(SAX模式),仅仅关注文件内部数据,内存消耗很低;
  4. 导出文件同样如此,使用Workbook普通导出,数据量小的时候可以正常使用,但时间等待仍然很长,这时推荐使用POI提供的SXXFWorkbook处理,其使用时间窗口原理(具体可以查询)限制访问,刷出内存,降低内存消耗,提升效率。
    另外还需要注意,根据你使用的功能,仍然可能消耗大量内存,例如合并区域,超链接,注释……,这些内容只存储在内存中。
    在这里插入图片描述

导入数据(大量)

大量数据导入在网络上搜寻到的相关代码大部分通过集成POI原生的DefaultHandler重写其startElement, endElement, characters方法进行相关的解析,而POI已经将相关逻辑封装在XSSFSheetXMLHandler,只要实现暴露的接口SheetContentsHandler即可。
使用SheetContentsHandler的例子可以参考官方的XLSX2CVS
本例实现该接口:

package cn.skio.venus.api;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.SAXHelper;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @autor jasmine
 */
public class ExcelEventParser {
    private String fileName;
    private SimpleSheetContentsHandler handler;
    // 测试使用对比使用SAX和UserModel模式选择(实际使用不需要)
    private Integer saxInterupt;
	private void setHandler(SimpleSheetContentsHandler handler) {
		this.handler = handler;
	}

	// 放置读取数据
    protected List<List<String>> table = new ArrayList<>();

    public ExcelEventParser(String filename, Integer saxInterupt){
        this.fileName = filename;
        this.saxInterupt = saxInterupt;
    }

    public List<List<String>> parse() {
        OPCPackage opcPackage = null;
        InputStream inputStream = null;

        try {
            FileInputStream fileStream = new FileInputStream(fileName);
            opcPackage = OPCPackage.open(fileStream);
            XSSFReader xssfReader = new XSSFReader(opcPackage);

            StylesTable styles = xssfReader.getStylesTable();
            ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(opcPackage);
            inputStream = xssfReader.getSheetsData().next();

            processSheet(styles, strings, inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (opcPackage != null) {
                try {
                    opcPackage.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return table;
    }

	// 确定XMLReader解析器,使用SAX模式解析xml文件
    private void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream) throws SAXException, ParserConfigurationException, IOException {
        XMLReader sheetParser = SAXHelper.newXMLReader();

        if (handler == null) {
            setHandler(new SimpleSheetContentsHandler());
        }
        sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings, handler, false));

        try {
            sheetParser.parse(new InputSource(sheetInputStream));
        } catch (RuntimeException e) {
            System.out.println("---> 遇到空行读取文件结束!");
        }
    }

	// 实现SheetContentsHandler
    public class SimpleSheetContentsHandler implements SheetContentsHandler{
        protected List<String> row;
        @Override
        public void startRow(int rowNum) {
            row = new LinkedList<>();
        }

        @Override
        public void endRow(int rowNum) {
        	// 判断是否使用异常作为文件读取结束(有些Excel文件格式特殊,导致很多空行,浪费内存)
            if (saxInterupt == 1) {
                if (row.isEmpty()) {
                    throw new RuntimeException("Excel文件读取完毕");
                }
            }
			// 添加数据到list集合
            table.add(row);
        }

        /**
         * 所有单元格数据转换为string类型,需要自己做数据类型处理
         * @param cellReference 单元格索引
         * @param formattedValue 单元格内容(全部被POI格式化为字符串)
         * @param comment
         */
        @Override
        public void cell(String cellReference, String formattedValue, XSSFComment comment) {
            row.add(formattedValue);
        }

        @Override
        public void headerFooter(String text, boolean isHeader, String tagName) {
        }
    }
}

经测试结果,发现使用SAX模式(抛弃了样式等,只关注数据)仅仅消耗很少内存,效率高;而普通Workbook读取数据(测试文件为5.2MB的有大量空行文件)内存消耗 > 1GB(此时线上系统OOM概率非常大);
在这里插入图片描述

导出数据(大量)

导出数据的话瓶颈主要在于数据写入Excel文件,代码(同样的74273条数据导出)如下:

	// 使用SXSSFwrokbook,大量数据处理快速
	@GetMapping("/outExcel")
    public void outPutExcel(HttpServletResponse response) throws Exception {
        // 每次写100行数据,就刷新数据出缓存
        SXSSFWorkbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
        Sheet sh = wb.createSheet();
        List<Tmp> tmps = tmpDao.findAll();
        log.info("---> 数据量:{}", tmps.size());

        for(int rowNum = 0; rowNum < tmps.size(); rowNum++){
            Row row = sh.createRow(rowNum);
            Tmp tmp = tmps.get(rowNum);
            Cell cell1 = row.createCell(0);
            cell1.setCellValue(tmp.getSource());

            Cell cell2 = row.createCell(1);
            cell2.setCellValue(tmp.getName());
            Cell cell3 = row.createCell(2);
            cell3.setCellValue(tmp.getPhone());
            Cell cell4 = row.createCell(3);
            cell4.setCellValue(tmp.getCity());
        }

        String fileName = "sxssf.xlsx";
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        wb.write(response.getOutputStream());
        wb.close();
    }
	// XSSFWorkbook, 效率低下
	@GetMapping("/outExcel2")
    public void outPutExcel2(HttpServletResponse response) throws Exception {
        XSSFWorkbook wb = new XSSFWorkbook();
        Sheet sh = wb.createSheet();
        List<Tmp> tmps = tmpDao.findAll();
        log.info("---> 数据量:{}", tmps.size());

        for(int rowNum = 0; rowNum < tmps.size(); rowNum++){
            Row row = sh.createRow(rowNum);
            Tmp tmp = tmps.get(rowNum);
            Cell cell1 = row.createCell(0);
            cell1.setCellValue(tmp.getSource());

            Cell cell2 = row.createCell(1);
            cell2.setCellValue(tmp.getName());
            Cell cell3 = row.createCell(2);
            cell3.setCellValue(tmp.getPhone());
            Cell cell4 = row.createCell(3);
            cell4.setCellValue(tmp.getCity());
        }

        String fileName = "sxssf.xlsx";
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "GBK"));
        wb.write(response.getOutputStream());
        wb.close();
    }

效率对比:

对象 耗时
SXSSFWorkbook 在这里插入图片描述
XSSFWorkbook 在这里插入图片描述

CPU和内存消耗对比:
在这里插入图片描述

总结

  1. 大文件读取使用SAX
  2. 大文件写入使用SXSSFWorkbook

参考链接:
[1]: https://blog.csdn.net/Holmofy/article/details/82532311
[2]: https://blog.csdn.net/daiyutage/article/details/53010491
[3]: https://www.cnblogs.com/yfrs/p/5689347.html
[4]: easyexcel

2016-09-12 10:33:18 u010456982 阅读数 2377
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

SpringMVC文件上传 Excle文件 Poi解析 验证 去重 并批量导入 MYSQL数据库

SpringMVC文件上传 Excle文件 Poi解析并批量导入 MYSQL数据库 

/**
* 业务需求说明:
* 1 批量导入成员 并且 自主创建账号
* 2 校验数据格式 且 重复导入提示 已被占用
* 3 导入手机相同 则更新源有信息
* 4 返回错误信息
*/

jsp文件 部分 浏览 以及功能键 代码:

复制代码
 1   <div class="modal-body" style="position: relative;">
 2         <form class="" role="form" id="upload_form">
 3             <select class="form-control m-b" id="upload_dept" name="uploadDept">
 4             </select>
 5             <div class="input-group">
 6                 <input type="text" class="form-control input-sm" name="upload_filename">
 7                     <div class="input-group-btn">
 8                         <button type="button" class="btn btn-sm btn-primary">
 9                         浏览
10                         </button>
11                     </div>
12             </div>
13               <!--  选择上传文件按钮   type类型指定为 file   accept 可以在浏览过程中 进行过滤显示   支持多个用逗号隔开  -->
14                             <!-- 选择文件后显示文件名称  对更改事件绑定了事件监听器 selectUploadFile(this)   此框按钮id为: upload_file    -->
15                 <input type="file" id="upload_file" onchange="selectUploadFile(this)" name="uploadFile" accept=".xls,.xlsx" class="input-fzliulan">
16         </form>
17     </div>
18     <div class="modal-footer">
19         <button type="button" id="btn_upCancel" class="btn btn-white" data-dismiss="modal">关闭</button>
20         <button type="button" id="btn_upSubmit" class="btn btn-success pdlr16"><span id="uploadTxt">导入</span><img id="loadingImg" style="display: none" src="<%=contextPath%>/resource/images/loading.gif" /></button>
21     </div>
复制代码

comm.jsp文件定义的变量:

复制代码
1   var userId = '<c:out value="${sessionScope.USER.userId}" />';
2     var orgId = '<c:out value="${sessionScope.ORG.orgId}" />';
3     var authLevel = '<c:out value="${sessionScope.USER.authLevel}" />';
4     var userType = '<c:out value="${sessionScope.USER.type}" />';
5     var orgAmount= '<c:out value="${sessionScope.AGENT.orgAmount}" />';
6     var loginUser = {userId: userId, orgId: orgId, authLevel: authLevel, type: userType ,orgAmount:orgAmount};
复制代码

页面js:

复制代码
 1 $(function(){
 2     bindEvent();
 3 })
 4 /** 为页面按钮绑定事件
 5  */
 6 function bindEvent(){
 7     /**
 8      * 显示上传文件名称
 9      * @param fileObj
10      */
11     function selectUploadFile(fileObj){
12         var fullPath = $(fileObj).val();
13         var index = fullPath.lastIndexOf('\\') + 1;
14         var fileName = fullPath.substring(index);
15         $('input[name="upload_filename"]').val(fileName);
16     }
17 
18 
19 
20  $('#downLoadTemplate').click(function(){  //下载模板按钮的监听器   
21         var url = webContext + '/file\\template\\组织用户信息模板.xlsx';
22         downloadFile(url)
23     });
24 
25 /**
26  * 上传文件
27  */
28 
29   $('#btn_upSubmit').click(function(){
30      var valid = uploadValidator.checkForm(); //检测传单内容输入是否有问题
31         if(!valid){ 
32             uploadValidator.showErrors();
33         } else{ //检测成功
34             $('#uploadTxt').text('');  
35             $('#loadingImg').show();  //按钮换成动画效果图片
36 /** 准备参数: */
37             var orgId = loginUser.orgId;  //但钱用户的组织id   
38             var deptId = $('#upload_dept').val();  //  选框中选择的部门id
39             var password = hex_md5('123456');//  默认密码 进行加密 
40             var param = {orgId: orgId, deptId: deptId, password: password};  //ajax传输 携带json详细信息
41             var url = webContext + '/org/uploadOrgUser';  //   /** 使用ajaxFileUpload */
42     $.ajaxFileUpload({
43         url: url, //用于文件上传的服务器端请求地址
44         secureuri: false, //是否需要安全协议,一般设置为false
45         fileElementId: 'upload_file', //文件上传域的ID  就是选定文件的 type=file的input框的id  ajaxFileUpload 会帮我们把他分装到ajax请求的 携带对象域中去
46         dataType: 'json', //返回值类型 一般设置为json
47         type: 'post',
48         data: param,
49         success:function(){
50         //成功的success 回调方法等业务流程结束后再写
51         //先留已空白
52         }
53     })
54         }
55   })
56 }
复制代码

项目使用SpringMVC : 

其controller为:

复制代码
 1 //-----------------------------------MVC 的控制器----------------------
 2 //Controller为:
 3 @Controller
 4 @RequestMapping("/org")
 5 public class OrgController extends BaseController {
 6 
 7     @Autowired
 8     private IOrgService orgService;
 9 
10     @RequestMapping("/uploadOrgUser")
11     @ResponseBody
12     public Map<String, Object> uploadOrgUser(HttpServletRequest request){
13         Map<String, Object> map = new HashMap<String, Object>();
14         String flag = "failure";
15         String msg = "上传成功";
16         MultipartHttpServletRequest mtRequest = (MultipartHttpServletRequest) request;//多部分httpRquest对象    是HttpServletRequest类的一个子类接口   支持文件分段上传对象
17         Integer orgId = RequestUtil.getIntParam(mtRequest, "orgId");  //组织id
18         Integer deptId = RequestUtil.getIntParam(mtRequest, "deptId"); //选取部门id
19         String password = RequestUtil.getStringParam(request, "password"); // 初始密码 已被md5加密
20         MultipartFile upFile = mtRequest.getFile("uploadFile"); // 直接获取文件对象
21         if(null == upFile || upFile.getSize()==0){   //文件不存在的情况
22             msg = "上传文件不存在或为空文件";
23             map.put("flag", flag);
24             map.put("msg", msg);
25             return map;  //返回错误信息
26         }
27         String targetPath = request.getServletContext().getRealPath("/file/upload"); //获取服务器 中file/update 的 url地址
28         map = orgService.uploadOrgUser(targetPath, orgId, deptId, password, upFile);  //调用实现类 返回 界面消息 对象
29         return map;
30     }
31 }
复制代码

--业务层接口--说明:

复制代码
 1 public interface IOrgService {
 2     /**
 3      * @param targetPath
 4      * @param orgId
 5      * @param deptId
 6      * @param password
 7      * @param upFile
 8      * @return
 9      */
10     public Map<String, Object> uploadOrgUser(String targetPath, Integer orgId, Integer deptId, String password, MultipartFile upFile);
11 }
复制代码

--业务层实现类:

复制代码
  1 //业务层实现类:
  2 @Service("orgService")
  3 public class OrgServiceImpl extends BaseService implements IOrgService {
  4 
  5     @Autowired
  6     private IOrgDao orgDao;
  7 
  8     @Autowired
  9     private IUserDao userDao;
 10 
 11     @Autowired
 12     private IDeptDao deptDao;
 13 
 14     @Autowired
 15     private IOrgUserDao orgUserDao;
 16 
 17     @Autowired
 18     private IServiceAuthDao authDao;
 19 
 20     /**  批量导入 业务方法  **/
 21     public Map<String, Object> uploadOrgUser(String targetPath, Integer orgId, Integer deptId, String password, MultipartFile upFile) {
 22         Map<String,Object> rm = new HashMap<String,Object>();
 23         String flag ="failure";
 24         String msg = "上传失败";
 25         File f = new File(targetPath) //实例硬盘中文件夹(路径)对象 
 26         if(!f.exists()){//判断此路径/文件夹是否存在
 27             f.mkdirs(); //如果不存在  则创建文件夹/目录
 28         }
 29         String originalName = upFile.getOriginalFilename();//获取文件对象原始文件名
 30         SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
 31         String tag = sdf.format(new Date());
 32         String upFileName = targetPath + File.separator+tag+"_"+originalName;// 拼接出文件的要存储的位置(全路径)
 33         File file = new File(upFileName);//创建 内存中的File对象
 34         if(file.exists()){ //判断是否存在
 35             file.delete();//如果有重名文件存在  就删除文件  
 36             // 这个对象对应的硬盘必须删  不能存在  如果已经存在 则会抛出
 37             // IOException异常
 38         }
 39         List<OrgUser> orgUsers = null;  
 40         List<User> users = null;
 41         List<RowData> offedData = null;  //List 集合对象准备
 42         try{
 43             upFile.transferTo(file);//转存文件  写入硬盘  //这个  本质还是一样的打开流传文件  需要注意 file对应的硬盘中的文件不能存在 需要删除  否则会抛出 文件已经存在且不能删除 异常
 44             // 校验上传数据
 45             /**  辅助方法一 **/
 46         Map<String,Object> validData = validUpload(file,orgId,deptId);// 校验数据    分类 返回 map形式
 47         users = (List<User>) validData.get("PASSED_USERS");  //通过的user  是向 m_user 表的 
 48         orgUsers = (List<OrgUser>) validData.get("PASSED_ORGUSERS"); //  是向 m_org_user 表的
 49         offedData = (List<RowData>) validData.get("OFFED_ROW");    //
 50         int rowNum = (Integer) validData.get("DATA_SIZE");   //  excle 数据总长度
 51         rm.put("ROW_COUNT", rowNum);//业务类的总长度
 52       
 53         List<OrgUser> ous = orgUserDao.getOrgUsers(orgId);//获取组织的所有用户
 54         ServiceAuth sa = new ServiceAuth(); //权限对象
 55         sa.setOrgId(orgId);  //  设置组织id
 56         sa.setServiceCode(Sys.GROUP_ORG); //设置服务编码  多用户版基础服务
 57         sa.setType(Sys.TYPE_BUY); //设置 类型 为购买类型
 58         ServiceAuth nSa = authDao.getOrgServiceAuthInfo(sa); //获取组织服务等级 详细信息
 59         int actSize = ous.size(); // 当前组织已有用户的总长度
 60         int license = nSa.getLicense(); // 组织上限人数
 61         int totalNum = 0;  //设置总数为 0
 62         
 63         Org o = orgDao.getOrgById(orgId);  //获取组织对象
 64         Date duration = DateFormater.stringToDate(o.getDuration(), "yyyy-MM-dd"); //获取服务到期时间
 65         //上数据库插入数据
 66         if(null!=users && !users.isEmpty()){
 67             totalNum = actSize + users.size();  //总数现在等于 添加人数和已有人数
 68             if(totalNum < license){//上传人数和原有人数之和小于组织服务人数上限
 69                 for(int i=0; i<users.size(); i++){
 70                     User u = users.get(i);
 71                     u.setPassword(password);
 72                     OrgUser ou = orgUsers.get(i);
 73                     userDao.addUser(u);
 74                     //添加到微信企业号
 75                     addCpUser(u);
 76                     //添加个人空间
 77                     Org selfOrg = new Org();
 78                     selfOrg.setAdminName(u.getUserName());
 79                     selfOrg.setType(Sys.ORG_TYPE_PER);
 80                     selfOrg.setState(Sys.ORG_VERIFY_1);
 81                     selfOrg.setAdminId(u.getUserId());
 82                     selfOrg.setAdminName(u.getUserName());
 83                     selfOrg.setDuration(duration);
 84                     selfOrg.setDel(Sys.UN_STOPED);
 85                     selfOrg.setCreateTime(new Date());
 86                     selfOrg.setUpdateTime(new Date());
 87                     selfOrg.setIdparent(0);
 88                     orgDao.addOrg(selfOrg);
 89                     Dept d = new Dept();
 90                     d.setDeptId(0);
 91                     addOrgUserRelation(selfOrg, d, u);
 92                     if(null!=u.getUserId() && u.getUserName().equals(ou.getOrgUserName())){
 93                         ou.setUserId(u.getUserId());
 94                         orgUserDao.addOrgUser(ou);
 95                     }
 96                 }
 97                 rm.put("PASSED_COUNT", users.size());//成功数据
 98             } else {
 99                 rm.put("ORG_LICENSE", license);  //上限
100                 rm.put("ORG_ACTSIZE", actSize);  //  
101                 rm.put("OVER_LICENSE", totalNum - license);
102             }
103 
104         }
105         int offedCount = 0;
106         if(null!= offedData && !offedData.isEmpty()){ 
107             offedCount = offedData.size();
108             rm.put("OFFED_DATA", offedData);
109         }
110         rm.put("OFFED_COUNT", offedCount);
111 
112         flag = "success";
113         msg = "上传成功";
114         }  catch (Exception e2) {
115             logger.error("Exception while uploadOrgUser", e2);
116         }
117         rm.put("flag", flag);
118         rm.put("msg", msg);
119 
120         return rm;
121 
122     }
123 }
复制代码

----------------------------------------------------------------------------------------------------------------------------------------------

//辅助方法清单: 

复制代码
 1  //*************************** 辅助方法一 *****************************************************************
 2     /**
 3      * 校验上传文件
 4      * 参数:文件对象
 5      *       组织id 
 6      *       部门id
 7      */
 8     private Map<String, Object> validUpload(File uploadFile, Integer orgId, Integer deptId) throws Exception{
 9         Map<String, Object> map = new HashMap<String, Object>();
10         List<User> passed = null;
11         List<User> offed = null;
12         List<String> mobileList = userDao.getAllActiveMobile();//为了防止已注册用户再次注册
13         List<String> emailList = userDao.getAllActiveEmail();//  现在还是查询出所有的     ------需要优化标记
14         //获取上传的excel中的数据
15         //******辅助方法二*********
16         ExcelData uploaddata = getUploadUserData(uploadFile);//获取内存中解析好的excle数据对象   
17         //校验上传数据
18         //******辅助方法三*********
19         Map<String, Object> dataMap = validUploadData(orgId, deptId, uploaddata, mobileList, emailList); //返回的是数据对象
20 
21         return dataMap;
22 }
复制代码
复制代码
  //*************************** 辅助方法二 *****************************************************************
    /**
     * 获取上传文件的数据
     * @param uploadFile
     * @return
     * @throws Exception
     */
    private ExcelData getUploadUserData(File uploadFile) throws Exception{
        List<User> list = new ArrayList<User>();
        String[] columnKey = {"userName", "mobile", "phone", "email", "QQ", "weixin", "job", "dept", "note"};
        int startRow = 1;
        ExcelData uploadData = FileUtil.parseExcelFile(uploadFile, startRow, columnKey);//将要抛出异常
        return uploadData;
    }


}
复制代码
复制代码
  1   //*************************** 辅助方法三 *****************************************************************
  2     /**
  3      *   方法说明:  
  4      *              校验上传数据
  5      *
  6      *
  7      * @param orgId     其应该所属的组织
  8      * @param deptId    所选的部门id
  9      * @param excelData excel表格数据对象
 10      * @param mobiles   所有的手机号码 集合   用来判断手机是否注册
 11      * @param emails    所有的邮箱号码 集合
 12      * @return
 13      */
 14     private Map<String, Object> validUploadData(Integer orgId, Integer deptId,ExcelData excelData, List<String> mobiles, List<String> emails) {
 15         Map<String, Object> map = new HashMap<String, Object>();
 16         List<RowData> passed = new ArrayList<RowData>();
 17         List<User> passedUsers = new ArrayList<User>();  // 通过验证的  到 m_user
 18         List<OrgUser> passedOrgUsers = new ArrayList<OrgUser>(); //通过验证的   到m_org_user
 19         List<RowData> offed = new ArrayList<RowData>();
 20         List<RowData> rows = null;//  所有数据
 21         Date createTime = new Date();//创建时间
 22         Date updateTime = new Date();  //更新时间
 23         List<Dept> deptList = null;  //当前组织的所有部门的   list集合
 24         Map<String, Dept> deptMap = new HashMap<String, Dept>();
 25         if(null != excelData && null != excelData.getRows() && !excelData.getRows().isEmpty()){  //如果传入对象不为空
 26             rows = excelData.getRows();  //获取对象中的所有数据   类型应该是List集合 每个元素应该是一行数据 即:RowData
 27             map.put("DATA_SIZE", rows.size());// 设置总数据有多少条
 28             List<String> excelMobiles = new ArrayList<String>();  //用于存放excle表格中的电话号码
 29             List<String> excelEmails = new ArrayList<String>(); //用于存放excle表格中的邮箱号码
 30             deptList = deptDao.getDeptsByOrgId(orgId);//获取所有部门?
 31             for(Dept dept:deptList){
 32                 String deptName = dept.getDeptName();
 33                 deptMap.put(deptName, dept);//转成map了
 34             }
 35 rowloop:     //行循环跳出坐标准备
 36             for (int i = 0; i < rows.size(); i++) {//循环便利数据
 37                 OrgUser orgUser = new OrgUser();  //组织用户 实例化对象准备
 38                 User user = new User();  //用户 POJO准备
 39                 //获取行数据
 40                 RowData r = rows.get(i);  //  获取行数据
 41                 int rowIndex = r.getRowIndex();  //  获取当前行是第几行
 42                 List<CellData> cells = r.getCells();  //获取当前行的所有数据  cell 的s  
 43                 boolean flag = true;
 44                 String userName="",mobile="",phone="",email="",qq="",weixin="",job="";
 45                 int mIndex = 0;
 46                 int eIndex = 0;
 47 columnloop: //列循环跳出坐标准备
 48                 for (int j = 0; j < cells.size(); j++) {  // 每一行单元格数据 遍历
 49                     CellData c = cells.get(j);  //获取出当前的 数据独立单元格  
 50                     String key = c.getKey();  //属于哪一列?
 51                     String cellValue = c.getCellValue(); //
 52                     if("userName".equals(key)){
 53                         userName = cellValue;
 54                         if(StringUtil.isBlank(cellValue)){
 55                             flag = false;
 56                             c.setPassed(0);
 57                             c.setExtraInfo("用户姓名不能为空");
 58                             continue columnloop;
 59                         }
 60                         user.setUserName(cellValue);
 61                         orgUser.setOrgUserName(cellValue);
 62                     } else if("mobile".equals(key)){  //手机相关验证
 63                         mIndex = j;
 64                         mobile = cellValue;
 65                         if(!StringUtil.isBlank(cellValue)){
 66                             if(!Validator.isMobile(cellValue)){ //校验手机格式
 67                                 flag = false;
 68                                 c.setPassed(0);
 69                                 c.setExtraInfo("不正确的手机号");
 70                                 continue columnloop;
 71                             }
 72 
 73                             if(mobiles.contains(cellValue.trim())){// 比对数据库中的  是否已被注册
 74                                 flag = false;
 75                                 c.setPassed(0);
 76                                 c.setExtraInfo("该手机号已经被使用");
 77                                 continue columnloop;
 78                             }
 79                             if(excelMobiles.contains(cellValue.trim())){ // 当前表格 数据有重复
 80                                 flag = false;
 81                                 c.setPassed(0);
 82                                 c.setExtraInfo("重复的手机号码");
 83                                 continue columnloop;
 84                             }
 85                             user.setLoginName(cellValue);
 86                         }
 87                         user.setMobile(cellValue);
 88                     } else if("phone".equals(key)){ //暂无
 89                         phone = cellValue;
 90                         if(!StringUtil.isBlank(cellValue)){
 91                             //                            if(!Validator.isPhone(cellValue)){
 92                             //                                flag = false;
 93                             //                                c.setPassed(0);
 94                             //                                c.setExtraInfo("不正确的电话号");
 95                             //                                continue columnloop;
 96                             //                            }
 97                         }
 98                         user.setPhone(cellValue);
 99                     } else if("email".equals(key)){  // 邮箱相关验证
100                         eIndex = j;
101                         email = cellValue;
102                         if(!StringUtil.isBlank(cellValue)){
103                             if(!Validator.isEmail(cellValue)){
104                                 flag = false;
105                                 c.setPassed(0);
106                                 c.setExtraInfo("邮箱格式不正确");
107                                 continue columnloop;
108                             }
109                             if(emails.contains(cellValue.trim())){
110                                 flag = false;
111                                 c.setPassed(0);
112                                 c.setExtraInfo("该邮箱已经被使用");
113                                 continue columnloop;
114                             }
115                             if(excelMobiles.contains(cellValue.trim())){
116                                 flag = false;
117                                 c.setPassed(0);
118                                 c.setExtraInfo("重复的邮箱");
119                                 continue columnloop;
120                             }
121                             user.setLoginName(cellValue);
122                         }
123                         user.setEmail(cellValue);
124                     } else if("QQ".equals(key)){
125                         qq = cellValue;
126                         user.setQq(cellValue);
127                     } else if("weixin".equals(key)){
128                         weixin = cellValue;
129                         user.setWeixin(cellValue);
130                     } else if("job".equals(key)){
131                         job = cellValue;
132                         orgUser.setPosition(cellValue);
133                         //暂无
134                     } else if("note".equals(key)){
135                         user.setNote(cellValue);
136                     } else if("dept".equals(key)) {
137                         if(!StringUtil.isBlank(cellValue) && null!=deptMap.get(cellValue.trim())){
138                             Dept d = deptMap.get(cellValue.trim());
139                             orgUser.setDeptId(d.getDeptId());
140                         } else {
141                             orgUser.setDeptId(deptId);
142                         }
143                     } else {
144                         //暂无
145                     }
146                 }
147                 //校验手机与邮箱是否同时为空
148                 if(StringUtil.isBlank(mobile) && StringUtil.isBlank(email)){
149                     flag = false;
150                     CellData mobileCell = cells.get(mIndex);//所属的 行和列
151                     CellData emailCell = cells.get(eIndex);
152                     mobileCell.setPassed(0);  //设置是否通过了校验的标识   注:此标识是对单元格数据进行设置的 
153                     mobileCell.setExtraInfo("手机与邮箱不能同时为空"); //没有通过校验  进行
154                     emailCell.setPassed(0);
155                     emailCell.setExtraInfo("手机与邮箱不能同时为空");
156                 }
157                 if(flag){  //验证通过的话
158                     //初始化user 和 orgUser对象
159                     user.setDefaultOrgId(orgId);
160                     user.setMultiLogin(0);
161                     user.setIsDistributor(0);
162                     user.setSrcOrg(orgId);
163                     user.setMobileBinded(0);
164                     user.setEmailBinded(0);
165                     user.setUtype(0);
166                     user.setUpdateTime(updateTime);
167                     user.setCreateTime(createTime);
168                     user.setDel(Sys.UN_STOPED);
169                     user.setType(2);
170                     user.setSource(1);
171                     user.setIspremiumuser(true);
172                     //                    user.setNote("上传生成用户");
173                     user.setPassword("123456");
174 
175                     orgUser.setOrgId(orgId);
176                     //                    orgUser.setDeptId(deptId);
177                     orgUser.setCreateTime(createTime);
178                     orgUser.setUpdateTime(updateTime);
179                     orgUser.setDel(Sys.UN_STOPED);
180                     orgUser.setState(1);
181                     orgUser.setIsDataCommissioner(0);
182                     orgUser.setIsMarketCommissioner(0);
183                     //向通过list里添加数据
184                     passedUsers.add(user);  //添加到通过的  数据列表中去
185                     passedOrgUsers.add(orgUser);
186                     if(!StringUtil.isBlank(mobile)){
187                         excelMobiles.add(mobile);  //添加到 准备的 list中去  以防下面重复数据   在上面验证
188                     }
189                     if(!StringUtil.isBlank(email)){
190                         excelEmails.add(email);
191                     }
192                 } else {
193                     offed.add(r);
194                 }
195 
196             }
197         }
198         map.put("PASSED_USERS", passedUsers); //
199         map.put("PASSED_ORGUSERS", passedOrgUsers);
200         map.put("OFFED_ROW", offed);
201         return map;
202     }
复制代码

==============================================================================================

//  辅助工具类:

复制代码
  1 package com.SS.util;
  2 
  3 import com.SS.util.excel.CellData;
  4 import com.SS.util.excel.ExcelData;
  5 import com.SS.util.excel.RowData;
  6 import com.sun.image.codec.jpeg.JPEGCodec;
  7 import com.sun.image.codec.jpeg.JPEGEncodeParam;
  8 import com.sun.image.codec.jpeg.JPEGImageEncoder;
  9 import org.apache.log4j.Logger;
 10 import org.apache.poi.hssf.usermodel.HSSFCell;
 11 import org.apache.poi.hssf.usermodel.HSSFRow;
 12 import org.apache.poi.hssf.usermodel.HSSFSheet;
 13 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 14 import org.apache.poi.ss.usermodel.Cell;
 15 import org.apache.poi.xssf.usermodel.XSSFCell;
 16 import org.apache.poi.xssf.usermodel.XSSFRow;
 17 import org.apache.poi.xssf.usermodel.XSSFSheet;
 18 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 19 
 20 import javax.imageio.ImageIO;
 21 import java.awt.*;
 22 import java.awt.image.BufferedImage;
 23 import java.io.*;
 24 import java.util.ArrayList;
 25 import java.util.List;
 26 
 27 /**
 28  * 文件操作工具类
 29  */
 30 public class FileUtil {
 31 
 32     private Logger logger = Logger.getLogger(FileUtil.class);
 33 
 34     /**
 35      * 获取文件的后缀名称
 36      * @param file
 37      * @return
 38      */
 39     public static String getFileSuffix(File file){
 40         String suffix = "";
 41         if(null != file && StringUtil.isBlank(file.getName())){
 42             String fileName = file.getName();
 43             suffix = fileName.substring(fileName.lastIndexOf("."));
 44         }
 45 
 46         return suffix;
 47     }
 48 
 49     /**
 50      * 解析excel文件
 51      * @param file excel文件
 52      * @param startRow 起始行 0为第一行
 53      * @param columnKey  每列对应的key值
 54      * @return
 55      */
 56     public static ExcelData parseExcelFile(File file, int startRow, String[] columnKey){
 57         List<RowData> rows = null;
 58         ExcelData excelData = new ExcelData();
 59         try {
 60             if(null==file || !file.exists() || columnKey.length<1){
 61                 return excelData;
 62             }
 63             String fileName = file.getName();
 64             excelData.setFileName(fileName);
 65             if(fileName.endsWith("xls")){
 66                 rows = parse2003Excel(file, startRow, columnKey);
 67             } else if(fileName.endsWith("xlsx")){
 68                 rows = parse2007Excel(file, startRow, columnKey);
 69             } else {
 70                 throw new RuntimeException("Unknown file type : "+fileName);
 71             }
 72             excelData.setRows(rows);
 73         } catch (Exception e) {
 74             e.printStackTrace();
 75         }
 76         return excelData;
 77     }
 78 
 79     /**
 80      * 解析2003 excel文件
 81      * @param file excel文件
 82      * @param startRow 起始行 0为第一行  第一行已经有 头了
 83      * @param columnKey  每列对应的key值
 84      * @return
 85      */
 86     private static List<RowData> parse2003Excel(File file, int startRow, String[] columnKey){
 87         List<RowData> rows = new ArrayList<RowData>();
 88         try {
 89             String fileName = file.getName();
 90             BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));//获取输入流
 91             HSSFWorkbook wk = new HSSFWorkbook(bis); // poi提供的类   工作簿
 92             HSSFSheet sheet = wk.getSheetAt(0);//获取一片?  工作表
 93             HSSFCell cell = null;
 94             for(int rowIndex=startRow; rowIndex<=sheet.getLastRowNum(); rowIndex++){  //getLastRowNum 获取最后一行的行号
 95                 HSSFRow row = sheet.getRow(rowIndex);  //获取行数据     
 96                 if(null==row){  //如果这行数据为空  继续
 97                     continue;
 98                 }
 99                 RowData rowData = new RowData(rowIndex+1);//起始是2  行数据存储对象初始化  
100                 List<CellData> cells = new ArrayList<CellData>();//  单元格s 对象存储对象初始化
101                 for(int columnIndex=0; columnIndex<columnKey.length; columnIndex++){  // 列个数
102                     String key = columnKey[columnIndex]; 
103                     String cellValue = "";
104                     cell = row.getCell(columnIndex); //获取独立单元格对象
105                     if(null!=cell){
106                         cell.setCellType(Cell.CELL_TYPE_STRING);//设置对象数据类型为String
107                         cellValue = cell.getStringCellValue(); // 获取数据   是String 因为上面转换了
108                     }
109                     if(!StringUtil.isBlank(cellValue)){
110                         cellValue = cellValue.trim(); //非空进行剪切
111                     }
112                     CellData cellData = new CellData(columnIndex+1, cellValue, key);//单元格数据对象实例化     参数有: 的列的位置   值   对应的列明  
113                     cells.add(cellData);  //添加到单元格s对象中去
114                 }
115                 rowData.setCells(cells);  // 行数据添加   cells  值
116                 rows.add(rowData); // 行数据列表 添加 行数据 
117             }
118             //关闭输入流
119             bis.close();
120         } catch (Exception e) {
121             e.printStackTrace();
122         }
123         return rows;  //rows 可以说是 内存中的转化好的表格格式正确文件内容对象 
124     }
125 
126     /**
127      * 解析2007 excel文件
128      * @param file excel文件
129      * @param startRow 起始行 0为第一行
130      * @param columnKey  每列对应的key值
131      * @return
132      */
133     private static List<RowData> parse2007Excel(File file, int startRow, String[] columnKey){
134         List<RowData> rows = new ArrayList<RowData>();
135         try {
136             String fileName = file.getName();
137             BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
138             XSSFWorkbook wb = new XSSFWorkbook(in);
139             XSSFSheet sheet = wb.getSheetAt(0);
140             XSSFCell cell = null;
141             for(int rowIndex=startRow; rowIndex<=sheet.getLastRowNum(); rowIndex++) {
142                 XSSFRow row = sheet.getRow(rowIndex);
143                 if(null==row){
144                     continue;
145                 }
146                 RowData rowData = new RowData(rowIndex+1);
147                 List<CellData> cells = new ArrayList<CellData>();
148                 for(int columnIndex=0; columnIndex<columnKey.length; columnIndex++){
149                     String key = columnKey[columnIndex];
150                     String cellValue = "";
151                     cell = row.getCell(columnIndex);
152                     cell.setCellType(Cell.CELL_TYPE_STRING);
153                     cellValue = cell.getStringCellValue();
154                     if(!StringUtil.isBlank(cellValue)){
155                         cellValue = cellValue.trim();
156                     }
157 
158                     CellData cellData = new CellData(columnIndex+1, cellValue, key);
159                     cells.add(cellData);
160                 }
161                 rowData.setCells(cells);
162                 rows.add(rowData);
163             }
164             //关闭输入流
165             in.close();
166         } catch (Exception e) {
167             e.printStackTrace();
168         }
169         return rows;
170     }
171 }
复制代码
复制代码
  1 public class Validator {
  2 
  3 
  4     /*public static void main(String[] args) {
  5         String mobile = "18412312313";
  6         String phone = "010-12312312";
  7         String username = "fdsdfsdj";
  8         System.out.println(Validator.isUsername(username));
  9         System.out.println(Validator.isChinese(username));
 10 
 11         String email = "zhangsan@163.com";
 12         System.out.println("isMobile="+Validator.isMobile(mobile));
 13         System.out.println("isPhone="+Validator.isPhone(phone));
 14         String regex = "^zo+$";
 15         String str = "zozo";
 16         boolean flag = Validator.testString(regex, str);
 17         System.out.println(flag);
 18     }
 19 
 20 */
 21     public static boolean testString(String regex, String str){
 22         return Pattern.matches(regex, str);
 23     }
 24 
 25 
 26     /**
 27      * 正则表达式:验证用户名
 28      */
 29     public static final String REGEX_USERNAME = "^[a-zA-Z]\\w{5,17}$";
 30 
 31     /**
 32      * 正则表达式:验证密码
 33      */
 34     public static final String REGEX_PASSWORD = "^[a-zA-Z0-9]{6,16}$";
 35 
 36     /**
 37      * 正则表达式:验证手机号
 38      */
 39     public static final String REGEX_MOBILE = "^((13[0-9])|(14[0-9])|(15[0-9])|(18[0-9])|(17[0-9]))\\d{8}$";
 40 
 41     /**
 42      * 正则表达式:验证固话
 43      */
 44     public static final String REGEX_PHONE = "^(0\\d{2}-\\d{8})|(0\\d{3}-\\d{7})|(0\\d{3}-\\d{8})$";
 45 
 46     /**
 47      * 正则表达式:验证qq
 48      */
 49     public static final String REGEX_QQ = "^[1-9][0-9]{4,} $";
 50 
 51     /**
 52      * 正则表达式:验证邮箱
 53      */
 54     public static final String REGEX_EMAIL = "^[A-Za-z0-9][\\w\\-\\.]{1,12}@([\\w\\\\-]+\\.)+[\\w]{2,3}$";
 55 
 56     /**
 57      * 正则表达式:验证汉字
 58      */
 59     public static final String REGEX_CHINESE = "^[\u4e00-\u9fa5],{0,}$";
 60 
 61     /**
 62      * 正则表达式:验证身份证
 63      */
 64     public static final String REGEX_ID_CARD = "(^\\d{18}$)|(^\\d{15}$)";
 65 
 66     /**
 67      * 正则表达式:验证URL
 68      */
 69 //    public static final String REGEX_URL = "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";
 70 
 71     /**
 72      * 正则表达式:验证IP地址
 73      */
 74     public static final String REGEX_IP_ADDR = "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)";
 75 
 76     /**
 77      * 校验用户名
 78      *
 79      * @param username
 80      * @return 校验通过返回true,否则返回false
 81      */
 82     public static boolean isUsername(String username) {
 83         return Pattern.matches(REGEX_USERNAME, username);
 84     }
 85 
 86     /**
 87      * 校验密码
 88      *
 89      * @param password
 90      * @return 校验通过返回true,否则返回false
 91      */
 92     public static boolean isPassword(String password) {
 93         return Pattern.matches(REGEX_PASSWORD, password);
 94     }
 95 
 96     /**
 97      * 校验手机号
 98      *
 99      * @param mobile
100      * @return 校验通过返回true,否则返回false
101      */
102     public static boolean isMobile(String mobile) {
103         return Pattern.matches(REGEX_MOBILE, mobile);
104     }
105 
106     /**
107      * 校验邮箱
108      *
109      * @param email
110      * @return 校验通过返回true,否则返回false
111      */
112     public static boolean isEmail(String email) {
113         return Pattern.matches(REGEX_EMAIL, email);
114     }
115 
116     /**
117      * 校验固话
118      * @param phone
119      * @return
120      */
121     public static boolean isPhone(String phone){
122         return Pattern.matches(REGEX_PHONE, phone);
123     }
124 
125     /**
126      * 校验qq
127      * @param qq
128      * @return
129      */
130     public static boolean isQQ(String qq){
131         return Pattern.matches(REGEX_QQ, qq);
132     }
133 
134     /**
135      * 校验汉字
136      *
137      * @param chinese
138      * @return 校验通过返回true,否则返回false
139      */
140     public static boolean isChinese(String chinese) {
141         return Pattern.matches(REGEX_CHINESE, chinese);
142     }
143 
144     /**
145      * 校验身份证
146      *
147      * @param idCard
148      * @return 校验通过返回true,否则返回false
149      */
150     public static boolean isIDCard(String idCard) {
151         return Pattern.matches(REGEX_ID_CARD, idCard);
152     }
153 
154     /**
155      * 校验URL
156      *
157      * @param url
158      * @return 校验通过返回true,否则返回false
159      */
160 //    public static boolean isUrl(String url) {
161 //        return Pattern.matches(REGEX_URL, url);
162 //    }
163 
164     /**
165      * 校验IP地址
166      *
167      * @param ipAddr
168      * @return
169      */
170     public static boolean isIPAddr(String ipAddr) {
171         return Pattern.matches(REGEX_IP_ADDR, ipAddr);
172     }
173 
174 
175 
176 }
复制代码

======================

下面是解析excle文档的  文档与内存对象的对应转换关系:

 

 

----ajax请求返回 后进行处理:

 

success: function (data, status) {//服务器成功响应处理函数
$('#uploadTxt').text('导入');
$('#loadingImg').hide();
if('success'==data.flag){
$('#btn_upSubmit').show();
$('#uploading').hide();
$('#btn_upCancel').trigger('click');
$("#orgUserTable").trigger("reloadGrid", [{page: 1}]);
var offedCount = data.OFFED_COUNT;
var rowCount = data.ROW_COUNT;
var offedData = data.OFFED_DATA;
var orgLicense = data.ORG_LICENSE;
var overLicense = data.OVER_LICENSE;
var actSize = data.ORG_ACTSIZE;
if(0<overLicense && 0!=orgLicense){//存在超出数据
$('#licenseNum').text(orgLicense);
$('#actNum').text(actSize);
$('#uploadMsg1').hide();
$('#uploadMsg2').show();
//显示错误信息
$('#showErrData').trigger('click');
} else {
if(0 != offedCount){
$('#totalCount').text(rowCount);
$('#errCount').text(offedCount);
$('#uploadMsg2').hide();
$('#uploadMsg1').show();
$('#err_body').find('tr').remove();
var errBody = $('#err_body');
for(var i=0; i<offedData.length; i++){
var tr = createTrObj();
var rowData = offedData[i];
var rowIndex = rowData.rowIndex;
var cells = rowData.cells;
$(tr).find('td[role="rowIndex"]').text(rowIndex);
for(var j=0; j<cells.length; j++){
var cell = cells[j];
var cellValue = cell.cellValue;
var extraInfo = cell.extraInfo;
var td;
switch(cell.key){
case 'userName':
td = $(tr).find('td[role="name"]').text(cellValue);
break;
case 'mobile':
td = $(tr).find('td[role="mobile"]').text(cellValue);
break;
case 'phone':
td = $(tr).find('td[role="phone"]').text(cellValue);
break;
case 'email':
td = $(tr).find('td[role="email"]').text(cellValue);
break;
case 'QQ':
td = $(tr).find('td[role="QQ"]').text(cellValue);
break;
case 'weixin':
td = $(tr).find('td[role="weixin"]').text(cellValue);
break;
case 'job':
td = $(tr).find('td[role="position"]').text(cellValue);
break;
case 'note':
td = $(tr).find('td[role="note"]').text(cellValue);
break;
default:

}
if(null!=extraInfo && ''!=extraInfo && 'undefined'!=extraInfo){
td.attr('class','font-rb');
if('userName'==cell.key){
td.attr('class','bggray');
}
if(('mobile'==cell.key||'email'==cell.key) && ''==cellValue){
td.attr('class','bggray');
}
td.attr('title',extraInfo);
}
}
$(tr).appendTo(errBody);
}
//显示错误信息
$('#showErrData').trigger('click');
} else {
swal({
title: "上传成功!",
//text: "点击下方按钮关闭提示框!",
type: "success"
});
}
}

}
},展示相关错误信息
文件内容为:

上传过程:


上传后返回:

结果为:

 


2012-03-26 16:27:55 zhanghe086 阅读数 376
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森
试共同条件:
数据总数为110011条,每条数据条数为19个字段。

一、POI、JXL、FastExcel比较
POI、JXL、FastExcel均为java第三方开源导出Excel的开源项目。

导出方案一:一次性全部导出到一个Excel文件中。
实际情况均报OutOfMemery错误,以下数据为报OutOfMemery数据时,数据到的最大数据数目,如表1所示:
表1:报OutOfMemery错误时所能处理的数据量
FastExecl POI JXL
10000数据/sheet 37465 28996 42270
5000数据/sheet 39096 31487 46270
3000数据/sheet 39000 32493 47860

小结:
多分sheet能一定程度上减少内存的使用,但是均因为程序中创建的Cell(即为Excel中的一个单元格)无法释放,消耗大量内存,导致OutOfMemery错误;JXL表现最好,创建Cell内存使用较少。

导出方案二:先分多个Excel文件将数据全部导出,然后对多个Excel文件进行合并。
首先,测试将全部数据导出所用的时间,如表2所示,数据均测试三次取平均。
表2:导出全部数据所用时间

FastExecl POI JXL
10000数据/文件 68s 33s 30s
5000数据/文件 68s 32s 33s
3000数据/文件 59s 33s 39s

小结:
均成功导出Excel文件,原因是导出一个Excel文件,释放所占用的创建Cell的内存。
FastExecl表现最差,POI表现稳定,JXL随着数据的增大,速度一定程度上增快。

然后,进行整合,由于将多Excel合并成一个Excel文件的功能只有POI所有,故使用POI测试,结果如表3所示。
注:数据量大合并还会报OutOfMemery错误,故合并总数据量以5万为准。
表3:合并5万数据所用时间
时间
10000数据/文件 11s
5000数据/文件 11s
3000数据/文件 11s

小结:
使用POI对文件进行合并速度较快,但有数据量的限制。


总结:方案二比较可行,但是数据量有限制,为5万条。


二、导出XML 的电子表格
导出的格式类似为纯文本,能实现大数据量的存储,并能实现分Sheet查看,且能添加简单的样式,符合项目要求。经实际测试Excel2003和Excel2007均能识别并正常打开查看。使用时间测试如表4所示,数据均测试3次取平均。
表4:生成全部数据所用时间
时间
10000数据/sheet 28.0秒
20000数据/sheet 30.1秒
30000数据/sheet 28.1秒
40000数据/sheet 26.5秒
50000数据/shee 28.2秒
55000数据/sheet 26.8秒
59000数据/sheet 30.1秒
59500数据/sheet 发生假死机现象
60000数据/sheet 发生假死机现象


但是导出的数据为XML不是纯正的Excel文件,如使用Excel文件的xls后缀保存,打开文件会弹出警告,但不影响阅读。
且经实际测试,在Access2007和Access2003中可通过导入外部数据的方式,将导出的XML导入进Access数据库。

三、总结
项目要求是大数据量导出Excel文件,POI、JXL、FastExcel不能完全满足要求;使用XML 的电子表格导出实现了大数据量导出,但是格式为XML不是纯正的Excel文件,为曲线救国。两种导出形式的比较,如表5所示。
表5:合并5万数据所用时间
POI、JXL、FastExcel XML 的电子表格
导出数据格式 为纯Execl文件 为XML文件
导出数据量 小 较大
能否分Sheet 能 能
能否添加样式 能 能
能否添加图片 POI 能 不能
导出数据能否导入Access 能 能

提高JVM的大小几乎没效果……
没有更多推荐了,返回首页