Main Tutorials

Spring 4 MVC Ajax Hello World Example

In this tutorial, we will show you how to create a Spring MVC web project and submit a form via Ajax.

Technologies used :

  1. Spring 4.2.2.RELEASE
  2. Jackson 2.6.3
  3. Logback 1.1.3
  4. jQuery 1.10.2
  5. Maven 3
  6. JDK 1.8
  7. Tomcat 8 or Jetty 9
  8. Eclipse 4.5
  9. Boostrap 3

P.S If the Jackson library is found in the project classpath, Spring will use Jackson to handle the json data to / from object conversion automatically.

Note
Try this – Spring Boot Ajax example

1. Quick Reference

1.1 In HTML, use jQuery $.ajax() to send a form request.


	jQuery(document).ready(function($) {
		$("#search-form").submit(function(event) {

			// Prevent the form from submitting via the browser.
			event.preventDefault();
			searchViaAjax();

		});
	});
	
	function searchAjax() {
		var data = {}
		data["query"] = $("#query").val();
		
		$.ajax({
			type : "POST",
			contentType : "application/json",
			url : "${home}search/api/getSearchResult",
			data : JSON.stringify(data),
			dataType : 'json',
			timeout : 100000,
			success : function(data) {
				console.log("SUCCESS: ", data);
				display(data);
			},
			error : function(e) {
				console.log("ERROR: ", e);
				display(e);
			},
			done : function(e) {
				console.log("DONE");
			}
		});
	}

1.2 Spring controller to handle the Ajax request.


@Controller
public class AjaxController {

	@ResponseBody
	@RequestMapping(value = "/search/api/getSearchResult")
	public AjaxResponseBody getSearchResultViaAjax(@RequestBody SearchCriteria search) {

		AjaxResponseBody result = new AjaxResponseBody();
		//logic
		return result;

	}
	
}

2. Project Directory

Review the project directory, a standard Maven project directory structure.

spring-mvc-ajax-example-1

3. Project Dependencies

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>com.mkyong</groupId>
	<artifactId>spring4-mvc-maven-ajax-example</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>spring4 mvc maven ajax example</name>

	<properties>
		<jdk.version>1.8</jdk.version>
		<spring.version>4.2.2.RELEASE</spring.version>
		<jackson.version>2.6.3</jackson.version>
		<logback.version>1.1.3</logback.version>
		<jcl.slf4j.version>1.7.12</jcl.slf4j.version>
		<jstl.version>1.2</jstl.version>
		<servletapi.version>3.1.0</servletapi.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<!-- Need this for json to/from object -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>${jackson.version}</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>

		<!-- JSTL for views -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>

		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${jcl.slf4j.version}</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
		</dependency>

		<!-- compile only, runtime container will provide this -->
		<!-- Need this for config annotation -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servletapi.version}</version>
			<scope>provided</scope>
		</dependency>

	</dependencies>

	<build>

		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.3</version>
				<configuration>
					<source>${jdk.version}</source>
					<target>${jdk.version}</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.eclipse.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>9.2.11.v20150529</version>
				<configuration>
					<scanIntervalSeconds>10</scanIntervalSeconds>
					<webApp>
						<contextPath>/spring4ajax</contextPath>
					</webApp>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.10</version>
				<configuration>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>true</downloadJavadocs>
					<wtpversion>2.0</wtpversion>
					<wtpContextName>spring4ajax</wtpContextName>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.6</version>
				<configuration>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>

			<!-- Deploy to WildFly -->
			<plugin>
				<groupId>org.wildfly.plugins</groupId>
				<artifactId>wildfly-maven-plugin</artifactId>
				<version>1.1.0.Alpha5</version>
				<configuration>
					<hostname>127.0.0.1</hostname>
					<port>9990</port>
					<username>admin</username>
					<password>admin</password>
					<name>spring4ajax.war</name>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

4. Spring Components

Only the important classes will be displayed.

4.1 @RestController to handle the Ajax request. Read the comments for self-explanatory.

