Kotlin +Spring Boot + Mongo DB + Vue.js - CRUD example

Hello everyone, today we will learn how to develop a full-stack web application that is a basic User Management Application using Vue, Kotlin, Spring Boot, and MongoDB.You can download the source code from our GitHub Repository.


After completing this tutorial what we will build? 

We will build a full-stack web application that is a basic User Management Application with CRUD features: 

• Create User 
• List User 
• Update User 
• Delete User 

User Interface -


A quick overview of Vue.js, Kotlin, Spring Boot, and MongoDB 

 Kotlin

Kotlin is a statically typed, general-purpose programming language targeting the Java platform. Kotlin is concise, safe, pragmatic, and fixated on interoperability with Java code. It can be used virtually everywhere Java is utilized today: for server-side development, Android apps, and much more. Kotlin works great with all subsisting Java libraries and frameworks and runs with the same level of performance as Java.

MongoDB

MongoDB is a document database built on a scale-out architecture that has to propagate with developers of all kinds who are building scalable applications utilizing agile methodologies.

MongoDB was built for people who are building internet and business applications who need to evolve expeditiously and scale elegantly. If you are doing that, you should consider MongoDB.

Companies and development teams of all sizes use MongoDB because:
  • The document data model is a potent way to store and retrieve data that sanctions developers to move expeditiously.
  • MongoDB’s horizontal, scale-out architecture can fortify astronomically immense volumes of both data and traffic.
  • MongoDB has a great utilizer experience for developers who can install MongoDB and commence inscribing code immediately.

Vue.js

Vue.js is an open-source model–view–ViewModel front end JavaScript framework for building user interfaces and single-page applications.

Spring Boot

Spring boot to develop REST web services and microservices. Spring Boot has taken the Spring framework to the next level. It has drastically reduced the configuration and setup time required for spring projects. We can set up a project with almost zero configuration and start building the things that actually matter to your application.

We divided this tutorial into two parts

PART 1 - Restful API Development with Kotlin + Spring Boot (back end)
PART 2 - UI development using Vue.js(front end/client)

PART 1 - Restful API Development with Kotlin + Spring Boot 

These are APIs that Spring backend App will export:
  1. GET all User's        :     /api/v1/users
  2.  GET User by ID     :    /api/v1/users/{id} 
  3. POST User             :     /api/v1/users 
  4. PUT User               :     /api/v1/users/{id} 
  5. DELETE User       :     /api/v1/users/{id}

Back end project structure:




pom.xml[Maven]

Include spring-boot-starter-web for Spring MVC and REST structure, spring-boot-starter-data-MongoDB for CRUD repository.
<?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.7.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev</groupId>
<artifactId>springboot_kotlin_crud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_kotlin_crud</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<kotlin.version>1.3.72</kotlin.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb
</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</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>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin
</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin
</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen
</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
 

Creating the User Document:

@Document annotation helps us override the collection name by “users”.
import org.bson.types.ObjectId
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.web.bind.annotation.CrossOrigin

@Document(collection = "users")
data class User(
@Id
var id: String? = ObjectId().toHexString(),
val firstName: String,
val lastName: String,
val emailId: String
)



Creating the Repository:

Let’s now create the repository for accessing the data from the database.
package com.knf.dev.repository

import com.knf.dev.model.User
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.stereotype.Repository

@Repository
interface UserRepository : MongoRepository<User, String>


Creating the Restcontroller 

The @RestController annotation was introduced in Spring 4.0 to simplify the engendering of RESTful web services. It's a convenience annotation that combines @Controller and @ResponseBody.
package com.knf.dev.controller

import com.knf.dev.model.User
import com.knf.dev.repository.UserRepository
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import java.util.*


