Enterprise Java

Developing a personal mini Photo Gallery application using Struts2, Hibernate and MySQL BLOB – Part 1

Overview:

In this workshop we’ll develop a web application which we can use to create a beautiful photo gallery. This you can host in a web server or you can use in your own PC to maintain and manage your collection of photos. Using this tutorial you will be able to learn the following important points related to Struts2 and Hibernate:

  • How to integrate Struts2 framework with Hibernate
  • How to upload photo or file in Struts2
  • How to dynamically upload/download photos to and from MySQL BLOB field
  • How to pass parameters dynamically from one action to another action in Struts2

In Part-1 of this tutorial, we’ll develop the admin panel. Admin Panel will be used to create photo album and upload photos to the album. In Part-2 we’ll create the front end main web application which will display photos by albums as added in the admin panel.

Tools Used:

  1. Eclipse Indigo Java EE IDE for Web Developers
  2. Struts 2
  3. Hibernate 3
  4. Hibernate Tools Eclipse Plugin Version 3.5.1
  5. mysql JDBC jar (mysql-connector-java-5.1.23)
  6. Tomcat 7

Step 1: Preparing the Database MySQL for the Photo gallery application

We’ll be using MySQL database. Belw is the script for you to create the database tables. The database name use used is ‘tctalk_apps_photoalbum’ . However you can create any database name. Just remember you need to change the database name in Hibernate configuration file. Below are SQLs for the two tables album and phototbl.

