结对作业二
作业的基本信息 | |
---|---|
这个作业属于哪个课程 | 2021春软件工程实践S班 |
这个作业要求在哪里 | 结对作业二 |
结对信息 | 221801206毛依婷&221801216汪碧桢 |
这个作业的目标 | 熟练使用github以及了解web页面的编码与设计 |
一、Github仓库地址
1.1 Github仓库地址
1.2 代码规范
二、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 25 |
Estimate | 估计这个任务需要多少时间 | 20 | 25 |
Development | 开发 | 1620 | 2350 |
Analysis | 需求分析 (包括学习新技术) | 30 | 25 |
Design Spec | 生成设计文档 | 20 | 20 |
Design Review | 设计复审 | 10 | 12 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 25 |
Design | 具体设计 | 20 | 20 |
Coding | 具体编码 | 1400 | 2520 |
Code Review | 代码复审 | 30 | 28 |
Test | 测试(自我测试,修改代码,提交修改) | 90 | 120 |
Reporting | 报告 | 70 | 120 |
Test Repor | 测试报告 | 45 | 60 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 15 | 20 |
合计 | 1710 | 2495 |
三、成品展示
3.1 成品功能完成情况一览
功能点 | 是否完成 | 备注 |
---|---|---|
展示待导入的论文 | √ | |
可以选择论文导入到论文列表 | √ | |
展示论文列表 | √ | |
对论文列表进行查看和删除操作 | √ | |
输入查找条件对论文列表进行精确查询和模糊查询 | √ | |
展示查询后的结果 | √ | |
根据论文广场中的论文信息,提取top10个热门领域或热门研究方向 | √ | |
根据论文广场中的论文信息,形成关键词列表,点击某个关键词可展现相关的论文 | √ | |
以动图的形式呈现多年间、不同顶会的热词呈现热度走势对比 | x | 尝试把echart表导入yii,但是没有学会,退而求次以表格形式展示不同年份的top10关键词 |
部署到云服务器上 | x |
3.2 成品视频展示
四、结对讨论过程描述
4.1 技术和框架的决定
项目开始初期,双方结合给出的需求查阅了相关资料,最后因为之前有用Yii2.0框架和Apache开发Web实践的经历,对Yii2.0框架有一定的了解,并发现Yii2.0与其他框架相比,有如下几个优点:
- 和其他PHP框架相比,Yii实现了MVC(Model-View-Controller)设计模式并基于该模式组织代码。
- Yii代码简单优雅。
- Yii是一个全栈框架,对关系型和NoSQL数据库都提供了查询生成器和ActiveRecord;多层缓存支持,等等。
- Yii代码简介,高性能始终是Yii的首要目标之一。
于是决定用Yii2.0框架来开发此次项目。
4.2 开发过程
决定了基于yii2.0框架的advanced模板进行论文网站的开发方向后,我们观看魏曦Yii2.0框架教学视频进行学习,同时写代码进行功能的实现。
在开发过程中遇到了很多问题,比如写的页面点击跳转后404了、页尾出现了奇怪的符号、想导入一篇论文到论文列表结果把整页的论文都导到论文列表了······。期间还经历了github实战,连着几天1点多才睡,我们做的是网站,掉的是头发。但是幸好,功夫不负掉发有心人,在多次修改代码、不断运行、上网寻找解决方法、多次观看教学视频后这些问题都解决了。
4.3 讨论合影
五、设计实现过程
5.1 数据库和数据表设计
数据表 | 作用 | 字段 |
---|---|---|
papersearchlist | 存放论文广场论文数据 | id,storeID,displayTitle,abstract,year,pubdate,link,keyword |
paperstore | 存放论文列表论文数据 | storeID,displayTitle,abstract,year,pubdate,link,keyword |
keywords | 存放论文广场论文关键词 | keywordname,keyWordCount |
eccvkey_16 | 存放ECCV2016年论文的关键词 | wordname,wordcount |
eccvkey_18 | 存放ECCV2018年论文的关键词 | wordname,wordcount |
eccvkey_20 | 存放ECCV2020年论文的关键词 | wordname,wordcount |
eccv | 生成Eccv(model),EccvController(controller) | id |
5.2 页面设计
5.3 具体功能设计
功能点 | 设计思路 |
---|---|
展示待导入的论文 | 调用Gii生成的Papersearchlist模型方法,在加载论文广场页面时通过获取actionIndex返回的dataProvider以列表形式展示 |
选择要导入的论文到论文列表 | 在paperstore的控制器方法中添加actionAddpaper,用户选择导入后把当前要导入的论文id作为参数传递给actionAddpaper |
展示论文列表 | 使用GridView::Widget,获取paperstore控制器方法的actionIndex传回的dataProvider展示论文列表 |
对论文列表进行查看和删除操作 | ActionColumn |
输入查找条件对论文列表进行精确查询和模糊查询 | filterModel自动搜索机制 |
展示查询后的结果 | filterModel |
根据论文广场中的论文信息,提取top10个热门领域或热门研究方向 | 在加载数据的时候把关键词按年份存入对应数据表 |
根据论文广场中的论文信息,形成关键词列表,点击某个关键词可展现相关的论文 | 本来是想参照魏曦Yii2.0框架教学视频中的标签云实现,但是关键词太多了比较困难,最后选择以列表形式在论文广场页面展示关键词 |
以动图的形式呈现多年间、不同顶会的热词呈现热度走势对比 | yii导入echart表 |
六、代码说明
论文广场(papersearchlist)部分代码说明
1.数据导入
加载论文广场页面时,会执行PapersearchlistController中的actionIndex,该方法的代码如下:
public function actionIndex()
{
$searchModel = new PapersearchlistSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
//$c=2941;
//$filepath="F:\jsonData\ECCV41";
//get_json($filepath,$c);
//$filename="F:\\eccvjson\\eccv20\\21";
//$tname="eccvkey_20";
//get_ek($filename,$tname);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
其中注释部分中的get_json($filename,$c)是我们用于解析本地json数据到数据表中的自定义函数,该函数解析json过程中还会对关键词进行存储。由于文件量过大,一次性解析3000+的json文件会进行频繁的读取文件、连接数据库操作,这就导致我们初次读取数据的时候报错,对此我们的解决方法是将文件分成多份,少量多次读入。
get_json中用到的update_key和add_key用于处理json数据中的关键词,如果keywords表中已有该关键词,则关键词次数+1,否则添加该关键词到keywords表中,这两个函数写在common/keyfunc.php中,代码很简单也很好理解,如果要查看,可以前往我们的 Github仓库查看,这里就不加展示了。
get_ek函数则是用于处理不同年份的论文数据,代码同样可以在我们的Github仓库中查看。
$count+=1;
$jsonfile = $filepath."/".$filename;
$json_data=file_get_contents($jsonfile);
$json_d=json_decode($json_data,true);
$tocpid="";
$keyarr = $json_d['关键词'];
$topicid=implode(',',$keyarr);//implode keywords
//import paper to papersearchlist table
Yii::$app->db->createCommand()->insert('papersearchlist', [
'id'=>$count,
'storeID' => $count,
'displayTitle' => $json_d['论文名称'],
'abstract'=>$json_d['摘要'],
'year'=>$json_d['会议和年份'],
'pubdate'=>$json_d['发布时间'],
'link'=>$json_d['原文链接'],
'keyword'=>$topicid,
])->execute();
//import keys to keywords table
$length=count($keyarr);
for($x=0;$x<$length;$x++)
{ $kstr='select * from keywords where keywordname=\''.$keyarr[$x].'\'';
$k_exist=Yii::$app->db->createCommand($kstr)->queryAll();
if($k_exist!=NULL)
{
update_key($keyarr[$x],1);
}
else
{
add_key($keyarr[$x]);
}
}
2.列表展示
使用ListView进行展示:
<?= ListView::widget([
'id'=>'papersearchlist',
'dataProvider'=>$dataProvider,
'itemView'=>'_listitem',//子视图,显示一篇文章的标题等内容.
'layout'=>'{items} {pager}',
'pager'=>[
'maxButtonCount'=>10,
'nextPageLabel'=>Yii::t('app','下一页'),
'prevPageLabel'=>Yii::t('app','上一页'),
],
])?>
其中子视图listitem代码如下:
<div class="paper">
<div class="test">
<div class="title" >
<br>
<span style="font-weight:bold" aria-hidden="true"></span>
<em>
<p class="glyphicon glyphicon-time" aria-hidden="true"></p>
<em><?= '发布时间:'.$model->pubdate." ";?></em>
<p><?= '论文名称:'.Html::encode($model->displayTitle)?></p>
<?=Html::a('导入到论文列表',['/paperstore/addpaper','_id'=>$model->storeID],['onclick'=>'return confirm("是否确认导入到列表?")'])?>
<br>
</em><hr>
</div>
</div>
</div>
3.按标题搜索
获取文本框输入内容,作为参数传递给PapersearchlistSearch的搜索,并重新加载论文广场页面完成展示内容的刷新,代码如下:
<div class="col-md-3">
<div class="searchbox">
<ul class="list-group">
<li class="list-group-item">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span> 查找文章(
<?= Papersearchlist::find()->count();?>
)
</li>
<li class="list-group-item">
<form class="form-inline" action="index.php?r=papersearchlist/index" id="w0" method="get">
<div class="form-group">
<input type="text" class="form-control" name="PapersearchlistSearch[displayTitle]" id="w0input" placeholder="按标题">
</div>
<button type="submit" class="btn btn-default">搜索</button>
</form>
</li>
</ul>
</div>
3.关键词搜索
和searchbox相似但有不同,具体不同在展示上,除了和searchbox相似的传递参数、调用方法、刷新页面外,还使用了keyWordWidget进行关键词列表的展示,代码如下:
//papersearchlist.php
<div class="keywordType">
<ul class="list-group">
<li class="list-group-item">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span> 关键词<br>(仅展示出现次数>=10的关键词)
</li>
<li class="list-group-item">
<?= keyWordWidget::widget();?>
</li>
</ul>
</div>
//keyWordWidget.php
<?php
namespace frontend\components;
use yii\base\Widget;
use yii\helpers\Html;
use common\models\Keywords;
use Yii;
class keyWordWidget extends Widget
{
public function init()
{
parent::init();
}
public function run()
{
$keyString='';
$keys = Keywords::find()->all();
foreach ($keys as $key)
{
$url = Yii::$app->urlManager->createUrl(['papersearchlist/index','PapersearchlistSearch[keyword]'=>$key->keywordname]);
$keyString .= '<a href="'.$url.'">'
.' <h2 style="margin:10px 0;panding:0;"><span class="label label-info" style="background:#00e0e0;'
.'display:inline-block;width:100%;">'
.$key->keywordname.'</span></h2'.'></a>';
//echo $typeString;
}
return $keyString;
}
}
?>
4.导入到论文列表
起初的想法:写一个自定义函数,放一个按钮,点击就运行函数。想象很美好,现实很折磨,尝试这样做之后发生了什么呢?点击了一次按钮,不断的提交参数导致整页的论文都被导到了列表,这可怎么办,不断查找后找到了解决方法。只要在paperstore中增加一个页面,并在控制器中添加相应的页面响应方法actionAddpaper,该方法接收从论文广场传来的论文id参数,在列表中搜索后返回表示是否存在的added参数,页面根据added参数展示不同的导入结果。代码如下:
//papersearchlist _listitem
<?=Html::a('导入到论文列表',['/paperstore/addpaper','_id'=>$model->storeID],['onclick'=>'return confirm("是否确认导入到列表?")'])?>
//addpaper.php
<div class="row">
<ol class="breadcrumb">
<li><a href="<?= Yii::$app->homeUrl;?>">首页</a></li>
<li>导入结果</li>
</ol>
<br><br>
<?php if($added){?>
<h4>导入成功!是否前去论文列表查看?</h4>
<?php }else{?>
<h4>导入失败,论文列表中已有该篇论文。</h4>
<?php }?>
<br><br><hr>
<?=Html::a('回到论文广场',['/papersearchlist/index'])." "?>
<?=Html::a('查看论文列表',['index'])?>
</div>
//actionAddpaper(&_id):
public function actionAddpaper($_id){
$added=1;
$searchstr='select * from paperstore where storeID=\''.$_id.'\'';
$_exist=Yii::$app->db->createCommand($searchstr)->queryAll();
if(!($_exist))
{
$resstr='select * from papersearchlist where storeID=\''.$_id.'\'';
$res=Yii::$app->db->createCommand($resstr)->queryOne();
$_title=$res['displayTitle'];
$_abstract=$res['abstract'];
$_y=$res['year'];
$_pub=$res['pubdate'];
$_link=$res['link'];
$_key=$res['keyword'];
Yii::$app->db->createCommand()->insert('paperstore', [
'storeID' => $_id,
'displayTitle' => $_title,
'abstract'=>$_abstract,
'year'=>$_y,
'pubdate'=>$_pub,
'link'=>$_link,
'keyword'=>$_key,
])->execute();
$this->added=1;
}
else{
$this->added=0;
}
return $this->render('addpaper',['added'=>$this->added]);
}
论文列表(paperstore)部分代码说明
这部分实现起来最简单,通过使用Gii生成模型和Search模型和控制器方法,再使用GridView进行展示就完事了,在教学视频中也有和该页面相似的页面教学。
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'options' => [
'style'=>'overflow: auto; word-wrap: normal;'
],
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'storeID',
'displayTitle:ntext',
// 'abstract:ntext',
'year:ntext',
// 'pubdate:ntext',
'keyword:ntext',
// 'link:ntext',
['class' => 'yii\grid\ActionColumn','header'=>'Operation','template' => '{view} {delete}',],
]]);
?>
ECCV热词统计(eccv)部分代码说明
在尝试n次echart无果后,选择以表格方式展示ECCV。经历了导入论文列表功能的折磨后,展示TOP10关键词功能就轻松了起来。和导入功能相似,建立ECCV页面,控制器中修改actionIndex方法,通过导航栏传入的参数_y获取不同数据表的数据并通过GridView::Widget展示。代码如下:
//nav(layouts/main.php):
['label' => 'ECCV热词统计', 'options'=>['class'=>'ycn-banner'], 'items'=>[
['label' => '<i class="key1-tag"></i> ECCV2016', 'url' => ['/eccv/index','_y'=>'1'],'encode'=>false],
['label' => '<i class="key2-tag"></i> ECCV2018', 'url' => ['/eccv/index','_y'=>'2'],'encode'=>false],
['label' => '<i class="key2-tag"></i> ECCV2020', 'url' => ['/eccv/index','_y'=>'3'],'encode'=>false],
]]
//actionIndex($_y):
public function actionIndex($_y)
{
if($_y==1)
{
$dataProvider = new SqlDataProvider([
'sql' => 'select * from eccvkey_16 order by wordcount desc',
'params' => [
':limit'=>10,
],
'totalCount' => 10,
'sort' => [ ],
'pagination' => [
'pageSize' => 10,
],
]);
}
else{
if($_y==2)
{
$dataProvider = new SqlDataProvider([
'sql' => 'select * from eccvkey_18 order by wordcount desc',
'params' => [
':limit'=>10,
],
'totalCount' => 10,
'sort' => [ ],
'pagination' => [
'pageSize' => 10,
],
]);
}
else{
$dataProvider = new SqlDataProvider([
'sql' => 'select * from eccvkey_20 order by wordcount desc',
'params' => [
':limit'=>10,
],
'totalCount' => 10,
'sort' => [ ],
'pagination' => [
'pageSize' => 10,
],
]);
}
}
return $this->render('index', [
'dataProvider' => $dataProvider,
]);
}
//GridView(index.php):
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'wordname',
'wordcount',
]]);
?>
七、心路历程与收获
221801206毛依婷:
本以为用yii2.0框架实现很简单,然后我掉的头发狠狠的打了我的脸。在逐步实现功能的过程中我的心情变化be like:
看了视频,觉得这样理论上好像可以(自信)→尝试失败(疑惑)→怎么不可以了,再看一遍视频,难道是这样(疑惑)→再次尝试失败(呆滞)→上网搜索→方法很多,逐个尝试(麻木)→成了(狂喜)
收获就是对yii2.0框架的认识+++++,并且对php语言也有了更多了解。
本次作业的感受:知识不够怎么办,学!
221801216汪碧桢:
此次刚看到题目,里面推荐的技术很多都不了解,所以刚开始会比较迷茫,因为要学习新的技术,而且要在摸索中写代码。后来经过讨论确定框架后,也是渐渐摸索(一边看视频一边debug),更加深刻地学习了一门新技术,当功能点完成时,会很有成就感,而且以前不了解前后端如何接起来,这次比较了解了,是新的收获呢。而且以前对于结对编程没什么概念,但这次结对编程让我感觉到通过随时复审和交流,程序设计和debug都更快了。
八、评价结对队友
221801206毛依婷 to 221801216汪碧桢:
虽然小汪同学说大多数代码是我打的,但这些代码的背后也有小汪同学不少的功劳,比如解析json数据并导入到数据表就是小汪同学完成的,数据导的很完美。本次作业多亏了小汪同学的陪伴,我才有坚持下去的意志。如果这是个人作业我肯定就因为麻烦草草了事了,但结对的方式让我用认真的态度对待并完成了它。
221801216汪碧桢 to 221801206毛依婷:
小毛是一个很有责任感又相对耐心的人(对比我),这次项目绝大多数都是她在努力顽强地debug,不管是页面数据的传递或是功能方法的编写,都是她熬夜打代码debug不断尝试解决出来的,真的很respect。