剛剛實現了Vue+Vuex的自動登錄功能,在實現的時候遇到了一些問題,這里記錄一下:
因為這個還不夠完善,在寫完下列代碼后,又進行了補充,可以從https://www.cnblogs.com/xiaoxineryi/p/12405563.html 看到補充內容
一、對於vuex的簡單理解:
可以參考這個:https://zhuanlan.zhihu.com/p/24357762、https://segmentfault.com/a/1190000009404727
還有官網文檔:https://vuex.vuejs.org/zh/guide/getters.html
差不多理解就是,vuex里面,用state來存儲數據,在mutations里面寫保存數據的函數,並且提供給外部調用,在getters中寫獲取數據的函數,在actions里面寫獲取數據后、寫入數據前的處理過程。
二、在看網上很多示例的時候,代碼寫得挺好的,但是沒有總的項目目錄,一個函數一個函數的寫,卻又不知道要放在哪里,就感覺很別扭,所以我先把項目目錄列出來:因為只用到了src下的,其他的按新建項目的就好
①:上一章的前后端分離里面,數據傳遞確實做到了,但是在Login.vue里面寫的,很多重復的內容完全可以重用,所以這次干脆提出一個api來,專門用來傳遞數據。
另外,此次使用的是aoxis,本身就已經封裝好很多了。