CREATE TABLE IF NOT EXISTS `album` (
  `albumid` INT(4) NOT NULL AUTO_INCREMENT,
  `albumname` VARCHAR(55) NOT NULL,
  `albumdesc` text NOT NULL,
  `albumcreatedate` DATE NOT NULL,
  PRIMARY KEY (`albumid`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `phototbl` (
  `photoid` INT(4) NOT NULL AUTO_INCREMENT,
  `albumid` INT(4) NOT NULL,
  `phototitle` VARCHAR(255) NOT NULL,
  `photoname` VARCHAR(255) NOT NULL,
  `imgcontenttype` VARCHAR(255) NOT NULL,
  `photocreatedate` datetime NOT NULL,
  `photodata` longblob NOT NULL,
  PRIMARY KEY (`photoid`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

Step 2: Create the packages in the java source

Create the packages in java src side after creating the dynamic web project in Eclipse. Remember the packages com.tctalk.apps.album.db.xxx holds all java and other files for working in database/hibernate side whereas com.tctalk.apps.album.web.xxx will have all java files for the presentation layer using struts2 framework.

image001

Businessobjects will have all BO classes mapped with tables. Dao will have the DAO classes to call database using Hibernate. Hbm will have *.hbm.xml files which has the mapping of the table fields and table java. Utils will have all kind of Utility classes. Actions will have all Action classes of the Struts2 framework. Delegates will have the delegate classes as a bridge between UI layer and DB layer. Forms will have the POJO(Plain Old Java Objects) correspond to UI fields. Hibernate.cfg.xml has the hibernate configuration file to have database connection information to connect to the database. Struts.xml has the Struts configurations data.

Step 3: Copy the jar files in the lib folder

image003

You would require servlet-api.jar file which you’ll get from Tomcat installation directory. My Tomcat is in C:\Java\Tomcat\tomcat7 folder.

Step 4: Add Struts 2 support to our app

We already have the required jar files for Struts2 support in our app. Now it is time to include the Struts2.xml and put the reference in web.xml to let Tomcat know about it.

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
<display-name>PersonalPhotoAlbumApp</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
 <filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>*.action</url-pattern>
</filter-mapping>
</web-app>

Struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="false" />

    <package name="default" extends="struts-default" namespace="/">

    <result-types>
		<result-type name="imageResult" class="com.tctalk.apps.album.web.actions.CustomPhotoResult" />
	</result-types>

    <default-action-ref name="index" />

    <action name="index">
        <result>index.jsp</result>
    </action>

    <action name="admin">
        <result name="success" type="redirectAction">listAlbumAdmn</result>
    </action>

    <action name="listAlbumAdmn" 
    	class="com.tctalk.apps.album.web.actions.PhotoAlbumAdminAction" method="getAllAlbumList" >
       	<result name="success">/WEB-INF/admin/jsp/showalbums.jsp</result>
    </action>

    <action name="addAlbumAdmn" 
    	class ="com.tctalk.apps.album.web.actions.PhotoAlbumAdminAction" method="addAlbumToCollection" >
    	<result name="input">listAlbumAdmn</result>
       	<result name="success" type="redirectAction">listAlbumAdmn</result>
    </action>

    <action name="delAlbumAdmn" 
    	class ="com.tctalk.apps.album.web.actions.PhotoAlbumAdminAction" method="delAlbumFromCollection" >
       	<result name="success" type="redirectAction">listAlbumAdmn</result>
    </action>

    <action name="listPhotosByAlbumAdmn" 
    	class="com.tctalk.apps.album.web.actions.PhotoAlbumAdminAction" method="listAllPhotos" >
       	<result name="success">/WEB-INF/admin/jsp/showphotos.jsp</result>
    </action>

    <action name="addPhotoAcion" 
    	class ="com.tctalk.apps.album.web.actions.PhotoAlbumAdminAction" method="uploadPhotoToAlbum" >
    		<interceptor-ref name="exception"/>
            <interceptor-ref name="i18n"/>
            <interceptor-ref name="fileUpload">
        		<param name="allowedTypes">image/x-png,image/png,image/gif,image/jpeg,image/pjpeg</param>
    		</interceptor-ref> 
    		<interceptor-ref name="params">
                <param name="excludeParams">dojo\..*,^struts\..*</param>
            </interceptor-ref>
            <interceptor-ref name="validation">
                <param name="excludeMethods">input,back,cancel,browse</param>
            </interceptor-ref>
            <interceptor-ref name="workflow">
                <param name="excludeMethods">input,back,cancel,browse</param>
            </interceptor-ref>

       	<result name="success" type="redirectAction">
       		<param name="actionName">listPhotosByAlbumAdmn</param>
         	<param name="albumid">${albumid}</param>
       	</result>

    	<result name="input">/WEB-INF/admin/jsp/showphotos.jsp</result>
    </action>

    <action name="delPhotoFrmAlbumAdmn" 
    	class ="com.tctalk.apps.album.web.actions.PhotoAlbumAdminAction" method="delPhoto" >
       	<result name="success" type="redirectAction">
       		<param name="actionName">listPhotosByAlbumAdmn</param>
         	<param name="albumid">${albumid}</param>
       	</result>
    </action>

    <action name="showPhotoAction"  
    	class="com.tctalk.apps.album.web.actions.PhotoAlbumAdminAction" method="showPhoto">
		<result name="success" type="imageResult"/>
	</action>

 </package>

</struts>

Step 5: Add Hibernate support to our photo album app

To work with hibernate we already have a nice step by step tutorial which shows how you can use Hibernate plugin in Eclipse to auto-generate the hbm and java files coresponds to the tables in your database. Check the tutorial – http://www.techcubetalk.com/2013/04/step-by-step-auto-code-generation-for-pojo-domain-java-classes-and-hbm-files-using-elipse-hibernate-plugin/

  1. Create hibernate.cfg.xml with database connection information to connect to the database
  2. Create the POJO classes using the plugin and keep in the package corresponding to the tables. In our app we’ll be using two tables album and phototbl, so we have two POJO classes for that.
  3. Then add the hbm files correspond to the two POJO classes created in above steps
  4. Next we’ll add the HibernateUtils.java for handling the hibernate session easily in our application. Also in the same package we are keeping one constant file to keep any constants we have in our project.
  5. Now we’ll add the DAO classes which will have all the methods to interact with database.
    1. ListgetAllPhotoAlbums() – returns list of all albums from the database
    2. boolean addAlbum(AlbumBO album) – this adds an album to the database
    3. boolean delAlbum(int albumId) – delete the album and all the photos under this album
    4. ListgetAllPhotosFromAlbum(int albumid) – Returns all photos from the album based on the albumid
    5. boolean addPhotoToAlbum(PhototblBO photo) – add photo object to the album
    6. boolean delPhotoFromAlbum(int photoid) – delete photo from the album
    7. ListgetPhoto(int photoid) – returns the photo object to display in the page

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/tctalk_apps_photoalbum</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">true</property>

    <mapping resource="com/tctalk/apps/album/db/hbm/Album.hbm.xml" />
    <mapping resource="com/tctalk/apps/album/db/hbm/Phototbl.hbm.xml" />

    </session-factory>    
</hibernate-configuration>

AlbumBO.java

package com.tctalk.apps.album.db.businessobjects;
// Generated Apr 22, 2013 1:26:39 PM by Hibernate Tools 3.4.0.CR1

import java.util.Date;

/**
 * Album generated by hbm2java
 */
public class AlbumBO implements java.io.Serializable {

	private Integer albumid;
	private String albumname;
	private String albumdesc;
	private Date albumcreatedate;

	public AlbumBO() {
	}

	public AlbumBO(String albumname, String albumdesc, Date albumcreatedate) {
		this.albumname = albumname;
		this.albumdesc = albumdesc;
		this.albumcreatedate = albumcreatedate;
	}

	public Integer getAlbumid() {
		return this.albumid;
	}

	public void setAlbumid(Integer albumid) {
		this.albumid = albumid;
	}

	public String getAlbumname() {
		return this.albumname;
	}

	public void setAlbumname(String albumname) {
		this.albumname = albumname;
	}

	public String getAlbumdesc() {
		return this.albumdesc;
	}

	public void setAlbumdesc(String albumdesc) {
		this.albumdesc = albumdesc;
	}

	public Date getAlbumcreatedate() {
		return this.albumcreatedate;
	}

	public void setAlbumcreatedate(Date albumcreatedate) {
		this.albumcreatedate = albumcreatedate;
	}

}

PhototblBO.java

package com.tctalk.apps.album.db.businessobjects;
// Generated Apr 22, 2013 1:26:39 PM by Hibernate Tools 3.4.0.CR1

import java.util.Date;

/**
 * Phototbl generated by hbm2java
 */
public class PhototblBO implements java.io.Serializable {

	private int photoid;
	private int albumid;
	private String phototitle;
	private String photoname;
	private String imgcontenttype;
	private Date photocreatedate;
	private byte[] photodata;

	public PhototblBO() {
	}

	public PhototblBO(int photoid, int albumid, String phototitle,
			String photoname, String imgcontenttype, Date photocreatedate,
			byte[] photodata) {
		this.photoid = photoid;
		this.albumid = albumid;
		this.phototitle = phototitle;
		this.photoname = photoname;
		this.imgcontenttype = imgcontenttype;
		this.photocreatedate = photocreatedate;
		this.photodata = photodata;
	}

	public int getPhotoid() {
		return this.photoid;
	}

	public void setPhotoid(int photoid) {
		this.photoid = photoid;
	}

	public int getAlbumid() {
		return this.albumid;
	}

	public void setAlbumid(int albumid) {
		this.albumid = albumid;
	}

	public String getPhototitle() {
		return this.phototitle;
	}

	public void setPhototitle(String phototitle) {
		this.phototitle = phototitle;
	}

	public String getPhotoname() {
		return this.photoname;
	}

	public void setPhotoname(String photoname) {
		this.photoname = photoname;
	}

	public String getImgcontenttype() {
		return this.imgcontenttype;
	}

	public void setImgcontenttype(String imgcontenttype) {
		this.imgcontenttype = imgcontenttype;
	}

	public Date getPhotocreatedate() {
		return this.photocreatedate;
	}

	public void setPhotocreatedate(Date photocreatedate) {
		this.photocreatedate = photocreatedate;
	}

	public byte[] getPhotodata() {
		return this.photodata;
	}

	public void setPhotodata(byte[] photodata) {
		this.photodata = photodata;
	}

}

Album.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Apr 22, 2013 1:26:40 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.tctalk.apps.album.db.businessobjects.AlbumBO" table="album" catalog="tctalk_apps_photoalbum">
        <id name="albumid" type="java.lang.Integer">
            <column name="albumid" />
            <generator class="identity" />
        </id>
        <property name="albumname" type="string">
            <column name="albumname" length="55" not-null="true" />
        </property>
        <property name="albumdesc" type="string">
            <column name="albumdesc" length="65535" not-null="true" />
        </property>
        <property name="albumcreatedate" type="date">
            <column name="albumcreatedate" length="10" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

Phototbl.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Apr 22, 2013 1:26:40 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.tctalk.apps.album.db.businessobjects.PhototblBO" table="phototbl" catalog="tctalk_apps_photoalbum">
        <id name="photoid" type="int">
            <column name="photoid" />
            <generator class="assigned" />
        </id>
        <property name="albumid" type="int">
            <column name="albumid" not-null="true" />
        </property>
        <property name="phototitle" type="string">
            <column name="phototitle" not-null="true" />
        </property>
        <property name="photoname" type="string">
            <column name="photoname" not-null="true" />
        </property>
        <property name="imgcontenttype" type="string">
            <column name="imgcontenttype" not-null="true" />
        </property>
        <property name="photocreatedate" type="timestamp">
            <column name="photocreatedate" length="19" not-null="true" />
        </property>
        <property name="photodata" type="binary">
            <column name="photodata" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

HibernateUtils.java

package com.tctalk.apps.album.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {
	private static SessionFactory hbmSessionFactory;

	static {
		try {
			Configuration cfg = new Configuration()
					.configure(PhotoAlbumConstant._HIBERNATE_CONFIG_LOCATION);
			hbmSessionFactory = cfg.buildSessionFactory();
		} catch (RuntimeException ex) {
			System.out.println("********* Error occurred while reading config file *********");
			ex.printStackTrace();
		}
	}

	/**
	 * getSession creates hibernate Session & returns it
	 */
	public static Session getSession() {
		return hbmSessionFactory.openSession();
	}

	/**
	 * closeSession closes the session, if it exists
	 */
	public static void closeSession(Session inSession) {
		if (inSession != null) {
			inSession.close();
		}
	}
}

PhotoAlbumConstant.java

package com.tctalk.apps.album.utils;

public interface PhotoAlbumConstant {

	String _HIBERNATE_CONFIG_LOCATION = "hibernate.cfg.xml";
	String _HQL_DEL_PHOTOS_ALBUM = "DELETE FROM PhototblBO WHERE albumid= :albumid";	
}

PhotoAlbumAdminDao.java

package com.tctalk.apps.album.db.dao;

import java.util.List;

import com.tctalk.apps.album.db.businessobjects.AlbumBO;
import com.tctalk.apps.album.db.businessobjects.PhototblBO;

public interface PhotoAlbumAdminDao {
	// Photo Album related operations
	public List<AlbumBO> getAllPhotoAlbums();	
	public boolean addAlbum(AlbumBO album);
	public boolean delAlbum(int albumId);

	//Photo related operations
	public List<PhototblBO> getAllPhotosFromAlbum(int albumid);
	public boolean addPhotoToAlbum(PhototblBO photo);
	public boolean delPhotoFromAlbum(int photoid);
	public List<PhototblBO> getPhoto(int photoid);
}

PhotoAlbumAdminDaoImpl.java

package com.tctalk.apps.album.db.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import com.tctalk.apps.album.db.businessobjects.AlbumBO;
import com.tctalk.apps.album.db.businessobjects.PhototblBO;
import com.tctalk.apps.album.utils.HibernateUtils;
import com.tctalk.apps.album.utils.PhotoAlbumConstant;

public class PhotoAlbumAdminDaoImpl implements PhotoAlbumAdminDao, PhotoAlbumConstant {

	/**
	 * The below methods will be used for handling the Photo album related
	 * operations
	 * 
	 */

	/**
	 * This function retrieves all the photo albums and send the list to the
	 * front end
	 */
	public List<AlbumBO> getAllPhotoAlbums() {
		List<AlbumBO> albumList = null;
		Session hbmSession = null;
		try {
			hbmSession = HibernateUtils.getSession();
			Criteria criteria = hbmSession.createCriteria(AlbumBO.class);
			albumList = criteria.list();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			HibernateUtils.closeSession(hbmSession);
		}

		return albumList;
	}

	/**
	 * This function adds one photo album to the database
	 */
	public boolean addAlbum(AlbumBO album) {
		Session hbmSession = null;
		boolean STATUS_FLAG = true;
		try {
			hbmSession = HibernateUtils.getSession();
			hbmSession.beginTransaction();

			// change the creation date to today's date in the album object
			album.setAlbumcreatedate(new Date());
			// add the album to the hibernate session to save
			hbmSession.save(album);
			hbmSession.getTransaction().commit();
		} catch (Exception ex) {
			hbmSession.getTransaction().rollback();
			ex.printStackTrace();
			STATUS_FLAG = false;
		} finally {
			HibernateUtils.closeSession(hbmSession);
		}
		return STATUS_FLAG;
	}

	/**
	 * This function deletes the photoalbum based on the album id. It first
	 * check if the album has any photos or not. If the album is not emptry then
	 * it deletes the photos first and then delete the album itself
	 */
	public boolean delAlbum(int albumId) {
		Session hbmSession = null;
		boolean STATUS_FLAG = true;
		try {
			// get the hibernate session to perform delete operation
			hbmSession = HibernateUtils.getSession();
			hbmSession.beginTransaction();

			//delete all photos from the Photo table correspond to the album id
			Query query = hbmSession.createQuery(_HQL_DEL_PHOTOS_ALBUM);
			query.setInteger("albumid", new Integer(albumId));
			int rowCount = query.executeUpdate();
	        System.out.println("Rows affected: " + rowCount);

			//now load the album object from Album table and delete it correspond to the album id
			AlbumBO albumObj = (AlbumBO) hbmSession.load(AlbumBO.class, albumId);
			hbmSession.delete(albumObj);

			hbmSession.getTransaction().commit();
		} catch (Exception ex) {
			hbmSession.getTransaction().rollback();
			ex.printStackTrace();
			STATUS_FLAG = false;
		} finally {
			HibernateUtils.closeSession(hbmSession);
		}
		return STATUS_FLAG;
	}

	/**
	 * The below functions will be helpful to work on the Photos in the photo
	 * album
	 */

	/**
	 * This function retrieves all the photos and send the list to the front end
	 */
	public List<PhototblBO> getAllPhotosFromAlbum(int albumid) {
		List<PhototblBO> photoList = null;
		Session hbmSession = null;
		Criteria criteria = null;

		try {
			hbmSession = HibernateUtils.getSession();
			hbmSession.beginTransaction();

			// retrieve all photos from photo table correspond to the album Id
			criteria = hbmSession.createCriteria(PhototblBO.class).add(
					Restrictions.eq("albumid", albumid));
			photoList = criteria.list();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			HibernateUtils.closeSession(hbmSession);
		}
		return photoList;
	}

	/**
	 * This function adds photo to the album
	 */
	public boolean addPhotoToAlbum(PhototblBO photoobj) {
		Session hbmSession = null;
		boolean STATUS_FLAG = true;
		try {
			hbmSession = HibernateUtils.getSession();
			hbmSession.beginTransaction();
			hbmSession.save(photoobj);
			hbmSession.getTransaction().commit();
		} catch (Exception ex) {
			hbmSession.getTransaction().rollback();
			ex.printStackTrace();
			STATUS_FLAG = false;
		} finally {
			HibernateUtils.closeSession(hbmSession);
		}
		return STATUS_FLAG;
	}

	/**
	 * This function deletes the photo from the album itself
	 */
	public boolean delPhotoFromAlbum(int photoid) {
		Session hbmSession = null;
		boolean STATUS_FLAG = true;

		try {
			// get the hibernate session to perform delete operation
			hbmSession = HibernateUtils.getSession();
			hbmSession.beginTransaction();
			PhototblBO photoobj = (PhototblBO) hbmSession.load(
					PhototblBO.class, photoid);
			hbmSession.delete(photoobj);
			hbmSession.getTransaction().commit();
		} catch (Exception ex) {
			hbmSession.getTransaction().rollback();
			ex.printStackTrace();
			STATUS_FLAG = false;
		} finally {
			HibernateUtils.closeSession(hbmSession);
		}
		return STATUS_FLAG;
	}

	/**
	 * This function returns the photo object itself
	 */
	public List<PhototblBO> getPhoto(int photoid) {
		List<PhototblBO> photoList = null;
		Session hbmSession = null;
		Criteria criteria = null;

		try {
			hbmSession = HibernateUtils.getSession();
			hbmSession.beginTransaction();

			// retrieve all photos from photo table correspond to the album Id
			criteria = hbmSession.createCriteria(PhototblBO.class).add(
					Restrictions.eq("photoid", photoid));
			photoList = criteria.list();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			HibernateUtils.closeSession(hbmSession);
		}
		return photoList;
	}

}

Step 6: Develop the UI part

Create the ‘admin’ folder to keep all admin related UI files. Though we’ll not have CSS or JavaScript file in our app still we’ll create folders as a placeholder. We’ll add two jsp files – showalbums.jsp – this will be used to show existing albums as well as fields to add one album to the database

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>TechcubeTalk.com - Let's build apps from scratch series - Personal Photo Album App</title>
</head>
<body>
<h2>:: TechcubeTalk.com - Personal Photo Album Admin Panel ::</h2>
<div style="margin-bottom: 25px;">
<s:form action="addAlbumAdmn" method="POST">
		<s:textfield label="Photo Album Name/Title" name="album.albumname"/>
		<s:textfield label="Optional Brief Description" name="album.albumdesc"/>
		<br/>	
		<s:submit value="Create Photo Album" align="center"/>
</s:form>
<hr/>
</div>
<div>
	<table style="border: 1px dotted black;">
	<tr>
	    <th style="background-color:#ABDCFF;" align="center"> Album Id </th>
	    <th style="background-color:#ABDCFF;" align="center"> Photo Album Title </th>
	    <th style="background-color:#ABDCFF;" align="center"> Brief Description </th>
	    <th style="background-color:#ABDCFF;" align="center"> Created On </th>
	    <th style="background-color:#ABDCFF;" align="center"> Delete? </th>
	    <th style="background-color:#ABDCFF;" align="center"> View Photos in Album </th>
	</tr>
	<s:iterator value="albumList" var="album">
	    <tr>
	        <td align="center"><s:property value="albumid"/></td>
	        <td align="center"><s:property value="albumname"/></td>
	        <td align="center"><s:property value="albumdesc"/></td>
	        <td align="center"><s:property value="albumcreatedate"/></td>
	        <td align="center"> <a href="delAlbumAdmn.action?albumid=<s:property value="albumid"/>">Delete</a> </td>
	        <td align="center"> <a href="listPhotosByAlbumAdmn.action?albumid=<s:property value="albumid"/>">Click to View</a> </td>
	    </tr>
	</s:iterator>
	</table>
</div>
</body>
</html>

showphotos.jsp – this jsp will show all photos under the album user will click. Also it will show fields to upload photos under that directory.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>TechcubeTalk.com - Let's build apps from scratch series - Personal Music Manager Application</title>
</head>
<body>
<h2>:: TechcubeTalk.com - Personal Photo Album Admin Panel ::</h2>
<div style="margin-bottom: 25px;">
<s:form action="addPhotoAcion" namespace="/" method="POST" enctype="multipart/form-data">
<s:textfield label="Photo Title" name="photoTitle"/>
<s:file name="fileUpload" label="Select a File to upload" size="40" />
<s:hidden name="albumid" value="%{albumid}" />

<s:submit value="Upload Photo to Album" name="submit" />
</s:form>

</div>
<div> <a href="listAlbumAdmn.action"><< Back to Albums</a></div>
<div>
	<table style="border: 1px dotted black;">
	<tr>
	    <th style="background-color:#ABDCFF;">Photo Id</th>
	    <th style="background-color:#ABDCFF;">Photo Title</th>
	    <th style="background-color:#ABDCFF;">Upload Date</th>
	    <th style="background-color:#ABDCFF;">View Photo</th>
	    <th style="background-color:#ABDCFF;">Delete Photo</th>
	</tr>
	<s:iterator value="photoList" var="photo">
	    <tr>
	        <td><s:property value="photoid"/></td>
	        <td><s:property value="phototitle"/></td>
	        <td><s:property value="photocreatedate"/></td>
	        <td><a href="showPhotoAction.action?photoid=<s:property value="photoid"/>" target="_blank">View</a></td>
	        <td><a href="delPhotoFrmAlbumAdmn.action?albumid=<s:property value="albumid"/>&photoid=<s:property value="photoid"/>">Delete</a></td>
	    </tr>
	</s:iterator>
	</table>
</div>
</body>
</html>

Step 7: Add Action classes and the custom result class

PhotoAlbumAdminAction extends the POJO PhotoAlbumForm.java to hold submitted form fields and other values for the UI page. We uses one custom result displaying the photo by fetching it as binary file from the BLOB field database.

PhotoAlbumAdminAction.java

package com.tctalk.apps.album.web.actions;

import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FileUtils;

import com.tctalk.apps.album.db.businessobjects.AlbumBO;
import com.tctalk.apps.album.db.businessobjects.PhototblBO;
import com.tctalk.apps.album.web.delegates.PhotoAlbumAdminDelegate;
import com.tctalk.apps.album.web.forms.PhotoAlbumForm;

public class PhotoAlbumAdminAction extends PhotoAlbumForm {

	private static final long serialVersionUID = 9168149105719285096L;
	private PhotoAlbumAdminDelegate delegate = new PhotoAlbumAdminDelegate();

	public String getAllAlbumList() {
		List<AlbumBO> albumList = delegate.getAllPhotoAlbums();
		String returnString = ERROR;

		if (albumList != null) {
			setAlbumList(albumList);
			returnString = SUCCESS;
		}
		return returnString;
	}

	public String addAlbumToCollection() {
		String returnString = ERROR;
		AlbumBO album = getAlbum();

		if (delegate.addAlbumToCollection(album)) {
			returnString = SUCCESS;
		}

		return returnString;
	}

	public String delAlbumFromCollection() {
		String returnString = ERROR;

		int albumId = getAlbumid();
		if (delegate.delAlbumFromCollection(albumId)) {
			returnString = SUCCESS;
		}

		return returnString;
	}

	public String listAllPhotos() {
		List<PhototblBO> photoList = delegate.getAllPhotos(this.getAlbumid());
		String returnString = ERROR;

		if (photoList != null) {
			this.setPhotoList(photoList);
			returnString = SUCCESS;
		}
		return returnString;
	}

	public String uploadPhotoToAlbum() {
		String returnString = ERROR;
		PhototblBO photoBO = new PhototblBO();

		// set the uploaded file meta data to the PhototblBO object before
		// saving to database
		photoBO.setAlbumid(getAlbumid());
		photoBO.setPhotocreatedate(new Date());
		photoBO.setImgcontenttype(getFileUploadContentType());
		photoBO.setPhotoname(getFileUploadFileName());
		photoBO.setPhototitle(getPhotoTitle());
		try {
			// the uploaded file is in File format so we need to convert to
			// byte[] array for storing in our database. For this apache 
			//common file utility class is used below.
			photoBO.setPhotodata(FileUtils.readFileToByteArray(getFileUpload()));
		} catch (IOException e) {
			e.printStackTrace();
		}

		setPhotobo(photoBO);
		setAlbumid(photoBO.getAlbumid());
		if (delegate.addAPhoto(getPhotobo())) {
			returnString = SUCCESS;
		}

		return returnString;
	}

	public String delPhoto() {
		String returnString = ERROR;

		int photoId = getPhotoid();
		if (delegate.delPhoto(photoId)) {
			returnString = SUCCESS;
		}

		return returnString;
	}

	public String showPhoto() {
		String returnString = ERROR;
		List<PhototblBO> photoList = delegate.getPhoto(this.getPhotoid());

		if (photoList != null) {
			PhototblBO photoBO = (PhototblBO)photoList.get(0);
			if(photoBO != null){
				setPhotobo(photoBO);
				returnString = SUCCESS;
			}
		}
		return returnString;
	}

}

PhotoAlbumForm.java

package com.tctalk.apps.album.web.forms;

import java.io.File;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;
import com.tctalk.apps.album.db.businessobjects.AlbumBO;
import com.tctalk.apps.album.db.businessobjects.PhototblBO;

public class PhotoAlbumForm extends ActionSupport{

	private static final long 	serialVersionUID 		 = 706337856877546963L;

	private List<AlbumBO> 		albumList 				 = null;
	private List<PhototblBO> 	photoList 				 = null;

	private AlbumBO 			album					 = null;
	private PhototblBO 			photobo					 = null;

	private File 				fileUpload;
	private String 				fileUploadContentType;
	private String 				fileUploadFileName;
	private String 				photoTitle;
	private int 				photoid;
	private int 				albumid;

	public String getFileUploadContentType() {
		return fileUploadContentType;
	}

	public void setFileUploadContentType(String fileUploadContentType) {
		this.fileUploadContentType = fileUploadContentType;
	}

	public String getFileUploadFileName() {
		return fileUploadFileName;
	}

	public void setFileUploadFileName(String fileUploadFileName) {
		this.fileUploadFileName = fileUploadFileName;
	}

	public File getFileUpload() {
		return fileUpload;
	}

	public void setFileUpload(File fileUpload) {
		this.fileUpload = fileUpload;
	}

	public String getPhotoTitle() {
		return photoTitle;
	}

	public void setPhotoTitle(String photoTitle) {
		this.photoTitle = photoTitle;
	}

	public List<AlbumBO> getAlbumList() {
		return albumList;
	}
	public void setAlbumList(List<AlbumBO> albumList) {
		this.albumList = albumList;
	}
	public List<PhototblBO> getPhotoList() {
		return photoList;
	}
	public void setPhotoList(List<PhototblBO> photoList) {
		this.photoList = photoList;
	}
	public AlbumBO getAlbum() {
		return album;
	}
	public void setAlbum(AlbumBO album) {
		this.album = album;
	}
	public PhototblBO getPhotobo() {
		return photobo;
	}
	public void setPhotobo(PhototblBO photobo) {
		this.photobo = photobo;
	}
	public int getPhotoid() {
		return photoid;
	}
	public void setPhotoid(int photoid) {
		this.photoid = photoid;
	}
	public int getAlbumid() {
		return albumid;
	}
	public void setAlbumid(int albumid) {
		this.albumid = albumid;
	}
}

CustomPhotoResult.java

package com.tctalk.apps.album.web.actions;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;

public class CustomPhotoResult implements Result {

	private static final long serialVersionUID = 1L;

	public void execute(ActionInvocation invocation) throws Exception {
		PhotoAlbumAdminAction action = (PhotoAlbumAdminAction) invocation.getAction();
		HttpServletResponse response = ServletActionContext.getResponse();

		response.setContentType(action.getPhotobo().getImgcontenttype());
		response.setHeader("Content-Disposition", "inline; filename=\""	+ action.getPhotobo().getPhotoname() + "\"");
		response.setHeader("cache-control", "no-cache");
		response.getOutputStream().write(action.getPhotobo().getPhotodata());
		response.getOutputStream().flush();
		response.getOutputStream().close();
	}
}

Step 8: Add the delegate class

Delegate class works as a bridge between Struts2 presentation layer and the business layer developed with Hibernate.

PhotoAlbumAdminDelegate.java

package com.tctalk.apps.album.web.delegates;

import java.util.List;

import com.tctalk.apps.album.db.businessobjects.AlbumBO;
import com.tctalk.apps.album.db.businessobjects.PhototblBO;
import com.tctalk.apps.album.db.dao.PhotoAlbumAdminDao;
import com.tctalk.apps.album.db.dao.PhotoAlbumAdminDaoImpl;

public class PhotoAlbumAdminDelegate {
	PhotoAlbumAdminDao admindao = (PhotoAlbumAdminDao) new PhotoAlbumAdminDaoImpl();

	// Photo Album related functions

	public List<AlbumBO> getAllPhotoAlbums() {
		return admindao.getAllPhotoAlbums();
	}

	public boolean addAlbumToCollection(AlbumBO album) {
		return admindao.addAlbum(album);
	}

	public boolean delAlbumFromCollection(int albumId) {
		return admindao.delAlbum(albumId);
	}

	//Only Photo related functions

	public List<PhototblBO> getAllPhotos(int albumId) {
		return admindao.getAllPhotosFromAlbum(albumId);
	}

	public boolean addAPhoto(PhototblBO photo) {
		return admindao.addPhotoToAlbum(photo);
	}

	public boolean delPhoto(int photoid) {
		return admindao.delPhotoFromAlbum(photoid);
	}

	public List<PhototblBO> getPhoto(int photoid) {
		return admindao.getPhoto(photoid);
	}
}

Step 9: Final Integration

The entire project structure will be similar to the following:

image005

In the struts.xml file when we are redirecting from one action to another action we need to pass the album id . For example after a photo is uploaded to the database you need to redirect back to the all photo list under that album. So we need to send back the albumid also after photo is added. For doing this we used ${albumid} in struts.xml to pass the albumid from the POJO form.

Once the project is done generate the WAR file from eclipse. To do this do right click on project and select Export -> WAR file to create the WAR file and deploy in Tomcat.

If your deployment is successful and there is no error message in Tomcat console (ignore any warning like LOG4J etc.) then launch the browser and type the URL – http://localhost:8080/PersonalPhotoAlbumApp/admin.action

This will invoke the admin panel and the list of categories will be shown(first time no result will be shown so go ahead and add one album).

image007

Select ‘Click to View’ to go to Photos page and you can upload photos in that page or view the photos uploaded.

image009

That’s all for today. In the 2nd Part I’ll develop the front end panel which will show albums and the photos in that album using jQuery and Struts2 and Hibernate.

Download Source Files:

I’ve already given all the source codes in above steps. The eclipse project(with jars) and the WAR files are uploaded in GitHub repo.
 

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

11 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
subbareddy
subbareddy
10 years ago

Hi Im subbareddy ,
your code is so good and Im wait for second part can u post that.
Thanks.

Suvoraj
10 years ago
Reply to  subbareddy

Hi Subbareddy, Thanks for your comment. I’ll try to publish the part tutorial using Spring MVC very soon.

skr
skr
10 years ago

hi ,
your code is not working properly,

firstly index.jsp is not available.

secondally it get error,

java.lang.reflect.InvocationTargetException
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)

java.lang.NoSuchFieldError: INSTANCE
org.hibernate.type.BasicTypeRegistry.(BasicTypeRegistry.java:94)
org.hibernate.type.TypeResolver.(TypeResolver.java:59)
org.hibernate.cfg.Configuration.(Configuration.java:250)
org.hibernate.cfg.Configuration.(Configuration.java:302)

Suvoraj
10 years ago
Reply to  skr

Have you downloaded the Jars from the repo https://github.com/smweb239/techcubetalk_com ?
Also you don’t need index.jsp as here I only showcased the admin part. In next tutorial part 2 we’ll develop the front end.

skr
skr
9 years ago
Reply to  Suvoraj

Hi Suvoraj
As u mentioned index.jsp in web.xml as welcome file but u didn’t gave index,jsp code on ur site

ashish
ashish
6 years ago
Reply to  Suvoraj

hey i have an error in class photoAlbumAdminDaoImpl

ashish
ashish
6 years ago
Reply to  Suvoraj

and i have also error in PhotoAlbumAdminAction class

Justin Mathew
Justin Mathew
9 years ago

Hai, your post is very nice. i am developing a photo gallaery using struts. how can i download the source files of your example. .?

Matteo
Matteo
9 years ago

Wow, this is fantastic, when the 2 part?

this is the index.jsp for test the app:

Insert title here

<<to Albums<<

neha
neha
9 years ago

Hi,
m getting error of this code HTTP Status 404 – No result defined for action act.PhotoAlbumAdminAction and result error
and please give me the link of your 2nd part

dks
dks
8 years ago

plz send second part …..

Back to top button