web编程第二次大作业

本文详细记录了一次web编程作业的过程,使用Node.js的Express框架、Angular前端框架以及MySQL数据库来构建一个数据展示网站。项目要求包括用户注册登录、数据查询日志、数据分页和排序、Echarts数据可视化以及用户管理和操作记录展示等功能。在实现过程中,涉及到了数据库配置、路由设计、前端页面逻辑以及数据交互等多个环节。
摘要由CSDN通过智能技术生成

web编程第二次大作业

1. 作业要求

  • 基于第一个项目爬虫爬取的数据,完成数据展示网站。
  • 基本要求
    • 1、用户可注册登录网站,非注册用户不可登录查看数据
    • 2、用户注册、登录、查询等操作记入数据库中的日志
    • 3、爬虫数据查询结果列表支持分页和排序
    • 4、用Echarts或者D3实现3个以上的数据分析图表展示在网站中
    • 5、实现一个管理端界面,可以查看(查看用户的操作记录)和管理(停用启用)注册用户。

2. 技术栈

理解该项目需要熟悉一下技术

  • 后端: nodejs, express框架

  • 前端: angular, bootstrap, jQuery

  • 语言: html, CSS, JavaScript

  • 数据可视化: eCharts

3. 实现步骤

3.1 express框架建立

在命令行中生成web网站脚手架

# 命令1
npm install -g express-generator
# 命令2
express eps_1

