"OAF上传大批量EXCEL文件"
2013-04-09(Tuesday) 00:00
客户有个需求:大量数据通过EXCEL导入系统表,并能提供效验及去重功能。
设计思路
- 采用POI解析EXCEL文件;
- bulk insert 插入数据到临时表
- 临时表结合正式表去除重复
POI解析EXCEL
在CO的processFormRequest
方法中添加如下:
{% codeblock lang:java %}
public void processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
super.processFormRequest(pageContext, webBean);
OAApplicationModule am = pageContext.getApplicationModule(webBean);
if (pageContext.getParameter("uploadBtn") != null)
{
DataObject fileUploadData = (DataObject)pageContext.getNamedDataObject("uploadFile");
String fileName = null;
try {
fileName = (String)fileUploadData.selectValue(null, "UPLOAD_FILE_NAME");
} catch(NullPointerException ex)
{
throw new OAException("请先选择需要上传的文件", OAException.INFORMATION);
}
if(fileName.endsWith(".xlsx"))
{
throw new OAException("不支持高版本EXCEL文件,请转换成2003版本的EXCEL再上传",OAException.WARNING);
}else if(!fileName.endsWith(".xls"))
{
throw new OAException("请上传EXCEL类型文件",OAException.ERROR);
}
BlobDomain uploadedByteStream = (BlobDomain)fileUploadData.selectValue(null, fileName);
Serializable aserializable2[] = {uploadedByteStream};
Class aclass2[] = {BlobDomain.class };
am.invokeMethod("importFile", aserializable2,aclass2);
}
}
在AM中编写importFile方法
{% codeblock lang:java %} public void importFile(BlobDomain fileData) { InputStream inStr = fileData.getInputStream(); HSSFWorkbook workbook=null; try{ workbook= new HSSFWorkbook(inStr); }catch(java.io.IOException e) { throw new OAException("读取上传的文件出错,请检查上传的文件是否为97-2003版本的EXCEL可读文件.",OAException.ERROR); } //信号1 if(workbook==null) { throw new OAException("ERROR001:workbook为空,请重新上传文件.",OAException.ERROR); } HSSFSheet sheet1 = workbook.getSheet("1"); if(sheet1==null) { throw new OAException("ERROR002:sheet1为空,上传文件中找不到名字为'1'的工作表,请检查工作表命名是否符合规则.",OAException.ERROR); } int rowCount1 = sheet1.getLastRowNum(); int realCount1=0;
Object[] o_vin1=new Object[rowCount1],
o_type1=new Object[rowCount1],
o_color1=new Object[rowCount1],
o_date1=new Object[rowCount1],
o_des1=new Object[rowCount1];
String vin1=null,type1=null,color1=null;
java.util.Date vdate1=null;
for (int r1=1; r1 <= rowCount1; r1++)
{
HSSFRow tempRow1=sheet1.getRow(r1);
if(tempRow1==null)
{
throw new OAException("INFO:sheet[1]中第"+(r1+1)+"行数据异常,请检查上传文件",OAException.INFORMATION);
}
if(tempRow1.getCell((short)0)==null||tempRow1.getCell((short)0).getStringCellValue()==null||"".equals(tempRow1.getCell((short)0).getStringCellValue().trim()))
{
throw new OAException("INFO:sheet[1]中第"+(r1+1)+"行第1列数据异常,请检查上传文件",OAException.INFORMATION);
}
if(tempRow1.getCell((short)1)==null||tempRow1.getCell((short)1).getStringCellValue()==null)
{
throw new OAException("INFO:sheet[1]中第"+(r1+1)+"行第2列数据异常,请检查上传文件",OAException.INFORMATION);
}
if(tempRow1.getCell((short)2)==null||tempRow1.getCell((short)2).getStringCellValue()==null)
{
throw new OAException("INFO:sheet[1]中第"+(r1+1)+"行第3列数据异常,请检查上传文件",OAException.INFORMATION);
}
if(tempRow1.getCell((short)3)==null||tempRow1.getCell((short)3).getDateCellValue()==null)
{
throw new OAException("INFO:sheet[1]中第"+(r1+1)+"行第4列数据异常,请检查上传文件",OAException.INFORMATION);
}
vin1=tempRow1.getCell((short)0).getStringCellValue().trim();
type1=tempRow1.getCell((short)1).getStringCellValue().trim();
color1=tempRow1.getCell((short)2).getStringCellValue().trim();
vdate1=tempRow1.getCell((short)3).getDateCellValue();
o_vin1[r1-1]=vin1;
o_type1[r1-1]=type1;
o_color1[r1-1]=color1;
o_date1[r1-1]=new oracle.jbo.domain.Date(new java.sql.Date(vdate1.getTime()));
o_des1[r1-1]=null;
realCount1++;
}
List exceptions = new ArrayList();
exceptions.add(new OAException("解析出上传EXCEL文件中信号1表"+realCount1+"条记录",OAException.INFORMATION ));
//bulkinsert...
exceptions.add(new OAException("开始插入信号1临时表",OAException.INFORMATION ));
String result=this.bulkInsert1(o_vin1,o_type1,o_color1,o_date1,o_des1);
exceptions.add(new OAException("结果:"+result,OAException.INFORMATION ));
exceptions.add(new OAException("结束插入信号1临时表",OAException.INFORMATION ));
OAException.raiseBundledOAException(exceptions);
}
OAF调用bulk insert插入大批量数据
{% codeblock lang:java %}
public String bulkInsert1(Object[] vin,Object[] type,Object[] color,Object[] vdate, Object[] des)
{
CallableStatement st = null;
String result="";
String stmt = "{ call ch_report_pkg.INSERTREPORT1(?,?,?,?,?,?) }";
try {
st=this.getDBTransaction().createCallableStatement(stmt,0);
ArrayDescriptor T_VARCHAR30=null,
T_VARCHAR10=null,
T_VARCHAR200=null,
T_DATE=null;
ARRAY a_vin=null,a_type=null,a_color=null,a_vdate=null,a_des=null;
T_VARCHAR30=oracle.sql.ArrayDescriptor.createDescriptor("T_VARCHAR30",st.getConnection());
T_VARCHAR10=oracle.sql.ArrayDescriptor.createDescriptor("T_VARCHAR10",st.getConnection());
T_VARCHAR200=oracle.sql.ArrayDescriptor.createDescriptor("T_VARCHAR200",st.getConnection());
T_DATE=oracle.sql.ArrayDescriptor.createDescriptor("T_DATE",st.getConnection());
a_vin=new ARRAY(T_VARCHAR30,st.getConnection(),vin);
a_type=new ARRAY(T_VARCHAR30,st.getConnection(),type);
a_color=new ARRAY(T_VARCHAR10,st.getConnection(),color);
a_vdate=new ARRAY(T_DATE,st.getConnection(),vdate);
a_des=new ARRAY(T_VARCHAR200,st.getConnection(),des);
st.setArray(1,a_vin);
st.setArray(2,a_type);
st.setArray(3,a_color);
st.setArray(4,a_vdate);
st.setArray(5,a_des);
st.registerOutParameter(6, OracleTypes.VARCHAR);
st.execute();
result=st.getString(6);
return result;
} catch (Exception e) {
throw new JboException(e);
} finally {
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
{% endcodeblock %}
将POI解析出来的数据,包装成Object对象作为参数传递给数据库ch_report_pkg包中的INSERTREPORT1方法,bulk insert到数据库,极大地提高了插入数据效率。 {% codeblock lang:sql %} PROCEDURE INSERTREPORT1(I_VIN IN T_VARCHAR30, I_CAR_TYPE IN T_VARCHAR30, I_COLOR IN T_VARCHAR10, I_VDATE IN T_DATE, I_DES IN T_VARCHAR200, MESSAGE OUT VARCHAR2) IS I INTEGER; BEGIN DELETE FROM CH_REPORT_1_TEMP; COMMIT; FORALL I IN 1 .. I_VIN.COUNT INSERT INTO CH_REPORT_1_TEMP (VIN, CAR_TYPE, COLOR, VDATE, DESCRIPTION) VALUES (I_VIN(I), I_CAR_TYPE(I), I_COLOR(I), I_VDATE(I), I_DES(I)); MESSAGE := I_VIN.COUNT || '条数据正常插入!'; COMMIT; EXCEPTION WHEN OTHERS THEN MESSAGE := '出现异常,错误代码如下:' || SQLERRM; ROLLBACK; END;
此外,需要先根据表结构定义出字段类型如下: {% codeblock lang:sql %} create or replace TYPE T_VARCHAR30 IS TABLE OF VARCHAR2(30); create or replace TYPE T_VARCHAR10 IS TABLE OF VARCHAR2(10); create or replace TYPE T_VARCHAR200 IS TABLE OF VARCHAR2(200); create or replace TYPE T_DATE IS TABLE OF DATE;
那么数据就顺利批量插入到临时表中了。
数据去除重复
需要根据插入数据的主键VIN判断是否跟数据库中存在的数据重复,
在程序中对比的话效率很低,所以采用在数据库中通过语句
select count(vin) from (table union temp_table) group by vin
来判断,count数量大于1表示有重复。