2016-05-03 12 views
1

である私は、JSF 2.3を使用してファイルのアップロードを実装しようとしています:列「ファイルは」型のOIDですが、式はbyte型

@Inject 
@Push 
private PushContext uploadProgress; 

private static final Logger logger = Logger.getLogger(NewProcedure.class.getName()); 
private Part file; 

public Part getFile() 
{ 
    return file; 
} 

public void setFile(Part file) 
{ 
    this.file = file; 
} 

public void upload() throws SQLException 
{ 
    if (file != null) 
    { 
     try (InputStream inputStream = file.getInputStream(); 
      //FileOutputStream outputStream = new FileOutputStream(path) 
      ) 
     { 

      long lastTimestamp = System.currentTimeMillis(); 
      int pushInterval = 1000; 
      long totalRead = 0; 
      long size = file.getSize(); 

      int bytesRead = 0; 
      final byte[] chunck = new byte[1024]; 
      while ((bytesRead = inputStream.read(chunck)) != -1) 
      { 
//     outputStream.write(chunck, 0, bytesRead); 
       totalRead += bytesRead; 

       if (System.currentTimeMillis() > lastTimestamp + pushInterval) 
       { 
        lastTimestamp = System.currentTimeMillis(); 
        uploadProgress.send(100.0 * totalRead/size); // Make sure this isn't sent more often than once per second. 
       } 
      } 

      Connection conn = ds.getConnection(); 
      // insert into database file 
      PreparedStatement ps = null; 
      boolean committed = false; 
      try 
      { 
       conn.setAutoCommit(false); 

       ps = conn.prepareStatement("INSERT INTO PROCEDURE_FILES (ID, PROCEDURE_ID, FILE_NAME, FILE) " 
        + " VALUES (?, ?, ?, ?)"); 
       ps.setInt(1, obj.number); 
       ps.setInt(2, obj.number); 
       ps.setString(3, "tests"); 
       ps.setBinaryStream(4, inputStream); 

       ps.executeUpdate(); 
       ps.close(); 

       conn.commit(); 
       committed = true; 
      } 
      catch (SQLException e) 
      { 
       e.printStackTrace(); 
      } 

      finally 
      { 
       if (!committed) 
       { 
        conn.rollback(); 
       } 

       if (ps != null) 
       { 
        ps.close(); 
       } 
       conn.close(); 
      } 

      FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload successfully ended!")); 
     } 
     catch (IOException e) 
     { 
      FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload failed!")); 
     } 
    } 
} 

私は、データベースに直接ファイルを挿入したいと思いますが、私はエラーを取得します:

org.postgresql.util.PSQLException: ERROR: column "file" is of type oid but expression is of type bytea 
    Hint: You will need to rewrite or cast the expression. 

ファイルをデータベースに挿入する適切な方法は何ですか? おそらく私はファイルを格納するために他のJava Objectを使用する必要がありますか?

public static byte[] getBytesFromInputStream(InputStream is) throws IOException 
    { 
     try (ByteArrayOutputStream os = new ByteArrayOutputStream();) 
     { 
      byte[] buffer = new byte[0xFFFF]; 

      for (int len; (len = is.read(buffer)) != -1;) 
       os.write(buffer, 0, len); 

      os.flush(); 

      return os.toByteArray(); 
     } 
    } 

    public void upload() throws SQLException 
    { 
     if (file != null) 
     { 
      try 
      { 
       InputStream inputStream = file.getInputStream(); 

       byte[] bytesFromInputStream = getBytesFromInputStream(inputStream); 
       ByteArrayInputStream input = new ByteArrayInputStream(bytesFromInputStream); 


       long lastTimestamp = System.currentTimeMillis(); 
       int pushInterval = 1000; 
       long totalRead = 0; 
       long size = file.getSize(); 

       int bytesRead = 0; 
       final byte[] chunck = new byte[1024]; 
       while ((bytesRead = inputStream.read(chunck)) != -1) 
       { 
//     outputStream.write(chunck, 0, bytesRead); 
        totalRead += bytesRead; 

        if (System.currentTimeMillis() > lastTimestamp + pushInterval) 
        { 
         lastTimestamp = System.currentTimeMillis(); 
         uploadProgress.send(100.0 * totalRead/size); // Make sure this isn't sent more often than once per second. 
        } 
       } 

       Connection conn = ds.getConnection(); 
       // insert into database file 
       PreparedStatement ps = null; 
       boolean committed = false; 
       try 
       { 
        conn.setAutoCommit(false); 

        ps = conn.prepareStatement("INSERT INTO PROCEDURE_FILES (ID, PROCEDURE_ID, FILE_NAME, FILE) " 
         + " VALUES (?, ?, ?, ?)"); 
        ps.setInt(1, obj.number); 
        ps.setInt(2, obj.number); 
        ps.setString(3, file.getSubmittedFileName()); 
        ps.setBinaryStream(4, input, input.available()); 

        ps.executeUpdate(); 
        ps.close(); 

        conn.commit(); 
        committed = true; 
       } 
       catch (SQLException e) 
       { 
        e.printStackTrace(); 
       } 
       finally 
       {} 
      } 
      catch (IOException e) 
      {} 
     } 
    } 
