Spring Boot + Groovy Templates CRUD Example
Hello everyone, today we will learn how to develop a Spring Boot CRUD web application, using Spring Boot, Groovy template, H2DB, and Spring Data JPA.
The Groovy markup template engine provides an innovative templating system based on the builder syntax.
It offers various key features:
- hierarchical (builder) syntax to generate XML-like contents (in particular, HTML5)
- compilation of templates to bytecode for fast rendering
- internationalization
- layout mechanism for sharing structural patterns
- optional type checking
and more!
Following technologies stack being used:
- Spring Boot 2.5.5
- Spring MVC 5.3.10
- Maven 3
- JDK 11
- Groovy templates 2.5.5
- H2DB
- Bootstrap
Project Structure
Maven[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.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>springjpagroovycrud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springjpagroovycrud</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</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-groovy-templates</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</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 the User Entity
package com.knf.dev.demo.springjpagroovycrud.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String first_name;
@Column(name = "last_name")
private String last_name;
@Column(name = "email", nullable = false, length = 200)
private String email;
public User() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Create User Repository
package com.knf.dev.demo.springjpagroovycrud.repository;
import com.knf.dev.demo.springjpagroovycrud.model.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
}
Create the User Service
package com.knf.dev.demo.springjpagroovycrud.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.knf.dev.demo.springjpagroovycrud.model.User;
import com.knf.dev.demo.springjpagroovycrud.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.persistence.EntityNotFoundException;
@Service
public class UserService {
@Autowired
UserRepository repository;
public List<User> getAllusers() {
List<User> result = (List<User>) repository.findAll();
if (result.size() > 0) {
return result;
} else {
return new ArrayList<User>();
}
}
public User getUserById(Long id) throws EntityNotFoundException {
Optional<User> user = repository.findById(id);
if (user.isPresent()) {
return user.get();
} else {
throw new EntityNotFoundException("No user record exist for given id");
}
}
public User createOrUpdateUser(User entity) {
if (entity.getId() == null) {
entity = repository.save(entity);
return entity;
} else {
Optional<User> user = repository.findById(entity.getId());
if (user.isPresent()) {
User newEntity = user.get();
newEntity.setEmail(entity.getEmail());
newEntity.setFirst_name(entity.getFirst_name());
newEntity.setLast_name(entity.getLast_name());
newEntity = repository.save(newEntity);
return newEntity;
} else {
entity = repository.save(entity);
return entity;
}
}
}
public void deleteUserById(Long id) throws EntityNotFoundException {
Optional<User> user = repository.findById(id);
if (user.isPresent()) {
repository.deleteById(id);
} else {
throw new EntityNotFoundException("No user record exist for given id");
}
}
}
Create the User Controller
package com.knf.dev.demo.springjpagroovycrud.controller;
import com.knf.dev.demo.springjpagroovycrud.model.User;
import com.knf.dev.demo.springjpagroovycrud.service.UserService;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import javax.persistence.EntityNotFoundException;
import java.util.List;
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String getAllUserView(Model model) {
List<User> users = userService.getAllusers();
model.addAttribute("users", users);
return "home";
}
@GetMapping("/create")
public String createUserView(Model model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("create", true);
model.addAttribute("actionUrl", "/create");
return "create-update";
}
@PostMapping("/update/{id}")
public String createUser(@ModelAttribute("user") User user,
@PathVariable("id") Long id) {
user.setId(id);
userService.createOrUpdateUser(user);
return "redirect:/";
}
@GetMapping("/update/{id}")
public String updateUser(Model model, @PathVariable("id") Long id)
throws EntityNotFoundException {
User user = userService.getUserById(id);
model.addAttribute("user", user);
model.addAttribute("create", false);
model.addAttribute("actionUrl",
"/update/" + (user == null ? 0 : user.getId()) );
return "create-update";
}
@PostMapping("/create")
public String createUser(@ModelAttribute("user") User user) {
userService.createOrUpdateUser(user);
return "redirect:/";
}
@GetMapping("/delete/{id}")
public String deleteUser(@PathVariable("id") Long id)
throws EntityNotFoundException {
userService.deleteUserById(id);
return "redirect:/";
}
}
Creating Groovy templates
home.tpl
yieldUnescaped '<!DOCTYPE html>'
html(lang: 'en') {
head {
meta('http-equiv': '"Content-Type" content="text/html; ' +
'charset=utf-8"')
title("Groovy example")
link(rel: "stylesheet", type: "text/css",
href: "https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css")
}
body {
div(class: 'container') {
h2("User CRUD operation with Groovy Template")
div {
nobr {
a(class: 'btn btn-primary', href: "/create", "Add User")
}
}
br()
br()
div {
table(class: 'table') {
tr {
th("Id")
th("First Name")
th("Last Name")
th("Email")
th("")
th("")
}
users.each { user ->
tr {
td("$user.id")
td("$user.first_name")
td("$user.last_name")
td("$user.email")
td {
a(class: 'btn btn-warning',
href: "/update/$user.id", "Edit")
}
td {
a(class: 'btn btn-danger',
href: "/delete/$user.id", "Delete")
}
}
}
}
}
}
}
}
create-update.tpl
yieldUnescaped '<!DOCTYPE html>'
html(lang: 'en') {
head {
meta('http-equiv': '"Content-Type" content="text/html; ' +
'charset=utf-8"')
title("Groovy example")
link(rel: "stylesheet", type: "text/css",
href: "https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css")
}
body {
div(class: 'container') {
if (create) {
h1("Create a User:")
} else {
h1("Edit User")
}
a(class: 'btn btn-primary', href: "/", "Back to User List")
br()
br()
form(id: "editForm", action: "$actionUrl", method: "POST") {
table(class: 'table') {
if (!create) {
tr {
td("Id")
td(":")
td(user.id ?: '')
}
}
tr {
td("First Name")
td(":")
td {
input(name: 'first_name', type: 'text',
value: user.last_name ?: '')
}
}
tr {
td("Last Name")
td(":")
td {
input(name: 'last_name', type: 'text',
value: user.last_name ?: '')
}
}
tr {
td("Email")
td(":")
td {
input(name: 'email', type: 'text',
value: user.email ?: '')
}
}
}
br()
if (create) {
input(class: 'btn btn-success', type: 'submit',
value: 'Create')
} else {
input(class: 'btn btn-success', type: 'submit',
value: 'Update')
}
}
}
}
}
Spring Boot Main Driver
package com.knf.dev.demo.springjpagroovycrud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringjpagroovycrudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringjpagroovycrudApplication.class, args);
}
}
Download the complete source code - click here
Local Setup and Run the application
Step1: Download or clone the source code from GitHub to the local machine - Click here
Step 2: mvn clean install
Step 3: Run the Spring Boot application - mvn spring-boot:run
Step1: Download or clone the source code from GitHub to the local machine - Click here
Step 2: mvn clean install
Step 3: Run the Spring Boot application - mvn spring-boot:run