AjaxController.java

package com.mkyong.web.controller;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.annotation.JsonView;
import com.mkyong.web.jsonview.Views;
import com.mkyong.web.model.AjaxResponseBody;
import com.mkyong.web.model.SearchCriteria;
import com.mkyong.web.model.User;

@RestController
public class AjaxController {

	List<User> users;

	// @ResponseBody, not necessary, since class is annotated with @RestController
	// @RequestBody - Convert the json data into object (SearchCriteria) mapped by field name.
	// @JsonView(Views.Public.class) - Optional, filters json data to display.
	@JsonView(Views.Public.class)
	@RequestMapping(value = "/search/api/getSearchResult")
	public AjaxResponseBody getSearchResultViaAjax(@RequestBody SearchCriteria search) {

		AjaxResponseBody result = new AjaxResponseBody();

		if (isValidSearchCriteria(search)) {
			List<User> users = findByUserNameOrEmail(search.getUsername(), search.getEmail());

			if (users.size() > 0) {
				result.setCode("200");
				result.setMsg("");
				result.setResult(users);
			} else {
				result.setCode("204");
				result.setMsg("No user!");
			}

		} else {
			result.setCode("400");
			result.setMsg("Search criteria is empty!");
		}

		//AjaxResponseBody will be converted into json format and send back to the request.
		return result;

	}

	private boolean isValidSearchCriteria(SearchCriteria search) {

		boolean valid = true;

		if (search == null) {
			valid = false;
		}

		if ((StringUtils.isEmpty(search.getUsername())) && (StringUtils.isEmpty(search.getEmail()))) {
			valid = false;
		}

		return valid;
	}

	// Init some users for testing
	@PostConstruct
	private void iniDataForTesting() {
		users = new ArrayList<User>();

		User user1 = new User("mkyong", "pass123", "[email protected]", "012-1234567", "address 123");
		User user2 = new User("yflow", "pass456", "[email protected]", "016-7654321", "address 456");
		User user3 = new User("laplap", "pass789", "[email protected]", "012-111111", "address 789");
		users.add(user1);
		users.add(user2);
		users.add(user3);

	}

	// Simulate the search function
	private List<User> findByUserNameOrEmail(String username, String email) {

		List<User> result = new ArrayList<User>();

		for (User user : users) {

			if ((!StringUtils.isEmpty(username)) && (!StringUtils.isEmpty(email))) {

				if (username.equals(user.getUsername()) && email.equals(user.getEmail())) {
					result.add(user);
					continue;
				} else {
					continue;
				}

			}
			if (!StringUtils.isEmpty(username)) {
				if (username.equals(user.getUsername())) {
					result.add(user);
					continue;
				}
			}

			if (!StringUtils.isEmpty(email)) {
				if (email.equals(user.getEmail())) {
					result.add(user);
					continue;
				}
			}

		}

		return result;

	}
}

4.2 The “json data” will be converted into this object, via @RequestBody.

SearchCriteria.java

package com.mkyong.web.model;

public class SearchCriteria {

	String username;
	String email;

	//getters and setters
}

4.2 Create a dummy class for @JsonView, to control what should be returned back to the request.

Views.java

package com.mkyong.web.jsonview;

public class Views {
    public static class Public {}
}

4.3 User object for search function. Fields which annotated with @JsonView will be displayed.

User.java

package com.mkyong.web.model;

import com.fasterxml.jackson.annotation.JsonView;
import com.mkyong.web.jsonview.Views;

public class User {

	@JsonView(Views.Public.class)
	String username;
	
	String password;
	
	@JsonView(Views.Public.class)
	String email;
	
	@JsonView(Views.Public.class)
	String phone;
	
	String address;

	//getters, setters and contructors
}

4.4 This object will be converted into json format and return back to the request.

AjaxResponseBody.java

package com.mkyong.web.model;

import java.util.List;
import com.fasterxml.jackson.annotation.JsonView;
import com.mkyong.web.jsonview.Views;

