Pessoal, estou colocando aqui a solução para gravar e ler um campo Blob num banco Oracle 10g Release 10.1.0.4.0.
É necessário utilizar o driver ojdbc14.jar (manifest 10.1.0.4.0) e os pacotes commons-fileupload-1.1.1.jar e commons-io-1.2.jar. (http://jakarta.apache.org/commons/fileupload/)
Notem que o exemplo do servlet é extremamente simples onde eu sequer fiz validação do tipo de arquivo para upload, está fixo um .jpg.
try {
PoolConnection conexao = new PoolConnection();
DataSource jdbcURL = conexao.getJdbcURL(); // Conexão do tomcat
conn = jdbcURL.getConnection();
conn.setAutoCommit(false);
response.setContentType("text/html");
if (request.getContentType() != null) { // Se foi submetido o formulário com dados
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setSizeMax(-1); // Tamanho máximo do arquivo em bytes, quando -1 não tem limites
factory.setSizeThreshold(500000);
List items = upload.parseRequest(request);
Iterator iter = items.iterator();
FileItem arquivo = null;
while (iter.hasNext()) { // Processa todos os campos submetidos
FileItem item = (FileItem) iter.next();
if (item.isFormField()) { // Aqui retorna campos tipe text, radio, checkbox, etc
System.out.println("Nome do campo: " + item.getFieldName());
} else { // senão retorna campo tipo file
arquivo = item;
//String fieldName = item.getFieldName();
//String fileName = item.getName();
//String contentType = item.getContentType();
//boolean isInMemory = item.isInMemory();
//long sizeInBytes = item.getSize();
}
}
//Name Null? Type
//------------------------------- -------- ----
//CD_ARQUIVO NUMBER(5)
//DS_NOME_ARQUIVO VARCHAR2(50)
//BL_ARQUIVO BLOB
// Insere valores na tabela, porém sem conteúdo para o campo blob
pstmt = conn.prepareStatement("insert into testeBlob values (?, ?, EMPTY_BLOB())");
pstmt.setLong(1,100);
pstmt.setString(2,arquivo.getName());
pstmt.execute();
stmt = conn.createStatement();
// Consulta para ler o registro que acabou de ser incluído (modo exclusivo)
ResultSet res = stmt.executeQuery("select bl_arquivo from testeblob where cd_arquivo = 100 for update");
if (res.next()) {
Blob mapBlob = res.getBlob(1); // Guarda ponteiro do campo blob
OutputStream blobOutputStream = mapBlob.setBinaryStream(0);
blobOutputStream.write(arquivo.get()); // Atualiza campo blob
blobOutputStream.close();
}
conn.commit(); // Grava as alterações no banco
// Ler da base o registro gravado
res = stmt.executeQuery("select bl_arquivo from testeblob where cd_arquivo = 100");
Blob mapBlob = null;
if (res.next()) {
mapBlob = res.getBlob(1);
}
res.getStatement().close();
// Gera o arquivo em disco com o conteúdo do campo blob
InputStream blobStream = mapBlob.getBinaryStream();
FileOutputStream fos = new FileOutputStream("D:\\Foto.jpg");
byte[] buffer = new byte[10];
int nbytes = 0;
while( (nbytes = blobStream.read(buffer)) != -1 )
fos.write(buffer, 0, nbytes);
fos.flush();
fos.close();
blobStream.close();
}
Olá Juliano, trago este tópico de volta, pois, estou com um problema ao tentar executar o código que vc descreveu. Peço, por favor, que me diga onde está o erro, pois acho que não está muito diferente do código q vc postou. Agradeço a ajuda de todos.
No meu servlet RenderPhoto.java está assim:
e o método de DBFoto que recupera a stream é (acho está ok):
public InputStream getBinaryStream(int numero, int cargo) throws SQLException {
Connection con = ConexaoDB.getInstance().getConnection();
PreparedStatement stm = null;
ResultSet rs = null;
InputStream in = null;
try {
String sqlCand = "SELECT sq_cand FROM admel06.candidato WHERE nr_cand = ? AND cd_cargo = ?";
String foto = "SELECT fl_foto FROM admel06.foto WHERE sq_cand = ?";
stm = con.prepareStatement(sqlCand);
stm.setInt(1, numero);
stm.setInt(2, cargo);
rs = stm.executeQuery();
rs.next();
int sq_cand = rs.getInt("sq_cand");
stm = con.prepareStatement(foto);
stm.setInt(1, sq_cand);
rs = stm.executeQuery();
rs.next();
Blob blob = rs.getBlob("fl_foto");
in = blob.getBinaryStream();
}
catch(SQLException e) {
throw e;
}
finally {
if(rs != null)
rs.close();
if(stm != null)
stm.close();
con.close();
}
return in;
}
Estou usando um tal de oracle_thin_driver.jar, mas já testei com o ojdbc14.jar e dá no mesmo.
Eu já debuguei com o Eclipse e o método realmente retorna a stream (linha 46), mas na hora de ler a stream para o array de bytes (linha 47) dá o seguinte erro:
WARNING: Servlet.service() for servlet RenderPhoto threw exception
java.io.IOException: Deve ter estabelecido logon no servidor
at oracle.jdbc.dbaccess.DBError.SQLToIOException(DBError.java:717)
at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:249)
at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:158)
at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:131)
at br.gov.tream.fotoCandidato.Foto.RenderPhoto.doGet(RenderPhoto.java:47)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:667)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)
O engraçado é que aparece outro tipo de erro agora:
SEVERE: Servlet.service() for servlet RenderPhoto threw exception
java.lang.NullPointerException
at oracle.sql.LobPlsqlUtil.plsql_read(LobPlsqlUtil.java:911)
at oracle.sql.LobPlsqlUtil.plsql_read(LobPlsqlUtil.java:52)
at oracle.jdbc.dbaccess.DBAccess.lobRead(DBAccess.java:658)
at oracle.sql.LobDBAccessImpl.getBytes(LobDBAccessImpl.java:95)
at oracle.sql.BLOB.getBytes(BLOB.java:175)
at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:126)
at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:108)
at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:91)
at br.gov.tream.fotoCandidato.Foto.RenderPhoto.doGet(RenderPhoto.java:47)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:667)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)
[RESOLVIDO]
Desculpe, Juliano, não atentei para um detalhe do seu código:
A conexão com o banco é fechada DEPOIS das operações de leitura/escrita sobre a InputStream.
Só percebi o erro após ver a explicação nesse post de outro fórum. No meu código, a classe do banco está naquele padrão: abre conexão, recupera dados, fecha conexão e entrega daods pro action, a NullPointerException era por causa da conexão fechada. :lol: