web编程期末大作业

目录

一. 实验要求

基本要求

扩展要求

二. 实现过程及项目展示

1. 建立mysql表

2. node_modules的安装

3. 构建登录、注册网站

登录功能

注册功能

设置Session

与数据库连接 

页面润色

效果展示

4. 信息检索功能

实现查询词支持布尔表达式

分页显示查询结果

信息排序功能

查询、清除按钮的设计

效果展示

5.数据分析图

柱状图

饼状图 

折线图

词云 

三. 总结


一. 实验要求

基于第一个项目爬虫爬取的数据(3-5个数据源),完成数据展示网站。

基本要求:

1、用户可注册登录网站,非注册用户不可登录查看数据

2、用户注册、登录、查询等操作记入数据库中的日志

3、实现查询词支持布尔表达式 (比如“新冠 AND 肺炎”或者“新冠 OR 肺炎”)

4、爬虫数据查询结果列表支持分页和排序

5、用Echarts或者D3实现3个以上的数据分析图表展示在网站中

扩展要求(非必须):

1、实现对爬虫数据中文分词的查询

2、实现查询结果按照主题词打分的排序

3、用Elastic Search+Kibana展示爬虫的数据结果

二. 实现过程及项目展示

1. 建立mysql表

        为实现用户注册、登录、查询等操作记入数据库中日志的功能,可以建立两个mysql表,用来保存用户信息和操作日志。

        在命令行中进入mysql/bin,分别建立如下所示的mysql表

       此时可以看到,加上之前的项目,一共建立了三个mysql表(fetches、user、user_antion)

 

在Navicat Premium中查看的效果如下 

2. node_modules的安装

  在项目文件夹下对应npm install 安装需要的模块,具体的模块位于package.json中

3. 构建登录、注册网站

  • 登录功能

根据老师的代码实现如下

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

            };

登录页面路由(对应起到提示用户名或密码错误、用户不存在的功能)

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) {
    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:'用户名或密码错误!请检查后输入'});
      }
    }
  });
});
  • 注册功能

注册页面对应起到提示两次密码不一致、用户已存在、注册成功跳转到登录页面的功能

 //增加注册用户
            $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;
                        });
                }
            };
        });

注册页面路由

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

});
  • 设置Session

用于在服务端存储用户信息

var session = require('client-sessions');
app.use(session({
  secret: 'sessiontest',
  resave: true,
  saveUninitialized: false,
  cookie : {
    maxAge : 1000 * 60 * 60, 
  },
}));
  • 与数据库连接 

将用户的操作日志写入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);

}, ));

多次操作后两个新建的mysql表中记录的操作日志

  • 页面润色

  • 加入大标题:web编程 期末大作业展示

body部分

<h1><i>web编程 期末大作业展示</i></h1>

css部分

 h1 {
         top:0px;
         margin-left: 500px;
         font-family: "隶书";
         font-size: 46px;
    }
  • 添加背景 

对页面添加背景图片,将需要的图片移到 public/images 文件夹下,此处的背景图片为:background1.jpg

 <body style="background: url(./images/background1.jpg) ;
        background-size:100% 100% ; 
        background-attachment: fixed" >
  • 加入个人信息

css

.contact {
            position:absolute;
            background-color:#e9e3e3;
            height :50px;
            width:100%;
            text-align: center;
            bottom:0;
            font-size: 18px;
        }

footer

<div ng-if="!pictureng && !searchng && !displayng" class = "contact" >
        10205501456  &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp  彭林航<br>
        <address>联系邮箱: 10205501456@stu.ecnu.edu.cn</address>
</div>

效果展示

4. 信息检索功能

用户成功登录后,调整到新的页面,只有登录后的用户才能拥有数据检索等功能。

在期中作业中,我们也类似地实现过了检索功能,详见 爬虫项目④(前后端的搭建)

下面介绍下与期中作业相比新添加的功能

  • 实现查询词支持布尔表达式

首先在news.html引入查询页面


<div ng-show="isShow" style="width: 1300px;position:relative; top:70px;left: 80px">
    <!--    查询页面-->
    <div ng-include="'search.html'"></div>

</div>

前端

<form class="form-horizontal" role="form">
    <div class="row" style="margin-bottom: 10px;">
        <label class="col-lg-2 control-label">标题关键字</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">内容关键字</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>
</form>

路由端

router.get('/search', function(request, response) {
    console.log(request.session['username']);
    //sql字符串和参数
    if (request.session['username']===undefined) {
        // response.redirect('/index.html')
        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});
        })
    }
});

以及位于dao/newsDAO.js中的newsDAO.search函数

