[dataexchange]完善Excel导入xlsx格式实现

This commit is contained in:
datagear 2019-07-30 21:57:33 +08:00
parent 64b25cf1a2
commit f9af08b509
5 changed files with 301 additions and 18 deletions

View File

@ -21,7 +21,7 @@ public class ExcelDataImport extends TextValueDataImport
{
private File file;
private boolean xlsx = true;
private boolean xls = false;
private String unifiedTable;
@ -37,7 +37,7 @@ public class ExcelDataImport extends TextValueDataImport
this.file = file;
String fileName = this.file.getName().toLowerCase();
this.xlsx = (!fileName.endsWith(".xls"));
this.xls = fileName.endsWith(".xls");
}
public File getFile()
@ -51,18 +51,18 @@ public class ExcelDataImport extends TextValueDataImport
}
/**
* 是否是{@code .xlsx}文件
* 是否是{@code .xls}文件
*
* @return {@code true}{@code .xlsx}文件{@code false} {@code .xls}文件
* @return {@code true}{@code .xls}文件{@code false} {@code .xlsx}文件
*/
public boolean isXlsx()
public boolean isXls()
{
return xlsx;
return xls;
}
public void setXlsx(boolean xlsx)
public void setXls(boolean xls)
{
this.xlsx = xlsx;
this.xls = xls;
}
/**

View File

@ -4,6 +4,7 @@
package org.datagear.dataexchange.support;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Types;
@ -24,14 +25,27 @@ import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.DateUtil;
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.model.StylesTable;
import org.datagear.dataexchange.AbstractDevotedDbInfoAwareDataExchangeService;
import org.datagear.dataexchange.DataExchangeContext;
import org.datagear.dataexchange.DataExchangeException;
import org.datagear.dataexchange.IndexFormatDataExchangeContext;
import org.datagear.dbinfo.ColumnInfo;
import org.datagear.dbinfo.DatabaseInfoResolver;
import org.datagear.util.IOUtil;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* Excel导入服务
@ -65,14 +79,10 @@ public class ExcelDataImportService extends AbstractDevotedDbInfoAwareDataExchan
Connection cn = context.getConnection();
cn.setAutoCommit(false);
POIFSFileSystem poifs = new POIFSFileSystem(dataExchange.getFile(), true);
HSSFRequest req = new HSSFRequest();
req.addListenerForAllRecords(
new MissingRecordAwareHSSFListener(new XlsEventListener(dataExchange, importContext, cn)));
HSSFEventFactory factory = new HSSFEventFactory();
factory.processWorkbookEvents(req, poifs);
if (dataExchange.isXls())
importXls(dataExchange, importContext, cn);
else
importXlsx(dataExchange, importContext, cn);
commit(cn);
}
@ -86,6 +96,89 @@ public class ExcelDataImportService extends AbstractDevotedDbInfoAwareDataExchan
super.onException(dataExchange, context, e);
}
/**
* 导入{@code .xls}文件
*
* @param dataExchange
* @param importContext
* @param cn
* @throws Throwable
*/
protected void importXls(ExcelDataImport dataExchange, IndexFormatDataExchangeContext importContext, Connection cn)
throws Throwable
{
POIFSFileSystem poifs = new POIFSFileSystem(dataExchange.getFile(), true);
HSSFRequest req = new HSSFRequest();
req.addListenerForAllRecords(
new MissingRecordAwareHSSFListener(new XlsEventListener(dataExchange, importContext, cn)));
HSSFEventFactory factory = new HSSFEventFactory();
factory.processWorkbookEvents(req, poifs);
}
/**
* 导入{@code .xlsx}文件
*
* @param dataExchange
* @param importContext
* @param cn
* @throws Throwable
*/
protected void importXlsx(ExcelDataImport dataExchange, IndexFormatDataExchangeContext importContext, Connection cn)
throws Throwable
{
OPCPackage opcPackage = OPCPackage.open(dataExchange.getFile(), PackageAccess.READ);
importContext.addContextCloseable(opcPackage);
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(opcPackage);
XSSFReader xssfReader = new XSSFReader(opcPackage);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
int index = 0;
while (iter.hasNext())
{
InputStream in = null;
try
{
in = iter.next();
String sheetName = iter.getSheetName();
importXlsxSheet(strings, styles, sheetName, index, in);
}
finally
{
IOUtil.close(in);
}
index++;
}
}
/**
* 导入{@code .xlsx}单个sheet
*
* @param sharedStringsTable
* @param stylesTable
* @param sheetName
* @param sheetIndex
* @param sheetInputStream
* @throws Throwable
*/
public void importXlsxSheet(ReadOnlySharedStringsTable sharedStringsTable, StylesTable stylesTable,
String sheetName, int sheetIndex, InputStream sheetInputStream) throws Throwable
{
InputSource sheetSource = new InputSource(sheetInputStream);
XMLReader sheetParser = SAXHelper.newXMLReader();
ContentHandler handler = new XlsxSheetHandler(stylesTable, sharedStringsTable, sheetName, sheetIndex);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
}
/**
* {@code .xls}格式的Excel处理器
*
@ -364,4 +457,138 @@ public class ExcelDataImportService extends AbstractDevotedDbInfoAwareDataExchan
return true;
}
}
protected class XlsxSheetHandler extends DefaultHandler
{
private StylesTable stylesTable;
private ReadOnlySharedStringsTable sharedStringsTable;
private String sheetName;
private int sheetIndex;
private int _rowIndex = 0;
private int _nextRowIndex = 0;
private StringBuilder _lastContents = new StringBuilder();
private boolean _nextIsString;
public XlsxSheetHandler()
{
super();
}
public XlsxSheetHandler(StylesTable stylesTable, ReadOnlySharedStringsTable sharedStringsTable,
String sheetName, int sheetIndex)
{
super();
this.stylesTable = stylesTable;
this.sharedStringsTable = sharedStringsTable;
this.sheetName = sheetName;
this.sheetIndex = sheetIndex;
}
public StylesTable getStylesTable()
{
return stylesTable;
}
public void setStylesTable(StylesTable stylesTable)
{
this.stylesTable = stylesTable;
}
public ReadOnlySharedStringsTable getSharedStringsTable()
{
return sharedStringsTable;
}
public void setSharedStringsTable(ReadOnlySharedStringsTable sharedStringsTable)
{
this.sharedStringsTable = sharedStringsTable;
}
public String getSheetName()
{
return sheetName;
}
public void setSheetName(String sheetName)
{
this.sheetName = sheetName;
}
public int getSheetIndex()
{
return sheetIndex;
}
public void setSheetIndex(int sheetIndex)
{
this.sheetIndex = sheetIndex;
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException
{
if ("row".equals(name))
{
String rowIndexStr = attributes.getValue("r");
if (rowIndexStr != null)
{
this._rowIndex = Integer.parseInt(rowIndexStr) - 1;
}
else
{
this._rowIndex = this._nextRowIndex;
}
}
else if ("c".equals(name))
{
String cellType = attributes.getValue("t");
if (cellType != null && cellType.equals("s"))
{
_nextIsString = true;
}
else
{
_nextIsString = false;
}
}
if (this._lastContents.length() > 0)
this._lastContents.delete(0, this._lastContents.length());
System.out.println("Sheet [" + this.sheetName + "] start element :" + localName + ", " + name);
}
@Override
public void endElement(String uri, String localName, String name) throws SAXException
{
if ("row".equals(name))
{
this._nextRowIndex = this._rowIndex + 1;
}
if (_nextIsString)
{
int idx = Integer.parseInt(this._lastContents.toString());
this._lastContents.delete(0, this._lastContents.length());
this._lastContents.append(sharedStringsTable.getEntryAt(idx));
_nextIsString = false;
}
if (name.equals("v"))
{
System.out.println("[row=" + this._rowIndex + "] : " + this._lastContents);
}
System.out.println("Sheet [" + this.sheetName + "] end element :" + localName + ", " + name);
}
@Override
public void characters(char[] ch, int start, int length)
{
this._lastContents.append(new String(ch, start, length));
}
}
}

View File

@ -43,7 +43,7 @@ public class ExcelDataImportServiceTest extends DataexchangeTestSupport
}
@Test
public void exchangeTest() throws Throwable
public void exchangeTest_xls() throws Throwable
{
DataFormat dataFormat = new DataFormat();
@ -77,7 +77,7 @@ public class ExcelDataImportServiceTest extends DataexchangeTestSupport
}
@Test
public void exchangeTest_ignoreInexistentColumn() throws Throwable
public void exchangeTest_xls_ignoreInexistentColumn() throws Throwable
{
DataFormat dataFormat = new DataFormat();
@ -132,6 +132,62 @@ public class ExcelDataImportServiceTest extends DataexchangeTestSupport
}
}
@Test
public void exchangeTest_xlsx_ignoreInexistentColumn() throws Throwable
{
DataFormat dataFormat = new DataFormat();
Connection cn = getConnection();
try
{
cn = getConnection();
File excelFile = getClasspathFileForTest(
"org/datagear/dataexchange/support/ExcelDataImportServiceTest.xlsx");
final AtomicInteger successCount = new AtomicInteger(0);
final AtomicInteger ignoreCount = new AtomicInteger(0);
ValueDataImportOption valueDataImportOption = new ValueDataImportOption(ExceptionResolve.ABORT, true, true);
ExcelDataImport impt = new ExcelDataImport(new SimpleConnectionFactory(cn, false), dataFormat,
valueDataImportOption, excelFile);
impt.setListener(new MockValueDataImportListener()
{
@Override
public void onSuccess(DataIndex dataIndex)
{
super.onSuccess(dataIndex);
successCount.incrementAndGet();
}
@Override
public void onIgnore(DataIndex dataIndex, DataExchangeException e)
{
super.onIgnore(dataIndex, e);
ignoreCount.incrementAndGet();
}
});
clearTable(cn, TABLE_NAME_DATA_IMPORT);
clearTable(cn, TABLE_NAME_DATA_EXPORT);
this.excelDataImportService.exchange(impt);
int count0 = getCount(cn, TABLE_NAME_DATA_IMPORT);
int count1 = getCount(cn, TABLE_NAME_DATA_EXPORT);
assertEquals(5, count0);
assertEquals(6, count1);
}
finally
{
JdbcUtil.closeConnection(cn);
}
}
protected File getClasspathFileForTest(String classpath)
{
if (!classpath.startsWith("/"))