搭建开发环境
全局安装express
和 express-generator
脚手架
npm install express -g
npm install -g express-generator
创建项目
我使用ejs模板引擎,所以是-e
express -e expressNews
初始化项目
cd expressNews
npm install
使用VS Code打开项目,找到package.json
,修改scripts
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon ./bin/www"
},
在启动项目时使用nodemon
指令来启动,这样当我们项目代码更改时它能够自动重新运行.
如果还没安装就在控制台输入npm i nodemon -g
全局安装nodemon
.
修改项目入口文件app.js
//...
//删除users路由,同时删除routers目录下的users.js
var usersRouter = require('./routes/users');
//添加监听端口
app.listen(8100, function () {
console.log('启动成功:http://localhost:8100')
})
//...
//删除user路由挂载
app.use('/users', usersRouter);
启动项目
npm dev
运行结果:
搭建前端页面
目录结构
├── app.js
├── bin
│ └── www
├── node_modules
├── package-lock.json
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
├── routes
│ ├── index.js
│ ├── login.js
│ └── signup.js
└── views
├── error.ejs
├── index.ejs
├── login.ejs
└── signup.ejs
登录页面 login.ejs
<!-- views/login.ejs -->
<!doctype html>
<html>
<head>
<title>Node Authentication</title>
<link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css"> <!-- load bootstrap css -->
<link rel="stylesheet" href="http://libs.baidu.com/fontawesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
<style>
body { padding-top:80px; }
</style>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span> Login</h1>
<!-- LOGIN FORM -->
<form action="/login" method="post">
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" name="username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password">
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="remember" value="yes">Remember Me
</label>
</div>
<button type="submit" class="btn btn-primary btn-lg">Login</button>
</form>
<hr>
<p>Need an account? <a href="/signup">Signup</a></p>
<p>Or go <a href="/">home</a>.</p>
</div>
</div>
</body>
</html>
注册页面signup.ejs
<!-- views/signup.ejs -->
<!doctype html>
<html>
<head>
<title>Node Authentication</title>
<link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css"> <!-- load bootstrap css -->
<link rel="stylesheet" href="http://libs.baidu.com/fontawesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
<style>
body { padding-top:80px; }
</style>
</head>
<body>
<div class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span> Signup</h1>
<!-- LOGIN FORM -->
<form action="/signup" method="post">
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" name="username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password">
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" class="form-control" name="repassword">
</div>
<button type="submit" class="btn btn-primary btn-lg">Signup</button>
</form>
<hr>
<p>Already have an account? <a href="/login">Login</a></p>
<p>Or go <a href="/">home</a>.</p>
</div>
</div>
</body>
</html>
创建路由文件routes/login.js
,routes/signup.js
//`routes/login.js`
var express = require('express')
var router = express.Router()
router.get('/', function (req, res) {
res.render('login')
})
module.exports = router
//`routes/signup.js`
var express = require('express')
var router = express.Router()
router.get('/', function (req, res) {
res.render('signup')
})
module.exports = router
修改app.js
//添加路由
var loginRouter = require('./routes/login');
var signupRouter = require('./routes/signup');
//挂载路由
app.use('/login', loginRouter);
app.use('/signup', signupRouter);
完成以上,我们创建的登录页面http://localhost:8100/login
和注册页面http://localhost:8100/signup
就可以访问了。
引入数据库
先在数据库中创建一个表用来存储信息,我创建的这个表名是userinfo
,结构如下图
在项目中安装mysql
npm install mysql --save
创建数据库配置文件models/db.config.js
,引入数据库mysql
,创建数据库连接池。
//引入数据库
const mysql = require("mysql");
var connection = mysql.createPool({
host: 'localhost',
user: 'root',
password: '123456',
database:'User'//指定要操作哪个数据库
});
module.exports = connection;
获取数据库连接
使用数据库连接池,创建models/user.model.js
文件
1.这里我先创建User
数据对象,用于接收注册时所填账号和密码。
2.监听数据库是否连接成功
3.getConnection
获取数据库连接
4.在User
对象上添加一个signup
函数,在路由中使用函数回调的方式返回注册结果
5.编写sql插入数据操作语句,在最后使用callback
回调函数返回操作结果
const sql = require("./db.config.js");
// constructor
const User = function(user) {
this.username = user.username;
this.password = user.password;
};
sql.on('connection', function () {
console.log('数据库连接成功')
})
sql.getConnection(function (err,connection) {
//注册用户
User.signup = function (newUser,callback) {
const sql = "INSERT INTO userinfo(id,username,password) VALUES(0,?,?)";
connection.query(sql,[newUser.username,newUser.password],function(err,result){
if(err){
console.log("USE Error:"+err.message);
return;
}
console.log("注册用户");
callback(err,result);
});
}
//根据用户名查找用户
User.findByUser = function (username,callback) {
const sql = "SELECT * FROM userinfo WHERE username =?"
connection.query(sql, [username], function (err,result) {
if(err){
console.log("findByUser Error:"+err.message);
return;
}
console.log("根据用户名查找用户");
callback(err,result);
})
}
})
module.exports = User
由于在注册的时候,往往会提示我们账号是否已经使用,所以在注册账号时需要通过用户名在数据库查找是否存在账号,如果不存在则注册成功,存在则提示更换新账号。
因此findByUser
函数的作用就是在注册时根据用户名查找用户。
注册路由实现
1.注册需要将新用户的账号和密码写入数据库,账号可以直接写入数据库,但密码一般不会直接存入到数据库中,会将密码加密后存入数据库中,能够提高账号的安全性。
2.密码加密用到一个包 crypto
,可以直接引入。
//routes/signup.js
var express = require('express')
var router = express.Router()
var crypto = require('crypto')
var User = require('../models/user.model')
var TITLE_REG = '注册';
//页面渲染
router.get('/', function (req, res) {
res.render('signup', { title: TITLE_REG })
})
//注册表单提交
router.post('/', function (req, res) {
var password = req.body.password,
username = req.body.username
//密码加密
var md5 = crypto.createHash('md5')
var userPwd = md5.update(password).digest('hex')
//创建一个数据库操作对象(User)
console.log(userPwd,userPwd.length)
const user = new User({
username: username,
password: userPwd
});
//数据库查找用户名称是否存在
User.findByUser(username, (err, data) => {
if (err) {
res.locals.error = err;
res.render('signup', { title: TITLE_REG });
return;
}
if (data != null && data.length > 0) {
res.locals.error = "用户名已存在"
res.render('signup', { title: TITLE_REG });
return;
}
//注册
User.signup(user, (err, data) => {
if (err) {
res.locals.error = err;
res.render('signup', { title: TITLE_REG });
return
}
res.locals.success = '注册成功,请点击 <a class="btn btn-link" href="/login" role="button"> 登录 </a>' ;
res.render('signup', { title: TITLE_REG });
})
})
})
module.exports = router
注册页面效果
前面搭建前端页面时已经写好了静态页面,这里展示注册页面最终代码。
<!-- views/signup.ejs -->
<!DOCTYPE html>
<html>
<head>
<title><%-title%></title>
<link
rel="stylesheet"
href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css"
/>
<!-- load bootstrap css -->
<link
rel="stylesheet"
href="http://libs.baidu.com/fontawesome/4.0.3/css/font-awesome.min.css"
/>
<!-- load fontawesome -->
<style>
body {
padding-top: 80px;
}
</style>
</head>
<body>
<div id="container" class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span> Signup</h1>
<% if(locals.success){%>
<%- success %>
<%}%> <%if(locals.error){%>
<%- error %>
<%}%>
<!-- LOGIN FORM -->
<form action="" method="post">
<div class="form-group">
<label>Username</label>
<input
type="text"
class="form-control"
id="username"
name="username"
/>
</div>
<div class="form-group">
<label>Password</label>
<input
type="password"
class="form-control"
id="password"
name="password"
/>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input
type="password"
class="form-control"
id="repassword"
name="repassword"
/>
</div>
<button id="btnSub" type="submit" class="btn btn-primary btn-lg">
Signup
</button>
</form>
<hr />
<p>Already have an account? <a href="/login">Login</a></p>
<p>Or go <a href="/">home</a>.</p>
</div>
</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
//禁用“确认重新提交表单”
window.history.replaceState(null, null, window.location.href);
$('#btnSub').on('click', function () {
var usernameVal = $.trim($('#username').val()),
passwordVal = $.trim($('#password').val()),
repasswordVal = $.trim($('#repassword').val()),
errorTip = '<div id="errorTip" class="alert alert-warning"></div> ';
$('#errorTip').remove();
if (usernameVal.length == 0) {
$('#container').prepend(errorTip);
$('#errorTip').text('用户名不能为空');
$('#username').focus();
return false;
}
if (passwordVal.length == 0) {
$('#container').prepend(errorTip);
$('#errorTip').text('密码不能为空');
$('#password').focus();
return false;
}
if (repasswordVal.length == 0) {
$('#container').prepend(errorTip);
$('#errorTip').text('确认密码不能为空');
$('#repassword').focus();
return false;
}
if (passwordVal != repasswordVal) {
$('#container').prepend(errorTip);
$('#errorTip').text('两次密码不一致');
$('#repassword').focus();
return false;
}
return true;
});
});
</script>
</body>
</html>
登录路由实现
在登录的时候再将密码通过同样的方式crypto
进行加密,与数据库中的存储的密码进行比对,相同的话则登录成功。
//routes/login.js
var express = require('express')
var router = express.Router()
var crypto = require('crypto')
var User = require('../models/user.model')
var TITLE_LOGIN = '登录';
//页面渲染
router.get('/', function (req, res) {
res.render('login', { title: TITLE_LOGIN })
})
//用户登录
router.post('/', function (req, res) {
//接收登录参数
var password = req.body.password,
username = req.body.username,
isRem = req.body.remember,
md5 = crypto.createHash('md5');
//根据用户名查找用户判断是否存在
User.findByUser(username, function (err,result) {
if (err) {
res.locals.error = err;
res.render('login', { title: TITLE_LOGIN });
return;
}
password = md5.update(password).digest('hex');
if (result.length == 0) {
res.locals.error = '用户不存在';
res.render('login',{title:TITLE_LOGIN});
return;
}
//判断用户名密码是否和数据库相同
if (result[0]['username'] != username || result[0]['password'] != password) {
res.locals.error = '用户名或密码有误';
res.render('login', { title: TITLE_LOGIN });
return;
} else {
//cookie记住登录状态
if(isRem){
res.cookie('islogin', username, { maxAge: 360000 });
}
res.locals.username = username;
req.session.username = res.locals.username;
console.log(req.session.username);
res.redirect('/');
}
})
})
module.exports = router
最后登录成功的状态是存在session
中的,这样在刷新的时候就能保持登录状态了。
登录页面效果
前面搭建前端页面时已经写好了静态页面,这里展示登录页面最终代码。
<!-- views/login.ejs -->
<!DOCTYPE html>
<html>
<head>
<title><%-title%></title>
<link
rel="stylesheet"
href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css"
/>
<!-- load bootstrap css -->
<link
rel="stylesheet"
href="http://libs.baidu.com/fontawesome/4.0.3/css/font-awesome.min.css"
/>
<!-- load fontawesome -->
<style>
body {
padding-top: 80px;
}
</style>
</head>
<body>
<div id="container" class="container">
<div class="col-sm-6 col-sm-offset-3">
<h1><span class="fa fa-sign-in"></span> Login</h1>
<% if(locals.success){%>
<%- success %>
<%}%> <%if(locals.error){%>
<%- error %>
<%}%>
<!-- LOGIN FORM -->
<form action="" method="post">
<div class="form-group">
<label>Username</label>
<input
type="text"
class="form-control"
id="username"
name="username"
/>
</div>
<div class="form-group">
<label>Password</label>
<input
type="password"
class="form-control"
id="password"
name="password"
/>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="remember" value="yes" />Remember Me
</label>
</div>
<button id="btnSub" type="submit" class="btn btn-primary btn-lg">
Login
</button>
</form>
<hr />
<p>Need an account? <a href="/signup">Signup</a></p>
<p>Or go <a href="/">home</a>.</p>
</div>
</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
//禁用“确认重新提交表单”
window.history.replaceState(null, null, window.location.href);
$('#btnSub').on('click', function () {
var usernameVal = $.trim($('#username').val()),
passwordVal = $.trim($('#password').val()),
errorTip = '<div id="errorTip" class="alert alert-warning"></div> ';
$('#errorTip').remove();
if (usernameVal.length == 0) {
$('#container').prepend(errorTip);
$('#errorTip').text('用户名不能为空');
$('#username').focus();
return false;
}
if (passwordVal.length == 0) {
$('#container').prepend(errorTip);
$('#errorTip').text('密码不能为空');
$('#password').focus();
return false;
}
return true;
});
});
</script>
</body>
</html>
express-session保存登录状态
session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session 保存在服务器上。
安装 express-session
npm install express-session --save
app.js中引入
cookie-parser
(express默认已安装)
//...
var cookieParser = require('cookie-parser');
var session = require('express-session')
//...
var indexRouter = require('./routes/index');
var loginRouter = require('./routes/login');
var logoutnRouter = require('./routes/logout');
var signupRouter = require('./routes/signup');
//...
app.use(cookieParser("huhao"));
//使用session中间件
app.use(session({
secret: 'huhao',// 相当于是一个加密密钥,值可以是任意字符串
resave:true, // 强制session保存到session store中
saveUninitialized:false// 强制没有“初始化”的session保存到storage中
}))
app.use('/', indexRouter);
app.use('/login', loginRouter);
app.use('/logout', logoutnRouter);
app.use('/signup', signupRouter);
这里还引入和挂载了退出登录相关路由logout
,后面会创建对应的文件。
首页路由实现
进入页面通过session.username
判断是否登录,如果存在进入首页,不存在进入登录页面。
//routes/index.js
var express = require('express');
var router = express.Router();
var moment = require('moment')
var News = require('../models/news.model')
var TITLE_INDEX = '新闻'
/* GET home page. */
router.get('/', function (req, res) {
if(req.cookies.islogin){
console.log('cookie:'+req.cookies.islogin);
req.session.username = req.cookies.islogin;
}
if(req.session.username){
console.log('session:'+req.session.username);
res.locals.username = req.session.username;
}else{
res.redirect('/login');
return;
}
res.render('index', { title: TITLE_INDEX });
});
module.exports = router;
退出登录
通过destroy()方法清空session数据,跳转到登录页面。
创建routes/logout.js
文件
var express = require("express");
router = express.Router();
router.get('/',function(req,res){
req.session.destroy();
res.redirect('/login');
});
module.exports = router;
完成以上步骤就实现了整个用户注册和登录的功能。
实现新闻管理
1.先在数据库中创建一个表用来存储信息,我创建的这个表名是news
,结构如下图
2.连接新闻数据库,创建models/news.model.js
文件
3.创建News
函数接收新增新闻的参数
4.写了一个公共的sql执行函数
5.获取数据库连接
6.编写新增,删除,修改,查找的sql函数
const sql = require("./db.config.js");
// constructor
const News = function(news) {
this.title = news.title;
this.content = news.content;
this.img = news.img;
this.time = news.time
};
//sql执行函数
function querySql (connection,sql,data,callback) {
connection.query(sql, data, function (err,result) {
if(err){
console.log("Error:"+err.message);
return;
}
callback(err,result);
})
}
sql.getConnection(function (err,connection) {
//新增
News.add = function (newsData, callback) {
const sql = "INSERT INTO news(id,title,content,img,time) VALUES(0,?,?,?,?)";
const data = [newsData.title, newsData.content, newsData.img, newsData.time]
querySql(connection,sql,data,callback)
}
//删除
News.delete = function (id, callback) {
const sql = "DELETE FROM news WHERE id=?";
const data = [id]
querySql(connection,sql,data,callback)
}
//修改
News.update = function (newsData, callback) {
const sql = "UPDATE news SET title=?,content=?,img=?,time=? WHERE id=?";
const data = [newsData.title,newsData.content,newsData.img,newsData.time,newsData.id]
querySql(connection,sql,data,callback)
}
//根据id查找
News.findNews = function (id, callback) {
const sql = "SELECT * FROM news WHERE id=?";
const data = [id]
querySql(connection,sql,data,callback)
}
//倒序查找所有新闻
News.findNewsAll = function (callback) {
const sql = "SELECT * FROM news order by time desc";
querySql(connection,sql,null,callback)
}
})
module.exports = News
首页新闻路由功能实现
这里图片我是直接写死使用网络的图片,新增新闻时只能添加新闻标题和新闻内容。
//routes/index.js
var express = require('express');
var router = express.Router();
var moment = require('moment')
var News = require('../models/news.model')
var TITLE_INDEX = '新闻'
/* GET home page. */
router.get('/', function (req, res) {
if(req.cookies.islogin){
console.log('cookie:'+req.cookies.islogin);
req.session.username = req.cookies.islogin;
}
if(req.session.username){
console.log('session:'+req.session.username);
res.locals.username = req.session.username;
}else{
res.redirect('/login');
return;
}
//查询新闻列表
News.findNewsAll(function (err, result) {
if (err) {
res.locals.error = err
res.render('index', { title: TITLE_INDEX, newList:[] });
return;
}
res.render('index', { title: TITLE_INDEX, newList:result });
})
});
// 添加新闻
router.post('/add', function (req, res) {
const newsData = new News({
title: req.body.title,
content: req.body.content,
img: 'http://n.xxxx.cn/news/1_img/upload/73a76861/105/w1023h682/20221218/c75c-b2d14d7c81670c1601b5f657ddac3542.jpg',
time:moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
})
console.log(newsData)
News.add(newsData, function (err, result) {
if (err) {
res.send({
status:400,
msg:err
})
return;
}
res.send({
status:200,
msg:'success',
data:result.insertId > 0
})
})
})
//删除
router.delete('/delete', function (req, res) {
News.delete(req.body.id, function (err, result) {
if (err) {
res.send({
status:400,
msg:err
})
return;
}
res.send({
status:200,
msg:'success',
data:true
})
})
})
// 根据id查询新闻
router.get('/findnews', function (req, res) {
News.findNews(req.query.id, function (err, result) {
if (err) {
res.send({
status:400,
msg:err
})
return;
}
res.send({
status:200,
msg:'success',
data:result[0] || null
})
})
})
//修改
router.put('/update', function (req, res) {
const data = {
id:req.body.id,
title: req.body.title,
content: req.body.content,
img: 'http://n.xxxx.cn/default/1_img/upload/3933d981/72/w1024h648/20221217/17f5-813de74b361d5679f078f0167faa6696.jpg',
time:moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
}
News.update(data, function (err,result) {
if (err) {
res.send({
status:400,
msg:err
})
return;
}
res.send({
status:200,
msg:'success',
data:true
})
})
})
module.exports = router;
首页新闻展示效果
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css"> <!-- load bootstrap css -->
<link rel="stylesheet" href="http://libs.baidu.com/fontawesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
<style>
.header,.newItem,.new-info{
display: flex;
justify-content: space-between;
align-items: center;
}
.new-info img{
width: 100px;
margin-right: 10px;
border-radius: 5px;
}
.btn-nav{
margin-bottom: 10px;
}
.nulldata{
text-align: center;
padding:50px 0;
font-size:16px;
color:#999;
}
</style>
</head>
<body>
<% include header%>
<div class="container">
<div class="btn-nav">
<button type="button" class="btn btn-primary btn-sm" onclick="addNews()">新增</button>
</div>
<ul class="list-group">
<li class="list-group-item newItem">
<div class="new-info">
<img src="item.img" alt="">
<div><%- item.title %></div>
</div>
<div>
<a href="/news?id=item.id" class="btn btn-primary btn-sm active" role="button">详情</a>
<button type="button" class="btn btn-warning btn-sm" onclick="updateFn('item.id')">修改</button>
<button type="button" class="btn btn-danger btn-sm" onclick="deleteFn('item.id')">删除</button>
</div>
</li>
<!---把上面li写在循环里面--->
<!-- <%if(newList.length > 0){%>
<% newList.forEach(function(item){ %>
<% }) %>
<%} else {%>
<div class="nulldata">暂无数据</div>
<% } %> -->
</ul>
</div>
<!---新增 修改--->
<div class="modal fade" tabindex="-1" role="dialog" id="addModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title"></h4>
</div>
<div class="modal-body" id="modal-body">
<div class="form-group">
<label for="exampleInputEmail1">新闻标题</label>
<input type="email" class="form-control" id="newtitle" name="title" placeholder="请输入新闻标题">
</div>
<div class="form-group">
<label for="exampleInputPassword1">新闻内容</label>
<textarea class="form-control" rows="3" id="newcontent" name="content"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="submit">确定</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<script type="text/javascript">
//显示新增
function addNews(){
$('#addModal').modal('show')
$('.modal-title').text('新增新闻')
}
//删除新闻
function deleteFn(id){
$.ajax({
url: "/delete",
type: "delete",
data: {id},
success:function(res){
if(res.data){
window.location.reload()
}
},
error:function(err){
console.log(err)
}
})
}
//修改新闻
let curNewsId = null // 当前要修改的新闻id
function updateFn(id){
curNewsId = id
$('#addModal').modal('show')
$('.modal-title').text('修改新闻')
$.ajax({
url:'/findnews',
type:'get',
data:{id},
success:function(res){
console.log(res)
if(res.data){
$('#newtitle').val(res.data.title)
$('#newcontent').val(res.data.content)
}
},
error:function(err){
console.log(err)
}
})
}
$(function(){
//添加新闻
$("#submit").on('click',function(){
var errorTip = '<div id="errorTip" class="alert alert-warning"></div> ';
var successTip = '<div id="successTip" class="alert alert-success"></div> ';
$("#errorTip,#successTip").remove();
var title = $.trim($('#newtitle').val()),
content = $.trim($('#newcontent').val())
if(title.length == 0){
$("#modal-body").append(errorTip);
$("#errorTip").text('新闻标题不能为空')
$('#newtitle').focus();
return false;
}
if(content.length == 0){
$("#modal-body").append(errorTip);
$("#errorTip").text('新闻内容不能为空')
$('#newcontent').focus();
return false;
}
const data = {title,content}
if(curNewsId){
data.id = curNewsId
}
if($('.modal-title').text() == '修改新闻'){
$.ajax({
url: "/update",
type: "put",
data: data,
success: function(res) {
console.log(res)
if(res.data){
window.location.reload()
}
},
error: function(err) {
console.log(err)
$("#modal-body").append(errorTip);
$("#errorTip").text('添加失败')
}
})
} else {
$.ajax({
url: "/add",
type: "post",
data: data,
success: function(res) {
console.log(res)
if(res.data){
window.location.reload()
}
},
error: function(err) {
console.log(err)
$("#modal-body").append(errorTip);
$("#errorTip").text('添加失败')
}
})
}
})
})
</script>
</body>
</html>
新闻详情路由实现
创建routes/news.js
文件
var express = require('express');
var router = express.Router();
var moment = require('moment')
var News = require('../models/news.model')
var TITLE_NEWS = '新闻详情'
// 根据id查询新闻
router.get('/', function (req, res) {
if(req.cookies.islogin){
console.log('cookie:'+req.cookies.islogin);
req.session.username = req.cookies.islogin;
}
if(req.session.username){
console.log('session:'+req.session.username);
res.locals.username = req.session.username;
}else{
res.redirect('/login');
return;
}
//新闻详情
News.findNews(req.query.id, function (err, result) {
const newsData = {
...result[0]
}
newsData.time = moment(result[0]['time']).format('YYYY-MM-DD HH:mm:ss')
res.render('news', { title: TITLE_NEWS,news:newsData })
})
})
module.exports = router
新闻详情前端页面
创建views/news.ejs
文件
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link
rel="stylesheet"
href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css"
/>
<!-- load bootstrap css -->
<link
rel="stylesheet"
href="http://libs.baidu.com/fontawesome/4.0.3/css/font-awesome.min.css"
/>
<!-- load fontawesome -->
<style>
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
</head>
<body>
<% include header%>
<div class="container">
<div class="form-group">
<label for="exampleInputEmail1">新闻标题</label>
<div><%- news.title%></div>
</div>
<div class="form-group">
<label for="exampleInputPassword1">新闻内容</label>
<div><%- news.content%></div>
</div>
<div class="form-group">
<label for="exampleInputPassword1">新闻图片</label>
<div><img src="<%- news.img%>" alt=""></div>
</div>
<div class="form-group">
<label for="exampleInputPassword1">时间</label>
<div><%- news.time%></div>
</div>
</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<script type="text/javascript"></script>
</body>
</html>
完整的app.js文件
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var session = require('express-session')
var logger = require('morgan');
var indexRouter = require('./routes/index');
var loginRouter = require('./routes/login');
var logoutnRouter = require('./routes/logout');
var signupRouter = require('./routes/signup');
var newsRouter = require('./routes/news');
var app = express();
app.listen(8100, function () {
console.log('启动成功:http://localhost:8100')
})
// view engine setup
// 指定模版目录
app.set('views', path.join(__dirname, 'views'));
// 设置模版引擎,'view engine' 为固定属性
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser("huhao"));
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: 'huhao',
resave:true,
saveUninitialized:false
}))
app.use('/', indexRouter);
app.use('/login', loginRouter);
app.use('/logout', logoutnRouter);
app.use('/signup', signupRouter);
app.use('/news', newsRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
最后的目录结构
├── app.js
├── bin
│ └── www
├── models
│ ├── db.config.js
│ ├── news.model.js
│ └── user.model.js
├── node_modules
├── package-lock.json
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
├── routes
│ ├── index.js
│ ├── login.js
│ ├── logout.js
│ ├── news.js
│ └── signup.js
└── views
├── error.ejs
├── header.ejs
├── index.ejs
├── login.ejs
├── news.ejs
└── signup.ejs
源码入口链接: Node-Express-mySql