VUE
知识点JavaWeb
项目前后端分离前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat
的方式(Nginx(engine x)
是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP
服务。它只能运行静态界面。)有效的进行解耦,并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如:浏览器,车载终端,安卓,IOS
等等)打下坚实的基础。
核心思想是前端html
页面通过ajax
调用后端的restuful api
接口并使用json
数据进行交互。
1.可以实现真正的前后端解耦,前端服务器使用nginx/tomcat
。前端/WEB服务器放的是css
,js
,图片等等一系列静态资源,前端服务器负责控制页面引用,跳转,路由。
2.发现bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。页面逻辑,跳转错误,浏览器兼容问题,脚本错误,页面也是等问题,全部由前端工程师来负责。接口数据出错,数据没有提交成功,应答超时等问题,全部由后端工程师来解决。
3.减少后端服务器的负载压力,除了接口以外的其他所有http
请求全部转移到前端服务器上。
4.多端应用,接口可以共用,提升效率。
5.页面显示的东西再多也不怕,因为是异步加载。
6.nginx
支持页面热部署,不用重启服务器,千伏安升级更无缝。
7.增加代码的维护性&易读性(前后端混在一起的代码读起来相当费劲)。
8.即使后端服务器暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。
9.提升开发效率,因为可以前后端并行开发,而不是像以前的强依赖。
10.前端大量的组件代码得以复用,组件化,提升开开效率。
MVVM
MVC
与MVVM
的对比:MVC
(Model-View-Controller):后端的架构模式
MVVM
是Model-View-ViewModel
的简写。MVVM
就是将其中的View的状态和行为抽象化,让我们将视图UI
和业务逻辑分开。当然这些事ViewModel
已经帮我们做了,它可以取出Model的数据同时帮忙处理View中需要展示内容而涉及的业务逻辑。
Vue
(官网)Vue
是一套用于构建用户界面的渐进式框架,与其他大型框架不同的是,Vue
被设计为可以自底向上逐层应用。Vue
的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue
也完全能够为复杂的单页应用提供驱动。
Vue.js
是前端的主流框架之一,和 Angular.js
、React.js
一起,并成为前端三 大主流框架!
官网:https://cn.vuejs.org/
Vue.js
优点: 1.体积小,压缩后 33k
2.更高的运行效率
用JQuery
或者原生的JavaScript DOM操作函数对DOM进行频繁操作的时候,浏览器要不停的渲染新的DOM树,导致页面看起来非常卡顿。
基于虚拟DOM,一种可以预先通过JavaScript进行各种计算,把最终的DOM操作计算出来并优化的技术,由于这个DOM操作属于预处理操作,并没有真是的操作DOM,所以叫做虚拟DOM,最后在计算完毕才真正将DOM操作提交,将DOM操作变化反映到DOM树上。
3.双向数据绑定,简化DOM操作
通过MVVM
思想实现数据的双向绑定,让开发者不用再操作DOM对象,把更多的精力投入到业务逻辑上。
4.生态丰富、学习成本低
市场上拥有大量成熟、稳定的基于vue.js
的UI
框架、常用组件,即来即用实现快速开发!对初学者友好、入门容易、学习资料多。
Vue
项目的创建Vue
程序:
<html>
<head>
<meta charset="utf-8" />
<title>title>
<script src="js/vue.js" type="text/javascript" charset="utf-8">script>
head>
<body>
<div id="app">
{{message}}
<p>
{{age}}<br>
{{city[0]}}
p>
div>
<script>
new Vue({
el:"#app", // element 数据挂载点
data:{ // 数据
message:"hello vue",
age:22,
city:["北京","天津","西安"]
}
})
script>
body>
html>
1.导入开发版本的Vue.js
2.创建Vue
实例对象,设置el属性和data属性
3.使用简洁的模板语法把数据渲染到页面上
{{ 插值 }} 模板语法,插值表达式获取数据
new Vue()
;创建 Vue
对象(VM
对象)
el:数据挂载的dom
对象
Vue
会管理 el 选项命中的元素及其内部的后代元素
可以使用其他的选择器,但是建议使用 ID 选择器
可以使用其他的选择器,但是建议使用 ID 选择器,
可以使用其他的闭合标签,不能使用 HTML 和 BODY
data:{ message:’hello world’} model 数据
Vue
中用到的数据定义在 data 中
data 中可以写复杂类型的数据,如对象,数组
渲染复杂类型数据时,遵守js
的语法即可
Vue.js
使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue
实例的数据。所有Vue.js
的模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析。
在底层的实现上,Vue
将模板编译成细腻DOM渲染函数,结合响应系统,Vue
能够只能地计算出最少需要重新渲染多少组件,并把DOM操作次数键到最少。
Vue
指令指令带有前缀v-开头,以表示他们是Vue
提供的特殊属性。
作用是设置标签的文本内容
默认写法会替换全部内容,使用插值表达式可以替换指定内容
内部支持写表达式
V-html
作用是设置元素的innerHTML
内容中有html
结构会被解析为标签
内部支持写表达式
<body>
<div id="app">
{{message}}
<p>姓名:{{message}}+'aaa'p>
<p v-text="message">姓名p>
<p v-html="message">姓名p>
div>
<script>
new Vue({
el:"#app", // element 数据挂载点
data:{ // 数据
message:"jim
",
}
})
script>
body>
作用是为元素绑定事件
事件名不需要写on指令可以简写为**@**
绑定的方法定义在methods属性中,可以传入自定义参数
<body>
<div id="app">
<!-- 插值表达式 -->
<input type="button" v-on:click="test" value="测试代码1" />
<input type="button" v-on:click="test1(1,2)" value="测试代码2" />
<input type="button" @click="test1(1,2)" value="测试代码3" />
</div>
<script>
new Vue({
el:"#app", // element 数据挂载点
data:{ // 数据
message:"hello",
},
methods:{ // 定义处理函数
test(){
console.log("hello world")
},
test1(a,b){
console.log(a+":"+b)
}
}
})
</script>
</body>
作用是便捷的设置和获取表单元素的值
绑定的数据会和表单元素值相关联
绑定的数据<—>表单元素的值 双向数据绑定
<div id="app">
<!-- 插值表达式 -->
<input type="text" v-model="message" /> <!-- v-model 把表单元素中的value值 绑定指定变量 -->
<input type="text" v-model="pwd" />
<input type="button" value="提交" @click="save()" />
{{message}}
</div>
<script>
new Vue({
el:"#app", // element 数据挂载点
data:{ // 数据
message:"hello",
pwd:'aaa'
},
methods:{
save(){
this.message="jim"
}
}
} )
</script>
作用是根据真假切换元素的显示状态
原理是修改元素的display,实现显示隐藏
指令后面的内容,最终都会解析为布尔值
值为true元素显示,值为false元素隐藏
数据改变之后,对应元素的显示状态会同步更新
作用是根据表达式的真假切换元素的显示状态
本质是通过操纵dom
元素来切换
显示状态表达式的值为true,元素存在于dom
中,为false,从dom
中移除
频繁的切换v-show,反之使用v-if,前者的切换消耗小
<div id="app">
<p v-show="flag">1111111111111p>
<p v-if="flag">2222222222222p>
div>
<script>
new Vue({
el:"#app", // element 数据挂载点
data:{ // 数据
flag:false
}
})
script>
作用是为元素绑定属性
完整写法是 v-bind:属性名
简写的话可以直接省略v-bind,只保留 :属性名
需要动态的增删class属性可以使用三元运算符,也可以使用对象的方式
<div id="app">
<!-- 插值表达式 -->
<img v-bind:src="imgsrc" :title="imgtitle" />
<input type="button" value="下一张" @click="next()" />
</div>
<script>
new Vue({
el:"#app", // element 数据挂载点
data:{ // 数据
imgsrc:"img/1.png",
imgtitle:"这是图片1",
num:1
},
methods:{
next(){
this.imgsrc="img/"+(++this.num)+".png",
this.imgtitle="这是图片"+(this.num)
}
}
})
</script>
作用是根据数据生成列表结构
数组经常和v-for结合
使用语法是(item,index) in 数据
item和index可以结合其他指令一起使用
数组长度的更新会同步到页面上是响应式的
为循环绑定一个key值 :key=“值” 尽可能唯一
当一个Vue
实例被创建时,它将data对象中的所有的property加入到Vue
的响应式系统中。当这些property的值发生改变时,视图将会产生"响应",即匹配更新为新的值。
补充:BootStrap
响应式
Vue
实例生命周期 每个Vue
实例在被创建时都要经过一系列的初始化过程----例如,需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
Vue
组件组件是可复用的vue
实例,说白了就是一组可以重复使用的模板,且带有一个名字。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
vue-cli
搭建项目vue-cli
官方提供的一个脚手架,用于快速生成一个vue
的项目模板;预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,我们的开发更加的快捷;
统一的目录结构
本地调试
热部署
单元测试
集成打包上线
Node.js
简单的说Node.js
就是运行在服务端的JavaScript。如果你熟悉JavaScript,那么你就很容易学会Node.js
。
Node.js
是一个基于 Chrome JavaScript 运行时建立的一个平台。
Node.js
是一个事件驱动 I/O 服务端 JavaScript 环境,基于 Google 的 V8
引擎, V8
引擎执行Javascript
的速度非常快,性能非常好。
npm
npm
是Node.js
的包管理工具,用来安装各种Node.js
的扩展。npm
是JavaScript的包管理工具,也是世界上最大的软甲注册表。npm
让JavaScript开发人员可以轻松地使用其他开发人员共享的代码。
node.js
下载:
http://nodejs.cn/download/(最新版)
https://nodejs.org/zh-cn/download/releases/(以往版本)
Vue
项目运行:
通过在终端输入 npm run serve
运行项目
(serve在package.json
文件中可以修改)
启动成功后,会出现访问项目地址:http://127.0.0.1:8080/
在命令行中**ctrl+c
**停止服务
npm
终端命令运行程序(兼打包): npm run serve
打包: npm run build
打包完后,项目下多出一个dist目录
vue
项目结构:
**main.js
**是全局配置文件,在其中可以导入vue
,导入vue
组件;导入路由组件(router);导入elementUI
;导入网络请求库;添加响应拦截器等等。
//main.js全局配置文件,导入vue 类似导入vue.js
import Vue from 'vue'
//导入App.vue组件 第一个被加载的组件
import App from './App.vue'
//导入路由组件
import router from './router'
//导入elementUI 将所有组件导入进来 实际开发按需加载
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
//导入网络请求库
import axios from 'axios';
//配置一个全局访问地址 例如:配置后端服务器地址
axios.defaults.baseURL = "http://127.0.0.1:8089/api/";
//将axios请求库,挂载(绑定)到全局的vue对象上
Vue.prototype.$http = axios;
//axios 请求拦截
axios.interceptors.request.use(
config => {
//为请求头对象,添加 Token 验证的 token 字段
config.headers.token = window.sessionStorage.getItem('token');
return config;
}
)
// 添加响应拦截器
axios.interceptors.response.use((res) => {
if (res.data.code == 202) {
ElementUI.Message({ Message: res.data.msg,type: 'warning',duration:1000})
router.replace("/login");
}
if (res.data.code == 500) {
ElementUI.Message({ Message: res.data.msg,type: 'warning',duration:1000})
}
return res;
});
Vue.config.productionTip = false
new Vue({
el: "#app",
router,
render: h => h(App),
})
**App.vue
**是一个组件文件,可以在里面的template标签中,写自己的html
内容,也可以导入其他组件 等等
<template>
<div id="app">
<!-- 自己写HTML内容 -->
<!-- <img alt="Vue logo" src="./assets/logo.png"> -->
<!-- 导入其他组件 -->
<!-- 页面路由 -->
<!-- <router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link> -->
<!-- 显示组件内容 -->
<router-view></router-view>
</div>
</template>
<script>
/* 导入其他组件 */
import HelloWorld from './components/HelloWorld.vue'
// 导出组件,只有导出后其他地方才可以导入组件
export default {
name: 'app',
components: { // 在当前组件中注册一个组件
HelloWorld
},
data:function(){
return {
}
},
methods:{
}
}
</script>
<style>
</style>
components
:放置自己独立开发的小组件,如网页中局部的导航栏。
**Vue Router
**是Vue.js
官方的路由管理器。它和Vue.js
的核心深度集成,让构建单页面应用变得易如反掌。
vue-router
是一个插件包,所以我们还是需要用npm/cnpm
来进行安装的。
打开命令行工具,进入到你的项目目录,输入如下命令。
npm install vue-router --save-dev
1.创建router目录
创建index.js
文件,在其中配置路由
import Vue from 'vue';
/* 导入路由 */
import router from 'vue-router';
/* 导入我们需要的组件 */
import login from "../view/login.vue"
import reg from "../view/reg.vue"
import success from "../view/success.vue"
import users from "../view/user/users.vue"
import roles from "../view/role/roles.vue"
Vue.use(router);
/* 创建路由对象 并为组件定义地址 */
var rout = new router({
routes: [{
path: "/login",
name: "login",
component: login
},
{
path: "/register",
component: reg
},
{
path: "/success",
component: success,
children:[
{
path: "/users",
component: users
},
{
path: "/roles",
component: roles
}
]
}
]
})
//导出router对象
export default rout;
//路由导航守卫
rout.beforeEach((to, from, next) => {
//如果用户访问的登录页, 直接放行
if (to.path == '/login') {
return next();
} else {
const account = sessionStorage.getItem("account");
if (account == null) {
return next("/login");//不存在去登录页面
} else {
next();//存在继续向下
}
}
})
2.使用路由
<router-link to="/index">首页</router-link>
<router-link to="/content">内容</router-link>
<router-view/>
3.在main.js
中配置路由
import router from './router'
Vue.use(router);
new Vue({
el: '#app',
router,
render: h => h(App)
})
4.在index.js
中配置路由导航守卫
//路由导航守卫
rout.beforeEach((to, from, next) => {
//如果用户访问的登录页, 直接放行
if (to.path == '/login') {
return next();
} else {
const account = sessionStorage.getItem("account");
if (account == null) {
return next("/login");//不存在去登录页面
} else {
next();//存在继续向下
}
}
})
ElementUI
组件**官网:**https://element.eleme.cn/#/zh-CN
Element
,一套为开发者、设计师和产品经理准备的基于Vue 2.0
的桌面端组件库。
打开命令行工具,进入到你的项目目录,输入如下命令。
npm i element-ui -S
在main.js
中写入以下内容:
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
axios
)axios
是一个HTTP的网络请求库。
axios
中文网:http://www.axios-js.com/
打开命令行工具,进入到你的项目目录,输入如下命令。
npm install axios
在main.js
中配置axios
//导入网络请求库
import axios from 'axios';
//配置一个全局访问地址 例如:配置后端服务器地址
axios.defaults.baseURL = "http://127.0.0.1:8089/api/";
//将axios请求库,挂载(绑定)到全局的vue对象上
Vue.prototype.$http = axios;
使用get或post方法即可发送对应的请求
then方法中的回调函数会在请求成功或失败时触发
通过回调函数的形参可以获取响应内容,或错误信息
axios
的常用API
get:查询数据
post:添加数据
put:修改数据
delete:删除数据
axios
的响应结果 响应结果的主要属性:
data:实际响应回来的数据
headers:响应头信息
status:响应状态码
statusText
:响应状态信息
在main.js
中可以配置拦截器:
//axios 请求拦截
axios.interceptors.request.use(config =>{
//为请求头对象,添加 Token 验证的 token 字段
config.headers.token = sessionstorage.getItem('token');
return config;
})
// 添加响应拦截器
axios.interceptors.response.use((res) =>{
if (res.data.code == 202) {
ElementUI.Message({ Message: res.data.msg,type: 'warning',duration:1000})
router.replace("/login");
}
if (res.data.code == 500) {
ElementUI.Message({ Message: res.data.msg,type: 'warning',duration:1000})
}
return res;
});
@RestController
:在前后端分离的项目中,后端controller
层中的类用该注解来代替原来的@Controller
,里面结合了@Controller
和@ResponseBody
,相当于所有的方法上都有@ResponseBody
,所有的响应都是异步的响应。
在A网站中,我们希望使用Ajax来获取B网站中的特定内容。如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。你可以理解为两个域名之间不能跨过域名来发送请求或者请数据,否则就是不安全的。跨域访问违反了同源策略。(跨域是指从一个域名的网页去请求另一个域名的资源,但是一般情况下不能这么做,它是由浏览器的同源策略造成的,是浏览器对JavaScript
施加的安全限制。)
同源策略规定,浏览器的ajax
只能访问跟它的HTML页面同源(相同域名或IP
)的资源。
跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当做是跨域。
原来就是安全问题:如果一个网页可以随意地地访问另外一个网站的资源,那么就有可能在客户完全不知情的情况下出现安全问题。
既然有安全问题,那为什么又要跨域呢? 有时公司内部有多个不同的子域,比如一个是location.company.com
,而应用是放在 app.company.com
, 这时想从app.company.com
去访问location.company.com
的资源就属于跨域。
后端
跨域资源共享(CORS
)
W3C
的 Web 工作组推荐了一种新的机制,即跨域资源共享(Cross-origin Resource Sharing),简称 CORS
。其实这个机制就是实现了跨站访问控制,使得安全地进行跨站数据传输成为可能。 服务器端对于CORS
的支持,主要就是通过设置 Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许 Ajax 进行跨域的访问。只需要在后台中加上响应头来允许域请求!在被请求的 Response header 中加入以下设置,就可以实现跨域访问了!
方法一:使用注解
@CrossOrigin(value = "11.234.45.12")
:针对跨域问题,在Controller的方法上可以加该注解,表示假如前端(11.234.45.12)给我们发请求,我们给浏览器设置允许,或者可以理解为放行。不加参数表示任意的都可以。也可以加在类上。
@RequestMapping("/hello")
@ResponseBody
@CrossOrigin("http://127.0.0.1:8848")
public String index(){
return "Hello World";
}
方法二:手工设置响应头(局部跨域)
手工设置响应头(局部跨域 ) 使用 HttpServletResponse
对象添加响应头 (Access-Control-Allow-Origin)来授权原始域,这里 Origin 的值也可以设 置为"*" ,表示全部放行。
@RequestMapping("/hello")
@ResponseBody
public String index(HttpServletResponse response){
response.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8848");
return "Hello World";
}
方法三:返回新的CorsFilter
(全局跨域)
在任意配置类,返回一个新的 CorsFilter Bean
,并添加映射路径和具体的 CORS
配置信息。
package com.ff.back.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
//1,允许任何来源
corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
// 2,允许任何请求头
corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
// 3,允许任何方法
corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
// 4,允许凭证
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source =new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
JWT
**Json web token
(JWT
),**是为了在网络应用环境间传递声明而执行的一种基于JSON
的开放标准(RFC 7519)。定义了一种简洁的,自包含的方法用于通信双方之间以JSON
对象的形式安全的传递消息。因为数字签名的存在,这些信息是可信的,JWT
可以使用HMAC
算法或者是RSA
的公开秘钥进行签名。
说起JWT
,我们应该来谈一谈基于token的认证和传统的session认证的区别。
我们知道,http
协议本身是一种无状态的协议,而这就意味着如果用户向 我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http
协议,我们并不能知道是哪个用户发 出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服 务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其 保存为 cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请 求来自哪个用户了,这就是传统的基于 session 认证。
但是这种基于 session 的认证使应用本身很难得到扩展,随着不同客户端用 户的增加,独立的服务器已无法承载更多的用户,而这时候基于 session 认证应 用的问题就会暴露出来。
Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做 一次记录,以方便用户下次请求的鉴别,通常而言 session 都是保存在内存中, 而随着认证用户的增多,服务端的开销会明显增大。
扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存 中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授 权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味 着限制了应用的扩展能力。
**CSRF
(跨站请求伪造)*因为是基于 cookie 来进行用户识别的, cookie 如果
被截获,用户就会很容易受到跨站请求伪造的攻击。
基于 token 的鉴权机制类似于http
协议也是无状态的,它不需要在服务端 去保留用户的认证信息或者会话信息。这就意味着基于 token 认证机制的应用 不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。 流程上是这样的:
1.用户使用账号和密码发出 post 请求;
2. 服务器使用私钥创建一个 jwt
;
3. 服务器返回这个 jwt
给浏览器;
4. 浏览器将该jwt
串在请求头中像服务器发送请求;
5. 服务器验证该 jwt
;
6. 返回响应的资源给浏览器。
JWT
的主要应用场景 身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含 JWT
,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由 于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录 **(SSO
)**中比较广泛的使用了该技术。 信息交换在通信的双方之间使用JWT
对 数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。
1**.简洁**(Compact): 可以通过 URL,POST 参数或者在 HTTP header 发送,因为数 据量小,传输速度也很快。
2.自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次 查询数据库 。
3.因为 Token 是以 JSON
加密的形式保存在客户端的,所以 JWT
是跨语言的,原 则上任何 web 形式都支持。
4.不需要在服务端保存会话信息,特别适用于分布式微服务。
JWT
的构成 JWT
是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt
字符 串。就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 用户 的信息),第三部分是签证(signature)
头部承载着两部分信息:声明类型,这里是jwt
;声明加密的算法,通常直接使用 HMAC HS256
,完整的头部就像下面的JSON
:
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行`base64`转码,就构成了第一部分。
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效 信息包含三个部分:标准中的声明、公共的声明(公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务。)、需要的必要信息,但不建议添加敏感信息(例如秘钥),因为该部分在客户端可解密。然后将其进行base64
转码,得到JWT
的第二部分。
签证信息由三部分组成:header (base64
后的) 、payload (base64
后的) 、secret 。这个部分需要 base64
转码后的 header 和 base64
转码后的 payload 使用。连接组成的字符串,然后通过 header 中声明的加密方式进行加盐 secret 组合加密,然后就构成了 jwt
的第三部分。
JWT
搭建引入JWT
依赖,由于是基于java
,所以需要的是java-jwt
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
/**
* jwt 生成 token
* @param id
* @param account
* @return
*/
public static String token (Integer id, String account){ String token = "";
try {
//过期时间 为 1970.1.1 0:0:0 至 过期时间 当前的毫秒值 + 有效时间
Date expireDate = new Date(new Date().getTime() + 10*1000);
//秘钥及加密算法
Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
//设置头部信息
Map<String,Object> header = new HashMap<>(); header.put("typ","JWT");
header.put("alg","HS256");
//携带 id,账号信息,生成签名
token = JWT.create()
.withHeader(header)
.withClaim("id",id)
.withClaim("account",account)
.withExpiresAt(expireDate)
.sign(algorithm);
}catch (Exception e){
e.printStackTrace();
return null;
} return token;
}
public static boolean verify(String token){
try {
//验签
Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception e) {
//当传过来的 token 如果有问题,抛出异常
return false;
}
}
playload
部分数据/**
* 获得 token 中 playload 部分数据,按需使用
* @param token
* @return
*/
public static DecodedJWT getTokenInfo(String token){
return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
}
用户登录成功后将用户 id 和账号存储到 token 中返回给客户端,之后客户端每次 请求将 token 发送到服务器端验证, 在服务器中进行验证。
Webpack
打包本质上,`webpack`是一个现代`JavaScript`应用程序的静态模块打包器(module bundler)。当`Webpack`处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。
Webpack
是当下最热门的前端资源模块化管理和打包工具,它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到时机需要时在异步加载。
npm run build
打包后将 dist 中的文件部署到 tomcat/nginx
服务器运行即可
借助mybatis提供的分页插件,我们只要传递当前页数he页数大小,它会自动计算,并给我们自动查询总条数。
<!-- pagehelper依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
<!--剔除重复的依赖-->
<exclusions><!--不包含-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
在application.yml
中增加如下配置:
#mybatis分页插件
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
在service层:
public PageInfo<User> users(User user) {
//借助mybatis提供的分页插件 我们只要传递当前页数和页数大小 自动将计算 并给我们自动查询总条数
//1.查询当前页的数据 2.查询总条数
PageHelper.startPage(user.getCurrentPage(), user.getPageSize());
List<User> list = userMapper.users(user);
PageInfo<User> page = new PageInfo<User>(list);
return page;
}
在controller层:
/*
查询用户列表
*/
@PostMapping(path = "/users")
public Map<String,Object> users(@RequestBody User user){
Map<String,Object> map = new HashMap();
try {
PageInfo<User> pageInfo = userService.users(user);
map.put("code","200");
map.put("data", pageInfo.getList());//只查询的是当前页数
map.put("total", pageInfo.getTotal());//总条数
} catch (Exception e) {
e.printStackTrace();
map.put("code",500);
map.put("msg","查询失败");
}
return map;
}