结对作业二

作业基本信息

这个作业属于哪个课程 2021春软件工程实践 | W班 (福州大学)
这个作业要求在哪里 结对第二次作业——顶会热词统计的实现
结对学号 221801119 | 221801134
这个作业的目标 1. 学会搭建web网站
2. 深入感受结对编程
3. 学习前端知识
4. 学会部署网站到云服务器
其他参考文献 CSDN、博客园、简书、git
Github仓库地址 PairProject

一、 作业链接

网站链接

论文爬取站

开放账户:

用户名 密码
admin admin

git仓库链接

PairProject

代码规范链接

代码规范

二、PSP表格

Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
计划 10 10
估计这个任务需要多少时间 10 10
开发 4400 4710
原型复审 10 10
需求分析 (包括学习新技术) 60 120
生成设计文档 40 30
设计复审 10 10
代码规范 30 20
具体设计 30 40
具体编码 4000 4200
代码复审 40 40
网站部署 30 60
测试 150 180
报告 60 90
测试报告 15 20
计算工作量 15 10
事后总结, 并提出过程改进计划 30 60
合计 4470 4810

三、 成品展示

1. 首页+登录注册+退出登录

2. 论文管理界面展示,显示论文标题、编号、会议、时间、五个关键词和摘要,以及本地论文的top10关键词

3. 论文导入界面展示,导入论文、关键词跳转功能

4. 动态分析界面展示,关键词跳转功能

5. 搜索功能,分别在本地和论文库按标题、编号、关键词和不限来搜索

6. 在论文管理界面和搜索界面实现关键词跳转功能(收藏夹界面、查看界面也可以实现关键词跳转)

7. 在论文管理界面删除论文,搜索界面添加论文

8. 在论文管理界面收藏和取消收藏论文,并给论文添加和修改备注(搜索界面和收藏夹界面也可实现相应的功能)

9. 收藏夹界面展示,查看收藏夹内的论文,添加收藏夹、移动论文至其他收藏夹功能

10. 论文查看界面展示,从原文链接导入论文的正文展示在页面上(由于论文网站访问较慢,加载原文需要等待5s左右)

11. 在论文查看界面还有添加学习笔记的功能(当论文没有添加到本地时没有该功能)

四、 结对讨论过程描述

结对过程总述

刚开始拿到题目的时候,因为都没有开发Web的经验,无从入手,有想到过使用现下流行的vue框架和spring框架,但考虑到学习时间有限就放弃了。又想到上学期web实践课有学过Html+css+js+php,于是就想着还是从最简单的开始,原生开发,没有用到什么框架。

刚开始的两天是最辛苦的,因为什么都不懂,在编程方式的选择上花费了一些时间,后面几天就顺利了起来,比如今天小欣同学完成了论文列表的UI设计,小蕾同学完成了动态分析图,明天完成对数据的爬取和导入……这次结对的分工也很明确,两人同步敲代码,当小欣同学设计论文管理等UI的时候,小蕾同学进行动态图表的设计和导入,并且包揽了服务器的部署和数据库导入的工作,为我们制定代码规范,分析项目需求,小欣同学则负责网站的逻辑跳转以及后端的操作,并在已有功能的基础上进行扩展。

讨论细节详述

  1. 前端开发由于之前有编写过静态的网页,所以还是很好上手的,但没有做过后端的开发,所以在后端的实现上费了一些时间,特别是前后端交互的实现,因为原生开发的局限性,在实现上我们要先用js提取html元素的数据,再用js传值给php,这个过程很容易出错,我们也试图使用过ajax来传递,但一直无法实现。最终还是用window.href来传值,虽然过程有点繁琐,但理解起来并不难,诟病就是每次都要刷新一下界面。

  2. 第一次接触到爬取的知识,两个人都一头雾水,各自用PHP和JAVA语言在网上查找相应的爬取的资料,我们学会了通过分析网站的HTML元素,使用正则表达式获取到需要的信息。

  3. 初次使用GitHub进行合作,刚开始建立了分支,但小欣同学因为操作失误,不知怎么切换到了main主分支下,并且不知不觉中已经在main下提交了5次,直到删除项目才后知后觉切错了分支,也是闹了个乌龙。(小欣gitHub使用不顺手,出现了问题)

  1. 由于要用到php的开发环境,于是我们都安装了wamp环境,但由于wamp里的phpmyadmin和本地的mysql有冲突,小蕾同学wamp的数据库一直是无法运行的,但好在可以使用navicat进行数据库管理,并且navicat导出的sql文件phpmyadmin也可以导入,解决了这个问题。(在wamp使用和数据库使用navicat还是phpMyadmin出现了点问题)

  1. 互相找bug,修改细节

五、 设计实现过程

功能结构图

功能结构图

过程描述

1. 首页

包含注册、登录等功能,用户登录后用SESSION来保存用户id,可随时退出登录。

2. 论文导入

实现单篇导入和批量导入论文的功能,论文导入后,将跳转至论文管理界面。然而,在实现过程中,由于觉得页面上只有一个搜索框实在过于单调,于是在搜索框的上方放置了一个词云。词云是依据网站搜集的论文的关键词定制的,出现频率高的词在词云中占比更大,这部分依靠查询数据库生成关键词数组实现。同时,用户点击关键词可跳转至相关论文(类似于搜索关键词的功能)。
其中导入文件的功能,先用JS解析文件的内容,再转换内容传递给PHP进行搜索,这里按换行符来分割每一个论文标题,再对每个标题在数据库进行搜索内容,当论文存在且未加入个人论文库,则添加至论文库。

3. 论文管理

该界面显示了用户的个人论文库。界面三分之二是论文列表,对于每一篇论文,依次显示论文标题、编号、会议、发布时间、五个关键词和摘要,并放置备注、收藏、查看和删除的操作按钮。界面三分之一显示是搜索框和本地论文库的top10关键词。
其中查看论文功能,是通过分析原文链接的HTML标签来获取论文的正文,显示到界面上(但由于访问原链接较慢,正文会加载5-10s)。在本地论文的论文查看界面,还新增添加笔记和查看学习笔记的功能。
搜索操作,每次向PHP传递搜索渠道、搜索方式和搜索内容参数进行搜索,同时还会显示搜索结果条数。

4. 收藏夹

用户可以新增收藏夹、移动论文进入另一收藏夹,这里移动论文需要向PHP传递论文ID、原收藏夹名和目标收藏夹名以及用户id参数。用户可以查看每一个收藏夹内对应的论文,这里我们设置每个用户都有一个默认收藏夹,当用户收藏论文时自动将论文收藏至默认收藏夹。

5. 动态分析

设计时将网页分为左、右两侧,左侧显示历年热词,右侧显示关键词饼图,这两个图表均引用highcharts的模板。由于左侧的条形图只能显示一年的热词词频,于是在图表上增加了三个年份的按钮,供用户切换历年视图。右侧的关键词饼图也添加了点击事件,用户点击关键词区块后,可跳转至论文管理界面,查看该关键词相关的论文。不过导入数据后,发现关键词长度过长,会挤压图表的宽度,使之变得不美观,于是最终改用上下排版。

六、 代码说明

  1. 判断用户是否登录

    //对用户的登录状态进行异常处理
    if(!isset($_SESSION["userid"])){
    	echo '<script>alert("请先登录!");window.location.href="../view/login.php";</script>';
    }
    //用SESSION获取用户ID,并从数据库获取用户名
    $userid=$_SESSION["userid"];
    $sql = "select * from user where userid = '$userid' ";
    $result = $conn->query($sql);
    $number = mysqli_num_rows($result);
    $row=$result ->fetch_assoc();
    echo $row["username"];
    
    //用户退出登录处理,使用注销SESSION的方法
    <?php
        session_start();
        if(isset($_SESSION['userid'])) {
            unset($_SESSION['userid']);
        }
        echo '  <script>
            alert("退出登录成功!");
            window.location.href="../index.php";
            </script>';
    ?>
    
  2. 论文导入
    论文导入时的内部逻辑。

    //查看文件
    function findFile(){
        var inputObj = document.createElement('input');
        inputObj.setAttribute('id','file');
        inputObj.setAttribute('type','file');
        inputObj.setAttribute("style",'visibility:hidden');
        document.body.appendChild(inputObj);
        inputObj.click();
        inputObj.onchange=readFile;
    }
    //读取文件
    function readFile() {
    	var objFile = document.getElementById('file');
    	var files = objFile.files;	
    	var reader = new FileReader();
    	var userid='<?php echo $userid;?>';
    	reader.readAsText(files[0], "UTF-8");
    	reader.onload = function(e){
      		var fstr = e.target.result;
    		var str=fstr.replace(/\n/g,"%0a");
      		window.location.href="../form/importPaper.php? str="+str+"&userid="+userid;
    	}
    }
    
  3. 为动态分析图表获取热门关键词排行
    从数据库论文表逐行读取论文关键词并保存,然后遍历关键词结果,将关键词存储至一个数组中,该数组的索引为关键词,值为关键词出现次数,最后按值排序。由此便得到一个热门关键词数组。

     function getTopKeys($sql, $conn, $nums) {
         $result = $conn->query($sql);
         $result_array = array();
         $key_array = array();
         if ($result->num_rows > 0) {
             while($row = $result->fetch_assoc()) {
                 $result_array[] = $row["key1"]; 
                 $result_array[] = $row["key2"];
                 $result_array[] = $row["key3"];
                 $result_array[] = $row["key4"];
                 $result_array[] = $row["key5"];
             }
         }
         foreach($result_array as $value){
             if(!empty($value)){
                 $value = ucfirst($value);
                 if(array_key_exists($value, $key_array)){
                     $key_array[$value] += 1;
                 }
                 else{
                     $key_array[$value] = 1;
                 }
             }
         }
         arsort($key_array);
         return array_slice($key_array, 0, $nums);  //$nums指定获取热度前几的关键词
     }
     //调用函数
     $top_ten_key = getTopKeys("SELECT key1, key2, key3, key4, key5 FROM paper", $conn, 10);
     $top_key_array = array_keys($top_ten_key);
     $top_value_array = array_values($top_ten_key);
    

    然后动态分析图表(条形图)用该数组来初始化x轴的类别:

    xAxis: {
    		categories: json_encode(array_slice($top_key_array, 0, 5)),
    		//……
     },
    

    同样,在论文导入界面生成词云时,也用到了这个热门关键词数组:

    series: [{
    		data:".json_encode($arr).",
         //……
     }],
    
  4. 搜索功能

    //进行搜索的时候有两种传递方式,一种是用表单POST另一种是用window.location.href,这两种接受数据的方式是不一样的,于是要对数据进行判断
     if(isset($_GET['searchName'])){
         $searchname=$_GET['searchName'];
         $searchtype=$_GET["searchSelect"];
         if(isset($_GET['searching']))
             $searching=$_GET['searching'];
         else
             $searching=2;
     }
     else if(isset($_POST['searchName'])){
         $searchname=$_POST['searchName'];
         $searchtype=$_POST["searchSelect"];
         $searching=$_POST["searching"];
     }
     //搜索方式判断,由于有四种搜索方式,于是要进行判断,并分别进行数据库搜索
     if($searchtype==1){
         $sql="select * from paper where title like '%$searchname%'  " ;
     }
     else if($searchtype==2){
         $sql="select * from paper where pid like '%$searchname%' ";
     }
     else if($searchtype==3){
         $sql="select * from paper where (key1 like '%$searchname%' or key2 like '%$searchname%' or key3 like '%$searchname%' or key4 like '%$searchname%' or key5 like '%$searchname%')  ";
     }
     else{
         $sql="select * from paper where (title like '%$searchname%' or pid like '%$searchname%' or key1 like '%$searchname%' or key2 like '%$searchname%' or key3 like '%$searchname%' or key4 like '%$searchname%' or key5 like '%$searchname%')  ";
     }\
    
    //搜索完毕,使用Js填充搜索结果条数
    <script type="text/javascript">
        var n='<?php echo $resultNum;?>';
        document.getElementById("resultNum").innerHTML=n;
    </script>
    
    //搜索界面收藏论文时需要传递7个参数,其中3个参数是返回搜索界面需要用到的 		
    function addCollect(e){
        window.event.returnValue=false;
        var pid=e.id;
        var userid='<?php echo $userid;?>';
        var searchname='<?php echo $searchname;?>';
        var searchtype='<?php echo $searchtype;?>';
        var searching='<?php echo $searching;?>';
        window.location.href="../form/collected.php? pid="+pid+"&userid="+userid+"&c=1"+"&view=2"+"&searching="+searching+"&searchtype="+searchtype+"&searchname="+searchname;
    }
    
  5. 由于a标签会导致window.location.href跳转无效,于是在代码中加入

    window.event.returnValue=false;                    
    if (window.event.preventDefault) 
        window.event.preventDefault(); 
    
  6. 论文列表的显示,在Html中嵌入php数据库代码后,用echo''输出

    <h3 >'.$row2["title"].'</h3>
    <div class="blog-meta big-meta">
        <small>'.$pid.'</small>
        <small>'.$row2["meeting"].' '.$row2["year"].'</small>
        <small>'.$row2["ptime"].'</small>
    </div>
    <div class="blog-meta big-meta">
        <small><a href="'.$row2["link"].'" title="" target="_blank"><i class="fa fa-eye"></i>原文链接:'.$row2["link"].'</a></small>
    </div>
    <div class="blog-title-area">
        <div class="tag-cloud-single">
            <a href="" onclick="keyButton(this)" id="'.$row2["key1"].'"><span style="background-color:#FC9D9A">'.$row2["key1"].'</span></a>
            <a href="" onclick="keyButton(this)" id="'.$row2["key2"].'"><span style="background-color:#ffacac">'.$row2["key2"].'</span></a>
            <a href="" onclick="keyButton(this)" id="'.$row2["key3"].'"><span style="background-color:#FF9999">'.$row2["key3"].'</span></a>
            <a href="" onclick="keyButton(this)" id="'.$row2["key4"].'"><span style="background-color:#ffacac">'.$row2["key4"].'</span></a>
            <a href="" onclick="keyButton(this)" id="'.$row2["key5"].'"><span style="background-color:#FC9D9A">'.$row2["key5"].'</span></a>
        </div>
    </div>
    <div class="blog-content" >  
        <div class="pp" >
            <p>'.$row2["summary"].'</p>
        </div><!-- end pp -->
    </div>
    
  7. 用php爬取原文链接中的正文内容,用到了正则表达式

    <?php 
        $text=file_get_contents($row2["link"]);
        preg_match_all('/<section id="Sec([0-9])*"(.*?)>(.*?)<\/section>/is', $text, $match);
        for($i=0;$i<count($match[0]);$i++){
            print_r($match[0][$i]);
        }  
    ?>    
    
  8. 收藏夹功能

    //在收藏夹界面,用PHP获取当前选中的收藏夹,使用js来使当前收藏夹样式变化
    <script type="text/javascript">
    	var f='<?php echo $folder;?>';
    	document.getElementById(f).style.color="white";
    	document.getElementById(f).style.background="#FFCCCC";
    </script>	
    
    //移动收藏夹这个功能,不仅要获取元素相对于的论文id还要获取目标收藏夹
    function moveButton(e){
        window.event.returnValue=false;                    
        if (window.event.preventDefault) 
    	    window.event.preventDefault();
        var pid=e.id;
        var userid='<?php echo $userid;?>';
        var f=e.childNodes.item(3).id;
        window.location.href="../form/updateFolder.php? folder="+f+"&userid="+userid+"&pid="+pid;
    }
    
  9. 实现数据库收藏夹的添加和删除,用GET获取JS传递的数据,并判断是添加还是删除操作

    <?php
        $pid=$_GET['pid'];
        $userid=$_GET['userid'];
        $c=$_GET['c'];
        $view=$_GET['view'];
        $conn = new mysqli('localhost','root','','paperdb');
        $conn->query("SET NAMES utf8");
        if($c==0){
            $sql = "update userPaper set collect='$c' where pid = '$pid' and userid='$userid' ";
            $sql2 = "update userPaper set folder='' where pid = '$pid' and userid='$userid' ";
        }
        else{
            $sql = "update userPaper set collect='$c'  where pid = '$pid' and userid='$userid' ";
            $sql2 = "update userPaper set folder='默认收藏夹' where pid = '$pid' and userid='$userid' ";
        }
        $conn->query($sql);
        $conn->query($sql2);
        if($c==0)
            echo '<script>alert("取消收藏成功!");</script>';
        else
            echo '<script>alert("已添加到默认收藏夹!");</script>';
        if($view==1)
            echo '<script>window.location.href="../view/manage.php";</script>';
        else if($view==3)
            echo '<script>window.location.href="../view/collect.php";</script>';
        else{
            $searchname=$_GET['searchname'];
            $searchtype=$_GET['searchtype'];
            $searching=$_GET['searching'];
        }
    ?>
    
    <script type="text/javascript">
        var userid='<?php echo $userid;?>';
        var searchname='<?php echo $searchname;?>';
        var searchtype='<?php echo $searchtype;?>';
        var searching='<?php echo $searching;?>';
        window.location.href="../view/search.php?searchName="+searchname+"&searching="+searching+"&searchSelect="+
    searchtype+"&userid="+userid;
    </script>
    
    
  10. 分享网站,复制到剪切板功能,由于当前只有IE浏览器支持该功能,因此加上了对IE浏览器的判断

    if (!!window.ActiveXObject || "ActiveXObject" in window){
    	window.clipboardData.setData("text",'http://222.77.0.199:8090/');
    	alert("已复制网址http://222.77.0.199:8090/至剪切板");
    }
    else{
    	alert("当前浏览器暂不支持改功能!");
    }
    
  11. 获取本地论文

    <?php 
    	$conn = new mysqli('localhost','root','','paperdb');
    	$conn->query("SET NAMES utf8");
    	$sql="select * from paper ";
    	$result = $conn->query($sql);
    	$sql = "select * from userPaper where userid = '$userid' ";
    	$res = $conn->query($sql);
    	$resultNum=0;
    	if($res->num_rows >0){
    	    $row=$res->fetch_assoc();
    	    if( $result->num_rows >0 ){
    	        while( $row2=$result->fetch_assoc()){
                    $pid=$row2["pid"];        
    	            if($pid==$row["pid"]){
                        $resultNum++;
    	                echo '
    	                        <div class="paper">
                                <div class="page-wrapper">
                                <div class="blog-title-area" >
                            ';
    	               if($row["remarks"]!=""){
    	                   echo '<span style="color:#FE4365">['.$row["remarks"].']</span>';
    	               }
    	               else{
    	                   echo '<span style="color:#C0C0C0">[点击添加备注]</span>';
    	               }
    	               echo '
    	                    <a href="" onclick="remarkButton(this)" id="'.$pid.'"></a>
                            <a href=""  style="float:right" onclick="deleteButton(this)" id="'.$pid.'" ></a>    
                            <a href=""  style="float:right;" onclick="checkButton(this)" id="'.$pid.'"></a>
                            ';
    	               if($row["collect"]==0){
    	                   echo '
                            <a href="" style="float:right" onclick="addCollect(this)" id="'.$pid.'"></a>';
    	               }
    	               else{
    	                   echo'
                            <a href="" style="float:right" onclick="deleteCollect(this)" id="'.$pid.'"></a>';
    	               }
    	               echo'
                                <br/><h3>'.$row2["title"].'</h3>
                                <div class="blog-meta big-meta">
                                    <small>'.$pid.'</small>
                                    <small>'.$row2["meeting"].' '.$row2["year"].'</small>
                                    <small>'.$row2["ptime"].'</small>
                                </div>
                                <div class="blog-meta big-meta">
                                    <small>
                                        <a href="'.$row2["link"].'" title="" target="_blank">
                                            <i class="fa fa-eye"></i>原文链接:'.$row2["link"].'
                                        </a>
                                    </small>
                                </div>
                                <div class="blog-title-area">
                                    <div class="tag-cloud-single">
                                        <a href="" onclick="keyButton(this)" id="'.$row2["key1"].'"><span style="background-color:#FC9D9A">'.$row2["key1"].'</span></a>
                                        <a href="" onclick="keyButton(this)" id="'.$row2["key2"].'"><span style="background-color:#ffacac">'.$row2["key2"].'</span></a>
                                        <a href="" onclick="keyButton(this)" id="'.$row2["key3"].'"><span style="background-color:#FF9999">'.$row2["key3"].'</span></a>
                                        <a href="" onclick="keyButton(this)" id="'.$row2["key4"].'"><span style="background-color:#ffacac">'.$row2["key4"].'</span></a>
                                        <a href="" onclick="keyButton(this)" id="'.$row2["key5"].'"><span style="background-color:#FC9D9A">'.$row2["key5"].'</span></a>
                                    </div>
                                </div>
                            </div>                          
                            <div class="blog-content" >
                                <div class="pp" >
                                    <p>'.$row2["summary"].'</p>
                                </div><!-- end pp -->
                            </div>
                        </div>
                    </div>
                        ';  
    	                if(!($row=$res->fetch_assoc()))
    	                   break;
    	           }
    	       }
    	   }
        }
    ?>
    

七、 心路历程和收获

小欣同学(221801134)

这次结对编程过程中,连续一周每天除了吃饭看剧上课睡觉剩余的时间就是敲代码,虽然过程很艰辛但是过的很充实,也收获了很多,熟练使用了Web的原生开发,在之后的项目中,我会更进一步使用框架前后端分离来进行开发。同时也学会使用了用GitHub进行开发合作,虽然每次push和pull都会遇到超时无法连接甚至要弄个半小时才能push上去。这次使用php语言尝试爬取了论文网站的相关信息,虽然中途出现了不少的问题,但还是收获满满。

小蕾同学(221801119)

刚接到一个新项目的时有些焦虑,但在与结对伙伴一起编程的过程中,焦虑得到了缓解。写代码的过程中,总会碰到一些一时无法解决的报错,或是意想不到的状况,虽然遇到这些困难时会很烦恼,但在尝试解决问题的过程中,也收获了很多知识。在这次项目中,学会了如何在云服务器上搭建环境、部署网,学会了如何通过Github协作、在Github上发布版本,更是提升了编程能力。总之就是,即使度过了许多头疼的夜晚,但网站成功部署并能从外部访问的那一刻真的好开心。

八、 队友评价

小欣同学(221801134)

小蕾同学很细心,对比我马虎的性格我们形成了互补,在功能的测试上她会找到BUG给我反馈。虽然她慢悠悠的性子常常让我很担心我们项目的进度,但她很努力也很积极做配置服务器、动态分析和数据库维护等多方面复杂的工作,让我们的项目进展得很顺利。

小蕾同学(221801119)

小欣同学很有干劲,每天都花很多时间来写代码、完善功能,不时会提出新的想法,让我很有动力,但是我们的步调不太一致,这导致我们初期需要一些时间来协调与沟通。不过互相适应之后,我们找到了两人都可以接受的合作模式。这次很高兴能跟小欣同学合作。

posted @ 2021-03-29 17:27  霍格沃茨荣誉学生  阅读(373)  评论(11编辑  收藏  举报