Let us implement Autocomplete feature in Spring MVC application using JQuery. Autocomplete is a feature you”ll see in almost all good web apps. It allows user to select proper values from a list of items. Adding this feature is recommended if the field has multiple ( > 20 to 25) values.
Related:Autocomplete in Java / JSP
Our requirement is simple. We will have two fields Country and Technologies. Both these fields will have autocomplete feature so user will be able to select from list of countries and technologies. The country field can have only one value. But the technologies field can have multiple values separated by comma (,).
Before we starts with our Spring MVC Autocomplete Example, we will need few tools.
Note that depending on the current version of Spring MVC, the version number of above jar files may change. Also note that we need jackson mapper and jackson core jars. This is required for generating JSON from our Spring MVC Controller.
Let us start with our Spring 3.0 MVC based application. Open Eclipse and goto File -> New -> Project and select Dynamic Web Project in the New Project wizard screen.
After selecting Dynamic Web Project, press Next.
Write the name of the project. For example SpringMVC_Autocomplete. Once this is done, select the target runtime environment (e.g. Apache Tomcat v6.0). This is to run the project inside Eclipse environment. After this press Finish. Once the project is created, you can see its structure in Project Explorer. This is how the project structure would look like once we finish the tutorial and add all source code.
Now copy all the required JAR files in WebContent > WEB-INF > lib folder. Create this folder if it does not exists.
Normally you would need a database from where you’ll fetch values required for autocomplete. But for sake of simplicity of this example we will write a DummyDB java class. Once the project is created, create a package net.viralpatel.springmvc.autocomplete and a Java class file DummyDB.java. DummyDB.java is the class that will simulate the database connection and it will provide the data for our example.
File: /src/net/viralpatel/springmvc/autocomplete/DummyDB.java
package net.viralpatel.spring.autocomplete;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class DummyDB {
private List<String> countries;
private List<String> tags;
public DummyDB() {
String data = "Afghanistan, Albania, Algeria, Andorra, Angola, Antigua & Deps,"+
"United Kingdom,United States,Uruguay,Uzbekistan,Vanuatu,Vatican City,Venezuela,Vietnam,Yemen,Zambia,Zimbabwe";
countries = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(data, ",");
//Parse the country CSV list and set as Array
while(st.hasMoreTokens()) {
countries.add(st.nextToken().trim());
}
String strTags = "SharePoint, Spring, Struts, Java, JQuery, ASP, PHP, JavaScript, MySQL, ASP, .NET";
tags = new ArrayList<String>();
StringTokenizer st2 = new StringTokenizer(strTags, ",");
//Parse the tags CSV list and set as Array
while(st2.hasMoreTokens()) {
tags.add(st2.nextToken().trim());
}
}
public List<String> getCountryList(String query) {
String country = null;
query = query.toLowerCase();
List<String> matched = new ArrayList<String>();
for(int i=0; i < countries.size(); i++) {
country = countries.get(i).toLowerCase();
if(country.startsWith(query)) {
matched.add(countries.get(i));
}
}
return matched;
}
public List<String> getTechList(String query) {
String country = null;
query = query.toLowerCase();
List<String> matched = new ArrayList<String>();
for(int i=0; i < tags.size(); i++) {
country = tags.get(i).toLowerCase();
if(country.startsWith(query)) {
matched.add(tags.get(i));
}
}
return matched;
}
}
Code language: Java (java)
The DummyDB.java
contains the list of all the countries and technologies in a comma separated string value and a method getCountryList()
and getTechList()
that will return the list of countries and technologies starting with the string query passed as argument to that method. Thus if we pass “IN” to this method, it will return as all the countries starting with IN. You may want to change this code and add the database implementation here. Just a simple "SELECT * FROM <table> WHERE country LIKE " query
will serve the purpose. Now we write SpringMVC Controller that returns JSON output for Autocomplete.
The spring mvc controller class that will process the request and returns JSON output. For this create a class UserController.java
under package net.viralpatel.springmvc.autocomplete
.
UserController.java
package net.viralpatel.spring.autocomplete;
import java.util.List;
import org.springframework.stereotype.Controller;
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.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class UserController {
private static DummyDB dummyDB = new DummyDB();
@RequestMapping(value = "/index", method = RequestMethod.GET)
public ModelAndView index() {
User userForm = new User();
return new ModelAndView("user", "userForm", userForm);
}
@RequestMapping(value = "/get_country_list",
method = RequestMethod.GET,
headers="Accept=*/*")
public @ResponseBody List<String> getCountryList(@RequestParam("term") String query) {
List<String> countryList = dummyDB.getCountryList(query);
return countryList;
}
@RequestMapping(value = "/get_tech_list",
method = RequestMethod.GET,
headers="Accept=*/*")
public @ResponseBody List<String> getTechList(@RequestParam("term") String query) {
List<String> countryList = dummyDB.getTechList(query);
return countryList;
}
}
Code language: Java (java)
Note how we used @ResponseBody
annotation in methods getCountryList()
and getTechList()
. Spring MVC converts the return type which in our case is List into JSON data. Following is the content of spring-servlet.xml file.
File: /WebContent/WEB-INF/spring-servlet.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="net.viralpatel.spring.autocomplete" />
<mvc:annotation-driven />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Code language: HTML, XML (xml)
The tag is required here. This lets Spring to process annotations like @ResponseBody
. The below User.java class is required only to bind a form with JSP. It is not required for this example. But for sake of Spring MVC we are using it.
File: /src/net/viralpatel/springmvc/autocomplete/User.java
package net.viralpatel.spring.autocomplete;
public class User {
private String name;
private String country;
private String technologies;
//Getter and Setter methods
}
Code language: Java (java)
Now add JSP file which renders User form. Also we will add index.jsp which redirect to proper request.
File: /WebContent/index.jsp
<jsp:forward page="index.html"></jsp:forward>
Code language: HTML, XML (xml)
File: /WebContent/WEB-INF/jsp/user.jsp
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Spring MVC Autocomplete with JQuery & JSON example</title>
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" />
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
</head>
<body>
<h2>Spring MVC Autocomplete with JQuery & JSON example</h2>
<form:form method="post" action="save.html" modelAttribute="userForm">
<table>
<tr>
<th>Name</th>
<td><form:input path="name" /></td>
</tr>
<tr>
<th>Country</th>
<td><form:input path="country" id="country" /></td>
</tr>
<tr>
<th>Technologies</th>
<td><form:input path="technologies" id="technologies" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Save" />
<input type="reset" value="Reset" />
</td>
</tr>
</table>
<br />
</form:form>
<script type="text/javascript">
function split(val) {
return val.split(/,\s*/);
}
function extractLast(term) {
return split(term).pop();
}
$(document).ready(function() {
$( "#country" ).autocomplete({
source: '${pageContext. request. contextPath}/get_country_list.html'
});
$( "#technologies").autocomplete({
source: function (request, response) {
$.getJSON("${pageContext. request. contextPath}/get_tech_list.html", {
term: extractLast(request.term)
}, response);
},
search: function () {
// custom minLength
var term = extractLast(this.value);
if (term.length < 1) {
return false;
}
},
focus: function () {
// prevent value inserted on focus
return false;
},
select: function (event, ui) {
var terms = split(this.value);
// remove the current input
terms.pop();
// add the selected item
terms.push(ui.item.value);
// add placeholder to get the comma-and-space at the end
terms.push("");
this.value = terms.join(", ");
return false;
}
});
});
</script>
</body>
</html>
Code language: HTML, XML (xml)
Check the above JSP. We have added INPUT fields for Country and Technologies. Also we used $().autocomplete()
to enable autocomplete. For country it was straightforward $( "#country" ).autocomplete()
but for technologies we did some parsing and splitting. This is because we need multiple technologies in textbox separated by comma.
You may want to run the application see the result. I assume you have already configured Tomcat in eclipse. All you need to do: Open Server view from Windows > Show View > Server. Right click in this view and select New > Server and add your server details. To run the project, right click on Project name from Project Explorer and select Run as > Run on Server (Shortcut: Alt+Shift+X, R)
SpringMVC_Autocomplete.zip (4.2 MB)
Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…
Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…
Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…
1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…
GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…
1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…
View Comments
Great job. Only I have one slight problem. Not wanting to use JQuery UI just for one widget, and really don't like JQuery UI. How can you use all the same code as you have, but a different AutoComplete widget?
Appreciate it. good example
Thanks
i had a doubt in the count text box you are showing the list countries starts with " i " but in the string data doesn't have those name which starts with " i "
see carefully the DummyDB.java file...String data contains all the country names and it also contains names starting with 'i'....
Good stuff.
Good one.
Good example and works.
Only comment is, the jackson jar's that is in the example screen needed to be updated with two more jar files that was is in the zip file.
Hi Satish,
I am getting json back.. But the not getting the dropdown... Can it be bcoz of those remaining 2 jar files?
That correct nilesh you need to add 2 jar that are highlighted.
Hi Viral.
Thanks for such a nicely documented blog. I tried implementing the above feature. I am able to get the json response at client side. But I am not getting the auto-populated drop down list. Any idea?
Hey great tutorial! I did everything but I got an error when I tried to run it. Can someone assist please? I get the error below:
HTTP Status 404 - /SpringMVC_Autocomplete/
type Status report
message /SpringMVC_Autocomplete/
description The requested resource (/SpringMVC_Autocomplete/) is not available.
Apache Tomcat/6.0.35
Update: sorry i forgot to put the index file in the right place...now i get a java error. one problem i noticed is that the project explorer view does not look like your example. I figure the reason is that i am using the lastest eclipse "cocoa" . Please advise, Here the java error...
HTTP Status 500 -
type Exception report
message
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
org.apache.jasper.JasperException: java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:502)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:424)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
root cause
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:84)
org.springframework.web.servlet.support.RequestContextUtils.getWebApplicationContext(RequestContextUtils.java:81)
org.springframework.web.servlet.support.RequestContext.initContext(RequestContext.java:219)
org.springframework.web.servlet.support.JspAwareRequestContext.initContext(JspAwareRequestContext.java:74)
org.springframework.web.servlet.support.JspAwareRequestContext.(JspAwareRequestContext.java:48)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:76)
org.apache.jsp.index_jsp._jspx_meth_form_005fform_005f0(index_jsp.java:184)
org.apache.jsp.index_jsp._jspService(index_jsp.java:95)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:388)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
note The full stack trace of the root cause is available in the Apache Tomcat/6.0.35 logs.
@BigCoder, It seems Spring is unable to locate your WebApplicationContext XML file. That is what the exception hints you - java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
Please check for the following -
1. By default, the naming convention of WebApplicationContext XML file is -servlet.xml. for e.g., if "springmvc" were the servlet name then the WebApplicationContext XML should be available in \WEB-INF folder with the name "springmvc-servlet.xml"
or
2. If you have named your WebApplicationContext XML file differently, not adhering to the above naming convention then you should specify the location and name of your WebApplicationContext XML in web.xml with a context parameter and a context loader listener to load it. See below for an example -
contextConfigLocation
/WEB-INF/
org.springframework.web.context.ContextLoaderListener
Hope the above steps will solve your problem.