I have a DB procedure which returns a BLOB. Can anyone tell me how to manipulate the BLOB? Is there any specific API for this?
Is there any specific API for this ?
Sure, the JDBC API.
Trail: JDBC™ Database Access
You get hold of the Blob instance just as you get hold of any value from a result set. You should then use the get...- and set... methods on this Blob.
Here you basically have two options:
Work with a byte-array:
Get hold of a byte[] containing the data through Blob.getBytes
Manipulate this byte-array
Set it back using Blob.setBytes.
Work with InputStream / OutputStream:
Get hold a an InputStream through Blob.getBinaryStream
Manipulate this stream as you see fit
Use Blob.setBinaryStream.
An alternative approach is to skip messing with Blob in the first place, and instead use the second approach (with streams) directly through the ResultSet-interface.
It depends on which kind of blob contains (image, video) and it's extension. I wrote a simple program to retrieve an image from DB and show it in JSP page. Hope it helps.
JSP Page
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<image src="blobAction"/>
</body>
Servlet Page
byte[] imgData = blobDao.getInstance().getPhoto();
response.setContentType("image/gif");
OutputStream o = response.getOutputStream();
o.write(imgData);
o.flush();
o.close();
Calling Procedure
public byte[] getPhoto() {
byte[] imgData = null;
Blob img = null;
ResultSet rs = null;
Statement stmt = null;
try {
conn = getConnection();
String sqlQ = "SELECT CONTENT_FILE FROM CONTENT where id = 'something';
stmt = conn.createStatement();
rs = stmt.executeQuery(sqlQ);
while (rs.next()) {
img = rs.getBlob("CONTENT_FILE");
imgData = img.getBytes(1, (int) img.length());
}
rs.close();
stmt.close();
conn.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
return imgData;
}
}
With Simple Java JDBC Api, you can get a java.sql.Blob back from a ResultSet.
ResultSet.getBlob(index) or
ResultSet.getBlob(String columnName).
Both returns a Blob.
Once you get a Blob, you can get the byte[] back from the Blob.getBytes() method or set using setBytes() method.
Update: Seeing that some Database driver vendors don't support Blob, you can use ResultSet.getBinaryStream().
You can use javax.sql.rowset.serial.SerialBlob.
I'm using it in my SpringBoot & Angular4 application like this:
get Base64String from Angular4 app
decode Base64String to byte[]
create SerialBlob like this: SerialBlob serialBlob = new SerialBlob(byte[])
store it in the database with JpaRepository
Example
public void Insert(Object obj){
try {
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(byteArray);
oos.writeObject(obj);
PreparedStatement ps= conn1.prepareStatement("insert into vehiculos values(?)");
ps.setBytes(1, byteArray.toByteArray());
ps.execute();
ps.close();
} catch (SQLException ex) {
System.out.println("ERROR:al hacer un Insert");
ex.printStackTrace();
} catch (IOException ex) {
Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void ShowData(){
try {
Statement stmt = conn1.createStatement();
String query = "SELECT * FROM vehiculos";
ResultSet rs = stmt.executeQuery(query);
Object obj;
while(rs.next()){
//Coche c = (Coche)rs.getBlob("coches");
Blob blob = rs.getBlob("coches");
ObjectInputStream ois = new ObjectInputStream(blob.getBinaryStream());
obj = ois.readObject();
System.out.println(obj.toString());
System.out.println("");
/*Blob blob = rs.getBlob("coches");
byte[] data = blob.getBytes(1, (int)blob.length());*/
}
rs.close();
stmt.close();
} catch (SQLException ex) {
System.out.println("ERROR:al consultar");
ex.printStackTrace();
} catch (IOException ex) {
Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void cerrar_Conexion (){
try {
conn1.close();
} catch (SQLException ex) {
System.out.println("ERROR:al cerrar la conexión");
ex.printStackTrace();
}
}
Related
I am trying to retrieve BLOB data(image) and display in html page using servlet.
Following is my code. But it displays nothing. Thanks in advance.
In addition I have used MySQL database.
public class retriveLogo extends HttpServlet {
standardFunction sf = new standardFunction();
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
HttpSession session=request.getSession();
Blob imageBlob=null;
byte[] imgData = null;
try {
String sql1 = "select img from userLogo where userID=?";
PreparedStatement statement = sf.co.con.prepareStatement(sql1);
statement.setString(1, (String)session.getAttribute("User"));
ResultSet resultSet = statement.executeQuery();
while(resultSet.next())
{
imageBlob = resultSet.getBlob("doc");
imgData = imageBlob.getBytes(1, (int) imageBlob.length());imageBlob.length());
}
OutputStream output = response.getOutputStream();
response.setContentType("image/gif");
output.write(imgData);
output.flush();
output.close();
} catch(Exception e) {
try {
sf.co.con.rollback();
} catch (SQLException ex1) {
Logger.getLogger(insertPaperSize.class.getName()).log(Level.SEVERE, null, ex1);
}
Logger.getLogger(insertPaperSize.class.getName()).log(Level.SEVERE, null, e);
}
}
I want to call it like
<img src="retriveLogo">
I am trying to save a file in the database. I am able to save using SQL it works perfectly fine. What I am avoiding with SQL is providing password directly in the code that why I am considering using native query. I am unsure if I can still use SQL without providing password and username directly in the code.The code for the SQL is as below
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection connection = null;
try {
connection = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/mydb", "postgres",
"postgres");
System.out.println("......Now attempting to insert the record.....");
// String matid = "007N00030000001";
File file = new File("C://JavaWorkspace/pdf-sample.pdf");
FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = connection.prepareStatement("INSERT INTO cli.documents VALUES (?,?,?,?)");
ps.setBinaryStream(1, fis, (int)file.length());
ps.setString(2, "1");
ps.setString(3, file.getName());
ps.setString(4,matid);
ps.executeUpdate();
ps.close();
fis.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
If using native query I cant see any method that I can use instead of
ps.setBinaryStream(1, fis, (int)file.length());
there is only setParameter
below is my attempt using native query
Query query = entityManager.createNativeQuery("INSERT INTO cli.documents (matid, doctype,upload,docfile) " +
" VALUES(?,?,?,?)");
EntityManagerFactory emfactory=Persistence.createEntityManagerFactory( "junit" );
EntityManager em = emfactory.createEntityManager( ); //= null;
EntityTransaction et = em.getTransaction();
et.begin();
em.createNativeQuery("INSERT INTO cli.documents (matid, doctype,upload,docfile) " + " VALUES(?,?,?,?)")
.setParameter(1,matid)
.setParameter(2, "1")
.setParameter(3, file.getName())
.setParameter(4, (int)file.length());
//.setBinaryStream(4, fis, (int)file.length())
// em.executeUpdate()
et.commit();
I have a java class (Shell) that stores all the information I need to load for my application. Currently, it is saved into a .txt file and loaded from said file.
This class is responsible for saving and loading the Shell:
public void saveShell() throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
new FileOutputStream(getPath()));
objectOutputStream.writeObject(new Date());
objectOutputStream.writeBoolean(true);
objectOutputStream.writeFloat(1.0f);
objectOutputStream.writeObject(shl);
objectOutputStream.flush();
objectOutputStream.close();
System.out.println("Successfully saved");
}
public Shell loadShell() throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(
new FileInputStream(getPath()));
Date date = (Date) objectInputStream.readObject();
System.out.println(date);
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readFloat());
Shell readShell = (Shell) objectInputStream.readObject();
System.out.println("Shell Loaded");
objectInputStream.close();
System.out.println("Object output stream closed");
return readShell;
}
However, now that I'm trying to distribute the application, using a file seems less viable than using a database so I have already set up SQLite.
Since Shell has everything I need, I'd like to store it as a BLOB and be able to retrieve the object later. I am new to databases so I don't quite know the specific java methods that I should use. I know that this question is very similar to How do i store and retrieve a blob from sqlite but its answer is in C#. Plus, most examples I've found are always storing pictures and images with a certain URL, there aren't many examples with objects.
I got it working. Basically I added two functions: saveShellDB and loadShellDB:
public void saveShellDB() throws ClassNotFoundException, IOException {
Class.forName(classForName);
Connection connection = null;
try
{
// create a database connection
connection = DriverManager.getConnection(connectionPath);
Statement statement = connection.createStatement();
statement.setQueryTimeout(30); // set timeout to 30 sec.
File file = new File("shell.txt");
FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = connection.prepareStatement("INSERT INTO shell (name, shl) VALUES (?, ?)");
ps.setString(1, file.getName());
ps.setBinaryStream(2, fis, (int)file.length());
ps.executeUpdate();
ps.close();
fis.close();
System.out.println("SQL save done");
}
catch(SQLException e)
{
// if the error message is "out of memory",
// it probably means no database file is found
System.err.println(e.getMessage());
}
finally
{
try
{
if(connection != null)
connection.close();
}
catch(SQLException e)
{
// connection close failed.
System.err.println(e);
}
}
}
public void loadShellDB() throws ClassNotFoundException, SQLException, IOException {
Class.forName(classForName);
Connection conn = DriverManager.getConnection(connectionPath);
String sql = "SELECT name, shl FROM shell";
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet resultSet = stmt.executeQuery();
while (resultSet.next()) {
File shl = new File(fileOutputPath);
FileOutputStream fos = new FileOutputStream(shl);
byte[] buffer = new byte[1];
InputStream is = resultSet.getBinaryStream(2);
while (is.read(buffer) > 0) {
fos.write(buffer);
}
fos.close();
}
conn.close();
System.out.println("SQL Load Done");
}
Then, I just had to call them from my old save functions:
public void saveShell() throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
new FileOutputStream(getPath()));
objectOutputStream.writeObject(new Date());
objectOutputStream.writeBoolean(true);
objectOutputStream.writeFloat(1.0f);
objectOutputStream.writeObject(shl);
objectOutputStream.flush();
objectOutputStream.close();
System.out.println("Successfully saved");
saveShellDB(); //here!
}
public Shell loadShell() throws FileNotFoundException, IOException, ClassNotFoundException {
loadShellDB(); //here!
ObjectInputStream objectInputStream = new ObjectInputStream(
new FileInputStream(getPath()));
Date date = (Date) objectInputStream.readObject();
System.out.println(date);
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readFloat());
Shell readShell = (Shell) objectInputStream.readObject();
System.out.println("Shell Loaded");
objectInputStream.close();
System.out.println("Object output stream closed");
return readShell;
}
I am trying to upload an image file with the code below, but the file is not being uploaded. The console still shows the message "1 Record Successfully Inserted."
Create table image
(
name varchar2(20),
photo blob
);
import java.sql.*;
import java.io.*;
public class ImageWriter {
static Connection connection = null;
static CallableStatement pstat = null;
static String connectionURL = null;
public static void main(String[] args) {
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
connection = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:xe", "SYSTEM", "SYSTEM");
PreparedStatement pstat = connection.prepareStatement("insert into image(name,photo) values(?,?)");
FileInputStream fin = new FileInputStream("E:\\test.jpg");
pstat.setString(1, "ABC");
pstat.setBinaryStream(2, fin,fin.available());
int result = pstat.executeUpdate();
System.out.println(result + " Record Successfully Inserted");
connection.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
The above code works fine.
I dont know how you verified the contents of database.
Here is my code to verify the db(blob column): Try with this method. I used your code to insert the image and I could retrieve the image successfully. (note : file extension should be same)
public static void getPic() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:orcl", "sys as sysdba",
"Oracle123");
ResultSet rs = null;
Statement stmt = null;
oracle.sql.BLOB photo = null;
conn.setAutoCommit(false);
stmt = conn.createStatement();
String name="ABC";
rs = stmt.executeQuery("select photo from image where name = '" + name + "'" );
rs.next();
photo = ((OracleResultSet) rs).getBLOB(1);
File f = new File("E:/image2.jpg");
f.getParentFile().mkdirs();
f.createNewFile();
InputStream in = photo.getBinaryStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStream outputStream = new FileOutputStream(f);
int bufferSize = 1024;
int length = (int) photo.length();
byte[] buffer = new byte[bufferSize];
while((length = in.read(buffer)) != -1) {
out.write(buffer,0,length);
}
out.writeTo(outputStream);
System.out.println("Image Retrieved");
out.close();
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
I've to save a pdf file represented as a ByteArrayOutputStream into a Blob SQL field of a table, here's my code:
public boolean savePDF(int version, ByteArrayOutputStream baos) throws Exception{
boolean completed = false;
ConnectionManager conn = new ConnectionManager();
try {
PreparedStatement statement = conn.getConnection().prepareStatement(INSERT_PDF);
statement.setLong(1, version);
statement.setBlob(2, (Blob)baos);
statement.execute();
conn.commit();
completed = true;
} catch (SQLException e) {
conn.rollbackQuietly();
e.printStackTrace();
throw e;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
conn.close();
}
return completed;
}
But I get a java.lang.ClassCastException:
java.io.ByteArrayOutputStream cannot be cast to java.sql.Blob
How can I manage that? Thanks
There is a setBlob that takes an InputStream, so
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
statement.setBlob(2, bais);
You can't cast ByteArrayOutputStream to Blob. Try creating the Blob instance as below:
SerialBlob blob = new SerialBlob(baos.toByteArray());
and then
statement.setBlob(2, blob);