o7planning

Spring MVC Form Handling and Hibernate Tutorial with Examples

  1. Introduction
  2. Prepare database
  3. Create Project
  4. Configure Web.xml & Maven
  5. Configure Spring MVC
  6. Classes participated in the example
  7. Spring MVC Validator
  8. Spring Controller
  9. JSP files
  10. Running application

1. Introduction

This document is based on:
  • Spring MVC 4.2.5

  • Hibernate 5.x

  • Database: Oracle, MySQL, SQL Server

Preview example:

2. Prepare database

ORACLE
-- Create table
create table APPLICANTS
(
  ID       VARCHAR2(50) not null,
  GENDER   VARCHAR2(10) not null,
  NAME     VARCHAR2(50) not null,
  POSITION VARCHAR2(50) not null,
  SKILLS   VARCHAR2(255) not null,
  EMAIL    VARCHAR2(50) not null
) ;

alter table APPLICANTS
  add constraint APPLICANT_PK primary key (ID);
MYSQL & SQL SERVER
-- Create table
create table APPLICANTS
(
  ID       VARCHAR(50) not null,
  GENDER   VARCHAR(10) not null,
  NAME     VARCHAR(50) not null,
  POSITION VARCHAR(50) not null,
  SKILLS   VARCHAR(255) not null,
  EMAIL    VARCHAR(50) not null,
  primary key (ID)
) ;

3. Create Project

In Eclipse select:
  • File/New/Others..
  • Group Id: org.o7planning
  • Artifact Id: SpringMVCAnnotationForm
Project is created.
Fix Project:
Right click Project, select Properties.

Select Java Compiler 7 or 8:

4. Configure Web.xml & Maven

You need to edit web.xml to use Servlet 3.x
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 id="WebApp_ID" version="3.0">

 <display-name>Spring MVC Form</display-name>
 

</web-app>
Configure Maven:
pom.xml
<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>org.o7planning</groupId>
  <artifactId>SpringMVCAnnotationForm</artifactId>
  <packaging>war</packaging>
  <version>1.0.0</version>
  <name>SpringMVCAnnotationForm Maven Webapp</name>
  <url>http://maven.apache.org</url>


  <properties>
      <java-version>1.7</java-version>
  </properties>

  <repositories>
      <!-- Repository for ORACLE JDBC Driver -->
      <repository>
          <id>codelds</id>
          <url>https://code.lds.org/nexus/content/groups/main-repo</url>
      </repository>
  </repositories>

  <dependencies>

      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
      </dependency>

      <!-- Servlet API -->
      <!-- http://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
      </dependency>

      <!-- Jstl for jsp page -->
      <!-- http://mvnrepository.com/artifact/javax.servlet/jstl -->
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jstl</artifactId>
          <version>1.2</version>
      </dependency>


      <!-- JSP API -->
      <!-- http://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
      <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.2</version>
          <scope>provided</scope>
      </dependency>

      <!-- Spring dependencies -->
      <!-- http://mvnrepository.com/artifact/org.springframework/spring-core -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>4.2.5.RELEASE</version>
      </dependency>

      <!-- http://mvnrepository.com/artifact/org.springframework/spring-web -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>4.2.5.RELEASE</version>
      </dependency>

      <!-- http://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>4.2.5.RELEASE</version>
      </dependency>

      <!-- http://mvnrepository.com/artifact/org.springframework/spring-orm -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-orm</artifactId>
          <version>4.2.5.RELEASE</version>
      </dependency>

      <!-- Hibernate -->
      <!-- http://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-core</artifactId>
          <version>5.1.0.Final</version>
      </dependency>

      <!-- http://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-entitymanager</artifactId>
          <version>5.1.0.Final</version>
      </dependency>


      <!-- http://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-c3p0</artifactId>
          <version>5.1.0.Final</version>
      </dependency>


      <!-- MySQL JDBC driver -->
      <!-- http://mvnrepository.com/artifact/mysql/mysql-connector-java -->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.34</version>
      </dependency>

      <!-- Oracle JDBC driver -->
      <dependency>
          <groupId>com.oracle</groupId>
          <artifactId>ojdbc6</artifactId>
          <version>11.2.0.3</version>
      </dependency>

    <!-- SQLServer JDBC driver (JTDS) -->
    <!-- http://mvnrepository.com/artifact/net.sourceforge.jtds/jtds -->
    <dependency>
        <groupId>net.sourceforge.jtds</groupId>
        <artifactId>jtds</artifactId>
        <version>1.3.1</version>
    </dependency>

    <!-- Email validator,... -->
    <!-- http://mvnrepository.com/artifact/commons-validator/commons-validator -->
    <dependency>
        <groupId>commons-validator</groupId>
        <artifactId>commons-validator</artifactId>
        <version>1.5.0</version>
    </dependency>

  </dependencies>


  <build>
      <finalName>SpringMVCAnnotationForm</finalName>
      <plugins>
    
          <!-- Config: Maven Tomcat Plugin -->
          <!-- http://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat7-maven-plugin -->
          <plugin>
              <groupId>org.apache.tomcat.maven</groupId>
              <artifactId>tomcat7-maven-plugin</artifactId>
              <version>2.2</version>
              <!-- Config: contextPath and Port (Default - /SpringMVCAnnotationForm : 8080) -->
              <!--
              <configuration>
                  <path>/</path>
                  <port>8899</port>
              </configuration>
              -->   
          </plugin>
      </plugins>
  </build>   
 