@RestController
@RequestMapping("/api/v1/")
@CrossOrigin(origins = arrayOf("http://localhost:8080"))
class UserController(private val userRepository: UserRepository) {

@GetMapping("/users")
fun getAllUsers(): List<User> =
userRepository.findAll()

@PostMapping("/users")
fun createNewUser(@RequestBody user: User): User =
userRepository.save(user)

@GetMapping("/users/{id}")
fun getUserById(@PathVariable(value = "id") userId: String):
ResponseEntity<User> {
return userRepository.findById(userId).map { user ->
ResponseEntity.ok(user)
}.orElse(ResponseEntity.notFound().build())
}

@PutMapping("/users/{id}")
fun updateUserById(@PathVariable(value = "id") userId: String,
@RequestBody newUser: User): ResponseEntity<User> {

return userRepository.findById(userId).map { existingUser ->
val updatedUser: User = existingUser
.copy(firstName = newUser.firstName, lastName =
newUser.lastName, emailId = newUser.emailId)
ResponseEntity.ok().body(userRepository.save(updatedUser))
}.orElse(ResponseEntity.notFound().build())

}

@DeleteMapping("/users/{id}")
fun deleteUserById(@PathVariable(value = "id") userId: String):
ResponseEntity<Void> {
return userRepository.findById(userId).map { user ->
userRepository.delete(user)
ResponseEntity<Void>(HttpStatus.OK)
}.orElse(ResponseEntity.notFound().build())

}
}


Main Class

The Spring Boot application's main class contains a public static void main() method that starts up the Spring ApplicationContext.
package com.knf.dev

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class SpringbootKotlinCrudApplication

fun main(args: Array<String>) {
runApplication<SpringbootKotlinCrudApplication>(*args)
}


Github repository download link is provided at the end of this tutorial

Local Setup:

Step 1: Download or clone the source code to a local machine.

Spring Boot - Backend Project Setup

Step 2mvn clean install

Step 3: Run the Spring Boot application
mvn spring-boot:run


PART 2 - UI development using Vue.js

Project Structure:




package.json:

A package.json is a JSON file that subsists at the root of a Javascript/Node project. It holds metadata pertinent to the project and is utilized for managing the project's dependencies, scripts, version, and a whole lot more.
{
"name": "frontend-vuejs",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.18.0",
"vue": "^2.6.6",
"vue-router": "^3.0.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.5.0",
"@vue/cli-plugin-eslint": "^3.5.0",
"@vue/cli-service": "^3.5.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.8.0",
"eslint-plugin-vue": "^5.0.0",
"vue-template-compiler": "^2.5.21"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}


Components:

Vue Components are one of the important features of VueJS that creates custom elements, which can be reused in HTML


User.vue

<template>
<div>
<h3>User</h3>
<div class="container">
<form @submit="validateAndSubmit">
<div v-if="errors.length">
<div
class="alert alert-danger"
v-bind:key="index"
v-for="(error, index) in errors"
>
{{ error }}
</div>
</div>
<fieldset class="form-group">
<label>First Name</label>
<input type="text" class="form-control" v-model="firstName" />
</fieldset>
<fieldset class="form-group">
<label>Last Name</label>
<input type="text" class="form-control" v-model="lastName" />
</fieldset>
<fieldset class="form-group">
<label>Email Id</label>
<input type="text" class="form-control" v-model="emailId" />
</fieldset>
<button class="btn btn-success" type="submit">Save</button>
</form>
</div>
</div>
</template>
<script>
import UserDataService from "../service/UserDataService";

export default {
name: "User",
data() {
return {
firstName: "",
lastName: "",
emailId: "",
errors: [],
};
},
computed: {
id() {
return this.$route.params.id;
},
},
methods: {
refreshUserDetails() {
UserDataService.retrieveUser(this.id).then((res) => {
this.firstName = res.data.firstName;
this.lastName = res.data.lastName;
this.emailId = res.data.emailId;
});
},
validateAndSubmit(e) {
e.preventDefault();
this.errors = [];
if (!this.firstName) {
this.errors.push("Enter valid values");
} else if (this.firstName.length < 5) {
this.errors.push("Enter atleast 5 characters in First Name");
}
if (!this.lastName) {
this.errors.push("Enter valid values");
} else if (this.lastName.length < 5) {
this.errors.push("Enter atleast 5 characters in Last Name");
}
if (this.errors.length === 0) {
if (this.id == -1) {
UserDataService.createUser({
firstName: this.firstName,
lastName: this.lastName,
emailId: this.emailId,
}).then(() => {
this.$router.push("/users");
});
} else {
UserDataService.updateUser(this.id, {
id: this.id,
firstName: this.firstName,
lastName: this.lastName,
emailId: this.emailId,
}).then(() => {
this.$router.push("/users");
});
}
}
},
},
created() {
this.refreshUserDetails();
},
};
</script>


