0

I am uploading a file from HTML

 <center><form action="pdf" method="post" enctype="multipart/form-data">
       <b>Upload Certificate</b>
       <input type="file" name="file"/></center>
      <center> <input type="submit" /></center>
</form>

On submitting the form, pdf Servlet is called. Inside the servlet the request object is parsed and file(pdf) is read using InputStream as given in code below.

protected void doPost(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse)
    throws ServletException, IOException
  {
    try
    {
      List localList = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(paramHttpServletRequest);
      for (FileItem localFileItem : localList)
      {
        String str1 = localFileItem.getFieldName();
        String str2 = FilenameUtils.getName(localFileItem.getName());
        System.out.println("fieldname:" + str1);
        System.out.println("filename:" + str2);
        InputStream localInputStream = localFileItem.getInputStream();
        try
        {
          PdfReader localPdfReader = new PdfReader(localInputStream);
          paramHttpServletResponse.sendRedirect("takedetails.jsp");
        }
        catch (InvalidPdfException localInvalidPdfException)
        {
          paramHttpServletResponse.sendRedirect("upload.jsp");
        }

      }

    }
    catch (FileUploadException localFileUploadException)
    {
      throw new ServletException("Cannot parse multipart request.", localFileUploadException);
    }
  }

As you can see,I used InputStream object to check for file format as pdf.

Now I want to save this pdf file to postgresql Database. What field should i use in postgresql and how can I get the file from InputStream object to store it in database?

suraj
  • 1,828
  • 12
  • 36
  • 64

2 Answers2

2

It's unclear what persistence API you're using. JDBC? JPA? Good ol' Hibernate? I'll assume JDBC. In JDBC, you can use PreparedStatement#setBinaryStream() to store an InputStream in the database, or PreparedStatement#setBytes() to store a byte[] in the database. Either way, in PostgreSQL you need a bytea column for this.

As you're verifying the uploaded file by a PdfReader first, the InputStream is unsuitable. It can namely be read only once. The client ain't going to resend the file multiple times each time you need to read the InputStream again. You need to copy the InputStream to a byte[] first.

ByteArrayOutputStream output = new ByteArrayOutputStream();
IOUtils.copy(localFileItem.getInputStream(), output);
byte[] filecontent = output.toByteArray();

(IOUtils is part of Apache Commons IO; if you're using FileUpload, then you already have it)

Don't forget to change iText to use the byte[] instead:

PdfReader localPdfReader = new PdfReader(filecontent);

After you've validated it by iText, you can store it in a PostgreSQL bytea column using JDBC as follows:

statement = connection.prepareStatement("INSERT INTO files (name, content) VALUES (?, ?)");
statement.setString(1, filename);
statement.setBytes(2, filecontent);
statement.executeUpdate();
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Instead of using an in-memory byte[], consider using a temporary file, or a smart buffer class that knows to switch from an in-memory buffer to a temporary file when it grows above a certain size. Also, though it probably doesn't matter for you, but bytea is limited to 1GB. For bigger files, store them outside the DB and just store a path and a checksum. – Craig Ringer Apr 25 '12 at 21:54
  • @BalusC Thanks a million :) That was just the perfect answer. I just got a small final doubt. While retrieving I ll get binary data. So to convert that into file and display that pdf file, What should I do? – suraj Apr 26 '12 at 04:25
  • Use `ResultSet#getBinaryStream()` to get it back from DB as `InputStream`. Do you want to provide it as a download? Just write to `HttpServletResponse#getOutputStream()` along some proper response headers so that the browser understands what to do with it. Do you want to save it as file? Just write it to `new FileOutputStream()`. Etcetera. Just write to any `OutputStream` to your flavor. See also http://stackoverflow.com/questions/4614935/how-to-display-a-pdf-file-in-jsp-using-servlet/4615155#4615155 – BalusC Apr 26 '12 at 04:28
  • @BalusC you said, the inputstream is unsuitable. The client ain't going to resend the file multiple times each time you need to read the InputStream again. What does it mean. Why should the client send the file multiple times? – Ashwin Apr 28 '12 at 01:51
  • @Ashwin: It's a network stream, not an in-memory byte array. Once a byte is read, it cannot be read anymore. To re-read it, the client has to re-send everything. – BalusC Apr 28 '12 at 02:32
  • @BalusC : okay.. So how does IOUtils work? To copy form the inputstream you have to read byte by byte and copy to the bytearrayoutput stream right. My question is how is using IOUtils different? – Ashwin Apr 28 '12 at 02:36
  • @Ashwin: It copies the `InputStream` to an in-memory byte array which can in turn be re-read multiple times. One time by `PdfReader` and another time by `PreparedStatement`. With an `InputStream`, the `PreparedStatement` would only retrive EOF because `PdfReader` has already consumed it. – BalusC Apr 28 '12 at 02:42
  • @BalusC : will this work. instead of copying the localfile.inputstream to an inputstream, directly do this : PdfReader localPdfReader = new PdfReader(localfile.getinputstream()); – Ashwin Apr 28 '12 at 02:56
  • @Ashwin: I am nowhere copying an `InputStream` to an `InputStream`. I think that you are just not understanding at all what the machine does under the covers. Go learn basic I/O and experiment a bit yourself. – BalusC Apr 28 '12 at 03:43
  • @BalusC : Where can I learn what the machine does "under the covers"? Everywhere only the code is given on the internet. Nowhere an explanation is given on how the machine interprets the code and what actions are triggered inside the machine. Here my questions is when you copy to bytearrayoutputstream using fileutils, you have to still read from the localfileitem.getinputstream() byte by byte and then copy it to the bytearrayoutputstream ,right? – Ashwin Apr 28 '12 at 07:57
  • @BalusC can u help me out for the question in this link http://stackoverflow.com/questions/10411433/validating-a-certificate-in-java/10411496#comment13432343_10411496 ? – suraj May 02 '12 at 11:39
1

There is a similar question in this forum. It use a image instead of a pdf. But the procedure may be the same. Save the stream to a file and store it to the database. Check it out. Maybe can help you.

For example, suppose you have a table containing the file name of an image and you also want to store the image in a bytea column:

CREATE TABLE images (imgname text, img bytea);

To insert an image, you would use:

File file = new File("myimage.gif");
FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = conn.prepareStatement("INSERT INTO images VALUES (?, ?)");
ps.setString(1, file.getName());
ps.setBinaryStream(2, fis, file.length());
ps.executeUpdate();
ps.close();
fis.close();
  • Even I had a look at the code you referred above. I have a doubt in my code whether the inputstream object "localInputStream" in this statement InputStream localInputStream = localFileItem.getInputStream(); is sufficient to store file in database or Do I need to do any conversions? – suraj Apr 25 '12 at 17:45