总的实现效果见下图

  • 分页显示查询结果

当页面列表数据过多时,我们往往采用将列表内容分页的办法来处理,一般有如下两种处理方式:1、不需要后台配合,前台一次性拿完所有数据,然后进行分页展示;这种方式只是为了界面上对用户更友好,并没有实际提升页面的效率(数据量过大时页面加载压力比较大)

2、需要后台配合,后台对改数据做分页处理,页面每次只请求需要展示的该页面的数据,换页时需要二次请求,这种方式是比较推荐的

这里采用第一种做法,不需要后台做数据分页上的支持。

//打印当前选中页
    $scope.selectPage = function (page) {
        //不能小于1大于最大(第一页不会有前一页,最后一页不会有后一页)
        if (page < 1 || page > $scope.pages) return;
        //最多显示分页数5,开始分页转换
        var pageList = [];
        if(page>2){
            for (var i = page-2; i <= $scope.pages && i < page+3; i++) {
                pageList.push(i);
            }
        }else {
            for (var i = page; i <= $scope.pages && i < page+5; i++) {
                pageList.push(i);
            }
        }

        $scope.index =(page-1)*$scope.pageSize+1;
        $scope.pageList = pageList;
        $scope.selPage = page;
        $scope.items = $scope.data.slice(($scope.pageSize * (page - 1)), (page * $scope.pageSize));//通过当前页数筛选出表格当前显示数据
        console.log("选择的页:" + page);
    };
   // 分页
    $scope.initPageSort=function(item){
        $scope.pageSize=5;  //每页显示的数据量,可以随意更改
        $scope.selPage = 1;
        $scope.data = item;
        $scope.pages = Math.ceil($scope.data.length / $scope.pageSize); //分页数
        $scope.pageList = [];//最多显示5页,后面6页之后不会全部列出页码来
        $scope.index = 1;
        // var page = 1;
        // for (var i = page; i < $scope.pages+1 && i < page+5; i++) {
        //     $scope.pageList.push(i);
        // }
        var len = $scope.pages> 5 ? 5:$scope.pages;
        $scope.pageList = Array.from({length: len}, (x,i) => i+1);

        //设置表格数据源(分页)
        $scope.items = $scope.data.slice(0, $scope.pageSize);

    };
//设置当前选中页样式
    $scope.isActivePage = function (page) {
        return $scope.selPage == page;
    };
    //上一页
    $scope.Previous = function () {
        $scope.selectPage($scope.selPage - 1);
    };
    //下一页
    $scope.Next = function () {
        $scope.selectPage($scope.selPage + 1);
    };

    $scope.searchsortASC = function () {
        $scope.sorttime = '1';
        $scope.search();
    };
    $scope.searchsortDESC = function () {
        $scope.sorttime = '2';
        $scope.search();
    };

设置前后切换页面效果

<div class="pull-right">
            <nav>
                <ul class="pagination">
                    <li>
                        <a ng-click="Previous()" role="button"><span role="button">上一页</span></a>
                    </li>
                    <li ng-repeat="page in pageList" ng-class="{active:isActivePage(page)}" role="button">
                        <a ng-click="selectPage(page)" >{{ page }}</a>
                    </li>
                    <li>
                        <a ng-click="Next()" role="button"><span role="button">下一页</span></a>
                    </li>
                </ul>
            </nav>
        </div>

总的实现效果见下图

  • 信息排序功能

通过以时间为排序标准,对信息进行排序显示

<div class="pull-left" style="margin-top: 12px;">
            <button type="submit" class="btn btn-primary" ng-click="searchsortASC()" >发布时间升序</button>
            <button type="submit" class="btn btn-primary" ng-click="searchsortDESC()">发布时间降序</button>
</div>

对查找到的信息按发布时间升序或发布时间降序

  • 查询、清除按钮的设计

   查询按钮对应显示检索得到的内容,清除按钮可以清空已输入的内容

<div class="form-group">
        <div class="col-md-offset-4">
             //查询按钮   
        <input  ng-click="search()"  class="btn btn-default" type="button" 
                value="查询"  style=" font-size: 20px; 
                color:rgb(0, 81, 128);
                background-color:rgb(17, 137, 206); 
                border-radius: 15px " ; />
                &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
             //清除按钮     
        <input  type="reset"   value="清除" 
                class="btn btn-default"  style="  font-size: 20px ;
                color:rgb(0, 81, 128);
                background-color:rgb(17, 137, 206);
                border-radius: 15px; "   />
</div>

实现效果如下

  • 效果展示

输入标题关键词如 “A股” 后,可以看到一下的检索结果

5.数据分析图

  • 柱状图

前端

        //柱状图     
        $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 {

                        // var newdata = washdata(data);
                        let xdata = [], ydata = [], newdata;

                        var pattern = /\d{4}-(\d{2}-\d{2})/;
                        res.data.result.forEach(function (element) {
                            // "x":"2020-04-28T16:00:00.000Z" ,对x进行处理,只取 月日
                            if (pattern.exec(element["x"]) != null)                            
                            xdata.push(pattern.exec(element["x"])[1]); 
                            ydata.push(element["y"]);
                        });
                        newdata = {"xdata": xdata, "ydata": ydata};

                        var myChart = echarts.init(document.getElementById('main1'));

                        // 指定图表的配置项和数据
                        var option = {
                            title: {
                                text: '新闻发布数 随时间变化'
                            },
                            tooltip: {},
                            legend: {
                                data: ['新闻发布数']
                            },
                            xAxis: {
                                data: newdata["xdata"]
                            },

                            yAxis: {},
                            series: [{
                                name: '新闻数目',
                                type: 'bar',
                                data: newdata["ydata"]
                            }]
                        };
                        // 使用刚指定的配置项和数据显示图表。
                        myChart.setOption(option);
                    }
                },
                function (err) {
                    $scope.msg = err.data;
                });

    };

由于提供的代码与本地查询到的数据格式不尽相同,故在原代码上稍加修改。在

 xdata.push(pattern.exec(element["x"])[1]);

代码前增加筛选的限制条件

  if (pattern.exec(element["x"]) != null)        

路由端

router.get('/histogram', function(request, response) {
    //sql字符串和参数
    console.log(request.session['username']);

    //sql字符串和参数
    if (request.session['username']===undefined) {
        // response.redirect('/index.html')
        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();
        });
    }
});

总的实现效果如下(大部分新闻的数据是在期中阶段和近段时间爬取的)

  • 饼状图 

前端

  //饼状图
  $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) {
                        // "x":  责任编辑:李夏君 ,对x进行处理,只取 名字
                        // console.log(pattern.exec(element["x"]), element["y"]);
                        if (pattern.exec(element["x"]) != null && element["y"] >= 4) {
                            newdata.push({name: pattern.exec(element["x"])[1], value: 
                            element["y"]});
                        }
                    });

                    var myChart = echarts.init(document.getElementById('main1'));
                    var app = {};
                    option = null;
                    // 指定图表的配置项和数据
                    var option = {
                        title: {
                            text: '作者发布新闻数量',
                            x: 'center'
                        },
                        tooltip: {
                            trigger: 'item',
                            formatter: "{a} <br/>{b} : {c} ({d}%)"
                        },
                        legend: {
                            orient: 'vertical',
                            left: 'left',
                            // data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索 
                                       引擎']
                        },
                        series: [
                            {
                                name: '访问来源',
                                type: 'pie',
                                radius: '55%',
                                center: ['50%', '60%'],
                                data: newdata,
                                itemStyle: {
                                    emphasis: {
                                        shadowBlur: 10,
                                        shadowOffsetX: 0,
                                        shadowColor: 'rgba(0, 0, 0, 0.5)'
                                    }
                                }
                            }
                        ]
                    };
                    // myChart.setOption(option);
                    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
                        });
                        // 显示 tooltip
                        myChart.dispatchAction({
                            type: 'showTip',
                            seriesIndex: 0,
                            dataIndex: app.currentIndex
                        });
                    }, 1000);
                    if (option && typeof option === "object") {
                        myChart.setOption(option, true);
                    }
                    ;
                }
            });
    };

与之前柱状图类似,增加上了筛选条件

if (pattern.exec(element["x"]) != null && element["y"] >= 4)

路由端

router.get('/pie', function(request, response) {
    //sql字符串和参数
    console.log(request.session['username']);

    //sql字符串和参数
    if (request.session['username']===undefined) {
        // response.redirect('/index.html')
        response.json({message:'url',result:'/index.html'});
    }else {
        var fetchSql = "select author as x,count(author) as y from fetches group by author;";
        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();
        });
    }
});

总的实现效果如下图所示

  • 折线图

前端

//折线图
$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: '"疫情"该词在新闻中的出现次数随时间变化图'
                        },
                        xAxis: {
                            type: 'category',
                            data: Object.keys(res.data.result)
                        },
                        yAxis: {
                            type: 'value'
                        },
                        series: [{
                            data: Object.values(res.data.result),
                            type: 'line',
                            itemStyle: {normal: {label: {show: true}}}
                        }],

                    };

                    if (option && typeof option === "object") {
                        myChart.setOption(option, true);
                    }
                }

            });
    }; 

路由端

router.get('/line', function(request, response) {
    //sql字符串和参数
    console.log(request.session['username']);

    //sql字符串和参数
    if (request.session['username']===undefined) {
        // response.redirect('/index.html')
        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();
        });
    }
});
  • 词云 

在项目文件夹下应安装好 nodejieba

前端

 //词云 
$scope.wordcloud = function () {     
        $scope.isShow = false;
        $http.get("/news/wordcloud").then(
            function (res) {
                if(res.data.message=='url'){
                    window.location.href=res.data.result;
                }else {
                    var mainContainer = document.getElementById('main1');

                    var chart = echarts.init(mainContainer);

                    var data = [];
                    for (var name in res.data.result) {
                        data.push({
                            name: name,
                            value: Math.sqrt(res.data.result[name])
                        })
                    }

                    var maskImage = new Image();
                    maskImage.src = './images/logo.png';

                    var option = {
                        title: {
                            text: '所有新闻内容 jieba分词 的词云展示'
                        },
                        series: [{
                            type: 'wordCloud',
                            sizeRange: [12, 60],
                            rotationRange: [-90, 90],
                            rotationStep: 45,
                            gridSize: 2,
                            shape: 'circle',
                            maskImage: maskImage,
                            drawOutOfBound: false,
                            textStyle: {
                                normal: {
                                    fontFamily: 'sans-serif',
                                    fontWeight: 'bold',
                                    // Color can be a callback function or a color string
                                    color: function () {
                                        // Random color
                                        return 'rgb(' + [
                                            Math.round(Math.random() * 160),
                                            Math.round(Math.random() * 160),
                                            Math.round(Math.random() * 160)
                                        ].join(',') + ')';
                                    }
                                },
                                emphasis: {
                                    shadowBlur: 10,
                                    shadowColor: '#333'
                                }
                            },
                            data: data
                        }]
                    };

                    maskImage.onload = function () {
                        // option.series[0].data = data;
                        chart.clear();
                        chart.setOption(option);
                    };

                    window.onresize = function () {
                        chart.resize();
                    };
                }

            });
    }

});

路由端

router.get('/wordcloud', function(request, response) {
    //sql字符串和参数
    console.log(request.session['username']);

    //sql字符串和参数
    if (request.session['username']===undefined) {
        // response.redirect('/index.html')
        response.json({message:'url',result:'/index.html'});
    }else {
        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();
        });
    }
});

 总的实现效果如下

更换logo后(新的logo存储在public/images文件夹下)的展示

三. 总结

       数据库是基于期中大作业的情况下完成的,在耗时许久、大多数参考老师代码的情况下艰难地完成了这次爬虫大作业,在这里要感谢老师和两位助教的耐心帮助,让我实现了从零开始的突破,掌握了些许html、css、JavaScrip等网页开发方面的知识,期待在今后的学习中能收获到更多内容!

