宿舍管理系统--前后端分离式项目架构流程复盘(三万字详解)

文章目录

🐒个人主页:信计2102罗铠威

🏅JavaEE系列专栏

📖前言:

本篇博客主要以巩固前后端分离式项目架构流程,通过开发一个宿舍管理系统为例,系统地梳理所学知识以及提高业务逻辑能力,欢迎大家来交流经验🐒

【🎇前端】先创建Vue-cli项目(版本2.6.10,仅包含babel),请选择此项目并创建

在这里插入图片描述

这个是创建完成后的样子

在这里插入图片描述

执行npm run serve命令,按回车进入浏览器,生成此页面,说明项目创建完成·在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vLvKFhdA-1685517220725)(../AppData/Roaming/Typora/typora-user-images/1685279544519.png)]

【整理简化项目模板】

1.直接删掉components文件下的HelloWorld.vue组件

在这里插入图片描述

在这里插入图片描述

2.清理APP.vue默认组件内容:在这里插入图片描述

【🎀创建路由】

打开命令行工具,进入你的项目目录,输入下面命令。并回车下载

npm i vue-router@3.5.3

在这里插入图片描述在这里插入图片描述

1.在src路径下创建 router 目录~创建 index.js 文件,在其中配置路由

在这里插入图片描述

【🧸在index.js配置】

import Vue from 'vue';
import router from 'vue-router'; /* 导入路由 */
import login from '../views/login'; /* 导入其他组件--【回头得改!】 */
import content from '../components/content'; /* 导入其他组件【回头得改!】 */
Vue.use(router)


/* 定义组件路由 */
var rout = new router({
	routes: [{
			path: '/index',
			name: 'index',
			component: index
		},
		{
			path: '/content',
			component: content
		}
	]
})

//导出路由对象
export default rout;

2.在🧸APP.vue中添加路由视图

<!-- 【路由组件】显示不同组件,就像一个画布 -->
    <router-view/>

在这里插入图片描述

3.在🧸 main.js 中配置路由

在这里插入图片描述

/* 【导入路由】 */
import router from './router/index.js'
Vue.use(router);

new Vue({//【一个Vue对象】
	render: h => h(App),
	router,
}).$mount('#app')

【🎀配置Element UI】

🦓安装 Element UI

npm i element-ui -S

在这里插入图片描述
🪂在 main.js 中写入以下内容:

//【导入Element UI 并声明vue项目使用Element UI】
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

在这里插入图片描述

🦓进入 Element UI官网网站

https://element.eleme.cn/#/zh-CN
在这里插入图片描述

【🏨创建组件并利用 Element UI修饰】

1.在src路径components路径下创建组件login.vue,注意:《template》《/template》中只能有一个根标签《div》《/div》(就是可以理解为所有标签写在根标签div的里面)在这里插入图片描述
2.在index.js中导入该组件
在这里插入图片描述
3.利用 Element UI修饰
在这里插入图片描述
在这里插入图片描述

【🎀如何使背景图片最大自适应】

#divbox{
		width: 100%;
		  height: 100vh;
		  background-image: url("[图片链接]"); /*将图片路径替换为你自己的图片路径*/
		  background-size: cover; /*保持图片比例并完全覆盖元素*/
		  background-position: center center; /*将图片居中对齐*/ 
	}

在这里插入图片描述

【🎀登录组件模板】

<template>
	<div id="divbox">
		<!-- 【此图像是圆圈头像logo】 -->
		<img src="https://ts1.cn.mm.bing.net/th/id/R-C.3aeeb6d5725738095a7ad521d46ce428?rik=prLV4puYz%2btYuw&riu=http%3a%2f%2fwww.gx8899.com%2fuploads%2fallimg%2f2018021008%2fjrmgrhcgro0.jpg&ehk=Im%2fy1GA0xuqdwYNnKtzfue2b09jzjym4jjUXy7e0Seo%3d&risl=&pid=ImgRaw&r=0"
			alt="Your Image">
		<div class="login-form">
			<div id="logo">
				<span style="font-family: 'Microsoft YaHei';letter-spacing: 0.5px; font-weight: bold; font-size: 40px;">
					&nbsp;<span style="color:#4F5155"> 欢迎登录</span><span style="color:rgb(137, 204, 255) ;">宿舍管理系统</span>
				</span>
			</div>
			<el-form ref="form" :rules="rules" :model="form" label-width="80px">
				<el-form-item label="用户名" prop="account">
					<el-input v-model="form.account" class="input"></el-input>
				</el-form-item>
				<el-form-item label="密码" prop="password">
					<el-input type="password" v-model="form.password" class="input"></el-input>
				</el-form-item>
				<el-form-item>

					<el-button type="primary" @click="onSubmit('form')" style="width: 300px;">登录</el-button>
					<br />
					<span style="color: #006A5A;" @click="reg()">没有账号?点击注册</span>
				</el-form-item>
			</el-form>
		</div>


	</div>
</template>

<script>
	export default {
		data() {
			return {
				form: {
					account: '',
					password: '',
				},
				rules: {
					 account: [
					            { required: true, message: '请输入账户', trigger: 'blur' },
					            { min: 3, max: 5, message: '长度在 3 到 10 个字符~', trigger: 'blur' }
					          ],
					 password: [
					            { required: true, message: '请输入密码', trigger: 'blur' },
					            { min: 3, max: 5, message: '长度在 1 到 10 个字符~', trigger: 'blur' }
					          ],
				}
			}
		},
		methods: {
			reg() {
				alert("注册");
			},
			onSubmit(form) {//【登录】
				
					//数据向后端发送进行验证
					//$refs是一个引用
					this.$refs[form].validate((valid) => {
					  if (valid) {
					    //如果发送成功,跳转到其他组件
						//【跳转语句】
						this.$message({showClose: true,message: '恭喜你,账户正确✔',type: 'success'});
						/* this.$message({showClose: true,message: '输入的账户或密码错误~', type: 'error'});
						this.$message({showClose: true,message: '系统忙,维修人员正在抢修!',type: 'warning'}); */
					  }
					});
				}
			}
	}
</script>

<style>
	#divbox {
		width: 100%;
		height: 100vh;
		/*将🎀页面背景  图片路径替换为你自己的图片路径*/
		background-image: url("https://ts1.cn.mm.bing.net/th/id/R-C.b923d0630782b4e46dcbb2121b22bdbf?rik=l7wVr9wcUyyTzw&riu=http%3a%2f%2fpic.bizhi360.com%2fbbpic%2f68%2f768.jpg&ehk=anhoZ%2fxmeecIhRHc2n9reoQbtJ2xXrvIEx0sJbLLMiI%3d&risl=&pid=ImgRaw&r=0");
		/*保持图片比例并完全覆盖元素*/
		background-size: cover;
		background-position: center center;
		/*将图片居中对齐*/
	}

	.login-form {
		width: 442px;
		height: 400px;
		background-color: rgba(248, 242, 235, 0.5);
		;
		position: relative;
		left: 455px;
		top: 170px;


	}

	#logo {
		width: 100%;
		height: 60px;
		/* background-color: aquamarine; */
		margin-bottom: 60px;
	}

	.input {
		max-width: 300px;
	}

	img {
		border-radius: 50%;
		width: 100px;
		position: absolute;
		left: 638px;
		top: 50px;
	}
</style>

【🎀注册组件模板】

在这里插入图片描述

在这里插入图片描述

<template>
	<div id="divbox">
		<!-- 【此图像是圆圈头像logo】 -->
		<img src="https://ts1.cn.mm.bing.net/th/id/R-C.3aeeb6d5725738095a7ad521d46ce428?rik=prLV4puYz%2btYuw&riu=http%3a%2f%2fwww.gx8899.com%2fuploads%2fallimg%2f2018021008%2fjrmgrhcgro0.jpg&ehk=Im%2fy1GA0xuqdwYNnKtzfue2b09jzjym4jjUXy7e0Seo%3d&risl=&pid=ImgRaw&r=0"
			alt="Your Image">
		<div class="login-form">
			<div id="logo">
				<span style="font-family: 'Microsoft YaHei';letter-spacing: 0.5px; font-weight: bold; font-size: 40px;">
					&nbsp; 欢迎注册🐒平台系统
				</span>
			</div>
			<el-form ref="form" :rules="rules" :model="form" label-width="80px">
				<el-form-item label="用户名" prop="account">
					<el-input v-model="form.account" class="input"></el-input>
				</el-form-item>
				<el-form-item label="密码" prop="password">
					<el-input type="password" v-model="form.password" class="input" show-password></el-input>
				</el-form-item>
				<el-form-item label="确认密码" prop="password1">
					<el-input type="password" v-model="form.password1" class="input" show-password></el-input>
				</el-form-item>

				<el-form-item>
					<el-button type="primary" @click="RegAccount('form')" style="width: 300px;">注册</el-button>
					<br />
					<span style="color: #006A5A;" @click="login()">已有账号?点击返回</span>
				</el-form-item>
			</el-form>
		</div>


	</div>
</template>

<script>
	export default {
		data() {
			var validatePass = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请输入密码'));
        } else {
          if (this.form.password1 !== '') {
            this.$refs.form.validateField('password1');
          }
          callback();
        }
      };
      var validatePass2 = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请再次输入密码'));
        } else if (value !== this.form.password) {
          callback(new Error('两次输入密码不一致!'));
        } else {
          callback();
        }
      };
			return {
				form: {
					account: '',
					password: '',
					password1: ''
				},
				rules: {
					account: [{
							required: true,
							message: '请输入注册的管理员账户!',
							trigger: 'blur'
						},
						{
							min: 3,
							max: 10,
							message: '长度在 3 到 10 个字符',
							trigger: 'blur'
						}
					],
					password: [{
							required: true,
							message: '请输入账户密码!',
							trigger: 'blur'
						},
						{
							min: 3,
							max: 10,
							message: '长度在 3 到 10 个字符',
							trigger: 'blur'
						},{ validator: validatePass, trigger: 'blur' }
					],
					password1: [{
							required: true,
							message: '请再次确认账户密码!',
							trigger: 'blur'
						},
						{
							min: 3,
							max: 10,
							message: '长度在 3 到 10 个字符',
							trigger: 'blur'
						},{ validator: validatePass2, trigger: 'blur' }
					]
				}
			}
		},
		methods: {
			login() {
				 alert("登录页面");
				//this.$router.push('/');
			},
			RegAccount(reffrom) { //【注册】
					//数据向后端发送进行验证
					//$refs是一个引用
					
				this.$refs[reffrom].validate((valid) => {
					if (valid) {
						//如果发送成功,跳转到其他组件
						//【跳转语句】
						this.$message({
							showClose: true,
							message: '恭喜你,账户已注册✔',
							type: 'success'
						});
						/* this.$message({showClose: true,message: '输入的账户或密码错误~', type: 'error'});
						this.$message({showClose: true,message: '系统忙,维修人员正在抢修!',type: 'warning'}); */
					}
				});
			}
		}
	}
</script>

<style>
	#divbox {
		width: 100%;
		height: 100vh;
		/*将🎀页面背景  图片路径替换为你自己的图片路径*/
		background-image: url("https://ts1.cn.mm.bing.net/th/id/R-C.b923d0630782b4e46dcbb2121b22bdbf?rik=l7wVr9wcUyyTzw&riu=http%3a%2f%2fpic.bizhi360.com%2fbbpic%2f68%2f768.jpg&ehk=anhoZ%2fxmeecIhRHc2n9reoQbtJ2xXrvIEx0sJbLLMiI%3d&risl=&pid=ImgRaw&r=0");
		/*保持图片比例并完全覆盖元素*/
		background-size: cover;
		background-position: center center;
		/*将图片居中对齐*/
	}

	.login-form {
		width: 442px;
		height: 400px;
		background-color: rgba(248, 242, 235, 0.5);
		;
		position: relative;
		left: 455px;
		top: 170px;


	}

	#logo {
		width: 100%;
		height: 60px;
		/* background-color: aquamarine; */
		margin-bottom: 30px;
	}

	.input {
		max-width: 300px;
	}

	img {
		border-radius: 50%;
		width: 100px;
		position: absolute;
		left: 638px;
		top: 50px;
	}
</style>

【🎇前端配置】

安装ajax(异步请求)之axios—网络请求库.

npm install axios

🎀在main.js中导入

// 导入 axios
import axios from 'axios';
// 设置访问后台服务器地址
/* axios.defaults.baseURL="http://127.0.0.1:8088/TsetWebProject/"; */
axios.defaults.baseURL = "http://127.0.0.1:9999/Test/";
// 将 axios 挂载到 vue 全局对象中,使用 this 可以直接访问
Vue.prototype.$http = axios;

在这里插入图片描述

🏅操作方法