</project>

5. Configure Spring MVC

SpringWebAppInitializer used to initialize the Spring configuration, it is starting point of Spring MVC. It replaces the Spring MVC configuration in web.xml.
** web.xml **
<!-- With SpringWebAppInitializer, you do not need to configure in web.xml -->

  <servlet>
      <servlet-name>spring-mvc</servlet-name>
      <servlet-class>
          org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>   
 
  <servlet-mapping>
      <servlet-name>spring-mvc</servlet-name>
      <url-pattern>/</url-pattern>
  </servlet-mapping>
SpringWebAppInitializer.java
package org.o7planning.springmvcforms.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class SpringWebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(ApplicationContextConfig.class);

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("SpringDispatcher",
                new DispatcherServlet(appContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

}
ApplicationContextConfig class used to configure Spring MVC Context, including:
  • View Resolver
  • Datasouce
  • Hiberante (Hibernate Transaction Manager, Hibernate Session,..)
  • DAO
  • Bean
  • ....
ApplicationContextConfig.java
package org.o7planning.springmvcforms.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.o7planning.springmvcforms.dao.ApplicantDAO;
import org.o7planning.springmvcforms.dao.impl.ApplicantDAOImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@ComponentScan("org.o7planning.springmvcforms.*")
@EnableTransactionManagement
// Load to Environment.
@PropertySource("classpath:ds-hibernate-cfg.properties")
public class ApplicationContextConfig {

 // The Environment class serves as the property holder
 // and stores all the properties loaded by the @PropertySource
 @Autowired
 private Environment env;



 @Bean
 public ResourceBundleMessageSource messageSource() {
     ResourceBundleMessageSource rb = new ResourceBundleMessageSource();
     // Load property in message/validator.properties
     rb.setBasenames(new String[] { "messages/validator"});
     return rb;
 }


 @Bean(name = "viewResolver")
 public InternalResourceViewResolver getViewResolver() {
     InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
     viewResolver.setPrefix("/WEB-INF/pages/");
     viewResolver.setSuffix(".jsp");
     return viewResolver;
 }

 @Bean(name = "dataSource")
 public DataSource getDataSource() {
     DriverManagerDataSource dataSource = new DriverManagerDataSource();

     dataSource.setDriverClassName(env.getProperty("ds.database-driver"));
     dataSource.setUrl(env.getProperty("ds.url"));
     dataSource.setUsername(env.getProperty("ds.username"));
     dataSource.setPassword(env.getProperty("ds.password"));

     return dataSource;
 }

 @Autowired
 @Bean(name = "sessionFactory")
 public SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
     Properties properties = new Properties();
   
     // See: ds-hibernate-cfg.properties
     properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
     properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
     properties.put("current_session_context_class", env.getProperty("current_session_context_class"));
     

     LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
     factoryBean.setPackagesToScan(new String[] { "org.o7planning.springmvcforms.entity" });
     factoryBean.setDataSource(dataSource);
     factoryBean.setHibernateProperties(properties);
     factoryBean.afterPropertiesSet();
     //
     SessionFactory sf = factoryBean.getObject();
     return sf;
 }

 @Autowired
 @Bean(name = "transactionManager")
 public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
     HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);

     return transactionManager;
 }

 @Bean(name = "applicantDAO")
 public ApplicantDAO getApplicantDAO() {
     return new ApplicantDAOImpl();
 }

}
ApplicationContextConfig will read the Datasource configuration information, Hibernate properties in ds-hibernate-cfg.properties file.
Configurations for Oracle, MySQL or SQL Server:
ds-hibernate-cfg.properties (For ORACLE)
# DataSource

