结对作业二

结对第二次作业——顶会热词统计的实现

作业基本信息

这个作业属于哪个课程 2021春软件工程实践|S班 (福州大学)
这个作业要求在哪里 结对第二次作业
团队成员 031801124&221801126
这个作业的目标 顶会热词统计的实现
其他参考文献 CSDN , GitHub

基础功能实现

总览

功能1:对已爬取的论文列表进行操作

  • 可对论文列表进行删除

    实现如下:

  • 可对论文列表进行查询详细信息(支持模糊查询,查询结果的展示、排序等功能可自行设计)

    实现如下:(支持模糊查询,查询结果的展示、排序等功能)
    全局搜索

    全字匹配搜索

    模糊搜索

功能2:分析已爬取到的论文信息,提取top10个热门领域或热门研究方向

  • 形成如关键词图谱之类直观的查看方式,点击某个关键词可展现相关的论文;

使用echart词云实现

  • 可对多年间、不同顶会的热词呈现热度走势对比,以动图的形式呈现(这里将范畴限定在计算机视觉的三大顶会CVPR、ICCV、ECCV内)

不同会议的多年论文趋势展示

我们还实现了对显示的图表的保存

附加功能

功能3:获取待爬取论文列表及论文信息爬取

通过论文列表,爬取论文的摘要、关键词、原文链接;

  • 数据来源网站:CVPR、ICCV、ECCV
  • 至少爬取三年、三大顶会各300篇论文
  • 可编写爬虫代码实现,也可使用爬虫工具(如八爪鱼)爬取

实现:使用八爪鱼爬虫工具实现,速度很慢,爬了很久...

ICCV爬取后的数据库,大于300条记录,满足要求

ECCV爬取后的数据库,大于300条记录,满足要求

CVPR爬取后的数据库,大于300条记录,满足要求

项目部署

本次项目需要部署到云服务器上,并且在博客中给出链接

项目服务器连接

编码要求

github使用

  1. Fork下面仓库,然后在根目录中新建一个以学号1&学号2(两位结对成员的学号)命名的文件夹,并至少进行20次以上的commit修改,两人至少分别提交10次以上,commit记录应该符合项目实情,如果虚构会被扣去所有分数。仓库目录结构没有硬性要求,但要保证可以依靠此仓库提供的代码来构建项目。
    https://github.com/kofyou/PairProject

  2. 对于非仓库要求的代码,如编译器生成的项目文件、输出文件、class、jar包、exe等,应该使用.gitignore进行忽略,并确保不会提交到github上。

  1. 为自己的仓库编写README.md,内容包括,作业链接、结对学号、项目介绍。

    README.md

  2. 在这次编程合作中学习使用Git分支、Release发布及其他高级功能。建立一条dev分支,让你的队友和你在dev分支上开发,开发结束后再合并到main分支。在基本功能开发完成后发布release包,标注版本为1.0.0,后边完成更多功能可以继续发布新的release包。

  3. 在完成项目后,deadline之前,请正确发起一个Pull Requet ,并确保自己的代码最终成功签入。(如果成功签入会在原始项目主页看到自己学号为名的文件夹)

代码规范制定

这一次作业仍然需要编写一份codestyle.md作为代码规范,但是要求该代码规范来自于主流的官方规范或者大公司推荐的规范,并在代码规范顶部标注来源。

codestyle.md

技术和框架

使用基于Web来开发,使用Web框架,如JSP、Servlet、等系列


博客撰写要求

PSP表格:

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 100 130
•Estimate •估计这个任务需要多少时间 1200 1310
Development 开发 60 70
•Analysis •需求分析 (包括学习新技术) 120 310
•Design Spec •生成设计文档 20 40
•Design Review •设计复审 20 50
•Coding Standard •代码规范(为目前的开发制定合适的规范) 30 60
•Design •具体设计 60 90
•Coding •具体编码 240 410
•Code Review •代码复审 60 130
•Test •测试(自我测试,修改代码,提交修改) 20 40
Reporting 报告 100 160
•Test Repor •测试报告 20 45
•Size Measurement •计算工作量 20 40
•Postmortem & Process Improvement Plan •事后总结, 并提出过程改进计划 60 110
合计 2130 2880

