Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Handling images in JSF with BASE 64

See in this article how to use the base algorithm 64 to save images in JSF

In this article we will see the use of a very interesting method for data encoding, Base64. We will use this method to store an image in the database and then display it on the user page, using JSF.

Base64 is a method commonly used on the Internet to transfer data using the MIME encoding, its main purpose is to send binary data in ways we can only travel text, such as email attachments. It is simple and complex at the same time: Simple because it transforms the conventional method of sending files, it would be physically saved in a directory and only then to download the same, something faster and easier, converting all text. Complex because behind all this facility is the operation of the algorithm and how it works.

This consists of 64 characters ([A-Za-z0-9], "/" and "+") and so even if your name is "Base 64". It works with processing in bits from another standard, such as ASCII. Let's see a Word coding example "Man" in Table 1.

Table 1. Coding Examples

Now in bit values are converted to decimal and then the base 64 algorithm understands these decimals as indexes to be converted to a 64 characters, as shown in the following example:

Bits Decimal Base 64

0 1 0 0 1 1 = 19 T

0 1 0 1 1 0 = 22 W

0 0 0 1 0 1 = 5 F

1 0 1 1 1 0 = 46 u

Note that we can convert any type of information to base 64 since it works with binary and this is common to all types of data. In Table 2 you can see the complete table of conversion to base64.

Table 2. Binary Table

Converting images in Base 64

We have seen that we can work with any data type by converting string to its original type if necessary.

Let abstracting some more specific points of server settings, connection to the bank, etc., by focusing on the use of Base 64. What we need first is our table that will record the image, as shown in Listing 1.

Listing 1. Table Creating the database

 CREATE TABLE image_base_64
  (
    id serial NOT NULL,
    format character varying(255),
    name character varying(255),
    b64 text,
    CONSTRAINT image_base_64_pkey PRIMARY KEY (id )
  )
  WITH (
    OIDS=FALSE
  );
  ALTER TABLE image_base_64
    OWNER TO postgres;

The b64 field will store the content in base 64 in the text format (text choose because we will save a lot of characters and varchar very limit our maximum size), the format will store the image is JPG, PNG, bitmap, etc. Finally the name field records the original file name so that we can generate it with the same name that was saved.

Our bean follows the same model of the table, as shown in Listing 2.

Listing 2. Bean ImageBase64

 public class ImageBase64 {
         
         private String b64;
         private String format;
         private String name;
   
        public String getB64() {
               return b64;
         }
         public void setB64(String b64) {
               this.b64 = b64;
         }
   
         public String getFormat() {
               return format;
         }
         public void setFormat(String format) {
               this.format = format;
         }
         public String getName() {
               return name;
         }
         public void setName(String name) {
               this.name = name;
         }      
  }

The idea of our project is to enable the user to send an image, and this is converted to base 64 and then saved in the database.

In our XHTML you send the file and in our ManagedBean, which will be received and converted to base 64. Consider first our XHTML in Listing 3.

Listing 3. Definition of XHTML

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml"
         xmlns:h="http://java.sun.com/jsf/html"
         xmlns:f="http://java.sun.com/jsf/core"
         xmlns:ui="http://java.sun.com/jsf/facelets">
   
  <h:head>
  </h:head>
  <h:body>
    <h:form enctype="multipart/form-data">
       <h:inputFile value="#{base64MB.image}" />
       <h:commandButton action="#{base64MB.save()}" value="Send" />
    </h:form>  
  </h:body>
  </html> 

Our form is simple having only one inputFile and a commandButton to submit the information to ManagedBean. The use of " enctype=multipart/form-data " is essential for this type of data can be sent by request.

The commandButton triggers a call to save() action that we will see later in our ManagedBean.