this.$http.get(地址?Key=value&key2=val1).then(function(response){ }

this.$http.post(“login”,{key:“value”,key2:“val2”}).then(function(response){ }

【🎀创建后端项目+数据库,先完成注册与登陆功能】

1.在idea中创建一个项目,然后右键单击

在这里插入图片描述
在这里插入图片描述

2.配置后端服务器tomcat

在这里插入图片描述
先点+,在滑动选择Tomcat Server 服务器,最好保存ok
在这里插入图片描述
点击路径配置,选择apache-Tomcat所在文件夹进行路径配置
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
3.点击运行,出现✔就算运行成功了在这里插入图片描述

3.创建处理程序,导入jar包

在这里插入图片描述

🏨这是需要导入的jar包下载地址—阿里云盘

记得配置servlet处理程序的地址,配置xml文件时,记得在标签里面写,优先配置编码过滤器EcondFilter

在这里插入图片描述
在这里插入图片描述

🧸创建公共类(记得util包中定义commentResoult类)

来规定代码传输格式:code , data , message

package util;

public class CommentResoult {
    private int code;
    private Object data;
    private String message;

    public CommentResoult(int code, Object data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
    }

    @Override
    public String toString() {
        return "CommentResoult{" +
                "code=" + code +
                ", data=" + data +
                ", message='" + message + '\'' +
                '}';
    }
}

🧸可以在util包中定义JDBC的封装类(使代码更加简洁)

在这里插入图片描述

package util;

import com.mysql.jdbc.Driver;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * Created by 罗铠威 on 2023/8/8 13:57
 * type: 对jdbc代码进行一个封装
 */
public class JDBCUtil {
    static {/*加载启动项*/
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    /*获取数据库连接对象*/
    public static Connection getConnection(String dataBaseName) throws SQLException {
        String url="jdbc:mysql://127.0.0.1:3306/"+dataBaseName+"?serverTimezone=Asia/Shanghai";
        return DriverManager.getConnection(url,"root","newpassword");
    }
    /*关闭连接管道*/
    public static void close(Connection connection, PreparedStatement ps) throws SQLException {
        if(connection!=null){
            connection.close();
        }
        if(ps!=null){
            ps.close();
        }
    }
}

🏅【采用json格式的打印】

🪂后端借助ObjectMapper类将对象转为json格式的字符串

在这里插入图片描述
在这里插入图片描述

🪂【前端发送数据时,由于axios发出的异步请求格式为json格式,利用jsonToString()方法转为默认键值对格式】
//将json对象序列化为键=值&键=值
	function jsonToString(jsonObj){
		console.log(jsonObj);
		var str="";
		for (var s in jsonObj) {
			str+=s+"="+jsonObj[s]+"&";
		}
		return str.substring(0,str.length-1);
	}

🧸如果使用前端ajax的axios,后端记得使用“跨域请求声明”

在这里插入图片描述

🏨补充知识:不同组件之间通过get()方式传递信息

传递信息的组件

this.$router.push("/?account="+this.form.account);

接收信息的组件

mounted() {//一般情况下在页面加载时就接收信息,所以一般在mounted的方法中写
			this.form.account=this.$route.query.account;
		}

【🎀主面板组件模板(简洁版)】

在这里插入图片描述

<template>
	<div>

		<el-container>
			<!--头部导航栏-->
			<el-header style="text-align: right; font-size: 20px;">
				<span class="logo">
					&nbsp;&nbsp;&nbsp;&nbsp;陕西理工大学<span style="color:rgb(137, 204, 255) ;">宿舍管理</span>系统&nbsp;
				</span>

				<el-dropdown>
					<!-- <div class="school"></div> -->
					<i class="el-icon-setting" style="margin-right: 15px;"></i>
					<el-dropdown-menu slot="dropdown">
						<el-dropdown-item> <el-button type="text" @click="open"
								icon="el-icon-switch-button">安全退出</el-button></el-dropdown-item>
					</el-dropdown-menu>
				</el-dropdown>
				<el-button icon="el-icon-s-custom" class="icon"> <span
						style="font-weight: bolder">{{account}}</span></el-button>
			</el-header>

			<!-- 🪂侧边栏-->

			<!--左边栏-->
			<el-container>

				<el-aside width="240px" style="background-color:  white">
					<el-menu router>

						<el-menu-item-group>
							<el-button type="success" icon="el-icon-user"
								style="width: 145px;">学生管理</el-button></el-menu-item>
						</el-menu-item-group>
						<el-menu-item-group>
							<el-button type="success" icon="el-icon-office-building " style="width: 145px;">楼栋管理</el-button></el-menu-item>
						</el-menu-item-group>
						<el-menu-item-group>
							<el-button type="success" icon="el-icon-s-home"
								style="width: 145px;">宿舍管理</el-button>
						</el-menu-item-group>
						<el-menu-item-group>
							<el-button type="success" icon="el-icon-s-custom"
									style="width: 145px;">管理员管理</el-button>
						</el-menu-item-group>
						<el-menu-item-group>
							<el-button type="success" icon="el-icon-setting"
									style="width: 145px;">入住登记管理</el-button>
						</el-menu-item-group>
						<el-menu-item-group>
							<el-button type="success" icon="el-icon-setting"
									style="width: 145px;">综合查询</el-button>
						</el-menu-item-group>
						<el-menu-item-group>
							<template slot="title"></template>
							<el-menu-item ><el-button type="text" @click="open"
									icon="el-icon-switch-button">安全退出</el-button></el-menu-item>
						</el-menu-item-group>

					</el-menu>
				</el-aside>


				<img src="https://pic.baike.soso.com/ugc/baikepic2/16827/20171227225852-88762951_jpg_300_300_19329.jpg/300"
					alt="Your Image">

				<!--中间部分-->
				<el-main>
					展示信息
				</el-main>

			</el-container>

		</el-container>
	</div>
</template>

<script>
	export default {
		name: "Main",
		data() {
			return {
				account: ""

			}
		},
		methods: {
			open() {
				this.$confirm('此操作将退出登录, 是否继续?', '提示', {
					confirmButtonText: '确定',
					cancelButtonText: '取消',
					type: 'warning'
				}).then(() => {
					sessionStorage.clear(); //情况存储信息
					this.$message({
						type: 'success',
						message: '退出成功!'
					});
					this.$router.push("/");
				}).catch(() => {
					this.$message({
						type: 'info',
						message: '已取消操作'
					});
				});
			}
		},
		mounted() {
			this.account = sessionStorage.account;
			/* 
		 this.account=sessionStorage.getItem("account");
		if(this.account==null){//【更改为路由导航守卫】
				  this.$router.push("/")
		 } 
		 */
		}
	}
</script>

<style type="text/css" scoped>
	#in1 {
		background-color: white;
		width: 100%;
		height: 100vh;
	}

	.el-header {
		background-color: #6da5ee;
		color: #333;
		text-align: center;
		line-height: 60px;
	}

	.el-aside {
		background-color: #67C23A;
		color: #333;
		text-align: center;
	}

	.el-main {
		background-color: white;
		color: #333;
		text-align: center;
	}

	body>.el-container {
		margin-bottom: 40px;
	}


	.icon {
		border-radius: 50%;
		background-color: #9dd79e;
	}

	.el-table .warning-row {
		background: oldlace;
	}

	.el-table .success-row {
		background: #f0f9eb;
	}

	.logo {
		font-weight: 900;
		font-size: 38px;
		background-color: #67C23A;
		font-family: 楷体;
		border-radius: 80px 50px 50px 80px;
		position: absolute;
		left: 0px;
	}

	img {
		border-radius: 50%;
		width: 70px;
		position: absolute;
		left: 0px;
		top: -2px;
	}
</style>

【🎀添加token令牌–临时会话跟踪】

🏅在index.js中配置路由导航守卫

== --目的:每次请求时验证用户是否登录==

// 为路由对象, 添加 beforeBach 导航守卫
// to - 将要访问的页面地址, from - 从哪个页面访问的, next - 放行函数
rout.beforeEach((to, from, next) => {
	if (to.path == '/login'|| to.path == '/reg') {
		//如果用户访问的登录页, 直接放行
		return next();
	} else {
		var account = sessionStorage.getItem("account");
		if (account == null) {
			return next("/login");
		} else {
			next();
		}
	}
})

在这里插入图片描述
在这里插入图片描述

🏅【前端配置:axios的响应拦截器、请求拦截器】=提高代码复用性

🎀我们需要在后端生成一个token令牌,然后在浏览器的临时存储空间中存储,每次向后端发送请求时,将token都会(加载的请求头中)随请求一同发往后端进行验证。== 由于token令牌中携带着用户的信息,会在后端进行解析,可以使后端知道到底是哪一个用户正在操作、发出请求,并且可以验证token是否失效,限制用户在线时间==。
在这里插入图片描述

//axios 🎀请求拦截
axios.interceptors.request.use(config => {
	//为请求头对象,添加 Token 验证的 token 字段
	config.headers.token = window.sessionStorage.getItem('token');
	return config;
})

🎀与此同时,当后端验证完token,并且完成对应的处理操作后,响应至前端,前端会进行响应拦截,提前判断是否token失效、被伪造 或数据库连接失败==>返回登录页面,重新进行登录。

// 🎀添加响应拦截器
axios.interceptors.response.use((resp) => { //正常响应拦截
	if (resp.data.code == 500) {
		ElementUI.Message({
			message: resp.data.message,
			type: "error"
		})
	}
	if (resp.data.code == 202) {//token失效、被伪造
		router.replace("/login");
	}
	return resp;
});

🏅【后端配置:添加JWT jar包、创建modle包/Admin类、在util包下创建JWTUtil类、创建TokenFilter过滤器】“json web token”

🎀添加JWT jar包

在这里插入图片描述在这里插入图片描述在这里插入图片描述

🏨这是需要导入的jar包下载地址—阿里云盘
🪂先在src路径下创建一个modle包,再创建一个Admin类

同时token也是根据此类的信息来生成token令牌的

提示一下:这里的属性是根据数据库表admins的属性来写的,这个admins表是存储登录界面的账户信息的在这里插入图片描述

package modle;

/**
 * Created by 罗铠威 on 2023/8/11 10:16
 * type:
 */


import java.util.Date;

public class Admin {
    private int id;
    private String account;
    private  String password;
    private Date reg_time;
    private  String token;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getReg_time() {
        return reg_time;
    }

    public void setReg_time(Date reg_time) {
        this.reg_time = reg_time;
    }
}

🎀添加JWT jar包
package com.example.back.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 */
public class JWTUtil {

    /**
     * 根据用户id,账号生成token
     * @param u
     * @return
     */
    public static String getToken(User u) {
        String token = "";
        try {
            //过期时间 为1970.1.1 0:0:0 至 过期时间  当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() + 600*1000);//10分钟后失效
            //秘钥及加密算法
            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",u.getId())
                    .withClaim("account",u.getAccount())
                    .withExpiresAt(expireDate)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }

    /**
     * 验证token是否有效
     * @param token
     * @return
     */
    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;
        }
    }

    /**
     * 获得token 中playload部分数据,按需使用
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token){
        return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
    }

}

🧸创建TokenFilter过滤器
package filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import util.CommentResoult;
import util.JWTUtil;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class TokenFilter implements Filter {
    @Override//【HttpServletRequest(子接口,定义了http请求相关的方法) extends ServletRequest(父类没有关于http相关的方法)】
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) servletRequest;//多态性
        HttpServletResponse resp = (HttpServletResponse) servletResponse;//多态性
        String token = req.getHeader("token");//【这个就是那个自定义的请求头】
        System.out.println(token+"已接收");
        //验证token代码是否有效--
//【verify()方法是验证token是否是伪造的、失效的,返回一个布尔类型的值】
        boolean res = JWTUtil.verify(token);//false-token【失效or伪造的】
        CommentResoult commentResoult=null;
        if(res){//【如果是真的】
            commentResoult= new CommentResoult(200, res, "token验证成功!");
            filterChain.doFilter(servletRequest,servletResponse);//【向下走】
        }else {
            commentResoult= new CommentResoult(202, res, "token已经失效或伪造!");
            PrintWriter responds = resp.getWriter();
            responds.print(new ObjectMapper().writeValueAsString(commentResoult));//发送json格式的信息至前端
        }
    }
}

【🪀记得配置xml】
在这里插入图片描述
【如何·🎀解析token中的用户信息】

package Servlet;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import util.CommonResult;
import util.JWTUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class TestServlet extends HttpServlet {
    @Override
    //【🎀解析token语句,】
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String token = req.getHeader("token");//【这个就是那个自定义的请求头】
        DecodedJWT tokenInfo = JWTUtil.getTokenInfo(token);
        Integer id = tokenInfo.getClaim("id").asInt();//拿到id
        String account = tokenInfo.getClaim("account").asString();//拿到账户
        System.out.println("测试请求!"+id+":"+account);
        //验证token代码是否有效
        boolean res = JWTUtil.verify(token);//false-token【失效or伪造的】
        CommonResult commonResult = new CommonResult(res?200:202, res, "token验证成功~");
        PrintWriter responds=resp.getWriter();
        responds.print(new ObjectMapper().writeValueAsString(commonResult));//发送json格式的信息至前端
    }
}

🧸【🎀后端:】记得登录成功时,要生成一个token

在这里插入图片描述

【🦓获取token,记得是请求头getHeader(),而不是请求体getParameter()】

在这里插入图片描述

🧸【🎀前端:】记得登录成功时,从后端响应回来的数据中将token存入临时会话存储区中

在这里插入图片描述

🧸【组件响应的路由跳转–跳转至新页面】

在menu标签上要添加router属性,否则没有反应,不会跳转
在这里插入图片描述

在这里插入图片描述
请添加图片描述

🧸路由嵌套🎀【组件嵌套的路由跳转–局部跳转】

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
这是两个案例:目的是为了告诉你:要在《el-menu》组件里加router属性,否则会没有反应!!!! 在这里插入图片描述请添加图片描述

🎀表格Table模板

在这里插入图片描述
在这里插入图片描述这里是引用
这里的数据可根据需要自行更换,响应事件可自己添加(可以自己更换)

🎀源码如下:

<template>
	<div>
		
		<el-card class="box-card" style="text-align: left;">
			<!-- 【🎀查询列表】 -->
			<el-row :gutter="20">
				<el-col :span="6"><el-input placeholder="学号" v-model="query.queryNum"/></el-col>
				<el-col :span="6"><el-input placeholder="姓名" v-model="query.queryName"/></el-col>
				<el-col :span="6">
					<el-button type="primary" icon="el-icon-search" @click="">查询</el-button>
					<el-button type="danger" icon="el-icon-delete" size="small" @click="">清空查询</el-button>
					</el-col>
			</el-row>
			
			
			<!-- 【🎀新增按钮】 -->
		<el-button type="success" icon="el-icon-circle-plus" @click="">新增</el-button>
		<!-- 【🎀返回按钮】 -->
			<el-button type="primary" icon="el-icon-house" @click="">返回主页</el-button>
			<!-- 【🎀学生列表】 -->
			<el-table :data="studentList" border style="width: 100%;" max-height="530">
				<el-table-column fixed prop="oper_time" label="注册日期" width="170">
				</el-table-column>
				<el-table-column type="index" fixed  label="序号" sortable="true" width="80">
				</el-table-column>
				<el-table-column prop="name" label="姓名" width="70">
				</el-table-column>
				<el-table-column prop="num" label="学号" width="70">
				</el-table-column>
				<el-table-column prop="gender" label="性别" width="60">
				</el-table-column>
				<el-table-column prop="majorName" label="专业" width="110">
				</el-table-column>
				<el-table-column prop="birthday" label="生日" width="110">
				</el-table-column>
				<el-table-column prop="birthday" label="生日" width="110">
				</el-table-column>
				<el-table-column prop="birthday" label="生日" width="110">
				</el-table-column>
				<el-table-column prop="address" label="地址" width="70">
				</el-table-column>
				<el-table-column prop="phone" label="联系方式" width="90">
				</el-table-column>
				<el-table-column  fixed="right" label="操作" width="190">
					<template slot-scope="scope">
						<el-button @click="" type="warning" icon="el-icon-edit" size="small"
							style="width: 40;">编辑</el-button>
						<el-button @click="" size="small" type="danger" icon="el-icon-delete"
							style="width: 40;">
							移除
						</el-button>
		
					</template>
				</el-table-column>
			</el-table>
		</el-card>
		
		
	</div>
</template>

<script>
	export default{
		data() {
			return{
				studentList: [],
				query:{
					queryName:"",
					queryNum:"",
					mark:"query"
				}
			}
		}
	}
</script>

<style>
</style>

🪀表单dalog模板

在这里插入图片描述
这里的数据可根据需要自行更换,响应事件可自己添加(可以自己更换)

🎀源码如下:

<template>
	<div>
		<!-- 【🎀新增信息】 -->
		<el-dialog title="新增学生信息" :visible.sync="dialogFormVisible">
			<el-form :model="form" style="background-color: bisque;">
				<el-row><!-- 【🪀姓名】 -->
					<el-col :span="4"><el-button type="success" style="width: 98px;">姓名</el-button> </el-col>
					<el-col :span="6"><el-form-item><el-input v-model="form.name" maxlength="10" show-word-limit
								autocomplete="off"></el-input></el-form-item></el-col>
				</el-row>
				<el-row><!-- 【🪀学号】 -->
					<el-col :span="4"><el-button type="success" style="width: 98px;">学号</el-button> </el-col>
					<el-col :span="5"><el-form-item><el-input v-model="form.num" maxlength="10" show-word-limit
								autocomplete="off"></el-input></el-form-item></el-col>
				</el-row>
				<el-row><!-- 【🪀性别】 -->
					<el-col :span="4"><el-button type="success" style="width: 98px;" plain>性别</el-button> </el-col>
					<el-col :span="6">
						<el-radio v-model="form.gender" label=""></el-radio>
						<el-radio v-model="form.gender" label=""></el-radio>
					</el-col>
				</el-row>
				<el-row><!-- 【🪀专业】 -->
					<el-col :span="4"><el-button type="success" style="width: 98px;" plain>专业</el-button> </el-col>
					<el-col :span="6">
						<el-select v-model="form.majors" placeholder="请选择专业">
							<el-option v-for="item in form.major" :key="item.id" :label="item.name" :value="item.id">
							</el-option>
						</el-select>
					</el-col>
				</el-row>
				<el-row><!-- 【🪀生日】 -->
					<el-col :span="4"><el-button type="success" style="width: 98px;" plain>生日</el-button> </el-col>
					<el-col :span="7">
						<div class="block">
							<el-date-picker value-format="yyyy-MM-dd" v-model="form.birthday" align="right" type="date"
								placeholder="选择日期" :picker-options="pickerOptions">
							</el-date-picker>
						</div>
					</el-col>
				</el-row>
				<el-row><!-- 【🪀地址】 -->
					<el-col :span="4"><el-button type="success" style="width: 98px;">地址</el-button> </el-col>
					<el-col :span="18">
						<el-form-item>
							<el-input type="textarea" :rows="2" placeholder="请输入地址" maxlength="20" show-word-limit
								v-model="form.address"></el-input>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row><!-- 【🪀联系方式】 -->
					<el-col :span="4"><el-button type="success" style="width: 98px;">联系方式</el-button> </el-col>
					<el-col :span="18"><el-form-item><el-input v-model="form.phone" maxlength="15" show-word-limit
								autocomplete="off"></el-input></el-form-item></el-col>
				</el-row>

			</el-form>
			<div slot="footer" class="dialog-footer">
				<el-button @click="concle()">取 消</el-button>
				<el-button type="primary" @click="addSudent()">保 存</el-button>
			</div>
		</el-dialog>
	</div>
</template>

<script>
	export default {
		data() {
			return {/* 【是否可见】 */
				dialogFormVisible: false,
				form: {
					name: '',
					num: '',
					gender: '',
					birthday: '',
					address: '',
					phone: '',
					delivery: false,
					major: [],
					majors: '',
					mark: 'add'
				},
				formLabelWidth: '120px',
				pickerOptions: {//【🎀日期选择器】
					disabledDate(time) {
						return time.getTime() > Date.now();
					}
				}

			}
		},
		methods: {
			concle() {
				this.$message({
					type: 'info',
					message: '退出成功!'
				});
				this.dialogFormVisible = false;
			},
			addSudent(){
				//【🎀请求事件自己添加~】
				this.$message({type: 'success',message:"保存成功!"});
				this.dialogFormVisible = false;//【🎀关闭对话框】
			}
		},
		mounted() {
			//【🎀获取专业信息】
			/* this.$http.get("admin/studentList?mark=major").then((resp) => {
				if (resp.data.code == 200) {
					this.form.major = resp.data.data;
				}
			}); */
		}



	}
	//将json对象序列化为键=值&键=值
	function jsonToString(jsonObj) {
		console.log(jsonObj);
		var str = "";
		for (var s in jsonObj) {
			str += s + "=" + jsonObj[s] + "&";
		}
		return str.substring(0, str.length - 1);
	}
</script>

<style scoped>
</style>

🎇刷新页面

this.$router.go();

🪂表单的二级联动

var obj=this.buildinglist.find((build)=>{
			return build.id==this.form.building;
				})/* 拿到当前楼栋对象 */
				
	this.fool_num=obj.buildingClass;

【解析】其中this.buildinglist是一种[{},{},{},{}]“数组+集合的嵌套结构”,调用find((item=>{ return 筛选条件;}));这个跟java里stream流的过滤fliter((e)->{return 筛选条件;})比较像。返回obj为符合 筛选条件的集合
这样就从[{},{},{},{}]“数组+集合的嵌套结构”变成了{}集合结构,在进行其他操作

🎀【🐒持续更新中…】

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信计2102罗铠威

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值