Github仓库地址

项目地址,挂了请私信我,谢谢各位老师和助教

云服务器的访问链接

服务器链接,挂了请私信我,谢谢各位老师和助教

展示你的成品

结对讨论过程描述

刚拿到题目回顾了一下结对作业一的顶会热词统计原型设计

遇到的问题:对题目的实现的效果不是很清晰,怕达不到第一次原型设计的作业呈现的效果;编程上,不知道从何下手,对相关技术不是很了解,使用什么技术和框架?使用什么开发工具?以及GitHub的使用还不是很熟练,再一个就是结对编程的经验不足,可能存在分工等问题(虽然好像没有?)

解决的方法:对第一次原型设计的作业实现在进行需求分析和设计,优化模型实践;技术上使用刚刚在学习的JavaEE相关知识进行开发,在CSDN、b站、博客园等进行servlet+jsp等相关技术学习,使用IDEA配合GitHub开发。实现了良好的效果。

查找的资料和过程:

我们在CSDN、b站、博客园等进行servlet+jsp等相关技术学习。相关🔗如下:

https://space.bilibili.com/19789508?spm_id_from=333.788.b_765f7570696e666f.1

https://www.bilibili.com/video/BV1uv411q7i3

https://blog.csdn.net/weixin_44100514/article/details/86408840

以及周筠编辑提供的学习榜样

https://www.cnblogs.com/ZCplayground/p/6539235.html

https://www.cnblogs.com/wenhongyu/archive/2017/12/06/7992028.html

结对讨论过程截图

代码说明

特别说明:本项目为个人学习用途,非商业用途,可能存在使用部分网络代码,或模块化代码块以及其他已存在的代码。对于重复使用的代码,我们不做任何商业用途,仅仅作为学习目的、交流、模仿、借鉴,没有任何抄袭等其他意图,如果您不希望您的代码出现在我们的程序内,请您联系我们删除,谢谢您的理解与支持。

