從零開始搭建Vue2.0項目(三)之集成SpringBoot

前言

前面一篇主要是介紹了怎么完成axios請求測試以及mock.js模擬真實數(shù)據(jù)請求,前后端分離的實際應用還是得與后端進行交互,下面是關(guān)于怎么樣與java后臺進行交互的介紹。

快速開始

我么將要完成Mybatis框架的集成,并編寫查詢語句查詢出MySQL數(shù)據(jù)庫的數(shù)據(jù),通過controller層的API暴露給前端,從而實現(xiàn)數(shù)據(jù)的交互。

首先,完成SpringBoot項目的創(chuàng)建,添加mybatis、spring-web、spring-configuration、mysql、lombok依賴。

項目目錄

創(chuàng)建完成后,項目目錄如下:

<img src="https://cdn.jsdelivr.net/gh/deepinsea/cdn/img/20210119222110.png" alt="img" style="zoom: 67%;" />

一、添加依賴

pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

二、編寫yaml配置文件

將根目錄下的application.properties重命名為application.yml,然后進行配置:

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
# 數(shù)據(jù)庫驅(qū)動
# 此處驅(qū)動有兩個
# com.mysql.jdbc.Driver
# com.mysql.cj.jdbc.Driver
# MySQL5用的驅(qū)動url是com.mysql.jdbc.Driver,
# MySQL6以后用的是com.mysql.cj.jdbc.Driver。
# 使用何種驅(qū)動,根據(jù)安裝MySQL的版本而定
# 下面是Mybatis下劃線轉(zhuǎn)駝峰
mybatis:
  configuration:
    map-underscore-to-camel-case: true

注意:這里如果添加了Mybatis而不進行數(shù)據(jù)庫連接池的配置,將會報出異常!

三、編寫主類文件

User.java

package com.deepinsea.cors.entity;

import lombok.Data;

/**
 * @author 南街北巷
 * @data 2021/1/6 15:51
 */
@Data
public class User {

    private int id;
    private String name;
    private int age;
}

注意:我們應該事先創(chuàng)建好MySQL數(shù)據(jù)庫,設(shè)置庫、表編碼為utf8mb64(為什么MySQL不用utf-8?),然后根據(jù)數(shù)據(jù)庫設(shè)置的字段編寫實體類!

UserMapper.java

package com.deepinsea.cors.mapper;

import com.deepinsea.cors.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @author 南街北巷
 * @data 2021/1/6 15:52
 */
@Mapper
@Repository
public interface UserMapper {

    /**
     * 根據(jù)id查詢User
     * @param id
     * @return
     */
    @Select("select * from user where id = #{id}")
    User findById(int id);

    /**
     * 查詢所有用戶
     * @return
     */
    @Select("select * from user")
    List<User> findAll();
}

HelloController.java

package com.deepinsea.cors.controller;

import com.deepinsea.cors.entity.User;
import com.deepinsea.cors.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author 南街北巷
 * @data 2021/1/6 14:44
 * @RestController 等同于 @Controller+@ResponseBody
 */
@RestController
@RequestMapping("/user")
public class HelloController {

    @Autowired
    private UserMapper userMapper;

    @PostMapping("/getBy/{id}")
    public User findById(@PathVariable int id){
        User user = userMapper.findById(id);
        return user;
    }

    @PostMapping("/getAll")
    public List<User> getAll(){
        List<User> users = userMapper.findAll();
        return users;
    }
}

四、測試使用

下面以請求APIhttp://localhost:8080/user/getBy/2為例進行測試:

[圖片上傳失敗...(image-df850c-1648582518205)]

測試以后,發(fā)現(xiàn)返回JSON字符串成功(需要自定義序列化配置、異常、枚舉可以自行配置,這里僅快速集成)!
到了這里,完成了數(shù)據(jù)庫到后端的數(shù)據(jù)傳遞,然后是后端到前端的數(shù)據(jù)傳遞了。

前后端交互

現(xiàn)在是正式集成進行后端與前端的跨域請求,因此我們需要把注釋的portproxyTable打開:

端口

port: 8081 # 后端端口為8080

代理配置

webpack.js

  proxyTable: {
        // 跨域配置
        // 修改配置后如果項目啟動404,記得重啟項目(類似于redis,webpack是依賴配置文件啟動的)
        // 錯誤日志:xhr.js?ec6c:177 POST http://localhost:8081/user/getAll 404 (Not Found)
        '/api': {
          target: 'http://localhost:8080/',
          changeOrigin: true,
          secure: false,  // 如果是https接口,需要配置這個參數(shù)
          pathRewrite: {
            '^/api': ''
          }
        }
    },