Users.vue
<template>
<div class="container">
<h3>All Users</h3>
<div v-if="message" class="alert alert-success">{{ this.message }}
</div>
<div class="container">
<table class="table">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email Id</th>
<th>Update</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" v-bind:key="user.id">
<td>{{ user.firstName }}</td>
<td>{{ user.lastName }}</td>
<td>{{ user.emailId }}</td>
<td>
<button class="btn btn-warning" v-on:click="updateUser(user.id)">
Update
</button>
</td>
<td>
<button class="btn btn-danger" v-on:click="deleteUser(user.id)">
Delete
</button>
</td>
</tr>
</tbody>
</table>
<div class="row">
<button class="btn btn-success" v-on:click="addUser()">Add</button>
</div>
</div>
</div>
</template>
<script>
import UserDataService from "../service/UserDataService";

export default {
name: "Users",
data() {
return {
users: [],
message: "",
};
},
methods: {
refreshUsers() {
UserDataService.retrieveAllUsers().then((res) => {
this.users = res.data;
});
},
addUser() {
this.$router.push(`/user/-1`);
},
updateUser(id) {
this.$router.push(`/user/${id}`);
},
deleteUser(id) {
UserDataService.deleteUser(id).then(() => {
this.refreshUsers();
});
},
},
created() {
this.refreshUsers();
},
};
</script>


UserDataService.js
import axios from 'axios'

const USER_API_URL = 'http://localhost:9080/api/v1'

class UserDataService {

retrieveAllUsers() {

return axios.get(`${USER_API_URL}/users`);
}

retrieveUser(id) {

return axios.get(`${USER_API_URL}/users/${id}`);
}

deleteUser(id) {

return axios.delete(`${USER_API_URL}/users/${id}`);
}

updateUser(id, user) {

return axios.put(`${USER_API_URL}/users/${id}`, user);
}

createUser(user) {

return axios.post(`${USER_API_URL}/users`, user);
}
}

export default new UserDataService()


App.vue
<template>
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Spring Boot + Mongo DB +
Vue.js CRUD Application</a><br/><br/>
</div>
<router-view/>
</div>
</template>

<script>
export default {
name: "app"
};
</script>

<style>
@import url(https://stackpath.bootstrapcdn.com/bootstrap/4.3.1
/css/bootstrap.min.css);

</style>


routes.js
import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

const router = new Router({
mode: 'history',
routes: [
{
path: "/",
name: "Users",
component: () => import("./components/Users"),
},
{
path: "/users",
name: "Users",
component: () => import("./components/Users"),
},
{
path: "/user/:id",
name: "User",
component: () => import("./components/User"),
},
]
});

export default router;


main.js
import Vue from 'vue'
import App from './App.vue'
import router from './routes';

Vue.config.productionTip = false

new Vue({
router,
render: h => h(App),
}).$mount('#app')



Vue JS - Frontend Project Setup

Step 1: The npm install installs all modules that are listed on package.json file and their
dependencies
npm install
Step 2: Run the Frontend application
npm run serve
 App running at:

git clone:


More Kotlin Examples,

Popular posts from this blog

Spring boot video streaming example-HTML5

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Spring Boot + Mockito simple application with 100% code coverage

Spring Boot + OpenCSV Export Data to CSV Example

Custom Exception Handling in Quarkus REST API

DataTable-Pagination example with Spring boot, jQuery and ajax

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Node JS mini projects with source code - free download

Spring boot web project free download:User Registration System

Java - Blowfish Encryption and decryption Example