ds.database-driver=oracle.jdbc.driver.OracleDriver
ds.url=jdbc:oracle:thin:@localhost:1521:db12c
ds.username=shoppingcart
ds.password=12345


# Hibernate Config

hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
hibernate.show_sql=true
current_session_context_class=thread
ds-hibernate-cfg.properties (For MYSQL)
# DataSource

ds.database-driver=com.mysql.jdbc.Driver
ds.url=jdbc:mysql://localhost:3306/mydatabase
ds.username=root
ds.password=12345


# Hibernate Config

hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
current_session_context_class=thread
ds-hibernate-cfg.properties (For SQL SERVER)
# DataSource

ds.database-driver=net.sourceforge.jtds.jdbc.Driver
ds.url=jdbc:jtds:sqlserver://localhost:1433/simplehr;instance=SQLEXPRESS
ds.username=shoppingcart
ds.password=12345


# Hibernate Config

hibernate.dialect=org.hibernate.dialect.SQLServerDialect
hibernate.show_sql=true
current_session_context_class=thread
Config for static resource (html, image, css,..)
WebMvcConfig.java
package org.o7planning.springmvcforms.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;


@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    // Static Resource Config
    // equivalents for <mvc:resources/> tags
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
        registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
        registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
    }

    // equivalent for <mvc:default-servlet-handler/> tag
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
 
}

6. Classes participated in the example

Applicant is an entity class, simulation 'APPLICANTS' table in the database
Applicant.java
package org.o7planning.springmvcforms.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "Applicants")
public class Applicant implements Serializable {

   private static final long serialVersionUID = -7893237204476214050L;
   private String id;
   private String name;
   private String email;

   private String position;
   private String gender;
   private String skills;

   @Id
   @Column(name = "ID", length = 50, nullable = false)
   public String getId() {
       return id;
   }

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

   @Column(name = "Name", length = 50, nullable = false)
   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   @Column(name = "Position", length = 50, nullable = false)
   public String getPosition() {
       return position;
   }

   public void setPosition(String position) {
       this.position = position;
   }

   @Column(name = "Gender", length = 10, nullable = false)
   public String getGender() {
       return gender;
   }

   public void setGender(String gender) {
       this.gender = gender;
   }

   @Column(name = "Email", length = 50, nullable = false)
   public String getEmail() {
       return email;
   }

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

   @Column(name = "Skills", length = 255, nullable = false)
   public String getSkills() {
       return skills;
   }

   public void setSkills(String skills) {
       this.skills = skills;
   }
}
ApplicantInfo.java
package org.o7planning.springmvcforms.model;

public class ApplicantInfo {

    private String id;
    private String name;
    private String email;

    private String position;
    private String gender;
    private String skillsString;
    private String[] skills;

    public ApplicantInfo() {

    }

    // Do not change this constructor,
    // it is used in the Hibernate Query
    public ApplicantInfo(String id, String name, String email, String gender, String position, String skillsString) {
        this.id = id;
        this.name = name;
        this.email = email;

        this.position = position;
        this.gender = gender;
        this.skillsString = skillsString;
        this.skills = toArray(skillsString);
    }

    private String[] toArray(String skillStrings) {
        if (skillStrings == null) {
            return new String[0];
        }
        String[] ret = skillStrings.split(",");
        return ret;
    }

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

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

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String[] getSkills() {
        return skills;
    }

    public void setSkills(String[] skills) {
        this.skills = skills;
        this.skillsString = this.joinString(skills);
    }

