结对作业二

作业基本信息

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

一、 作业链接

网站链接

论文爬取站

开放账户:

用户名 密码
admin admin

git仓库链接

PairProject

代码规范链接

代码规范

二、 成品展示

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-20 11:09  满天都是小欣欣~  阅读(65)  评论(0编辑  收藏  举报