Friday, July 6, 2012

Creating A Simple Web Application Using Struts 2 and Spring 3.0


In this article we’ll create a simple User Registration form using Struts 2 and configure it with Spring 3.0

Technologies used:
Java 6
Struts 2
Spring 3.0
Maven 3.0

This example application is named ‘CeylonCuisine’. I’m using Maven as the build tool, the pom.xml file including the required libraries will be shown later in this article.

We are applying the MVC pattern:
Model – Java domain object : User
View – JSP file : register.jsp
Controller – Struts 2 Action class : RegisterAction

User.java
package com.ceyloncuisine.domain;

import java.io.Serializable;

public class User implements Serializable {

 private static final long serialVersionUID = 1L;
 private long id;
 private String fname;
 private String lname;
 private char sex;
 private String email;

 public long getId() {
  return id;
 }

 public String getFname() {
  return fname;
 }

 public String getLname() {
  return lname;
 }

 public char getSex() {
  return sex;
 }

 public String getEmail() {
  return email;
 }

 public void setId(long id) {
  this.id = id;
 }

 public void setFname(String fname) {
  this.fname = fname;
 }

 public void setLname(String lname) {
  this.lname = lname;
 }

 public void setSex(char sex) {
  this.sex = sex;
 }

 public void setEmail(String email) {
  this.email = email;
 }

}


Add the above file to src\main\java folder.

We are going to store the User’s first name, last name, sex and email address in database. The code to insert the user details to db is not included in this tutorial.

Now we will create the register.jsp file to present the user with a form to insert required details. With Struts 2 tags , creation of forms is very easy.

Place register.jsp file in src\main\webapp folder.

register.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>

<%@ taglib prefix="s" uri="/struts-tags"%>



Ceylon Cuisine - Register


 

  
  
  
  

  

 



<%@ taglib prefix="s" uri="/struts-tags"%>
We need to include this line in our jsp file in order to use Struts 2 tag libraries.
Now we can begin with ‘<s:’ to use Struts 2 tags as in ‘<s:form action="register">’.

<s:form action="register">
Struts 2 form tag will create a simple form for you. By default the form method will be ‘post’. When the user fills in the form and press the submit button, the ‘register’ action will be called. ‘register’ action is the java controller class which will process the form data.
We have to relate this action to the java controller class by specifying it in the struts.xml configuration file.

<s:textfield name="userBean.fname" label="First Name" />
This will create a text field inside your form. When the user provides input and clicks on the ‘submit’ button, the form data will be sent to the action class.
‘userBean.fname’ is interpreted inside the action class as ‘setUserBean() and setFname()’. Struts 2 will look for a method called setUserBean() and upon the returned object it will then call setFname() with the user provided String value.
Therefore we need to define a variable userBean in the ‘RegisterAction’ class.

RegisterAction.java
package com.ceyloncuisine.action;

import com.ceyloncuisine.domain.User;
import com.ceyloncuisine.mgr.UserMgr;
import com.opensymphony.xwork2.ActionSupport;

public class RegisterAction extends ActionSupport {

 private static final long serialVersionUID = 1L;

 User userBean;

 UserMgr userMgr;

 @Override
 public String execute() throws Exception {
  // Insert user to db
  userMgr.addUser(userBean);
  return SUCCESS;
 }

 public User getUserBean() {
  return userBean;
 }

 public void setUserBean(User userBean) {
  this.userBean = userBean;
 }

 public UserMgr getUserMgr() {
  return userMgr;
 }

 public void setUserMgr(UserMgr userMgr) {
  this.userMgr = userMgr;
 }

}
Place the above file in src\main\java folder.

Struts 2 action classes must extend ActionSupport class which comes with the xwork2 dependent libraries.
‘userBean’ is the model class to which we’ll be storing the information received from the register.jsp as mentioned earlier. Struts 2 framework will create an instance of ‘User’ and assign it to ‘userBean’ using the setter provided in action class.

‘userMgr’ is a service class that will be invoked to insert the User data to database. (The DAO layer operations will be internally called by this)
To inject the dependency for ‘userMgr’ we need Spring configuration. For the moment ignore this part, we’ll be discussing it later.

The execute() method is inherited from ActionSupport class and overridden to invoke service methods after processing form.

Now we’ll configure the struts.xml file to relate this ‘RegisterAction’ class to Register form.

struts.xml


 

  
   /thankyou.jsp
   


 



Save this file in src\main\resources folder.

Using the <action> tag we specify the action name as ‘register’ and relate it to our controller class.
Set the Action’s method as ‘execute’ to indicate this action will look for the execute() method in RegisterAction class and invoke it.