public class AjaxResponseBody {

	@JsonView(Views.Public.class)
	String msg;
	
	@JsonView(Views.Public.class)
	String code;
	
	@JsonView(Views.Public.class)
	List<User> result;

	//getters and setters
}

Note
The @JsonView belongs to Jackson library, not Spring framework.

5. jQuery Ajax

In JSP, create a simple search form and send the form request with jQuery $.ajax.

welcome.jsp

<%@page session="false"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<c:url var="home" value="/" scope="request" />

<spring:url value="/resources/core/css/hello.css" var="coreCss" />
<spring:url value="/resources/core/css/bootstrap.min.css"
	var="bootstrapCss" />
<link href="${bootstrapCss}" rel="stylesheet" />
<link href="${coreCss}" rel="stylesheet" />

<spring:url value="/resources/core/js/jquery.1.10.2.min.js"
	var="jqueryJs" />
<script src="${jqueryJs}"></script>
</head>

<nav class="navbar navbar-inverse">
	<div class="container">
		<div class="navbar-header">
			<a class="navbar-brand" href="#">Spring 4 MVC Ajax Hello World</a>
		</div>
	</div>
</nav>

<div class="container" style="min-height: 500px">

	<div class="starter-template">
		<h1>Search Form</h1>
		<br>

		<div id="feedback"></div>

		<form class="form-horizontal" id="search-form">
			<div class="form-group form-group-lg">
				<label class="col-sm-2 control-label">Username</label>
				<div class="col-sm-10">
					<input type=text class="form-control" id="username">
				</div>
			</div>
			<div class="form-group form-group-lg">
				<label class="col-sm-2 control-label">Email</label>
				<div class="col-sm-10">
					<input type="text" class="form-control" id="email">
				</div>
			</div>

			<div class="form-group">
				<div class="col-sm-offset-2 col-sm-10">
					<button type="submit" id="bth-search"
						class="btn btn-primary btn-lg">Search</button>
				</div>
			</div>
		</form>

	</div>

</div>

<div class="container">
	<footer>
		<p>
			&copy; <a href="https://mkyong.com">Mkyong.com</a> 2015
		</p>
	</footer>
</div>

<script>
	jQuery(document).ready(function($) {

		$("#search-form").submit(function(event) {

			// Disble the search button
			enableSearchButton(false);

			// Prevent the form from submitting via the browser.
			event.preventDefault();

			searchViaAjax();

		});

	});

	function searchViaAjax() {

		var search = {}
		search["username"] = $("#username").val();
		search["email"] = $("#email").val();

		$.ajax({
			type : "POST",
			contentType : "application/json",
			url : "${home}search/api/getSearchResult",
			data : JSON.stringify(search),
			dataType : 'json',
			timeout : 100000,
			success : function(data) {
				console.log("SUCCESS: ", data);
				display(data);
			},
			error : function(e) {
				console.log("ERROR: ", e);
				display(e);
			},
			done : function(e) {
				console.log("DONE");
				enableSearchButton(true);
			}
		});

	}

	function enableSearchButton(flag) {
		$("#btn-search").prop("disabled", flag);
	}

	function display(data) {
		var json = "<h4>Ajax Response</h4>&lt;pre&gt;"
				+ JSON.stringify(data, null, 4) + "&lt;/pre&gt;";
		$('#feedback').html(json);
	}
</script>

</body>
</html>

6. Demo

6.1 http://localhost:8080/spring4ajax/

spring-mvc-ajax-example-demo-1

6.2 Empty field validation.

spring-mvc-ajax-example-demo-2

6.3 Search by username.

spring-mvc-ajax-example-demo-3

6.4. Search by email.

spring-mvc-ajax-example-demo-4

5. The Chrome browser, inspect element, network tag.

spring-mvc-ajax-example-demo-5

7. How to run this project?

7.1 Clone the source code from Github


$ git clone https://github.com/mkyong/spring4-mvc-ajax-example

