当前位置:   article > 正文

vue-admin-admin后台集成方案

vue-admin

一、 vue-admin-admin介绍

  • vue-element-admin是一个后台前端解决方案,它基于vue和element-ui实现。
  • vue-admin-template是基于vue-element-admin的一套后台管理系统基础模板(最少精简版),可作为模板进行二次开发。
  • 内置了i18国际化解决方案,动态路由,权限认证,提炼了典型的业务类型,提供了丰富的功能组件。
  • 可以快速搭建企业级中后台产品原型。
  • 地址:https://panjiachen.github.io/vue-element-admin-site/zh/guide/

建议:你可以在 vue-admin-template 的基础上进行二次开发,把 vue-element-admin当做工具箱,想要什么功能或者组件就去 vue-element-admin 那里复制过来。

二、目录分析

2.1 目录结构

在这里插入图片描述

|-dist 生产环境打包生成的打包项目
|-mock 产生模拟数据
|-public 包含会被自动打包到项目根路径的文件夹
    |-index.html 唯一的页面
|-src
    |-api 包含接口请求函数模块
        |-table.js  表格列表mock数据接口的请求函数
        |-user.js  用户登陆相关mock数据接口的请求函数
    |-assets 组件中需要使用的公用资源
        |-404_images 404页面的图片
    |-components 非路由组件
        |-SvgIcon svg图标组件
        |-Breadcrumb 面包屑组件(头部水平方向的层级组件)
        |-Hamburger 用来点击切换左侧菜单导航的图标组件
    |-icons
        |-svg 包含一些svg图片文件
        |-index.js 全局注册SvgIcon组件,加载所有svg图片并暴露所有svg文件名的数组
    |-layout
        |-components 组成整体布局的一些子组件
        |-mixin 组件中可复用的代码
        |-index.vue 后台管理的整体界面布局组件
    |-router
        |-index.js 路由器
    |-store
        |-modules
            |-app.js 管理应用相关数据
            |-settings.js 管理设置相关数据
            |-user.js 管理后台登陆用户相关数据
        |-getters.js 提供子模块相关数据的getters计算属性
        |-index.js vuex的store
    |-styles
        |-xxx.scss 项目组件需要使用的一些样式(使用scss)
    |-utils 一些工具函数
        |-auth.js 操作登陆用户的token cookie
        |-get-page-title.js 得到要显示的网页title
        |-request.js axios二次封装的模块
        |-validate.js 检验相关工具函数
        |-index.js 日期和请求参数处理相关工具函数
    |-views 路由组件文件夹
        |-dashboard 首页
        |-login 登陆
    |-App.vue 应用根组件
    |-main.js 入口js
    |-permission.js 使用全局守卫实现路由权限控制的模块
    |-settings.js 包含应用设置信息的模块
|-.env.development 指定了开发环境的代理服务器前缀路径
|-.env.production 指定了生产环境的代理服务器前缀路径
|-.eslintignore eslint的忽略配置
|-.eslintrc.js eslint的检查配置
|-.gitignore git的忽略配置
|-.npmrc 指定npm的淘宝镜像和sass的下载地址
|-babel.config.js babel的配置
|-jsconfig.json 用于vscode引入路径提示的配置
|-package.json 当前项目包信息
|-package-lock.json 当前项目依赖的第三方包的精确信息
|-vue.config.js webpack相关配置(如: 代理服务器)
  • 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
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

2.2 配置信息(

vue.config.js

这里面配置了项目的基本信息: 所使用的环境、端口号、对外路径、输入文件路径等信息 , 可以看到我们使用的dev开发环境,下面将查看开发环境的配置

const port = process.env.port || process.env.npm_config_port || 9528 // dev port

// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
  /**
   * You will need to set publicPath if you plan to deploy your site under a sub path,
   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
   * then publicPath should be set to "/bar/".
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   */
  publicPath: '/',
  outputDir: 'dist',
  assetsDir: 'static',
  lintOnSave: process.env.NODE_ENV === 'development',
  //如果你不想使用 ESLint 校验
  // lintOnSave: false,
  productionSourceMap: false,
  devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true
    },
  • 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

.env.development

在这里会标注我们后台的路径, 此时因为使用的是mock数据, 所有只是提供了一下路径而已。以及标注当前文件的类型

ENV = ‘development’ 此时便引入了与后端数据交互, 与后端的交互接口都在 api的文件家里面。

# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'
  • 1
  • 2
  • 3
  • 4

2.3 主要文件分析

api 文件夹

截取user.js 文件里面的一部分, 可以看到这个文件会向后端发送http请求, 但是它使用的是 /utils/request 里面的内容

先说明此文件的作用, 在这个开源框架中与后端交互使用的是 axios 组件。指定请求的路径、类型、请求参数、请求体参数, 就可以执行异步亲求了。下一步介绍 /utils/request

import request from '@/utils/request'

export function login(data) {
  return request({
    url: '/vue-admin-template/user/login',
    method: 'post',
    data
  })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

/utils/request

首先创建一个axios的实例, 对于这个实例需要设定的有: 基本的URL、以及请求超时的。

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第二步是添加拦截器, axios每次请求都会经过这个拦截器。 store.getters.token 首先从全局状态管理那里判断 token , 有的话就可以请求, 否则就抛出异常。并且可以清楚的看到如果有 token的话, 我们在请求的时候会得到当前的token 并且直接添加到请求头中, 以便后端得到当前登录的信息。

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent

    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

下面是对返回结果的拦截, 在这里会判断返回结果中的状态码, 根据状态码来判断这次请求的状态如何。

// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
  */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code
   */
  response => {
    const res = response.data

    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 20000) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)
  • 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
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

最后将 axios的实例导出 export default service, 在这里我们看到了 store.getters.token 以及文件最上面的导入

import store from '@ /store'
store.getters.token // 下一步查看  /store  这个文件夹
  • 1
  • 2

/store

简单介绍此文件中几个重要的知识点

  • State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储
  • ​ Mutation用于修改变更$store中的数据
  • 在mutations中不能编写异步的代码,会导致vue调试器的显示出错。在vuex中我们可以使用Action来执行异步操作。
  • Getter用于对Store中的数据进行加工处理形成新的数据
    它只会包装Store中保存的数据,并不会修改Store中保存的数据,当Store中的数据发生变化时,Getter生成的内容也会随之变化
token: state => state.user.token,
  • 1

在 gettes 文件中我们看到了 token 这个标识, 其中 gettes 文件就是为了我们方便从全局状态管理中获取数据的工具, 在这里可以得到当前的 token 。

此文件主要是使用了 vuex , 而 vuex 是 vue中的全局的状态管理, 方便我们进行组件之间的数据传递。基本使用如下

this.$store.state.count // 得到store中值

