1、下载node.js
2、在cmd查看node.js版本node -v
,查看npm版本npm -v
3、为了加快npm的下载速度,可以更换npm的registry为国内镜像,或者下载cnpm使用cnpm,使用 cnpm 命令来下载安装淘宝镜像上的 npm 包,而不必修改 npm 的 register。
npm config set registry https://registry.npm.taobao.org
npm install -g cnpm --registry=https://registry.npm.taobao.org
4、安装vue-cli
npm install -g @vue/cli
//注意使用npm install -g vue-cli会导致版本vue版本低于3.0,一些命令,比如vue ui就无法使用
5、在vscode终端使用vue命令,报错(可直接在cmd使用vue ui构建)
vue : 无法将“vue”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
所在位置 行:1 字符: 1
+ vue
+ ~~~
+ CategoryInfo : ObjectNotFound: (vue:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
解决:
在vscode的终端中输入
get-ExecutionPolicy
查看执行策略,如果为Restricted,那么需要修改
用管理员身份运行power shell
在终端中输入Set-ExecutionPolicy RemoteSigned
修改当前终端的执行策略,重启vscode既可以正常使用vue命令
6、使用命令vue ui
在ui界面构建项目,启动项目使用命令
npm run serve
//npm run dev是旧版本的启动方式
使用火狐浏览器,在扩展和主题搜索安装Vue.js devtools
npm run build
打包部署会出现缩放问题,和打包时windows缩放百分比有关
1、搭建vue项目之后,重要的文件有三个
src/main.js
src/App.vue
public/index.html
main.js和App.vue起到渲染index.html的作用 vue的单文件组件以.vue结尾,里面可以包含html(template),css(style),js(script),结构如下: 1、vue router的rul有# 如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。 2、像下面的login,workbench平级的路由会跳转页面,只有子路由才会在组件 3、 感谢晨子语的博客: Springboot项目与vue项目整合打包 文件-》首选项-》设置-》搜search.followSymlinks和search.followSymlinks,取消勾选 router-link有点击后会有下划线且颜色变紫色,取消影响应在App.vue的style设置a的样式应用所有组件,因为router-link本质是 只能访问index页面,通过index页面可以访问其他页面,但直接访问其它页面404 不需用vue ui下载,要用npm 在main.js 注意事项: 这是跨域问题,只要访问的目标协议,子域名,主域名,端口号有一项和本地不同,就属于跨域,后端接收参数的形式也会影响 每次axios请求都在请求头加上token,在main.js 使用router.beforeEach+vuex基于token实现 参考:JWT详解 负责token的生成与验证。 2、创建jwt工具类,存放getToken方法 创建验证token过期时间方法 JWTVerifier的verify方法,如果token过期会报错(非法的签名也会报错),利用这一机制,try即返回true,catch即返回true 参考:Vue中登录成功保存token,并每次请求携带并验证token 安装vuex: 引用vuex,在main.js 在组件中使用vuex,打印储存在vuex的state的值,以及调用mutations里的方法 问题:页面刷新,vuex的state会重置 在main.js引入使用: 1、访问后端login,将返回的token存入vuex 2、在main.js的router.beforeEach每次访问页面都检查有误token,以及访问后端检查token是否过期 axios登录成功,后端将属性redisType为product或test,存入token传回前端。前端将token存入vuex,每次访问接口将token存入请求头,后端根据redisType的不同向service传入不同的jedis 在登录组件利用el-tabs设计生产登录入口和测试登录入口,关键代码 登录和生产不同的axios,其返回token处理如下 每次访问后端接口将token存入请求头,代码位于main.js,如下 每个接口获取token属性后使用JWT解析,返回redisType的值,并且如果token过期或无效会报错
在main.js中new Vue,用el挂载index.html的render: h => h(App)
渲染
2、
App.vue是一个单文件组件,是所有其他组件的父view/router,所有其它的页面都是一个个单文件组件通过App.vue的
展示,即你看到的视图都是App.vue+子组件的内容,所以不要在App.vue加其它的东西,否则会出现在任何页面。
单文件组件
<template>
<div id="app">
div>
template>
<script>
export default {
data() {
return {
username: "", //用户名
password: "", //密码
}
},
methods:{
login:function(event){
}
}
}
script>
<style scoped>
#time_show {
bottom: 30px;
color: #eeeeee;
position: absolute;
left: 190px; /*左边距*/
}
style>
标签内只能有一个根div标签,即
内不能有并列的
要加scoped,代表它的样式只作用于当下的组件。否则会和其他组件样式混在一起,造成污染。
如果要对背景样式操作,不要对
进行样式修改,如果加了scoped,会对所有的组件都造成样式影响,加了scoped,则无效,因为当前组件没有
。正确的办法是在最外层
position:fixed; height:100%; width: 100%; top: 0; left: 0;
注意app.vue中还设置了一层div,我们所加的并不是最外层的div,所以要额外加这些属性,否则你会发现你的背景效果只有中间一部分。
vue router路由
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。new VueRouter({
mode: 'history',
routes: routers
})
workbench
的
中嵌套展示const routes = [
{
path: '/',
name: 'login',
component: login
},
{
path: '/login',
name: 'login',
component: login
},{
path: '/workbench',
name: 'workbench',
component: workbench,
children: [
{
path: '/function1',
name: 'function1',
component: function1
}
]
}
]
参考:Vue 爬坑之路(三)—— 使用 vue-router 跳转页面springboot整合vue
将vue项目用命令npm run build
产生dist文件夹,将dist文件夹内容复制到springboot的static文件夹下vscode导致电脑卡顿
CSS
a {
text-decoration: none;
color:black;
}
nginx部署vue问题
解决,在location加上try_files $uri $uri/ /index.html;location / {
root /usr/share/nginx/dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
element
下载:npm i element-ui -S
在main.js引入:import Element from 'element-ui'
引入样式:import 'element-ui/lib/theme-chalk/index.css'
axios
安装
npm install axios
引入
import axios from 'axios'
Vue.prototype.$axios = axios
使用
this.$axios({
url: "http://ip/test",
method: "post",
data: {
username: this.username,
password: this.password,
},
})
.then((res) => {
if (res.data.status == 200) {
this.$router.push("/workbench");
} else if (res.data.status == 404) {
this.loginalert = true;
} else if (res.data.status == 444) {
this.loginalert = true;
}
})
.catch((err) => {
console.log(err);
});
1、url需要加上http,否则会出现访问本地ip加上目标ip的情况
2、前后端分离,访问后端接口报错跨域
已拦截跨源请求:同源策略禁止读取位于 http://ip:port/login 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
已拦截跨源请求:同源策略禁止读取位于 http://ip:port/login 的远程资源。(原因:CORS 请求未能成功)。
解决参考:SpringBoot 跨域 Access-Control-Allow-Origin
解决办法:1、在要跨域的controller加上注解@CrossOrigin
2、接口使用@RequestBody JSONObject params)
接收参数axios.interceptors
axios.interceptors.request.use(function(config){
config.headers.token=store.state.token
return config
})
未登录拦截
准备、token与jwt
谈谈JWT一、后端
在前端传来用户名密码验证通过后,使用jwt生成token,要设置token的iat发布时间与exp到期时间
1、引入token依赖<dependency>
<groupId>com.auth0groupId>
<artifactId>java-jwtartifactId>
<version>3.18.2version>
dependency>
// 签名用的密钥,指定一个字符串
private static String secret = "secret";
//获取token
public static String getToken(String username) {
// token不要放敏感信息,不要存放密码
// 当前时间
Date expTime = new Date();
// 半小时到期,数量级是毫秒
expTime.setTime(expTime.getTime() + 1000 * 60*30);
//token的header部分map
Map<String, Object> header = new HashMap<String, Object>();
header.put("alg", "HS256");
header.put("typ", "JWT");
String token = JWT.create().withHeader(header).withExpiresAt(expTime).withAudience(username)
.sign(Algorithm.HMAC256(secret));
System.out.println(token);
return token;
}
// 解析token
public static boolean verifyToken(String token) {
// 创建解析对象
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(secret)).build();
// 解析指定token
DecodedJWT decodedJWT;
try {
decodedJWT = jwtVerifier.verify(token);
// 验签
String signature=decodedJWT.getAlgorithm();
System.out.println(signature);
// 到期时间
Date expTime=decodedJWT.getExpiresAt();
System.out.println(expTime);
return true;
} catch (JWTVerificationException e) {
// TODO Auto-generated catch block
e.printStackTrace();//token的Exp过期时间如果到了就会报错
return false;
}
}
二、前端
登录成功从后端取到的token存入vuex,使用router.beforeEach在每次访问组件前,先判断有无token,再用axios访问后端接口检测token是否过期准备vuex
npm install vuex --save
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
new Vue({
store,
render: h => h(App)
}).$mount('#app')
console.log(this.$store.state.count) ;
this.$store.commit('increment');
那是因为,vuex是解决vue组件数据共享问题,但vuex 的状态存储并不能持久化,持久化需要vuex-persist
下载vuex-persist:npm install --save vuex-persist
import VuexPersistence from 'vuex-persist'
const vuexLocal = new VuexPersistence({
storage: window.localStorage
})
const store = new Vuex.Store({
plugins: [vuexLocal.plugin]
})
开始
this.$axios({
url: "http://ip/login",
method: "post",
data: {
username: this.username,
password: this.password,
},
})
.then((res) => {
if (res.data.status == 200) {
var token=res.data.data.token
this.$store.commit('setToken',token)
this.$router.push("/workbench");
} else if (res.data.status == 404) {
this.loginalert = true;
} else if (res.data.status == 444) {
this.loginalert = true;
}
})
.catch((err) => {
console.log(err);
});
router.beforeEach(function (to, from, next) {
console.log('token:'+store.state.token)
//访问login的放行
if (to.path == '/' || to.path == '/login') {
next()
} else {
// 访问非login,判断vuex是否有token
if (store.state.token == '') {
// 没有token,转到login
next({
path: '/login'
});
} else {
// token有值,访问后端查询是否过期
axios({
url: "http://ip/vertifyTokenOverTime",
method: "post",
data: {
token: store.state.token
},
})
.then((res) => {
if (res.data.status == 200) {
next()
} else {
next({
path: '/login'
});
}
})
.catch((err) => {
console.log(err);
});
}
}
})
需求
1、可以选择生产redis或者测试redis
前端
<el-tabs type="card" stretch="true">
<el-tab-pane label="生产登录" name="first">生产登录表单el-tab-pane>
<el-tab-pane label="测试登录" name="second">测试登录表单el-tab-pane>
el-tabs>
then((res) => {
if (res.data.status == 200) {
var token=res.data.data.token//取token
this.$store.commit('setToken',token)//存入vuex
}
}
axios.interceptors.request.use(function(config){
config.headers.token=store.state.token
return config
})
后端
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(secret)).build();
DecodedJWT decodedJWT=jwtVerifier.verify(token);
String redisType=decodedJWT.getClaim("redisType").asString();