上面的配置相當于將前端的請求代理為:

http://localhost:8081/api => http://localhost:8080

上面將原后端增加一個/api路徑參數(shù),是為了隱藏真實的后端API地址,但是對于前端請求真實的API地址沒有用。因此 ,我們需要在main.js中(或者vue.config.js)設(shè)置前端跨域代理的基本路徑,這樣就不用編寫地址時每次都加一個/api了:

axios.defaults.baseURL = '/api' // 設(shè)置跨域代理基本路徑

因為使用axios進行過測試(后面可以集成vuex狀態(tài)管理器對axios進行二次封裝),只需要將Home.vue中的測試API訪問地址更改為后端的API地址即可:

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import MockTest from '@/components/MockTest.vue' // 這里不能使用./AxiosTest.vue的方式引入
  name: 'Home',
  components: { // 局部注冊(引入并注冊)
    HelloWorld,
    MockTest
  },
  methods: {
    mockTest () {
      this.$axios.post('/user/getAll') // 'https://v1.alapi.cn/api/music/search?   keyword=我愛你'
        .then(res => {
          console.log(res) // 在控制臺打印響應數(shù)據(jù)(包括響應頭與響應體)
        })
        .catch(err => {
          console.log(err)
        })
    }
  }
</script>

注意:也可以在created()mounted()生命周期函數(shù)里面添加該方法,將會自動執(zhí)行。

測試使用

跨域配置完成了,啟動項目:

[圖片上傳失敗...(image-f6cc8f-1648582518205)]

可以看到,成功返回了后端的數(shù)據(jù)!

到這里基本可以結(jié)束了,下面是關(guān)于數(shù)組遍歷出對象顯示到前端的部分(主要為原理深究)

讀取對象數(shù)組數(shù)據(jù)

1. 使用foreach遍歷讀取

首先,一般遍歷Javascript遍歷實現(xiàn)數(shù)據(jù)的傳遞都是通過document.getElementById()方法進行單向數(shù)據(jù)傳遞,但是對于已經(jīng)默認進行了雙向綁定的vue對象來說——即:在data()中聲明的對象,進行數(shù)據(jù)的傳遞往往要考慮一個數(shù)據(jù)的狀態(tài)變化性(動態(tài)變化性)。

因為獲取到axios響應體的數(shù)據(jù)一般是通過this指針傳遞給vue對象的,因此this指向的對象發(fā)生變化時全局的對象的值也會隨之發(fā)生改變(this相當于指針),這將會導致數(shù)組使用for循環(huán)以及其他各種遍歷方式非鉤子函數(shù),遍歷時新數(shù)組對象都會將原來的數(shù)組對象覆蓋:

下面是使用for循環(huán)遍歷等各種數(shù)組測試

Home.vue

<template>
  <div class="home">
    <Hello-World />
    <Mock-Test />
    <button @click="userTest">試試</button>
  <!-- 下面兩種方式進行遍歷都可以,index是數(shù)組下標0,1,2...,item是id序號1,2,3... -->
  <!-- 當兩種標簽遍歷方式都存在時,只用item的遍歷會報key重復錯誤(應該是DOM結(jié)構(gòu)沖突),
       因此最好使用item和index同時定位對象的遍歷方式 -->
  <p>{{userList}}</p>
  <!-- <p v-for="item in userList" :key="item.id">{{item}}</p>
  <p v-for="(item,index) in userList" :key="index">{{item.id}}</p> -->

  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import MockTest from '@/components/MockTest.vue' // 這里不能使用./AxiosTest.vue的方式引入

