Hey learners, in this post we will learn spring boot project full tutorial step by step. We will develop Enotes project using java spring boot technology. i will share your full source code with full tutorial video.
Spring Boot Project Prerequisite
In this project i will used Spring boot, Data JPA, Lambok, Hibernate, Thymeleaf, html, css and spring tool suite IDE, Mysql database using workbench .
Guys you should know this concept, if you have little bit knowledge you can follow it , i explained step by step everything you can follow video also.
Spring Boot Enotes Project Full tutorial video
Project Structure

Enotes Spring boot Project Source Code
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.6.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.enotes</groupId>
<artifactId>SBT-Enotes</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SBT-Enotes</name>
<description>Enotes Spring boot Project</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-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/yt_enotes
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
SbtEnotesApplication.java
package com.enotes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
@EnableJpaAuditing
public class SbtEnotesApplication {
public static void main(String[] args) {
SpringApplication.run(SbtEnotesApplication.class, args);
}
}
CustomUserDtls.java
package com.enotes.config;
import java.util.Arrays;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.enotes.entity.UserDtls;
public class CustomUserDtls implements UserDetails {
private UserDtls userdtls;
public CustomUserDtls(UserDtls userdtls) {
super();
this.userdtls = userdtls;
}
public CustomUserDtls() {
// TODO Auto-generated constructor stub
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(userdtls.getRole());
return Arrays.asList(simpleGrantedAuthority);
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return userdtls.getPassword();
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return userdtls.getEmail();
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
}
SecurityConfig.java
package com.enotes.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService getUserDetailsService() {
return new UserDetailsServiceImpl();
}
@Bean
public DaoAuthenticationProvider getDaoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(getUserDetailsService());
daoAuthenticationProvider.setPasswordEncoder(getPasswordEncoder());
return daoAuthenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getDaoAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER")
.antMatchers("/**").permitAll().and().formLogin().loginPage("/login").loginProcessingUrl("/login")
.defaultSuccessUrl("/user/addNotes").and().csrf().disable();
}
}
UserDetailsServiceImpl.java
package com.enotes.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.enotes.entity.UserDtls;
import com.enotes.repository.UserRepository;
public class UserDetailsServiceImpl implements UserDetailsService{
@Autowired
private UserRepository userRepo;
public UserDetailsServiceImpl() {
// TODO Auto-generated constructor stub
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDtls user=userRepo.findByEmail(username);
if(user==null)
{
throw new UsernameNotFoundException("User Not Exist");
}else
{
CustomUserDtls customUserDtls =new CustomUserDtls(user);
return customUserDtls;
}
}
}
HomeController.java
package com.enotes.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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 com.enotes.entity.UserDtls;
import com.enotes.repository.UserRepository;
@Controller
public class HomeController {
@Autowired
private BCryptPasswordEncoder passwordEncode;
@Autowired
private UserRepository userRepo;
@GetMapping("/")
public String home() {
return "home";
}
@GetMapping("/login")
public String login() {
return "login";
}
@GetMapping("/signup")
public String signup() {
return "signup";
}
@PostMapping("/saveUser")
public String saveUser(@ModelAttribute UserDtls user, Model m, HttpSession session) {
user.setPassword(passwordEncode.encode(user.getPassword()));
user.setRole("ROLE_USER");
UserDtls u = userRepo.save(user);
if (u != null) {
session.setAttribute("msg", "Register Sucessfully");
} else {
session.setAttribute("msg", "Something wrong on server");
}
return "redirect:/signup";
}
}
UserController.java
package com.enotes.controller;
import java.security.Principal;
import java.util.Optional;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.enotes.entity.Notes;
import com.enotes.entity.UserDtls;
import com.enotes.repository.NotesRepository;
import com.enotes.repository.UserRepository;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserRepository userRepository;
@Autowired
private NotesRepository notesRepository;
@ModelAttribute
public void addCommnData(Principal p, Model m) {
String email = p.getName();
UserDtls user = userRepository.findByEmail(email);
m.addAttribute("user", user);
}
@GetMapping("/addNotes")
public String home() {
return "user/add_notes";
}
@GetMapping("/viewNotes/{page}")
public String viewNotes(@PathVariable int page, Model m, Principal p) {
String email = p.getName();
UserDtls user = userRepository.findByEmail(email);
Pageable pageable = PageRequest.of(page, 5, Sort.by("id").descending());
Page<Notes> notes = notesRepository.findyNotesByUser(user.getId(), pageable);
m.addAttribute("pageNo", page);
m.addAttribute("totalPage", notes.getTotalPages());
m.addAttribute("Notes", notes);
m.addAttribute("totalElement", notes.getTotalElements());
return "user/view_notes";
}
@GetMapping("/editNotes/{id}")
public String editNotes(@PathVariable int id, Model m) {
Optional<Notes> n = notesRepository.findById(id);
if (n != null) {
Notes notes = n.get();
m.addAttribute("notes", notes);
}
return "user/edit_notes";
}
@PostMapping("/updateNotes")
public String updateNotes(@ModelAttribute Notes notes, HttpSession session, Principal p) {
String email = p.getName();
UserDtls user = userRepository.findByEmail(email);
notes.setUserDtls(user);
Notes updateNotes = notesRepository.save(notes);
if (updateNotes != null) {
session.setAttribute("msg", "Notes Update Sucessfully");
} else {
session.setAttribute("msg", "Something wrong on server");
}
System.out.println(notes);
return "redirect:/user/viewNotes/0";
}
@GetMapping("/deleteNotes/{id}")
public String deleteNotes(@PathVariable int id,HttpSession session) {
Optional<Notes> notes=notesRepository.findById(id);
if(notes!=null)
{
notesRepository.delete(notes.get());
session.setAttribute("msg", "Notes Delete Successfully");
}
return "redirect:/user/viewNotes/0";
}
@GetMapping("/viewProfile")
public String viewProfile() {
return "user/view_profile";
}
@PostMapping("/saveNotes")
public String saveNotes(@ModelAttribute Notes notes, HttpSession session, Principal p) {
String email = p.getName();
UserDtls u = userRepository.findByEmail(email);
notes.setUserDtls(u);
Notes n = notesRepository.save(notes);
if (n != null) {
session.setAttribute("msg", "Notes Added Sucessfully");
} else {
session.setAttribute("msg", "Something wrong on server");
}
return "redirect:/user/addNotes";
}
@PostMapping("/updateUser")
public String updateUser(@ModelAttribute UserDtls user,HttpSession session,Model m)
{
Optional<UserDtls> Olduser=userRepository.findById(user.getId());
if(Olduser!=null)
{
user.setPassword(Olduser.get().getPassword());
user.setRole(Olduser.get().getRole());
user.setEmail(Olduser.get().getEmail());
UserDtls updateUser=userRepository.save(user);
if(updateUser!=null)
{
m.addAttribute("user",updateUser);
session.setAttribute("msg", "Profile Update Sucessfully..");
}
}
return "redirect:/user/viewProfile";
}
}
Audit.java
package com.enotes.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.auditing.config.AuditingConfiguration;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Audit {
@Temporal(TemporalType.DATE)
@CreatedDate
@Column(name = "create_dt",nullable = false,updatable = false)
private Date cratedDate;
@Temporal(TemporalType.DATE)
@LastModifiedDate
@Column(name = "update_dt",nullable = false)
private Date updateDate;
}
Notes.java
package com.enotes.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import lombok.Data;
@Data
@Entity
@Table(name = "notes")
public class Notes extends Audit {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private UserDtls userDtls;
public Notes() {
// TODO Auto-generated constructor stub
}
}
UserDtls.java
package com.enotes.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Data;
@Data
@Entity
public class UserDtls {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "full_name")
private String name;
private String email;
private String password;
private String about;
private String role;
public UserDtls() {
// TODO Auto-generated constructor stub
}
}
NotesRepository.java
package com.enotes.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.enotes.entity.Notes;
public interface NotesRepository extends JpaRepository<Notes, Integer>{
@Query("from Notes as n where n.userDtls.id=:uid")
Page<Notes> findyNotesByUser(@Param("uid") int uid,Pageable p);
}
UserRepository.java
package com.enotes.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.enotes.entity.UserDtls;
public interface UserRepository extends JpaRepository<UserDtls,Integer>{
public UserDtls findByEmail(String email);
}
Frontend Code
style.css
.backimg {
background: url("../img/notes.jpg");
height: 100%;
width: 100%;
background-repeat: no-repeat;
position: fixed;
background-size: cover;
}
.navbar .nav-item .nav-link {
font-size: 20px;
color: white;
}
.navbar .nav-item:hover .nav-link {
background: white;
color: black;
border-radius: 10px;
}
User Folder Html Code
add_notes.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="user/base::layout(~{::section})">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<section>
<div class="container-fluid p-3">
<div class="col-md-10 offset-md-1">
<div class="card paint-card">
<h3 class="text-center">Add Notes</h3>
<div th:if="${session.msg}" class="text-center" role="alert">
<h4 class="text-success" th:text="${session.msg}"></h4>
<th:block th:text="${#session.removeAttribute('msg')}"></th:block>
</div>
<div class="card-body">
<form th:action="@{/user/saveNotes}" method="post">
<div class="form-group">
<label>Enter Title</label> <input type="text"
class="form-control" name="title">
</div>
<div class="form-group">
<label>Enter Description</label>
<textarea rows="12" cols="" name="content" class="form-control"></textarea>
</div>
<div class="text-center">
<button class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
base.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.com"
th:fragment="layout(content)">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<title>Base</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
<style type="text/css">
.paint-card {
box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.3);
}
</style>
</head>
<body>
<!-- Start Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-success">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}"><i class="fas fa-book"></i>
Enotes</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item"><a class="nav-link active"
aria-current="page" th:href="@{/user/addNotes}"> Add Notes</a></li>
<li class="nav-item"><a class="nav-link active"
aria-current="page" th:href="@{/user/viewNotes/0}">View Notes</a></li>
</ul>
<form class="d-flex">
<a th:href="@{/user/viewProfile}" class="btn btn-light"><i
class="fas fa-user-circle"></i> [[${user.name}]]</a>
<a th:href="@{/logout}"
class="btn btn-light ms-2"><i class="fas fa-sign-in-alt"></i>
Logout</a>
</form>
</div>
</div>
</nav>
<!--End Navbar -->
<div th:replace="${content}"></div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous">
</script>
</body>
</html>
edit_notes.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="user/base::layout(~{::section})">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<section>
<div class="container-fluid p-3">
<div class="col-md-10 offset-md-1">
<div class="card paint-card">
<h3 class="text-center">Edit Notes</h3>
<!-- <div th:if="${session.message}"
th:classappend="${session.message.type}" class="text-center"
role="alert">
<h4 th:text="${session.message.content}"></h4>
<th:block th:text="${#session.removeAttribute('message')}"></th:block>
</div> -->
<div class="card-body">
<form th:action="@{/user/updateNotes}" method="post">
<div class="form-group">
<label>Enter Title</label> <input type="text" th:value="${notes.title}"
class="form-control" name="title">
</div>
<div class="form-group">
<label>Enter Description</label>
<textarea rows="12" cols="" name="content" th:value="${notes.content}"
class="form-control">[[${notes.content}]]</textarea>
</div>
<input type="hidden" th:value="${notes.id}" name="id">
<div class="text-center">
<button class="btn btn-primary">Update</button>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
view_notes.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="user/base::layout(~{::section})">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<section>
<div class="container">
<h3 class="text-center">Notes</h3>
<div th:if="${session.msg}"
class="text-center"
role="alert">
<h4 th:text="${session.msg}"></h4>
<th:block th:text="${#session.removeAttribute('msg')}"></th:block>
</div>
<div class="col-md-12 mt-3" th:each="n:${Notes}">
<div class="card paint-card">
<div class="card-body">
<div class="text-center">
<img alt="" th:src="@{/img/paper.png}"
style="width: 50px; height: 50px;">
</div>
<h5>[[${n.title}]]</h5>
<p>
[[${n.content}]] <br> <br> <span class="font-weight-bold">Upload
Date :</span> [[${n.updateDate}]]
</p>
<div class="text-center">
<a th:href="@{'/user/editNotes/'+${n.id}}" class="btn btn-primary btn-sm">Edit</a>
<a
th:href="@{'/user/deleteNotes/'+${n.id}}" class="btn btn-danger btn-sm ml-2">Delete</a>
</div>
</div>
</div>
</div>
<div class="row p-4">
<div class="col-md-4">Total Elements : [[${totalElement}]]</div>
<div class="col-md-6">
<nav aria-label="Page navigation example">
<ul class="pagination">
<li th:classappend="${pageNo==0} ? 'disabled':'' " class="page-item">
<a class="page-link" th:href="@{'/user/viewNotes/'+${pageNo-1} }"
aria-label="Previous"> <span aria-hidden="true">«</span>
</a>
</li>
<li th:each="i:${#numbers.sequence(1,totalPage)}" th:classappend="${pageNo+1==i}?'active':''" class="page-item">
<a th:href="@{'/user/viewNotes/' +${i-1} }" class="page-link" href="#">[[${i}]]</a>
</li>
<li th:classapppend="${pageNo+1==totalPage} ? 'disabled' : '' " class="page-item">
<a class="page-link" th:href="@{'/user/viewNotes/'+${pageNo+1}}"
aria-label="Next"> <span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</section>
</body>
</html>
view_profile.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="user/base::layout(~{::section})">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<section>
<div class="container p-5">
<div class="row">
<div class="col-md-4">
<div class="card paint-card">
<div class="card-body">
<form th:action="@{/saveUser}" method="post">
<p class="fs-4 text-center">View Profile</p>
<div class="form-group mt-2">
<label> Name</label> <input type="text" name="name"
th:value="${user.name}" readonly class="form-control"
required="required">
</div>
<div class="form-group mt-2">
<label> Email</label> <input type="email" name="email"
th:value="${user.email}" readonly class="form-control"
required="required">
</div>
<div class="form-group mt-2">
<textarea rows="3" cols="" class="form-control" name="about"
th:value="${user.about}" readonly placeholder="Enter About">[[${user.about}]]</textarea>
</div>
</form>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card paint-card">
<div class="card-body">
<form th:action="@{/user/updateUser}" method="post">
<p class="fs-4 text-center">Edit Profile</p>
<div th:if="${session.msg}" class="text-center" role="alert">
<h4 class="text-success" th:text="${session.msg}"></h4>
<th:block th:text="${#session.removeAttribute('msg')}"></th:block>
</div>
<div class="form-group mt-2">
<label>Enter Name</label> <input type="text" name="name"
th:value="${user.name}" class="form-control"
required="required">
</div>
<div class="form-group mt-2">
<label>Enter Email</label> <input type="email" name="email"
th:value="${user.email}" readonly class="form-control"
required="required">
</div>
<div class="form-group mt-2">
<textarea rows="3" cols="" class="form-control" name="about"
placeholder="Enter About">[[${user.about}]]</textarea>
</div>
<input type="hidden" name="id" th:value="${user.id}">
<div class="text-center mt-3">
<button class="btn bg-primary text-white">Update</button>
<button type="reset" class="btn btn-primary text-white">Reset</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
Outside User Folder html Code
base.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.com"
th:fragment="layout(content)">
<head>
<meta charset="ISO-8859-1">
<title>Base Page</title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" th:href="@{/css/style.css}">
<style type="text/css">
.paint-card {
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.3);
}
</style>
</head>
<body>
<!-- Start Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-success">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}"><i class="fas fa-book"></i> Enotes</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item"><a class="nav-link active"
aria-current="page" th:href="@{/}"><i class="fas fa-home"></i> Home</a></li>
</ul>
<form class="d-flex">
<a th:href="@{login}" class="btn btn-light"><i class="fas fa-sign-in-alt"></i> Login</a> <a
th:href="@{signup}" class="btn btn-light ms-2"><i class="fas fa-user-plus"></i> Signup</a>
</form>
</div>
</div>
</nav>
<!--End Navabar -->
<div th:replace="${content}"></div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
</body>
</html>
home.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="base::layout(~{::section})">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<section>
<div class="backimg">
<div class="text-white text-center">
<h1>ENotes- Save Notes</h1>
<p>Start Collecting your Notes in very smarter way .We provied
very difficult and smarter way of handling Notes</p>
<button class="btn bg-primary text-white">Get Start</button>
</div>
</div>
</section>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="base::layout(~{::section})">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<section>
<div class="container p-5">
<div class="row">
<div class="col-md-6 offset-md-3">
<div class="card paint-card">
<div class="card-body">
<h4 class="form-signin-heading text-center">Sign in</h4>
<form class="form-signin" method="post" th:action="@{/login}">
<div th:if="${param.error}" class="alert alert-danger">
Invalid username & Password</div>
<div th:if="${param.logout}" class="alert alert-success">
Logout Sucessfully</div>
<div class="form-group">
<label>Email</label> <input type="text" id="username"
name="username" class="form-control" required autofocus>
</div>
<div class="form-group mt-2">
<label>Password</label> <input type="password" id="password"
name="password" class="form-control" required>
</div>
<button class="btn btn-primary col-md-12 mt-3" type="submit">Sign
in</button>
<div class="text-center">
<a href="/signup">Create Account</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
signup.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="base::layout(~{::section})">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<section>
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<div class="card mt-2 paint-card">
<h1 class="text-center">Register Here</h1>
<!--alert message -->
<div th:if="${session.msg}"
class="text-center">
<h4 class="text-success" th:text="${session.msg}"></h4>
<th:block th:text="${#session.removeAttribute('msg')}"></th:block>
</div>
<!--alert message -->
<div class="card-body">
<form th:action="@{/saveUser}" method="post">
<div class="form-group mt-2">
<label>Enter Name</label> <input type="text" name="name"
class="form-control" required="required">
</div>
<div class="form-group mt-2">
<label>Enter Email</label> <input type="email" name="email"
class="form-control" required="required">
</div>
<div class="form-group mt-2">
<label>Enter Password</label> <input type="password"
name="password" class="form-control" required="required">
</div>
<div class="form-group mt-2">
<textarea rows="3" cols="" class="form-control" name="about"
placeholder="Enter About"></textarea>
</div>
<div class="text-center mt-3">
<button class="btn bg-primary text-white">Submit</button>
<button type="reset" class="btn btn-primary text-white">Reset</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
you great
very useful brother. really appreciate it 🙂