1.SearchServlet用post方法处理主页的搜索(附加换页功能的后端处理)和详情页的删除。dopost方法套用模板来做。queryPapers用req传来的参数来判断现在第几页以及论文的关键词来查询。
@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String type = req.getParameter("type");
        switch (type) {
            case "1": // 保存

                break;
            case "2": // 编辑

                break;
            case "3": // 删除
                deletePaper(req, resp);
                break;
            default: // 查询
                queryPapers(req, resp);
        }
    }
	
	public void queryPapers(HttpServletRequest req, HttpServletResponse resp) {
        try {
            PaperService paperService=new PaperServiceImpl();
            Paper tempPaper=new Paper();
            tempPaper.setPaperTitle(req.getParameter("pTitle"));
            tempPaper.setPaperKeyword(req.getParameter("pKeyword"));
            tempPaper.setPaperReleasetime(req.getParameter("PaperReleasetime"));
            String pageNum = req.getParameter("pageNum");
            String changeNum = req.getParameter("changeNum");
            // pl每页显示的记录行数, pn当前页码,cn(上一页、下一页、查询),tn总的记录数
            int pl = 10, pn = 1, cn = 0, tn = paperService.queryNumber(tempPaper);
            // tp总的页数
            int tp = tn / 10 + (tn % 10 == 0 ? 0 : 1);
            // 当根据查询条件查询结果为空时,总页数默认为1页
            if (tp == 0) {
                tp = 1;
            }
            if (pageNum != null && !"".equals(pageNum)) {
                pn = Integer.parseInt(pageNum);
            }
            if (changeNum != null && !"".equals(changeNum)) {
                cn = Integer.parseInt(changeNum);
            }

            if (!(pn == 1 && cn == -1) && !(pn == tp && cn == 1)) {
                pn = pn + cn;
            }

            if (pn > tp) {
                pn = tp;
            }

            List<Paper> list = paperService.queryPapers(tempPaper, pn, pl);
            req.setAttribute("paper", tempPaper);
            req.setAttribute("pageNum", pn);
            req.setAttribute("totalPageNum", tp);
            req.setAttribute("totalNum", tn);
            req.setAttribute("paperList2", list);
            req.getRequestDispatcher("paperList.jsp").forward(req, resp);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    int deletePaper(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String Link=req.getParameter("pLink");
        PaperService paperService=new PaperServiceImpl();
        System.out.println(paperService.deletePaper(Link));
        req.getRequestDispatcher("paperList.jsp").forward(req, resp);
        return 0;
    }
2.用get方法处理词云功能中点击单词传给服务器的url并实现搜索。由于词云只能传网页地址过来故实现doget,逻辑上与dopost差不多
@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try
        {
        PaperService paperService=new PaperServiceImpl();
        Paper tempPaper=new Paper();
/*        tempPaper.setPaperTitle(req.getParameter("pTitle"));*/
            String keyword=new String(req.getParameter("name").getBytes("ISO8859-1"),"UTF-8");
        tempPaper.setPaperKeyword(keyword);
/*        tempPaper.setPaperReleasetime(req.getParameter("PaperReleasetime"));*/
        String pageNum = "1";
        String changeNum = "0";
        // pl每页显示的记录行数, pn当前页码,cn(上一页、下一页、查询),tn总的记录数
        int pl = 10, pn = 1, cn = 0, tn = paperService.queryNumber(tempPaper);
        // tp总的页数
        int tp = tn / 10 + (tn % 10 == 0 ? 0 : 1);
        // 当根据查询条件查询结果为空时,总页数默认为1页
        if (tp == 0) {
            tp = 1;
        }
        if (pageNum != null && !"".equals(pageNum)) {
            pn = Integer.parseInt(pageNum);
        }
        if (changeNum != null && !"".equals(changeNum)) {
            cn = Integer.parseInt(changeNum);
        }

        if (!(pn == 1 && cn == -1) && !(pn == tp && cn == 1)) {
            pn = pn + cn;
        }

        if (pn > tp) {
            pn = tp;
        }

        List<Paper> list = paperService.queryPapers(tempPaper, pn, pl);
        req.setAttribute("paper", tempPaper);
        req.setAttribute("pageNum", pn);
        req.setAttribute("totalPageNum", tp);
        req.setAttribute("totalNum", tn);
        req.setAttribute("paperList2", list);
        req.getRequestDispatcher("paperList.jsp").forward(req, resp);
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    } catch (ServletException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    }
3.搜索(附加换页功能)与删除的jsp页面 用表单来post,遍历论文列表用le表达式。
<div id="divcss5">
<form method="post" id="queryForm" action="<%=path%>/SearchServlet">
    <input  type="text" name="pTitle" value="${paper.paperTitle}" placeholder="论文标题"/><br><br>
    <input  type="text" name="pKeyword" value="${paper.paperKeyword}" placeholder="论文关键词"/><br>
    <input type="hidden" name="pLink" value="${paper.paperLink}" placeholder="论文链接"/>
    <input type="hidden" name="type" value="0" />
    <input type="hidden" name="pageNum" value="${pageNum}" />
    <input type="hidden" id="changeNum" name="changeNum" value="" />
    <button  onclick="changePage(0);" id="btnSearch">查 询</button>
</form>
</div>
<table border="1">
    <tr>
        <td>序号</td>
        <td>论文标题</td>
        <td>论文会议</td>
        <td>论文摘要</td>
        <td>关键词</td>
        <td>论文时间</td>
        <td>论文链接</td>
        <td>操作</td>
    </tr>
    <c:forEach items="${paperList2}" var="l" varStatus="vs">
        <tr>
            <td>${vs.index + 1}</td>
            <td>${l.getPaperTitle()}</td>
            <td>${l.getPaperTypeYear()}</td>
            <td style="font-size:5pt;width: 400px">${l.getPaperAbstract()}</td>
            <td>${l.getPaperKeyword()}</td>
            <td>${l.getPaperReleasetime()}</td>
            <td>${l.getPaperLink()}</td>
            <td>
                <%--<button  type="button" onclick="">编 辑</button>--%>
                <%--<button type="button" onclick="deletePaper(l.getPaperLink())">删 除</button>--%>
                <form method="post" id="deleteForm" action="<%=path%>/SearchServlet">
                    <input type="hidden" name="pLink" value="${l.getPaperLink()}"/>
                    <input type="hidden" name="type" value="3" />
                    <input type="hidden" name="pageNum" value="${pageNum}" />
                    <input type="hidden"  name="changeNum" value="" />
                    <button  onclick="deletePaper(${l.getPaperLink()});">删除</button>
                </form>
            </td>
        </tr>

    </c:forEach>
</table>
<button type="button" onclick="changePage(-1)">上一页</button>
<button type="button" onclick="changePage(1)">下一页</button>

第 ${pageNum}页 共${totalPageNum} 页 ,共 ${totalNum} 条记录
</body>
</html>

<script>
    function changePage(num) {
        document.getElementById("changeNum").value = num;
        document.getElementById("queryForm").submit();
    }

    function deletePaper(link)
    {
        document.getElementById("changeNum").type=3;
        document.getElementById("queryForm").pLink=link;
        document.getElementById("queryForm").submit();

    }
</script>
4.页面划分为左菜单与右主页面的实现 用frame来划分
<html>
<title>论文检索系统</title>
<frameset cols="120,*">

    <frame src="leftMenu.jsp">
    <frame src="paperList.jsp" name="rightframe">

</frameset>

</html>
5.词云跳转实现 数据是使用WordCount程序统计关键词然后手动输入到程序中。数据项中的url数据项是点击的跳转链接 词云调用现成的js文件实现
data: [
                {
                    name: 'iamge',url:"SearchServlet?name=image",
                    value: 10000,
                    textStyle: {
                        normal: {
                            color: 'black'
                        },
                        emphasis: {
                            color: 'red'
                        }
                    }
                },
                {
                    name: 'learning',url:"SearchServlet?name=learning",
                    value: 6181
                },
......
chart.on("click",function(e)
    {
        window.open(e.data.url);
    });
6.按条件查询的sql语句写法 where 1=1来防止出现sql语句的错误
@Override
    public List<Paper> queryUsers(Paper p, int pageNum, int lineNum) throws SQLException {
        int limit_x = (pageNum - 1) * lineNum;
        int limit_y = lineNum;
        StringBuffer sql = new StringBuffer("select * from paperInfo  ");
        sql.append(" where 1 = 1 ");
        if (p.getPaperAbstract() != null && !"".equals(p.getPaperAbstract())) {
            sql.append(" and PaperAbstract like '%" + p.getPaperAbstract() + "%' ");
        }
        if (p.getPaperKeyword() != null && !"".equals(p.getPaperKeyword())) {
            sql.append(" and PaperKeyword like '%" + p.getPaperKeyword() + "%' ");
        }
        if (p.getPaperLink() != null && !"".equals(p.getPaperLink())) {
            sql.append(" and PaperLink like '%" + p.getPaperLink() + "%' ");
        }
        if (p.getPaperReleasetime() != null && !"".equals(p.getPaperReleasetime())) {
            sql.append(" and PaperReleasetime like '%" + p.getPaperReleasetime() + "%' ");
        }
        if (p.getPaperTitle() != null && !"".equals(p.getPaperTitle())) {
            sql.append(" and PaperTitle like '%" + p.getPaperTitle() + "%' ");
        }
        if (p.getPaperTypeYear() != null && !"".equals(p.getPaperTypeYear())) {
            sql.append(" and PaperTypeYear like '%" + p.getPaperTypeYear() + "%' ");
        }
        sql.append(" order by PaperTitle ");
        sql.append(" limit " + limit_x + "," + limit_y);
        System.out.println(sql.toString());
        List<Paper> list = new ArrayList<>();
        MysqlDB mysqlDB = new MysqlDB();
        Connection conn = mysqlDB.getConn();
        Statement stmt = null;
        ResultSet rs = null;
        try {
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql.toString());
            while (rs.next()) {
                Paper tempPaper = new Paper();
                tempPaper.setPaperTitle(rs.getString("paperTitle"));
                tempPaper.setPaperAbstract(rs.getString("paperAbstract"));
                tempPaper.setPaperLink(rs.getString("paperLink"));
                tempPaper.setPaperKeyword(rs.getString("paperKeyword"));
                tempPaper.setPaperTypeYear(rs.getString("PaperTypeYear"));
                tempPaper.setPaperReleasetime(rs.getString("PaperReleasetime"));
                list.add(tempPaper);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            rs.close();
            stmt.close();
            conn.close();
        }
        return list;
    }
7.热词统计 热词统计功能调用echart来实现。数据也是用WordCount程序统计关键词然后手动输入到程序中。
<div id="main" style="width: 1536px;height:864px;"></div>
<script type="text/javascript">
    var myChart = echarts.init(document.getElementById('main'));

    var yearlist = ['2015','2017','2019'];
    var countryList = ['image','learning','object','feature','computer','analysis','recognition','detection','vision','reconstruction'];
    var option = {
        timeline:{
            axisType: 'category',
            autoPlay: true,
            playInterval: 1500,
            data: yearlist,
            label:{
                fontSize: 18
            }
        },
        baseOption:{
            dataset:{
                source:[
                    ['year','image','learning','object','feature','computer','analysis','recognition','detection','vision','reconstruction'],
                    ['2015',1125,
                        277,
                        271,
                        260,
                        245,
                        237,
                        228,
                        221,
                        220,
                        190 ],

历程与收获和评价

阅读《构建之法》第四章的内容,结合在构建之法中学习到的相关内容,结对伙伴分别撰写结对开发项目的心路历程与收获,并评价结对队友

031801124
这次结队开发正好可以运用刚刚学习的javaee的内容,正好我们两人都有上javaee的选修课,所以在技术上沟通比较畅通,在磨合阶段很顺利。也很快就确定了用servlet+jsp的结构来实现项目。之后的实现功能和前端设计在团队合作下推进的很顺利,合作得很不错。git熟练使用后效果很好,update队友的代码按按钮就好了。
这次除了javaee课上学的还学到了servlet用get来跳转链接,学会了echart和爬虫工具的使用。最后效果令人满意。

队友评价:
031801124:
善于沟通,对作品态度认真,效率很高!跟他合作起来完成这项作业非常愉快。

221801126

我在阅读《构建之法》的四五章后,明白了结对编程不仅需要实现实际功能,满足用户需求,还有许多其他需要考虑的地方,代码依赖、codestyle代码规范、代码可读性、单元测试、黑白盒测试等等,对此我阅读了许多CSDN和博客园的相关文章,重新增加和删改了之前的代码规范和相关文档,如首先对文件进行合理划分,再者通过添加必要的注释,增加代码可读性,还有就是在函数命名时也尽量采用有意义的命名等等。

这次结对编程刚开始有些坎坷,比如GitHub建仓库的时候有些问题,加之我们俩也是刚刚开始学习javaEE,一开始进度不是很快。后来在开发过程中,两个人经过沟通,共同进步,互帮互助,学习了servlet+jsp的结构来实现项目,还有echarts实现图表。还学会了GitHub团队合作开发,所谓实践出真知,你没有试过犯错,就永远不知道什么时候pull会出错......我觉得我们的团队模式很和谐,两个人各有分工,不会出现谁主导的情况。最后,希望接下来的作业对我温柔一点……

队友评价:

221801126

这次结对作业是我第二次进行两个人组队编程,我的队友认真负责,善于沟通,碰到不会的难题也非常积极地去解决,是一个非常好的队友,和他合作非常愉快。和他相互交流沟通也是让我受益匪浅,我知道了一个产品的顺利开发是需要团队的一起努力的结果,宇哥是十分的棒,一有问题就及时沟通,节省了许许多多的时间,提高了开发的效率。这两次的结对作业下来,一起收获很多,合作很愉快!~

写在最后:

特别说明:本项目为个人学习用途,非商业用途,可能存在使用部分网络代码,或模块化代码块以及其他已存在的代码。对于重复使用的代码,我们不做任何商业用途,仅仅作为学习目的、交流、模仿、借鉴,没有任何抄袭等其他意图,我们已经最大程度体现我们的代码学习来源和其他获取代码的方式。如果有遗漏,或者如果您不希望您的代码出现在我们的程序内,请您联系我们删除,谢谢您的理解与支持。Salute&Peace.

posted @ 2021-03-31 00:13  _ChangLee  阅读(176)  评论(6编辑  收藏  举报