import axios from 'axios' let base = 'http://127.0.0.1:8090'; export const postRequest = (url, params) => { return axios({ method: 'post', url: `${base}${url}`, data: params, transformRequest: [function (data) { // Do whatever you want to transform the data let ret = '' for (let it in data) { ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&' } return ret }], headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); }
base的路徑,按照自己服務器的端口進行修改。
②:現在先在store里,定義好數據和方法(就相當於數據庫):store/index.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { // 存儲token Authorization: localStorage.getItem('Authorization') ? localStorage.getItem('Authorization') : '' }, mutations: { // 修改token,並將token存入localStorage changeLogin (state, user) { // alert(user.Authorization); state.Authorization = user.Authorization; localStorage.setItem('Authorization', user.Authorization); } } }); export default store;
這里state里面就是存儲的數據,這里就是存儲用戶的token,下面mutations,寫了一個修改token的方法,這個方法將token寫入localStorage,而且保存到自己的state中。
③:定義好了數據和方法以后,自動登錄就是要在用戶訪問頁面的時候,自動檢查有沒有token,token對不對:

// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import ElementUI from 'element-ui' import VueResource from 'vue-resource' import 'element-ui/lib/theme-chalk/index.css' // import './styles/element-variables.scss' import './styles/font-awesome-4.7.0/css/font-awesome.min.css' import './utils/filter_utils.js' import store from './store' import axios from 'axios' Vue.use(ElementUI) // Vue.use(VueResource) Vue.config.productionTip = false // Vue.http.options.emulateJSON = true /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, components: { App }, template: '<App/>' }) axios.interceptors.request.use( config => { if (localStorage.getItem('Authorization')) { config.headers.Authorization = localStorage.getItem('Authorization'); } return config; }, error => { return Promise.reject(error); });
在這里面,有兩個需要注意的:
第一個就是,因為定義了store,所以在常規的main之外,還在Vue里面多加了一個store,否則的話,在使用的使用就相當於與沒有注冊,查找不到,經常有如下錯誤:
Cannot read property 'commit' of undefined
第二個就是下面的攔截器:因為只是對全局的訪問都配置,所以直接就在全局中寫了,而且前面是axios.interceptors.request.xx,前面的axios就表示了是全局的。
如果要對某個方法來使用,應該先創建一個axios,然后假設這個變量名為xx,則使用xx.interceptors來執行,后面用request或者response來表示是請求數據還是響應數據。
更詳細的可以看https://www.jianshu.com/p/646ed4edf51f
④:在router/index.js中,也就是路由里面,也需要添加內容:
import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import login from '@/components/login.vue' import home from '@/components/home.vue' import logo from '@/components/HelloWorld.vue' Vue.use(Router); const router = new Router({ mode:'history', routes:[ { path:'/login', name:'登錄', component:login, }, { path:'/', name:'主頁', component:logo, } ] }); router.beforeEach((to,from,next)=>{ if(to.path ==='/login'){ next(); }else { let token = localStorage.getItem('Authorization'); if(token ===null || token ===''){ next('/login'); }else { // alert(localStorage.getItem("Authorization")); next(); } } }); export default router;
第一點就是將router加上mode:'history',這個也不知道為啥,反正我寫的時候,沒有這個就不管什么頁面都跳轉到首頁,怎么調都不管用,加上這一句話就好了。
第二個就是定義了一個beforeEach的函數,這個可以檢測來的請求路徑、去的請求路徑,加上token檢測,可以讓用戶如果沒有登錄就自動跳轉到登錄界面。
⑤:再寫登錄頁面:
<template> <el-form :rules="rules" class="login-container" label-position="left" label-width="0px" v-loading="loading"> <h3 class="login_title">系統登錄</h3> <el-form-item prop="account"> <el-input type="text" v-model="loginForm.username" auto-complete="off" placeholder="賬號"></el-input> </el-form-item> <el-form-item prop="checkPass"> <el-input type="password" v-model="loginForm.password" auto-complete="off" placeholder="密碼"></el-input> </el-form-item> <el-checkbox class="login_remember" v-model="checked" label-position="left">記住密碼</el-checkbox> <el-form-item style="width: 100%"> <el-button type="primary" @click.native.prevent="submitClick" style="width: 100%">登錄</el-button> </el-form-item> </el-form> </template> <script> import {postRequest} from '../utils/api' import {putRequest} from '../utils/api' import { mapMutations } from 'vuex'; export default{ data(){ return { rules: { account: [{required: true, message: '請輸入用戶名', trigger: 'blur'}], checkPass: [{required: true, message: '請輸入密碼', trigger: 'blur'}] }, checked: true, loginForm: { username: '11', password: '123' }, loading: false } }, methods: { ...mapMutations(['changeLogin']), submitClick: function () { var _this = this; this.loading = true; postRequest('/login', { username: this.loginForm.username, password: this.loginForm.password }).then(resp=> { _this.loading = false; if (resp.status == 200) { //成功 var json = resp.data; if (json.status == 'success') { _this.userToken = 123; // localStorage.setItem('Authorization',_this.userToken); _this.changeLogin({Authorization:_this.userToken}); _this.$router.replace({path: '/'}); } else { _this.$alert('登錄失敗!', '失敗!'); } } else { //失敗 _this.$alert('登錄失敗!', '失敗!'); } }, resp=> { _this.loading = false; _this.$alert('找不到服務器⊙﹏⊙∥!', '失敗!'); }); } } } </script> <style> .login-container { border-radius: 15px; background-clip: padding-box; margin: 180px auto; width: 350px; padding: 35px 35px 15px 35px; background: #fff; border: 1px solid #eaeaea; box-shadow: 0 0 25px #cac6c6; } .login_title { margin: 0px auto 40px auto; text-align: center; color: #505458; } .login_remember { margin: 0px 0px 35px 0px; text-align: left; } </style>
這里一定不要忘了引入函數
⑥在這里我們可以看到,返回的是json數據,對應后台可以:先創建一個Bean,用來專門返回響應內容:
package com.example.Bean; public class RespBean { private String status; private String msg; public RespBean() { } public RespBean(String status, String msg) { this.status = status; this.msg = msg; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
而在controller中,直接調用即可:
package com.example.Controller; import com.example.Bean.RespBean; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @CrossOrigin(origins = "*") @RequestMapping("/login") public RespBean login( @RequestParam(value = "username", required = false) String username, @RequestParam(value = "password",required = false) String password, Model model ){ System.out.println("用戶名為"+username); System.out.println("密碼為"+password); if (username.equals("11")){ return new RespBean("success","登錄成功"); }else{ return new RespBean("fail","登錄失敗"); } } }