poi是一个excel的文件的解析引擎,我目前接触到的就两种文件格式xsl,xlsx,xsl是早先版本的excel文件格式,xlsx是后期版本的规范
poi解析引擎的解析速度是非常快的,一般2000条数据200多毫秒就解析完成了,但是这带来的是巨大的内存消耗,当文件过大,或者多人同时使用这个引擎
这个时候就容易导致内存不足而溢出,使得java虚拟机抛出OutOfMemory的异常
解决的办法可以使用poi中基于事件的解析方案,在usereventmodel这个包下,分别有hssf和xssf这两种解析的方式:
其中当使用的是解析xsl这种格式的文件的时候我们使用的是一个Listener的封装好的类来读取相应的文件,这个的话消耗内存大概比excel文件大小大10%;
当我们使用的是xlsx这种的时候,因为这种格式的文件已经使用XML格式规范了,这个时候,使用基于sax读流的方式非常的省内存,所以对这个类进行封装就可以了。
所以在对文档进行基于流方式的读取的时候,我们必须分开来考虑,分别编写他们的解析类,xls和xlsx格式
面对不同的业务逻辑,我们要对解析类进行不同种类的封装,这个过程当中由于解析逻辑的代码可能很长,这个时候我们要防止我们的方法过于冗长,一定要注意使得方法不要太大,这样也有利于栈内存的合理使用。
另外对于poi,除了内存溢出问题,还有格式转换问题,空格问题。
在解析的具体业务逻辑上,我们可以在我们的javabean上使用一个注解来描述我们的javabean的一些对excel中数据的规范性声明,这样我们在解析excel的时候,就可以对他们进行验证,防止在excel中解析的数据违反了我们数据库中的约束而导致不可预知的异常,降低后期维护存在的风险。
其实还有一种解决方案,就是通过限制上传文件的大小,和同时上传文件的人数来达到目的,那么这个时候我们要怎么来实现呢?
首先是限制文件的大小,我们可以在Struts的action中对文件的大小进行判断,这个时候限制不能大于多少,大于了就不让他上传
第二个是限制同时上传的人数,这个我们可以在我们的工具类中写一个基于数量的锁,在我们的action中使用这个锁,当然如果要做的好点,我们可以使用AOP来加锁,灵活性更高。
在项目中我使用了第二种方案,第一种方案复杂,需要重构,风险大,维护也困难;
第二种方案简单,技术风险小,维护简单。可配置参数来对系统进行调优。