• eyb:项目介绍到获取用户信息功能实现(一)



    (1)项目介绍

    (2)创建项目

    (3)项目结构介绍

    (4)登录页面的编写

    (5)处理登陆事件

    (6)配置相应拦截器

    (7)配置请求转发解决跨域

    (8)登录成功跳转页面

    (9)导航栏功能实现

    (10)安装Vuex

    (11)封装菜单请求工具类

    (13)路由导航守卫介绍

    (14)菜单功能完整实现

    (15)获取用户信息功能实现


    (1)项目介绍

    为什么要学习云E办呢?

      因为受今年疫情的影响,很多企业从之前的线下办公,转到线上办公,线上办公页一度成为了微博的热搜词,可见线上办公热度也是非常高的。线上办公的人数增多,我们也发现了线上办公的优点,比如说可以实现办公流程的自动化,节省企业办公费用,实现绿色办公,同时呢也可以去提高我们的工作效率…由于这些优点,线上办公已经成为了当今的一个主流趋势。

    我们的项目主要目的是为了实现中小型企业的在线办公系统,是用来管理日常办公事务的一个系统,能够管理的内容非常的多,比如说:日常的各种流程的审批呀,公告啊,财务,人事,资产,行政,项目移动办公等等…最主要的一个作用是通过以软件的形式,让我们办公系统更加方便管理,更加简单,高效规范,能够提高管理运营水平,就想我们的项目名字一样,让我们的办公更容易。

    这个项目在技术方面采用了最主流前后端分离开发的模式,后端采用SpringBoot MVC MyBatis-plus 安全框架用了Spring Security

    基本Vue全家桶

    项目搭建:vue-cli

    状态管理:Vuex

    路由:VueRouter

    UI界面:elementUI

    通讯框架:Axios

    前端语法:ES6

    打包:Webpack

    在线聊天:WebSocket

    字体:font-awesome

    文件上传下载:js-file-download

    在线聊天开源项目:vue-chat

     (2)创建项目

    首先下载Node.js:

    之后: 

    安装vue-cli:下面是新版本的安装办法:

     查看是否安装成功:

     创建项目:使用Windows PowerShell搭建项目

     进入一个目录创建yeb项目

    如果出现问题:运行命令 

     不使用骨架,我们手动去选,选择第二项

     

    选择一些东西:先选择这两个

     下面直接选择:no

    创建完成:

     启动项目:

    启动成功 

     浏览器可以正常访问:

    (3)项目结构介绍

     我们这里使用WebStorm进行打开编辑,也可以使用IDEA,但是需要安装一个插件vue.js就可以了

    第一个目录是整个项目用的依赖:可以通过npm install 去安装依赖了

    public目录:有一个图标,一个index.html:它相当于是项目的入口,可以理解为首页,或模板页,在实际开发中用不到,因为vue的话开发出来的叫做单页面应用,就一个html的页面,剩下的叫做组件

    这个项目是单页面应用,所以有一个index.html,只是作为模板页,在开发中用不到,真正的入口在main.js

    src:是项目的原码目录 

    assets:放一些资源的 component:组件目录 router:路由的目录(在创建项目的时候选了路由,所以这里有这个目录)views:页面目录

    main.js:整个程序的入口了  import是ES6的语法,当被babel打包的时候转成ES5的语法,ES5是reequire

    Vue.config.productionTip = false :关闭浏览器对应的提示 当为true的时候,会开启提示:

    render: h => h(App) :是渲染我们对应的组件

     .$mount('#app'):是手动挂和之前通过el:‘#app‘ 是一样的

     
    

     

    .gitgnore:git的忽略的配置文件

    bable.config.js:是babel的配置文件,主要是将ES6的语法转换成ES5 

    README.md:项目说明

    package.json:项目的配置文件

    scrips下面是封装的常用的命令 向server启动服务啊 build:构建 他们都是可以直接去运行的  小路三角

    dependercies:正式环境用到的依赖

    devDependencies:开发环境用到的依赖

     配置一下启动项目:

     (4)登录页面的编写

    vue是关注度分离的,所以没办法提供UI的操作,需要安装ElementUI

    安转完之后,package.json:多个elementUI

     引入到项目中去使用:main.js

     修改一下App.vue:

    删除这两个组价:

    在views目录下创建Login.vue组件: 

     

    配置路由:

    1. import Vue from 'vue'
    2. import VueRouter from 'vue-router'
    3. import Login from "@/views/Login";
    4. Vue.use(VueRouter)
    5. const routes = [
    6. {
    7. //加载斜杠,会找到Login
    8. path: '/',
    9. name: 'Login',
    10. component: Login
    11. },
    12. ]
    13. const router = new VueRouter({
    14. routes
    15. })
    16. export default router

    Login.vue:

    (5)处理登陆事件

    首先去校验一下用户明密码不能为空,添加校验规则:

    添加@click

     添加 :rules=“rules”

     

     

     (6)配置相应拦截器

    下面需要调用后端的接口,去实现相关的 功能,那怎么去调呢?Vue注重关注度分离原则的,Vue框架并没有通讯的能力,提倡使用Axios框架进行通信

    安装Axios

     在package.json:里面加入了axios:

     下面就可以写我们的请求了,比如说在登录这一块直接通过axios去调用后端的接口,然后进行相应的返回,仅进行处理,那么每一个事件需要调用后端接口,都需要写axios框架,有一个问题,你这个请求有可能成功有可能失败,成功有成功的处理方法,失败有失败的处理方法,也就是说每一个调用后端接口的方法,都要去判断你的请求是否成功或者失败,每一个地方都要去做,过于麻烦了,这个时候我们可以把它封装起来,用统一的响应拦截器,判断它是否成功或者失败,失败的话把它提示出来,省略了响应的处理了:

    创建目录utils 创建配置 api.js:

    1. import axios from 'axios'
    2. //导入elemenui的提示信息
    3. import {Message} from "element-ui";
    4. import router from '../router'
    5. import Vue from 'vue'
    6. axios.defaults.baseURL = '/'
    7. Vue.prototype.axios = axios
    8. // 请求拦截器
    9. axios.interceptors.request.use(config=>{
    10. if (window.sessionStorage.getItem('tokenStr')) {
    11. //请求携带自定义token
    12. config.headers['Authorization'] =
    13. window.sessionStorage.getItem('tokenStr');
    14. }
    15. return config
    16. },error => {
    17. console.log(error);
    18. })
    19. //响应拦截器 请求的统一的处理
    20. axios.interceptors.response.use(success => {
    21. //业务逻辑错误 成功调到接口返回响应码200
    22. if (success.status && success.status == 200) {
    23. //后端返回的 code
    24. if (success.data.code == 500 || success.data.code == 401 ||
    25. success.data.code == 403) {
    26. //输出返回响应信息
    27. Message.error({message: success.data.message});
    28. return;
    29. }
    30. //后端返回响应信息
    31. if (success.data.message) {
    32. Message.success({message: success.data.message});
    33. }
    34. }
    35. return success.data;
    36. //error表示没有调到后端接口
    37. }, error => {
    38. if (error.response.code == 504 || error.response.code == 404) {
    39. Message.error({message: '服务器被吃了o(╯□╰)o'});
    40. } else if (error.response.code == 403) {
    41. Message.error({message: '权限不足,请联系管理员!'});
    42. } else if (error.response.code == 401) {
    43. Message.error({message: '尚未登录,请登录'});
    44. router.replace('/');
    45. } else {
    46. if (error.response.data.message) {
    47. Message.error({message: error.response.data.message});
    48. } else {
    49. Message.error({message: '未知错误!'});
    50. }
    51. }
    52. return;
    53. });
    54. let base = '';//访问地址后来可能加的东西,如果需要加的话直接修改base
    55. //传送json格式的post请求
    56. export const postRequest = (url, params) => {
    57. return axios({
    58. method: 'post',
    59. url: `${base}${url}`,
    60. data: params
    61. })
    62. }
    63. //封装请求
    64. //传递json的put请求
    65. export const putRequest = (url, params) => {
    66. return axios({
    67. method: 'put',
    68. url: `${base}${url}`,
    69. data: params
    70. })
    71. }
    72. //传递json的get请求
    73. export const getRequest = (url, params) => {
    74. return axios({
    75. method: 'get',
    76. url: `${base}${url}`,
    77. data: params
    78. })
    79. }
    80. //传递json的delete请求
    81. export const deleteRequest = (url, params) => {
    82. return axios({
    83. method: 'delete',
    84. url: `${base}${url}`,
    85. data: params
    86. })
    87. }

     (7)配置请求转发解决跨域

    先获取后端的验证码,请求后端的接口:

    在Login.vue里面

     

     访问:图片没有正常显示,

    它默认是访问前端的接口 ,前端没有接口,后端的接口是8081,这时候就涉及到跨域:我们8080接口去调8081接口,需要进行跨域:

    用了简单的办法:Node.js的代理类去转发,也就是说我们请求还是请求8080,但是请求到Nodejs哪里,Nodejs会给我们转发到8081

     

     新建一个配置:vue.config.js:进行跨域配置:

    1. //新建代理
    2. let proxyObj = {}
    3. proxyObj['/ws'] = {
    4. ws: true,
    5. target: 'ws://localhost:8081'
    6. };
    7. proxyObj['/'] = {
    8. //websocket
    9. ws: false,
    10. //目标地址
    11. target: 'http://localhost:8081',
    12. //发送请求头中host会设置成target
    13. changeOrigin: true,
    14. //不重写请求地址
    15. pathRewrite: {
    16. '^/': '/'
    17. }
    18. }
    19. //默认访问的路径端口
    20. module.exports = {
    21. devServer: {
    22. host: 'localhost',
    23. port: 8080,
    24. proxy: proxyObj //代理转发
    25. }
    26. }

    重启项目,就获取到后端的验证码 

    (8)登录成功跳转页面

     先准备home.vue的组件:用来测试登录成功的

     在路由配置中配置home路由:

    1. import Vue from 'vue'
    2. import VueRouter from 'vue-router'
    3. import Login from "@/views/Login";
    4. import Home from '../views/Home'
    5. Vue.use(VueRouter)
    6. const routes = [
    7. {
    8. //加载斜杠,会找到Login
    9. path: '/',
    10. name: 'Login',
    11. component: Login
    12. },
    13. {
    14. path:'/home',
    15. name:'Home',
    16. component:Home
    17. }
    18. ]
    19. const router = new VueRouter({
    20. routes
    21. })
    22. export default router

    先封装请求拦截器:把token放到请求头里面,上面已经写过这个代码

     

     使用ElementUI的组件:登录的时候动画加载显示:

     在Login.vue:el-form中添加:

     

    输入了postRequest之后会自动需要导入:可以把它加入main.js,当在调用的时候用this.postRequest 

    main.js:

    1. import Vue from 'vue'
    2. import App from './App.vue'
    3. import router from './router'
    4. //引入elementUI
    5. import ElementUI from 'element-ui';
    6. import 'element-ui/lib/theme-chalk/index.css';
    7. import {postRequest} from "./utils/api";
    8. import {putRequest} from "./utils/api";
    9. import {getRequest} from "./utils/api";
    10. import {deleteRequest} from "./utils/api";
    11. Vue.use(ElementUI);
    12. //插件形式使用请求
    13. Vue.prototype.postRequest=postRequest;
    14. Vue.prototype.putRequest=putRequest;
    15. Vue.prototype.getRequest=getRequest;
    16. Vue.prototype.deleteRequest=deleteRequest;
    17. Vue.config.productionTip = false
    18. new Vue({
    19. router,
    20. render: h => h(App)
    21. }).$mount('#app')

    Login.vue组件 

     

    点击登录:

     (9)导航栏功能实现

    创建两个子组件:Test1.vue、Test2.vue

    更改Home.vue:

    这里是通过事件进行跳转:以后会有很多很多的菜单,发现以后会写很多的路由,需要频繁的在路由配置里面去添加,那我们频繁的添加菜单的时候,操作步骤是重复的,所以可以把菜单和路由数据统一起来,将路由数据动态渲染到菜单上去

     路由配置:index.js

    1. import Vue from 'vue'
    2. import VueRouter from 'vue-router'
    3. import Login from "@/views/Login"
    4. import Home from '../views/Home'
    5. import Test1 from "../views/Test1";
    6. import Test2 from "../views/Test2";
    7. Vue.use(VueRouter)
    8. const routes = [
    9. {
    10. //加载斜杠,会找到Login
    11. path: '/',
    12. name: 'Login',
    13. component: Login,
    14. hidden:true
    15. },
    16. {
    17. path:'/home',
    18. name:'导航一',
    19. component:Home,
    20. children:[
    21. {
    22. path:'/test1',
    23. name:'选项1',
    24. component:Test1
    25. },
    26. {
    27. path:'/test2',
    28. name:'选项2',
    29. component:Test2
    30. }
    31. ]
    32. }
    33. ]
    34. const router = new VueRouter({
    35. routes
    36. })
    37. export default router

     更改Home.vue:

    (10)安装Vuex

    导航栏已经写好了,可以实现菜单的功能,怎么实现呢?两种办法:

    第一种,可以在路由配置中去写,根据有多少菜单,在路由配置中写死就行了,这是比较简单的

    第二种:是从后端获取对应的一个菜单数据,然后在我们前端路由这边进行一个相应的转化,为什么从后端获取数据呢?因为这些菜单不能说一直是写死的,就是这些,更能会有变更,变更之后,还要在路由配置中修改,这是比较麻烦的

    所以我们选择去后端获取,数据库中存好了,变更之后,数据库也会变,变好之后呢,我们数据是从菜单接口数据获取的,菜单就没必要手动的修改了

    通过后端接口获取菜单:

    有了这个菜单之后,把菜单存到哪里?

    Local Storage Session Storage可以存放我们的菜单,除了这两种,还可以使用Vuex,vuex本质上就是为vue开发的状态管理模式,它采用集中式管理应用的所有组件的状态,并且以相应的规则去保证状态呢以一种可预测的方式发生变化,可以理解为整体的数据的状态管理,只不过它不是存放到浏览器的Session Storage上面,它直接存放在vuex对应的内存里面,Session Storage存储的对用户是可见的

     

     安装vuex:

    安装的时候出现问题: 

    下载完之后:package.json:多了vuex

    创建目录:store,创建配置index.js

     这里只是简单的写了下配置,以后还会继续写

    1. import Vue from 'vue'
    2. import Vuex from 'vuex'
    3. Vue.use(Vuex)
    4. export default new Vuex.Store({
    5. //state可以理解为全局的对象,用来保存组件的公共数据
    6. state:{
    7. routes:[]
    8. },
    9. //mutations:表示可以改变state里面的对应值的一个对应方法(同步执行的)异步执行的是actions方法
    10. mutations:{
    11. //初始化路由
    12. initRoutes(state,data){
    13. state.routes=data;
    14. }
    15. }
    16. })

    在main.js引入vuex的配置

    加一个store:

    (11)封装菜单请求工具类

     要获取到后端的菜单数据,后端的是一个字符串,需要把它转换为前端所需要的一个对象,并且把这个数据放到路由的配置里面去,我们需要封装一个菜单请求工具类去实现我们的要求

    创建menus.js: 

    1. import {getRequest} from "./api";
    2. export const initMenu = (router, store) => {
    3. //先判断store中的state是否为空
    4. if (store.state.routes.length > 0) {
    5. return;
    6. }
    7. //get请求调用接口/system/cfg/menu:,初始化 data:拿到的数据
    8. getRequest("/system/cfg/menu").then(data => {
    9. //判断data是否存在
    10. if (data) {
    11. //格式化router
    12. let fmtRoutes = formatRoutes(data);
    13. //添加到router
    14. router.addRoutes(fmtRoutes);
    15. //将数据存入vuex
    16. store.commit('initRoutes', fmtRoutes);
    17. }
    18. })
    19. }
    20. //格式化数据方法
    21. export const formatRoutes = (routes) => {
    22. let fmRoutes = [];
    23. routes.forEach(router => {
    24. let {
    25. path,
    26. component,
    27. name,
    28. meta,
    29. iconCls,
    30. children,
    31. } = router;
    32. if (children && children instanceof Array) {
    33. //递归
    34. children = formatRoutes(children);
    35. }
    36. //格式化
    37. let fmRouter = {
    38. path: path,
    39. name: name,
    40. meta: meta,
    41. iconCls: iconCls,
    42. children: children,
    43. component(resolve) {
    44. require(['../views/' + component + '.vue'], resolve);
    45. }
    46. }
    47. fmRoutes.push(fmRouter);
    48. })
    49. return fmRoutes;
    50. }

    (12)完善菜单请求工具类

    创建组件:一 一的创建出来,以EmpAdv为例:其他的不写了

     修改菜单配置menu.js:

    1. import {getRequest} from "./api";
    2. //初始化方法
    3. export const initMenu = (router, store) => {
    4. //先判断store中的state是否为空
    5. if (store.state.routes.length > 0) {
    6. return;
    7. }
    8. //get请求调用接口/system/cfg/menu:,初始化 data:拿到的数据
    9. getRequest("/system/cfg/menu").then(data => {
    10. //判断data是否存在
    11. if (data) {
    12. //格式化router
    13. let fmtRoutes = formatRoutes(data);
    14. //添加到router
    15. router.addRoutes(fmtRoutes);
    16. //将数据存入vuex
    17. store.commit('initRoutes', fmtRoutes);
    18. //连接websocket
    19. //store.dispatch('connect');
    20. }
    21. })
    22. }
    23. //格式化数据方法
    24. export const formatRoutes = (routes) => {
    25. let fmRoutes = [];
    26. routes.forEach(router => {
    27. let {
    28. path,
    29. component,
    30. name,
    31. meta,
    32. iconCls,
    33. children,
    34. } = router;
    35. if (children && children instanceof Array) {
    36. //递归
    37. children = formatRoutes(children);
    38. }
    39. //格式化
    40. let fmRouter = {
    41. path: path,
    42. name: name,
    43. meta: meta,
    44. iconCls: iconCls,
    45. children: children,
    46. component(resolve) {
    47. if (component.startsWith("Home")) {
    48. require(['../views/' + component + '.vue'], resolve);
    49. } else if (component.startsWith("Emp")) {
    50. require(['../views/emp/' + component + '.vue'], resolve);
    51. } else if (component.startsWith("Per")) {
    52. require(['../views/per/' + component + '.vue'], resolve);
    53. } else if (component.startsWith("Sal")) {
    54. require(['../views/sal/' + component + '.vue'], resolve);
    55. } else if (component.startsWith("Sta")) {
    56. require(['../views/sta/' + component + '.vue'], resolve);
    57. } else if (component.startsWith("Sys")) {
    58. require(['../views/sys/' + component + '.vue'], resolve);
    59. }
    60. }
    61. }
    62. fmRoutes.push(fmRouter);
    63. })
    64. return fmRoutes;
    65. }

     (13)路由导航守卫介绍

    现在把菜单请求工具类写完了,就是在什么时候调用initMenu初始化方法,去初始化菜单,毫无疑问,就是在登录的时候,但是需要考虑,现在是把菜单放在vuex里面的,也就类似内存里面,而且现在是浏览器的运用,如果用户按下了刷新按钮,就会可能被初始化数据(空数据)刷新,菜单就可能丢失,怎么解决丢失呢?

    比如说在Home.vue按了F5刷新,那我页面Home添加上初始化,菜单就行了呀!这样处理也可以,但是需要考虑用户不只是在Home页,按F5刷新,比如说在高级资料EmpAdv去刷新,那么之前放在Home页的初始化菜单,它也没有办法去调,也就不会生效,还会出现菜单丢失的情况,那怎么解决,只能在每个页面添加初始化菜单的方法,这样是非常麻烦的,那我们还有非常简单的东西叫:“路由导航守卫”

     

     

    to:是跳转到那个路由

    from:是从那个路由跳转的

    next():如果没有next() 是不能实现跳转的

    (14)菜单功能完整实现

    main.js:

    1. import Vue from 'vue'
    2. import App from './App.vue'
    3. import router from './router'
    4. //引入vuex
    5. import store from "./store";
    6. //引入elementUI
    7. import ElementUI from 'element-ui';
    8. import 'element-ui/lib/theme-chalk/index.css';
    9. import {postRequest} from "./utils/api";
    10. import {putRequest} from "./utils/api";
    11. import {getRequest} from "./utils/api";
    12. import {deleteRequest} from "./utils/api";
    13. import {initMenu} from "./utils/menus";
    14. Vue.use(ElementUI);
    15. //插件形式使用请求
    16. Vue.prototype.postRequest=postRequest;
    17. Vue.prototype.putRequest=putRequest;
    18. Vue.prototype.getRequest=getRequest;
    19. Vue.prototype.deleteRequest=deleteRequest;
    20. Vue.config.productionTip = false
    21. //路由导航守卫
    22. router.beforeEach((to,from,next)=>{
    23. ///登录的时候把token放在了sessionStorage里面,可以去判断是否有这个token
    24. if (window.sessionStorage.getItem('tokenStr')) {
    25. //初始化菜单
    26. initMenu(router, store);
    27. next();
    28. }else{
    29. next();
    30. }
    31. })
    32. new Vue({
    33. router,
    34. store,
    35. render: h => h(App)
    36. }).$mount('#app')

    更改Home.vue:

     

    更换一下图标:图标是font-awesome的图标需要安装:

     

    在main.js:导入css

     

    然后更改Home.vue:

     (15)获取用户信息功能实现

    先设置一下标题:

    Home.vue:

    设置样式:

     添加头像:

    首先在main.js中添加:

    在Home.vue中首先获取到用户信息,就可以进行相关的操作了:

    添加:表头信息:

     

     

  • 相关阅读:
    线段树
    (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
    HBR推荐|迎战未来必知的10大管理创新趋势
    ARMv8通用定时器简介
    Haproxy配合Nginx搭建Web集群
    linux中使用命令启动tomcat后显示tomcat started,实际却没启动的问题
    MyBatis查询数据库
    百度面试——机器学习
    Git基本应用<一>:Git安装及GitHub连接
    Vue 04 el和data的两种写法
  • 原文地址:https://blog.csdn.net/dengfengling999/article/details/126501478