I am new to Java development so apologies in advance if I am asking something stupid.
I am trying to retrieve an image and it's thumbnail from sql database.
I get data from ResultSet in BinaryStream format and then convert it to byte[].
For thumbnail it works fine and for original image too I am able to retrieve BinaryStream using getBinaryStream method But when I convert it to byte[], the array remain empty for some reason.
binaryStream = rs.getBinaryStream("image");
thumbBinaryStream = rs.getBinaryStream("thumbnail");
if (binaryStream != null) {
// Tested on following line and I get empty imageBytes
byte[] imageBytes = IOUtils.toByteArray(binaryStream);
thisRecord.put("image", DatatypeConverter.printBase64Binary(imageBytes)); // imageBytes is empty here
}
We probably need more information, especially about the datatypes of the columns, but maybe it helps to retrieve the stream from the BLOB like in this example:
if (rs.getMetaData().getColumnType(column) == Types.BLOB) {
in = rs.getBlob(column).getBinaryStream();
} else {
in = rs.getBinaryStream(column);
}
To be sure:
Statement and ResultSet must be closed and getBinaryStream only used when the ResultSet is still open, like:
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
InputStream binaryStream = rs.getBinaryStream("image");
InputStream thumbBinaryStream = rs.getBinaryStream("thumbnail");
if (binaryStream != null) {
// Tested on following line and I get empty imageBytes
byte[] imageBytes = IOUtils.toByteArray(binaryStream);
thisRecord.put("image", DatatypeConverter.printBase64Binary(imageBytes));
boolean mustGenerateThumbnail = thumbBinaryStream == null;
if (mustGenerateThumbnail ) {
thumbBinaryStream = generateThumbnail(imageBytes);
}
byte[] thumbBytes = IOUtils.toByteArray(thumbBinaryStream);
thisRecord.put("thumbnail", DatatypeConverter.printBase64Binary(thumbBytes));
Here we are at the error. At this point thumbBinaryStream is read till the end, so do:
if (mustGenerateThumbnail ) {
ByteArrayInputStream baIn = new ByteArrayInputStream(thumbBytes);
saveThumbnailForRecordWithId(baIn, floor_drawing_id);
}
}
}
}
(Here I used try-with-resources to automatically close the ResultSet even on thrown exception.)
Furthermore there is a more general class for Base64. Should you in future have the need for such.
DatatypeConverter.printBase64Binary(thumbBytes)
Base64.getEncoder().encodeToString(thumbBytes)
I'm writing an endpoint that dynamically generates a GIF file. I'll go from the ground up.
I have a class named Function that works like an abstract class and I have several classes, in this example AddFunction, that represent small chunks of functionality. In this case, the AddFunction adds some numbers together. When the end point is hit, the ID of the AddFunction is passed to it (it could be any, in this example it's the add function). The code in the controller is as follows:
/**
* Returns the image for a function
*/
#RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(#PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));
Logger logger = Logger.getLogger(FunctionController.class);
ServletOutputStream servOut = response.getOutputStream();
// Uses default values if you pass in nulls.
function.getImage(servOut, null, null);
servOut.flush();
servOut.close();
}
First, the Function is found by it's ID. I have checked, and the correct function is being found. This code is in need of some validation (for example checking the id passed in is a valid number) but I'll get to that later. I then grab the servlet output stream and pass it to the getImage methods of the function. This method generates the GIF that describes the function. This code looks like this:
public void getImage(OutputStream out, String staticContent, String changedContent) throws IOException {
String[] data = {"2", "+", "2", "=", "4"};
Logger logger = Logger.getLogger(AddFunction.class);
logger.info("Getting the add image.");
ImageUtils.writeSequenceToImage(ImageIO.createImageOutputStream(out), data, 5, Constants.IMAGE_HEIGHT / 2);
}
As you can see, it ignores the values and it is using stock data at the moment. It creates an array of values. Each of these values which appear in each frame of the GIF. So what I do is I take the ServletOutputStream and I use the ImageIO.createImageOutputStream to wrap that with an ImageOutputStream object. This is when passed into the writeSequenceToImage method in my own ImageUtils class. The last two values are coordinates for where to write from. In this case, the vertical middle of the image, on the far left. The code for the writeSequenceToImage method is as follows:
public static void writeSequenceToImage(ImageOutputStream out, String[] contentList, int x, int y) throws IOException {
StringBuilder dataBuilder = new StringBuilder();
Test test = new Test(out, BufferedImage.TYPE_INT_RGB, 500, true);
Logger logger = Logger.getLogger(ImageUtils.class);
logger.info("Writing sequence to image.");
for (String content : contentList) {
dataBuilder.append(content);
logger.info("writing " + dataBuilder.toString() + " to the gif.");
test.writeToSequence(generateAndWriteToImage(dataBuilder.toString(), x, y));
}
}
In this code, I am using the class Test (temporary name) which contains code that writes data to a GIF file. All I'm doing here is looping through and adding each value to a frame in the GIF. The code for class Test can be found here. What I do is I build up the String, so in our example the logs would output:
2014-12-31 14:37:15 INFO ImageUtils:48 - Writing sequence to image.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2 to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+ to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+2 to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+2= to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+2=4 to the gif.
This will give the appearance in each frame of the GIF of it building up the string. Now, I write this to the GIF and I expect it to be pushed straight into the ServletOutputStream, only when I attempt to reference it with the following HTML:
<div class="panel columns large-12" ng-show="selectedFunction">
<h2>{{selectedFunction.name}}</h2>
<p>{{selectedFunction.description}}</p>
<p>This function expects a {{selectedFunction.expectedParameterType}} as a parameter.</p>
<p>This function will return a {{selectedFunction.expectedReturnType}}</p>
<img src="/autoalgorithm/functions/function/{{selectedFunction.id}}/image.gif" alt="{{selectedFunction.name}}"/>
</div>
I am seeing the following data returning in Chrome:
And I am seeing no image on my page:
What I have tried
I've tried to see the size of what is coming back. To do this, I have replaced the ServletOutputStream with a ByteArrayOutputStream so I can get the size of the data. If I do this, my code looks like this:
/**
* Returns the image for a function
*/
#RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public #ResponseBody byte[] getImage(#PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));
Logger logger = Logger.getLogger(FunctionController.class);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Uses default values if you pass in nulls.
function.getImage(baos, null, null);
logger.info("The number of bytes returned is " + baos.toByteArray().length);
return baos.toByteArray();
}
And the log outputs:
2014-12-31 15:34:09 INFO FunctionController:85 - The number of bytes returned is 0
So that is telling me that it isn't being written too. So I changed up my approach and refactored the code so I maintained a reference to the ImageOutputStream in my controller. This meant that I had complete control over the object, so now the log outputted:
2014-12-31 15:39:56 INFO FunctionController:85 - The number of bytes returned is 2708
Which was encouraging! And 2KB sounds about right for a very very simple GIF. However, when I check the response from Google, similar story:
Although this time it has a content length, but there is no preview available and the image still is not appearing.
I was wondering if anyone on here had tackled a similar issue? I suspect it is to do with the encoding of the GIF, but ImageIO doesn't support conversion from one stream to another, only from one BufferedImage type to another. So I used the ImageIO.read method to read it into a BufferedImage and used ImageIO.write to write it as a gif onto the ServletOutputStream. This yielded the following error:
java.lang.IllegalArgumentException: image == null!
At this point, I'm stumped. I'm hoping a fresh set of eyes can help me out. Does anyone have any ideas?
As already noted in the comments your question is a little bit unconcise but I'll try to show you how it can work.
First try the following:
#RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(#PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
BufferedImage firstImage = ImageIO.read(new File("/bla.jpg"));
response.setContentType("image/gif"); // this should happen automatically
ImageIO.write(firstImage, "gif", response.getOutputStream());
response.getOutputStream().close();
}
Place some file named bla.jpg in your root directory or change the path to some existing image file (can also be a GIF). Make sure you have at least read access rights.
This should work in any case, regardless if jpg or gif file. If this doesn't work there may be something wrong with your Spring configuration. You should rule that out.
If this is working, you can use your method generateAndWriteToImage() to replace ImageIO.read(new File("/bla.jpg"));. And you should be done.
Now, I don't know what your generateAndWriteToImage() method does but I assume that it creates an instance of BufferedImage, writes some text into the image and returns it.
Something like this:
public static BufferedImage generateAndWriteToImage(String string, int x, int y) {
BufferedImage image = new BufferedImage(x,y,BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setPaintMode();
g.setFont(g.getFont().deriveFont(30f));
g.drawString(string, 100, 100);
g.dispose();
return image;
}
If you create the image with the type BufferedImage.TYPE_INT_RGB this shouldn't cause any problems.
TL;DR Another thing you already found out yourself is that a little refactoring gives you the ability to close the ImageOutputStream.
Assume the following method:
#RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(#PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));
ServletOutputStream servOut = response.getOutputStream();
// Uses default values if you pass in nulls.
function.getImage(servOut, null, null);
servOut.flush();
servOut.close();
}
and this method:
public void getImage(OutputStream out, String staticContent, String changedContent) throws IOException {
String[] data = {"2", "+", "2", "=", "4"};
Logger logger = Logger.getLogger(AddFunction.class);
logger.info("Getting the add image.");
ImageUtils.writeSequenceToImage(ImageIO.createImageOutputStream(out), data, 5, Constants.IMAGE_HEIGHT / 2);
}
In the second method, you are creating a local instance of ImageOutputStream with ImageIO.createImageOutputStream(out) (last line).
I guess the main problem is, that you aren't closing this ImageOutputStream, this may result in data not beeing written to any other OutputStream (because of buffering).
To make it work you can refactor your methods to this:
#RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(#PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));
ImageOutputStream servOut = ImageIO.createImageOutputStream(response.getOutputStream());
// Uses default values if you pass in nulls.
function.getImage(servOut, null, null);
servOut.close();
}
and this:
public void getImage(ImageOutputStream out, String staticContent, String changedContent) throws IOException {
String[] data = {"2", "+", "2", "=", "4"};
Logger logger = Logger.getLogger(AddFunction.class);
logger.info("Getting the add image.");
ImageUtils.writeSequenceToImage(out, data, 5, Constants.IMAGE_HEIGHT / 2);
}
The same thing applies here for the generateAndWriteToImage() method. If it correctly returns an instance of BufferedImage, this should work (with the refactoring).
I did not try with spring but tried with J2EE instead. Below approach works for me !
private void process(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
String baseServletPath = httpServletRequest.getServletContext().getRealPath("/");
System.out.println("Base Servlet Path :"+baseServletPath);
String relativeInputFilePath = "images/Tulips.gif";
String imageFilePath = baseServletPath + relativeInputFilePath;
File file = new File(imageFilePath);
BufferedImage bufferedImage = null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
bufferedImage = ImageIO.read(file);
ImageIO.write(bufferedImage, "GIF", byteArrayOutputStream);
} catch (IOException e) {
e.printStackTrace();
}
byte[] imageData = byteArrayOutputStream.toByteArray();
String relativeOutFilePath = "images/TulipsOut.gif";
String imageOutFilePath = baseServletPath + relativeOutFilePath;
File fileOut = new File(imageOutFilePath);
FileOutputStream fileOutputStream=null;
try {
fileOutputStream = new FileOutputStream(fileOut);
fileOutputStream.write(imageData);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
httpServletResponse.getOutputStream().write( imageData );
} catch (IOException e) {
e.printStackTrace();
}
}
I am getting exception while fatch image from database and display image on screen. Please help me to solve this error..
int questionid ;
Connection conn = null;
conn= new DBFunction().getconnect();
Statement stmt = conn.createStatement();
questionid=4;
try
{
conn.setAutoCommit (false);
// get the image from the database
Blob img ;
byte[] imgData = null ;
String req = "Select img From questionlist Where queid = " + questionid ;
ResultSet rset = stmt.executeQuery ( req );
while (rset.next ())
{
img = rset.getBlob("img");
imgData = img.getBytes(1,(int)img.length());
}
// display the image
response.reset();
response.setContentType("image/gif");
OutputStream o = response.getOutputStream();
o.write(imgData);
o.flush();
o.close();
}
catch (Exception e)
{
e.printStackTrace();
}
Let me know where am i wrong ?
It is not the better practice to write the java codes inside jsp as jsp calls printWriter by default. Scriptlets are not advised over decades . try moving the code into a java file , preferably a servlet.
Also it is not better option to store images into Database , try to use the diskspace instead. As far as your question try out.clear()
see How to avoid Java code in JSP files?
I Have some values associated with id i want to print those values with respective id's in pdf format, values can be in database or in some variable , can anyone suggest me which way i should go... i have some ideas either i can save those values in database and can make a single xml file from database of all records and then divide each node with different different pdf or directly get the values from database and generate the pdf so please anyone suggest me ideas and ways also if you can refer some links then most welcome please try to help me here.....
public class PDFGenerator extends HttpServlet
{
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException
{
try
{
Connection con = ConnectionManager.getConnection();
Statement st4= con.createStatement();
ResultSet rs1 = st4.executeQuery("select count(*) from salary");
while(rs1.next())
{
int p = Integer.parseInt(rs1.getString(1));
System.out.println("saurabh :" +p);
for(int q=1;q<=p;q++)
{
Document document=new Document();
PdfWriter.getInstance(document,new FileOutputStream("c:/temp/salary.pdf"));
document.open();
PdfPTable table = new PdfPTable(2);
table.addCell("eid");
table.addCell("salary");
Statement st3= con.createStatement();
ResultSet rs = st3.executeQuery("select * from salary where eid ='"+q+"'");
while(rs.next())
{
table.addCell(rs.getString("eid"));
table.addCell(rs.getString("salary"));
}
document.add(table);
document.close();
}
}
}
catch (Exception e)
{
System.out.println(e);
}
}}
please anyone help me here....its printing last row only because its dealing with same pdf and again values are getting over written so please anyone help me how to generate pdf with multiple names so i can store in the same folder... with different name ....
If you want to create PDF's from Java, this is covered pretty comprehensively in the following question
http://www.stackoverflow.com/questions/6118635/
Here's a tutorial for the iText Java PDF library. I've used this guys tutorials for several Java/Eclipse/Android related problems and find him to be thorough and easy to follow:
http://www.vogella.com/tutorials/JavaPDF/article.html
its already generating n number of pdf which is specified through results of rows
but not getting saved only last one is getting saved because its getting over written
so its working because i have to send the mail after getting generated one mail..
so here is solution...
for(int q=1;q<=p;q++)
{
Document document=new Document();
PdfWriter.getInstance(document,new FileOutputStream("c:/temp/salary.pdf"));
document.open();
PdfPTable table = new PdfPTable(2);
table.addCell("eid");
table.addCell("salary");
Statement st3= con.createStatement();
ResultSet rs = st3.executeQuery("select * from salary where eid ='"+q+"'");
while(rs.next())
{
table.addCell(rs.getString("eid"));
table.addCell(rs.getString("salary"));
}
document.add(table);
document.close();
}
}
I have an application that uses PostgreSQL, JSP and the STRUTS Framework
I want to insert a file into a table in PostgreSQL using the OID type, so it's stored as a large object in the database.
My table definition is this one:
CREATE TABLE mensaje
(
id serial NOT NULL,
file oid,
CONSTRAINT pk_mensaje PRIMARY KEY (id)
)
WITH (
OIDS=TRUE
);
ALTER TABLE mensaje
OWNER TO postgres;
Anybody know an example of how the Action, the ActionForm and the .jsp should be?
If not, is there any other example that explains how to do it without using the OID type?
This is a two step process to solve the problem:
File upload using Struts 2
PostgreSQL Java tutorial, check the Writing images section.
Additional note: Once the file has been received in your Action, you should use the byte array data to save it in your OID field.
From your comment, this should be the way in Struts 1.x
In the JSP
<html:form action="fileUploadAction" method="post" enctype="multipart/form-data">
File : <html:file property="upload" />
<br />
<html:submit />
</html:form>
In your action class
YourForm uploadForm = (YourForm) form;
FormFile file = null;
try {
file = uploadForm.getFile();
//FormFile#getFileData() returns the byte array containing the file data
//You can use it to save the file in your database and other things you want/need
int id = 9001; //assuming this is a valid id in the mensaje table
MensajeService mensajeService = new MensajeService();
mensajeService.saveFile(id, file.getFileData());
} catch (Exception e) {
//log the errors for maintenance purposes (bugs, fixes, etc)
}
The MensajeService class will connect to your Postgre database and save the file
public class MensajeService {
public MensajeService() {
}
public void saveFile(int id, byte[] fileData) throws SQLException {
//this is a very simple skeleton, you have to adapt this to
//your needs, the way you're connecting to dabatase, etc...
Connection con = null;
PreparedStatement pstmt = null;
try {
con = ... //get the connection to your postgre db
//Initialize a new transaction
con.setAutoCommit(false);
// Get the Large Object Manager to perform operations with
LargeObjectManager lobj = ((org.postgresql.PGConnection)conn)
.getLargeObjectAPI();
// Create a new large object
int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE);
// Open the large object for writing
LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);
//in the provided example, the code shows a way to get the byte array data
//from the file (using the File and FileInputStream classes)
//you don't need all that because you already have the byte array (good!)
//so you only write the binary data in your LargeObject (OID) object
obj.write(fileData);
//creating the SQL statement to insert the OID
String sql = "INSERT INTO mensaje VALUES (?, ?)";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, id);
ps.setInt(2, oid);
//
pstmt.setBinaryStream(2, fin, (int) img.length());
//saving the file
pstmt.executeUpdate();
//closing the transaction successfully
con.commit();
} catch (SQLException e) {
//error in the transaction, start a rollback
if (con != null) {
con.rollback();
}
throw e;
} finally {
//don't forget to free the resources after using them
pstmt.close();
con.close();
}
}
}
Struts 1 code adapted from: Uploading a file in struts1.
PostreSQL code adapted from here.