天天看點

學習筆記:Spring Boot + Vue 前後端分離極簡上手

功能示範

後端:Spring boot + MyBatis-Plus

前端:Vue + Element UI + ECharts + Axios

學習筆記:Spring Boot + Vue 前後端分離極簡上手

建立 Vue 工程

安裝 Vue 及腳手架:

參考:https://blog.csdn.net/dream_summer/article/details/108867317

在 cmd 輸入

vue ui

指令,打開 Vue 項目管理器:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

建立新項目:

選擇【建立】→【編輯路徑】→點選【在此建立新項目】→【詳情】→【預設】→【功能】→【配置】→點選【建立項目】

學習筆記:Spring Boot + Vue 前後端分離極簡上手

安裝插件:

選擇【插件】→【添加插件】→【查找插件】→【安裝插件】→【完成安裝】

學習筆記:Spring Boot + Vue 前後端分離極簡上手

用 IDEA 打開項目,在 Terminal 終端輸入

npm run serve

指令,嘗試運作:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

成功建立 Vue 工程。

使用 Element UI 和 ECharts

編寫 Bar.vue 元件,用于繪制柱狀圖:

<template>
  <div id="myChart" :style="{width: '800px', height: '600px'}"></div>
</template>

<script>
export default {
  name: "Bar",
  mounted() {
    // 基于準備好的dom,初始化echarts執行個體
    let myChart = this.$echarts.init(document.getElementById('myChart'))
    // 繪制圖表,setOption的内容可以按需替換
    myChart.setOption({
      title: {
        text: '水果銷量統計-柱狀圖',
        left: 'center',
        top: 20,
        textStyle: {
          color: '#555555',
        },
      },
      tooltip: {},
      xAxis: {
        data: [
          "蘋果",
          "香蕉",
          "橘子",
          "火龍果",
          "葡萄",
          "西瓜",
        ],
      },
      yAxis: {},
      series: [{
        name: '銷量',
        type: 'bar',
        data: [
          {
            value: 333,
            itemStyle: {color: "#f35959"},
          },
          {
            value: 133,
            itemStyle: {color: "#e7e694"},
          },
          {
            value: 99,
            itemStyle: {color: "#e87f47"},
          },
          {
            value: 222,
            itemStyle: {color: "#5fa54e"},
          },
          {
            value: 399,
            itemStyle: {color: "#7d5f9a"},
          },
          {
            value: 123,
            itemStyle: {color: "#3b9265"},
          },
        ],
      }],
    });
  }
}
</script>
           

在 router.js 中配置路由:

{
      path: '/bar',  // 路由位址
      component: () => import('./views/Bar')  // 對應跳轉的元件
    },
           

在 App.vue 中添加

<router-view/>

,當浏覽器通路時,可以替換成指定的元件:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

在 ECharts 網站中,可以選擇各類圖表的模闆:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

另外,在 Element 網站中,可以選擇各類元件的模闆:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

搭建後端服務

在 IDEA 中建立 Spring Boot 項目:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

直接添加依賴:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

在 pom.xml 中導入 MyBatis-Plus 依賴:

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>
           

編寫 MyBatis-Plus 的代碼生成器,所有配置都可以使用 Java Config 完成:

package com.example;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

public class GenerateTest {

    public static void main(String[] args) {

        // 建立generator對象,操縱這個對象生成代碼
        AutoGenerator autoGenerator = new AutoGenerator();

        // 資料庫資訊配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDbType(DbType.MYSQL);  // 資料庫類型
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");  // 驅動名稱
        dataSourceConfig.setUsername("root");  // 使用者名
        dataSourceConfig.setPassword("123456");  // 登入密碼
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/fruit");  // url
        autoGenerator.setDataSource(dataSourceConfig);

        // 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");  // user.dir擷取目前工程的src目錄路徑
        globalConfig.setAuthor("admin");  // 注釋作者
        globalConfig.setOpen(false);  // 生成代碼後是否打開資料總管
        globalConfig.setFileOverride(false);  // 重新生成代碼後是否覆寫原檔案
        globalConfig.setServiceName("%sService");  // 去掉Service接口的首字母I
        autoGenerator.setGlobalConfig(globalConfig);

        // 包資訊配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setModuleName(null);  // 子產品名
        packageConfig.setParent("com.example");  // 包名
        packageConfig.setController("controller");  // 前端控制器,控制請求和響應,負責前後端互動
        packageConfig.setEntity("entity");  // 存放實體類,一張資料庫表對應一個model類
        packageConfig.setMapper("mapper");  // 資料存儲對象,作用是通路資料庫,向資料庫發送sql語句,完成資料的增删改查任務
        packageConfig.setService("service");  // 資料服務層,負責調用mapper的接口進行業務邏輯應用的處理
        packageConfig.setServiceImpl("service.impl");  // 資料服務的實作接口,把mapper和service進行整合
        autoGenerator.setPackageInfo(packageConfig);

        // 政策配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("fruit_info");  // 資料庫表名,可以指定多個表進行處理
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);  // 資料庫表名映射到實體類的命名政策,underline_to_camel表示下劃線轉駝峰
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);  // 資料庫表字段名映射到成員變量的命名政策
        strategyConfig.setEntityLombokModel(true);  // 是否使用Lombok注解
        autoGenerator.setStrategy(strategyConfig);

        // 運作
        autoGenerator.execute();
    }
}
           