7.2 Run the embedded Jetty container.


$ mvn jetty:run

7.3 Visit this URL – http://localhost:8080/spring4ajax/

Download Source Code

References

  1. jQuery.ajax()
  2. Jackson Feature: JSON Views
  3. Using @JsonView with Spring MVC
  4. Latest Jackson integration improvements in Spring
  5. HTTP : Status Code Definitions
  6. Spring – @RequestBody
  7. Spring – @ResponseBody
  8. Spring – @RestController
  9. Gradle – Spring 4 MVC hello world annotation

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
39 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Java9pro
6 years ago

Thanks.This tutorial solved my problem

Mourad
7 years ago

Hi Mkyong,
I always found your examples clear and good,
Thanks lot!

Java9pro
6 years ago

Thanks. tutorial solved my problem

Danilo Domingos
8 years ago

Hey guy, what example! So far the best tutorial i’ve ever seen. Thanks!!!

Kailash
1 year ago

Thanks for the article . I am quite late but while working on this code, I get following issue.
Multiple markers at this line
– PostConstruct cannot be resolved 
to a type
– PostConstruct cannot be resolved 
to a type

Anyone know how to resolve this?

Noman
4 years ago

Hi, is it possible to save an image in this way? how can I do it? Do you have any example? Thank you

Shahul
4 years ago

Thank you mkYong for providing this good example.

I am able to deploy and start jetty with this project.

But I am getting below content on hitting http://localhost:2222/spring4ajax/ not showing search page.

Could you/someone please help me here.

Directory: /spring4ajax/
spring4-mvc-maven-ajax-example-1.0-SNAPSHOT.war 13184243 bytes Apr 8, 2020 3:58:31 PM

anonymous
5 years ago

method post not allowed

Shivam Upadhyay
5 years ago

how to do CRUD operating in Spring MVC in eclipse without refreshing the page and connection with database

Deamonnnnnnn
5 years ago

when i “$ mvn jetty:run “in the git bush it shows “No plugin found for prefix ‘jetty”‘

Mudassir
6 years ago

Could you please explain how can i do the same if i’m sending and receiving the data in XML instead of json?

Thanks

nelson
6 years ago

good tutorial, but i integration in my project and show this
{
“readyState”: 4,
“responseText”: ”
Estado HTTP 405 – Request method ‘POST’ not supported
type Informe de estado

mensaje Request method ‘POST’ not supported

descripción El método HTTP especificado no está permitido para el recurso requerido.

Pivotal tc Runtime 3.1.5.RELEASE/8.0.36.A.RELEASE
“,
“status”: 405,
“statusText”: “Método No Permitido”
}

freakander
7 years ago

Could you please explain to me what the “$” sign mean in the following line:

jQuery(document).ready(function($) {
And also why this line doesn’t start like:
$(document) ?
Thanks in advance!

Akash Chavda
7 years ago

this is a good example, thanks.

Ercan
7 years ago

Hi Mkyong,

I have two questions. First, How to create layout file?
And other question, Can we add annotation to validation for view class. i don’t want to write isValidSearchCriteria method.

thanks.

sairam
7 years ago

i got the following error while i execute the code …

The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.

“status”: 415,

“statusText”: “Unsupported Media Type”

Ahmet Ercan Ünal
7 years ago

this is a good example, thanks.

Yang Min
7 years ago

Thanks

sultanc2
8 years ago

Hi Mkyoung,
i’m getting this error :
HTTP ERROR 406 Not Acceptable.

i’m sure that the ‘result’ object from ‘AjaxResponseBody’ class having a value when returned back to ajax response but i always get that error.

I’m using:
– spring 4.0.2
– jackson 2.6.3
– jetty server

Kapil Naidu
8 years ago

HI Mkyong,
I’m uable to run this project in Tomcat 8, I mean the Tomcat starts properly with this project, but when I hit the url, it gives me 404.

Thanks,
Kapil

Prashanth Arul
8 years ago

Hi Mkyong,

Am trying to get this application up and running in JBoss AS7 but am getting a 404 when accessing http://localhost:8080/spring4ajax/search/api/getSearchResult/

I have the same issue with one of my application which works well in Tomcat but not in JBoss AS7, just wondering if there is a workaround if you know off.

Thanks

mkyong
8 years ago
Reply to  Prashanth Arul

Article is updated with wildfly-maven-plugin, use this command mvn wildfly:deploy to deploy this web application to WildFly.

Access http://localhost:8080/spring4ajax/

Hosein Aghajani
7 years ago
Reply to  mkyong

I am new in java
where should I run this command

mkyong
8 years ago
Reply to  Prashanth Arul

1. 404 is resources not found. Make sure ‘spring4ajax’ is your deployed web context.

2. If you get this example and deploy directly, the default web context will be this – http://localhst:8080/spring4-mvc-maven-ajax-example-1.0-SNAPSHOT

3. To update the WildFly web context, try this tutorial – https://mkyong.com/maven/maven-deploy-web-application-to-wildfly/

P.S This web application is tested with WildFly 9, no error.

Mukesh Sharma
8 years ago

hey guys , find given solution to compile the project.

you need to add following plugin in pom.xml

maven-war-plugin

2.4

false

Hope it would work for you guys , cheers 🙂

mkyong
8 years ago
Reply to  Mukesh Sharma

Thanks, article is updated with maven-war-plugin.

Scott Chen
8 years ago
Reply to  Mukesh Sharma

still can not work please help.HTTP Status 500 – An exception occurred processing JSP page /welcome.jsp at line 11

Mukesh Sharma
8 years ago
Reply to  Scott Chen

can you try that link after starting jetty server
make sure your port should not be used before.
http://localhost:8080/spring4ajax/

Raul Mordillo Lluva
8 years ago

It is not compiling:

Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode) -> [Help 1]

mkyong
8 years ago

Fixed, article is updated with maven-war-plugin.

Mukesh Sharma
8 years ago

Raul ,add this in your pom.xml

maven-war-plugin

2.4

false

Paul Zeh
8 years ago

Jeez, this is not a tutorial, but rather a template. It’s 400+ lines of code and merely a dozen lines of explanation.

Srini
8 years ago

Where is the web.xml file ? I have the following error:

org.xml.sax.SAXParseException; systemId: file:/C:/DEV/apache-tomcat-8.0.28/webapps/spring4-mvc-maven-ajax-example-1.0-SNAPSHOT/WEB-INF/web.xml; lineNumber: 1; columnNumber: 2; Pre
mature end of file.

at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)

mkyong
8 years ago
Reply to  Srini

For servlet container >= 3, web.xml is option. Code is updated, try clone the source code from GitHub again.

Mukesh Sharma
8 years ago
Reply to  Srini

you need to add following plugin in pom.xml

maven-war-plugin

2.4

false

Angel Ruiz
8 years ago

Hi Mkyong,

I reckon that you will find that using my library http://www.ajaxanywhere.com makes things a lot easier with a far more maintainable outcome. Ajaxanywhere is intended to provide declarative Ajax for apps that use server side rendering. Because it is declarative, by using HTML markup, you will find that you use very llittle to none javascript code. Please have a look at the examples: http://examples.ajaxanywhere.com
I would appreciate your feedback a lot!
Thanks!

Andrei
6 years ago

Good stuff, but you should keep it more simple. Some details are not really needed here. For example, the @JsonView annotation only confused me more untill I figured it has nothing to do with the scope of this presentation. Just skip it.
Also, some details are maybe missing. For example, in order to work, I had to add an extention in ajax url (“url: getSearchResult.ext”) and then add this in web.xml:

dispatcher
*.ext

Andrei
6 years ago
Reply to  Andrei

servlet-mapping
servlet-name dispatcher /servlet-name
url-pattern *.ext /url-pattern
/servlet-mapping