SpringBoot CRUD API with JPA and Thymeleaf

in this blog we create spring boot crud operation using @controller annotation and Thymeleaf Template engine. Thymeleaf can work both in web and non-web environments for More Detail

HTTP Method Url Mapping CRUD Action
POST customer/customersave Create a new customer
GET customer/all-customer-list Read a list of customers
GET customer/single-customer-view Read a single customer
POST customer/customersave Update an exiting customer
DELETE customer/delete Delete an existing customer

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.3.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.code4devops</groupId>
	<artifactId>SpringBootRestApiWithHibernate</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SpringBootRestApiWithHibernate</name>
	<description>Spring Boot RestApi With Hibernate</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<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.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
	

Customer.java

	
package com.code4devops.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonFormat;

@Entity
@Table(name = "customer_detail")
public class Customer {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "customer_id", length = 10, nullable = false)
	private int customer_id;
	
	@Column(name = "customer_fname", length = 45, nullable = true)
	private String customer_fname;
	
	@Column(name = "customer_lname", length = 45, nullable = true)
	private String customer_lname;
	
	@Column(name = "customer_mobile", length = 45, nullable = true)
	private String customer_mobile;
	
	@Column(name = "customer_email", length = 45, nullable = true)
	private String customer_email;
	
	@Column(name = "customer_join_date", length = 45, nullable = true)
	@JsonFormat(pattern="yyyy-MM-dd")
    private String customer_join_date; 
	
	public Customer() {}
	
	public Customer(String customer_fname, String customer_lname, String customer_mobile, String customer_email) {
		this.customer_fname = customer_fname;
		this.customer_lname = customer_lname;
		this.customer_mobile = customer_mobile;
		this.customer_email = customer_email;
	}
	
	public int getCustomer_id() {
		return customer_id;
	}

	public void setCustomer_id(int customer_id) {
		this.customer_id = customer_id;
	}

	public String getCustomer_fname() {
		return customer_fname;
	}

	public void setCustomer_fname(String customer_fname) {
		this.customer_fname = customer_fname;
	}

	public String getCustomer_lname() {
		return customer_lname;
	}

	public void setCustomer_lname(String customer_lname) {
		this.customer_lname = customer_lname;
	}

	public String getCustomer_mobile() {
		return customer_mobile;
	}

	public void setCustomer_mobile(String customer_mobile) {
		this.customer_mobile = customer_mobile;
	}

	public String getCustomer_email() {
		return customer_email;
	}

	public void setCustomer_email(String customer_email) {
		this.customer_email = customer_email;
	}

	public String getCustomer_join_date() {
		return customer_join_date;
	}

	public void setCustomer_join_date(String customer_join_date) {
		this.customer_join_date = customer_join_date;
	}

	@Override
	public String toString() {
		return  customer_id + "|" + customer_fname + "|"+ customer_lname + "|" + customer_mobile + "|" + customer_email+ "|" + customer_join_date;
	}
}	
	

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot _build_a_rest_api_with_hibernate?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root

CustomerDataAccessObject.java

package com.code4devops.dao;
import java.util.List;
import com.code4devops.entity.Customer;
public interface CustomerDataAccessObject {
	public abstract List<Customer> findAll();
	public abstract Customer findById(int customerId);
	public abstract void save(Customer customer);
	public abstract void deleteById(int customerId);
	
}

CustomerDataAccessObjectImplementation.java

	
package com.code4devops.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.code4devops.entity.Customer;

@Repository
public class CustomerDataAccessObjectImplementation implements CustomerDataAccessObject{

	@Autowired
	private EntityManager entityManager;
	
	@Override
	public List<Customer> findAll() {
		
		//get the current hibernate session
		Session session=entityManager.unwrap(Session.class);
		
		//create a query
		//table name same as class name here in query it case sensitive
		Query	theQuery=session.createQuery("from Customer", Customer.class);
						
		//execute query and get result list
		List<Customer> customerList= theQuery.getResultList();
						
		//return the results
		return customerList;
	}

	@Override
	public Customer findById(int customerId) {
		
		//get the current hibernate session
		Session session=entityManager.unwrap(Session.class);
		
		//get the Customer Object by customerId
		Customer customer=session.get(Customer.class, customerId);
													
		//return the results
		return customer;
	}

	@Override
	public void save(Customer customer) {
		
		//get the current hibernate session
		Session session=entityManager.unwrap(Session.class);
		
		//Remember One Thing : if id=0 the insert else update
		session.saveOrUpdate(customer);
	}

	@Override
	public void deleteById(int customerId) {
		
		//get the current hibernate session
		Session session=entityManager.unwrap(Session.class);
		
		//delete Object with primary key
		Query theQuery = session.createQuery("delete from Customer where customer_id=:customer_id");
				
		theQuery.setParameter("customer_id", customerId);
				
		theQuery.executeUpdate();
	}
}
	

CustomerService.java


	package com.code4devops.service;
	import java.util.List;
	import com.code4devops.entity.Customer;
	public interface CustomerService {
	
	public abstract List<Customer> findAll();
	public abstract Customer findById(int customerId);
	public abstract void save(Customer Customer);
	public abstract void deleteById(int customerId);
	
	}

CustomerServiceImplementation.java

	
package com.code4devops.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.code4devops.dao.CustomerDataAccessObject;
import com.code4devops.entity.Customer;

@Service
public class CustomerServiceImplementation implements CustomerService{

	@Autowired
	private CustomerDataAccessObject customerDataAccessObject;
		
	@Override
	@Transactional
	public List<Customer> findAll() {
		return customerDataAccessObject.findAll();
	}

	@Override
	@Transactional
	public Customer findById(int customerId) {
		return customerDataAccessObject.findById(customerId);
	}