// 调用Acton中的异步方法 user.js 中的login 方法  , 这个是 /veew/login 文件中的代码 
this.$store.dispatch('user/login', this.loginForm).then(() => {
     this.$router.push({path: this.redirect || '/'})
      this.loading = false
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

token 相关的

  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

登录相关的

举例说明 login 方法, 首先 传入 {commit} 以及在方法中 commit(‘SET_TOKEN’, data.token) 这两个的作用是执行 action 中异步方法的简写, 组用就是设置 token 的值, 我们知道修改 store中的数据需要使用 Mutation 就是会调用上面的 SET_TOKEN 把 后端返回的token 保存到vuex中, 并且使用 setToken(data.token) 方法把 token写入到 cookie中 以便我们每次请求都可以带上这个 cookie , 并且能够解析出当前登录的用户 。

src\store\modules\user.js

  // user login
  login({commit}, userInfo) {
    console.log('login')
    const {username, password} = userInfo
    console.log("user info ->>>>" + username + "=>>>" + password)
    return new Promise((resolve, reject) => {
      login({username: username.trim(), password: password}).then(response => {
        const {data} = response
        commit('SET_TOKEN', data.token)
        console.log(data.token)

        setToken(data.token)
        resolve()
      }).catch(error => {

        reject(error)
      })
    })
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这个文件中我们还可以观察到最上面存在组件的导入, 这就和之前的说明相匹配。

import {login, logout, getInfo} from '@/api/user'
import {getToken, setToken, removeToken} from '@/utils/auth'
import {resetRouter} from '@/router'

  • 1
  • 2
  • 3
  • 4

main.js

这个是项目的入口文件, 在这个入口文件中, 我们看到当前是使用mock数据, 并且全局挂在 element - ui 以及在vue的实例中挂载了 路由、store (vuex) , 那下一步开始讲解路由

if (process.env.NODE_ENV === 'production') {
  const { mockXHR } = require('../mock')
  mockXHR()
}

// set ElementUI lang to EN
// Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式声明
Vue.use(ElementUI)

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

/router

使用vue router的第一步是需要一个路由表、以及把路由表加载到路由实例中, 最后把路由实例导出。下面就是定义的路由表, 对于路由表 中包括

  • path : 访问的路径
  • component : 此路由对于的组件
  • hidden : 是否在界面显示此路由
  • meta : 设置路由的属性, 图标之类的
  • name : 路由名字
  • children : 该路由下的子路由, 效果就是二级菜单
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true,
          children: [
      {
        path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
        meta: {title: 'External Link', icon: 'link'}
      }
  },
  {
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

下面就是新建路由实例, 以及添加路由表, 导出路由。 上面介绍到了组件, 下一步解释路由对应的组件

const createRouter = () => new Router({
  // mode: 'history', // require service support
  scrollBehavior: () => ({y: 0}),
  routes: constantRoutes
})

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

/view/login/login.vue

组件的概念比较广泛,可以暂时理解为一个界面, 下面是登录的界面, name: ‘Login’, 定义的组件名称。 当在路由表中配置了此路由的信息后,就可以在使用中根据对应的path 来访问此路由。

<template>
  <div class="login-container">
  </div>
</template>
<script>
  import {validUsername} from '@/utils/validate'
  export default {
    name: 'Login',
    data() {
    },
    watch: {
    },
    methods: {
    }
  }
</script>

<style lang="scss">

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

permission.js

此文件是用来配合路由使用的, 对于vue router 而言它还附带了一些其他的信息, 比如路由守卫, 在路由守卫中我们可以在路由跳转之前来做一些事情的。

对于此项目来讲;

  1. 首先判断是否有token
  2. 没有token , 如果在白名单里面, 就直接放行, 否则就直接强制跳转登录。
  3. 有token , 如果是 /login 就就直接到 根目录下
  4. 不是 /login 就去 store 里面找 当前用户的信息, 然后在放行
const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()
  // set page title
  document.title = getPageTitle(to.meta.title)
  // determine whether the user has logged in
  //console.log(getToken())
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo')
          next()
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

  • 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
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

三、修改登录功能

因为该模板使用的是mock数据,没有连接到后端系统。
所以当我们想要连接到自己写的后端系统时,需要对vue-admin-template进行改造。

3.1 因为浏览器对Ajax请求具有限制问题,一下三个地方不同,就会产生跨域问题。

已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8080/user/login 的远程资源。(原因:CORS 请求未能成功) 需要添加如下配置解决跨域问题!

  • 不同主机
  • 不同端口
  • 不同协议

都会产生跨域问题!

@Configuration
public class CorsConfiguration implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 允许跨域访问的路径
                .allowCredentials(true) // 是否发送 Cookie
                .allowedOriginPatterns("*") // 支持域
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"}) // 支持方法
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

实践应用:前后端分离实践中常遇到的跨域问题

SpringBoot 解决跨域问题的 5 种方案!

3.2 登录接口

此处需要返回的是用户信息以及登录后的token , 后端配置:

@RequestMapping("/user")
@RestController
public class UserController {

    @PostMapping("/login")
    //如果前端传递的数据是json格式,必须使用对象接收,同时需要添加@RequestBody User
    public Result login(@RequestBody User user){
        String token = JwtUtil.generateToken(user.getUsername());
        return Result.ok().data("token",token);
    }

    @GetMapping("/info")
    public Result login(String token ){
        String username = JwtUtil.getClaimsByToken(token).getSubject();
        String url="https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif";
        return Result.ok().data("name",username).data("avatar",url);
    }

    @PostMapping("/logout")
    public Result logout(){
        return Result.ok();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3.3 修改前端

此时我们只需要把前端的 访问 url 以及端口 请求的路径做出对应的修改即可。

.env.development

# just a flag
ENV = 'development'
# base api
# VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API = 'http://127.0.0.1:8001/api/'
  • 1
  • 2
  • 3
  • 4
  • 5

vue.config.js

  devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true
    }/*,
    before: require('./mock/mock-server.js')*/
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

api/user.js

import request from '@/utils/request'


export function login(data) {
  return request({
    url: '/user/login',
    method: 'post',
    data
  })
}

export function getInfo(token) {
  return request({
    url: '/user/info',
    method: 'get',
    params: { token }
  })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

src/utils/request.js的请求状态码

由于前端访问后端的数据,会传递一个状态码,后端返回数据的状态码可能是200,但是前端默认是20000,这时候需要把两者改为一样的即可,默认修改前端状态码的判断条件即可。

在这里插入图片描述

四、项目部署

这里我们使用Docker安装Nginx。
【云原生 • Docker】mysql、tomcat、nginx、redis 环境部署

4.1 部署vue项目

打包Vue项目

进入到Vue项目目录,执行

npm run build
  • 1

将生成的dist目录上传到服务器/dhx/nginx/dist

配置nginx

使用命令启动nginx

docker run -d -p 80:80 --name mynginx -v /dhx/nginx/mynginx.conf:/etc/nginx/conf.d/default.conf -v  /dhx/nginx/dist:/usr/app/dist nginx
  • 1

进入到/dhx/nginx/目录下,创建mynginx.conf文件,内容如下

 server {
		#侦听80端口
        listen       192.168.1.1:80;
        #定义使用 localhost访问
        server_name  localhost;
		#默认请求
         location / {
        root   /usr/app/dist;
        index  index.html index.htm;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

重启容器

docker  restart  mynginx
  • 1

在这里插入图片描述

4.2 打包Java程序

双击package,会自动打包在项目路径文件的/target文件夹下
在这里插入图片描述
因为springboot有内置tomcat容器,这点比较方便,省去了tomcat的部署,我们到时候可以直接把jar包上传到Linux服务器上。

nohup java -jar  spring-boot-seckill-1.0-SNAPSHOT.jar  >seckill.log 2>&1
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/811839
推荐阅读
相关标签
  

闽ICP备14008679号