JSF 2 – Read from and write images to SQL database

Today we are going to show you our application that writes and then reads back an image from SQL database. Application looks like this.

JSF 2 - Read and write images from SQL database - Image upload form

JSF 2 – Read and write images from SQL database – Image upload form

JSF 2 - Read and write images from SQL database - Image from database

JSF 2 – Read and write images from SQL database – Image from database

This is a JSF 2 application. We are using a Primefaces component library. Application displays form which allows you to enter an image path from your local drive and send it to the server. There is a bean responsible for storing image send via the form.
There is also an image tag present on the sample site. Last uploaded image is being read by the servlet and send to the servlet output. This servlet is pointed to in the URL attribute of the image tag. This application concept looks like this.

JSF 2 - Read and write images from SQL database - High level components view

JSF 2 – Read and write images from SQL database – High level components view

Ok. Now we are going to show you how this application is coded. Let’s start from the database.

Database – MySQL

We are using a MySQL database engine in our example. This is a table creation script. Images are stored in the column of type BLOB.

CREATE TABLE files (
	id int(11) NOT NULL AUTO_INCREMENT,
	file blob NOT NULL,
	PRIMARY KEY (id)
);

Note that although we are using a MySQL database the whole application code was tested and will work also on the Oracle and MSSQL database engines. You will need to change only the database and the JDBC connector.

pom.xml

To see how to create a base project that was used in this tutorial please visit our earlier tutorial – Getting started with Primefaces using Eclipse IDE and Maven
.
Our project uses Primefaces, JSF2 API, Servlet API artifacts as the main technologies. We also need to specify the commons-fileupload, commons-io artifacts because they are used by the Primefaces upload mechanisms. The last used artifact is mysql-connector-java used to connect to our database.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.itcuties.examples.webapps</groupId>
	<artifactId>jsf2-sql-read-write-image</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>jsf2-sql-read-write-image Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<!-- Primefaces -->
		<dependency>
			<groupId>org.primefaces</groupId>
			<artifactId>primefaces</artifactId>
			<version>3.4</version>
		</dependency>
		<!-- JSF 2 API -->
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.2.0-m07</version>
		</dependency>
		<!-- Servlet API -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
		</dependency>
		<!-- Dependencies needed by the file upload -->
		<!-- Commons Fileupload -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.2.1</version>
		</dependency>
		<!-- Apache Commons IO -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-io</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!-- MySQL connector -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.22</version>
		</dependency>
	</dependencies>
	<repositories>
		<repository>
			<id>primefaces-repository</id>
			<name>Primefaces repository</name>
			<url>http://repository.primefaces.org</url>
		</repository>
	</repositories>
	<build>
		<finalName>sql-img</finalName>
	</build>
</project>

web.xml

This is web.xml descriptor of our application. We have JSF 2 and Primefaces configured the same way as we did in Getting started with Primefaces using Eclipse IDE and Maven
.
Here we also have our ImageServlet configuration. This servlet is mapped to the /image path of our application.
At the end you will find PrimeFaces FileUpload Filter configuration that allows your application to read files through the form.

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
	<display-name>Storing/Restoring image from SQL database</display-name>

	<!-- Current project stage. When it is set to 'Development' Primefaces give 
		a lot of debug information on the screen. -->
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>

	<welcome-file-list>
		<welcome-file>index.xhtml</welcome-file>
	</welcome-file-list>

	<!-- Staring JSF -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- JSF URL mapping -->
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>

	<!-- Servlet that displays latest uploaded file -->
	<servlet>
	    <servlet-class>com.itcuties.webapps.examples.storeimage.servlets.ImageServlet</servlet-class>
	    <servlet-name>ImageServlet</servlet-name>
	</servlet>
	<servlet-mapping>
	    <servlet-name>ImageServlet</servlet-name>
	    <url-pattern>/image</url-pattern>
	</servlet-mapping>

	<!-- Upload filter configuration -->
	<filter>
		<filter-name>PrimeFaces FileUpload Filter</filter-name>
		<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
		<init-param>
			<param-name>thresholdSize</param-name>
			<param-value>51200</param-value>
		</init-param>
		<init-param>
			<param-name>uploadDirectory</param-name>
			<param-value>c:/tmp</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>PrimeFaces FileUpload Filter</filter-name>
		<servlet-name>Faces Servlet</servlet-name>
	</filter-mapping>

</web-app>

index.xhtml

This is our sample view. It consist of the form, a fileUpload component that is used to read the image file and the graphicImage component that renders html img tag which takes image data from our ImageServlet.

<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:p="http://primefaces.org/ui">

<h:head>

</h:head>