Listing 4. Definition of ManagedBean

 import java.io.IOException;
   
  import javax.faces.bean.ManagedBean;
  import javax.faces.bean.ManagedProperty;
  import javax.faces.bean.ViewScoped;
  import javax.servlet.http.Part;
   
  import org.bouncycastle.util.encoders.Base64;
   
  import br.com.myproject.bean.ImageBase64;
  import br.com.myproject.util.Persist;
   
  @ManagedBean(name = "base64MB")
  @ViewScoped
  public class Base64ManagedBean {
         
         private Part image;
         
         @ManagedProperty(value = "#{persist}")
         private Persist per;
         
  public void save(){
               String format = image.getContentType();
               String name = image.getName();
               byte[] imageAsByte = new byte[(int) image.getSize()];
               try {
                      image.getInputStream().read(imageAsByte);
                      ImageBase64 ib4 = new ImageBase64();
                      String base64AsString = new String(Base64.encode(imageAsByte));
                      ib4.setB64(base64AsString);
                      ib4.setFormat(format);
                      ib4.setName(name);
                      bo.save(ib4);
                      
                      System.out.println(ib4.getB64());
               } catch (IOException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
               }
         }
   
         public Part getImage() {
               return image;
         }
   
         public void setImage(Part image) {
               this.image = image;
         }
   
         public Persist getPer() {
               return per;
         }
   
         public void setPer(Persist per) {
               this.per = per;
         }
  }

Let us understand the functioning of the Listing 4 code in parts:

  • First we have our object "private Part image" in general will record the image sent through the request of XHTML. We will explain later the function of javax.servlet.http.Part for now just know that this class is responsible for receiving the content sent by XHTML;
  • Just below we have the definition of a Persist object type:

@ManagedProperty(value="#{persist}")
Persist per private;

This object is only one class responsible for performing the insertion of content in the database, and at the time no matter us know how this insertion is performed but that it should be done in some way, either with Hibernate, JPA, JDBC or any other technique you are adopting for inserts in your project.

Do not forget that the get() and set() of both properties are required so that we can trigger the save() operation smoothly, as shown in the following code:

 public Part getImage() {
             return image;
       }
 
       public void setImage(Part image) {
             this.image = image;
       }
 
       public Persist getPer() {
             return per;
       }
 
 
       public void setPer(Persist per) {
             this.per = per;
       }

Finally, we come to the method that really matters, the save(). We captured some important information such as the content type and name:

String format = image.getContentType();
String name = image.getName();

Since the content is formatted as follows: image/png, image/jpg, etc. After we create a byte array with the image size with the getSize() method:

 byte[] imageAsByte = new byte[(int) image.getSize()];

So we ensure that we have enough space to store the size that the image need. Next, we need to read the content of this object bytes "image" and save it in our array "imageAsByte":

 image.getInputStream().read(imageAsByte);

The getInputStream().read() ensures the storage of the bytes in our array.

The org.bouncycastle.util.encoders.Base64 class is responsible for transforming our byte array into a String formatted in Base64. There are two method used, encode() and decode(), where the first encodes information for Base64, and Base64 the second decodes this information to the original value.

In the following lines we carry out this process

 ImageBase64 ib4 = new ImageBase64();

String base64AsString = new String(Base64.encode(imageAsByte));
ib4.setB64(base64AsString);
ib4.setFormat(format);
ib4.setName(name);

We create our object of type ImageBase64 and condition with the necessary content. The most important here is to note the following line:

 String base64AsString = new String(Base64.encode(imageAsByte));

This line converts a byte array and another array of bytes, the difference is that the second byte array is in base 64, but as we need to write a string in the bank and not a byte array, we use the "new String() "to convert this byte array to String.

Finally we call the method that will save the content in the database and then show the value in base 64 that store. We will not show the full result of the line:

 System.out.println(ib4.getB64());

For this it returns a lot of data, which would give at least 10 pages of characters only in base64.

See a part of it (for the image we spent), as shown in Listing 5.

Listing 5. Part Return ib4.getB64()

 /9j/4AAQSkZJRgABAQEASABIAAD//gATQ3JlYXRlZCB3aXRoIEdJTVD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAKGBQ4DASIAAhEBAxEB/8QAHQABAAMAAwEBAQAAAAAAAAAAAAUGBwMECAIBCf/EAFoQAAEDBAEDAgQCBwYEAgUAGwECAwQABQYREgcTISIxFBVB0lFVIzJTYZKUlQgWM0JxgRckUmJDkSUmNGOzcnN0ocHw8QkYNZaisdQ4R1ZldYKlsrTF0dPh/8QAGgEBAQEBAQEBAAAAAAAAAAAAAAECAwQFBv/EAD4RAAIBAQQJAwIEBQMFAAMBAAABEQIhMUHwElFhcZGhscHRAyKBBOEywtLxBRNCorJSYuIUI3KCkgYk8hX/2gAMAwEAAhEDEQA/APXVKVSctysMrWzBkLQ20dKcaAK3Vb1xTsaCQfr+P4AHfm+p+p9P6ejTrPT9P9PX9RXo0F2pVbg5dY0QY6Zt4jqkhpIeUlCgkr0ORHj23up+JIYlxm5MV5t5lxPJDjagpKh+IIrfp+tR6n4XJn1PQ9T0/wASa+DlpXw44htHJxQSn8TXVlTWuwrtPAL+nj/zrocju0roQJocUGnFbJ/VUfr+4/vrv0ApVYzfJFWZCI0bj8S4nmVKG+2n2Gh9VEg6+ngnzrRqE/IMotklKJUiYw6413QHUtK0k7AJSB48g+PSfFez0vovU9WmU0pPL6v1dHpuHLNWrr3CUmHFU8pClnYSlKfdSiQAP9yRUPgFwk3LHUyJTynlh5xAcUACpIUdb1+7xXfyD/2Jr/5rj/8AxU15vVofp1Ol4Hf061XSqlicmr+fIt0EfuMs7/8AnIpxyD8vgfzivsruZI++xb2zGeUw47KYZ7iQklIW6lJ1yBG9E+4qFu1yuFkuUZZmTrhFWy4p1pUQOEqBRxSktNjiSCsjl4PHXjexmDUne45B+XwP5xX2U45B+XwP5xX2VMwpLMyGzLjr5svIS42rWtpI2PFVzFcrRcLdfJ93XDt8a2XWTDLq3OCA20oAKUpR0Cd/6Ujz08ifGeB2uOQfl8D+cV9lOOQfl8D+cV9lSNvu1quNt+ZW+5wpcHRPxLD6VtaHv6gdeP8AWukjLsUctbt1Rk9kVb2XA27KE9otNrPslS+Wgf3E0iBJx8cg/L4H84r7Kccg/L4H84r7K6mSZY1DYx2VZ3YVxi3e6tQu+26Fo4LCyVIUk6J9P+ldfD88tV5ut0tEy42uLc4t0kQ2IXxSQ+6hs6C+BPI78+w14oqW86o8oNxnf4ZJ8cg/L4H84r7Kccg/L4H84r7K7r1+sTN4RZnb1bm7m4NohqlID6h+5G+R/wDKvyRf7DGvDVmkXu2s3N7XahuSkJfXv20gnkf9hSBJ0+OQfl8D+cV9lOOQfl8D+cV9ldXHM7xy9Trlb27lEjT7fKfjuxHpLYe00rSnOG9hH12alLhfI8V9DDMeTOcUz3ymKlKuLf8A1EkgaP01smpFiYm1rUdXjkH5fA/nFfZTjkH5fA/nFfZXJIySChuOqMxLml9j4gJjtglLX/UrZGv9Pf8AdX1IyKGkM/CsSp5dY+IAjIBKW/oo8iP/AC9/HtVgScPHIPy+B/OK+ynHIPy+B/OK+yuSRkkFDcdUZiXNL7HxATHbBKWv+pWyNf6e/wC6pWHJZmRG ...

This is only 1% of the total content of our image sent. The interesting thing here is that if we put all the content of our image in Bas64 suffice you copy the entire list and perform the "decode()" whatever language you are working (Java, PHP, Python, Ruby ...) and image will be generated, since the language can be different but the algorithm is the same.

