23.04.2014

Загрузка и распарсивание файла xls с помощью Java-based concurrent

Цель: прочитать файл электронной таблицы Excel 95-2003 и загрузить результат в таблицу БД Oracle 11g. В нашем примере мы хотим прочитать данные из одной ячейки и положить их в таблицу create table HF_TMP (val VARCHAR2(50))
Алгоритм решения:
1. Загрузка файла через пользовательский интерфейс. Применяется messageFileUploadBean с типом данных BLOB. 

При нажатии кнопки Загрузить происходит вставка записи в таблицу загрузок вместе с бинарным файлов Excel в blob-поле, присваивание upload_id и запуск Java-based канкарента, в который этот upload_id передается.
CO:
Serializable[] aserializable = { uploadId };
Class[] aclass = { uploadId.getClass() };
String requestId = (String)am.invokeMethod("sendConcurrentRequest", aserializable, aclass);
am.getTransaction().commit();
AM:
public void sendConcurrentRequest(Number uploadId) throws RequestSubmissionException {
  ConcurrentRequest cpRequest = new ConcurrentRequest(this.getOADBTransaction().getJdbcConnection());
  Vector requestParameters = new Vector(1);
  requestParameters.add(uploadId.stringValue());
  int requestId = cpRequest.submitRequest(UploadHistFactBean.APPLICATION_SHORT_NAME, UploadHistFactBean.CONCURRENT_PROGRAM_NAME, null, null, false, requestParameters);
}
2. Работа канкарента
    // считываем BLOB
    public InputStream getFileForUploadId(){
        StringBuffer strBuf = new StringBuffer();
        InputStream dataStream = null;
        String lQuery = "select file_data from DATA_UPLOADS where request_id = :1";
        String res = "";
        try
        {
          OracleCallableStatement statement = (OracleCallableStatement)connection.prepareCall(lQuery);
          statement.setInt(1, requestId);
          ResultSet resultSet = statement.executeQuery();
          while (resultSet.next()) {                  
              BLOB blob = ((OracleResultSet)resultSet).getBLOB(1);
              dataStream = blob.getBinaryStream();
          }       
        } catch (SQLException e)
        {
          throw OAException.wrapperException(e);
        }
        return dataStream;
    }
    public void initialize(CpContext cpContext) throws SQLException,
                                                       XMLParseException,
                                                       SAXException,
                                                       IOException,
                                                       InstantiationException,
                                                       IllegalAccessException,
                                                       ClassNotFoundException,
                                                       NoSuchMethodException,
                                                       InvocationTargetException     {
        connection = cpContext.getJDBCConnection();
        requestId = cpContext.getReqDetails().getRequestId();
        logFile = cpContext.getLogFile();
        reqCompletion = cpContext.getReqCompletion();
        NameValueType parameter;
        while (cpParameters.hasMoreElements()) {
         parameter = cpParameters.nextParameter();
          if ("p_upload_id".equalsIgnoreCase(parametr.getName())) {
          this.uploadId = Integer.valueOf(parametr.getValue()).intValue();
        }
    }
    public void runProgram(CpContext cpContext) {
        try {
            initialize(cpContext);
            HashMap<String, String> inputParameters = new HashMap<String, String>();
            inputParameters.put(DataInput.PARAMETER_PREFIX + "1",                                   "oracle.apps.xxmy.test.bean.TemplateXML");
            InputStream file = getFileForUploadId();

            { логика по распарсиванию файла Excel }
            connection.commit();

            // Успешно завершим конкаррент
            Message normComplMessage = new Message("FND", "CONC-CP SUCCESSFUL TERMINATION");
            reqCompletion.setCompletion(ReqCompletion.NORMAL, normComplMessage.getMessageText(cpContext.getResourceStore()));
        } catch (Exception e) {
            // Если произошла ошибка, нужно выставить конкаренту ошибочный статус и выдать в лог стек ошибки
            reqCompletion.setCompletion(ReqCompletion.ERROR, e.getMessage());
            StringWriter errStringWriter = new StringWriter();
            PrintWriter errPrintWriter = new PrintWriter(errStringWriter, true);
            e.printStackTrace(errPrintWriter);
            logFile.writeln(errStringWriter.toString(), LogFile.ERROR);
        } finally {
            cpContext.releaseJDBCConnection();
        }
    }
3. Распарсивание XLS с помощью библиотеки POI. Шаблон oracle.apps.xxmy.test.bean.TemplateXML из шага 2 содержит набор параметров для вызова API вставки в таблицу с указанием данных о том, в каких ячейках брать значения. В нашем случае:
<?xml version="1.0" encoding='windows-1251'?>
<upload method="XXMY_TEST_PKG.upload_excel">
 <element name="test" type="single">
  <location src="sheet" sheet="Sheet1" row="0" col="0"/>
 </element>
</upload>
Пробегаясь по структуре данных и файлу данных, мы формируем вызов API:
begin XXMY_TEST_PKG.upload_excel(P_TEST => :1, P_REQUEST_ID => :2, P_UPLOAD_ID => :3, P_UPLOAD_METHOD => :4); end;
Имея коллекции параметров и их значений, выполняем вызов:
    public void doDbUpload() throws SQLException {
        OracleCallableStatement statement = (OracleCallableStatement)connection.prepareCall(this.query);
        ArrayList<Integer> keyList = new ArrayList<Integer>();
        keyList.addAll(uploadParameters.keySet());
        Collections.sort(keyList);
        Iterator<Integer> parameterIterator = keyList.iterator();
        while (parameterIterator.hasNext()) {
            Integer parameterIndex = parameterIterator.next();
            UploadParameter parameter = this.uploadParameters.get(parameterIndex);
            statement.setString(parameterIndex.intValue(), parameter.getValue());
        }
        statement.execute();
        statement.close();
    }
Всё. Данные из файла отправляются в таблицу.