总体预览
登录页面
注册页面
主界面
文件夹
前端代码
登录页面web/signin.html
DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< meta http-equiv = " X-UA-Compatible" content = " IE=edge" >
< meta name = " viewport" content = " width=device-width, initial-scale=1.0" >
< title> Document title>
< style>
form {
width : 500px;
height : 500px;
border-color : pink;
margin : 0 auto;
}
input {
width : 200px;
height : 30px;
margin-top : 10px;
outline : none;
}
input:last-child {
margin-top : 27px;
}
style>
head>
< body>
< form>
< input type = " text" name = " name" placeholder = " 输入名字" > < br>
< p class = " nameTip" > p>
< input type = " password" name = " password" placeholder = " 输入密码" > < br>
< p class = " passwordTip" > p>
< input type = " submit" name = " submit" value = " 登录" > < br>
< input type = " button" name = " login" value = " 注册" >
form>
< script src = " jquery.js" > script>
< script>
const nameVal= $ ( 'input[name="name"]' ) . val ( )
const passwordVal= $ ( 'input[name="password"]' ) . val ( )
function checkUserNameNull ( ) {
if ( $ ( 'input[name="name"]' ) . val ( ) == '' ) {
$ ( '.nameTip' ) . html ( '用户名不能为空' )
return false
} else {
return checkUserName ( )
}
}
function checkPasswordNull ( ) {
if ( $ ( 'input[name="password"]' ) . val ( ) == '' ) {
$ ( '.passwordTip' ) . html ( '密码不能为空' )
} else {
return checkPassword ( )
}
}
function checkUserName ( ) {
const reg= / [0-9a-zA-Z]{4,10} /
if ( reg. test ( $ ( 'input[name="name"]' ) . val ( ) ) ) {
$ ( '.nameTip' ) . html ( '' )
return true
} else {
$ ( '.nameTip' ) . html ( '不符合英文加数字,长度在4-10规则' )
return false
}
}
function checkPassword ( ) {
const reg= / \w /
if ( reg. test ( $ ( 'input[name="password"]' ) . val ( ) ) ) {
$ ( '.passwordTip' ) . html ( '' )
return true
} else {
$ ( '.passwordTip' ) . html ( '不符合英文加数字' )
return false
}
}
$ ( 'form' ) . on ( 'blur' , 'input[name="name"]' , function ( ) {
checkUserNameNull ( )
} ) . on ( 'blur' , 'input[name="password"]' , function ( ) {
checkPasswordNull ( )
} )
$ ( 'form' ) . on ( 'submit' , function ( e ) {
e. preventDefault ( )
const isokName= checkUserNameNull ( )
const isokPasswors= checkPasswordNull ( )
if ( isokName || isokPasswors) {
$. ajax ( {
url : 'http://10.7.178.116:4000/api/sign' ,
type : 'post' ,
data : {
username : $ ( 'input[name="name"]' ) . val ( ) ,
password : $ ( 'input[name="password"]' ) . val ( )
} ,
success : function ( data ) {
if ( data. status== 1 ) {
alert ( data. message)
} else {
localStorage. setItem ( 'token' , JSON . stringify ( data. token) )
alert ( '登录成功' )
location. href= 'index.html'
}
}
} )
} ) . on ( 'click' , 'input[name="login"]' , function ( ) {
location. href= 'login.html'
} )
}
script>
body>
html>
注册页面web/login.html
DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< meta http-equiv = " X-UA-Compatible" content = " IE=edge" >
< meta name = " viewport" content = " width=device-width, initial-scale=1.0" >
< title> Document title>
< style>
form {
width : 500px;
height : 500px;
border-color : pink;
margin : 0 auto;
}
input {
width : 200px;
height : 30px;
margin-top : 10px;
outline : none;
}
style>
head>
< body>
< form>
< input type = " text" name = " name" placeholder = " 输入名字" > < br>
< input type = " password" name = " password" placeholder = " 输入密码" > < br>
< input type = " button" name = " login" value = " 注册" >
form>
< script src = " jquery.js" > script>
< script>
$ ( 'form' ) . on ( 'click' , 'input[name="login"]' , function ( e ) {
e. preventDefault ( )
$. ajax ( {
url : 'http://10.7.178.116:4000/api/reguser' ,
type : 'post' ,
data : {
username : $ ( 'input[name="name"]' ) . val ( ) ,
password : $ ( 'input[name="password"]' ) . val ( )
} ,
success : function ( data ) {
if ( data. status== 1 ) {
alert ( data. message)
} else {
location. href= 'signin.html'
}
}
} )
} )
script>
body>
html>
主界面web/index.html
DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< meta http-equiv = " X-UA-Compatible" content = " IE=edge" >
< meta name = " viewport" content = " width=device-width, initial-scale=1.0" >
< title> Document title>
< style>
body,html {
height : 100%;
}
* {
margin : 0;
padding : 0;
}
.head {
width : 100%;
height : 150px;
background-color : skyblue;
}
.head img {
width : 100px;
height : 100px;
border-radius : 50%;
margin-left : 20px;
margin-top : 10px;
}
.head .use {
float : left;
}
.head div {
font-size : 24px;
margin-left : 28px;
}
.head button {
width : 50px;
height : 50px;
float : right;
margin-right : 20px;
margin-top : 50px;
}
.nav {
width : 200px;
height : 100%;
background-color : pink;
float : left;
}
.nav .title {
height : 30px;
padding : 10px 0;
margin-left : 15px;
color : #fff;
line-height : 30px;
}
.nav li {
list-style : none;
padding-left : 20px;
color : #fff;
height : 30px;
}
.nav .active {
background-color : blueviolet;
}
.table {
height : 100%;
margin-left : 200px ;
background-color : bisque;
}
.table table {
text-align : center;
line-height : 100px;
width : 100%;
}
.table table img {
width : 80px;
height : 80px;
}
.table table tr td {
width : 100px;
height : 100px;
}
.table form {
width : 300px;
margin : 0 auto;
text-align : center;
}
.table input {
margin-top : 10px;
outline : none;
}
.table button {
margin-top : 10px;
width : 40px;
}
style>
head>
< body>
< div class = " head" >
< div class = " use" > div>
< button class = " signOut" > 退出 button>
div>
< div class = " nav" >
< div class = " title" > 管理 div>
< ul>
< li class = " vister" > 游客列表 li>
< li class = " updataPws" > 更新信息 li>
< li class = " avatar" > 重置头像 li>
< li class = " password" > 重置密码 li>
ul>
div>
< div class = " table" > div>
< script src = " jquery.js" > script>
< script>
const token= JSON . parse ( localStorage. getItem ( 'token' ) )
function fun ( ) {
$. ajax ( {
url : 'http://10.7.178.116:4000/my/userinfo' ,
type : 'get' ,
headers : { 'Authorization' : token} ,
dataType : 'JSON' ,
success : function ( data ) {
if ( data. status== 1 ) {
alert ( '获取信息失败' )
} else {
data= data. data
let str= `
${ data. user_pic} ">
${ data. username}
`
$ ( '.use' ) . html ( str)
}
}
} )
}
fun ( )
function animation ( ) {
$ ( '.nav .title' ) . click ( function ( ) {
$ ( this ) . next ( ) . slideToggle ( )
} )
$ ( '.nav li' ) . click ( function ( ) {
$ ( '.nav li' ) . removeClass ( 'active' )
$ ( this ) . addClass ( 'active' )
} )
}
animation ( )
function total ( ) {
$ ( '.nav' ) . on ( 'click' , '.vister' , function ( ) {
getList ( )
} ) . on ( 'click' , '.updataPws' , function ( ) {
getUpdataPws ( )
} ) . on ( 'click' , '.avatar' , function ( ) {
getAvatar ( )
} ) . on ( 'click' , '.password' , function ( ) {
getPassword ( )
} )
$ ( '.head' ) . on ( 'click' , '.signOut' , function ( ) {
localStorage. setItem ( 'token' , '' )
location. href= 'signin.html'
} )
}
total ( )
function getList ( ) {
$. ajax ( {
type : 'get' ,
url : 'http://10.7.178.116:4000/my/list' ,
headers : { 'Authorization' : token} ,
dataType : 'JSON' ,
success : function ( data ) {
if ( status== 0 ) {
let list= data. data
let strTable= `
id
名字
图片
邮箱
功能
`
let str= list. map ( item => {
return `
${ item. id}
${ item. username}
${ item. user_pic} ">
${ item. email}
${ item. id} ">删除
`
} )
str= str. join ( '' )
$ ( '.table' ) . html ( strTable+ str+ '
' )
}
}
} )
}
function getUpdataPws ( ) {
let str= `
`
$ ( '.table' ) . html ( str)
$ ( 'input[name="btn"]' ) . on ( 'click' , function ( ) {
$. ajax ( {
type : 'post' ,
url : 'http://10.7.178.116:4000/my/updateUserinfo' ,
headers : { 'Authorization' : token} ,
dataType : 'JSON' ,
data : {
id : $ ( 'input[name="id"]' ) . val ( ) ,
nickname : $ ( 'input[name="nickname"]' ) . val ( ) ,
email : $ ( 'input[name="email"]' ) . val ( ) ,
} ,
success : function ( data ) {
if ( data. status== 0 ) {
alert ( '更新信息成功' )
getList ( )
}
}
} )
} )
}
function getAvatar ( ) {
let str= `
`
$ ( '.table' ) . html ( str)
$ ( 'input[name="btn"]' ) . on ( 'click' , function ( ) {
$. ajax ( {
type : 'post' ,
url : 'http://10.7.178.116:4000/my/update/avatar' ,
headers : { 'Authorization' : token} ,
dataType : 'JSON' ,
data : {
avatar : $ ( 'input[name="avatar"]' ) . val ( ) ,
} ,
success : function ( data ) {
console. log ( data) ;
if ( data. status== 0 ) {
alert ( '更换成功' )
getList ( )
}
}
} )
} )
}
function getPassword ( ) {
let str= `
`
$ ( '.table' ) . html ( str)
$ ( 'input[name="btn"]' ) . on ( 'click' , function ( ) {
$. ajax ( {
type : 'post' ,
url : 'http://127.0.0.1:4000/my/updatePwd' ,
headers : { 'Authorization' : token} ,
dataType : 'JSON' ,
data : {
oldPws : $ ( 'input[name="oldPas"]' ) . val ( ) ,
newPws : $ ( 'input[name="newPas"]' ) . val ( ) ,
} ,
success : function ( data ) {
if ( data. status== 0 ) {
alert ( '更改成功' )
getList ( )
}
}
} )
} )
}
$ ( '.table' ) . on ( 'click' , '.del' , function ( ) {
const id= $ ( this ) . attr ( 'data-index' )
$. ajax ( {
type : 'post' ,
url : 'http://127.0.0.1:4000/my/delUser' ,
headers : { 'Authorization' : token} ,
dataType : 'JSON' ,
data : {
id : id,
} ,
success : function ( data ) {
if ( data. status== 0 ) {
alert ( '删除成功' )
getList ( )
}
}
} )
} )
script>
body>
html>
后端
连接数据库db/index.js
const mysql= require ( 'mysql' )
const db= mysql. createPool ( {
host : '127.0.0.1' ,
user : 'root' ,
password : '123456' ,
database : 'test2'
} )
module. exports= db
建立路由
公开路由,不用身份验证router/user.js
const express= require ( 'express' )
const router= express. Router ( )
const user_handler= require ( '../router-handler/user' )
const expressJoi= require ( '@escook/express-joi' )
const { reg_sign_schema} = require ( '../schema/user' )
router. post ( '/reguser' , expressJoi ( reg_sign_schema) , user_handler. reguser)
router. post ( '/sign' , expressJoi ( reg_sign_schema) , user_handler. sign)
module. exports= router
私有路由要验证router/userinfo.js
const express= require ( 'express' )
const router= express. Router ( )
const userinfo_handler= require ( '../router-handler/userinfo' )
const expressJoi= require ( '@escook/express-joi' )
const { update_userinfo_schema, update_password_schema, update_avatar_schema, delete_user_shema} = require ( '../schema/user' )
router. get ( '/userinfo' , userinfo_handler. getUserinfo)
router. post ( '/updateUserinfo' , expressJoi ( update_userinfo_schema) , userinfo_handler. updataUserinfo)
router. post ( '/updatePwd' , expressJoi ( update_password_schema) , userinfo_handler. updatePassword)
router. post ( '/update/avatar' , expressJoi ( update_avatar_schema) , userinfo_handler. updateAvatar)
router. get ( '/list' , userinfo_handler. getList)
router. post ( '/delUser' , expressJoi ( delete_user_shema) , userinfo_handler. getDelUser)
module. exports= router
路由执行代码
公开路由执行代码router-handler/user.js
const db= require ( '../db/index' )
const bcrypt= require ( 'bcryptjs' )
const jwt= require ( 'jsonwebtoken' )
const config= require ( '../schema/config' )
const { TokenExpiredError } = require ( 'jsonwebtoken' )
exports. reguser = ( req, res ) => {
const userinfo= req. body
const sqlStr= 'SELECT * FROM ev_users WHERE username=?'
db. query ( sqlStr, [ userinfo. username] , function ( err, results ) {
if ( err) return res. cc ( err)
if ( results. length> 0 ) return res. cc ( '用户名已占用' )
userinfo. password= bcrypt. hashSync ( userinfo. password, 10 )
const newUserSql= 'insert into ev_users set ?'
db. query ( newUserSql, { username : userinfo. username, password : userinfo. password} , ( err, results ) => {
if ( err) return res. cc ( err)
if ( results. affectedRows!== 1 ) return res. cc ( '注册出错了' )
res. cc ( err, 0 )
} )
} )
}
exports. sign = ( req, res ) => {
const userinfo= req. body
let usernanmSql= 'SELECT * FROM ev_users WHERE username=?'
db. query ( usernanmSql, userinfo. username, ( err, results ) => {
if ( err) return res. cc ( err)
if ( results. length== 0 ) return res. cc ( '用户名不存在' )
const comparResults= bcrypt. compareSync ( userinfo. password, results[ 0 ] . password)
if ( ! comparResults) return res. cc ( '密码错误' )
const user= { ... results[ 0 ] , password : '' , user_pic : '' }
const tokenStr= jwt. sign ( user, config. jwtSecretKey, { expiresIn : '10h' } )
res. send ( {
status : 0 ,
message : '登录成功' ,
token : 'Bearer ' + tokenStr
} )
} )
}
私有路由执行代码router-handler/userinfo.js
const db = require ( '../db/index' )
const bcrypt= require ( 'bcryptjs' )
exports. getUserinfo = ( req, res ) => {
const sql= 'SELECT id,username,nickname,email,user_pic FROM ev_users WHERE id=?'
db. query ( sql, req. user. id, ( err, results ) => {
if ( err) return res. cc ( err)
if ( results. length!== 1 ) return res. cc ( '获取用户信息失败' )
res. send ( {
status : 0 ,
message : '获取成功' ,
data : results[ 0 ]
} )
} )
}
exports. updataUserinfo = ( req, res ) => {
const sql= 'UPDATE ev_users SET id=?,nickname=?,email=? WHERE id=?'
db. query ( sql, [ req. body. id, req. body. nickname, req. body. email, req. user. id] , ( err, results ) => {
if ( err) return res. cc ( err)
console. log ( results) ;
if ( results. affectedRows!== 1 ) return res. cc ( '错误' )
return res. cc ( '修改成功' , 0 )
} )
}
exports. updatePassword = ( req, res ) => {
const sql= 'SELECT * FROM ev_users WHERE id=?'
db. query ( sql, [ req. user. id] , ( err, results ) => {
if ( err) return res. cc ( err)
if ( results. length!== 1 ) return res. cc ( '查询失败' )
const comparePws= bcrypt. compareSync ( req. body. oldPws, results[ 0 ] . password)
if ( ! comparePws) return res. cc ( '密码出错' )
const sql= 'UPDATE ev_users SET password=? WHERE id=?'
const newPws= bcrypt. hashSync ( req. body. newPws, 10 )
db. query ( sql, [ newPws, req. user. id] , ( err, results ) => {
if ( err) return res. cc ( err)
if ( results. affectedRows!== 1 ) return res. cc ( '更改密码出错' )
res. cc ( '成功' , 0 )
} )
} )
}
exports. updateAvatar = ( req, res ) => {
const sql= 'UPDATE ev_users SET user_pic=? WHERE id=?'
db. query ( sql, [ req. body. avatar, req. user. id] , ( err, results ) => {
if ( err) return res. cc ( err)
if ( results. affectedRows!== 1 ) return res. cc ( '更改失败' )
res. cc ( '更换成功' , 0 )
} )
}
exports. getList = ( req, res ) => {
const sql= 'SELECT * FROM ev_users'
db. query ( sql, ( err, results ) => {
if ( err) return res. cc ( err)
res. send ( {
status : 0 ,
message : '获取成功' ,
data : results
} )
} )
}
exports. getDelUser = ( req, res ) => {
const sql= 'DELETE FROM ev_users WHERE id=?'
db. query ( sql, [ req. body. id] , ( err, results ) => {
console. log ( req. body. id) ;
if ( err) return res. cc ( err)
if ( results. affectedRows!== 1 ) return res. cc ( '删除错误' )
res. cc ( '删除成功' , 0 )
} )
}
模式验证与密钥
const joi= require ( 'joi' )
const username= joi. string ( ) . min ( 4 ) . max ( 10 ) . required ( )
const password= joi. string ( ) . required ( )
const avatar= joi. string ( ) . required ( )
exports. reg_sign_schema= {
body : {
username,
password
} ,
}
const id= joi. number ( ) . integer ( ) . min ( 1 ) . required ( )
const nickname= joi. string ( ) . required ( )
const email= joi. string ( ) . email ( ) . required ( )
exports. update_userinfo_schema= {
body : {
id,
nickname,
email
}
}
exports. update_password_schema= {
body : {
oldPws : password,
newPws : joi. not ( joi. ref ( 'oldPws' ) ) . concat ( password)
}
}
exports. update_avatar_schema= {
body : {
avatar
}
}
exports. delete_user_shema= {
body : {
id
}
}
module. exports= {
jwtSecretKey : 'this is key' ,
}
因为是在区域网内进行的测试还需要个代码web.js托管前端代码
const express= require ( 'express' )
const app= express ( )
app. use ( express. static ( 'web' ) )
app. listen ( 3000 , function ( ) {
console. log ( 'express server tunning' ) ;
} )