您的当前位置:首页Spring Boot + Vue.js 例子| Spring

Spring Boot + Vue.js 例子| Spring

2024-12-10 来源:哗拓教育
图片.png

在本教程中,我们将向您展示Vue.js Http Client和Spring Boot Server示例,该示例使用Spring JPA将MySQL,Vue.js作为前端技术进行CRUD发出请求和接收响应。

用到的技术:

– 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

1. Spring Boot Server

图片.png

2. Vue.js Client

图片.png

开始实战

1. Spring Boot Server

图片.png

– Customer 实体类及customer表
– CustomerRepository 一个继承于CrudRepository的接口(相当于以前的DAO),他在CustomerController 会自动被注入进来。你可以在该接口中实现自己操作数据库的方法。
– CustomerController 是一个REST Controller,里面有各个请求端点的映射。例如getAllCustomers,
postCustomer,deleteCustomer,findByAge,updateCustomer方法。
– Configuration Spring Datasource 和 Spring JPA properties 的配置在application.properties中
– Dependencies Spring Boot 和MySQL的相关依赖包在 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>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>

1.2 数据模型

model/Customer.java

package com.grokonez.spring.restapi.mysql.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.grokonez.spring.restapi.mysql.repo;
 
import java.util.List;
 
import org.springframework.data.repository.CrudRepository;
 
import com.grokonez.spring.restapi.mysql.model.Customer;
 
public interface CustomerRepository extends CrudRepository<Customer, Long> {
  List<Customer> findByAge(int age);
}

1.4 REST Controller

controller/CustomerController.java

package com.grokonez.spring.restapi.mysql.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.grokonez.spring.restapi.mysql.model.Customer;
import com.grokonez.spring.restapi.mysql.repo.CustomerRepository;
 
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api")
public class CustomerController {
 
  @Autowired
  CustomerRepository repository;
 
  @GetMapping("/customers")
  public List<Customer> getAllCustomers() {
    System.out.println("Get all Customers...");
 
    List<Customer> 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<String> 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<Customer> findByAge(@PathVariable int age) {
 
    List<Customer> customers = repository.findByAge(age);
    return customers;
  }
 
  @PutMapping("/customer/{id}")
  public ResponseEntity<Customer> updateCustomer(@PathVariable("id") long id, @RequestBody Customer customer) {
    System.out.println("Update Customer with ID = " + id + "...");
 
    Optional<Customer> 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 CSpring Datasource & JPA 相关配置信息

application.properties

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

2. Vue.js Client

图片.png
给项目添加Vue Router

– 执行命令: npm install vue-router.
– Import router 到 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");
定义路由

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 添加Navbar and router-view

src/App.vue:

<template>
    <div id="app" class="container-fluid">
        <div class="site-info">
            <h1>grokonez</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>

2.1 初始化HTTP Client

import axios from "axios";
export default axios.create({
  baseURL: "http://localhost:8080/api",
  headers: {
    "Content-type": "application/json",
  }
});

2.2 Components

列表组件
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>
单个详情查看

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>

添加

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>

查询操作

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>

2.3 为 Vue App配置端口

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

运行代码:

源代码:

显示全文