web编程期末——项目一

项目要求

在这里插入图片描述

登录功能的实现

  1. 用户名不存在时 ,提示用户名不存在,请注册;
  2. 当密码错误时, 提示密码错误;

mysql存放用户名及密码

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;

index.html实现登录页面

<form id="login-form" method="post" role="form" style="display: block;">
        <input ng-model="username" tabindex="1" class="form-control" placeholder="Username" value="">
        <input type="password" ng-model="password" tabindex="2" class="form-control" placeholder="Password">
        <button id="login-submit" tabindex="4" class="form-control btn btn-login" ng-click="check_pwd()">LOG IN</button>   
</form> 

angular代码将输入数据暴露给控制器

通过 $scope 对象的 username 和 password 属性获取绑定的用户名和密码,生成json对象传给路由。 如果返回结果是“ok”,则将当前页面跳转至主页面news.html ;否则 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;
        });
};

路由代码检查账户正确性

在上面的angularjs代码中,数据传入后,需要传递给路由,从而判断账户正确性。
在路由代码(user.js)中我们需要做两个判断:
1、用户名是否为空
2、获取密码后检查是否与用户匹配

var userDAO = require('../dao/userDAO');

router.post('/login', function(req, res) {
  var username = req.body.username;
  var password = req.body.password;

  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'});
      }else{
        res.json({msg:'用户名或密码错误!请检查后输入'});
      }
    }
  });
});

注册功能的实现

index.html中预设表单

默认打开时不显示注册界面,所以display设置为none。当点击register时才显示

<form id="register-form" method="post" role="form" style="display: none;">
        <input ng-model="add_username" tabindex="1" class="form-control" placeholder="Username" value=""/>
        <input type="password" ng-model="add_password" tabindex="2" class="form-control" placeholder="Password">
        <input type="password" ng-model="confirm_password" tabindex="2" class="form-control" placeholder="Confirm Password">
        <button tabindex="4" class="form-control btn btn-register" ng-click="doAdd()">Register Now</button>
</form>

angular代码

$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;
    });
}

路由代码

检查账号是否重复,如果符合注册条件则显示:成功注册!请登录

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: '成功注册!请登录'});
      })
    }
  });
});

操作日志的存储

创建操作日志表单

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(1000) NOT NULL,
 PRIMARY KEY(`id`))
 ENGINE=InnoDB DEFAULT CHARSET=utf8;

app.js将操作计入日志中

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('成功保存!');
    })
  }

布尔表达式查询

单独设计search.html模块

search.html作为news.html的一部分展示在主页面中,从而控制查询结果的显示。预览效果为,第一次点进主界面时,显示导航栏,搜索框和云词;当输入数据查询后,显示搜索结果。
为实现此功能,我们将查询框和查询结果放在不同的div中,只有点击查询按钮,出发了search()函数后,才会展示搜索结果

<form class="form-horizontal" role="form">
    <div class="row" style="margin-bottom: 10px;">
        <label class="col-lg-2 control-label" style="color: aliceblue;">标题关键字</label>
        <div class="col-lg-3">
            <input type="text" class="form-control" placeholder="标题关键字" ng-model="$parent.title1">
        </div>
        <div class="col-lg-1">
            <select class="form-control" autocomplete="off" ng-model="$parent.selectTitle">
                <option selected="selected" >AND</option>
                <option >OR</option>

            </select>
        </div>
        <div class="col-lg-3">
            <input type="text" class="form-control" placeholder="标题关键字" ng-model="$parent.title2">
        </div>
    </div>



    <div class="row" style="margin-bottom: 10px;">
        <label class="col-lg-2 control-label" style="color: aliceblue;">内容关键字</label>
        <div class="col-lg-3">
            <input type="text" class="form-control" placeholder="内容关键字" ng-model="$parent.content1">
        </div>
        <div class="col-lg-1">
            <select class="form-control" autocomplete="off" ng-model="$parent.selectContent">
                <option selected="selected" >AND</option>
                <option >OR</option>
            </select>
        </div>
        <div class="col-lg-3">
            <input type="text" class="form-control" placeholder="内容关键字" ng-model="$parent.content2">
        </div>
    </div>


    <div class="form-group">
        <div class="col-md-offset-9">
            <button type="submit" class="btn btn-default" ng-click="search()">查询</button>
        </div>
    </div>

</form>

搜索结果的关键代码如下,我们将该板块的显示标签定义为isisshowresult

<div class='formshow' ng-show="isisshowresult">

    <table class="table table-striped">
        <thead>
            <tr>
                <td>序号</td>
                <td>标题</td>
                <td>作者</td>
<!--                <td>内容</td>-->
                <td>关键词</td>
                <td>链接</td>
                <td>发布时间</td>
            </tr>

        </thead>
        <tbody>
        <tr ng-repeat="(key, item) in items">
            <td>{{index+key}}</td>
            <td>{{item.title}}</td>
            <td>{{item.author}}</td>
<!--            <td>{{item.content}}</td>-->
            <td>{{item.keywords}}</td>
            <td>{{item.url}}</td>
            <td>{{item.publish_date}}</td>
        </tr>

        </tbody>
    </table>

调用search函数

$scope.search = function () {
        $scope.isShows =false;
        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}`;

连接池返回查询结果

由路由段将查询关键字发送给连接池,连接池将关键字拼接后返回查询结果,由时间顺序分页表示

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); //事件驱动回调
                });
            }
        });
    }

echarts实现图表展示

折线图类

首先需要引用<script src="echarts.min.js"></script>
在echarts官网可以下载
以折线图为例,在news.js中,以line函数为trigger,调用图表

router.get('/line', function(request, response) {
        var keyword = request.query.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();
        });
});

效果如下
在这里插入图片描述
在这里插入图片描述

词云类

首先定义关键词分割的js代码,并且调用node-analyzer模块

npm install node-analyzer -save
var Segmenter = require('node-analyzer');

//正则表达式去掉一些无用的字符,与高频但无意义的词。
const regex = /[\t\s\r\n\d\w]|[\+\-\(\),\.。,!?《》@、【】"'::%-\/“”]/g;

var wordcut = function(vals) {
    var segmenter = new Segmenter();
    var word_freq = {};
    vals.forEach(function (content){
        if(content['content']!=null){
        var newcontent = content["content"].replace(regex,'');
        if(newcontent.length !== 0){
            // console.log();

            var words = segmenter.analyze(newcontent).split(' ');

            // var words = nodejieba.cut(newcontent);
            words.forEach(function (word){
                word = word.toString();
                word_freq[word] = (word_freq[word] +1 ) || 1;
            });
        };
    }

    });
    return word_freq;
};
exports.wordcut = wordcut;

词云的触发函数为wordcloud

router.get('/wordcloud', function(request, response) {
    //sql字符串和参数

    //sql字符串和参数

        var fetchSql = "select content from fetches;";
        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:mywordcutModule.wordcut(result)}));//返回处理过的数据
            response.end();
        });

});

之后我们让词云在主页上显示,效果如下
在这里插入图片描述

效果展示

web编程期末作业

通过这学期的课程,学到了很多知识,同时也看到了自己很多不足。web编程课为我打开了一扇窗,让我看到更广阔的未知的大海,让我认识到了即便是处理从未涉及过的难题,只要一步一步踏实地走下去,也是一定可以有回报的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值