Micronaut + 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 Micronaut, 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
Add User:
View All Users:
Update User:
We divided this tutorial into two parts.
PART 1 - Rest APIs Development using Micronaut
PART 2 - UI development using Vue.js
PART 1 - Rest APIs Development using Micronaut
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.demo</groupId> <artifactId>micronaut-mongodb-crud</artifactId> <version>0.1</version> <packaging>${packaging}</packaging>
<parent> <groupId>io.micronaut</groupId> <artifactId>micronaut-parent</artifactId> <version>3.1.1</version> </parent>
<properties> <packaging>jar</packaging> <jdk.version>11</jdk.version> <release.version>11</release.version> <micronaut.version>3.1.1</micronaut.version> <exec.mainClass>com.knf.dev.demo.Application </exec.mainClass> <micronaut.runtime>netty</micronaut.runtime> </properties>
<repositories> <repository> <id>central</id> <url>https://repo.maven.apache.org/maven2</url> </repository> </repositories>
<dependencies> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-inject</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-validation</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-http-server-netty</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-http-client</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-runtime</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut.mongodb</groupId> <artifactId>micronaut-mongo-sync</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micronaut.test</groupId> <artifactId>micronaut-test-junit5</artifactId> <scope>test</scope> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>io.micronaut.build</groupId> <artifactId>micronaut-maven-plugin</artifactId> </plugin>
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>io.micronaut</groupId> <artifactId>micronaut-inject-java</artifactId> <version>${micronaut.version}</version> </path> <path> <groupId>io.micronaut</groupId> <artifactId>micronaut-validation</artifactId> <version>${micronaut.version}</version> </path> </annotationProcessorPaths> <compilerArgs> <arg>-Amicronaut.processing.group=com.knf.dev.demo</arg> <arg>-Amicronaut.processing.module=micronaut-mongodb-crud</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
</project>application.yaml
micronaut: application: name: micronautMongodbCrudmongodb.uri: mongodb://localhost:27017
micronaut: server: port: 8081 cors: enabled: true configurations: web: allowedOrigins: - http://localhost:8080Create Document - User.java
package com.knf.dev.demo.entity;
import io.micronaut.core.annotation.Introspected;
@Introspectedpublic class User { private String id; private String firstName; private String lastName; private String emailId;
public String getId() { return id; }
public void setId(String 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(String id, String firstName, String lastName, String emailId) { super(); this.id = id; this.firstName = firstName; this.lastName = lastName; this.emailId = emailId; }
public User() { super(); }}Create UserRepository.java
package com.knf.dev.demo.repository.impl;
import java.util.ArrayList;import java.util.List;import java.util.Optional;import org.bson.Document;import org.bson.conversions.Bson;import org.bson.types.ObjectId;import com.knf.dev.demo.entity.User;import com.mongodb.client.MongoClient;import com.mongodb.client.MongoCollection;import com.mongodb.client.MongoCursor;import com.mongodb.client.model.Filters;import jakarta.inject.Singleton;
@Singletonpublic class UserRepository {
private final MongoClient mongoClient;
public UserRepository(MongoClient mongoClient) {
this.mongoClient = mongoClient; }
private MongoCollection<Document> getCollection() {
return mongoClient.getDatabase("user-test"). getCollection("user-test"); }
public User saveUser(User user) {
Document document = new Document(). append("firstName", user.getFirstName()) .append("lastName", user.getLastName()). append("emailId", user.getEmailId()); getCollection().insertOne(document); user.setId(document.getObjectId("_id").toString()); return user; }
public User updateUser(String id, User user) { Optional<Document> optionalDocument = findDocumentById(id); if (optionalDocument.isPresent()) { Document document = optionalDocument.get(); document.put("firstName", user.getFirstName()); document.put("lastName", user.getLastName()); document.put("emailId", user.getEmailId()); Bson bsonFilter = Filters.eq("_id", new ObjectId(id)); getCollection().replaceOne(bsonFilter, document); } return user; }
public List<User> findAll() {
List<User> users = new ArrayList<>(); MongoCursor<Document> cursor = getCollection(). find().iterator();
try { while (cursor.hasNext()) { Document document = cursor.next(); User user = new User(); user.setLastName(document.getString("lastName")); user.setFirstName(document.getString("firstName")); user.setEmailId(document.getString("emailId")); user.setId(String. valueOf(document.getObjectId("_id"))); users.add(user); } } finally { cursor.close(); } return users; }
public Optional<User> findUserById(String id) { return findDocumentById(id).map(this::mapUser); }
public void deleteUserById(String id) { Bson bsonFilter = Filters.eq("_id", new ObjectId(id)); getCollection().deleteOne(bsonFilter); }
private Optional<Document> findDocumentById(String id) { Bson bsonFilter = Filters.eq("_id", new ObjectId(id)); try (MongoCursor<Document> iterator = getCollection(). find(bsonFilter).iterator()) { return iterator.hasNext() ? Optional. of(iterator.next()) : Optional.empty(); } }
private User mapUser(Document document) { User user = new User(); user.setId(document.getObjectId("_id").toString()); user.setEmailId(document.getString("emailId")); user.setLastName(document.getString("lastName")); user.setFirstName(document.getString("firstName")); return user; }}Create UserController.java
package com.knf.dev.demo.contoller;
import java.util.List;import java.util.Optional;import com.knf.dev.demo.entity.User;import com.knf.dev.demo.repository.impl.UserRepository;import io.micronaut.http.HttpResponse;import io.micronaut.http.annotation.Body;import io.micronaut.http.annotation.Controller;import io.micronaut.http.annotation.Delete;import io.micronaut.http.annotation.Get;import io.micronaut.http.annotation.Post;import io.micronaut.http.annotation.Put;import jakarta.inject.Inject;
@Controller("/api/v1/users")public class UserController {
@Inject UserRepository userRepository;
@Get public List<User> getUsers() {
return userRepository.findAll(); }
@Get("/{id}") public Optional<User> getUser(String id) {
return userRepository.findUserById(id); }
@Post public HttpResponse<User> addUser(@Body User user) {
userRepository.saveUser(user); return HttpResponse.created(user); }
@Put("/{id}") public HttpResponse<User> updateUser(String id, @Body User user) {
userRepository.updateUser(id, user); return HttpResponse.created(user); }
@Delete("/{id}") public HttpResponse<Void> delete(String id) {
userRepository.deleteUserById(id); return HttpResponse.noContent(); }}Create Main Class
package com.knf.dev.demo;
import io.micronaut.runtime.Micronaut;
public class Application {
public static void main(String[] args) { Micronaut.run(Application.class, args); }}Run the backend application
mvn mn:run or run as java application
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="#"> Micronaut + 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>Micronaut-vuejs-mongodb-crud</title></head>
<body> <noscript> <strong>We're sorry but Micronaut-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>Download Source code - Local environment setup
Step1: Install JDK 17 - click here
Step2: Install eclipse - click here
Step3: Install VueJS - click here
Step4: Install VS code - click here
Step5: Download/clone source code - click here
Step6: Install Apache Maven - click here
Step7: Install MongoDB - click here
Step1: Install JDK 17 - click here
Step2: Install eclipse - click here
Step3: Install VueJS - click here
Step4: Install VS code - click here
Step5: Download/clone source code - click here
Step6: Install Apache Maven - click here
Step7: Install MongoDB - click here
Backend setup
Step8: Execute the command - mvn clean install
Step9: Run the app as a Java application or execute mvn mn:run
Step8: Execute the command - mvn clean install
Step9: Run the app as a Java application or execute mvn mn:run
Frontend setup
Step10: The npm install installs all modules that are listed on package.json file and their dependencies - npm install
Step11: Run the Frontend application - npm run serve
Step10: The npm install installs all modules that are listed on package.json file and their dependencies - npm install
Step11: Run the Frontend application - npm run serve

Comments
Post a Comment