让Unitils实现excel下的多数据源支持

说明:这里的多数据源需要利用spring中配置的多个DataSource.而且仅针对oracle数据库. 在oracle有一个schema的概念, 一个datasource下可能有多个schema, 而一个schema一般会跟一组用户名密码绑定, 这里我们采用用户名作为schema名称.
为了实现对多schema的支持, unitils提供了一个 MultiSchemaXmlDataSetFactory, 也就是在采用xml的格式来实现多数据源的创建, 但不知道为什么原因, 没有提供对excel格式的多schema的支持, 而对于所有测试都采用excel来构造测试数据用户来说, 则显得有些无奈, 为了实现这个功能, 了解了一下unitils-dbunit, dbunit相关的源代码, 不过有些困难, 一个是dbunit提供的接口对我们的扩展有一些限制. 比如我们希望我们在excel中定义测试数据的时候, 每个sheet的名称将采用"datasourceName.tablename"的约定来定义. 因此我们必须在解析excel文件的时候, 必须从中已有的table中解析出datasource和tablename.
废话少说, 其具体做法是: 在从excel中取得DataSet之后(一个excel对应一个DataSet, 一个Sheet对应一个Table), 将DataSet中的所有Table根据datasource名称进行重组, 然后将得到的多个DataSet用MultiSchemaDataSet进行封装. 而 MultiSchemaXlsDataSetFactory类的工作就是为了创建这个MultiSchemaDataSet.
/**
* 需要在unitils.properties文件中将<tt>DbUnitModule.DataSet.factory.default</tt>属性名设置为该类全限定名.
* 
 * @author lengda
 * @since 2009-12-3 下午04:15:29
 */
public class MultiSchemaXlsDataSetFactory implements DataSetFactory {
    private static Pattern pattern = Pattern.compile("\\.");
    protected String defaultSchemaName;

    public void init(Properties configuration, String defaultSchemaName) {
        this.defaultSchemaName = defaultSchemaName;
    }

    public MultiSchemaDataSet createDataSet(File... dataSetFiles) {
        Map<String, List<ITable>> tableMap = getTables(dataSetFiles);

        MultiSchemaDataSet dataSets = new MultiSchemaDataSet();
        for (Entry<String, List<ITable>> entry : tableMap.entrySet()) {
            List<ITable> tables = entry.getValue();
            try {
                DefaultDataSet ds = new DefaultDataSet(tables.toArray(new ITable[] {}));
                dataSets.setDataSetForSchema(entry.getKey(), ds);
            } catch (AmbiguousTableNameException e) {
                throw new UnitilsException(String.format("使用指定表[%s]重新构造DataSet失败", tables), e);
            }
        }

        return dataSets;
    }

    private Map<String, List<ITable>> getTables(File... dataSetFiles) {
        Map<String, List<ITable>> tableMap = new HashMap<String, List<ITable>>();
        // 需要根据schema把Table重新组合一下
        try {
            for (File file : dataSetFiles) {
                IDataSet dataSet = new XlsDataSet(new FileInputStream(file));
                String[] tableNames = dataSet.getTableNames();
                for (String each : tableNames) {
                    // 这个实际上不是schema, 是对应的spring的datasouceId
                    String schema = null;
                    String tableName;
                    String[] temp = pattern.split(each);
                    if (temp.length == 2) {
                        schema = temp[0];
                        tableName = temp[1];
                    } else {
                        schema = this.defaultSchemaName;
                        tableName = each;
                    }

                    ITable table = dataSet.getTable(each);
                    if (!tableMap.containsKey(schema)) {
                        tableMap.put(schema, new ArrayList<ITable>());
                    }
                    tableMap.get(schema).add(new XslTableWrapper(tableName, table));
                }
            }
        } catch (Exception e) {
            throw new UnitilsException("Unable to create DbUnit dataset for data set files: "
                    + Arrays.toString(dataSetFiles), e);
        }
        return tableMap;
    }

    public String getDataSetFileExtension() {
        return "xls";
    }

}


为了对XslTable重新进行封装, 使用了下面的类来处理去掉datasource后的tablename, 因为在执行过程中 ITableMetaData会使用到表名, 而这个表名我们是没办法通过继承来进行修改的, 只能通过代理的形式了.
/**
* 为了获得strip datasource后的表名
* 
 * @author lengda
 * @since 2009-12-3 下午06:44:36
 */
class XslTableWrapper extends AbstractTable {
    private ITable delegate;
    private String tableName;

    public XslTableWrapper(String tableName, ITable table) {
        this.delegate = table;
        this.tableName = tableName;
    }
    public int getRowCount() {
        return delegate.getRowCount();
    }

    public ITableMetaData getTableMetaData() {
        ITableMetaData meta = delegate.getTableMetaData();
        try {
            return new DefaultTableMetaData(tableName, meta.getColumns(), meta.getPrimaryKeys());
        } catch (DataSetException e) {
            throw new UnitilsException("Don't get the meta info from  " + meta, e);
        }
    }

    public Object getValue(int row, String column) throws DataSetException {
        Object delta = delegate.getValue(row, column);
        if (delta instanceof String) {
            if (StringUtils.isEmpty((String) delta)) {
                return null;
            }
        }
        return delta;
    }

}


另外目前本人使用的unitls版本为3.1, 而在其内部依赖的dbunit版本为2.2.2, 这个版本使用解析excel的poi版本在处理excel中cell的格式为日期的时候, 会有问题, 需要指定一下dbunit的最新版本2.4.6, 在maven中的依赖配置:
        <dependency>
          <groupId>org.unitils</groupId>
          <artifactId>unitils-dbunit</artifactId>
          <version>${unitils.version}</version>
          <exclusions>
            <exclusion>
                <groupId>org.dbunit</groupId>
                <artifactId>dbunit</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.1-FINAL</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.dbunit</groupId>
            <artifactId>dbunit</artifactId>
            <version>2.4.6</version>
            <scope>compile</scope>
        </dependency>

你可能感兴趣的:(spring,oracle,maven,xml,Excel)