Spring Boot 与 Vue.js 整合流程

时间:2021-12-16 02:59:12

一直都想尝试做前后端分离,我之前一直是学 java 的,所以后端选择了 spring boot;前端选择了 vue.js 这个轻量、易上手的框架。网上其实已经有了不少 spring boot 和 vue.js 整合的资料,github 上就有好多 repo,但是每当我指望按图索骥的时候就会出现各种各样奇怪的 bug,上 stack overflow 问了也没人搭理。前前后后研究了差不多三个星期,现在总算是理清楚了。

本文重点介绍我在实践过程中的基本流程,以及我遇到的一个困扰了我好久的问题,就是如何 cors。

框架版本

  • spring boot: 2.0.4.release(jdk 是1.8)
  • vue.js: 2.x

基本流程

前端:编写 vue 组件

首先用 vue-cli 搭好脚手架,我这个 demo 用到的第三方库有:

  • axios:负责 http 请求
  • bootstrap-vue:bootstrap 和 vue.js 的整合,方便设计页面
  • vue-router:管理路由
  • qs:实现 cors

然后写一个登录组件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!-- 下面是我直接从 bootstrap-vue 文档抄下来的模板 -->
<template>
 <div>
 <b-form @submit="onsubmit" @reset="onreset" v-if="show">
  <b-form-group id="exampleinputgroup1"
     label="username:"
     label-for="exampleinput1">
  <b-form-input id="exampleinput1"
      type="text"
      v-model="form.username"
      required
      placeholder="enter username">
  </b-form-input>
  </b-form-group>
  <b-form-group id="exampleinputgroup2"
     label="password:"
     label-for="exampleinput2">
  <b-form-input id="exampleinput2"
      type="text"
      v-model="form.password"
      required
      placeholder="enter password">
  </b-form-input>
  </b-form-group>
  <b-form-group id="examplegroup4">
  <b-form-checkbox-group v-model="form.checked" id="examplechecks">
   <b-form-checkbox value="me">check me out</b-form-checkbox>
   <b-form-checkbox value="that">check that out</b-form-checkbox>
  </b-form-checkbox-group>
  </b-form-group>
  <b-button type="submit" variant="primary">submit</b-button>
  <b-button type="reset" variant="danger">reset</b-button>
 </b-form>
 </div>
</template>
<script>
//...
</script>

我现在想实现的就是用户登录成功之后导航到另一个组件,所以我就又写了一个欢迎组件:

?
1
2
3
4
5
<template>
 <div>
  <h1>welcome!</h1>
 </div>
</template>

记得配置路由:

// src/router/index.js

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import vue from 'vue'
import router from 'vue-router'
import login from '@/components/login.vue'
import information from '@/components/information.vue'
vue.use(router)
export default new router({
 routes: [
 {
  path: '/',
  name: 'login',
  component: login
 },
 {
  path: '/information',
  name: 'information',
  component: information
 }
 ]
})

后端:提供 restful api

因为只有后端提供了接口,前端才能调用,所以现在要进行后端开发。restful 是现在很流行的 api 设计风格,所以我这里也实践了一下。下面是 controller 的代码,完整源码地址附在文末。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@restcontroller
@requestmapping("/api")
public class logincontroller {
 @requestmapping(path = "/login", method = requestmethod.post)
 @responsebody
 public string login(@requestparam string username,
      @requestparam string password) {
  // 简单处理一下,实际开发中肯定是要用到数据库的
  if (username.equals("123") && password.equals("123")) {
   return "successful";
  } else {
   return "failed";
  }
 }
}

后端的 api 现在有了,就差前端调用了。但是没这么简单,接下来就要解决我前面提到的问题。

实现 cors

在这个 demo 中前端占用的端口是8080,后端是 8088。这就存在跨域的问题,如果不解决的话后端就没法接收前端的请求。

我参考了 这个例子 ,通过配置 spring mvc 实现了 cors:

?
1
2
3
4
5
6
7
8
9
10
11
@configuration
public class corsconfig implements webmvcconfigurer {
 @override
 public void addcorsmappings(corsregistry registry) {
  registry.addmapping("/**")
    .allowedorigins(all)
    .allowedmethods(all)
    .allowedheaders(all)
    .allowcredentials(true);
 }
}

后端配置好了还不行,前端也要有一些配置,要用 axios 顺利地发送请求并保证后端能接收到,需要对请求参数做处理。我参考 这个回答 用 qs 库对请求参数做了处理:

?
1
2
3
4
qs.stringify({
  'username': this.form.username,
  'password': this.form.password
  })

现在只需完善前端调用后端 api 的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// login.vue
<script>
export default {
 data () {
 return {
  form: {
  username: '',
  password: '',
  checked: []
  },
  show: true
 }
 },
 methods: {
 onsubmit (evt) {
  evt.preventdefault();
  
  // 关键就在于要对参数进行处理
  axios.post('http://localhost:8088/api/login',qs.stringify({
  'username': this.form.username,
  'password': this.form.password
  })).then((response) => {
  var status = response.data;
  if(status === 'successful') {
   this.$router.push('/information');
  } else {
   alert(response.data.message);
  }
  console.log(response);
  }).catch((error) => {
  console.log(response);
  });
 }
 }
}
</script>

至此,终于实现了前后端的分离,并且保证前后端能够顺利交互。

题外话

让 controller 能获取请求参数

  controller 可能无法获取请求参数, 这篇文章 提供了一种解决方案。我这个 demo 中并没有出现 controller 收不到请求参数的问题,但也把这个问题记录下来,以后可能遇上也说不准。

axios 方法中的 this

我这个 demo 中还试着用 axios 发 get 请求,然后获取后端响应的 json 数据。

?
1
2
3
4
5
6
7
8
9
10
11
12
// information.vue
<template>
 <div>
  <h1>welcome!</h1>
  <div>
   <b-button @click="getinfo()">get your information</b-button>
   <h2 v-if="username !== ''">your username is: {{ username }}</h2>
   <h2 v-if="email !== ''">your email is: {{ email }}</h2>
  </div>
 </div>
</template>
<script>
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import axios from 'axios'
 
export default {
 data () {
  return {
   username: '',
   email: ''
  };
 },
 methods: {
  getinfo () {
   axios.get('http://localhost:8088/api/information')
   .then(function(response) {
    this.username = response.data['username'];
    this.email = response.data['email'];
    console.log(response);
   }).catch(function(error) {
    console.log(error);
   });
  }
 }
}
</script>

一开始我是这么写的,乍一看没什么问题,但是 javascript 就一直报错:

typeerror: cannot set property 'username' of undefined

搞了很久都没有解决,直到看到 这篇文章 ,才明白原来是 this 作用域的问题(javascript 的 this 是真的复杂啊!!!)。改成下面这样就没问题了:

?
1
2
3
4
5
6
7
8
axios.get('http://localhost:8088/api/information')
   .then((response) => {
    this.username = response.data['username'];
    this.email = response.data['email'];
    console.log(response);
   }).catch((error) => {
    console.log(error);
   });

后来 stack overflow 上有人说不用箭头函数也行,只需提前把指向 vue 实例的 this 保存在一个变量就行了:

?
1
2
3
4
5
6
7
8
9
var vue = this;
   axios.get('http://localhost:8088/api/information')
   .then(function (response) {
    vue.username = response.data['username'];
    vue.email = response.data['email'];
    console.log(response);
   }).catch((error) => {
    console.log(error);
   });

经实践,这样也是可以的。

demo 完整源码

总结

以上所述是小编给大家介绍的spring boot 与 vue.js 整合流程,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:https://www.jianshu.com/p/4402545763c8