Technology Stack
Project Structure
pom.xml
Add the below in pom.xml
- spring-boot-starter-parent – add this as parent
- mysql-connector-java – needed for mysql driver and other related classes.
Add the below spring boot starters
- spring-boot-starter-web – needed for spring mvc
- spring-boot-starter-thymeleaf – needed for thymeleaf
- spring-boot-starter-data-jpa – needed for spring data jpa
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
Domain Layer
Define the Account Entity here.
package com.spring.mvc.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Account {
public Account() {}
@Id
private String username;
public Account(String username, String password, String firstname, String lastname) {
this.username = username;
this.password = password;
this.firstname = firstname;
this.lastname = lastname;
}
private String password;
private String firstname;
private String lastname;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}
Repository Layer
Define the Spring Data JPA Interface which extends CrudRepository.
Please visit Spring Data JPA+Spring Boot+MySQL for better understanding of Spring Data JPA.
package com.spring.mvc.repository;
import org.springframework.data.repository.CrudRepository;
import com.spring.mvc.model.Account;
public interface AccountRepository extends CrudRepository<Account, String>{
}
Service Layer
Define Service Interface
package com.spring.mvc.service;
import com.spring.mvc.model.Account;
public interface AccountService {
public Account createAccount(Account account);
public Account findAccount(String username, String password);
}
Define Service Implementation
package com.spring.mvc.service;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.spring.mvc.model.Account;
import com.spring.mvc.repository.AccountRepository;
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountRepository repository;
@Override
public Account createAccount(Account account) {
if (repository.existsById(account.getUsername())) {
return null;
}
return repository.save(account);
}
@Override
public Account findAccount(String username, String password) {
Optional<Account> dbAccount = repository.findById(username);
if (dbAccount.isPresent() && dbAccount.get().getPassword().equals(password)) {
return dbAccount.get();
}
return null;
}
}
Controller Layer
package com.spring.mvc.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.spring.mvc.model.Account;
import com.spring.mvc.service.AccountService;
@Controller
public class ApplicationController {
@Autowired
private AccountService accountService;
@GetMapping(“/”)
public String landingPage(Model model) {
return “landing”;
}
@PostMapping(“/login”)
public String welcome(@RequestParam(“username”) String username, @RequestParam(“password”) String password,
Model model) {
if(username == null || username.isEmpty()) {
model.addAttribute(“errormessage”, “Please enter username”);
return landingPage(model);
}
if(password == null || password.isEmpty()) {
model.addAttribute(“password”, “Please enter password”);
return landingPage(model);
}
Account account = accountService.findAccount(username, password);
if (account == null) {
model.addAttribute(“errormessage”, “Your username and password combination is not correct”);
model.addAttribute(“username”, username);
model.addAttribute(“password”, password);
return landingPage(model);
}
model.addAttribute(“account”, account);
return “welcome”;
}
@GetMapping(“/registration”)
public String registration(Model model) {
return “registration”;
}
@PostMapping(“/createAccount”)
public String createAccount(Model model,@RequestParam(“username”) String username,
@RequestParam(“password”) String password,@RequestParam(“againpassword”) String againpassword,
@RequestParam(“firstname”) String firstname,@RequestParam(“lastname”) String lastname) {
boolean reloadPage = false;
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password) || StringUtils.isEmpty(againpassword)
|| StringUtils.isEmpty(firstname) || StringUtils.isEmpty(lastname)) {
reloadPage = true;
model.addAttribute(“errormessage”, “All fields are mandatory.”);
}
if (!reloadPage && !password.equals(againpassword)) {
reloadPage = true;
model.addAttribute(“errormessage”, “Password does not match”);
}
if (!reloadPage) {
Account account = new Account(username, password, firstname, lastname);
Account dbAccount = accountService.createAccount(account);
if (dbAccount == null) {
reloadPage = true;
model.addAttribute(“errormessage”, “Account already exists for the username”);
}
}
if (reloadPage) {
model.addAttribute(“username”, username);
model.addAttribute(“password”, password);
model.addAttribute(“againpassword”, againpassword);
model.addAttribute(“firstname”, firstname);
model.addAttribute(“lastname”, lastname);
return registration(model);
}
model.addAttribute(“message”, “Account successfully created. Please login.”);
return landingPage(model);
}
}
Define datasource, entityManagerFactory and other beans here.
package com.spring.mvc.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(scanBasePackages = {“com.spring.mvc.controller”,”com.spring.mvc.service”})
@EnableTransactionManagement
@EnableJpaRepositories(“com.spring.mvc.repository”)
@PropertySource(“classpath:database.properties”)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Autowired
Environment environment;
private final String URL = “url”;
private final String USER = “dbuser”;
private final String PASSWORD = “dbpassword”;
private final String PROPERTY_SHOW_SQL = “hibernate.show_sql”;
private final String PROPERTY_DIALECT = “hibernate.dialect”;
@Bean
DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl(environment.getProperty(URL));
driverManagerDataSource.setUsername(environment.getProperty(USER));
driverManagerDataSource.setPassword(environment.getProperty(PASSWORD));
return driverManagerDataSource;
}
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistenceProvider.class);
lfb.setPackagesToScan(“com.spring.mvc.model”);
lfb.setJpaProperties(hibernateProps());
return lfb;
}
Properties hibernateProps() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
}
@Bean
JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
database.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testchema
dbuser=root
dbpassword=root
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
View Layer – templates
Thymeleaf is a default template used by Spring Boot.
By default, Spring Boot looks for the templates in src/main/resources/templates location.
Add the html files inside src/main/resources/templates
landing.html
<html xmlns:th=″http://www.thymeleaf.org″>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<title>Application</title>
<link rel=”stylesheet” href=″https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css″>
</head>
<body style=”width:50%;margin: 20px;padding: 20px;”>
<h3>Spring MVC Application using Spring Boot and Thymeleaf</h3>
<p style=”color: red;”>[[${errormessage}]]</p>
<p style=”color: green;”>[[${message}]]</p>
<div style=”margin: 20px;border: 1px solid blue;padding: 20px;”>
<div class=”form” style=”margin: 20px;padding: 20px;”>
<h4>Login</h4>
<form action=”login” method=”post”>
<table class=”table table-bordered”>
<tr>
<td>Please Enter Your UserName</td>
<td><input id=”username” name=”username” th:value=”${username}”></td>
</tr>
<tr>
<td>Please Enter Your Password</td>
<td><input id=”password” name=”password” type=”password” th:value=”${password}”></td>
</tr>
</table>
<input type=”submit” value=”Submit”>
</form>
</div>
<div class=”form”>
<form action=”/registration” method=”get”>
<table>
<tr>
<td><input type=”submit” value=”Registration”></td>
</tr>
</table>
</form>
</div>
</div>
</body>
</html>
welcome.html
<html xmlns:th=″http://www.thymeleaf.org″>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<title>Application</title>
<link rel=”stylesheet” href=″https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css″>
</head>
<body style=”width:50%;”>
<div style=”margin: 20px;padding: 20px;”>
<h3>Spring MVC Application using Spring Boot and Thymeleaf</h3>
<div class=”form” style=”margin: 20px;border: 1px solid blue;padding: 20px;”>
<h4>Your Details are mentioned below:</h4>
<table class=”table table-bordered” style=”padding: 20px;”>
<tr>
<td>UserName</td>
<td>[[${account.username}]]</td>
</tr>
<tr>
<td>FirstName</td>
<td>[[${account.firstname}]]</td>
</tr>
<tr>
<td>LastName</td>
<td>[[${account.lastname}]]</td>
</tr>
</table>
<div class=”form”>
<form action=”/” method=”get”>
<table>
<tr>
<td><input type=”submit” value=”Logout”></td>
</tr>
</table>
</form>
</div>
</div>
</div>
</body>
</html>
registration.html
<html xmlns:th=″http://www.thymeleaf.org″>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<title>Application</title>
<link rel=”stylesheet” href=″https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css″>
</head>
<html xmlns:th=″http://www.thymeleaf.org″>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<title>Application</title>
<link rel=”stylesheet” href=″https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css″>
</head>
<body style=”width:50%;margin: 20px;padding: 20px;”>
<h3>Spring MVC Application using Spring Boot and Thymeleaf</h3>
<p style=”color: red;”>[[${errormessage}]]</p>
<div style=”margin: 20px;border: 1px solid blue;padding: 20px;”>
<div class=”form” style=”margin: 20px;padding: 20px;”>
<h4>Registration</h4>
<form action=”createAccount” method=”post”>
<table class=”table table-bordered”>
<tr>
<td>Please Enter Your UserName</td>
<td><input id=”username” name=”username” th:value=”${username}”></td>
</tr>
<tr>
<td>Please Enter Your Password</td>
<td><input id=”password” name=”password” type=”password” th:value=”${password}”></td>
</tr>
<tr>
<td>Please Enter Your Password Again</td>
<td><input id=”againpassword” name=”againpassword” type=”password” th:value=”${againpassword}”></td>
</tr>
<tr>
<td>Please Enter Your First Name</td>
<td><input id=”firstname” name=”firstname” th:value=”${firstname}”></td>
</tr>
<tr>
<td>Please Enter Your last Name</td>
<td><input id=”lastname” name=”lastname” th:value=”${lastname}”></td>
</tr>
</table>
<input type=”submit” value=”Submit”>
</form>
</div>
<div class=”form”>
<form action=”/” method=”get”>
<table>
<tr>
<td><input type=”submit” value=”Go to Login”></td>
</tr>
</table>
</form>
</div>
</div>
</body>
</html>
Running Application
Execute the main method of Application.class and then hit http://localhost:8080
Enter some random values and click on Submit
Enter valid values now and click on Submit
Click on Logout and it will go back to landing page
Registration Flow
Click on Registration Button