	@Override
	@Transactional
	public void save(Customer customer) {
		customerDataAccessObject.save(customer);
		
	}

	@Override
	@Transactional
	public void deleteById(int customerId) {
		customerDataAccessObject.deleteById(customerId);
		
	}
}
	
	
	

index.html

<meta http-equiv="refresh" content="0;URL='customer/all-customer-list'">

customer-from.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8">
<title>All Customer List</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<script type="text/javascript" th:src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="#">CRM</a>
    </div>
    <ul class="nav navbar-nav">
      <li class="active"><a th:href="@{/customer/all-customer-list}">Customer List</a></li>
      <li><a th:href="@{/customer/customer-from}">Add Customer</a></li>
    </ul>
    <ul class="nav navbar-nav navbar-right">
      <li><a href="#"><span class="glyphicon glyphicon-user"></span> Sign Up</a></li>
      <li><a href="#"><span class="glyphicon glyphicon-log-in"></span> Login</a></li>
    </ul>
  </div>
</nav>
<div class="container">
<form action="#" th:action="@{customersave}" th:object="" method="post">
<input type="hidden" th:field="*{customer_id}">
<div class="row">
	  <div class="col-sm-6">
	  	<div class="form-group">
	  		<input type="text" th:field="*{customer_fname}"  class="form-control" placeholder="customer first name">
	  	</div>
	  </div>
	  <div class="col-sm-6">
	  	<div class="form-group">
	  		<input type="text" th:field="*{customer_lname}" class="form-control"  placeholder="customer last name">
	  	</div>	
	  </div>
</div>
<div class="row">
	  <div class="col-sm-6">
	  	<div class="form-group">
	  		<input type="text" th:field="*{customer_mobile}" class="form-control"  placeholder="customer mobile">
	  	</div>
	  </div>
	  <div class="col-sm-6">
	  	<div class="form-group">
	  		<input type="text" th:field="*{customer_email}" class="form-control"  placeholder="custome email">
	  	</div>	
	  </div>
</div>
<div class="row">
	  <div class="col-sm-6">
	  	<div class="form-group">
	  		<input type="date" th:field="*{customer_join_date}" class="form-control"  placeholder="customer join date">
	  	</div>	
	  </div>
	  <div class="col-sm-6">
	  	<div class="form-group">
	  		<button type="submit" class="btn btn-primary btn-sm mb-3">SAVE</button>
		</div>
	  </div>
</div>
</form>
</div>
</body>
</html>

customer-list.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8">
<title>All Customer List</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<script type="text/javascript" th:src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="#">CRM</a>
    </div>
    <ul class="nav navbar-nav">
      <li class="active"><a th:href="@{/customer/all-customer-list}">Customer List</a></li>
      <li><a th:href="@{/customer/customer-from}">Add Customer</a></li>
    </ul>
    <ul class="nav navbar-nav navbar-right">
      <li><a href="#"><span class="glyphicon glyphicon-user"></span> Sign Up</a></li>
      <li><a href="#"><span class="glyphicon glyphicon-log-in"></span> Login</a></li>
    </ul>
  </div>
</nav>
<div class="container">
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
	<th>Customer ID</th>
	<th>Customer FName</th>
	<th>customer LName</th>
	<th>Customer Mobile</th>
	<th>Customer Email</th>
	<th>Customer Join Date</th>
	<th>UPdate</th>
</tr>
</thead>
<tr th:each="tempCustomer : ">
<td th:text=""/>
<td th:text=""/>
<td th:text=""/>
<td th:text=""/>
<td th:text=""/>
<td th:text=""/>
<td><a th:href="@{/customer/single-customer-view(customer_id=)}" class="btn btn-primary btn-sm mb-3">Update</a></td>
<td><a th:href="@{/customer/delete(customer_id=)}" class="btn btn-danger btn-sm mb-3"
		   onclick="if(!(confirm('Are you sure you want to delete this custome'))) return false">Delete</a></td>
</tr>	
</table>
<!-- <a th:href="@{/customer/customer-from}" class="btn btn-primary btn-sm mb-3">Add Customer</a> -->
</div>
</body>
</html>

ControllerForCustomer.java


package com.code4devops;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.code4devops.entity.Customer;
import com.code4devops.service.CustomerService;

@Controller
@RequestMapping("customer")
public class ControllerForCustomer {
	
@Autowired
private CustomerService customerService;
		
		
@GetMapping("/all-customer-list")
public String getAllCustomerList(Model model) {
	 List<Customer> list = customerService.findAll();
	 model.addAttribute("customerlist",list);
return "customer-list";
}
				
@GetMapping("/customer-from")
public String getCustomerFrom(Model model) {
	Customer customer=new Customer();
	model.addAttribute("customer",customer);
return "customer-from";
}
		
@PostMapping("/customersave")
public  String getCustomerSave(@ModelAttribute("customer") Customer theCustomer) {
	System.out.println(theCustomer);
	customerService.save(theCustomer);
return "redirect:all-customer-list";
}
				
@GetMapping("/single-customer-view")
public String getSingleCustomerView(@RequestParam("customer_id") int customer_id, Model model) {
	Customer customer= customerService.findById(customer_id);
	model.addAttribute("customer", customer);
return "customer-from";
}
			
@GetMapping("/delete")
public String getEmployee(@RequestParam("customer_id") int customer_id) {
	customerService.deleteById(customer_id);
	return "redirect:all-customer-list";
}
	
}

SpringBootSecurityWithThymleafANDHibernate.java

package com.code4devops;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootSecurityWithThymleafANDHibernate {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootSecurityWithThymleafANDHibernate.class, args);
	}

}