EL-ADMIN 基于 Spring Boot 2.1.0 、 Spring Boot Jpa、 JWT、Spring Security、Redis、Vue、Element-UI 的前后端分离的后台管理系统, 项目采用按功能分模块的开发方式。本开发模块属于该项目前端。
Vue
vue-router
axios
element ui
使用vue-cli打开项目管理界面创建非常方便。直接在后台输入vue ui(需要vue-cli3.0以上版本)就可以打开项目管理界面。
在选好的目录下创建新项目,包管理选择npm。
接下来预设选择手动配置项目。
Babel:把JavaScript 中 es6 的新语法转化为 es5,让低端运行环境(如浏览器和 node )能够认识并执行)
Router:路由
Vuex:专为 Vue.js 应用程序开发的“状态管理模式”,采用集中式存储管理应用的所有组件的状态
然后下一步,等待项目自动初始化完成。
`|-- public 存放静态资源,存放在该文件夹的东西不会被打包影响,而是会原封不动的输出到dist文件夹中
|-- favicon.ico 网站图标
|-- index.html 主页,项目入口
|-- src
|-- api 后端请求接口文件
|-- assets 静态资源
|-- components 公用组件
|-- layout 系统布局:头部、侧边栏、设置、中间内容页面
|-- mixins 混入文件(CRUD混合模式)
|-- router 路由配置
|-- plugins 插件
|-- store vuex存放数据
|-- utils 工具包
|-- views 页面
|-- app.vue 根组件
|-- main.js 入口文件
|-- .gitignore git忽略上传的文件格式
|-- package.json 项目描述文件
|-- vue.config.js cli配置文件
有两种方式:
第一种,直接在main.js中下入这三行:
第二种,直接引入element.js文件(上面三行代码抽出来放到里面)
import './plugins/element.js'
这里直接把项目登录页面的样式和页面元素搬到login.vue。
然后把黄色波浪线的变量和方法都在login组件内。
标签也要注释掉,因为涉及到index.vue组件。
但这个时候还会存在一个问题,就是样式格式不兼容,页面全局比例不对。
解决方法有两个:
方法一,安装sass、sass-loader依赖(安装依赖后记得重启项目),把App.vue的样式都删掉,然后再main.js中引入准备好的全局样式index.scss。
import './assets/styles/index.scss'
方法二,不导入全局样式,直接在index.html中设置样式
body, html, #app{
height: 100%;
}
至此登录页面画好了,接下来就可以完成页面的底层逻辑了。
补充一下:
.vue文件由、
首先需要安装axios依赖:
npm install axios
为了使axios能够全局使用,要在main.js用import导入,并且将导入的axios赋值给Vue.prototype的$axios变量(变量名可随便取)中
注:
如果想用全局注册一些数据/实用工具,可以在main.js中将变量添加到 Vue.prototype(原型)中。
Vue.prototype.$appName = ‘My App’
这样 $appName 就在所有的 Vue 实例中可用了,甚至在实例被创建之前就可以。
重启使axios依赖生效后,将getCode()方法补全
getCode(){
//发送请求给后端,需要用到axios
this.$axios.get('http://localhost:8000/auth/code').then(resp =>{
this.codeUrl = resp.data.img;
this.loginForm.uuid = resp.data.uuid;
})
}
这样获取验证码的方法就写好了!
导入准备好的js工具文件rsaEncrypt.js,利用公钥对密码进行加密(密钥可自己生成)。
this.loginForm.password = encrypt(this.loginForm.password);
this.$axios.post('http://localhost:8000/auth/login',this.loginForm).then(resp => {
this.$router.push('/dashboard');
})
其中$router
是访问路由实例,$router.push
方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
push方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
// 字符串路径
router.push('/users/eduardo')
// 带有路径的对象
router.push({ path: '/users/eduardo' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })
将表单校验规则补全:
loginRules:{
username: [{required :true, trigger : 'blur' , message: '用户名不能为空'}],
password: [{required :true, trigger : 'blur' , message: '密码不能为空'}],
code: [{required :true, trigger : 'blur' , message: '验证码不能为空'}],
},
required设置是否必输,trigger设置触发条件。
还需在发送请求前判断校验结果,校验通过才能发送请求。
handleLogin(){
this.$refs.loginForm.validate( valid =>{
if(valid){
//如果表单校验通过,则发送登录请求
//密码加密
this.loginForm.password = encrypt(this.loginForm.password);
this.$axios.post('http://localhost:8000/auth/login',this.loginForm).then(resp=>{
this.$router.push('/dashboard');
})
}else alert("请按请求完善登录信息");
});
}
注意,这里通过this.$refs.loginForm获取的loginForm实例是由ref="loginForm"
将表单实例绑定上去的。
若请求得到失败响应后,我们需要对返回响应信息进行处理,提示失败信息。
这个时候就可以用到拦截器。
这里我们把axios放在新建的request.js工具文件中导入,再在main.js中引入该文件,然后给创建的axios实例添加响应拦截器。
import axios from "axios";
import ElementUI from "element-ui";
let request = axios.create();
//添加响应拦截器
request.interceptors.response.use(response => {
console.log("response");
return response;//固定格式
},
error => {
ElementUI.Message.error("请求失败!"+error);
return Promise.reject(error);//固定格式
}
)
export default request;
原先的Vue.prototype.$axios = axios
也要改成Vue.prototype.$request = request
,相应的this.$axios
要改成this.$request
。
如果后端很慢,这时候如果没有提示登录中的话,用户可能会再次点击登录,所以现在还需要实现以下请求等待的功能。
只需要在发送请求前把loading设置为true,请求结束后再设置会false就好了。
实现”记住我“功能实际上就是实现JWT的前端功能。
数据的交互过程:用户登录 -> 后端验证登录返回 token
-> 前端带上token
请求后端数据 -> 后端返回数据。
具体要实现的:
①保存用户名密码到cookies
②保存token到cookies
这里之前的this.loginForm也要改为user
③rememberMe判断是否要自动登录
还需要实现判断是否要跳过登录页面,这个时候就又涉及到路由的基础知识了。
在router/index.js中添加导航守卫(NavigationGuard),用来通过跳转或取消的方式守卫导航。
router.beforeEach((to,from,next)=> {
if(getToken()){//已登录
if(to.name === 'Login') next('/dashboard')
else next()
}else if(to.path !== '/') //若不是在根路径,则自动跳转到根路劲
next({path:'/'})
else next()
})
“to”: 即将要进入的目标 路由对象;(这个对象中包含name,params,meta等属性)
“from”: 当前导航正要离开的路由对象;(这个对象中包含name,params,meta等属性)
“next”: Function: 确保要调用 next 方法,否则钩子就不会被 resolved。这个当中还可以传一些参数,具体可以看官方文档。
这样记住我功能就实现好了。
实现注销功能需要请求后端接口删除该用户的token,同时前端Cookies也要删除该用户的token
logout(){
//请求后端接口删除该用户的token,同时前端Cookies也要删除该用户的token
this.$requset.delete('http://localhost:8000/auth/logout').then(res=>{
removeToken(config.TokenKey)
this.$Router.replace('/')
})
}
想要在每个请求头上加上token,需要使用到请求拦截器。
和之前响应拦截器一样,在request.js中添加:
//添加请求拦截器
request.interceptors.request.use(config => {
console.log('请求拦截!')
if(getToken()){
config.heads['Authorization'] = getToken()
}
return config
},
error => {
return Promise.reject(error)
})
由于axios默认的请求格式就是application/json, 所以这里是不用设置的。
注:一定要记得return!因为use接受两个函数作为参数,那么这两个函数就必须要有返回值。
一般,认证失败后,需要做的是自动注销并且跳转至登录页面。
首先,我们可以把登录相关的方法抽出来封装到login.js中。
import {removeToken} from "./auth";
import Config from '@/setting';
import router from "@/router";
import request from "./request";
export function logout(){
request.delete('http://localhost:8000/auth/logout').then(res =>{
removeToken(Config.TokenKey)
router.replace('/')
})
}
然后在响应拦截器中添加判断认证失败(401错误码)的操作,如果是认证失败就直接进行注销。
到这里登录页面的基本功能就已经都完成了!