    private String joinString(String[] skills) {
        if (skills == null) {
            return "";
        }
        return String.join(",", skills);
    }

    public String getSkillsString() {
        return this.skillsString;
    }

}
ApplicantDAO is a Spring Bean, to handle the insert, update, query data in the APPLICANTS table.
ApplicantDAO.java
package org.o7planning.springmvcforms.dao;

import java.util.List;

import org.o7planning.springmvcforms.entity.Applicant;
import org.o7planning.springmvcforms.model.ApplicantInfo;

public interface ApplicantDAO {

    public Applicant findApplicant(String id);

    public List<ApplicantInfo> listApplicantInfos();

    public void saveApplicant(ApplicantInfo applicantInfo);

    public ApplicantInfo findApplicantInfo(String id);

    public void deleteApplicant(String id);
   
}
ApplicantDAOImpl.java
package org.o7planning.springmvcforms.dao.impl;

import java.util.List;
import java.util.UUID;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.o7planning.springmvcforms.dao.ApplicantDAO;
import org.o7planning.springmvcforms.entity.Applicant;
import org.o7planning.springmvcforms.model.ApplicantInfo;
import org.springframework.beans.factory.annotation.Autowired;

public class ApplicantDAOImpl implements ApplicantDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Applicant findApplicant(String id) {
        Session session = sessionFactory.getCurrentSession();
        Criteria crit = session.createCriteria(Applicant.class);
        crit.add(Restrictions.eq("id", id));
        return (Applicant) crit.uniqueResult();
    }

    @Override
    public ApplicantInfo findApplicantInfo(String id) {
        Applicant applicant = this.findApplicant(id);
        if (applicant == null) {
            return null;
        }
        return new ApplicantInfo(applicant.getId(), applicant.getName(), //
                applicant.getEmail(), applicant.getGender(), //
                applicant.getPosition(), applicant.getSkills());
    }

    @Override
    public List<ApplicantInfo> listApplicantInfos() {
        String sql = "Select new " + ApplicantInfo.class.getName()//
                + "(a.id, a.name, a.email, a.gender, a.position, a.skills) "//
                + " from " + Applicant.class.getName() + " a ";
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(sql);
        return query.list();
    }

    public void saveApplicant(ApplicantInfo applicantInfo) {
        String id = applicantInfo.getId();
        Applicant applicant = null;
        if (id != null) {
            applicant = this.findApplicant(id);
        }
        boolean isNew = false;
        if (applicant == null) {
            isNew = true;
            applicant = new Applicant();
            applicant.setId(UUID.randomUUID().toString());
        }
        applicant.setEmail(applicantInfo.getEmail());
        applicant.setGender(applicantInfo.getGender());
        applicant.setName(applicantInfo.getName());
        applicant.setPosition(applicantInfo.getPosition());
        String skillsString = applicantInfo.getSkillsString();

        applicant.setSkills(skillsString);
        //

        if (isNew) {
            Session session = this.sessionFactory.getCurrentSession();
            session.persist(applicant);
        }
    }

    @Override
    public void deleteApplicant(String id) {
        Applicant applicant = this.findApplicant(id);
        if (applicant != null) {
            this.sessionFactory.getCurrentSession().delete(applicant);
        }
    }

}

7. Spring MVC Validator

ApplicantValidator is a class that checks the user data entered into a form. In case the user entered wrong, there will be notice as shown below:
ApplicantValidator.java
package org.o7planning.springmvcforms.validator;

import org.apache.commons.validator.routines.EmailValidator;
import org.o7planning.springmvcforms.model.ApplicantInfo;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

@Component
public class ApplicantValidator implements Validator {
   
    // common-validator library.
    private EmailValidator emailValidator =   EmailValidator.getInstance();

    // The classes is supported to Validate
    @Override
    public boolean supports(Class<?> clazz) {
        return clazz == ApplicantInfo.class;
    }