1. 总体介绍 本次项目主要以本学期所学内容为基础,采用servlet+jsp+jdbc的技术以及mvc模式进行项目开发,本次开发的内容主要以实现CRUD核心功能为主的教务管理系统,分为学生端和教师端,前端采用jquery进行数据传输以及处理,bootstap写界面。 2. 技术架构 运行环境:tomcat9+mysql5+maven3.8+jdk8 前端技术:jquery 用以数据处理以及前端验证以及生成验证码等等 Bootstrap 前端界面处理 后端技术:servelt+jsp maven进行jar包和第三方库管理 采用jspsmart进行文件的操作处理 数据库:mysql5 基于MVC的分层思想及采用jsp+servelt技术的B/S结构的应用系统,系统主要开发语言为JAVA,JSP。数据库要求使用MySQL8.0,应用服务器选用Tomcat服务器 3. 功能介绍 系统能够提供用户有好的界面 系统具有良好的允许效率 系统具有良好的扩充性,灵活性 系统管理操作简单易懂 3.1 总体结构 3.2 模块详情 学生模块: 注册: 1. 用户点击注册,进行注册; 2. 用户输入注册信息; 3. 校验数据:如果用户名重复或者两次密码校验不合格或者密码规格不符合,则提示错误信息; 4. 若信息无错误,提示注册成功,跳转到登录页。 登录: 1. 用户进入系统未进行登录则自行跳转登录页面; 2. 点击忘记密码可进行密码找回; 3. 提交信息进行校验,查看用户名密码是否为空以及是否符合格式,随后在后台进行校验,合格则进行登录跳转到用户界面; 4. 若登录信息不正确,则提示登录错误信息。 查看成绩: 1. 点击查看成绩,打印成绩列表; 2. 支持到处成绩单为pdf格式。 导出成绩: 1. 点击到处按钮; 2. 系统自动处理并到处成pdf。 个人信息管理: 1. 选择上传头像 2. 修改个人信息:按需填写个人信息,随后进行保存则覆盖修改以往的个人信息。 退出登录: 1. 点击退出登录,自动退出到首页并删除本地和服务器缓存。 教师模块: 注册: 1用户点击注册,进行注册; 2用户输入注册信息; 3校验数据:如果用户名重复或者两次密码校验不合格或者密码规格不符合,则提示错误信息; 4若信息无错误,提示注册成功,跳转到登录页。 登录: 1用户进入系统未进行登录则自行跳转登录页面; 2点击忘记密码可进行密码找回; 3提交信息进行校验,查看用户名密码是否为空以及是否符合格式,随后在后台进行校验,合格则进行登录跳转到用户界面; 4若登录信息不正确,则提示登录错误信息。 个人信息管理: 1选择上传头像 2修改个人信息:按需填写个人信息,随后进行保存则覆盖修改以往的个人信息。 学生管理: 1. 点击添加学生,填写学生信息进行添加; 2. 修改学生信息,点击修改,按需填写要修改的学生信息,进行保存覆盖修改; 3. 点击删除学生数据,提示是否删除,确定则删除,取消则不删除; 4. 查看成绩,点击查看学生成绩,单独列出学生成绩列表; 成绩管理: 1. 点击成绩管理,列出所有学生成绩; 2. 点击修改,勾选需要修改的学生,按需填写修改信息,保存覆盖修改学生信息。 退出登录: 1点击退出登录,自动退出到首页并删除本地和服务器缓存。 4. 页面设计 静态jsp页面和jquery和bootstrap 5. 数据库设计 权限对照表: 表名: role 名称 类型 长度 允许空值 是否主键 注释 uid 整型 11 否 是 权限等级 utype 字符 255 否 否 用户等级名称 分数表: 表名: score 名称 类型 长度 允许空值 是否主键 注释 id 整型 200 否 是 学号 dat 字符 255 否 否 课程1分数 Android 字符 255 否 否 课程2分数 Jsp 字符 255 是 否 课程3分数 学生表: 表名: student 名称 类型 长度 允许空值 是否主键 注释 id 整型 59 否 是 学号 password 字符 255 否 否 登陆密码 Name 字符 255 否 否 学生姓名 Sex 字符 255 是 否 性别 School_date 字符 255 是 否 入学时间 Major 字符 255 是 否 专业 email 字符 255 是 否 邮箱 教师表: 表名: student 名称 类型 长度 允许空值 是否主键 注释 id 整型 59 否 是 教师工号 password 字符 255 否 否 登陆密码 Name 字符 255 否 否 教师姓名 Sex 字符 255 是 否 性别 email 字符 255 是 否 邮箱
Web前端期末大作业是一项重要的任务,需要学生在限内完成一个完整的网页设计项目。这个项目通常需要包括网页的设计、布局、交互、响应式设计等多个方面。以下是一些可能需要涉及的技术和工具: 1. HTML和CSS:这是网页设计的基础,需要学生掌握HTML和CSS的基本语法和用法,以及如何将它们应用到实际的网页设计中。 2. JavaScript:JavaScript是一种用于网页交互和动态效果的编程语言,需要学生掌握JavaScript的基本语法和用法,以及如何将它应用到网页设计中。 3. 响应式设计:现代网页需要适应不同的设备和屏幕大小,需要学生掌握响应式设计的基本原理和技术,以确保网页在不同设备上都能正常显示。 4. 设计工具:学生需要使用一些设计工具来辅助网页设计,例如Photoshop、Sketch、Figma等。 5. 版本控制工具:学生需要使用版本控制工具来管理自己的代码,例如Git。 对于Web前端期末大作业,建议学生按照以下步骤进行: 1. 确定网页设计的主题和目标受众。 2. 设计网页的结构和布局,包括页面的导航、内容区域、底部等。 3. 使用HTML和CSS编写网页的基本结构和样式。 4. 使用JavaScript实现网页的交互和动态效果。 5. 使用响应式设计确保网页在不同设备上都能正常显示。 6. 使用设计工具制作网页的图像和素材。 7. 使用版本控制工具管理自己的代码。 8. 测试和调试网页,确保网页的功能和效果都正常。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值