Vue.js + Spring Boot example | Spring Data JPA + REST + MariaDB CRUD

https://grokonez.com/frontend/vue-js/vue-js-spring-boot-example-spring-data-jpa-rest-mariadb-crud-example

https://ozenero.com/vuejs-springboot-crud-mariadb

Tutorial: Vue.js SpringBoot CRUD MariaDB Example | Spring Data JPA + REST + MariaDB CRUD

In this Vue.js SpringBoot tutorial, we show you Vue.js Http Client & Spring Boot Server example that uses Spring JPA to do CRUD with MariaDB and Vue.js as a front-end technology to make request and receive response.

Related Posts:

Technologies - Vuejs SpringBoot MariaDB

– 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 - Vue.js Spring Boot CRUD MariaDB Example

    This is full-stack Architecture:

[caption id="attachment_18486" align="alignnone" width="735"]vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-architecture vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-architecture[/caption]

Demo

1. Implement Spring Boot CRUD MariaDB Server

[caption id="attachment_18487" align="alignnone" width="720"]vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-spring-server-architecture vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-spring-server-architecture[/caption]

2. Vue.js RestAPI CRUD Client

[caption id="attachment_18488" align="alignnone" width="700"]vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-vue-client-ui vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-vue-client-ui[/caption]

Practice - Vue.js Spring Boot CRUD MariaDB Example

1. Spring Boot Server

vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-spring-server-structure

  • Customer class corresponds to entity and table customer.
  • CustomerRepository is an interface extends CrudRepository, 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 JPA properties in application.properties
  • Dependencies for Spring Boot and MariaDB in pom.xml

    1.1 Dependency

    
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>

1.2 Data Model

model/Customer.java


package com.ozenero.spring.restapi.mariadb.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "customer")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "age")
    private int age;

    @Column(name = "active")
    private boolean active;

    public Customer() {
    }

    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
        this.active = false;
    }

    public long 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 + "]";
    }
}

1.3 JPA Repository

repo/CustomerRepository.java


package com.ozenero.spring.restapi.mariadb.repo;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

import com.ozenero.spring.restapi.mariadb.model.Customer;

public interface CustomerRepository extends CrudRepository {
    List findByAge(int age);
}

1.4 REST Controller

controller/CustomerController.java


package com.ozenero.spring.restapi.mariadb.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.mariadb.model.Customer;
import com.ozenero.spring.restapi.mariadb.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") long 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") long 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);
        }
    }
}

1.5 Configuration for Spring Datasource & JPA properties

application.properties


spring.datasource.url=jdbc:mariadb://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.generate-ddl=true

2. Vue.js Client

vue-spring-boot-mariadb-example-spring-data-mariadb-rest-api-vue-client-structure

  • 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

2.0 Setup Vue Project & Router

Init 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:

vue-create-project-config

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 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>
            <h2>Vue SpringBoot example</h2>
        </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>

2.1 Initialize 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",
  }
});

2.2 Components

List of Items

components/CustomersList.vue


<template>
    <div class="list row">
        <div class="col-md-6">
            <h3>Customers List</h3>
            <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>
Item Details

components/Customer.vue


<template>
  <div v-if="this.customer">
    <h3>Customer</h3>
    <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>
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>
      <h3>You submitted successfully!</h3>
      <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">
    <h3>Find by Age</h3>
    <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">
        <h5> { { customer.name}} ( { { customer.age}})</h5>
      </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>
</code></pre>
<h4>2.3 Configure Port for Vue App</h4>
<em>vue.config.js</em>
<pre><code class="language-java">
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 for Vue.js and SpringBoot

Further Reading

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

Male avatar

loveprogramming

448 bài viết.
78 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
Male avatar
1 0
Tutorial Link: (Link) (Ảnh) Django is a Pythonbased free and opensource web framework that follows the modeltemplateview architectural pattern. A...
loveprogramming viết 6 tháng trước
1 0
Male avatar
1 0
https://loizenai.com/angular11nodejspostgresqlcrudexample/ Angular 11 Node.js PostgreSQL Crud Example (Ảnh) Tutorial: “Angular 11 Node.js Postg...
loveprogramming viết 5 tháng trước
1 0
Male avatar
1 0
Angular Spring Boot jwt Authentication Example Github https://loizenai.com/angularspringbootjwt/ (Ảnh) Tutorial: ” Angular Spring Boot jwt Authe...
loveprogramming viết 5 tháng trước
1 0
Bài viết liên quan
Male avatar
0 0
https://grokonez.com/frontend/angular/angular6/kotlinspringbootangular6crudhttpclientmysqlexamplespringdatajparestapisexample Kotlin Spring Boot +...
loveprogramming viết 1 tháng trước
0 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


Male avatar
{{userFollowed ? 'Following' : 'Follow'}}
448 bài viết.
78 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!