老师作业要求如下:
这次大作业我选择了第一个,因为想对期中作业进行一个补充和扩展。在之前的期中作业已经完成了分页、排序和分词查询——如下图所示
详细代码请见上次的期中作业哦
所以在这次期末作业,主要是进行注册登陆操作,将用户查询、登陆等操作记录在数据库中,以及用Echarts实现3个数据分析表展现在网页中并且在网页端实现增加删除用户操作。
技术实现:Angular.js+Express+Mysql
写好后,在终端打开文件,然后输入:npm start
然后在网页端打开查看
准备工作:
1.先在数据库中建表
一个是用于记录已注册用户的注册名、密码和注册时间,用于添加新用户的信息和检验用户再次登录时是否匹配之前的
CREATE TABLE `crawl`.`user` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(45) NOT NULL,
`password` VARCHAR(45) NOT NULL,
`registertime` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `username_UNIQUE` (`username`))ENGINE=InnoDB DEFAULT CHARSET=utf8;
另一个是记录用户的注册、登录和查询等操作,记入数据库中的日志,并且实时显示在终端
CREATE TABLE `crawl`.`user_action` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(45) NOT NULL,
`request_time` VARCHAR(45) NOT NULL,
`request_method` VARCHAR(20) NOT NULL,
`request_url` VARCHAR(300) NOT NULL,
`status` int(4),
`remote_addr` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`))ENGINE=InnoDB DEFAULT CHARSET=utf8;
然后我们的tables就是这样
2.建立好连接数据库的配置文件
module.exports = {
mysql: {
host: 'localhost',
user: 'root',
password: 'root',
database:'crawl',
// 最大连接数,默认为10
connectionLimit: 10
}
};
3.安装包
啊啊啊啊啊气死我了,安装nodejieba这个包,就各种报错,最后在助教的帮助下安装成功
换个路径安装:输入npm install nodejieba --save(注意⚠️:–save前一定要有空格,亲身试错了的)
4.配置连接池dao文件,集中储存在dao文件夹中
然后正式开始啦
一、实现要求用户可查询网站,非用户不可查询
按要求:(包括了基本要求1和基本要求3)
页面主要实现三个功能:
1.老用户登陆进入网站
2.新用户注册再进入网站
3.忘记密码后先删除用户,再重新注册后进入网站
⚠️注意:第一次注册和忘记密码重新注册时,若是密码两次输入不一致会给出提示;登陆时用户不存在、密码输错也会给出提示
效果如下图所示:
登陆页面
忘记密码页面
注册页面
前端页面代码(index.html):
首先在根元素上定义 AngularJS 应用“login”,指定AngularJS应用程序管理的边界,使得在ng-app内部的指令起作用
登陆页面:
通过 ng-model 指令把输入域的用户名和密码绑定到当前作用域中,以便 $scope 对象传递数据;当ng-click被触发时,调用 check_pwd() 函数。
<form id="login-form" method="post" role="form" style="display: block;">
<!-- 登陆部分-->
<div class="form-group">
<input ng-model="username" tabindex="1" class="form-control" placeholder="用户名/学号" value=""/>
</div>
<div class="form-group">
<input type="password" ng-model="password" tabindex="2" class="form-control" placeholder="密码">
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<button id="login-submit" tabindex="4" class="form-control btn btn-login" ng-click="check_pwd()">立即登录</button>
</div>
</div>
</div>
</form>
登陆操作的angular代码——check_pwd函数:
通过 $scope 对象获取用户名和密码,生成json对象传给路由。 如果返回结果是“ok”,则将当前页面跳转至前端页面 news.html ;否则通过预先定义在前端页面定义的 &scope 对象属性 msg 显示警告。
$scope.check_pwd = function () {
var data = JSON.stringify({
username: $scope.username,
password: $scope.password
});
$http.post("/users/login", data)
.then(
function (res) {
if(res.data.msg=='ok') {
window.location.href='/news.html';
}else{
$scope.msg=res.data.msg;
}
},
function (err) {
$scope.msg = err.data;
});
};
登陆操作的路由代码:
根据或得的用户名查询数据库所对应的密码。如果返回的用户名长度为零,说明用户不存在;如果获取到密码,检查和用户输入的密码是否匹配:若匹配则发送 json 响应,msg 赋值为“ok”,并且把用户名保存到服务器内存中,以便记录用户登录操作日志等;否则 msg 为错误提示。
outer.post('/login', function(req, res) {
var username = req.body.username;
var password = req.body.password;
// var sess = req.session;
userDAO.getByUsername(username, function (user) {
if(user.length==0){
res.json({msg:'用户不存在!请检查后输入'});
}else {
if(password===user[0].password){
req.session['username'] = username;
res.cookie('username', username);
res.json({msg: 'ok'});
// res.json({msg:'ok'});
}else{
res.json({msg:'用户名或密码错误!请检查后输入'});
}
}
});
});
注册页面和忘记密码页面
这两个页面也是同理,在最后调用doAdd和ReAdd两个函数
<div class="col-xs-5">
<a href="#" id="register-form-link">立即注册</a>
<a href="#" id="reregister-form-link">忘记密码</a>
</div>
<form id="register-form" method="post" role="form" style="display: none;">
<div class="form-group">
<input ng-model="add_username" tabindex="1" class="form-control" placeholder="用户名" value=""/>
</div>
<div class="form-group">
<input type="password" ng-model="add_password" tabindex="2" class="form-control" placeholder="密码">
</div>
<div class="form-group">
<input type="password" ng-model="confirm_password" tabindex="2" class="form-control" placeholder="再次输入密码">
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<button tabindex="4" class="form-control btn btn-register" ng-click="doAdd()">立即注册</button>
</div>
</div>
</div>
</form>
<form id="reregister-form" method="post" role="form" style="display: none;">
<div class="form-group">
<input ng-model="add_username" tabindex="1" class="form-control" placeholder="用户名" value=""/>
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<button tabindex="4" class="form-control btn btn-reregister" ng-click="ReAdd()">重新注册</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
其中
这是为了实现简单的动画效果
注册操作的angular代码——doAdd函数:
//增加注册用户
$scope.doAdd = function () {
// 检查用户注册时,输入的两次密码是否一致
if($scope.add_password!==$scope.confirm_password){
$scope.msg = '小主,你的两次密码不一致哦!';
}
else {
var data = JSON.stringify({
username: $scope.add_username,
password: $scope.add_password
});
$http.post("/users/register", data)
.then(function (res) {
if(res.data.msg=='成功注册!请登录') {
$scope.msg=res.data.msg;
$timeout(function () {
window.location.href='index.html';
},2000);
} else {
$scope.msg = res.data.msg;
}
}, function (err) {
$scope.msg = err.data;
});
}
};
忘记密码的angular代码——ReAdd函数:
//重新注册
//重新注册
$scope.ReAdd = function () {
var data = JSON.stringify({
username: $scope.username
});
$http.post("/users/reregister", data)
.then(function (res) {
if(res.data.msg=='成功删除!请注册新用户') {
$scope.msg=res.data.msg;
$timeout(function () {
window.location.href='index.html';
},2000);
}else{
$scope.msg=res.data.msg;
}
},
function (err) {
$scope.msg = err.data;
});
};
});
路由代码:
注册:根据获得的用户名查询数据库,如果返回的用户名长度为零,说明用户不存在,可以注册。
忘记密码:根据获得的用户名从而在数据库中删除这个用户,然后再重新注册新用户后登陆。
/* add users */
router.post('/register', function (req, res) {
var add_user = req.body;
// 先检查用户是否存在
userDAO.getByUsername(add_user.username, function (user) {
if (user.length != 0) {
res.json({msg: '用户已存在!'});
}else {
userDAO.add(add_user, function (success) {
res.json({msg: '成功注册!请登录'});
})
}
});
});
/* re users */
router.post('/reregister', function (req, res) {
var name = req.body.username;
userDAO.delete(name, function (success){
res.json({msg: '成功删除!请注册新用户'});
});
});
在路由中用到的add、delect、getByUsername函数如图所示
对数据库的操作
基本上登陆这部分的页面就完成了,接着就是对页面进行设计,按照自己喜好来即可
设计好后在前端加入:写好的css文件即可,就可以出现在前面展现的效果啦
二、用户注册、登录、查询等操作记入数据库中的日志(app.js)
这里借助 Express 框架记录日志的中间件 morgan ,而且在 app.js 文件中已经默认引入了该中间件 var logger = require(‘Morgan’),从而可以将用户等操作存入数据库的日志中,并可以在终端打印出来
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 logDAO = require('./dao/logDAO.js');
var usersRouter = require('./routes/users');
var newsRouter = require('./routes/news');
var app = express();
//设置session
app.use(session({
secret: 'sessiontest',//与cookieParser中的一致
resave: true,
saveUninitialized: false, // 是否保存未初始化的会话
cookie : {
maxAge : 1000 * 60 * 60, // 设置 session 的有效时间,单位毫秒
},
}));
let method = '';
app.use(logger(function (tokens, req, res) {
console.log('打印的日志信息:');
var request_time = new Date();
var request_method = tokens.method(req, res);
var request_url = tokens.url(req, res);
var status = tokens.status(req, res);
var remote_addr = tokens['remote-addr'](req, res);
if(req.session){
var username = req.session['username']||'notlogin';
}else {
var username = 'notlogin';
}
// 直接将用户操作记入mysql中
if(username!='notlogin'){
logDAO.userlog([username,request_time,request_method,request_url,status,remote_addr], function (success) {
console.log('成功保存!');
})
}
console.log('请求时间 = ', request_time);
console.log('请求方式 = ', request_method);
console.log('请求链接 = ', request_url);
console.log('请求状态 = ', status);
console.log('请求长度 = ', tokens.res(req, res, 'content-length'),);
console.log('响应时间 = ', tokens['response-time'](req, res) + 'ms');
console.log('远程地址 = ', remote_addr);
console.log('远程用户 = ', tokens['remote-user'](req, res));
console.log('http版本 = ', tokens['http-version'](req, res));
console.log('浏览器信息 = ', tokens['user-agent'](req, res));
console.log('用户 = ', username);
console.log(' ===============',method);
}, ));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/angular', express.static(path.join(__dirname , '/node_modules/angular')));
// app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/news', newsRouter);
app.use(function(req, res, next) {
next(createError(404));
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
module.exports = app;
效果如图
三、主页面的实现
登陆后即进入主页面
完整主页面的前端代码见(news.html)
其中页面分为查询、图片、词云、账号管理等操作
故网页需要下拉样式,则在style中加入以下代码:
<style>
/* 设置下拉按钮的样式 */
.dropbtn {
background-color: #020f02;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* 容器 <div> - 需要放置下拉内容 */
.dropdown {
position: relative;
display: inline-block;
}
/* 下拉内容(默认隐藏) */
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* 下拉链接 */
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
/* 悬停时更改下拉链接的颜色 */
.dropdown-content a:hover {background-color: #f1f1f1}
/* 悬停时显示下拉菜单 */
.dropdown:hover .dropdown-content {
display: block;
}
/* 显示下拉内容时,更改下拉按钮的背景颜色 */
.dropdown:hover .dropbtn {
background-color: #010801;
}
</style>
最后网页效果如图:
四、查询页面
因为在之前已经实现了分页和分词查询,完整代码见期中作业,故在这次网页中实现了一种新的查询方法——布尔查询
一开始的想法是直接跳转到之前写的页面,最后都以失败告终,故最后使用老师的方法
通过ng-include将查询页面引到新闻页面(search.html)
<span ng-hide="isShow" id="main1" style="width: 1000px;height:600px;position:fixed; top:70px;left:80px"></span>
<div ng-show="isShow" style="width: 1300px;position:relative; top:70px;left: 80px">
<div ng-include="'search.html'"></div>
调用search()函数:
其中先检查传入参数是否有问题,再通过get请求传给路由,若获得数据则查询结果分页展示
$scope.search = function () {
var title1 = $scope.title1;
var title2 = $scope.title2;
var selectTitle = $scope.selectTitle;
var content1 = $scope.content1;
var content2 = $scope.content2;
var selectContent = $scope.selectContent;
var sorttime = $scope.sorttime;
// 检查用户传的参数是否有问题
//用户有可能这样输入:___ and/or 新冠(直接把查询词输在了第二个位置)
if(typeof title1=="undefined" && typeof title2!="undefined" && title2.length>0){
title1 = title2;
}
if(typeof content1=="undefined" && typeof content2!="undefined" && content2.length>0){
content1 = content2;
}
// 用户可能一个查询词都不输入,默认就是查找全部数据
var myurl = `/news/search?t1=${title1}&ts=${selectTitle}&t2=${title2}&c1=${content1}&cs=${selectContent}&c2=${content2}&stime=${sorttime}`;
$http.get(myurl).then(
function (res) {
if(res.data.message=='data'){
$scope.isisshowresult = true;
$scope.initPageSort(res.data.result)
}else {
window.location.href=res.data.result;
}
},function (err) {
$scope.msg = err.data;
});
};
然后传给路由(routes/news.js):
先检验用户是否是登录状态,若不是则返回登录界面
router.get('/search', function(request, response) {
console.log(request.session['username']);
//sql字符串和参数
if (request.session['username']===undefined) {
response.json({message:'url',result:'/index.html'});
}else {
var param = request.query;
newsDAO.search(param,function (err, result, fields) {
response.json({message:'data',result:result});
})
}
});
在连接池文件 newsDao.js 中对关键词和连接词执行拼路由操作
search :function(searchparam, callback) {
// 组合查询条件
var sql = 'select * from fetches ';
if(searchparam["t2"]!="undefined"){
sql +=(`where title like '%${searchparam["t1"]}%' ${searchparam['ts']} title like '%${searchparam["t2"]}%'`);
}else if(searchparam["t1"]!="undefined"){
sql +=(`where title like '%${searchparam["t1"]}%' `);
};
if(searchparam["t1"]=="undefined"&&searchparam["t2"]=="undefined"&&searchparam["c1"]!="undefined"){
sql+='where ';
}else if(searchparam["t1"]!="undefined"&&searchparam["c1"]!="undefined"){
sql+='and ';
}
if(searchparam["c2"]!="undefined"){
sql +=(`content like '%${searchparam["c1"]}%' ${searchparam['cs']} content like '%${searchparam["c2"]}%' `);
}else if(searchparam["c1"]!="undefined"){
sql +=(`content like '%${searchparam["c1"]}%' `);
}
if(searchparam['stime']!="undefined"){
if(searchparam['stime']=="1"){
sql+='ORDER BY publish_date ASC ';
}else {
sql+='ORDER BY publish_date DESC ';
}
}
sql+=';';
console.log(sql);
pool.getConnection(function(err, conn) {
if (err) {
callback(err, null, null);
} else {
conn.query(sql, function(qerr, vals, fields) {
conn.release(); //释放连接
callback(qerr, vals, fields); //事件驱动回调
});
}
});
}
然后查询结果如图所示:
若是想完成排序操作,比如按时间排序,只需要在路由中加一句“Sql+=“order by publish_date””即可
四、用Echarts实现数据分析图表
关于这部分的图表展示,我就是在老师ppt给的例子上加上在网上学习的一些知识,对图标进行了一个装修和改进,本来还想对折线图增加一个搜索词功能,但是因为publish_time那里一直有问题,所以就放弃了
1.柱状图
前端代码:
$scope.histogram = function () {
$scope.isShow = false;
$http.get("/news/histogram")
.then(
function (res) {
if(res.data.message=='url'){
window.location.href=res.data.result;
}else {
let newdata = [];
var pattern = /责任编辑:(.+)/;
res.data.result.forEach(function (element) {
newdata.push({name: pattern.exec(element["x"]), value: element["y"]});
});
var myChart = echarts.init(document.getElementById('main1'));
var option = {
title: {
text: '不同球队的粉丝人数'
},
tooltip: {},
legend: {
data: ['人数']
},
xAxis: {
type: 'category',
name: '球队',
show: true,
data: ["雄鹿队","勇士队","湖人队","快船队","凯尔特人队","猛龙队","热火队","雷霆队","独行侠队","骑士队"],
axisLabel: {
rotate: 40,
interval :0
}
},
yAxis: {
type: 'value',
name: '人数',
min: 0,
max: 900,
interval:100,
axisLabel: {
formatter: '{value}'
}
},
series: [{
name: '人数',
type: 'bar',
itemStyle: {
normal: {
color: function(params) {
var colorList = [
'#F6CECE','#F6E3CE','#F2F5A9','#BEF781','#A9F5D0',
'#81F7F3','#81DAF53','#5882FA','#0101DF','#D358F7',
'#F781D8','#FA58AC','#FA5882','#D8D8D8','#848484'
];
return colorList[params.dataIndex]
},
label: {
show: true,
position: 'top',
formatter: '{c}'
}
}
},
barWidth: 40,
data: [530,650,800,590,620,400,350,480,430,300]
}]
};
myChart.setOption(option);
}
},
function (err) {
$scope.msg = err.data;
});
};
路由代码:
router.get('/histogram', function(request, response) {
console.log(request.session['username']);
//sql字符串和参数
if (request.session['username']===undefined) {
response.json({message:'url',result:'/index.html'});
}else {
var fetchSql = "select publish_date as x,count(publish_date) as y from fetches group by publish_date order by publish_date;";
newsDAO.query_noparam(fetchSql, function (err, result, fields) {
response.writeHead(200, {
"Content-Type": "application/json",
"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache",
"Expires": 0
});
response.write(JSON.stringify({message:'data',result:result}));
response.end();
});
}
});
效果展示:
2.饼状图:
前端代码:
$scope.pie = function () {
$scope.isShow = false;
$http.get("/news/pie").then(
function (res) {
if(res.data.message=='url'){
window.location.href=res.data.result;
}else {
let newdata = [];
var pattern = /责任编辑:(.+)/;
res.data.result.forEach(function (element) {
newdata.push({name: pattern.exec(element["x"]), value: element["y"]});
});
var myChart = echarts.init(document.getElementById('main1'));
var app = {};
option = null;
var option = {
title: {
text: '在中国粉丝的主要分布地区',
y: 'top',
itemGap: 30,
backgroundColor: '#EEE',
textStyle: {
fontSize: 26,
fontWeight: 'bolder',
color: '#FA5882'
},
subtextStyle: {
fontSize: 18,
color: '#FFFFFF'
}
},
legend: {
y: 'center',
itemWidth: 20,
itemHeight: 14,
textStyle: {
color: '#666'
},
itemGap: 30,
backgroundColor: '#eee',
data: ['北京','上海','广东','深圳','四川','重庆']
},
series: [
{
name: '去向',
type: 'pie',
radius: ['25%', '50%'],
center: ['18%', '40%'],
data: [
{value:210, name:'北京'},
{value:404, name:'上海'},
{value:234, name:'广东'},
{value:135, name:'深圳'},
{value:148, name:'四川'},
{value:120, name:'重庆'}
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(30, 144, 255,0.5)'
}
},
labelLine: {
normal: {
show: false
}
},
label: {
normal: {
position: 'inner',
formatter: '{c}'
}
}
}
],
tooltip: {
trigger: 'item',
showDelay: 20,
hideDelay: 20,
backgroundColor: 'rgba(255,0,0,0.7)',
textStyle: {
fontSize: '14px',
color: '#000'
},
formatter: '{a} <br/>{b} : {c}个 ({d}%)'
},
color: ['#0080FF', '#01DFD7', '#D0A9F5', '#E6E6E6', '#F6D8CE', '#F78181']
};
app.currentIndex = -1;
setInterval(function () {
var dataLen = option.series[0].data.length;
myChart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: app.currentIndex
});
app.currentIndex = (app.currentIndex + 1) % dataLen;
myChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: app.currentIndex
});
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: app.currentIndex
});
}, 1000);
if (option && typeof option === "object") {
myChart.setOption(option, true);
};
}
});
};
路由代码:
router.get('/histogram', function(request, response) {
console.log(request.session['username']);
//sql字符串和参数
if (request.session['username']===undefined) {
response.json({message:'url',result:'/index.html'});
}else {
var fetchSql = "select publish_date as x,count(publish_date) as y from fetches group by publish_date order by publish_date;";
newsDAO.query_noparam(fetchSql, function (err, result, fields) {
response.writeHead(200, {
"Content-Type": "application/json",
"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache",
"Expires": 0
});
response.write(JSON.stringify({message:'data',result:result}));
response.end();
});
}
});
效果展示:
3.条形图
前端代码:
$scope.line = function () {
$scope.isShow = false;
$http.get("/news/line").then(
function (res) {
if(res.data.message=='url'){
window.location.href=res.data.result;
}else {
var myChart = echarts.init(document.getElementById("main1"));
option = {
title: {
text: '"NBA"该词在近一周出现次数变化图'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
itemStyle: {normal: {label: {show: true}}}
}],
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
}
});
};
传给路由:
router.get('/line', function(request, response) {
console.log(request.session['username']);
if (request.session['username']===undefined) {
response.json({message:'url',result:'/index.html'});
}else {
var keyword = '综艺';
var fetchSql = "select content,publish_date from fetches where content like'%" + keyword + "%' order by publish_date;";
newsDAO.query_noparam(fetchSql, function (err, result, fields) {
response.writeHead(200, {
"Content-Type": "application/json",
"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache",
"Expires": 0
});
response.write(JSON.stringify({message:'data',result:myfreqchangeModule.freqchange(result, keyword)}));
response.end();
});
}
});
效果如下:
4.词云
前端代码:
背景图需要自己提前下载好保存在文件内
其他方法同理,写好前端和路由代码即可
完整代码见wordcloud.js
效果如下:
五、最后是关于账号管理的操作
点击已有账号后会显示数据库已有的用户
增加和删除用户其实就是对应了登陆页面时的注册和忘记密码的操作,和前面一样是对数据库进行删除增加操作,故只需要写一个和index.html差不多的页面,前端页面完整代码见index1.html。
增加、删除函数代码
$scope.add = function () {
//增加用户
$http.get("/users/logout").then(
function (res) {
window.location.href=res.data.result;
},function (err) {
$scope.msg = err.data;
}
);
};
$scope.delect = function () {
//删除用户
$http.get("/users/logout").then(
function (res) {
window.location.href=res.data.result;
},function (err) {
$scope.msg = err.data;
}
);
};
然后logout路由代码:
// 退出登录
router.get('/logout', function(req, res, next){
req.session.destroy(function(err) {
if(err){
res.json('退出登录失败');
return;
}
// req.session.loginUser = null;
res.clearCookie('username');
res.json({result:'/index1.html'});
});
});
效果展示:
感觉自己真是个小机灵鬼哈哈哈哈哈👍
关于删除用户操作
我是真的想吐槽一下之前在登陆页面写删除操作的过程——真的是很无语了,因为一直错,一直错,不是函数传参数有问题,就是两次参数名称不相等,数据库写的有问题;反正,总而言之,言而总之,就是废了很多力气,真的是多多亏了助教!!!!!!!!!
本网页实现的是根据用户名来删除,其实同理可得,根据id来删除也可以;实现了删除和增加用户之后,其实我们还可以实现更新用户,即由得到的ID对用户的用户名和密码进行更新
总体来说大概思路是这样的
var id = req.body.id;
var username = req.body.username;
var password = req.body.password;
sql.query('update user set username = "'+username+'" , password = "'+password+'" where id = '+id,function(err,result){
if (err) {
res.send('更新用户失败'+err);
}else{
res.send('修改成功')s;
}
})
六、总结
web这门课是我第一次自己做项目,期中、期末这两次作业让我对爬虫、网页设计有了很初步的一个认识,过程中多亏了老师、助教和同学的帮助,顺利完成了对老师代码的加工,并在这个过程中学到了很多方法和技巧,会继续努力的,以后也会自己多多尝试!