<h:body>
	<h:form enctype="multipart/form-data">
		
		<p:messages showDetail="true" />

		<p:fileUpload value="#{imageStoreBean.file}" mode="simple" />

		<p:commandButton value="Submit" ajax="false" actionListener="#{imageStoreBean.storeImage}" />

		<h:graphicImage id="image" alt="uploaded image" url="/image"/>

	</h:form>
</h:body>
</html>

ImageStoreBean.java

This is our bean code. This code reads uploaded file bytes and stores it in the database. To store file bytes in the database you need use a setBinaryStream() method of the PreparedStatement class as shown in this example.

package com.itcuties.webapps.examples.storeimage.beans;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

import org.primefaces.model.UploadedFile;

@ManagedBean
@RequestScoped
public class ImageStoreBean {

	private UploadedFile file;
	
	// Store file in the database
	public void storeImage() {
		// Create connection
		try {
			// Load driver
			Class.forName("com.mysql.jdbc.Driver");
			// Connect to the database
			Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/itcuties?user=uploader&password=password");
			// Set autocommit to false to manage it by hand
			connection.setAutoCommit(false);
			
			// Create the statement object
			PreparedStatement statement = connection.prepareStatement("INSERT INTO files (file) VALUES (?)");
			// Set file data
			statement.setBinaryStream(1, file.getInputstream());
			
			// Insert data to the database
			statement.executeUpdate();
			
			// Commit & close
			connection.commit();	// when autocommit=false
			connection.close();
			
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Upload success", file.getFileName() + " is uploaded.");  
	        FacesContext.getCurrentInstance().addMessage(null, msg);
			
		} catch (Exception e) {
			e.printStackTrace();
			
			// Add error message
			FacesMessage errorMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Upload error", e.getMessage());  
	        FacesContext.getCurrentInstance().addMessage(null, errorMsg);
		}
		
	}

	// Getter method
	public UploadedFile getFile() {
		return file;
	}

	// Setter method
	public void setFile(UploadedFile file) {
		this.file = file;
	}	
}

ImageServlet.java

This code reads image bytes from the database and writes them to the standard servlet output. To read bytes from the database you need to use getBytes() method of the ResultSet class.
To write bytes to the servlet output stream use getOutputStream() of the HttpServletResponse method to get the stream and then the write() method. Remember to call the close() method after writing bytes to the output stream. This way all the byte will be written to the output.

package com.itcuties.webapps.examples.storeimage.servlets;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ImageServlet extends HttpServlet {

	private static final long serialVersionUID = -6449908958106497977L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// Get last uploaded image
		try {
			// Image bytes
			byte[] imageBytes = null;
			
			// Load driver
			Class.forName("com.mysql.jdbc.Driver");
			// Connect to the database
			Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/itcuties?user=uploader&password=password");
			
			// Create the statement
			// This query is specific to MySQL, it returns only one row (using 'LIMIT 1') - the last uploaded file
			PreparedStatement statement = connection.prepareStatement("SELECT id, file FROM files ORDER BY id DESC LIMIT 1");
			
			ResultSet rs = statement.executeQuery();
			
			while (rs.next()) {	// This will run only once
				imageBytes = rs.getBytes("file");
			}

			// Close the connection
			connection.close();
			
			resp.getOutputStream().write(imageBytes);
			resp.getOutputStream().close();
			
		} catch (Exception e) {
			// Display error message
			resp.getWriter().write(e.getMessage());
			resp.getWriter().close();
		}
		
	}	
}

Download this sample code here.

This code is available on our GitHub repository as well.

6 Responses to "JSF 2 – Read from and write images to SQL database"

  1. malik says:

    ı want to ask question , i can’t speak english
    but i did same this code in netbeans
    i have got primefaces but give me eror ?
    (i create table in mysql )
    if you have to running code , can you sent me ?
    thank you for your support

    Reply
  2. tulga says:

    How to do this Upload image file work in Java ee + JSF + PrimeFaces + API + jboss

    Reply
    • itcuties says:

      Which JBoss version are you using? We have tested this solution under JBoss 7.1 and it works like a charm :)

      Reply
  3. Nelson Viga says:

    Can I implements in a dinamyc web project without be a Maven Project?

    Reply
  4. Vladimir says:

    Hi,
    I tried this solution and it doesn’t work. I choose a picture and when I click the “Submit” button, I get the following message:
    Upload error – Field ‘file’ doesn’t have a default value
    I tried setting some default value for that column (NULL and 0), but phpMyAdmin says that a “blob” column cannot have a default value.
    What could be wrong and what’s the solution for this problem?

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Java by Example App is available at Google Play Store NOW