[no_toc]In this Spring Boot Vue.js tutorial, we show you Vue.js Http Client & Spring Boot Server example that uses Spring Data to do CRUD with MongoDB and Vue.js as a front-end technology to make request and receive response.
Related Posts:
– Spring MongoOperations to access MongoDB
– How to use SpringData MongoRepository to interact with MongoDB
– How to build SpringBoot MongoDb RestfulApi
– Vue Router example – with Nav Bar, Dynamic Route & Nested Routes
Technologies
– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.4.RELEASE
– Spring Boot: 2.0.5.RELEASE
– Vue 2.5.17
– Vue Router 3
– Axios 0.18.0
Overview
This is full-stack Architecture:
Demo
Spring Boot Server
Vue.js Client
Spring Boot Server
– Customer class corresponds to entity and table customer.
– CustomerRepository is an interface extends MongoRepository, will be autowired in CustomerController for implementing repository methods and custom finder methods.
– CustomerController is a REST Controller which has request mapping methods for RESTful requests such as: getAllCustomers
, postCustomer
, deleteCustomer
, findByAge
, updateCustomer
.
– Configuration for Spring Datasource and Spring Data properties in application.properties
– Dependencies for Spring Boot and MongoDb in pom.xml
Dependency
<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>
Data Model
model/Customer.java
package com.ozenero.spring.restapi.mongodb.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "customer")
public class Customer {
@Id
private String id;
private String name;
private int age;
private boolean active;
public Customer() {
}
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", age=" + age + ", active=" + active + "]";
}
}
SpringJPA Repository
repo/CustomerRepository.java
package com.ozenero.spring.restapi.mongodb.repo;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.ozenero.spring.restapi.mongodb.model.Customer;
public interface CustomerRepository extends MongoRepository{
List findByAge(int age);
}
SpringBoot REST Controller
controller/CustomerController.java
package com.ozenero.spring.restapi.mongodb.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ozenero.spring.restapi.mongodb.model.Customer;
import com.ozenero.spring.restapi.mongodb.repo.CustomerRepository;
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api")
public class CustomerController {
@Autowired
CustomerRepository repository;
@GetMapping("/customers")
public List getAllCustomers() {
System.out.println("Get all Customers...");
List customers = new ArrayList<>();
repository.findAll().forEach(customers::add);
return customers;
}
@PostMapping("/customer")
public Customer postCustomer(@RequestBody Customer customer) {
Customer _customer = repository.save(new Customer(customer.getName(), customer.getAge()));
return _customer;
}
@DeleteMapping("/customer/{id}")
public ResponseEntity deleteCustomer(@PathVariable("id") String id) {
System.out.println("Delete Customer with ID = " + id + "...");
repository.deleteById(id);
return new ResponseEntity<>("Customer has been deleted!", HttpStatus.OK);
}
@GetMapping("customers/age/{age}")
public List findByAge(@PathVariable int age) {
List customers = repository.findByAge(age);
return customers;
}
@PutMapping("/customer/{id}")
public ResponseEntity updateCustomer(@PathVariable("id") String id, @RequestBody Customer customer) {
System.out.println("Update Customer with ID = " + id + "...");
Optional customerData = repository.findById(id);
if (customerData.isPresent()) {
Customer _customer = customerData.get();
_customer.setName(customer.getName());
_customer.setAge(customer.getAge());
_customer.setActive(customer.isActive());
return new ResponseEntity<>(repository.save(_customer), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
Configuration for Spring Datasource & Data MongoDb properties
application.properties
spring.data.mongodb.database=jsa_mongodb
spring.data.mongodb.port=27017
Vue.js Client
– package.json with 3 main modules: vue
, vue-router
, axios
.
– 4 components: CustomersList, Customer, AddCustomer, SearchCustomer.
– router.js defines routes
, each route has a path and maps to a component.
– http-common.js initializes HTTP Client with baseUrl
and headers
for axios HTTP methods.
– vue.config.js configures port
for Vue App.
For more details about how to use Vue Router in this example, please visit:
Vue Router example – with Nav Bar, Dynamic Route & Nested Routes
Init Vue Project
Point cmd to the folder you want to save Project folder, run command:
vue create vue-springboot
You will see 2 options, choose default:
Add Vue Router to Project
– Run command: npm install vue-router
.
– Import router
to src/main.js:
import Vue from "vue";
import App from "./App.vue";
import router from './router'
Vue.config.productionTip = false;
new Vue({
router, // inject the router to make whole app router-aware
render: h => h(App)
}).$mount("#app");
Define Vue Routes
src/router.js:
import Vue from "vue";
import Router from "vue-router";
import CustomersList from "./components/CustomersList.vue";
import AddCustomer from "./components/AddCustomer.vue";
import SearchCustomers from "./components/SearchCustomers.vue";
import Customer from "./components/Customer.vue";
Vue.use(Router);
export default new Router({
mode: "history",
routes: [
{
path: "/",
name: "customers",
alias: "/customer",
component: CustomersList,
children: [
{
path: "/customer/:id",
name: "customer-details",
component: Customer,
props: true
}
]
},
{
path: "/add",
name: "add",
component: AddCustomer
},
{
path: "/search",
name: "search",
component: SearchCustomers
}
]
});
App template with Navbar and router-view
src/App.vue:
<template>
<div id="app" class="container-fluid">
<div class="site-info">
<h1>ozenero</h1>
<h3>Vue SpringBoot example</h3>
</div>
<nav>
<router-link class="btn btn-primary" to="/">Customers</router-link>
<router-link class="btn btn-primary" to="/add">Add</router-link>
<router-link class="btn btn-primary" to="/search">Search</router-link>
</nav>
<br/>
<router-view/>
</div>
</template>
<script>
export default {
name: "app"
};
</script>
<style>
.site-info {
color: blue;
margin-bottom: 20px;
}
.btn-primary {
margin-right: 5px;
}
.container-fluid {
text-align: center;
}
</style>
Initialize Vue HTTP Client
Install axios with command: npm install axios
.
Then create http-common.js file:
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-type": "application/json",
}
});
Vuejs List of Items
components/CustomersList.vue
<template>
<div class="list row">
<div class="col-md-6">
<h4>Customers List</h4>
<ul>
<li v-for="(customer, index) in customers" :key="index">
<router-link :to="{
name: 'customer-details',
params: { customer: customer, id: customer.id }
}">
{{customer.name}}
</router-link>
</li>
</ul>
</div>
<div class="col-md-6">
<router-view @refreshData="refreshList"></router-view>
</div>
</div>
</template>
<script>
import http from "../http-common";
export default {
name: "customers-list",
data() {
return {
customers: []
};
},
methods: {
/* eslint-disable no-console */
retrieveCustomers() {
http
.get("/customers")
.then(response => {
this.customers = response.data; // JSON are parsed automatically.
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
refreshList() {
this.retrieveCustomers();
}
/* eslint-enable no-console */
},
mounted() {
this.retrieveCustomers();
}
};
</script>
<style>
.list {
text-align: left;
max-width: 450px;
margin: auto;
}
</style>
Vue Item Details
components/Customer.vue
<template>
<div v-if="this.customer">
<h4>Customer</h4>
<div>
<label>Name: </label> {{this.customer.name}}
</div>
<div>
<label>Age: </label> {{this.customer.age}}
</div>
<div>
<label>Active: </label> {{this.customer.active}}
</div>
<span v-if="this.customer.active"
v-on:click="updateActive(false)"
class="button is-small btn-primary">Inactive</span>
<span v-else
v-on:click="updateActive(true)"
class="button is-small btn-primary">Active</span>
<span class="button is-small btn-danger" v-on:click="deleteCustomer()">Delete</span>
</div>
<div v-else>
<br/>
<p>Please click on a Customer...</p>
</div>
</template>
<script>
import http from "../http-common";
export default {
name: "customer",
props: ["customer"],
methods: {
/* eslint-disable no-console */
updateActive(status) {
var data = {
id: this.customer.id,
name: this.customer.name,
age: this.customer.age,
active: status
};
http
.put("/customer/" + this.customer.id, data)
.then(response => {
this.customer.active = response.data.active;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
deleteCustomer() {
http
.delete("/customer/" + this.customer.id)
.then(response => {
console.log(response.data);
this.$emit("refreshData");
this.$router.push('/');
})
.catch(e => {
console.log(e);
});
}
/* eslint-enable no-console */
}
};
</script>
Vue Add Item
components/AddCustomer.vue
<template>
<div class="submitform">
<div v-if="!submitted">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" required v-model="customer.name" name="name">
</div>
<div class="form-group">
<label for="age">Age</label>
<input type="number" class="form-control" id="age" required v-model="customer.age" name="age">
</div>
<button v-on:click="saveCustomer" class="btn btn-success">Submit</button>
</div>
<div v-else>
<h4>You submitted successfully!</h4>
<button class="btn btn-success" v-on:click="newCustomer">Add</button>
</div>
</div>
</template>
<script>
import http from "../http-common";
export default {
name: "add-customer",
data() {
return {
customer: {
id: 0,
name: "",
age: 0,
active: false
},
submitted: false
};
},
methods: {
/* eslint-disable no-console */
saveCustomer() {
var data = {
name: this.customer.name,
age: this.customer.age
};
http
.post("/customer", data)
.then(response => {
this.customer.id = response.data.id;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
this.submitted = true;
},
newCustomer() {
this.submitted = false;
this.customer = {};
}
/* eslint-enable no-console */
}
};
</script>
<style>
.submitform {
max-width: 300px;
margin: auto;
}
</style>
Search Items
components/SearchCustomers.vue
<template>
<div class="searchform">
<h4>Find by Age</h4>
<div class="form-group">
<input type="number" class="form-control" id="age" required v-model="age" name="age">
</div>
<div class="btn-group">
<button v-on:click="searchCustomers" class="btn btn-success">Search</button>
</div>
<ul class="search-result">
<li v-for="(customer, index) in customers" :key="index">
<h6>{{customer.name}} ({{customer.age}})</h6>
</li>
</ul>
</div>
</template>
<script>
import http from "../http-common";
export default {
name: "search-customer",
data() {
return {
age: 0,
customers: []
};
},
methods: {
/* eslint-disable no-console */
searchCustomers() {
http
.get("/customers/age/" + this.age)
.then(response => {
this.customers = response.data; // JSON are parsed automatically.
console.log(response.data);
})
.catch(e => {
console.log(e);
});
}
/* eslint-enable no-console */
}
};
</script>
<style>
.searchform {
max-width: 300px;
margin: auto;
}
.search-result {
margin-top: 20px;
text-align: left;
}
</style>
Configure Port for Vue App
vue.config.js
module.exports = {
devServer: {
port: 4200
}
}
Run
– Spring Boot Server: mvn clean install
and mvn spring-boot:run
.
– Vue.js Client: npm run serve
.
Open Browser with Url: http://localhost:4200/
.
Source Code
– SpringBootRestMongoDB
– vue-springboot
Hi Grokonez,
When I issued a command npm create , it did not do anything , instead it prompted me “Didi you mean this? : Update”. was there a typos error ?
Never mind, I got it after dealing some configuration issue on Windows 10.
instead of “npm create vue-springboot” , it should be “vue create vue-springboot”.
Magnificent items from you, man. I have have in mind your stuff previous to and you’re simply too great. I actually like what you’ve received right here, really like what you are stating and the best way wherein you say it. You are making it enjoyable and you continue to care for to stay it smart. I cant wait to learn much more from you. That is really a great site.
Some genuinely terrific work on behalf of the owner of this website , perfectly great articles .
Hi” i think that you should add captcha to your blog.
When visiting blogs” i always look for a very nice content like yours .
Aw, the labyrinth was an especially good post. With presumed I must make a note of something like this similarly ; slacking and simply real perform produce a solid article… anyhow assist with While i say… A person put things a decent amount never ever rrn any way apparently go written.
Write more, thats all I have to say. Literally, it seems as though you relied on the video to make your point. You definitely know what youre talking about, why throw away your intelligence on just posting videos to your blog when you could be giving us something informative to read?
thanks to the author for taking his time on this one.
I’ve recently started a web site, and the info you provide on this site has helped me tremendously. Thank you for all of your time & work.
61846 744855you are in point of fact a excellent webmaster. The site loading velocity is incredible. It seems that you are performing any distinctive trick. In addition, The contents are masterpiece. youve done a fantastic activity on this topic! 132811
189419 206474Sweet internet site , super pattern , extremely clean and utilize friendly . 559880
834238 915044extremely nice post, i definitely really like this site, maintain on it 545008
105861 646570As I site owner I think the topic material here is real amazing, appreciate it for your efforts. 87974
My brother suggested I would possibly like this blog.
He was entirely right. This publish actually made my day.
You can not consider simply how so much time I had
spent for this info! Thanks!
At this time it seems like Movable Type is the preferred blogging platform available right now.
(from what I’ve read) Is that what you’re using on your blog?
Asking questions are truly fastidious thing if
you are not understanding anything entirely, however this
post gives pleasant understanding yet.
whoah this blog is wonderful i really like reading your posts.
Keep up the great work! You know, many individuals are hunting around for this info, you can help them
greatly.
Fantastic site. Lots of useful information here. I’m sending
it to a few buddies ans additionally sharing in delicious.
And naturally, thank you for your effort!
This design is incredible! You obviously know how to keep a reader
amused. Between your wit and your videos, I was almost
moved to start my own blog (well, almost…HaHa!) Wonderful job.
I really loved what you had to say, and more than that, how you presented it.
Too cool!
Everything is very open with a precise explanation of the challenges.
It was really informative. Your website is useful. Thanks
for sharing!
I really like your blog.. very nice colors & theme. Did you design this website
yourself or did you hire someone to do it for you? Plz respond as I’m looking to create my own blog and would
like to find out where u got this from. kudos
This page definitely has all the information I wanted concerning this subject and didn’t know who to ask.
At this time I am going to do my breakfast, after having my breakfast coming again to read additional news.
excellent points altogether, you simply won a brand new reader.
What could you recommend about your put up that you made a few days in the past?
Any positive?
I always used to study paragraph in news papers but now as I am a user
of web thus from now I am using net for articles or reviews, thanks to web.
Right here is the right webpage for everyone who really wants
to find out about this topic. You understand so much its almost tough to
argue with you (not that I really will need to…HaHa). You definitely put a new spin on a topic which has been written about for years.
Wonderful stuff, just wonderful!
This is my first time pay a quick visit at here and i am truly happy
to read everthing at one place.
Hi there everyone, it’s my first visit at this web page, and
article is really fruitful in favor of me, keep up posting these articles.
I will right away grab your rss as I can not to find your e-mail subscription link or e-newsletter service.
Do you’ve any? Kindly allow me realize so that I may just subscribe.
Thanks.
I all the time used to study post in news papers but now as I
am a user of net so from now I am using net for articles or
reviews, thanks to web.
Thanks for sharing your info. I really appreciate your efforts
and I will be waiting for your next post thanks once again.
Woah! I’m really digging the template/theme of this blog.
It’s simple, yet effective. A lot of times it’s very hard to get that “perfect balance” between usability and visual appeal.
I must say you’ve done a excellent job with this.
In addition, the blog loads super fast for me on Chrome.
Exceptional Blog!
hello there and thank you for your information – I have certainly picked up something new from right here.
I did however expertise several technical points using this site,
since I experienced to reload the website a lot of times previous to I could get it to load correctly.
I had been wondering if your hosting is OK? Not that I am complaining, but slow loading instances times will sometimes affect your placement in google and can damage your high-quality score if advertising and marketing with Adwords.
Anyway I am adding this RSS to my email and can look out
for a lot more of your respective fascinating content.
Make sure you update this again very soon.
Hey there! This post couldn’t be written any better!
Reading this post reminds me of my old room mate!
He always kept talking about this. I will forward this write-up to him.
Pretty sure he will have a good read. Thank you for sharing!
Excellent article. Keep writing such kind
of information on your site. Im really impressed by your site.
Hello there, You’ve performed an excellent job. I’ll definitely digg
it and in my opinion recommend to my friends. I am confident they will be benefited from this web site.
Write more, thats all I have to say. Literally, it seems as though you
relied on the video to make your point. You obviously
know what youre talking about, why waste your intelligence
on just posting videos to your weblog when you could be giving us something informative to read?
If you want to improve your experience only keep visiting this web page and be updated with the latest
gossip posted here.
A person necessarily help to make significantly posts I’d state.
That is the first time I frequented your web page and thus far?
I amazed with the analysis you made to make this
particular post amazing. Fantastic job!
always i used to read smaller posts that as well clear their
motive, and that is also happening with this article which I am reading here.
Thanks , I have recently been looking for info approximately
this topic for ages and yours is the best I have found out so far.
However, what concerning the conclusion? Are you sure concerning
the source?
What’s up, the whole thing is going perfectly here and ofcourse every one is sharing facts, that’s in fact good,
keep up writing.
Hi exceptional website! Does running a blog like this require a massive amount work?
I have no understanding of computer programming however I was hoping to
start my own blog soon. Anyway, if you have any recommendations or
techniques for new blog owners please share. I know this is off topic however I simply had to ask.
Kudos!