Spring MVC - Ajax based form processing using JQuery and JSON with server side validation

Spring MVC provides support for processing the form as well as server side validation. It maps request parameters to form backing bean and validate the bean object if we have used @Valid annotation. When we submit the form, form get displayed with the error messages if validation is failed. Error messages are managed by Spring MVC and spring MVC binds them to the input fields.

But, If we want to submit the form using ajax request, form page will not refresh and spring MVC cannot send validation error messages to browsers. In this case, server side validation does not work as per my expectations. So here I devised my approach to use the spring MVC validation even in ajax based form submission. 

I am using JQuery to serialize the form data and capturing them in controller. In controller, form data is being mapped in User bean and User bean is validated based on field validation annotations. Now if validation is get failed and some errors are appeared there, I collect them in UserJsonResponse object. This is the object being sent to browser in JSON format. I am putting errors, status and bean object in this object to send the errors to browser. Spring MVC provides the facility @ResponseBody that converts the returning object in JSON output.

Now I am processing this output in webpage using the javascript where, all messages are being extracted and associated to corresponding  input fields.


package controller;

import java.beans.PropertyEditorSupport;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.ServletRequestDataBinder;
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.ResponseBody;

import bo.User;

public class RegistrationController {
    private MessageSource messages;
    public User exposeUser(){
        System.out.println("creating @ModelAttribute object");
        return new User();
    @RequestMapping(value = "/submituser",method=RequestMethod.POST )
    public  @ResponseBody UserJsonResponse submitUser(@Valid User user,BindingResult bindingResult){
        System.out.println("Submited User Data : \n"+user);
        UserJsonResponse userJsonResponse=new UserJsonResponse();
            Map<String ,String> errors=new HashMap<StringString>();
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
                String[] resolveMessageCodes = bindingResult.resolveMessageCodes(fieldError.getCode());
                String string = resolveMessageCodes[0];
                //System.out.println("resolveMessageCodes : "+string);
                String message = messages.getMessage(string+"."+fieldError.getField()new Object[]{fieldError.getRejectedValue()}null);
                //System.out.println("Meassage : "+message);
                errors.put(fieldError.getField(), message)    ;
        return userJsonResponse;
    public MessageSource getMessages() {
        return messages;
    public void setMessages(MessageSource messages) {
        this.messages = messages;
    class UserJsonResponse{
        private String status;
        private Map<String,String> errorsMap;
        private User user;
        public String getStatus() {
            return status;
        public void setStatus(String status) {
            this.status = status;
        public Map<String,String> getErrorsMap() {
            return errorsMap;
        public void setErrorsMap(Map<String,String> errorsMap) {
            this.errorsMap = errorsMap;
        public User getUser() {
            return user;
        public void setUser(User user) {
            this.user = user;
     protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
         binder.registerCustomEditor(long.classnew PropertyEditorSupport() {
         public void setAsText(String text) {
             long ch = Long.parseLong(text);

User Bean
package bo;

import javax.validation.Valid;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

public class User {

    private int id;
    @Size(min = 6, max = 10)
    String name;
    String email;

    long phone;
    private Address address;

    public User() {


    public User(String name, String email, long phone) {

        this.name = name;
        this.email = email;
        this.phone = phone;

    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 long getPhone() {
        return phone;

    public void setPhone(long phone) {
        this.phone = phone;

    public int getId() {
        return id;

    public void setId(int id) {
        this.id = id;

    public String toString() {
        return "User [id=" + id + ", name=" + name + ", email=" + email
                + ", phone=" + phone + "]";

    public Address getAddress() {
        return address;

    public void setAddress(Address address) {
        this.address = address;


package bo;

import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotEmpty;

public class Address {

    String addressLine1;
    String addressLine2;
    String city;
    long pincode;

    public String getAddressLine1() {
        return addressLine1;

    public void setAddressLine1(String addressLine1) {
        this.addressLine1 = addressLine1;

    public String getAddressLine2() {
        return addressLine2;

    public void setAddressLine2(String addressLine2) {
        this.addressLine2 = addressLine2;

    public String getCity() {
        return city;

    public void setCity(String city) {
        this.city = city;

    public long getPincode() {
        return pincode;

    public void setPincode(long pincode) {
        this.pincode = pincode;

    public String toString() {
        return "Address [addressLine1=" + addressLine1 + ", addressLine2="
                + addressLine2 + ", city=" + city + ", pincode=" + pincode
                + "]";


Size.user.name = Name must be of 4 to 10 character NotEmpty.user.name = Name is required NotEmpty.user.address.addressLine1= addressLine1 is required NotEmpty.user.address.city = city is required Email.user.email=Email {0} you entered is invalid NotEmpty.user.email = Email is required typeMismatch.user.phone = This is not a number! typeMismatch.user.address.pincode = This is not a number!

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript">
                    url: jQuery(this).attr("action"),
                    context: document.body,
                    type: 'post',
                }).done(function(res) {
                        for(var key in res.errorsMap){
                            var err="<span class=\"formFieldError\" id=\""+key+"Id\">"+res.errorsMap[key]+"</span>";
                        jQuery("#msg").html("Form submitted");
                    jQuery("#msg").html("<span class=\"formFieldError\">Server failed to process request</span>");
            return false;
<style type="text/css">
        <form id="userform" action="submituser" method="post"  >
            Name  :<input type="text" name="name"/><br/>
            Email  :<input type="text" name="email"/><br/>
            Phone  :<input type="text" name="phone"/><br/>
            AddressLine1  :<input type="text" name="address.addressLine1"/><br/>
            AddressLine2  :<input type="text" name="address.addressLine2"/><br/>
            City  :<input type="text" name="address.city"/><br/>
            Pincode  :<input type="text" name="address.pincode"/><br/>
            <input type="submit"/>
        <div id="msg"></div>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"

    <context:component-scan base-package="controller"></context:component-scan>
    <mvc:annotation-driven />
    <mvc:resources mapping="/**" location="/" />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name = "prefix" value="/WEB-INF/jsps/" />
        <property name = "suffix" value=".jsp" />
    <bean class="org.springframework.context.support.ResourceBundleMessageSource"
        <property name="basename" value="messages" />

Download Source Code 
Spring framework

WARNING: SQL Error: 1062, SQLState: 23000 SEVERE: Duplicate entry '*' for key '************'

May 14, 2013 4:35:23 PM org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 1062, SQLState: 23000
May 14, 2013 4:35:23 PM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: Duplicate entry '2' for key 'navigation_id'
May 14, 2013 4:35:23 PM org.hibernate.event.def.AbstractFlushingEventListener performExecutions
SEVERE: Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:183)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)

Following is the screenshot of actual scenario .

Here is the solution for above problem. Just I used @JoinColumn annotation 

Popular Posts