+0

'ps.setBinaryStream(4値、INPUTSTREAM、file.length());' 引用: 'にsetBinaryStreamに長さパラメータが正確でなければなりません。ストリームの長さが不明であることを示す方法はありません。このような状況にある場合は、ストリームを一時的な記憶域に読み込んで長さを判断する必要があります。正しい長さで、一時的なストレージからドライバにデータを送信することができます。 '問題は' file'は実際には 'Part'(JavaMail?)です。この場合、' Content-Length'ヘッダを問い合わせる必要があります。 – Stavr00

+0

@ Stavr00どのように長さを設定できますか?コードのどの部分から長さのサイズを取得できますか? –

+0

-1を返す場合は、 'getSize()'から取得するか、ストリーム全体を 'ByteArayInputStream'に読み込む必要があります。 – Stavr00

答えて

1

whileループ読み取りInputStreamを削除します。

P.S私はこれを試してみました。

読み取りは、列のバイナリ入力ストリームを設定することによって行われます。file

これには別の種類の進捗状況が必要です。

何が起こったかは、inputStreamが最後まで読み込まれ、プリ​​ペアドステートメントが0バイトしか読み取れなかったことです。


public void upload() throws SQLException { 
    if (file != null) { 
     try (InputStream inputStream = file.getInputStream()) { 

      long lastTimestamp = System.currentTimeMillis(); 
      int pushInterval = 1000; 
      long totalRead = 0; 
      long size = file.getSize(); 

      Connection conn = ds.getConnection(); 
      // insert into database file 
      boolean committed = false; 
      try { 
       conn.setAutoCommit(false); 

       try (PreparedStatement ps = 
         conn.prepareStatement("INSERT INTO PROCEDURE_FILES" 
           + " (ID, PROCEDURE_ID, FILE_NAME, FILE) " 
           + " VALUES (?, ?, ?, ?)")) { 
        ps.setInt(1, obj.number); 
        ps.setInt(2, obj.number); 
        ps.setString(3, "tests"); 
        ps.setBinaryStream(4, inputStream); 

        ps.executeUpdate(); 
       } 

       conn.commit(); 
       committed = true; 
      } 
      catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      finally { 
       if (!committed) { 
        conn.rollback(); 
       } 
       conn.close(); 
      } 

      FacesContext.getCurrentInstance().addMessage(null, 
        new FacesMessage("Upload successfully ended!")); 
     } 
     catch (IOException e) { 
      FacesContext.getCurrentInstance().addMessage(null, 
        new FacesMessage("Upload failed!")); 
     } 
    } 
} 
+0

[OK]をクリックしますが、アップロードの進行状況についてクライアントの更新に返信するにはwhileループが必要です。コードサンプルを表示してもらえますか? –

+0

'InputStream'クラスを拡張し、' executeUpdate'がそのストリームを消費するようにすると、アップロードの進捗コードをラップする必要があります。 – Stavr00

+0

ByteArayInputStreamにストリーム全体を実装しようとしましたが、同じエラーが発生します。投稿が更新されます。何か案は?私は同じエラーが発生します。 –