nodejs mongo博客说说小项目
2019-01-02 本文已影响0人
pretty_rain
项目下载地址:https://github.com/prettyRain/shuoshuo
项目用到的技术:nodejs+express+mongodb+ejs+cookie+session
项目功能: 注册、登录、上传裁切头像 、发表说说 、查看所有说说、看某人说说
项目环境:node环境 mongo数据库安装
项目目录:
image.png
avatar:存放上传的图片
model:db.js 操作数据库 md5.js 加密
image.png
node_modules: 下载的包
public: bootstrap框架 jcrop裁切图片框架 toptip提示框
image.png
router : 路由
image.png
views:页面展示
image.png
app.js:控制层
settings.js: 配置参数
db.js:
/**
* Created by prettyRain on 2018/12/10.
*/
var mongoClient = require('mongodb').MongoClient;
var settings = require('../settings.js');
var dburl = settings.dburl;
var dbname = settings.dbname;
/**
* 连接数据库
* @param callback
*/
function clientmongodb(callback){
mongoClient.connect(dburl,function(err,client){
callback(err,client);
})
}
/**
* 插入一条数据
* @param collectionName
* @param paramJSON
* @param callback
*/
exports.insertOne = function(collectionName,paramJSON,callback){
clientmongodb(function(err,client){
if(err){
callback(err,null);
return;
}
var db = client.db(dbname);
db.collection(collectionName).insertOne(paramJSON,function(err,result){
callback(err,result);
client.close();
})
})
}
/**
* 插入多条数据
* @param collectionName 集合名称
* @param paramArray json数组
* @param callback 回调函数
*/
exports.insertMany = function(collectionName,paramArray,callback){
clientmongodb(function(err,client){
var db = client.db(dbname);
db.collection(collectionName).insertMany(paramArray,function(err,result){
callback(err,result);
client.close();
})
})
}
/**
* 修改一条数据
* @param collectionName 集合名称
* @param whereJSON 修改条件
* @param paramJSON 修改内容
* @param callback 回调函数
*/
exports.updateOne = function(collectionName,whereJSON,paramJSON,callback){
clientmongodb(function(err,client){
var db = client.db(dbname);
db.collection(collectionName).updateOne(whereJSON,paramJSON,function(err,result){
callback(err,result);
client.close();
})
})
}
/**
* 修改多条数据
* @param collectionName 集合名称
* @param whereJSON 修改条件
* @param paramJSON 修改内容
* @param callback 回调函数
*/
exports.updateMany = function(collectionName,whereJSON,paramJSON,callback){
clientmongodb(function(err,client){
var db = client.db(dbname);
db.collection(collectionName).updateMany(whereJSON,paramJSON,function(err,result){
callback(err,result);
client.close();
})
})
}
/**
* 删除一条数据
* @param collectionName 集合名称
* @param whereJSON 条件
* @param callback 回调函数
*/
exports.deleteOne = function(collectionName,whereJSON,callback){
clientmongodb(function(err,client){
var db = client.db(dbname);
db.collection(collectionName).deleteOne(whereJSON,function(err,result){
callback(err,result);
client.close();
})
})
}
/**
* 删除多条数据
* @param collectionName 集合名称
* @param whereJSON 条件
* @param callback 回调函数
*/
exports.deleteMany = function(collectionName,whereJSON,callback){
clientmongodb(function(err,client){
var db = client.db(dbname);
db.collection(collectionName).deleteMany(whereJSON,function(err,result){
callback(err,result);
client.close();
})
})
}
/**
* 查询
* @param collectionName
* @param whereStr
* @param B
* @param C
*/
exports.find = function(collectionName,whereStr,B,C) {
if (arguments.length == 3) {
var callback = B;
clientmongodb(function (err, client) {
var db = client.db(dbname);
db.collection(collectionName).find(whereStr).toArray(function (err, result) {
callback(err, result);
client.close();
})
})
} else {
var callback = C;
var paramJSON = B;
clientmongodb(function (err, client) {
var sort = (!paramJSON.sort) ? {} : paramJSON.sort;
var end = (!paramJSON.end) ? 0 : paramJSON.end;
var start = (!paramJSON.start) ? 0 : paramJSON.start;
var db = client.db(dbname);
db.collection(collectionName).find(whereStr).sort(sort).skip(start).limit(end).toArray(function (err, result) {
callback(err, result);
client.close;
})
})
}
}
/**
* 删除集合
* @param collectionName
* @param callback
*/
exports.drop = function(collectionName,callback){
clientmongodb(function(err,client){
var db = client.db(dbname);
db.collection(collectionName).drop(function(err,result){
callback(err,result);
client.close();
});
})
}
/**
* 查询总条数
* @param collectionName
* @param whereStr
* @param callback
*/
exports.count = function(collectionName,whereStr,callback){
clientmongodb(function(err,client){
var db = client.db(dbname);
db.collection(collectionName).find(whereStr).count(function(err,result){
callback(err,result);
client.close();
})
})
}
md5.js
/**
* Created by prettyRain on 2018/12/10.
*/
var crypto = require('crypto');
module.exports = function(password){
var md5 = crypto.createHash('md5');
return md5.update(password).digest('hex');
}
router.js
/**
* Created by prettyRain on 2018/12/10.
*/
var db = require('../model/db.js');
var md5 = require('../model/md5');
var formidable = require('formidable');
var util = require('util');
var fs = require('fs');
var gm = require('gm');
/**
* 首页
* @param req
* @param res
*/
exports.showIndex = function(req,res){
console.log(req.session.login);
if(req.session.login=='1'){
db.find("users",{username:req.session.username},function(err,result){
if(!err){
res.render('index',{login:"1",username:req.session.username,avatar:result[0].avatar,active:"全部说说"})
}
});
}else{
res.render('index',{login:"-1",active:"全部说说"});
}
}
/**
* 注册页面
* @param req
* @param res
*/
exports.showRegist = function(req,res){
if(req.session.login=='1'){
res.render('regist',{login:"1",username:req.session.username,avatar:req.session.avatar,active:"全部说说"})
}else{
res.render('regist',{login:"-2",active:"全部说说"});
}
}
/**
* 注册
* @param req
* @param res
*/
exports.doRegist = function(req,res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
console.log(util.inspect({fields: fields, files: files}));
var username = fields.username;
var password = md5(fields.password);
db.find("users",{username:username},{"end":1},function(err,result){
if(err){
res.send("-1");
return;
}
if(result.length > 0){
if(password == result[0].password){
res.send("-2")
return;
}
}
db.insertOne("users",{username:username,password:password,avatar:"headphoto.jpg"},function(err,result){
if(err){
res.send("-1");
return;
}
req.session.username = username;
req.session.login = "1";
res.send("1");
});
})
});
}
/**
* 登录页面
* @param req
* @param res
*/
exports.showLogin = function(req,res){
res.render('login',{login:"-3",active:"全部说说"});
}
/**
* 登录
* @param req
* @param res
*/
exports.doLogin = function(req,res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
var username = fields.username;
var password = md5(fields.password);
db.find('users',{username:username},function(err,result){
if(err){
res.send("-1");
return;
}
if(result.length > 0){
if(password == result[0].password){
req.session.login = '1';
req.session.username = username;
req.session.avatar = result[0].avatar;
res.send("1");
}else{
//用户名密码不匹配
res.send("-3");
};
}else{
//用户名不存在
res.send("-2")
}
})
})
}
/**
* 上传图片页面
* @param req
* @param res
*/
exports.showAvatar = function(req,res){
if(req.session.login == "1"){
res.render('avatar',{login:'1',username:req.session.username,active:"全部说说"});
}else{
res.render('avatar',{login:'-1',active:"全部说说"});
}
}
/**
* 上传图片
* @param req
* @param res
*/
exports.doAvatar = function(req,res){
if(req.session.login != "1"){
res.send("-2");
return;
}
var form = new formidable.IncomingForm();
form.uploadDir = "./avatar";
form.parse(req, function(err, fields, files) {
var oldpath = "./"+files.tupian.path;
var newpath = "./avatar/"+req.session.username+".jpg";
fs.rename(oldpath,newpath,function(err){
if(err){
res.send("-1");
return;
}
//压缩图片
gm(newpath)
.resize(500, 500, '!')
.noProfile()
.write(newpath, function (err) {
if (err) {
console.log(err);
res.send("-1");
return;
}
res.send({username:req.session.username});
});
})
})
}
/**
* 裁切图片
* @param req
* @param res
*/
exports.setAvatar = function(req,res){
if(req.session.login != "1"){
res.send("-2");
return;
}
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
var x = fields.x;
var y = fields.y;
var w = fields.w;
var h = fields.h;
console.log(fields);
//裁切图片
gm("./avatar/"+req.session.username+".jpg")
//裁剪参数(w,h,x,y)
.crop(w,h,x,y)
.write("./avatar/"+req.session.username+".jpg",function(err){
if(!err) {
console.log(1)
db.updateOne("users",{username:req.session.username},{$set: {avatar:req.session.username+".jpg"} },function(err,result){
if(err){
console.log(err);
res.send("-1");
return;
}
console.log("done");
res.send("1");
})
}
})
})
}
/**
* 添加说说
* @param req
* @param res
* @param next
*/
exports.addPost = function(req,res,next){
if(req.session.login=='1') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var username = fields.username;
var content = fields.content;
db.insertOne("posts", {username: username, content: content, creatTime:new Date()}, function (err, reuslt) {
if (err) {
res.send("-2");
return;
}
res.send("1");
})
})
}else{
res.send("-1");
}
}
/**
* 查询所有说说
* @param req
* @param res
* @param next
* @constructor
*/
exports.AllPosts = function(req,res,next){
var currentPage = parseInt(req.query.currentPage);
var pageSize = parseInt(req.query.pageSize);
var start = (currentPage-1)*pageSize;
var end = pageSize;
db.find('posts',{},{start:start,end:end,sort:{creatTime:-1}},function(err,result){
if(err){
res.send("");
return;
}
db.count('posts',{},function(err,result1){
if(err){
res.send("");
return;
}
var totalPage = result1%pageSize==0?result1/pageSize:(result1/pageSize + 1);
(function itempost(i){
if(!result.length || result.length == i){
res.send({list:result,totalPage:parseInt(totalPage),currentPage:currentPage});
return;
}
db.find('users',{username:result[i].username},function(err,result2){
if(err){
console.log(err);
return;
}
result[i].avatar = result2[0].avatar;
i++;
itempost(i);
});
})(0)
})
})
}
/**
* 成员列表
* @param req
* @param res
* @param next
*/
exports.userlist = function(req,res,next){
if(req.session.login=='1'){
db.find("users",{username:req.session.username},function(err,result){
if(!err){
db.find("users",{},function(err,results){
if(!err){
res.render('userlist',{login:"1",username:req.session.username,avatar:result[0].avatar,active:"成员列表",users:results})
}
})
}
});
}else{
db.find("users",{},function(err,result){
if(!err){
res.render('userlist',{login:"-1",active:"成员列表",users:result});
}
})
}
}
/**
* 某个人的说说
* @param req
* @param res
* @param next
*/
exports.user = function(req,res,next){
var user = req.params.username;
if(req.session.login=='1'){
db.find("users",{username:req.session.username},function(err,result){
if(!err){
db.find("users",{username:user},function(err,result1){
if(!err){
db.find('posts',{username:user},function(err,result2){
for(var i in result2){
result2[i].avatar = result1[0].avatar;
}
console.log(result2);
res.render('user',{login:"1",username:req.session.username,avatar:result[0].avatar,active:"我的说说",userposts:result2});
})
}
})
}
});
}else{
db.find("users",{username:user},function(err,result1){
if(!err){
db.find('posts',{username:user},function(err,result2){
for(var i in result2){
result2[i].avatar = result1[0].avatar;
}
console.log(result2);
res.render('userlist',{login:"-1",active:"我的说说",userposts:result2});
})
}
})
}
}
/*exports.queryUserByUsername = function(req,res,next){
var username = req.query.username;
console.log(username);
db.find('users',{username:username},function(err,result){
if(err){
console.log(err);
res.send("");
return;
}
res.send(result[0]);
})
}*/
avatar.ejs
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>上传头像</title>
<link rel="stylesheet" href="/toptip/toptip.css">
<link rel="stylesheet" href="/jcrop/jquery.Jcrop.css">
<link rel="stylesheet" href="/jcrop/demos.css">
<!-- Bootstrap core CSS -->
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--头部-->
<%include head.ejs%>
<div class="container theme-showcase" role="main">
<div class="jumbotron">
<div class="media" style="margin-top:40px;">
<form enctype="multipart/form-data" id="formId" >
<div class="form-group">
<label for="exampleInputFile">头像</label>
<input type="file" id="exampleInputFile" accept="image/gif, image/jpeg" name="tupian">
</div>
<p class="btn btn-default psubmit">提交<p/>
</form>
</div>
<!--裁切图片-->
<div id="outer" style="display:none;">
<div class="jcExample">
<div class="article">
<h1>上传头像拖动例子</h1>
<p id="xianshi"></p>
<table>
<tr>
<td>
<img id="target" alt="Flowers" style="width:500px;height:500px;"/>
</td>
<td>
<div style="width:100px;height:100px;overflow:hidden;" id="aa">
<img id="preview" alt="Preview" class="jcrop-preview" />
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="subdiv">
<p class="subp btn btn-danger">提交裁切</p>
</div>
</div>
</div>
</div> <!-- /container -->
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/bootstrap/js/jquery-1.11.3.js"></script>
<script src="/toptip/toptip.js"></script>
<script src="/jcrop/jquery.min.js"></script>
<script src="/jcrop/jquery.Jcrop.min.js"></script>
</body>
</html>
<script type="text/javascript">
var tip = tipAlert();
$('.psubmit').on('click',function(){
if(!$('#exampleInputFile').val()){
tip('内容不能为空');
return ;
}
$.ajax({
type:"post",
url:"/doAvatar",
dataType:"json",
data:new FormData(document.getElementById("formId")),
contentType:false,
processData:false,
success:function(result){
if(result=="-1"){
tip('上传图片错误');
return;
}else if(result == "-2"){
window.location.href = "/";
}
$('#outer').slideDown(1000);
$('#target').width("500px").height("500px").attr("src","/"+result.username+".jpg");
$('#preview').attr("src","/"+result.username+".jpg");
//加载裁切图片js
new cutImage().init();
}
})
$(".subp").on('click',function(){
$.post("/setAvatar",xyhw,function(result){
if(result == "-2"){
tip("报错");
return;
}
window.location.href = "/";
})
})
})
var xyhw = {};
var x,y,h,w;
function cutImage(){
var oop = this;
this.option = {
x:170,
y:110,
w:350,
h:200,
t:'target',
p:'preview',
o:'aa',
q:'xianshi'
}
this.init = function(){
oop.target();
}
this.target = function(){
$('#'+oop.option['t']).Jcrop({
onChange: oop.updatePreview,
onSelect: oop.updatePreview,
aspectRatio: 1,
setSelect: [ oop.option['x'], oop.option['y'], oop.option['w'],oop.option['h'] ],
bgFade: true,
bgOpacity: .5
});
}
this.updatePreview = function(obj){
if (parseInt(obj.w) > 0)
{
var rx = $('#'+oop.option['o']).width()/ obj.w;
var ry = $('#'+oop.option['o']).height()/ obj.h;
var holder = document.querySelector('.jcrop-holder').children[0];
w = getcurrentStyle(holder,"width");
h = getcurrentStyle(holder,"height");
x = getcurrentStyle(holder,"left");
y = getcurrentStyle(holder,"top");
document.querySelector("#xianshi").innerHTML = "x:"+x+";"+"y"+y+";"+"w:"+w+"h:"+h;
xyhw.x = parseInt(x);
xyhw.y = parseInt(y);
xyhw.w = parseInt(w);
xyhw.h = parseInt(h);
$('#'+oop.option['p']).css({
width: Math.round(rx*$('#'+oop.option['t']).width()) + 'px',
height: Math.round(ry*$('#'+oop.option['t']).height()) + 'px',
marginLeft: '-' + Math.round(rx * obj.x) + 'px',
marginTop: '-' + Math.round(ry * obj.y) + 'px'
});
}
}
}
function getcurrentStyle(ele,attr){
if(window.getComputedStyle){
return window.getComputedStyle(ele,null)[attr];
}else{
//IE
return ele.currentStyle(attr);
}
}
</script>
head.ejs
<!-- Fixed navbar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">班级说说</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li <%if(active=='全部说说'){%>class = "active" <%}%> ><a href="/">全部说说</a></li>
<li <%if(active=='我的说说'){%>class = "active" <%}%> >
<%if(login == '1'){%>
<a href="/user/<%=username%>">我的说说</a>
<%}else{%>
<a href="/">我的说说</a>
<%}%>
</li>
<li <%if(active=='成员列表'){%>class = "active" <%}%> ><a href="/userlist">成员列表</a></li>
</ul>
<ul class="nav navbar-nav pull-right">
<%if(login != null && login=='-1'){%>
<li><a href="/regist">注册</a></li>
<li><a href="/login">登录</a></li>
<%}else if(login == '1'){%>
<li><a href="javascript:void(0);">欢迎,<%=username%></a></li>
<li><a href="/avatar">设置个人资料</a></li>
<%}else if(login == '-2'){%>
<li class="active"><a href="javascript:void(0);">注册</a></li>
<li><a href="/login">登录</a></li>
<%}else if(login == '-3'){%>
<li><a href="/regist">注册</a></li>
<li class="active"><a href="javascript:void(0);" >登录</a></li>
<%}%>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
index.ejs
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>班级说说</title>
<!-- Bootstrap core CSS -->
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="/toptip/toptip.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--头部-->
<%include head.ejs%>
<div style="background:#eee;">
<div class="container theme-showcase" role="main">
<div class="row" style="padding-top:100px;padding-bottom:20px;">
<%if(login=="1"){%>
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object" src="/<%=avatar%>" alt="..." style="width:150px;">
</a>
</div>
<div class="media-body">
<h4 class="media-heading username"><%=username%></h4>
<textarea style="display:block;width:500px;height:90px;"></textarea>
<botton id="bottonText" class="btn btn-default" >发表说说</botton>
</div>
</div>
<%}else{%>
<div class="col-md-6">
<h3 style="font-weight:700;">班级动态</h3>
<p class="lead">欢迎积极发表说说动态</p>
<p><a class="btn btn-lg btn-success" href="#" role="button">注册</a></p>
</div>
<div class="col-md-6">
<form enctype="multipart/form-data" id="formId">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" placeholder="请输入用户名" name="username">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" placeholder="请输入密码" name="password" id="password">
</div>
<div class="checkbox">
<label>
<input type="checkbox"> 记住密码
</label>
</div>
<p class="btn btn-default psubmit">提交<p/>
</form>
</div>
<%}%>
</div>
</div> <!-- /container -->
</div>
<div>
<div class="container" style="padding-top:20px;" id="contentId">
</div>
</div>
<div>
<div class="container" style="height:100px;">
<footer class="footer" style="position:fixed;bottom:20px;">
<p>© 2018 Company, Inc.</p>
</footer>
</div>
</div>
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/bootstrap/js/jquery-1.11.3.js"></script>
<script src="/toptip/toptip.js"></script>
</body>
</html>
<script>
var tip = tipAlert();
//tip("这是一个提示");
//添加说说
$('.theme-showcase').on('click','#bottonText',function(){
if(!$('textarea').val()){
tip('发表内容不能为空');
return;
}
$.post('/addPost',{content:$('textarea').val(),username:$('.username').html()},function(data){
if(data == "-2"){
tip("error");
}else if(data == "-1"){
window.location.href = "/";
}else{
getPage();
}
})
})
//注册
var psubmit = document.querySelector(".theme-showcase");
psubmit.onclick = function(event){
var event = event || window.event;
if(event.target.className.indexOf("psubmit") != -1){
if(!$('#username').val() || !$('#password').val()){
tip("用户名密码不能为空");
}
$.ajax({type:"post",url:"/doLogin",data:$("#formId").serialize(),success:function(result){
if(result == "-1"){
tip("登录失败")
}else if(result == "-2"){
tip("用户名不存在");
}else if(result == "-3"){
tip("用户名密码不匹配");
}else{
tip("登录成功");
window.location.href = "/";
}
}})
}
}
//加载说说
function AllPosts(objId,pageSize){
this.totalPage = 0;
this.currentPage = 1;
this.list = [];
this.config = {
obj:$("#"+objId),
pageSize:pageSize
}
}
AllPosts.prototype = {
//拼接数据
clientPage : function(currentPage){
var this_ = this;
if(!!currentPage){
this_.currentPage = currentPage;
}
this.serverPage(function(){
var str = "";
var count = 0;
for(var i = 0; i < this_.list.length; i++){
if(count == 0){
str += '<div class="row" style="padding-top:20px;">';
}
str += '<div class="col-md-4">'
+'<div class="media">'
+'<div class="media-left">'
+'<a href="/user/'+this_.list[i].username+'">'
+'<img class="media-object img-circle" style="width:100px;" src="'+this_.list[i].avatar+'" alt="...">'
+'</a>'
+'</div>'
+'<div class="media-body">'
+'<h4 class="media-heading">'+this_.list[i].username+'</h4>'
+ this_.list[i].content
+'</div>'
+'</div>'
+'</div>';
if(count == 2){
str += '</div>';
}
count ++;
if(count == 3){
count = 0;
}
}
str += '<nav aria-label="Page navigation">'
+'<ul class="pagination">';
if(this_.currentPage > 1){
str += '<li>'
+'<a href="javascript:getPage('+(this_.currentPage-1)+');" aria-label="Previous">'
+'<span aria-hidden="true">«</span>'
+'</a>'
+'</li>';
}
var startnum = (this_.currentPage-2)>1?this_.currentPage:1;
var endnum = (this_.currentPage + 2 <= this_.totalPage)?this_.currentPage + 2:this_.totalPage;
for(var i = startnum ; i <= endnum ; i++ ){
if(i == this_.currentPage){
str += '<li class="active"><a href="javascript:void(0);">'+i+'</a></li>';
}else{
str += '<li><a href="javascript:getPage('+i+');">'+i+'</a></li>'
}
}
if(this_.currentPage < this_.totalPage){
str += '<li>'
+'<a href="javascript:getPage('+(this_.currentPage+1)+');" aria-label="Previous">'
+'<span aria-hidden="true">»</span>'
+'</a>'
+'</li>';
}
str += ' </ul></nav>';
this_.config.obj.html(str);
})
},
//请求数据
serverPage : function(fn){
var this_ = this;
$.get("/AllPosts",{currentPage:this_.currentPage,pageSize:this_.config.pageSize},function(data){
this_.totalPage = data.totalPage;
this_.list = data.list;
this_.currentPage = data.currentPage;
//请求数据后进行拼接
fn&&fn();
})
}
}
var AllPosts = new AllPosts('contentId',3);
var getPage = function(currentPage){
AllPosts.clientPage(currentPage)
}
getPage();
</script>
login.ejs
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>Theme Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="/toptip/toptip.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--头部-->
<%include head.ejs%>
<div class="container theme-showcase" role="main">
<div class="jumbotron">
<div class="media" style="margin-top:40px;">
<form enctype="multipart/form-data" id="formId">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" placeholder="请输入用户名" name="username">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" placeholder="请输入密码" name="password" id="password">
</div>
<div class="checkbox">
<label>
<input type="checkbox"> 记住密码
</label>
</div>
<p class="btn btn-default psubmit">提交<p/>
</form>
</div>
</div>
</div> <!-- /container -->
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/bootstrap/js/jquery-1.11.3.js"></script>
<script src="/toptip/toptip.js"></script>
<script>
var tip = tipAlert();
//tip("这是一个提示");
var psubmit = document.querySelector(".psubmit");
psubmit.onclick = function(){
if(!$('#username').val() || !$('#password').val()){
tip("用户名密码不能为空");
}
$.ajax({type:"post",url:"/doLogin",data:$("#formId").serialize(),success:function(result){
if(result == "-1"){
tip("登录失败")
}else if(result == "-2"){
tip("用户名不存在");
}else if(result == "-3"){
tip("用户名密码不匹配");
}else{
tip("登录成功");
window.location.href = "/";
}
}})
}
/*psubmit.addEventListener("click",function(){
console.log(1);
$.ajax({type:"post",url:"/doregist",data:$("#formId").serialize(),success:function(result){
if(result == "-1"){
tip("注册失败")
}else if(result == "-2"){
tip("用户名已被占用");
}else{
tip("注册成功");
}
}})
})*/
</script>
</body>
</html>
regist.ejs
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>Theme Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="/toptip/toptip.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--头部-->
<%include head.ejs%>
<div class="container theme-showcase" role="main">
<div class="jumbotron">
<div class="media" style="margin-top:40px;">
<form enctype="multipart/form-data" id="formId">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" placeholder="请输入用户名" name="username">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" placeholder="请输入密码" name="password" id="password">
</div>
<!--<div class="form-group">
<label for="exampleInputFile">头像</label>
<input type="file" id="exampleInputFile">
</div>-->
<p class="btn btn-default psubmit">提交<p/>
</form>
</div>
</div>
</div> <!-- /container -->
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/bootstrap/js/jquery-1.11.3.js"></script>
<script src="/toptip/toptip.js"></script>
<script>
var tip = tipAlert();
//tip("这是一个提示");
var psubmit = document.querySelector(".psubmit");
psubmit.onclick = function(){
if(!$('#username').val() || !$('#password').val()){
tip("用户名密码不能为空");
}
$.ajax({type:"post",url:"/doRegist",data:$("#formId").serialize(),success:function(result){
if(result == "-1"){
tip("注册失败")
}else if(result == "-2"){
tip("用户名已被占用");
}else{
tip("注册成功");
window.location.href = "/";
}
}})
}
/*psubmit.addEventListener("click",function(){
console.log(1);
$.ajax({type:"post",url:"/doregist",data:$("#formId").serialize(),success:function(result){
if(result == "-1"){
tip("注册失败")
}else if(result == "-2"){
tip("用户名已被占用");
}else{
tip("注册成功");
}
}})
})*/
</script>
</body>
</html>
user.ejs
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>班级说说</title>
<!-- Bootstrap core CSS -->
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="/toptip/toptip.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--头部-->
<%include head.ejs%>
<div >
<div class="container theme-showcase" role="main">
<div class="row" style="padding-top:100px;padding-bottom:20px;">
<%for(var i = 0 ; i < userposts.length ; i++){%>
<div class="col-md-4">
<div class="media" style="border-bottom:1px dashed #ccc;padding-bottom:5px;">
<div class="media-left">
<a href="#">
<img class="media-object" src="/<%=userposts[i].avatar%>" alt="..." style="width:90px;border-radius:45px/45px;">
</a>
</div>
<div class="media-body">
<h4 class="media-heading username"><%=userposts[i].username%></h4>
<%=userposts[i].content%>
</div>
</div>
</div>
<%}%>
</div>
</div> <!-- /container -->
</div>
<div>
<div class="container" style="height:100px;">
<footer class="footer" style="position:fixed;bottom:20px;">
<p>© 2018 Company, Inc.</p>
</footer>
</div>
</div>
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/bootstrap/js/jquery-1.11.3.js"></script>
<script src="/toptip/toptip.js"></script>
</body>
</html>
<script>
</script>
userlist.ejs
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>班级说说</title>
<!-- Bootstrap core CSS -->
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="/toptip/toptip.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--头部-->
<%include head.ejs%>
<div >
<div class="container theme-showcase" role="main">
<div class="row" style="padding-top:100px;padding-bottom:20px;">
<%for(var i = 0 ; i < users.length ; i++){%>
<div class="media" style="border-bottom:1px dashed #ccc;padding-bottom:5px;">
<div class="media-left">
<a href="#">
<img class="media-object" src="/<%=users[i].avatar%>" alt="..." style="width:90px;border-radius:45px/45px;">
</a>
</div>
<div class="media-body">
<h4 class="media-heading username"><%=users[i].username%></h4>
</div>
</div>
<%}%>
</div>
</div> <!-- /container -->
</div>
<div>
<div class="container" style="height:100px;">
<footer class="footer" style="position:fixed;bottom:20px;">
<p>© 2018 Company, Inc.</p>
</footer>
</div>
</div>
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/bootstrap/js/jquery-1.11.3.js"></script>
<script src="/toptip/toptip.js"></script>
</body>
</html>
app.js
/**
* Created by prettyRain on 2018/12/10.
*/
var express = require('express');
var app = express();
var session = require('express-session');
var cookie = require('cookie-parser');
var router = require('./router/router.js');
//加载静态文件
app.use(express.static('./public'));
app.use(express.static('./avatar'));
//ejs模板
app.set("view engine",'ejs');
app.use(session({
secret: '12345',
name: 'testapp', //这里的name值得是cookie的name,默认cookie的name是:connect.sid
cookie: {maxAge: 800000 }, //设置maxAge是80000ms,即80s后session和相应的cookie失效过期
resave: false,
saveUninitialized: true
}));
//路由
app.get('/',router.showIndex);
//注册
app.get('/regist',router.showRegist);
app.post('/doRegist',router.doRegist);
//登录
app.get('/login',router.showLogin);
app.post('/doLogin',router.doLogin);
app.get('/avatar',router.showAvatar);
app.post('/doAvatar',router.doAvatar);
app.post('/setAvatar',router.setAvatar);
//添加说说
app.post("/addPost",router.addPost);
app.get("/AllPosts",router.AllPosts);
//成员列表
app.get("/userlist",router.userlist);
app.get("/user/:username",router.user);
app.listen(3000);
settings.js
/**
* Created by prettyRain on 2018/12/10.
*/
module.exports = {
"dburl" : "mongodb://localhost:27017",
"dbname" : "shuoshuo"
}
首页样式:
注册登录样式:
image.png
修改个人资料页面:
image.png
我的说说页面:
image.png
成员列表:
image.png