Kotlin + Spring + Groovy Templates CRUD Example
Hello everyone, Today we will learn how to develop a Spring Boot CRUD web application, using Kotlin, Spring Boot, Groovy template, H2DB, and JPA.
Following technologies stack being used:
- Spring Boot 2.5.5
- Spring MVC 5.3.10
- Gradle
- Kotlin
- Groovy templates 2.5.5
- H2DB
- Bootstrap
Project Structure:
Project Dependency(build.gradle.kts)
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.5.5"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.5.31"
kotlin("plugin.spring") version "1.5.31"
kotlin("plugin.jpa") version "1.5.31"
}
group = "com.knf.dev.demo"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-groovy-templates")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
runtimeOnly("com.h2database:h2")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
Configure the Entity class
package com.knf.dev.demo.kotlinspringbootcrudexample.model
import javax.persistence.*
@Entity
@Table(name = "user")
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null
@Column(name = "first_name")
var first_name: String? = null
@Column(name = "last_name")
var last_name: String? = null
@Column(name = "email", nullable = false, length = 200)
var email: String? = null
}
Create CRUD Repository
package com.knf.dev.demo.kotlinspringbootcrudexample.repository
import com.knf.dev.demo.kotlinspringbootcrudexample.model.User
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
@Repository
interface UserRepository : CrudRepository<User?, Long?>
Create the Service class
package com.knf.dev.demo.kotlinspringbootcrudexample.service
import com.knf.dev.demo.kotlinspringbootcrudexample.model.User
import org.springframework.beans.factory.annotation.Autowired
import com.knf.dev.demo.kotlinspringbootcrudexample.repository.UserRepository
import org.springframework.stereotype.Service
import java.util.ArrayList
import kotlin.Throws
import javax.persistence.EntityNotFoundException
@Service
class UserService {
@Autowired
var repository: UserRepository? = null
val allusers: List<User?>
get() {
val result = repository!!.findAll() as List<User?>
return if (result.size > 0) {
result
} else {
ArrayList()
}
}
@Throws(EntityNotFoundException::class)
fun getUserById(id: Long): User {
val user = repository!!.findById(id)
return if (user.isPresent) {
user.get()
} else {
throw EntityNotFoundException("No user record exist for given id")
}
}
fun createOrUpdateUser(entity: User): User {
var entity = entity
return if (entity.id == null) {
entity = repository!!.save(entity)
entity
} else {
val user = repository!!.findById(
entity.id!!
)
if (user.isPresent) {
var newEntity = user.get()
newEntity.email = entity.email
newEntity.first_name = entity.first_name
newEntity.last_name = entity.last_name
newEntity = repository!!.save(newEntity)
newEntity
} else {
entity = repository!!.save(entity)
entity
}
}
}
@Throws(EntityNotFoundException::class)
fun deleteUserById(id: Long) {
val user = repository!!.findById(id)
if (user.isPresent) {
repository!!.deleteById(id)
} else {
throw EntityNotFoundException("No user record exist for given id")
}
}
}
Create the Web Controller class
package com.knf.dev.demo.kotlinspringbootcrudexample.controller
import com.knf.dev.demo.kotlinspringbootcrudexample.model.User
import org.springframework.beans.factory.annotation.Autowired
import com.knf.dev.demo.kotlinspringbootcrudexample.service.UserService
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PathVariable
import kotlin.Throws
import javax.persistence.EntityNotFoundException
@Controller
class UserController {
@Autowired
private val userService: UserService? = null
@GetMapping("/")
fun getAllUserView(model: Model): String {
val users = userService!!.allusers
model.addAttribute("users", users)
return "home"
}
@GetMapping("/create")
fun createUserView(model: Model): String {
val user = User()
model.addAttribute("user", user)
model.addAttribute("create", true)
model.addAttribute("actionUrl", "/create")
return "create-update"
}
@PostMapping("/update/{id}")
fun createUser(
@ModelAttribute("user") user: User,
@PathVariable("id") id: Long?
): String {
user.id = id
userService!!.createOrUpdateUser(user)
return "redirect:/"
}
@GetMapping("/update/{id}")
@Throws(EntityNotFoundException::class)
fun updateUser(model: Model, @PathVariable("id") id: Long?):
String {
val user = userService!!.getUserById(id!!)
model.addAttribute("user", user)
model.addAttribute("create", false)
model.addAttribute(
"actionUrl",
"/update/" + if (user == null) 0 else user.id
)
return "create-update"
}
@PostMapping("/create")
fun createUser(@ModelAttribute("user") user: User?): String {
userService!!.createOrUpdateUser(user!!)
return "redirect:/"
}
@GetMapping("/delete/{id}")
@Throws(EntityNotFoundException::class)
fun deleteUser(@PathVariable("id") id: Long?): String {
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 Class
package com.knf.dev.demo.kotlinspringbootcrudexample
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class KotlinspringbootcrudexampleApplication
fun main(args: Array<String>) {
runApplication<KotlinspringbootcrudexampleApplication>(*args)
}
Run
Start Spring Boot: gradle bootRun.
Access the URL in the browser: http://localhost:8080/
Create User:
Update User:
Download the source code:
More related topics ...