export default {
  name: 'Home',
  components: {
    HelloWorld,
    MockTest
  },
  data () {
    return {
      userList: '' // 注意: 這里為對象數(shù)組時參數(shù)時定義為userList:[](適用于單個對象)的話會默認產(chǎn)生一個[]符號,
    }
  },
  // created () { // 或created: function(),為生命周期函數(shù)created,也可以是mounted—已掛載,可在頁面加載時自動執(zhí)行方法
  //   this.userTest()
  // },
  methods: {
    userTest () {
      this.$axios.post('/user/getAll') // 'https://v1.alapi.cn/api/music/search?keyword=我愛你'
        .then(res => {
          // 響應體獲取測試
          // console.log(res)
          // console.log(res.data) // 這里采用逐步分層取值的方式測試
          // console.log(res.data[0])
          // console.log(res.data[0].name)
          // console.log(res.data[res.data[0].id].name) // 嵌套取值
          // console.log(res.data.length)

          // var _this = this// 這句話的位置需要注意
          // console.log(this)// 依然是這個方法的對象
          // console.log(_this) // 這個變成了原來的對象

          // 循環(huán)取值測試(因為this的指針變化問題,不可行,因為this無論是否處于嚴格模式下都引用全局對象。)
          for (var i = 0; i < res.data.length; i++) { // 遍歷出所有對象
            // 將對象合并(for循環(huán)遍歷賦值、Object.assign()、序列化、淺拷貝、深拷貝(不會覆蓋對象)、foreach遍歷(測試成功))
            // 1.遍歷賦值
            // this.userList = res.data[i] // 測試發(fā)現(xiàn)只有id為2(即:第二個對象)對象的值,說明userList的this指向被修改了
            // console.log(this.userList)
            // 2.Object.assign()
            // var objList = Object.assign({}, res.data[i]) // 參數(shù)表示,測試時也可以直接用常數(shù)表示
            // console.log(objList)
            // this.userList >= objList
            // 3.序列化
            // const obj = JSON.parse(JSON.stringify(res.data[i]))
            // this.userList = obj
            // console.log(obj)
            // 淺拷貝與深拷貝需要下載JQuery,暫時沒有嘗試
          }

          // 4.foreach遍歷測試
          // var list = ['750', '1080', '1125', '1242', '1242']
          // var data = []
          // Object.keys(list).forEach(key => {
          //   let item = {
          //     val: list[key]
          //   }
          //   data.push(item)
          // })
          // console.log(list)
          // 正式使用
          var list = res.data
          var data = []
          Object.keys(list).forEach(key => { // 因為這里使用了ES6語法中的 => 鉤子函數(shù),因此將不會
            data.push(list[key])
          })
          this.userList = data
          console.log(data)

          // this.userList = res.data
          // console.log(res.data)
          // axios的response采用默認參數(shù)data存放數(shù)據(jù),這里只需要傳data的值就行了,
          // 否則要從一個加了其他參數(shù)的多重JSON對象中取值,無異于自己設(shè)計一個JSON序列化工具
          // 注意:這里res.data前不需要加this指針,因為箭頭函數(shù)沒有自己的this(因此本身是局部變量),
          // 箭頭函數(shù)里面的this是對象的指針(定義時的全局變量),如果加了this那么將獲取不到res.data的值
        })
        .catch(err => {
          console.log(err)
        })
    }
  }
}
</script>

使用for循環(huán)里面的遍歷賦值與淺拷貝都會導致最終數(shù)組元素的值發(fā)生改變,導致對象數(shù)組遍歷出對象再合并出現(xiàn)對象覆蓋的現(xiàn)象:

[圖片上傳失敗...(image-56bd16-1648582518205)]

但是使用foreach遍歷搭配鉤子函數(shù)就能避免這個問題:

 // 4.foreach遍歷測試
      // var list = ['750', '1080', '1125', '1242', '1242']
      // var data = []
      // Object.keys(list).forEach(key => {
      //   let item = {
      //     val: list[key]
      //   }
      //   data.push(item)
      // })
      // console.log(list)
      // 正式使用
      var list = res.data
      var data = []
      Object.keys(list).forEach(key => { // 因為這里使用了ES6語法中的 => 鉤子函數(shù),因此將不會
        data.push(list[key])
      })
      this.userList = data
      console.log(data)

[圖片上傳失敗...(image-da8e20-1648582518205)]

2. 使用v-for讀取

對此,vue2.0提供了默認的數(shù)組遍歷方法(當然,數(shù)組還存在下標屬性更新不了以及數(shù)組長度不可響應式改變的問題,具體參考issues;這些在vue3.0中使用proxy代替Object.defineProperty()時得到了解決),下面是關(guān)于vue的數(shù)組遍歷方法v-for的使用:

Home.vue