運作其中的 main 方法,就可以生成 Entity、Mapper、Service、Controller 子產品代碼:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

在 application.yml 中添加配置資訊:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/fruit
    username: root
    password: 123456
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:com/example/mapper/xml/*.xml
server:
  port: 8181
           

在 FruitInfoController 中編寫增删改查資料接口:

package com.example.controller;

import com.example.entity.FruitInfo;
import com.example.service.FruitInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author admin
 * @since 2021-08-11
 */
@RestController
@RequestMapping("/fruitInfo")
public class FruitInfoController {

    @Autowired
    private FruitInfoService fruitInfoService;

    // 查詢資料接口
    @GetMapping("/list")
    public List<FruitInfo> list() {
        return this.fruitInfoService.list();
    }

    // 删除資料接口
    @DeleteMapping("/delete/{id}")
    public boolean delete(@PathVariable("id") Integer id) {
        return this.fruitInfoService.removeById(id);
    }

    // 編輯資料接口
    @GetMapping("/find/{id}")
    public FruitInfo find(@PathVariable("id") Integer id) {
        return this.fruitInfoService.getById(id);
    }

    // 更新資料接口
    @PutMapping("/update")
    public boolean update(@RequestBody FruitInfo fruitInfo) {
        return this.fruitInfoService.updateById(fruitInfo);
    }

    // 添加資料接口
    @PostMapping("/add")
    public boolean add(@RequestBody FruitInfo fruitInfo) {
        return this.fruitInfoService.save(fruitInfo);
    }
}

           

運作程式,測試查詢資料接口:

學習筆記:Spring Boot + Vue 前後端分離極簡上手

前後端資料對接

使用 Axios 連接配接查詢資料接口:

// 連接配接查詢資料接口
    axios
        .get('http://localhost:8181/fruitInfo/list')
        .then(function(response) {
          that.tableData = response.data;  // 傳回所有資料
        });
           

在背景添加 configuration 檔案,解決跨域問題:

package com.example.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CrosConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 允許跨域的請求路徑
                .allowedOriginPatterns("*")
                .allowedMethods("*")  // 允許送出請求的方法
                .allowedHeaders("*")  // 允許通路的頭資訊
                .maxAge(3600)  // 預請求的結果有效期
                .allowCredentials(true);
    }
}

           

編寫 Table.vue 元件,用于查詢資料和删除資料:

<template>
  <el-table :data="tableData" border style="width: 100%"
            :cell-style="rowClass" :header-cell-style="headClass">
    <el-table-column prop="id" label="水果ID" width="150"></el-table-column>
    <el-table-column prop="name" label="水果名稱" width="150"></el-table-column>
    <el-table-column prop="sale" label="水果銷量" width="150"></el-table-column>
    <el-table-column prop="icon" label="圖檔" width="150">
      <template slot-scope="scope">
        <img :src="scope.row.icon" style="width: 100px; height: 100px" />
      </template>
    </el-table-column>
    <el-table-column label="操作" width="150">
      <template slot-scope="scope">
        <el-button @click="findFruit(scope.row)" type="text" size="small">編輯</el-button>
        <el-button @click="deleteFruit(scope.row)" type="text" size="small">删除</el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  name: "Table",
  methods: {
    // 表頭内容樣式設定
    headClass() {
      return 'text-align: center;';
    },
    // 表格内容樣式設定
    rowClass() {
      return 'text-align: center;';
    },
    // 編輯資料操作
    findFruit(row) {
      this.$router.push('/edit?id='+row.id);  // 跳轉到/edit頁面
    },
    // 删除資料操作
    deleteFruit(row) {
      let that = this;
      this.$confirm('是否确定删除'+row.name+'?', '删除資料', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {  // 點選确定
        // 連接配接删除資料接口
        axios
            .delete('http://localhost:8181/fruitInfo/delete/'+row.id)
            .then(function(response) {
              if(response.data) {  // 接口傳回bool類型,true表示删除成功
                that.$alert('删除成功!', '删除資料', {
                  confirmButtonText: '确定',
                  callback: action => {
                    location.reload();  // 重新整理目前頁面
                  }
                });
              }
            })
      }).catch(() => {  // 點選取消
      });
    },
  },
  // 顯示表格資料
  created() {
    let that = this;
    // 連接配接查詢資料接口
    axios
        .get('http://localhost:8181/fruitInfo/list')
        .then(function(response) {
          that.tableData = response.data;  // 傳回所有資料
        });
  },
  // 預設表格資料
  data() {
    return {
      tableData: null,
    };
  },
}
</script>

           

