??個(gè)人主頁(yè)
??JavaEE系列專欄
??前言:
本篇博客主要以鞏固前后端分離式項(xiàng)目架構(gòu)流程,通過(guò)開(kāi)發(fā)一個(gè)宿舍管理系統(tǒng)為例,系統(tǒng)地梳理所學(xué)知識(shí)以及提高業(yè)務(wù)邏輯能力,歡迎大家來(lái)交流經(jīng)驗(yàn)??
【??前端】先創(chuàng)建Vue-cli項(xiàng)目(版本2.6.10,僅包含babel),請(qǐng)選擇此項(xiàng)目并創(chuàng)建
這個(gè)是創(chuàng)建完成后的樣子
執(zhí)行npm run serve命令,按回車進(jìn)入瀏覽器,生成此頁(yè)面,說(shuō)明項(xiàng)目創(chuàng)建完成·
【整理簡(jiǎn)化項(xiàng)目模板】
1.直接刪掉components文件下的HelloWorld.vue組件
2.清理APP.vue默認(rèn)組件內(nèi)容:
【??創(chuàng)建路由】
打開(kāi)命令行工具,進(jìn)入你的項(xiàng)目目錄,輸入下面命令。并回車下載
npm i vue-router@3.5.3
1.在src路徑下創(chuàng)建 router 目錄~創(chuàng)建 index.js 文件,在其中配置路由
【??在index.js配置】
import Vue from 'vue';
import router from 'vue-router'; /* 導(dǎo)入路由 */
import login from '../views/login'; /* 導(dǎo)入其他組件--【回頭得改!】 */
import content from '../components/content'; /* 導(dǎo)入其他組件【回頭得改!】 */
Vue.use(router)
/* 定義組件路由 */
var rout = new router({
routes: [{
path: '/index',
name: 'index',
component: index
},
{
path: '/content',
component: content
}
]
})
//導(dǎo)出路由對(duì)象
export default rout;
2.在??APP.vue中添加路由視圖
<!-- 【路由組件】顯示不同組件,就像一個(gè)畫(huà)布 -->
<router-view/>
3.在?? main.js 中配置路由
/* 【導(dǎo)入路由】 */
import router from './router/index.js'
Vue.use(router);
new Vue({//【一個(gè)Vue對(duì)象】
render: h => h(App),
router,
}).$mount('#app')
【??配置Element UI】
??安裝 Element UI
npm i element-ui -S
??在 main.js 中寫(xiě)入以下內(nèi)容:
//【導(dǎo)入Element UI 并聲明vue項(xiàng)目使用Element UI】
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
??進(jìn)入 Element UI官網(wǎng)網(wǎng)站
https://element.eleme.cn/#/zh-CN
【??創(chuàng)建組件并利用 Element UI修飾】
1.在src路徑components路徑下創(chuàng)建組件login.vue,注意:《template》《/template》中只能有一個(gè)根標(biāo)簽《div》《/div》(就是可以理解為所有標(biāo)簽寫(xiě)在根標(biāo)簽div的里面)
2.在index.js中導(dǎo)入該組件
3.利用 Element UI修飾
【??如何使背景圖片最大自適應(yīng)】
#divbox{
width: 100%;
height: 100vh;
background-image: url("[圖片鏈接]"); /*將圖片路徑替換為你自己的圖片路徑*/
background-size: cover; /*保持圖片比例并完全覆蓋元素*/
background-position: center center; /*將圖片居中對(duì)齊*/
}
【??登錄組件模板】
<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;">
<span style="color:#4F5155"> 歡迎登錄</span><span style="color:rgb(137, 204, 255) ;">宿舍管理系統(tǒng)</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()">沒(méi)有賬號(hào)?點(diǎn)擊注冊(cè)</span>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: {
account: '',
password: '',
},
rules: {
account: [
{ required: true, message: '請(qǐng)輸入賬戶', trigger: 'blur' },
{ min: 3, max: 5, message: '長(zhǎng)度在 3 到 10 個(gè)字符~', trigger: 'blur' }
],
password: [
{ required: true, message: '請(qǐng)輸入密碼', trigger: 'blur' },
{ min: 3, max: 5, message: '長(zhǎng)度在 1 到 10 個(gè)字符~', trigger: 'blur' }
],
}
}
},
methods: {
reg() {
alert("注冊(cè)");
},
onSubmit(form) {//【登錄】
//數(shù)據(jù)向后端發(fā)送進(jìn)行驗(yàn)證
//$refs是一個(gè)引用
this.$refs[form].validate((valid) => {
if (valid) {
//如果發(fā)送成功,跳轉(zhuǎn)到其他組件
//【跳轉(zhuǎn)語(yǔ)句】
this.$message({showClose: true,message: '恭喜你,賬戶正確?',type: 'success'});
/* this.$message({showClose: true,message: '輸入的賬戶或密碼錯(cuò)誤~', type: 'error'});
this.$message({showClose: true,message: '系統(tǒng)忙,維修人員正在搶修!',type: 'warning'}); */
}
});
}
}
}
</script>
<style>
#divbox {
width: 100%;
height: 100vh;
/*將??頁(yè)面背景 圖片路徑替換為你自己的圖片路徑*/
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;
/*將圖片居中對(duì)齊*/
}
.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>
【??注冊(cè)組件模板】
<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;">
歡迎注冊(cè)??平臺(tái)系統(tǒng)
</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="確認(rèn)密碼" 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;">注冊(cè)</el-button>
<br />
<span style="color: #006A5A;" @click="login()">已有賬號(hào)?點(diǎn)擊返回</span>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('請(qǐng)輸入密碼'));
} else {
if (this.form.password1 !== '') {
this.$refs.form.validateField('password1');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('請(qǐng)?jiān)俅屋斎朊艽a'));
} else if (value !== this.form.password) {
callback(new Error('兩次輸入密碼不一致!'));
} else {
callback();
}
};
return {
form: {
account: '',
password: '',
password1: ''
},
rules: {
account: [{
required: true,
message: '請(qǐng)輸入注冊(cè)的管理員賬戶!',
trigger: 'blur'
},
{
min: 3,
max: 10,
message: '長(zhǎng)度在 3 到 10 個(gè)字符',
trigger: 'blur'
}
],
password: [{
required: true,
message: '請(qǐng)輸入賬戶密碼!',
trigger: 'blur'
},
{
min: 3,
max: 10,
message: '長(zhǎng)度在 3 到 10 個(gè)字符',
trigger: 'blur'
},{ validator: validatePass, trigger: 'blur' }
],
password1: [{
required: true,
message: '請(qǐng)?jiān)俅未_認(rèn)賬戶密碼!',
trigger: 'blur'
},
{
min: 3,
max: 10,
message: '長(zhǎng)度在 3 到 10 個(gè)字符',
trigger: 'blur'
},{ validator: validatePass2, trigger: 'blur' }
]
}
}
},
methods: {
login() {
alert("登錄頁(yè)面");
//this.$router.push('/');
},
RegAccount(reffrom) { //【注冊(cè)】
//數(shù)據(jù)向后端發(fā)送進(jìn)行驗(yàn)證
//$refs是一個(gè)引用
this.$refs[reffrom].validate((valid) => {
if (valid) {
//如果發(fā)送成功,跳轉(zhuǎn)到其他組件
//【跳轉(zhuǎn)語(yǔ)句】
this.$message({
showClose: true,
message: '恭喜你,賬戶已注冊(cè)?',
type: 'success'
});
/* this.$message({showClose: true,message: '輸入的賬戶或密碼錯(cuò)誤~', type: 'error'});
this.$message({showClose: true,message: '系統(tǒng)忙,維修人員正在搶修!',type: 'warning'}); */
}
});
}
}
}
</script>
<style>
#divbox {
width: 100%;
height: 100vh;
/*將??頁(yè)面背景 圖片路徑替換為你自己的圖片路徑*/
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;
/*將圖片居中對(duì)齊*/
}
.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(異步請(qǐng)求)之a(chǎn)xios—網(wǎng)絡(luò)請(qǐng)求庫(kù).
npm install axios
??在main.js中導(dǎo)入
// 導(dǎo)入 axios
import axios from 'axios';
// 設(shè)置訪問(wèn)后臺(tái)服務(wù)器地址
/* axios.defaults.baseURL="http://127.0.0.1:8088/TsetWebProject/"; */
axios.defaults.baseURL = "http://127.0.0.1:9999/Test/";
// 將 axios 掛載到 vue 全局對(duì)象中,使用 this 可以直接訪問(wèn)
Vue.prototype.$http = axios;
??操作方法
this.$http.get(地址?Key=value&key2=val1).then(function(response){ }
this.$http.post(“l(fā)ogin”,{key:“value”,key2:“val2”}).then(function(response){ }
【??創(chuàng)建后端項(xiàng)目+數(shù)據(jù)庫(kù),先完成注冊(cè)與登陸功能】
1.在idea中創(chuàng)建一個(gè)項(xiàng)目,然后右鍵單擊
2.配置后端服務(wù)器tomcat
先點(diǎn)+,在滑動(dòng)選擇Tomcat Server 服務(wù)器,最好保存ok
點(diǎn)擊路徑配置,選擇apache-Tomcat所在文件夾進(jìn)行路徑配置
3.點(diǎn)擊運(yùn)行,出現(xiàn)?就算運(yùn)行成功了
3.創(chuàng)建處理程序,導(dǎo)入jar包
??這是需要導(dǎo)入的jar包下載地址—阿里云盤
記得配置servlet處理程序的地址,配置xml文件時(shí),記得在標(biāo)簽里面寫(xiě),優(yōu)先配置編碼過(guò)濾器EcondFilter
??創(chuàng)建公共類(記得util包中定義commentResoult類)
來(lái)規(guī)定代碼傳輸格式: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的封裝類(使代碼更加簡(jiǎn)潔)
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: 對(duì)jdbc代碼進(jìn)行一個(gè)封裝
*/
public class JDBCUtil {
static {/*加載啟動(dòng)項(xiàng)*/
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/*獲取數(shù)據(jù)庫(kù)連接對(duì)象*/
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");
}
/*關(guān)閉連接管道*/
public static void close(Connection connection, PreparedStatement ps) throws SQLException {
if(connection!=null){
connection.close();
}
if(ps!=null){
ps.close();
}
}
}
??【采用json格式的打印】
??后端借助ObjectMapper類將對(duì)象轉(zhuǎn)為json格式的字符串
??【前端發(fā)送數(shù)據(jù)時(shí),由于axios發(fā)出的異步請(qǐng)求格式為json格式,利用jsonToString()方法轉(zhuǎn)為默認(rèn)鍵值對(duì)格式】
//將json對(duì)象序列化為鍵=值&鍵=值
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,后端記得使用“跨域請(qǐng)求聲明”
??補(bǔ)充知識(shí):不同組件之間通過(guò)get()方式傳遞信息
傳遞信息的組件
this.$router.push("/?account="+this.form.account);
接收信息的組件
mounted() {//一般情況下在頁(yè)面加載時(shí)就接收信息,所以一般在mounted的方法中寫(xiě)
this.form.account=this.$route.query.account;
}
【??主面板組件模板(簡(jiǎn)潔版)】
<template>
<div>
<el-container>
<!--頭部導(dǎo)航欄-->
<el-header style="text-align: right; font-size: 20px;">
<span class="logo">
陜西理工大學(xué)<span style="color:rgb(137, 204, 255) ;">宿舍管理</span>系統(tǒng)
</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>
<!-- ??側(cè)邊欄-->
<!--左邊欄-->
<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;">學(xué)生管理</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('此操作將退出登錄, 是否繼續(xù)?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
sessionStorage.clear(); //情況存儲(chǔ)信息
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){//【更改為路由導(dǎo)航守衛(wèi)】
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令牌–臨時(shí)會(huì)話跟蹤】
??在index.js中配置路由導(dǎo)航守衛(wèi)
== --目的:每次請(qǐng)求時(shí)驗(yàn)證用戶是否登錄==
// 為路由對(duì)象, 添加 beforeBach 導(dǎo)航守衛(wèi)
// to - 將要訪問(wèn)的頁(yè)面地址, from - 從哪個(gè)頁(yè)面訪問(wèn)的, next - 放行函數(shù)
rout.beforeEach((to, from, next) => {
if (to.path == '/login'|| to.path == '/reg') {
//如果用戶訪問(wèn)的登錄頁(yè), 直接放行
return next();
} else {
var account = sessionStorage.getItem("account");
if (account == null) {
return next("/login");
} else {
next();
}
}
})
??【前端配置:axios的響應(yīng)攔截器、請(qǐng)求攔截器】=提高代碼復(fù)用性
??我們需要在后端生成一個(gè)token令牌
,然后在瀏覽器的臨時(shí)存儲(chǔ)空間中存儲(chǔ)
,每次向后端發(fā)送請(qǐng)求時(shí),將token都會(huì)(加載的請(qǐng)求頭中)隨請(qǐng)求一同發(fā)往后端進(jìn)行驗(yàn)證
。== 由于token令牌中攜帶著用戶的信息,會(huì)在后端進(jìn)行解析,可以使后端知道到底是哪一個(gè)用戶正在操作、發(fā)出請(qǐng)求,并且可以驗(yàn)證token是否失效,限制用戶在線時(shí)間==。
//axios ??請(qǐng)求攔截
axios.interceptors.request.use(config => {
//為請(qǐng)求頭對(duì)象,添加 Token 驗(yàn)證的 token 字段
config.headers.token = window.sessionStorage.getItem('token');
return config;
})
??與此同時(shí),當(dāng)后端驗(yàn)證完token,并且完成對(duì)應(yīng)的處理操作后,響應(yīng)至前端,前端會(huì)進(jìn)行響應(yīng)攔截,提前判斷是否token失效、被偽造 或數(shù)據(jù)庫(kù)連接失敗
==>返回登錄頁(yè)面,重新進(jìn)行登錄。
// ??添加響應(yīng)攔截器
axios.interceptors.response.use((resp) => { //正常響應(yīng)攔截
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包、創(chuàng)建modle包/Admin類、在util包下創(chuàng)建JWTUtil類、創(chuàng)建TokenFilter過(guò)濾器】“json web token”
??添加JWT jar包
??這是需要導(dǎo)入的jar包下載地址—阿里云盤
??先在src路徑下創(chuàng)建一個(gè)modle包,再創(chuàng)建一個(gè)Admin類
同時(shí)token也是根據(jù)此類的信息來(lái)生成token令牌的
提示一下
:這里的屬性是根據(jù)數(shù)據(jù)庫(kù)表admins的屬性來(lái)寫(xiě)的,這個(gè)admins表是存儲(chǔ)登錄界面的賬戶信息的
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 {
/**
* 根據(jù)用戶id,賬號(hào)生成token
* @param u
* @return
*/
public static String getToken(User u) {
String token = "";
try {
//過(guò)期時(shí)間 為1970.1.1 0:0:0 至 過(guò)期時(shí)間 當(dāng)前的毫秒值 + 有效時(shí)間
Date expireDate = new Date(new Date().getTime() + 600*1000);//10分鐘后失效
//秘鑰及加密算法
Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
//設(shè)置頭部信息
Map<String,Object> header = new HashMap<>();
header.put("typ","JWT");
header.put("alg","HS256");
//攜帶id,賬號(hào)信息,生成簽名
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;
}
/**
* 驗(yàn)證token是否有效
* @param token
* @return
*/
public static boolean verify(String token){
try {
//驗(yàn)簽
Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception e) {//當(dāng)傳過(guò)來(lái)的token如果有問(wèn)題,拋出異常
return false;
}
}
/**
* 獲得token 中playload部分?jǐn)?shù)據(jù),按需使用
* @param token
* @return
*/
public static DecodedJWT getTokenInfo(String token){
return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
}
}
??創(chuàng)建TokenFilter過(guò)濾器
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請(qǐng)求相關(guān)的方法) extends ServletRequest(父類沒(méi)有關(guān)于http相關(guān)的方法)】
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;//多態(tài)性
HttpServletResponse resp = (HttpServletResponse) servletResponse;//多態(tài)性
String token = req.getHeader("token");//【這個(gè)就是那個(gè)自定義的請(qǐng)求頭】
System.out.println(token+"已接收");
//驗(yàn)證token代碼是否有效--
//【verify()方法是驗(yàn)證token是否是偽造的、失效的,返回一個(gè)布爾類型的值】
boolean res = JWTUtil.verify(token);//false-token【失效or偽造的】
CommentResoult commentResoult=null;
if(res){//【如果是真的】
commentResoult= new CommentResoult(200, res, "token驗(yàn)證成功!");
filterChain.doFilter(servletRequest,servletResponse);//【向下走】
}else {
commentResoult= new CommentResoult(202, res, "token已經(jīng)失效或偽造!");
PrintWriter responds = resp.getWriter();
responds.print(new ObjectMapper().writeValueAsString(commentResoult));//發(fā)送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語(yǔ)句,】
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String token = req.getHeader("token");//【這個(gè)就是那個(gè)自定義的請(qǐng)求頭】
DecodedJWT tokenInfo = JWTUtil.getTokenInfo(token);
Integer id = tokenInfo.getClaim("id").asInt();//拿到id
String account = tokenInfo.getClaim("account").asString();//拿到賬戶
System.out.println("測(cè)試請(qǐng)求!"+id+":"+account);
//驗(yàn)證token代碼是否有效
boolean res = JWTUtil.verify(token);//false-token【失效or偽造的】
CommonResult commonResult = new CommonResult(res?200:202, res, "token驗(yàn)證成功~");
PrintWriter responds=resp.getWriter();
responds.print(new ObjectMapper().writeValueAsString(commonResult));//發(fā)送json格式的信息至前端
}
}
??【??后端:】記得登錄成功時(shí),要生成一個(gè)token
【??獲取token,記得是請(qǐng)求頭getHeader(),而不是請(qǐng)求體getParameter()】
??【??前端:】記得登錄成功時(shí),從后端響應(yīng)回來(lái)的數(shù)據(jù)中將token存入臨時(shí)會(huì)話存儲(chǔ)區(qū)中
??【組件響應(yīng)的路由跳轉(zhuǎn)–跳轉(zhuǎn)至新頁(yè)面】
在menu標(biāo)簽上要添加router屬性,否則沒(méi)有反應(yīng),不會(huì)跳轉(zhuǎn)
??路由嵌套??【組件嵌套的路由跳轉(zhuǎn)–局部跳轉(zhuǎn)】
這是兩個(gè)案例:目的是為了告訴你:要在《el-menu
》組件里加router屬性,否則會(huì)沒(méi)有反應(yīng)?。。?!
??表格Table模板
這里的數(shù)據(jù)可根據(jù)需要自行更換,響應(yīng)事件可自己添加(可以自己更換)
??源碼如下:
<template>
<div>
<el-card class="box-card" style="text-align: left;">
<!-- 【??查詢列表】 -->
<el-row :gutter="20">
<el-col :span="6"><el-input placeholder="學(xué)號(hào)" 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="">返回主頁(yè)</el-button>
<!-- 【??學(xué)生列表】 -->
<el-table :data="studentList" border style="width: 100%;" max-height="530">
<el-table-column fixed prop="oper_time" label="注冊(cè)日期" width="170">
</el-table-column>
<el-table-column type="index" fixed label="序號(hào)" sortable="true" width="80">
</el-table-column>
<el-table-column prop="name" label="姓名" width="70">
</el-table-column>
<el-table-column prop="num" label="學(xué)號(hào)" width="70">
</el-table-column>
<el-table-column prop="gender" label="性別" width="60">
</el-table-column>
<el-table-column prop="majorName" label="專業(yè)" 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="聯(lián)系方式" 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模板
這里的數(shù)據(jù)可根據(jù)需要自行更換,響應(yīng)事件可自己添加(可以自己更換)
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-641464.html
??源碼如下:
<template>
<div>
<!-- 【??新增信息】 -->
<el-dialog title="新增學(xué)生信息" :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><!-- 【??學(xué)號(hào)】 -->
<el-col :span="4"><el-button type="success" style="width: 98px;">學(xué)號(hào)</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><!-- 【??專業(yè)】 -->
<el-col :span="4"><el-button type="success" style="width: 98px;" plain>專業(yè)</el-button> </el-col>
<el-col :span="6">
<el-select v-model="form.majors" placeholder="請(qǐng)選擇專業(yè)">
<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="請(qǐng)輸入地址" maxlength="20" show-word-limit
v-model="form.address"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row><!-- 【??聯(lián)系方式】 -->
<el-col :span="4"><el-button type="success" style="width: 98px;">聯(lián)系方式</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 {/* 【是否可見(jiàn)】 */
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(){
//【??請(qǐng)求事件自己添加~】
this.$message({type: 'success',message:"保存成功!"});
this.dialogFormVisible = false;//【??關(guān)閉對(duì)話框】
}
},
mounted() {
//【??獲取專業(yè)信息】
/* this.$http.get("admin/studentList?mark=major").then((resp) => {
if (resp.data.code == 200) {
this.form.major = resp.data.data;
}
}); */
}
}
//將json對(duì)象序列化為鍵=值&鍵=值
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>
??刷新頁(yè)面
this.$router.go();
??表單的二級(jí)聯(lián)動(dòng)
var obj=this.buildinglist.find((build)=>{
return build.id==this.form.building;
})/* 拿到當(dāng)前樓棟對(duì)象 */
this.fool_num=obj.buildingClass;
【解析】
其中this.buildinglist是一種[{},{},{},{}]“數(shù)組+集合的嵌套結(jié)構(gòu)”,調(diào)用find((item=>{ return 篩選條件;}));這個(gè)跟java里stream流的過(guò)濾fliter((e)->{return 篩選條件;})比較像。返回obj為符合 篩選條件的集合
這樣就從[{},{},{},{}]“數(shù)組+集合的嵌套結(jié)構(gòu)”變成了{(lán)}集合結(jié)構(gòu)
,在進(jìn)行其他操作文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-641464.html
??【??持續(xù)更新中…】
到了這里,關(guān)于宿舍管理系統(tǒng)--前后端分離式項(xiàng)目架構(gòu)流程復(fù)盤(三萬(wàn)字詳解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!