1.app.js
var express = require('express');
var path = require('path');
var app = express();
var router = require('./router');
//配置body-parser
var BodyParser = require('body-parser');
app.use(BodyParser.urlencoded({extend: false}));
app.use(BodyParser.json());
//配置静态开放资源目录,便于请求访问
app.use('/public/',express.static(path.join(__dirname,'./public/')));
app.use('/node_modules',express.static(path.join(__dirname,'./node_modules/')));
app.use('/views/',express.static(path.join(__dirname,'./views/')));
//配置渲染的视图后缀名
app.engine('html',require('express-art-template'));
//引入session 文件
var session = require('express-session');
/*
-cookie数据存放在客户的浏览器上,session数据放在服务器上
-cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session
-session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE
-单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。
-所以:将登陆信息等重要信息存放为SESSION(默认暂存30分钟);其他信息如果需要保留,可以放在COOKIE中
-在 Express 框架中,默认不支持 Session 和 Cookie
但我们可以使用第三方中间件: express-session 来解决
1.nmp install express-session
2.配置
3.使用
Example: -添加 Session 数据: req.session.instance = 'Vodka';
-访问 Session 数据: req.session.instance;
*/
app.use(session({
//配置加密字符串,它会在原有的加密基础之上和这个自定义的字符串拼接起来
//目的是为了增加安全性,防止客户端的恶意伪造
secret: '688',
resave: false,
//无论客户端请求是否使用 session ,都默认分配一把 ‘钥匙’
saveUninitialized: false
}));
//加载路由
app.use(router);
app.listen(5000,function(){
console.log('running!');
});
2.router.js
var fs = require('fs');
var express = require('express');
var Router = express.Router();
var User = require('./data');
//密码加密包
// var md5 = require('blueimp-md5');
/*
{ NickName: 'Vodka',
PassWord: '123456',
Account: '190942' }
*/
//主页面
Router.get('/',function(request,response){
response.render('index.html');
});
//登录请求
Router.post('/logining',function(request,response){
var body = request.body;
console.log(body.Account)
var errCode = 0 ;
if( body.Account == '' || body.PassWord == '' ){
return response.status(200).json({
success: true,
message: 'Please fillout the information!',
errCode: -1
});
}
User.findOne({
$and: [
{
PassWord: body.PassWord
},
{
Account: body.Account
}
]
},function(error,result){
if(error){
//查询过程出错
return response.status(200).json({
success: false,
message: 'Server error!',
errCode: 500
})
} else if(result){
//成功查找到相应数据
/*
Express 提供了一个响应方法: json,该方法接收一个对象作为参数,它会自动把对象转为字符串
*/
return response.status(200).json({
success: true,
errCode: 0, //查找到已存在用户,所以返回注册失败的标记 '0'
message: 'The User had been exists'
});
}
//若当前用户并没有数据库记录,则跳转到注册页面
else {
return response.status(200).json({
success: true,
errCode: 1,
message: 'Please regist'
});
}
/*服务端重定向只对同步请求有效,对异步请求无效:
response.redirect('/');
需要在客户端重定向:
window.location.href = '/xxxx';
*/
});
});
//登录页面
Router.get('/login',function(request,response){
response.render('login.html');
});
//注册页面
Router.get('/regist',function(request,response){
response.render('register.html');
});
//处理注册请求
Router.post('/register',function(request,response){
//定义一个表数据用户对象,用于接收request的请求体
var body = request.body;
//先判断用户是否全部信息填写完毕
if (body.Account == '' || body.NickName == '' || body.PassWord == ''){
return response.status(200).json({
success: true,
message: 'Please fillout the information!',
errCode: -1
})
};
var errCode = 0; //定义标示
User.findOne({
//有其中一个属性相同,就可以证明数据库存在相同的用户
$or: [
{
NickName: body.NickName
},
{
Account: body.Account
}
]
},function(error,result){
if(error){
//查询过程出错
return response.status(200).json({
success: false,
message: 'Server error!',
errCode: 500
})
} else if(result){
//成功查找到相应数据
/*
Express 提供了一个响应方法: json,该方法接收一个对象作为参数,它会自动把对象转为字符串
*/
return response.status(200).json({
success: true,
errCode: 1 , //查找到已存在用户,所以返回注册失败的标记 '1'
message: 'The User had been exists'
});
}
//若当前用户并没有数据库记录,则允许注册
new User(body).save(function(error,data){
if(error){
return response.status(200).json({
success: true,
errCode: 500,
message: 'Internal error!'
});
}
//若注册成功,使用Session记录用户的信息
//(Session有会话生命周期,默认30分钟,存在服务端(通常用来保存敏感数据,安全性较高)
//Cookie的生命周期可以设置,存在浏览器本地内存)
request.session.User = data;
return response.status(200).json({
success: true,
errCode: 0,
message: 'Regist success!'
});
});
/*服务端重定向只对同步请求有效,对异步请求无效:
response.redirect('/');
需要在客户端重定向:
window.location.href = '/xxxx';
*/
})
});
//导出路由容器
module.exports = Router;
3.data.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/HeroUser',{useNewUrlParser:true});
//定义用户表模式
var UserSchema = new mongoose.Schema({
Account: {
type: String,
default: null,
require: true
},
PassWord: {
type: String,
require: true,
defaultt: null
},
NickName: {
type: String,
require: true,
default: null
},
CreateTime: {
/*
账号创建时间,注意类型要写Date,而不是Date.now(),
因为Date.now()会立即调用,而写默认值在 new Model时,
没有传参数,系统就会调用默认值 default, 获得确切时间
*/
type: Date,
default: Date.now
},
LastModifyTime:{
//最近一次修改时间
type: Date,
default: Date.now
},
Gender: {
type: Number,
default: null
},
Birthday: {
type: Date,
},
avtar: {
type: String,
deafult: './views/img/huowu.png'
},
Status: {
/*
用户权限状态:
'0': 表示没有权限限制,
'1': 不可以评论,
'2': 不能登录
*/
type: Number,
enum: [0,1,2],
default: 0
}
});
//根据列名以及模式名,导出该表的模式
module.exports = mongoose.model('User',UserSchema);
1.index.html
<!-- 模板继承: 继承 layout 页面模块 , 若继承者没有补充被继承模块中的block(待填充模块),则使用被继承模块的默认内容-->
{{ extend '../layout/layout.html'}}
<!-- 继承者可以自行设计 head标签内的 内容 -->
{{ block 'head'}}
<link rel="stylesheet" href="/views/css/index.css">
<link rel="stylesheet" href="/views/icon/font_q7l36wd9ys/iconfont.css">
{{ /block }}
<!-- 补充内容 -->
{{ block 'content'}}
<div id="BigBox">
<div id="Content">
<div id="TrangleLeft"></div>
<div id="box" class="box">
<div id="Evaluate">庄周:天地与我并生,万物与我为一。</div>
<div id="Time">2021/5/21</div>
</div>
<div id="TrangleRight"></div>
</div>
<div id="Content">
<div id="TrangleLeft"></div>
<div id="box" class="box">
<div id="Evaluate">庄周:天地与我并生,万物与我为一。</div>
<div id="Time">2021/5/21</div>
</div>
<div id="TrangleRight"></div>
</div>
<div id="Content">
<div id="TrangleLeft"></div>
<div id="box" class="box">
<div id="Evaluate">庄周:天地与我并生,万物与我为一。</div>
<div id="Time">2021/5/21</div>
</div>
<div id="TrangleRight"></div>
</div>
<div id="Content">
<div id="TrangleLeft"></div>
<div id="box" class="box">
<div id="Evaluate">庄周:天地与我并生,万物与我为一。</div>
<div id="Time">2021/5/21</div>
</div>
<div id="TrangleRight"></div>
</div>
<div id="Content">
<div id="TrangleLeft"></div>
<div id="box" class="box">
<div id="Evaluate">庄周:天地与我并生,万物与我为一。</div>
<div id="Time">2021/5/21</div>
</div>
<div id="TrangleRight"></div>
</div>
<div id="Content">
<div id="TrangleLeft"></div>
<div id="box" class="box">
<div id="Evaluate">庄周:天地与我并生,万物与我为一。</div>
<div id="Time">2021/5/21</div>
</div>
<div id="TrangleRight"></div>
</div>
<div id="TimeAxis">时间轴</div>
</div>
{{ /block}}
<!-- 继承者 可以自行设计 script标签内的 脚本内容 -->
{{ block 'script' }}
<script>
/*
-window.scrollTo({ top,left ,behavior}),分别为数字、数字、字符串。
指定跳转到距离文档顶部、左边的距离,以及跳转效果(smooth、instant)
-监听事件跳转时机:添加事件监听
-获取元素到文档最顶部的距离(offsetTop属性),offsetTop返回当前元素相对于其 offsetParent 元素的顶部的距离,
因此可以通过循环累加的方式来拿到距离文档最顶部的距离
*/
//获取偏移量的函数
function GetOffSetHeight(ins){
let height = 0;
let temp = ins;
let end = document.body;
//通过循环求出当前元素相对于body的绝对偏移量
do{
height += temp.offsetTop;
//将父级元素设置为temp,知道temp等于 document.body为止
temp = temp.offsetParent;
} while (temp !== end)
return height;
}
window.onload = function(){
//偏移量监听事件
var ele = document.getElementsByClassName('box');
var index = 0;
/*
原谅我现在技术不够,用这种愚蠢之极的方法来实现点击跳转到相应页面,
因为我还无法解决异步监听事件的变量与循环之间的问题,待我他日技术有成,
回来解决这个愚蠢的做法
*/
ele[0].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[0]) - 150,
behavior: 'smooth'
})
});
ele[1].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[1]) - 150,
behavior: 'smooth'
})
});
ele[2].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[2]) - 150,
behavior: 'smooth'
})
});
ele[3].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[3]) - 150,
behavior: 'smooth'
})
});
ele[4].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[4]) - 150,
behavior: 'smooth'
})
});
ele[5].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[5]) - 150,
behavior: 'smooth'
})
});
ele[6].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[6]) - 150,
behavior: 'smooth'
})
});
ele[7].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[7]) - 150,
behavior: 'smooth'
})
});
ele[8].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[8]) - 150,
behavior: 'smooth'
})
});
ele[9].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[9]) - 150,
behavior: 'smooth'
})
});
ele[10].addEventListener('click',function(){
var temp = index;
window.scrollTo({
top:GetOffSetHeight(ele[10]) - 150,
behavior: 'smooth'
})
});
}
</script>
{{ /block }}
2.login.html
{{ extend '../views/register.html'}}
<!-- 重写页面头 -->
{{ block 'head' }}
<link rel="stylesheet" href="../views/css/login.css">
{{ /block}}
<!-- 继承者补充页面,覆盖掉继承得那部分 -->
{{ block 'content'}}
<form action="" method="POST" id="LoginForm">
<div class="Login">
<div class="box1">
<input type="text" placeholder="Account" name="Account">
</div>
<div class="box2">
<input type="password" placeholder="PassWord" name="PassWord">
</div>
<div class="box4">
<button type="submit" class="submit">Login</button>
</div>
</div>
</form>
{{ /block }}
<!-- 继承者重写自己的脚本 -->
{{ block 'script'}}
<script src="/node_modules/jquery/dist/jquery.js"></script>
<script>
$('#LoginForm').on('submit',function(event){
event.preventDefault();
var FormData = $(this).serialize();
$.ajax({
url: '/logining', //请求路由
type: 'post', //请求方法
data: FormData, //数据
dataType: 'json', //数据类型
success: function(data) {
var errCode = data.errCode;
//如果当前用户存在,则跳转到主页
if(errCode === 0 ){
window.alert('登录成功!');
window.location.href = '/';
}
//如果信息未填完整,则提醒用户填写完整
if(errCode === -1){
window.alert('请填写完整用户信息');
}
//如果当前用户不存在,则跳转到注册页面
if(errCode === 1){
window.alert('用户不存在,请先注册');
window.location.href = '/regist';
}
if(errCode === 500){
window.alert('服务端错误!');
}
}
});
});
</script>
{{ /block}}
3.register.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>注册页面</title>
{{ block 'head'}}
<!-- 继承者可以自行设计头部,如果继承者没有重写,就用被继承者原有的 -->
<link rel="stylesheet" href="../views/css/register.css">
{{ /block }}
</head>
<body>
{{ block 'content'}}
<!-- 待补充页面 ,如果继承者重写这部分,原有的将被覆盖-->
<form action="" method="POST" id="RegistForm">
<div class="Register">
<div class="box1">
<input type="text" placeholder="NickName" name="NickName">
</div>
<div class="box2">
<input type="password" placeholder="PassWord" name="PassWord">
</div>
<div class="box3">
<input type="text" placeholder="Account" name="Account">
</div>
<div class="box4">
<button type="submit" class="submit" >regist</button>
</div>
</div>
</form>
{{ /block}}
{{ block 'script'}}
<!-- 继承者可自行设计脚本 ,继承者重写之后,覆盖原有-->
<script src="/node_modules/jquery/dist/jquery.js"></script>
<script>
/*
-表单既有同步提交,也有异步提交,默认是同步的,同步表单提交,浏览器会锁死(加载转圈),等待服务器端的响应结果。
-表单同步提交得到服务端返回的结果,会直接解析成(html页面),之后就直接渲染到浏览器页面,对于这种情况,
可以直接用页面重定向,再将服务端返回的信息,渲染到重定向后的页面的某个固定位置,若想保留重定向前用户在页面留下的信息
,可以将原有的信息与服务端要返回的信息一并发送,并渲染到相应位置
*/
//表单异步提交数据
$('#RegistForm').on('submit',function(event){
event.preventDefault();
var formData = $(this).serialize();
$.ajax({
url: '/register',
type: 'post',
data: formData,
//默认把接收到的数据,转换成对象
dataType: 'json',
//这里的success表示服务端对ajax响应请求是否成功
success: function(data) {
var errCode = data.errCode;
if(errCode === 0 ) {
//客户端重定向
window.location.href = '/login';
window.alert('注册成功!');
}
//处理没填写信息就注册的路由
if(errCode === -1){
window.alert('请填写完整信息!');
}
if (errCode === 1){
window.location.href = '/regist';
window.alert('用户已存在,请重新填写信息!');
}
if (errCode === 500) {
window.alert('服务器繁忙,请稍后重试!');
}
}
})
});
</script>
{{ /block }}
</body>
</html>
4.layout.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>布局页面</title>
{{ block 'head' }}
<!-- 继承者 可以自行设计自己的head内容 -->
{{ /block}}
</head>
<body>
{{ include '../views/header.html'}}
<!-- block 里面留个空白,给继承当前模板的版块填写 -->
{{ block 'content' }}
<h1>待补充页面</h1>
{{ /block }}
{{ include '../views/footer.html'}}
</body>
<!-- 继承者可以自行设计自己的脚本 -->
{{ block 'script' }}
{{ /block }}
</html>
5.header.html (用于页面共同的头部)
<!-- 用于相同页面的公共头部 -->
<div id="header">
<div id="Title">
<img src="../public/img/logo.png" alt="">
</div>
<div id="MajorWeb">
<a href="">官网</a>
</div>
<div id="Comment">
<a href="">评论</a>
</div>
<div id="Hero">
<a href="">英雄简介</a>
</div>
<form action="" method="post" id="SearchContent">
<input type="text" id="Search" name="Search" class="iconfont icon-sousuo">
<button type="submit" id="SearchButton" class="iconfont icon-sousuo3"></button>
</form>
<div id="User">
<ul id="UserList">
<li>亲爱的召唤师,</li>
<li>欢迎您!</li>
<br>
<li>账号: 2291792561</li>
<li>召唤师: 信予子</li>
<br>
<a href="#">更多信息......</a>
</ul>
</div>
<div id="Regist">
<a href="/regist" id="MajorRegist">注册</a>
</div>
<div id="Login">
<a href="/login" id="MajorLogin">登录</a>
</div>
</div>
6.footer.html (用于共同的底部)
<!-- 用于相同页面的公共底部 -->
<div id="footer">
</div>
#案例主要页面展示