Spring Boot 与 Vue.js 整合流程
一直都想尝试做前后端分离,我之前一直是学 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
然后写一个登录组件:
<!-- 下面是我直接从 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>
我现在想实现的就是用户登录成功之后导航到另一个组件,所以我就又写了一个欢迎组件:
<template> <div> <h1>welcome!</h1> </div> </template>
记得配置路由:
// src/router/index.js
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 的代码,完整源码地址附在文末。
@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:
@configuration public class corsconfig implements webmvcconfigurer { @override public void addcorsmappings(corsregistry registry) { registry.addmapping("/**") .allowedorigins(all) .allowedmethods(all) .allowedheaders(all) .allowcredentials(true); } }
后端配置好了还不行,前端也要有一些配置,要用 axios 顺利地发送请求并保证后端能接收到,需要对请求参数做处理。我参考 这个回答 用 qs 库对请求参数做了处理:
qs.stringify({ 'username': this.form.username, 'password': this.form.password })
现在只需完善前端调用后端 api 的代码:
// 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 数据。
// 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>
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 是真的复杂啊!!!)。改成下面这样就没问题了:
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 保存在一个变量就行了:
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 整合流程,希望对大家有所帮助
推荐阅读
-
Spring Boot 与 Vue.js 整合流程
-
Spring Boot中扩展XML请求与响应的支持详解
-
Spring与Mybatis的整合方法有哪些
-
Spring与Mybatis的整合方法有哪些
-
Spring Boot与React集成的示例代码
-
JEE与Spring Boot代码性能比较分析
-
SpringBoot定时任务两种(Spring Schedule 与 Quartz 整合 )实现方法
-
详解Spring Boot 部署与服务配置
-
详解Spring Boot整合Mybatis实现 Druid多数据源配置
-
SpringBoot定时任务两种(Spring Schedule 与 Quartz 整合 )实现方法