Create Spring MVC Project
On the Eclipse, create a Spring MVC project
Enter Project Information:
- Name: LearnSpringMVCWithRealApps
- Group: com.demo
- Artifact: LearnSpringMVCWithRealApps
- Description: Learn Spring MVC with Real Apps
- Package: com.demo
Select the technologies and libraries to be used:
- Web
- JPA
- MySQL
Click Next button to show Site Information for project
Click Finish button to finish create Spring MVC project
Configure pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>CascadingDropDownListWithSpringMVC</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>CascadingDropDownListWithSpringMVC</name>
<description>Cascading Drop Down List with Spring MVC and Spring Data JPA</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- JSTL tag lib -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Create Database
Create a database with the name is learn_spring_mvc_with_real_apps. This database have 3 table: Country, State and City table
--
-- Table structure for table `city`
--
CREATE TABLE `city` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(250) NOT NULL,
`stateId` int(11) NOT NULL REFERENCES state(id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `city`
--
INSERT INTO `city` (`id`, `name`, `stateId`) VALUES
(1, 'City 1', 1),
(2, 'City 2', 1),
(3, 'City 3', 2),
(4, 'City 4', 2),
(5, 'City 5', 2),
(6, 'City 6', 3),
(7, 'City 7', 3);
-- --------------------------------------------------------
--
-- Table structure for table `country`
--
CREATE TABLE `country` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `country`
--
INSERT INTO `country` (`id`, `name`) VALUES
(1, 'Country 1'),
(2, 'Country 2'),
(3, 'Country 3'),
(4, 'Country 4');
-- --------------------------------------------------------
--
-- Table structure for table `state`
--
CREATE TABLE `state` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(250) NOT NULL,
`countryId` int(11) NOT NULL REFERENCES country(id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `state`
--
INSERT INTO `state` (`id`, `name`, `countryId`) VALUES
(1, 'State 1', 1),
(2, 'State 2', 1),
(3, 'State 3', 1),
(4, 'State 5', 2),
(5, 'State 6', 2),
(6, 'State 7', 3),
(7, 'State 8', 3);
Structure of Country Table
Data of Country Table
Structure of State Table
Data of State Table
Structure of City Table
Data of City Table
Configure application.properties
spring.mvc.view.prefix = /WEB-INF/views/
spring.mvc.view.suffix = .jsp
spring.mvc.static-path-pattern=/resources/**
server.port=9596
spring.datasource.url= jdbc:mysql://localhost:3306/demo5
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
Create Resources
JQuery
Create new folder named js in src\main\resources\static folder. Copy jquery file to this folder
Entities Class
Create new package, named com.demo.entities. In this package, create entities class as below:
Country Entity
Create new java class, named Country.java
package com.demo.entities;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "country")
public class Country implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Set<State> states = new HashSet<State>(0);
public Country() {
}
public Country(String name) {
this.name = name;
}
public Country(String name, Set<State> states) {
this.name = name;
this.states = states;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "name", nullable = false, length = 250)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "country")
public Set<State> getStates() {
return this.states;
}
public void setStates(Set<State> states) {
this.states = states;
}
}
State Entity
Create new java class, named State.java
package com.demo.entities;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "state")
public class State implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Country country;
private String name;
private Set<City> cities = new HashSet<City>(0);
public State() {
}
public State(Country country, String name) {
this.country = country;
this.name = name;
}
public State(Country country, String name, Set<City> cities) {
this.country = country;
this.name = name;
this.cities = cities;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "countryId", nullable = false)
public Country getCountry() {
return this.country;
}
public void setCountry(Country country) {
this.country = country;
}
@Column(name = "name", nullable = false, length = 250)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "state")
public Set<City> getCities() {
return this.cities;
}
public void setCities(Set<City> cities) {
this.cities = cities;
}
}
StateEntity Entity
Create new java class, named StateEntity.java
package com.demo.entities;
import java.io.Serializable;
public class StateEntity implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
public StateEntity() {
}
public StateEntity(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
City Entity
Create new java class, named City.java
package com.demo.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "city")
public class City implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private State state;
private String name;
public City() {
}
public City(State state, String name) {
this.state = state;
this.name = name;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "stateId", nullable = false)
public State getState() {
return this.state;
}
public void setState(State state) {
this.state = state;
}
@Column(name = "name", nullable = false, length = 250)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
CityEntity Entity
Create new java class, named CityEntity.java
package com.demo.entities;
import java.io.Serializable;
public class CityEntity implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
public CityEntity() {
}
public CityEntity(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Repository Interfaces
Create new package named com.demo.repositories. In this package, create new repositories as below.
Country Repository
In com.demo.repositories package, create new interface named CountryRepository.java as below:
package com.demo.repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.demo.entities.Country;
@Repository("countryRepository")
public interface CountryRepository extends CrudRepository<Country, Integer> {
}
State Repository
In com.demo.repositories package, create new interface named StateRepository.java as below:
package com.demo.repositories;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.demo.entities.State;
import com.demo.entities.StateEntity;
@Repository("stateRepository")
public interface StateRepository extends CrudRepository<State, Integer> {
@Query("select new com.demo.entities.StateEntity(id, name) from State where country.id = :id")
public List<StateEntity> findByCountry(@Param("id") int id);
}
City Repository
In com.demo.repositories package, create new interface named CityRepository.java as below:
package com.demo.repositories;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.demo.entities.City;
import com.demo.entities.CityEntity;
@Repository("cityRepository")
public interface CityRepository extends CrudRepository<City, Integer> {
@Query("select new com.demo.entities.CityEntity(id, name) from City where state.id = :id")
public List<CityEntity> findByState(@Param("id") int id);
}
Country Service
Create new package named com.demo.services. In this package, create country service as below:
Country Service Interface
In com.demo.services package, create new interface named CountryService.java as below:
package com.demo.services;
import com.demo.entities.Country;
public interface CountryService {
public Iterable<Country> findAll();
public Country find(int id);
}
Country Service Class
In com.demo.services package, create new class named CountryServiceImpl.java implements from CountryService interface as below:
package com.demo.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.entities.Country;
import com.demo.repositories.CountryRepository;
@Service("countryService")
public class CountryServiceImpl implements CountryService {
@Autowired
private CountryRepository countryRepository;
@Override
public Iterable<Country> findAll() {
return countryRepository.findAll();
}
@Override
public Country find(int id) {
return countryRepository.findById(id).get();
}
}
State Service
Create new package named com.demo.services. In this package, create state service as below:
State Service Interface
In com.demo.services package, create new interface named StateService.java as below:
package com.demo.services;
import java.util.List;
import com.demo.entities.StateEntity;
public interface StateService {
public List<StateEntity> findByCountry(int id);
}
State Service Class
In com.demo.services package, create new class named StateServiceImpl.java implements from StateService interface as below:
package com.demo.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.entities.StateEntity;
import com.demo.repositories.StateRepository;
@Service("stateService")
public class StateServiceImpl implements StateService {
@Autowired
private StateRepository stateRepository;
@Override
public List<StateEntity> findByCountry(int id) {
return stateRepository.findByCountry(id);
}
}
City Service
Create new package named com.demo.services. In this package, create city service as below:
City Service Interface
In com.demo.services package, create new interface named CityService.java as below:
package com.demo.services;
import java.util.List;
import com.demo.entities.CityEntity;
public interface CityService {
public List<CityEntity> findByState(int id);
}
City Service Class
In com.demo.services package, create new class named CityServiceImpl.java implements from CityService interface as below:
package com.demo.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.entities.CityEntity;
import com.demo.repositories.CityRepository;
@Service("cityService")
public class CityServiceImpl implements CityService {
@Autowired
private CityRepository cityRepository;
@Override
public List<CityEntity> findByState(int id) {
return cityRepository.findByState(id);
}
}
Demo Controllers
Create new package named com.demo.controllers. In this package, create new controller as below:
Demo Controller
Create new java class, named DemoController.java
package com.demo.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.demo.services.CityService;
import com.demo.services.CountryService;
import com.demo.services.StateService;
import com.google.gson.Gson;
@Controller
@RequestMapping(value = { "", "demo" })
public class DemoController {
@Autowired
private CountryService countryService;
@Autowired
private StateService stateService;
@Autowired
private CityService cityService;
@RequestMapping(method = RequestMethod.GET)
public String index(ModelMap modelMap) {
modelMap.put("countries", countryService.findAll());
return "demo/index";
}
@ResponseBody
@RequestMapping(value = "loadStatesByCountry/{id}", method = RequestMethod.GET)
public String loadStatesByCountry(@PathVariable("id") int id) {
Gson gson = new Gson();
return gson.toJson(stateService.findByCountry(id));
}
@ResponseBody
@RequestMapping(value = "loadCitiesByState/{id}", method = RequestMethod.GET)
public String loadCitiesByState(@PathVariable("id") int id) {
Gson gson = new Gson();
return gson.toJson(cityService.findByState(id));
}
}
Create Views
Create new folders with path webapp\WEB-INF\views in src\main. In views folder, create views as below:
Index View
Create new folder named demo. Create new jsp file named index.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Cascading Dropdown List with Ajax in Spring MVC Framework and Spring Data JPA</title>
<script src="${pageContext.request.contextPath }/resources/js/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#comboboxCountry').on('change', function(){
var countryId = $(this).val();
$.ajax({
type: 'GET',
url: '${pageContext.request.contextPath }/demo/loadStatesByCountry/' + countryId,
success: function(result) {
var result = JSON.parse(result);
var s = '';
for(var i = 0; i < result.length; i++) {
s += '<option value="' + result[i].id + '">' + result[i].name + '</option>';
}
$('#comboboxState').html(s);
}
});
});
$('#comboboxState').on('change', function(){
var stateId = $(this).val();
$.ajax({
type: 'GET',
url: '${pageContext.request.contextPath }/demo/loadCitiesByState/' + stateId,
success: function(result) {
var result = JSON.parse(result);
var s = '';
for(var i = 0; i < result.length; i++) {
s += '<option value="' + result[i].id + '">' + result[i].name + '</option>';
}
$('#comboboxCity').html(s);
}
});
});
});
</script>
</head>
<body>
<form>
<table>
<tr>
<td>Country</td>
<td>
<select id="comboboxCountry" style="width:200px">
<c:forEach var="country" items="${countries }">
<option value="${country.id }">${country.name }</option>
</c:forEach>
</select>
</td>
</tr>
<tr>
<td>State</td>
<td>
<select id="comboboxState" style="width:200px"></select>
</td>
</tr>
<tr>
<td>City</td>
<td>
<select id="comboboxCity" style="width:200px"></select>
</td>
</tr>
</table>
</form>
</body>
</html>
Structure of Spring MVC Project
Run Application
Select LearnSpringMVCWithRealAppsApplication.java file in com.demo package, right click and select Run As/Spring Boot App menu
Access index method in demo controller with following url: http://localhost:9596
Output