    @Override
    public void validate(Object target, Errors errors) {
        ApplicantInfo applicantInfo = (ApplicantInfo) target;

        // Check the fields of ApplicantInfo.
        // (See more in property file: messages/validator.property)
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "NotEmpty.applicantForm.name");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "NotEmpty.applicantForm.email");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "position", "NotEmpty.applicantForm.position");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "gender", "NotEmpty.applicantForm.gender");
       
        if(!emailValidator.isValid(applicantInfo.getEmail())) {
            // Error in email field.
            errors.rejectValue("email", "Pattern.applicantForm.email");
        }
       
        if(applicantInfo.getSkills()== null || applicantInfo.getSkills().length==0 ) {
            errors.rejectValue("skills", "Select.applicantForm.skills");
        }
     
    }

}
The error messages are configured in the messages/validator.properties file:
messages/validator.properties
NotEmpty.applicantForm.name=Name is required
NotEmpty.applicantForm.email=Email is required
NotEmpty.applicantForm.position=Position is required
NotEmpty.applicantForm.gender=Gender is required

Pattern.applicantForm.email=Email is not valid

Select.applicantForm.skills=Must select at least one skill
The content of validator.properties loaded by ApplicationContextConfig:
** ApplicationContextConfig.java **
// Load property in message/validator.properties

@Bean
public ResourceBundleMessageSource messageSource() {
   ResourceBundleMessageSource rb = new ResourceBundleMessageSource();
   // Load property in message/validator.properties
   rb.setBasenames(new String[] { "messages/validator"});
   return rb;
}

8. Spring Controller

MyController.java
package org.o7planning.springmvcforms.controller;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.o7planning.springmvcforms.dao.ApplicantDAO;
import org.o7planning.springmvcforms.model.ApplicantInfo;
import org.o7planning.springmvcforms.validator.ApplicantValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
// Enable Hibernate Transaction.
@Transactional
// Need To use RedirectAttributes
@EnableWebMvc
public class MyController {

   @Autowired
   private ApplicantDAO applicantDAO;

   @Autowired
   private ApplicantValidator applicantValidator;

   @RequestMapping("/")
   public String homePage(Model model) {

       return applicantList(model);
   }

   @RequestMapping("/applicantList")
   public String applicantList(Model model) {
       List<ApplicantInfo> list = applicantDAO.listApplicantInfos();
       model.addAttribute("applicantInfos", list);
       return "applicantList";
   }

   private Map<String, String> dataForPositions() {
       Map<String, String> positionMap = new LinkedHashMap<String, String>();
       positionMap.put("Developer", "Developer");
       positionMap.put("Leader", "Leader");
       positionMap.put("Tester", "Tester");
       return positionMap;
   }

   private List<String> dataForSkills() {
       List<String> list = new ArrayList<String>();
       list.add("Java");
       list.add("C/C++");
       list.add("C#");
       return list;
   }

   private String formApplicant(Model model, ApplicantInfo applicantInfo) {
       model.addAttribute("applicantForm", applicantInfo);

       Map<String, String> positionMap = this.dataForPositions();

       model.addAttribute("positionMap", positionMap);

       List<String> list = dataForSkills();
       model.addAttribute("skills", list);

       if (applicantInfo.getId() == null) {
           model.addAttribute("formTitle", "Create Applicant");
       } else {
           model.addAttribute("formTitle", "Edit Applicant");
       }

       return "formApplicant";
   }

   @RequestMapping("/createApplicant")
   public String createApplicant(Model model) {

       ApplicantInfo applicantInfo = new ApplicantInfo();

       return this.formApplicant(model, applicantInfo);
   }

   @RequestMapping("/editApplicant")
   public String editApplicant(Model model, @RequestParam("id") String id) {
       ApplicantInfo applicantInfo = null;
       if (id != null) {
           applicantInfo = this.applicantDAO.findApplicantInfo(id);
       }
       if (applicantInfo == null) {
           return "redirect:/applicantList";
       }

       return this.formApplicant(model, applicantInfo);
   }

   @RequestMapping("/deleteApplicant")
   public String deleteApplicant(Model model, @RequestParam("id") String id) {
       if (id != null) {
           this.applicantDAO.deleteApplicant(id);
       }
       return "redirect:/applicantList";
   }

   // Set a form validator
   @InitBinder
   protected void initBinder(WebDataBinder dataBinder) {
       // Form target
       Object target = dataBinder.getTarget();
       if (target == null) {
           return;
       }
       System.out.println("Target=" + target);

       if (target.getClass() == ApplicantInfo.class) {
           dataBinder.setValidator(applicantValidator);
       }
   }

   // Save or update Applicant
   // 1. @ModelAttribute bind form value
   // 2. @Validated form validator
   // 3. RedirectAttributes for flash value
   @RequestMapping(value = "/saveApplicant", method = RequestMethod.POST)
   public String saveApplicant(Model model, //
           @ModelAttribute("applicantForm") @Validated ApplicantInfo applicantInfo, //
           BindingResult result, //
           final RedirectAttributes redirectAttributes) {

   
       if (result.hasErrors()) {
           return this.formApplicant(model, applicantInfo);
       }

       this.applicantDAO.saveApplicant(applicantInfo);

       // Important!!: Need @EnableWebMvc
       // Add message to flash scope
       redirectAttributes.addFlashAttribute("message", "Save Applicant Successful");

       return "redirect:/applicantList";

   }

}

9. JSP files

WEB-INF/pages/applicantList.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Applicant List</title>
<style>
   table  {
       margin-top: 10px;
       border: solid black 1px;
   }
   table  td {
        padding: 5px;
   }
   .message  {
        font-size:90%;
        color:blue;
        font-style:italic;
        margin-top:30px;
   }
</style>
</head>
<body>



<a href="${pageContext.request.contextPath}/createApplicant">Create Applicant</a>

<br/>


<table border="1">
 <tr>
   <th>Name</th>
   <th>Position</th>
   <th>Gender</th>
   <th>Email</th>
   <th>Skills</th>
   <th>Edit</th>
   <th>Delete</th>
 </tr>
 <c:forEach items="${applicantInfos}" var="info">

 <tr>
   <td> ${info.name}  </td>
   <td> ${info.position}  </td>
   <td> ${info.gender} </td>
   <td> ${info.email} </td>
   <td> ${info.skillsString} </td>
   <td> <a href="deleteApplicant?id=${info.id}">Delete</a> </td>
   <td> <a href="editApplicant?id=${info.id}">Edit</a> </td>
 </tr>    

 </c:forEach>
</table>
<c:if test="${not empty message}">
 
   <div class="message">${message}</div>
</c:if>



</body>
</html>
WEB-INF/pages/formApplicant.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Create Applicant</title>
<style>
.error-message {
   color: red;
   font-size:90%;
   font-style: italic;
}
</style>
</head>
<body>

   <h3>${formTitle}</h3>

   <form:form action="saveApplicant" method="POST"
       modelAttribute="applicantForm">

       <form:hidden path="id" />

       <table>
           <tr>
               <td>Name</td>
               <td><form:input path="name" /></td>
               <td><form:errors path="name"
                       class="error-message" /></td>      
           </tr>
           <tr>
               <td>Gender</td>
               <td><form:select path="gender">
                       <form:option value="" label="- Gender -" />
                       <form:option value="M" label="Male" />
                       <form:option value="F" label="Female" />
                   </form:select></td>
               <td><form:errors path="gender" class="error-message" /></td>
           </tr>
           <tr>
               <td>Email</td>
               <td><form:input path="email" /></td>
               <td><form:errors path="email" class="error-message" /></td>
           </tr>
           <tr>
               <td>Position</td>
               <td><form:select path="position">
                       <form:options items="${positionMap}" />
                   </form:select></td>
               <td><form:errors path="position" class="error-message" /></td>
           </tr>

           <tr>
               <td>Skills</td>
               <td><c:forEach items="${skills}" var="skill">
                       <form:checkbox path="skills" value="${skill}" label="${skill}" />
                   </c:forEach></td>
               <td><form:errors path="skills" class="error-message" /></td>
           </tr>

           <tr>
               <td>&nbsp;</td>
               <td><input type="submit" value="Submit" />
                  <a href="${pageContext.request.contextPath}/applicantList">Cancel</a>
               </td>
               <td>&nbsp;</td>
           </tr>
       </table>
   </form:form>

</body>
</html>

10. Running application

Right click the project, select:
  • Run As/Run Applications:
Enter:
  • Name: Spring MVC Form
  • Base directory: ${workspace_loc:/SpringMVCAnnotationForm}
  • Goals: tomcat7:run