image-20210628210937915

  • package.json应用的配置文件,文件内包含程序的基础信 息、启动脚本和依赖包等。
  • app.js应用的初始化文件,包括引入应用程序的基础依赖 项、设置视图即view的引擎目录以及模板、设置静态资 源路径、配置通用的中间件、引入路由和一些错误处理中间件等。
  • bin/www应用的启动文件,文件内包含引用要启动的应用、设置应用监听的端口和启动http服务等。
  • public/**应用的静态资源文件目录,该目录下的 文件资源不需要经过文件映射就可以直接访问。
  • routes/**应用的路由文件,这些路由文件中设置的接口 最终会以指定的HTTP请求方式暴露给用户,并在用户请 求之后将结果返回。
  • views应用的视图文件,在app.js中设置好视图引擎和模板 之后,该目录即为应用视图的根目录,然后路由文件就 会根据app.js中的设置加载并渲染该目录下的视图文件。

3.2 安装库

本项目的packages.json文件

{
   
  "name": "final-project",
  "version": "0.0.0",
  "private": true,
  "scripts": {
   
    "start": "node ./bin/www"
  },
  "dependencies": {
   
    "angular": "^1.7.9",
    "body-parser": "^1.19.0",
    "bootstrap": "^4.5.0",
    "cookie-parser": "^1.4.5",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "express-session": "^1.17.1",
    "http-errors": "~1.6.3",
    "morgan": "~1.9.1",
    "mysql": "^2.18.1",
    "nodejieba": "^2.4.1",
    "pug": "2.0.0-beta11"
  }
}

3.3 配置mysql数据库

本案例使用的数据库为mysql, 需要前面爬虫的crawl表.

使用命令建立user, user_action两张表, 分别存储用户信息和用户操作记录

user表格字段分别为id, username, password, registertime, valid

useraction表格分别为id, username, request_time, request_url, status

--之前的新闻数据表
CREATE TABLE `fetches` (
  `id_fetches` int(11)  NOT NULL AUTO_INCREMENT,
  `url` varchar(200) DEFAULT NULL,
  `source_name` varchar(200) DEFAULT NULL,
  `source_encoding` varchar(45) DEFAULT NULL,
  `title` varchar(200) DEFAULT NULL,
  `keywords` varchar(200) DEFAULT NULL,
  `author` varchar(200) DEFAULT NULL,
  `publish_date` date DEFAULT NULL,
  `crawltime` datetime DEFAULT NULL,
  `content` longtext,
  `createtime` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id_fetches`),
  UNIQUE KEY `id_fetches_UNIQUE` (`id_fetches`),
  UNIQUE KEY `url_UNIQUE` (`url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--创建用户信息数据表
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,
  `valid` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  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;

之后需要使用nodejs中的mysql库去连接本机上的mysql数据库, 这里我们需要连接crawl数据库

// 1. 导入mysql 模块
const mysql = require('mysql');

// 2. 建立与mysql数据库的连接
const db = mysql.createPool({
   
    host: 'localhost',      // 数据库ip地址
    user: 'root',           // 登陆数据库的账号
    password: 'root',       // 登陆数据库的密码
    database: 'crawl'       // 指定要操作哪个数据库
});

3.4 登陆页面

这里我们需要实现一个登陆页面和登陆功能.

3.4.1 登陆页面前端

登陆页面前端存放在./public/index.html文件中

前端页面借助了jQuery, angular, bootstap等前端库, 我们通过script标签引入.

我们自己编写的样式存放在./public/stylesheets/index.css

<!DOCTYPE html>
<html ng-app="login">
<head>
    <meta charset="utf-8" />
    <title>Login</title>
    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/popper.js/1.12.5/umd/popper.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/js/bootstrap.min.js"></script>
<!--    <script src="../node_modules/angular/angular.min.js"></script>-->
    <script src="/angular/angular.min.js"></script>

<!--    引入自己的样式与js-->
    <link rel="stylesheet" type="text/css" href="stylesheets/index.css">
</head>
<body>
<div class="container" ng-controller="loginCtrl">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <div class="panel panel-login">
                <div class="panel-heading">
                    <div class="row">
                        <div class="col-xs-6">
                            <a href="#" class="active" id="login-form-link">Login</a>
                        </div>
                        <div class="col-xs-6">
                            <a href="#" id="register-form-link">Register</a>
                        </div>
                    </div>
                    <hr>
                </div>
                <div class="panel-body">
                    <div class="row">
                        <div class="col-lg-12">
                            <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="Username" value=""/>
                                </div>
                                <div class="form-group">
                                    <input type="password" ng-model="password" tabindex="2" class="form-control" placeholder="Password">
                                </div>
<!--                                <div class="form-group text-center">-->
<!--                                    <input type="checkbox" tabindex="3" class="" name="remember" id="remember">-->
<!--                                    <label for="remember"> Remember Me</label>-->
<!--                                </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()">LOG IN</button>
                                        </div>
                                    </div>
                                </div>
                            </form>
                            <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="Username" value=""/>
                                </div>

                                <div class="form-group">
                                    <input type="password" ng-model="add_password" tabindex="2" class="form-control" placeholder="Password">
                                </div>

                                <div class="form-group">
                                    <input type="password" ng-model="confirm_password" tabindex="2" class="form-control" placeholder="Confirm Password">
                                </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()">Register Now</button>
                                        </div>
                                    </div>
                                </div>

                            </form>

                        </div>
                    </div>
                </div>
<!--                <div class="alert alert-warning alert-dismissible fade show">-->
<!--                    <button type="button" class="close" data-dismiss="alert">&times;</button>-->
<!--                    <strong>警告!</strong>{
   {msg}}-->
<!--                </div>-->
            </div>
            <div class="alert alert-warning" ng-if="msg && msg!='ok'">
                <a href="#" class="close" data-dismiss="alert">&times;</a>
                <strong>警告!</strong>{
  {msg}}
            </div>
        </div>
    </div>
</div>
</body>

image-20210628213735934

image-20210628213748680

接下来, 我们需要实现路由功能, 确保在进入登陆页面后, 本地服务端会处理登陆请求事件.

3.4.2 angular登陆界面逻辑实现

在html中内置script标签, 使用angular框架实现登陆逻辑

    <script>
        var app = angular.module('login', []);
        app.controller('loginCtrl', function ($scope, $http, $timeout) {
    

            // 登录时,检查用户输入的账户密码是否与数据库中的一致
            $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;
                    });

            };
            //增加注册用户
            $scope.doAdd = function () {
    
                // 检查用户注册时,输入的两次密码是否一致
                if($scope.add_password!==$scope.confirm_password){
    
                    // $timeout(function () {
    
                    //     $scope.msg = '两次密码不一致!';
                    // },100);
                    $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;
                        });
                }
            };
        });
    </script>

引入index.js文件为登陆界面添加点击时间, 并引入到index.html中

$(function() {
   
    $('#login-form-link').click(function(e) {
   
        $("#login-form").delay(100).fadeIn(100);
        $("#register-form").fadeOut(100);
        $('#register-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });
    $('#register-form-link').click(function(e) {
   
        $("#register-form").delay(100).fadeIn(100);
        $("#login-form").fadeOut(100);
        $('#login-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });
});
3.4.3 为登陆功能实现路由

为登陆, 注册页面添加路由, 路由代码存放在./router/user.js中

var express = require('express');
var router = express.Router();
var userDAO = require('../dao/userDAO');

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

  userDAO.getByUsername(username, function (user) {
   
    // console.log(user);
    // console.log(user[0].valid);
    // console.log("success!");
    if(user.length==0){
   
      res.json({
   msg:'用户不存在!请检查后输入'});

    }else {
   
      if(password===user[0].password && user[0].valid == 1){
   
        req.session['username'] = username;
        res.cookie('username', username);
        res.json({
   msg: 'ok'});
        // res.json({msg:'ok'});
      } else if(user[0].valid != 1) {
   
        res.json({
   msg:'你输入的注册用户无效!'});
      } else {
   
        res.json({
   msg:'用户名或密码错误!请检查后输入'});
      }
    }
  });
});


/* 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.render('index', {msg:'用户不存在!'});
      res.json({
   msg: '用户已存在!'});
    }else {
   
      userDAO.add(add_user, function (success) {
   
        res.json({
   msg: '成功注册!请登录'});
      })
    }
  });

});

// 退出登录
router.get('/logout', function(req, res, next){
   
  // 备注:这里用的 session-file-store 在destroy 方法里,并没有销毁cookie
  // 所以客户端的 cookie 还是存在,导致的问题 --> 退出登陆后,服务端检测到cookie
  // 然后去查找对应的 session 文件,报错
  // session-file-store 本身的bug

  req.session.destroy(function(err) {
   
    if(err){
   
      res.json('退出登录失败');
      return;
    }

    // req.session.loginUser = null;
    res.clearCookie('username');
    res.json({
   result:'/index.html'});
  });
});

module.exports = router;
3.4.4 数据库业务逻辑实现

我们需要在用musql库操作数据库, 对登陆界面发来的请求进行接受并处理.

  • 接受登陆请求并在数据库中搜索
  • 接受注册请求, 并将注册信息填入数据库
var mysql = require('mysql');
var mysqlConf = require('../conf/mysqlConf');
var userSqlMap = require('./userSqlMap');
var pool = mysql.createPool(mysqlConf.mysql);
// 使用了连接池,重复使用数据库连接,而不必每执行一次CRUD操作就获取、释放一次数据库连接,从而提高了对数据库操作的性能。
module.exports = {
   
    add: function (user, callback) {
   
        pool.query(userSqlMap.add, [user.username, user.password
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值