赞
踩
建议:你可以在
vue-admin-template
的基础上进行二次开发,把vue-element-admin
当做工具箱,想要什么功能或者组件就去vue-element-admin
那里复制过来。
|-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相关配置(如: 代理服务器)
这里面配置了项目的基本信息: 所使用的环境、端口号、对外路径、输入文件路径等信息 , 可以看到我们使用的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
},
在这里会标注我们后台的路径, 此时因为使用的是mock数据, 所有只是提供了一下路径而已。以及标注当前文件的类型
ENV = ‘development’ 此时便引入了与后端数据交互, 与后端的交互接口都在 api的文件家里面。
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-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
})
}
首先创建一个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
})
第二步是添加拦截器, 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)
}
)
下面是对返回结果的拦截, 在这里会判断返回结果中的状态码, 根据状态码来判断这次请求的状态如何。
// 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)
}
)
最后将 axios的实例导出 export default service, 在这里我们看到了 store.getters.token 以及文件最上面的导入
import store from '@ /store'
store.getters.token // 下一步查看 /store 这个文件夹
简单介绍此文件中几个重要的知识点
token: state => state.user.token,
在 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
})
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
SET_TOKEN: (state, token) => {
state.token = token
},
举例说明 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)
})
})
},
在这个文件中我们还可以观察到最上面存在组件的导入, 这就和之前的说明相匹配。
import {login, logout, getInfo} from '@/api/user'
import {getToken, setToken, removeToken} from '@/utils/auth'
import {resetRouter} from '@/router'
这个是项目的入口文件, 在这个入口文件中, 我们看到当前是使用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)
})
使用vue router的第一步是需要一个路由表、以及把路由表加载到路由实例中, 最后把路由实例导出。下面就是定义的路由表, 对于路由表 中包括
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
},
下面就是新建路由实例, 以及添加路由表, 导出路由。 上面介绍到了组件, 下一步解释路由对应的组件
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
组件的概念比较广泛,可以暂时理解为一个界面, 下面是登录的界面, 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>
此文件是用来配合路由使用的, 对于vue router 而言它还附带了一些其他的信息, 比如路由守卫, 在路由守卫中我们可以在路由跳转之前来做一些事情的。
对于此项目来讲;
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()
}
}
})
因为该模板使用的是mock数据,没有连接到后端系统。
所以当我们想要连接到自己写的后端系统时,需要对vue-admin-template进行改造。
已拦截跨源请求:同源策略禁止读取位于 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("*");
}
}
此处需要返回的是用户信息以及登录后的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();
}
}
此时我们只需要把前端的 访问 url 以及端口 请求的路径做出对应的修改即可。
# just a flag
ENV = 'development'
# base api
# VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API = 'http://127.0.0.1:8001/api/'
devServer: {
port: port,
open: true,
overlay: {
warnings: false,
errors: true
}/*,
before: require('./mock/mock-server.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 }
})
}
由于前端访问后端的数据,会传递一个状态码,后端返回数据的状态码可能是200,但是前端默认是20000,这时候需要把两者改为一样的即可,默认修改前端状态码的判断条件即可。
这里我们使用Docker安装Nginx。
【云原生 • Docker】mysql、tomcat、nginx、redis 环境部署
进入到Vue项目目录,执行
npm run build
将生成的dist目录上传到服务器/dhx/nginx/dist
使用命令启动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
进入到/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;
}
}
重启容器
docker restart mynginx
双击package,会自动打包在项目路径文件的/target文件夹下
因为springboot有内置tomcat容器,这点比较方便,省去了tomcat的部署,我们到时候可以直接把jar包上传到Linux服务器上。
nohup java -jar spring-boot-seckill-1.0-SNAPSHOT.jar >seckill.log 2>&1
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。