<template>
  <div class="home">
    <Hello-World />
    <Mock-Test />
    <button @click="userTest">試試</button>
  <!-- 下面兩種方式進行遍歷都可以,index是數(shù)組下標0,1,2...,item是id序號1,2,3... -->
  <!-- 當兩種標簽遍歷方式都存在時,只用item的遍歷會報key重復錯誤(應該是DOM結(jié)構(gòu)沖突),
       因此最好使用item和index同時定位對象的遍歷方式 -->
  <p>{{userList}}</p>
  <p v-for="item in userList" :key="item.id">{{item}}</p>
  <!-- 使用單item作為參數(shù)的方式最好不要獲取詳細到具體key的值,否則會提示錯誤,因此這種適合整個對象的獲取 -->
  <!-- <p v-for="(item,index) in userList" :key="index">{{item.id}}</p> -->

  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import MockTest from '@/components/MockTest.vue' // 這里不能使用./AxiosTest.vue的方式引入

export default {
  name: 'Home',
  components: {
    HelloWorld,
    MockTest
  },
  data () {
    return {
      userList: '' // 注意: 這里為對象數(shù)組時參數(shù)時定義為userList:[](適用于單個對象)的話會默認產(chǎn)生一個[]符號,
    }
  },
  // created () { // 或created: function(),為生命周期函數(shù)created,也可以是mounted—已掛載,可在頁面加載時自動執(zhí)行方法
  //   this.userTest()
  // },
  methods: {
    userTest () {
      this.$axios.post('/user/getAll') // 'https://v1.alapi.cn/api/music/search?keyword=我愛你'
        .then(res => {
          // 響應體獲取測試
          // console.log(res)
          // console.log(res.data) // 這里采用逐步分層取值的方式測試
          // console.log(res.data[0])
          // console.log(res.data[0].name)
          // console.log(res.data[res.data[0].id].name) // 嵌套取值
          // console.log(res.data.length)

          // var _this = this// 這句話的位置需要注意
          // console.log(this)// 依然是這個方法的對象
          // console.log(_this) // 這個變成了原來的對象

          // 循環(huán)取值測試(因為this的指針變化問題,不可行,因為this無論是否處于嚴格模式下都引用全局對象。)
          for (var i = 0; i < res.data.length; i++) { // 遍歷出所有對象
            // 將對象合并(for循環(huán)遍歷賦值、Object.assign()、序列化、淺拷貝、深拷貝(不會覆蓋對象)、foreach遍歷(測試成功))
            // 1.遍歷賦值
            // this.userList = res.data[i] // 測試發(fā)現(xiàn)只有id為2(即:第二個對象)對象的值,說明userList的this指向被修改了
            // console.log(this.userList)
            // 2.Object.assign()
            // var objList = Object.assign({}, res.data[i]) // 參數(shù)表示,測試時也可以直接用常數(shù)表示
            // console.log(objList)
            // this.userList >= objList
            // 3.序列化
            // const obj = JSON.parse(JSON.stringify(res.data[i]))
            // this.userList = obj
            // console.log(obj)
            // 淺拷貝與深拷貝需要下載JQuery,暫時沒有嘗試
          }

          // 4.foreach遍歷測試
          // var list = ['750', '1080', '1125', '1242', '1242']
          // var data = []
          // Object.keys(list).forEach(key => {
          //   let item = {
          //     val: list[key]
          //   }
          //   data.push(item)
          // })
          // console.log(list)
          // 正式使用
          // var list = res.data
          // var data = []
          // Object.keys(list).forEach(key => { // 因為這里使用了ES6語法中的 => 鉤子函數(shù),因此將不會
          //   data.push(list[key])
          // })
          // this.userList = data
          // console.log(data)

          this.userList = res.data
          console.log(res.data)
          // axios的response采用默認參數(shù)data存放數(shù)據(jù),這里只需要傳data的值就行了,
          // 否則要從一個加了其他參數(shù)的多重JSON對象中取值,無異于自己設(shè)計一個JSON序列化工具
          // 注意:這里res.data前不需要加this指針,因為箭頭函數(shù)沒有自己的this(因此本身是局部變量),
          // 箭頭函數(shù)里面的this是對象的指針(定義時的全局變量),如果加了this那么將獲取不到res.data的值
        })
        .catch(err => {
          console.log(err)
        })
    }
  }
}
</script>

啟動項目,成功獲取到數(shù)據(jù):


20210119222352.png

前后端數(shù)據(jù)請求成功!

小結(jié)

前后端打通了,下面就是項目UI框架的集成了,沖沖沖????

我是Java白羊??,一只想做全棧的小羊,感謝大家的觀看ヾ(?°?°?)??!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容