Upon successful invocation of the execute() method, the controller will then load ‘thankyou.jsp’ which will display a thank you note to the user for registering.
Create thankyou.jsp in src\main\webapp folder.

thankyou.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>




Ceylon Cuisine - Thank You


Thank  you for registering with us!





Now most of the application is complete, except for the integration with the services layer to actually insert the user object to database. Also we need to update web.xml file.
This article will not give you information about DAO layer or hibernate configuration, So I will outline only the interfaces here.


UserDao.java
package com.ceyloncuisine.dao;

import com.ceyloncuisine.domain.User;

public interface UserDao {

 public void addUser(User user);

}


UserMgr.java
package com.ceyloncuisine.mgr;

import com.ceyloncuisine.domain.User;

public interface UserMgr {
 
 public void addUser(User user);

}


As I have mentioned earlier, in RegisterAction class, in the execute() method, we call the service bean to persist the user input data.
userMgr.addUser(userBean);
We need to inject ‘userMgr’ bean to our action class using Spring. See below Spring configuration file.

SpringBeans.xml


 
  
 

 
 
 



Save SpringBeans.xml in src\main\resources folder.

Now we need to add few entries to web.xml file. (src\main\webapp\WEB-INF)

web.xml

 CeylonCuisine

 
  struts2
  org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
 

 
  struts2
  /*
 

 
  org.springframework.web.context.ContextLoaderListener
 
 
  contextConfigLocation
  classpath:SpringBeans.xml
 





We need to add a filter class mapping to enable Struts 2 to work with the web application. By specifying ‘/*’ in filter mapping, it indicates that this filter will be applied to all URLs in this web application.

A listener class is required to activate Spring framework on our application. By default the Spring framework looks for a file named ‘applicationContext.xml’ in src\main\webapp\WEB-INF folder to load configuration.
In this example, I have my Spring configuration saved in ‘SpringBeans.xml’ in src\main\resources folder. So have given the path to this using <context-param> tags.

Run ‘mvn clean install’ to compile the project and create the WAR file. Deploy this in your web server. (I use Tomcat)
Run your application by typing the below URL in your browser.

http://localhost:8080/CeylonCuisine/register.jsp


The pom.xml file with the required libraries is shown below.


 4.0.0
 CeylonCuisine
 CeylonCuisine
 0.0.1-SNAPSHOT
 war
 CeylonCuisine

 
  
   Java.Net
   http://download.java.net/maven/2/
  

  
   com.springsource.repository.bundles.release
   SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases
   http://repository.springsource.com/maven/bundles/release
  
  
   com.springsource.repository.bundles.external 
   SpringSource Enterprise Bundle Repository - External Bundle Releases
   http://repository.springsource.com/maven/bundles/external
  

 
 
  
  
   org.springframework
   org.springframework.core
   3.1.1.RELEASE
  

  
   org.springframework
   org.springframework.beans
   3.1.1.RELEASE
  

  
  
   asm
   asm
   3.3.1
  

  
  
   org.apache.struts
   struts2-spring-plugin
   2.3.4
  

  
  
   org.apache.struts
   struts2-core
   2.3.4
  
 

Tuesday, July 3, 2012

Writing JUnit4 tests - Spring 3.0 Hibernate 3.0 configuration


I have modified the earlier example to show you how we can write the JUnit4 test case for the same Dao class configured on Spring 3.0 environment.

Technologies used:
Java 6
JUnit4
Spring 3.0
Hibernate 3.0
Maven 3.0

UserDao has one method to insert a User entity to the USERS table – addUser().

UserDao.java
package com.ceyloncuisine.dao;

import com.ceyloncuisine.domain.User;

public interface UserDao {

      public void addUser(User user);

}

To keep this simple, only the interface method is shown.
When writing the test case, it’s always good to have a base test class which we can store all the common methods and utility methods. 
  
BaseTest.java
package com.ceyloncuisine.base;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.Ignore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.transaction.TransactionConfiguration;

@Ignore
@ContextConfiguration(locations = "/test-spring-config.xml")
@TransactionConfiguration(transactionManager = "txManager", 
                                     defaultRollback = true) 
public class BaseTest extends
             AbstractTransactionalJUnit4SpringContextTests { 

      @Autowired
      SessionFactory sessionFactory;

      protected void flush() {
            this.sessionFactory.getCurrentSession().flush();
      }

      protected Session getCurrentSession() {
            return sessionFactory.getCurrentSession();
      }

}


We need to extend AbstractTransactionalJUnit4SpringContextTests. Use of annotations will make things easier for you.

@Ignore – I don’t need this class to run as a test case, this is only used as a base class. So @Ignore annotation will make sure this will be ignored at test run.

@ContextConfiguration – This is how to load the application context for tests.  We need to have a separate Spring configuration that will be used for tests.  You have to place this configuration file in src\test\resources folder. I will include the test configuration file later in this article.

@TransactionConfiguration – We need to provide transactional support for testing. This is where to specify the transaction manager we’ll be using.

By default the transaction manager name is called “transactionManager”, if you have some other name for your transaction manager, as in this example, you have to specify the name. “txManager” is defined in the ‘test-spring-config.xml’ file.
sessionFactory’ is configured in the test-spring-config.xml file.

Now let’s see the test class.

UserDaoTest.java
package com.ceyloncuisine.dao;

import junit.framework.Assert;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.ceyloncuisine.base.BaseTest;
import com.ceyloncuisine.domain.User;

public class UserDaoTest extends BaseTest {

      @Autowired
      UserDao userDao;

      @Test
      public void testAddUser() {

        long count = -1;
        String testFname = "bob";

  // HQL query to get the count.
        String query = "select count(u.fname) " +
                        "from User u where u.fname = ?";

        // Get the count before the Dao method call.
        count = (Long) getCurrentSession().createQuery(query)
                        .setString(0, testFname).uniqueResult();
        // There should be no existing record with the name specified.
        Assert.assertEquals("A user already exists in the DB", 
                                                      0, count);

        // Call the Dao method to add new user.
        User user = new User();
        user.setFname(testFname);
        userDao.addUser(user);

        // flush the session so we can get the updated record.
        flush();

        // Get the count after the Dao method call.
        count = (Long) getCurrentSession().createQuery(query)
                        .setString(0, testFname).uniqueResult();

        // A record should be fetched matching the specified name.
        Assert.assertEquals("User was not found in the DB", 
                                                   1, count);
      }

}


The method uniqueResult()is used as the query returns a single object. If the query is returns a list of objects we should use list() method instead.

The @TransactionConfiguration setting in the base test class has an attribute ‘defaultRollback’. The value of this is ‘true’ by default, meaning the transaction will be rolled back at the end. If you set this to ‘false’, test data inserted to the database will not be removed.
TransactionConfiguration(transactionManager = "txManager", defaultRollback=false)
Therefore the inserted record will be removed from the database when the test case completes and the database remains clean so you don’t have to bother about cleaning test data.


This is the Spring configuration file used for tests.

test-spring-config.xml


  
       
              
       
  

  
       
              
       
       
              
                     com/ceyloncuisine/hibernate/User.hbm.xml
              
       
       
              
                     
org.hibernate.hql.classic.ClassicQueryTranslatorFactory
                     
                     
org.hibernate.dialect.MySQLDialect
              
       
  

  
       
       
       
       
  


  
       
              
       
  



test-spring-config.xml defines the sessionFactory  and the dataSource beans required to communicate with the MySQL database.  sessionFactory defines the hibernate mapping file for the User entity. (User.hbm.xml)
A HibernateTransactionManager is used to handle transactions and it is defined as “txManager”.

Below is the pom.xml file used to configure dependencies with Maven.

  4.0.0
  CeylonCuisine
  CeylonCuisine
  0.0.1-SNAPSHOT
  war
  CeylonCuisine

  
    
      Java.Net
      http://download.java.net/maven/2/
    

    
      com.springsource.repository.bundles.release
      
    SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases
      
      http://repository.springsource.com/maven/bundles/release
    

    
      com.springsource.repository.bundles.external 
      
    SpringSource Enterprise Bundle Repository - External Bundle Releases
      
      http://repository.springsource.com/maven/bundles/external
    
   

  

              
              
                     org.springframework
                     org.springframework.core
                     3.1.1.RELEASE
              

              
                     org.springframework
                     org.springframework.beans
                     3.1.1.RELEASE
              

              
                     org.springframework
                     org.springframework.transaction
                     3.1.1.RELEASE
              

              
                     org.springframework
                     org.springframework.test
                     3.1.1.RELEASE
              

              
                     org.springframework
                     spring-hibernate3
                     2.0.8
              

              
              
                     junit
                     junit
                     4.10
              

              
              
                     mysql
                     mysql-connector-java
                     5.1.9
              

              
              
                     org.hibernate
                     hibernate
                     3.2.7.ga
              

              
              
                     dom4j
                     dom4j
                     1.6.1
              

              
                     commons-collections
                     commons-collections
                     3.2.1
              

              
                     cglib
                     cglib
                     2.2
              

              
              
                     antlr
                     antlr
                     2.7.7
              

              
              
                     asm
                     asm
                     3.3.1
              

  



So, that’s it. Hope this post will help you to configure your JUnit4 test cases.