Quarkus + Vue.js + MongoDB CRUD Example

Hello everyone, today we will learn how to develop a full-stack web application that is a basic User Management Application using Quarkus, Vue.js and MongoDB.
GitHub repository link is provided at the end of this tutorial. You can download the source code.


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

-Add User:

-Retrieve all Users:

-Update User:

We divided this tutorial into two parts. 

PART 1 - Rest APIs Development using Quarkus
PART 2 - UI development using Vue.js

 PART 1 - Rest APIs Development using Quarkus 

Project Directory:



Maven[pom.xml]

A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details utilized by Maven to build the project. It contains default values for most projects. Some of the configurations that can be designated in the POM is the project dependencies, the plugins or goals that can be executed, the build profiles, and so on. Other information such as the project version, description, developers, mailing lists and such can withal be designated.
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.knf.dev</groupId>
<artifactId>quarkus-mongo-panache-crud</artifactId>
<version>1.0</version>

<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8
</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8
</project.reporting.outputEncoding>
<quarkus-plugin.version>2.2.3.Final
</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom
</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus
</quarkus.platform.group-id>
<quarkus.platform.version>2.2.3.Final
</quarkus.platform.version>
<surefire-plugin.version>2.22.1
</surefire-plugin.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}
</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mongodb-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemProperties>
<java.util.logging.manager>
org.jboss.logmanager.LogManager
</java.util.logging.manager>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemProperties>
<native.image.path>
${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>


application.properties
quarkus.mongodb.connection-string = mongodb://localhost:27017
quarkus.mongodb.database = test-user-data
quarkus.http.cors=true
quarkus.http.cors.origins=http://localhost:8080
quarkus.http.cors.methods=GET,PUT,POST,DELETE
quarkus.http.port=8081



Create Document - User.java
package com.knf.dev.model;

import io.quarkus.mongodb.panache.PanacheMongoEntity;
import org.bson.types.ObjectId;

public class User {

public ObjectId id;
private String firstName;
private String lastName;
private String emailId;

public ObjectId getId() {
return id;
}

public void setId(ObjectId id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmailId() {
return emailId;
}

public void setEmailId(String emailId) {
this.emailId = emailId;
}

public User(ObjectId id, String firstName,
                  String lastName, String emailId) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.emailId = emailId;
}

public User() {
super();
}
}


Create UserRepository.java
package com.knf.dev.repository;

import com.knf.dev.model.User;
import io.quarkus.mongodb.panache.PanacheMongoRepository;
import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class UserRepository implements PanacheMongoRepository<User> {

}


Create UserController.java
package com.knf.dev.controller;

import com.knf.dev.model.User;
import com.knf.dev.repository.UserRepository;
import io.quarkus.mongodb.panache.PanacheQuery;
import org.bson.types.ObjectId;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;

@Path("/api/users")
public class UserController {

private final UserRepository userRepository;

@Inject
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}

@GET
public List<User> getUsers() {
return userRepository.listAll();
}

@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public User getUser
(@PathParam("id") String id) {
return userRepository.findById(new ObjectId(id));
}

@PUT
@Path("/{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public void updateUser
(@PathParam("id") String id, User user) {
user.setId(new ObjectId(id));
userRepository.update(user);
}

@POST
public Response addUser(User user) {
userRepository.persist(user);
return Response.status(Response.Status.CREATED).build();
}

@DELETE
@Path("/{id}")
public void deleteUser(@PathParam("id") String id) {
User user = userRepository.findById(new ObjectId(id));
userRepository.delete(user);
}
}


Run the Quarkus Application

Build application  jar file: 
mvn clean package

Start the application: 

java -jar quarkus-run.jar



PART 2 - UI Development using Vue.js


Package structure - Front end



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:8081/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="#"> Quarkus + 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;


vue.config.js
module.exports = {
devServer: {
port: 8080
}
}


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')


index.html
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>Quarkus-vuejs-mongodb-crud</title>
</head>

<body>
<noscript>
<strong>We're sorry but Quarkus-vuejs-crud
doesn't work properly without JavaScript enabled. Please
enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>


## Project setup
npm install

### Run the application in local
npm run serve

 App running at - Local:http://localhost:8080/ 





More Quarkus Related topics,

Popular posts from this blog

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

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Spring Boot + Mockito simple application with 100% code coverage

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete