软工第二次结对作业


作业基本信息

这个作业属于哪个课程 2021春软件工程实践
这个作业要求在哪里 作业要求
这个作业的目标 功能1:对已爬取的论文列表进行操作可对论文列表进行删除;可对论文列表进行查询详细信息(支持模糊查询,查询结果的展示、排序等功能可自行设计);功能2:分析已爬取到的论文信息,提取top10个热门领域或热门研究方向形成如关键词图谱之类直观的查看方式,点击某个关键词可展现相关的论文;可对多年间、不同顶会的热词呈现热度走势对比,以动图的形式呈现(这里将范畴限定在计算机视觉的三大顶会CVPR、ICCV、ECCV内)2. 附加功能功能3:获取待爬取论文列表及论文信息爬取支持用户输入单个论文题目,也支持批量导入论文列表;通过论文列表,爬取论文的摘要、关键词、原文链接;数据来源网站:CVPR、ICCV、ECC至少爬取三年、三大顶会各300篇论文可编写爬虫代码实现,也可使用爬虫工具(如八爪鱼)爬取此功能为附加功能,实现此功能将获得附加分(详情见评分细则),如果技术上存在难度,可使用助教提供的数据来完成功能1和功能23. 本次项目需要部署到云服务器上,并且在博客中给出链接4. 推荐基于Web来开发,使用Web框架,如常见的JSP、Servlet、spring系列、flask、php、express等,如果技术存在难度也可以直接使用纯前端来进行开发,数据写在代码中,持久化在storage。Web使用的持久化建议持久化在嵌入式数据库中,如sqllite或derby。采用的技术应该具有平台兼容性,不依托于具体的环境。本次作业以实现功能为主要目标,技术考量仅仅占一定的分数。切勿用原型工具生成代码,一经发现直接0分。5. 可以扩展你想扩展的功能,扩展功能会被记入作为附加分(不超过编码部分的15%)。
作业正文 正文
其他参考文献 yii2.0使用手册

PSP表格

PSP2.1 [Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 180
Estimate 估计这个任务需要多少时间 1990 2830
Development 开发 1930 2650
Analysis 需求分析 (包括学习新技术) 60 60
Design Spec 生成设计文档 60 30
Design Review 设计复审 200 240
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 80
Design 具体设计 60 120
Coding 具体编码 1200 1500
Code Review 代码复审 100 300
Test 测试(自我测试,修改代码,提交修改) 0 0
Reporting 报告 180 240
Test Report 测试报告 30 30
Size Measurement 计算工作量 10 20
Size Measurement 事后总结, 并提出过程改进计划 30 30
合计 1990 2830

git仓库链接和代码规范链接

git仓库链接
代码规范链接

成品展示

1.主界面,展示论文,用户可在此点击


关键词图谱展示功能,点击关键词展示相关论文

2.登陆界面,用户在此进行登录

3.论文列表,用户可再次进行模糊搜索,删除和查看修改页面


查看页面:

删除页面:

修改页面:

4.图表分析

结对讨论过程描述

结对讨论截图:


描述:
刚看到这个题目的时候,我和我结对队友都觉得这是不可能完成的任务,因为上学期刚学过web课,精通的东西不是很多,甚至系统都很少写,然后我们用了一个晚上加一个早上的时间学习JSP等其他的框架,但是效果都不甚理想,所以思来想去,最后决定使用上学期刚学过的yii2.0框架,由于有框架的支持,所以论文的查找,删除,修改功能都比较好实现,但是对文章首页的搭建和关键词代码的实现就有比较大的问题,我们俩人改了bug无数次调试,主要查资料时从以前看的视频上学来的,然后还有功能分配的问题,我来实现图表分析,队友来实现首页和图表的增删改,最后时间实在不多,所以没来的及实现云服务器的部署和搭建,希望以后有机会实现。

设计实现过程

设计首页,论文列表页,论文分析页。首页可显示论文的基本信息(包括标题,论文内容,关键词等)点击论文标题可查看论文的详细内容。点击关键词可显示含有这个关键词的所有论文。关键词云可通过点击不同的关键词云显示含有这个关键词的论文列表。论文列表页,可对论文进行查看,修改,删除,模糊搜索。论文分析页展示了多年间、不同顶会的热词呈现热度走势。
功能结构图:

代码说明

GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],

            'title',
           // 'abstract:ntext',
            'typeandyear',
            'keywords',
            'releasetime',
            //'link',
            [
                'attribute' => '链接',
                'value' => function ($model) {
                    return Html::a($model->link, "{$model->link}", ['target' => '_blank']);
                },
                'format' => 'raw',
            ],
            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]);

创建gridview表在首页展示给用户论文搭建基础框架,利用dataprovider调取数据库所需的链接,实现点击即可查看论文,然后再用value实现链接可点击直接跳转

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);

    $this->load($params);

    if (!$this->validate()) {
      
        return $dataProvider;
    }

    
    $query->andFilterWhere(['like', 'title', $this->title])
        ->andFilterWhere(['like', 'abstract', $this->abstract])
        ->andFilterWhere(['like', 'typeandyear', $this->typeandyear])
        ->andFilterWhere(['like', 'keywords', $this->keywords])
        ->andFilterWhere(['like', 'releasetime', $this->releasetime])
        ->andFilterWhere(['like', 'link', $this->link]);

    return $dataProvider;

利用dataProvider提供数据,引用find方法,视线模糊搜索效果,利用andFilterWhere寻找所需的数据,这个方法是框架自带的查询方法,可直接提取出所想要的数据。

$this->title = '修改论文: ' . $model->title;
$this->params['breadcrumbs'][] = ['label' => '论文列表', 'url' => ['index']];
$this->params['breadcrumbs'][] = ['label' => '查看论文', 'url' => ['view', 'id' => $model->link]];
$this->params['breadcrumbs'][] = '修改论文';
?>
<div class="paper-update">

    <h1><?= Html::encode($this->title) ?></h1>

    <?= $this->render('_form', [
        'model' => $model,
    ]) ?>

</div>

文章修改模型类的主代码,可将改好的后的表单-form render回数据库,只要在表单中进行更改就好了,在上学期的web课程有学过类似的方法

public static function findKeywordWeights($limit=20)
    {
    	$keyword_size_level = 5;
    	 
    	$models=Keyword::find()->orderBy('frequency desc')->limit($limit)->all();
    	$total=Keyword::find()->limit($limit)->count();
    	 
    	$stepper=ceil($total/$keyword_size_level);
    	 
    	$keywords=array();
    	$counter=1;
    	 
    	if($total>0)
    	{
    		foreach ($models as $model)
    		{
    			$weight=ceil($counter/$stepper)+1;
    			$keywords[$model->name]=$weight;
    			$counter++;
    		}
    		ksort($keywords);
    	}
    	return $keywords;
    }

在数据库中查询关键词最热的十个单词,并将其做成图谱形式,在进行排序组合,同时将出现次数最多的关键词展示成最大

    public static function addKeywords($keywords)
    {
    	if(empty($keywords)) return ;
    	
    	foreach ($keywords as $name)
    	{
    		$aKeyword = Keyword::find()->where(['name'=>$name])->one();
    		$aKeywordCount = Keyword::find()->where(['name'=>$name])->count();
    		
    		if(!$aKeywordCount)
    		{
    			$keyword = new Keyword;
    			$keyword->name = $name;
    			$keyword->frequency = 1;
    			$keyword->save();
    		}
    		else 
    		{
    			$aKeyword->frequency += 1;
    			$aKeyword->save();
    		}
    	}
    }
    
    public static function removeKeywords($keywords)
    {
    	if(empty($keywords)) return ;
    	
    	foreach($keywords as $name)
    	{
    		$aKeyword = Keyword::find()->where(['name'=>$name])->one();
    		$aKeywordCount = Keyword::find()->where(['name'=>$name])->count();
    		
    		if($aKeywordCount)
    		{
    			if($aKeywordCount && $aKeyword->frequency<=1)
    			{
    				$aKeyword->delete();
    			}
    			else 
    			{
    				$aKeyword->frequency -= 1;
    				$aKeyword->save();
    			}
    		}
    	}
    }
    
    public static function updateFrequency($oldKeywords,$newKeywords)
    {
    	if(!empty($oldKeywords) || !empty($newKeywords))
    	{
    		$oldKeywordsArray = self::string2array($oldKeywords);
    		$newKeywordsArray = self::string2array($newKeywords);
    		
    		self::addKeywords(array_values(array_diff($newKeywordsArray,$oldKeywordsArray)));
    		self::removeKeywords(array_values(array_diff($oldKeywordsArray,$newKeywordsArray)));
    	}
	} 

再次通过连接数据库可实现新增一篇文章,修改一篇文章,删除一篇文章都会使得关键词的表格发生变化,利用aKeywordCount可进行数据库的增加修改和删除,

 $this->title = '登录';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-login">
    <h1><?= Html::encode($this->title) ?></h1>

    <p>请输入用户名和密码:</p>

    <div class="row">
        <div class="col-lg-5">
            <?php $form = ActiveForm::begin(['id' => 'login-form']); ?>

                <?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>

                <?= $form->field($model, 'password')->passwordInput() ?>

                <?= $form->field($model, 'rememberMe')->checkbox() ?>

                <div class="form-group">
                    <?= Html::submitButton('登录', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
                </div>

            <?php ActiveForm::end(); ?>
        </div>
    </div>
</div>

用户进行登陆功能,将输入的账户和密码传入与数据库对应,并将本来的登陆界面优化

<?php $form = ActiveForm::begin([
        'action' => ['index'],
        'method' => 'get',
    ]); ?>
 <?= $form->field($model, 'title') ?>

    <?= $form->field($model, 'abstract') ?>

    <?= $form->field($model, 'typeandyear') ?>

    <?= $form->field($model, 'keywords') ?>

    <?= $form->field($model, 'releasetime') ?>

    <?php // echo $form->field($model, 'link') ?>

    <div class="form-group">
        <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
    </div>

    <?php ActiveForm::end(); ?>

搜索框的实现利用active form方法来寻找其他所需要的搜索量


    <div class="carousel-inner">
        <div class="item active">
            <img src="http://5b0988e595225.cdn.sohucs.com/images/20190731/98a8e684a10240d4ba4be9c1cca522f8.jpeg" alt="First slide">
            <div class="carousel-caption">标题 1</div>
        </div>
        <div class="item">
            <img src="http://p4.itc.cn/q_70/images03/20200703/0cfcf8427e884ca99ed1f45f984a9d44.png" alt="Second slide">
            <div class="carousel-caption">标题 2</div>
        </div>
        <div class="item">
            <img src="https://img-blog.csdnimg.cn/img_convert/80b20f224cf3cd6300f106ea6e57c268.png" alt="Third slide">
            <div class="carousel-caption">标题 3</div>
        </div>
    </div>

这是首页轮播图的主要运用,运用了yii一个非常好用的插件

public static function addScript($view, $jsfile) {  
        $view->registerJsFile($jsfile, [AppAsset::className(), 'depends' => 'api\assets\AppAsset']);  
    }  
      
   //定义按需加载css方法,注意加载顺序在最后  
    public static function addCss($view, $cssfile) {  
        $view->registerCssFile($cssfile, [AppAsset::className(), 'depends' => '。、。
api\assets\AppAsset']);  
    }  

加上以上这行代码即可重新定义框架的JS文件

$this->title = $model->title;
$this->params['breadcrumbs'][] = ['label' => '论文列表', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="paper-view">

    <h1><?= Html::encode($this->title) ?></h1>

    <p>
        <?= Html::a('修改', ['update', 'id' => $model->link], ['class' => 'btn btn-primary']) ?>
        <?= Html::a('删除', ['delete', 'id' => $model->link], [
            'class' => 'btn btn-danger',
            'data' => [
                'confirm' => '您确定删除这篇论文吗?',
                'method' => 'post',
            ],
        ]) ?>
    </p>

    <?= DetailView::widget([
        'model' => $model,
        'attributes' => [
            'title',
            'abstract:ntext',
            'typeandyear',
            'keywords',
            'releasetime',
            'link',
        ],
        'template'=>'<tr><th style="width:120px;">{label}</th><td>{value}</td></tr>',
    ]) ?>

这是文章查看界面的代码,用户可借助detailview组件进行文章内容的查看,通过数据库提取文件即可

class KeywordsCloudWidget extends Widget
{
    public $keywords;

    public function init()
    {
        parent::init();
    }

    public function run()
    {
        $keywordString='';
        $fontStyle=array("6"=>"danger",
        "5"=>"info",
        "4"=>"warning",
        "3"=>"primary",
        "2"=>"success",
    );

    foreach ($this->keywords as $keyword=>$weight)
    {
        $url = Yii::$app->urlManager->createUrl(['site/index','PaperSearch[keywords]'=>$keyword]);
        $keywordString.='<a href="'.$url.'">'.
                ' <h'.$weight.' style="display:inline-block;"><span class="label label-'
                .$fontStyle[$weight].'">'.$keyword.'</span></h'.$weight.'></a>';
    }
    sleep(3);
    return $keywordString;
    }
}

调用标签云组件的代码,通过设置1 到5来展示不同出现次数的标签大小,数据库出现频率越高,标签云越大

class PaperController extends Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Lists all Paper models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new PaperSearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Displays a single Paper model.
     * @param string $id
     * @return mixed
     */
    public function actionView($id)
    {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new Paper model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $model = new Paper();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->link]);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Updates an existing Paper model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param string $id
     * @return mixed
     */
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->link]);
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Deletes an existing Paper model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param string $id
     * @return mixed
     */
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();

        return $this->redirect(['index']);
    }

  
    protected function findModel($id)
    {
        if (($model = Paper::findOne($id)) !== null) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }
}

这是整个文章的控制类,通过收集各种数据,在各个界面之间传递数据,传递ID值

心路历程和收获

221801408廖龙垲心路历程:
首先和上次一样心态崩溃了,就觉得这个课程是不是以为我们只有这门课,三个晚上有课,从7点到21.30,除了熬夜在写在改bug没有其他办法,周六还有团队合作项目,12.24分第一个回宿舍,博客还一堆要求,每一届都是这么过来每一届都难受,而且没技术支持成长极为有限,还不如改为一门技术课,然后结对过程就算做出来更多的也是疲惫感,和终于不用在被这东西压在心头的如释重负的感觉,收获的话,由于是自己学过的技术,就是对之前所学进行修改,然后学会了eCHART的引用,学会了轮播图控件的使用,就是开学初希望老师助教提供啥,啥都没,连资料都不给,这么多届过来连这个都没改进,就一年一年加大题目难度。效率极低!!!!!
221801408黄雕心路历程:
通过本次结对,让我对结对编程有了更加深刻的了解,也体会到了结对编程的优势和存在的问题。本次结对编程,虽然遇到了许多问题,通过自己查找资料解决了部分问题,更重要的是通过与结对伙伴的讨论,共同解决了其他大部分的问题。这让我更加体会到了结对对于编程开发所带来的方便。但是两个人共同编程,难免有意见不一致的时候,因此沟通各自的意见,以及讨论解决办法需要一定的时间。总之,本次结对编程虽然仍有许多的不足,但大体符合自己的预期。学会了使用github进行协作开发,提升了php编程开发经验。希望自己在之后的结对编程能学到更多东西。

评价结对队友

龙垲评价:我的队友还是非常认真的,可以一起熬夜改代码,经常崩溃也还是会认真去完成,最后圆满实现我们互相分配的任务,很多时候一个人坚持不下去,俩个人就能坚持下去了,就算有时候俩个人想的不一样也会坚持沟通,我觉得这就是结对合作比较重要的部分
黄雕评价:编程开发效率很高,能及时提出编程过程中存在的问题,并与我积极讨论。我在编程开发中遇到困难,也能提出自己的见解,并帮助我共同解决。

posted @ 2021-03-30 09:48  冷夜梦  阅读(152)  评论(4编辑  收藏  举报