web编程项目
一 项目要求
二 项目实现
该项目使用了以下模块:
express-session:是express中的一个处理session的中间件。有以下特点:session管理(基本功能),cookie签名,可替换持久储存模块。
在app.js
中,设置session的各个参数。
morgan:express默认的日志中间件。
angularJS:是一个 JavaScript 框架。它可通过<script> 标签添加到 HTML 页面。AngularJS通过指令扩展了HTML,并且通过表达式绑定数据到 HTML。
ng-app
指令指明了应用, ng-controller
指明了控制器。
根据项目要求,分别介绍基本要求中的五个功能。
1. 用户注册/非注册
要实现用户注册的功能,首先需要创建一个保存用户信息的user
表,然后实现当用户注册时存入user
,没有注册的用户不能访问网页。
1.1 构建user表
其中的cond列存储该账号的状态,stop:账号禁用,start:账号启用。
--创建用户信息数据表
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,
`cond` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username_UNIQUE` (`username`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.2 实现login,register,logout代码
-
login:登录时调用该函数,访问
/users/login
路径,判断该用户是否存在,用户和密码是否匹配,该用户是否没被禁用;如果都满足,则返回ok
,将用户信息存入session和cookie中,跳转到news.html
页面。
-
register:注册时调用该函数,访问
/users/register
路径,判断该用户是否已经存在,不存在就添加到user表中并返回ok
,跳转到index.html
界面。
-
logout:登出时调用该函数,访问
/users/logout
路径,删除掉session和cookie中存储的用户信息,并跳转到index.html
界面。
1.3 实现非注册用户无法访问
在进入news.html页面后,每一个操作都需要首先判断request.session['username']
是否等于undefined
,即判断当前是否有用户登录,只有登录之后才能进行相应的操作,否则只能跳转到登录界面index.html
.
2. 用户操作记入日志
2.1 构建user_action表
存入用户的用户名,请求时间,方式,网址和状态码。
--记录用户的登陆,查询(具体查询语句)操作
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;
2.2 实现请求存入表
引入morgan
,借助中间件保存的信息。将每一次请求的信息通过函数解析得到相关的数据,调用logDAO
中的userlog
插入user_action
表中。
并在terminal中输出相关的信息。
3. 查询结果实现分页和排序
使用AngularJs
实现分页和排序,使得每一页显示5条记录,并且可以按照升序或者降序排列。
3.1 分页
首先在网页上实现页面的按钮,其中按钮关联的函数在js代码中实现。
在js中首先需要在initPageSort()
根据查询得到的数据进行初始化页面。在任意需要分页的函数中可以调用该函数进行分页初始化。
然后在点击了相应的页数之后调用selectPage(page)
中显示当前页的数据。
3.2 排序
在search.html
中设置两个按钮,表示升序和降序
在news.js
中调用相应的函数设置sorttime
的值,并再调用search()
函数,得到相应的返回结果。
4. Echarts实现图表分析
4.1 时间热度分析
在一个页面实现输入查询词后会显示查询词的时间热度分析页面。
首先需要设计一个网页,在该页面中有输入表单,提交按钮。提交后显示相应的折线图。设置点击按钮后执行wordhot()
函数,查询后使isshowwordhot=true
显示图表。
wordhot()
函数获取查询输入wordkey
,然后访问路径/news/wordhot?k=${wordkey}
将查询词传入,得到新闻中含有该词的数目和相应的日期,将这些数据通过echarts在id=main2
的位置构建一个折线图表。
其中的请求会在路由函数中获取查询词,设置sql查询语句,从fetches
表中得到含有该词的新闻文本,调用publish_date.toLocaleDateString()
将标准形式的日期转换为日常使用的日期。对返回的新闻再调用freqchange()
函数。将所有结果通过response
返回给wordhot
函数。
- freqchange():使用
nodejieba
对每一个新闻文本进行匹配,得到每一个文本中的包含该关键词的数量,通过word_freq
字典,保存每一个日期所含关键词的数量。
因为日期在传输过来之前已经处理,因此不需要再通过正则化进行解析。
4.2 关键词词云分析
对所有新闻的关键词进行中文分词分析,按照每个词出现的次数多少决定词的大小,最后构成一幅由关键词组成的词云。
当在新闻页面点击词云时,会调用wordcloud()
函数,在该函数中设置显示的界面,请求/news/wordcloud
路径,得到由词语和出现数量组成的字典。使用Echarts
构成一个词云返回给页面。
当访问/news/wordcloud
路径,会调用路由函数。在该函数中通过fetches
表中返回所有的keywords
。调用wordcut()
函数,对所有关键词进行分词。得到分词后的{词语:数量}
结果,返回给wordcloud()
函数。
- wordcut.js:对传入的所有文本使用正则化去掉异常字符,使用
nodejieba.cut()
获得分词结果,将分词结果写入word_freq
中。
原本的词云使用的是所有新闻的正文内容,但因为nodejieba
无法去掉停用词,因此将正文换为关键词,能够更好的体现新闻中关注的热点。
因为随着时代新出现的词并没有及时的增添到分词列表中,因此使用nodejieba.load()
将需要分到一起的词填入。
新冠 //userdict.utf8文本中填入内容
4.3 其余数据分析
和4.1中绘制折线图的步骤一致,当点击相应的按钮时,调用相应的函数,访问相应的路径,得到结果,通过Echarts
绘制图像,传输到网页上。
- 以柱状图为例:
设置相应网页的显示,访问/news/histogram
路径,得到每天的新闻数量。在id=main1
中初始化一个echart
图,将相应的参数写入options
中,构建一个柱状图。
在路由函数中,从fetches
表中获取发布时间和根据发布时间得到的每天的新闻数。将查询结果返回给上述函数,以便构造图表。
5. 管理端界面
只有管理员(admin)一个人有管理员界面,管理员可以在该页面中查看所有用户的操作记录和停用启用注册用户。
5.1 实现管理员页面的显示与否
用户登录后在登录成功跳转到news.html
页面时将当前用户名存入scope中,并判断当前用户是否是管理员。
在news.html
中,设置body中ng-init="getuser()"
,这样在加载该页面的时候就会调用getuser()
函数获得登录成功的用户名user
。并将该用户名填入网页中,显示欢迎:XXX。
- getuser():在该函数中访问
/news/info
路径,获取session中存储的用户名,判断用户名是否是管理员admin,如果是则在导航栏中显示管理员界面,设置$scope.isAdminbar = true
,使得管理员可以对注册用户进行查看和管理。
5.2 设计管理员页面
当点击了管理员界面 后,会显示管理员界面的网页。
- 设置一个输入文本和按钮方便管理员查询用户。
- 当点击
查询
之后,在查询框的下方设置一个table显示查询结果,使用ng-repeat
将每个用户填入表格中。 - 在最后一列给每个用户设置一个
查看
(操作记录)的按钮和停用/启用
(账号)的按钮:
点击查看
后会显示该用户的所有操作记录。
停用
和启用
根据该用户的cond
信息判断,如果该用户是启用(start)的,则显示停用
按钮;如果该用户是被停用(stop)的,则显示启用
按钮。
- 在该页面的最下方设置一个显示用户操作记录的表格,当点击了
查看
之后,才会在下方显示该用户的操作记录。
5.3 查看注册用户的操作记录
在管理员页面中点击查询之后,会调用searsearchaction()
函数。
<td><button type="button" class="button1" ng-click="searchaction(item.username)">查看</button>
和之前的函数的逻辑相同,访问/news/searchaction?u=${username}
路径,将要查询的username传入,获得返回值后,设置$scope.isshowaction = true
,显示用户操作记录数据,并将数据存入actiondata
中。
将返回的数据显示在5.2中设置的表格中。
5.4 停用启用注册用户
在管理员页面中点击停用[启用]
时,会调用stop()[start()]
函数。
<button type="button" class="button2" ng-show="item.cond == 'start'" ng-click="stop(item.username)">停用</button>
<button type="button" class="button3" ng-show="item.cond == 'stop'" ng-click="start(item.username)">启用</button>
这两个函数的执行逻辑相似,都是访问相应的路径,如果执行成功就返回ok。
当访问/news/stop
路径时,将传入的用户名username存入user,构造改变该用户账号状态的sql语句。
"update user set cond = 'stop' where username ='" + user + "';";
当该语句执行成功之后,返回ok消息,表示该账号已被停用。
6. 查询优化
因为爬取到的新闻文本都是有关键词的,因此可以在已有查询的基础上,增加关键词查询。
- 在
search.html
网页中添加输入端,设置输入的值为keyword1
和keyword2
。
在点击查询之后,调用search()
函数,请求/news/search
路径,将参数传入newsDAO.search()
函数,获取相应的新闻。在该函数中增加对keyword的查询语句的判断。
三 项目展示
在文件根目录下输入:
node bin/www
可以在localhost:3000
网址打开该网站。
1. 登录与注册
打开网站后必须先登录或者注册。
- 登录过程中,当密码和用户不匹配,用户被停用,没有该用户都无法成功登录。
- 注册过程中,无法注册已有账号。
2. 登录成功
当登录成功之后,会进入new.html页面。
- 普通用户只会显示用户名。
- 管理员会显示管理员界面和管理员用户名。
3. 查询
- 可以对查询数据进行任意组合形式,也可以对查询结果进行
排序
和分页
展示。
4. 分析
- 查询任意词显示时间热度分析
- 新闻关键词的词云展示
从词云可以看出最近最受关注的话题是新冠,肺炎,疫情,外交
等等。
- 每天新闻发布数的柱状图
- 作者发布新闻数量饼状图
5. 管理员界面
- 点击
管理员界面
后,会显示用户查询界面。输入查询的用户后,会显示相关的用户。
- 当点击用户后面的
查看
按钮后,会显示该用户的操作记录在网页的下方。
- 当点击用户后面的
停用
按钮后,该用户的cond
设置为stop
,该账户无法再登录使用,直到管理员启用
该账号。
6. 登出
- 点击用户名,再点击下方的
退出登录
,即可登出账号。
四 项目总结
通过完成web编程期末项目,更加熟悉javascript的实现逻辑,了解了AngularJS这个JavaScript 框架。但在该项目中还没有实现修改数据库的值后及时显示在页面上,希望之后能加以改进。而对于如何实现一个从前端-后端-数据库的项目有了一定的经验。当想要实现某个功能时:
- 首先需要考虑这个功能需要从网页中获取数据吗?如果需要,则应该在html中设计相应的组件,点击按钮会发生怎样的变化。
- 如果这个变化需要后端的参与,则应该设计相应的函数处理该请求。
- 而且后端也分为了处理代码和路由代码:
- 路由函数处理request请求,可以获取传过来的参数,使用这些参数可以访问数据库,并将结果写入response。
- 处理函数可以响应前端的调用,构造url调用路由函数,得到返回结果可以进行相应的处理,比如:返回新页面,显示某页面,返回echarts图表,将返回数据写入到前端页面中。