Note that we are working only with images but our scope is fully adapted to work well with any kind of file: PDF, txt, MP4, AVI, JPG, PNG and any other type of file, because the idea will always be the same: Capture content in bytes and convert to base64 and send it to wherever it is, in our case we are saving in a database but we could send to another system via XML, JSON or even calling a webservice or via HTTP, etc. The range of possibilities is huge and when we started working with this "wonderful" algorithm realize that everything is more simple and practical, no longer need to create supercomplexas structures to save user-uploaded files.

Pros and cons

Unfortunately the base algorithm 64 is not a "silver bullet" that kills anything, it has its drawbacks.

One of the disadvantages of working with this type of method is the large amount of information that is stored in the database, making the queries become slower and consequently the construction of the original file also different than it would only capturássemos the file in a directory where it is already saved. Imagine a very large file, 1 GB for example, you probably would have serious problems if trying to load the information converted into Base 64 of this size, the ideal would be to break the file into smaller blocks to join it later, thus bringing more complexity to the project.

Make a test yourself, convert a video for your 500MB Base 64, and then try to copy the contents somewhere, you will see a very slow due to be trying to upload 500MB of information into memory at once.

Another point you will notice is an increase of approximately 33% of the original file size after conversion to base64, this can have a considerable weight in data transfer over a network. Moreover the conversion of large files base 64 and vice versa is cost standpoint processing required by CPU.

The great advantage of using the base algortimo 64 is on practicality and flexibility when working with communication between different systems, this standardizes the communication between the systems as well as XML. Before you would have to make a complex structure of stored files in a directory, saving a pointer to this file so that you can retrieve it with agility later, but with base64 none of this is necessary because you will have every file on a String, not that this is the best solution but it is certainly the most practical.

The use of javax.servlet.http.Part class

In previous sections we use the javax.servlet.http.Part class for the transfer of the file via HTTP. In JSF 2.2 has been introduced inputFile component along with the servlet 3.0 (which provides the javax.servlet.http.Part class) enables us to handle sending files via HTTP without the need for third-party libraries like Primefaces, omnifaces, and icefaces etc.

To be able to use the javax.servlet.http.Part class you need to add a servlet-api.jar library version 3.0 in your project, there are two ways to do this:

1. If you use Maven, then just add the Listing 6 code in your pom.xml file.

Listing 6. Adding servlet-api.jar in pom.xml

 <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
       <version>3.0-alpha-1</version>
</dependency>

It is mandatory that the version is 3.0 or higher.

2. Another way is to manually add to your build path. Click the right button on your project and go to the "Properties" option. On the screen to open search for "Java Build Path" and go to the tab "Libraries".

Click "Add External JARs ..." and look for the servlet-api.jar library, which must be within the just "lib" of your tomcat.

Once this is done, your project will be able to use the javax.servlet.http.Part class. Class Part is actually not a class but an interface that represents the file sent as part of a request multipart/form-data. So it's important that your form has the "enctype" set to "multipart/form-data":

<h:form enctype="multipart/form-data">

When we try to submit a form, or process a request without the above definition, we have the following error:

org.apache.tomcat.util.http.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is application/x-www-form-urlencoded

Briefly, this error indicates that it is necessary to use the multipart/form-data or multipart/mixed to send a form that has a file, be it of any kind.

When using the Base 64? There is no general rule to use this method, which will set your need or are not the business rules of your system, as with most of the features.

Usually this is used when it is need to send content (files) to other systems with languages or different structures, as it works with bit-level conversion, no matter what language is receiving data. Another less common use is the need for file storage in the database, or even within a Java class (if the file is not too large). Imagine that you need to upload a file ".ddc" 1KB every time the user opens the system, so you could use the base algorithm 64 to store it within your own code just recreating it each system opening. But be careful, it is not a good practice to keep files in base64 within the code itself, it can make your slow and extremely large system (in terms of physical space consumed).



Fabrí­cio Galdino is a software expert and has worked with IT analysis and business development for more than five years. It has extensive experience with testing, back and front-end technologies.

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login