編寫 Edit.vue 元件,用于編輯資料和更新資料:

<template>
  <el-form ref="fruitRules" :model="fruitData" :rules="rules"
           label-width="80px" style="width: 600px" class="demo-ruleForm">
    <el-form-item label="水果ID" prop="id">
      <el-input v-model="fruitData.id" readonly></el-input>
    </el-form-item>
    <el-form-item label="水果名稱" prop="name">
      <el-input v-model="fruitData.name"></el-input>
    </el-form-item>
    <el-form-item label="水果銷量" prop="sale">
      <el-input v-model.number="fruitData.sale"></el-input>
    </el-form-item>
    <el-form-item label="圖檔" prop="icon">
      <el-input v-model="fruitData.icon"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="onSubmit('fruitRules')">立即修改</el-button>
      <el-button>取消</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
export default {
  name: "Edit",
  methods: {
    onSubmit(formName){
      this.$refs[formName].validate((valid) => {
        if(valid) {
          let that = this;
          // 連接配接更新資料接口
          axios
              .put('http://localhost:8181/fruitInfo/update', this.fruitData)
              .then(function (response) {
                if(response.data){
                  that.$alert(that.fruitData.name+'修改成功!', '修改資料', {
                    confirmButtonText: '确定',
                    callback: action => {
                      that.$router.push('/table');  // 跳轉到/table頁面
                    }
                  });
                }
              });
        }
      });
    }
  },
  // 顯示表格資料
  created() {
    let id = this.$route.query.id;
    let that = this;
    // 連接配接編輯資料接口
    axios
        .get('http://localhost:8181/fruitInfo/find/'+id)
        .then(function(response) {
          that.fruitData = response.data;  // 傳回對應id的資料
        });
  },
  data() {
    return {
      fruitData: {
        name: '',
        sale: '',
        icon: '',
      },
      rules:{
        name:[
          { required: true, message: '請輸入水果名稱', trigger: 'blur' },
        ],
        sale:[
          { required: true, message: '請輸入水果銷量', trigger: 'blur' },
          { type: 'number', message: '水果銷量必須為數字值'},
        ],
        icon:[
          { required: true, message: '請輸入圖檔連結', trigger: 'blur' },
        ],
      },
    }
  },
}
</script>

           

編寫 Add.vue 元件,用于添加資料:

<template>
  <el-form ref="fruitRules" :model="fruitData" :rules="rules"
           label-width="80px" style="width: 600px" class="demo-ruleForm">
    <el-form-item label="水果ID" prop="id">
      <el-input v-model="fruitData.id"></el-input>
    </el-form-item>
    <el-form-item label="水果名稱" prop="name">
      <el-input v-model="fruitData.name"></el-input>
    </el-form-item>
    <el-form-item label="水果銷量" prop="sale">
      <el-input v-model.number="fruitData.sale"></el-input>
    </el-form-item>
    <el-form-item label="圖檔" prop="icon">
      <el-input v-model="fruitData.icon"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="onSubmit('fruitRules')">立即建立</el-button>
      <el-button>取消</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
export default {
  name: "Add",
  methods: {
    onSubmit(formName){
      this.$refs[formName].validate((valid) => {
        if(valid) {
          let that = this;
          // 連接配接添加資料接口
          axios
              .post('http://localhost:8181/fruitInfo/add', this.fruitData)
              .then(function (response) {
                if(response.data){
                  that.$alert(that.fruitData.name+'添加成功!', '添加資料', {
                    confirmButtonText: '确定',
                    callback: action => {
                      that.$router.push('/table');  // 跳轉到/table頁面
                    }
                  });
                }
              });
        }
      });
    }
  },
  data() {
    return {
      fruitData: {
        id: '',
        name: '',
        sale: '',
        icon: '',
      },
      rules:{
        id:[
          { required: true, message: '請輸入水果ID', trigger: 'blur' },
        ],
        name:[
          { required: true, message: '請輸入水果名稱', trigger: 'blur' },
        ],
        sale:[
          { required: true, message: '請輸入水果銷量', trigger: 'blur' },
          { type: 'number', message: '水果銷量必須為數字值'},
        ],
        icon:[
          { required: true, message: '請輸入圖檔連結', trigger: 'blur' },
        ],
      },
    }
  },
}
</script>

           

繼續閱讀