结对第二次作业

这个作业属于哪个课程 2021春软件工程实践S班 (福州大学)
这个作业要求在哪里 结对作业二
结对学号 221801111
221801132
这个作业的目标 1、和伙伴通过github协作/代码规范等
2、实现结对作业一中原型中的部分功能
3、将项目部署到云服务器上
其他参考文献 CSDN、博客园

Github仓库地址和代码规范链接

Github仓库地址
代码规范

PSP表格和效能分析

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

访问链接

项目地址
ps:我们的服务器响应时间过长,搜索之后要过很久才能显示

成品展示

  • 首页

  • 论文列表

  • 数据分析页

  • 关键词图谱

  • 包含关键词的论文列表

  • 热词动图


  • 搜索和删除

  • 热词动图

  • 关键词图谱

结对讨论过程描述

这次结对作业是对结对作业一的原型的部分功能实现。
基础功能:
功能一:对已爬取的论文列表进行操作
1、对论文列表进行删除
2、对论文列表进行查询详细信息(支持模糊查询)
功能二:分析已爬取到的论文信息,提取top10个热门领域或热门研究方向
1、关键词图谱:点击某个关键词可展现相关的论文
2、多年间、不同顶会的热词呈现热度走势对比动

分析了基础功能之后,我们决定用刚刚学的JSP、Servlet,基于Web来开发。对论文列表的展示用JSP来显示,论文列表的删除、查询用Servlet来处理。上网查阅了一些资料后,我们觉得关键词图谱、热词动图可以用echart来实现展示。K负责Servlet部分的代码编写,L负责JSP部分的代码编写。同一个功能模块的JSP和Servlet代码同步进行编写,这样可以避免前后端后期再集中整合的冲突。

两人结对讨论的截图

设计实现过程

论文列表的数据需要一个Paper对象类来表示,数据库的CRUD用DAO层的接口类来实现。论文列表的展示用一个PaperList.jsp来显示,JSP提交表单后ListServlet处理数据,执行sql语句,再返回数据给JSP显示出论文列表。删除的功能与查询类似。
热词的数据用一个HotWord来表示,数据库的CRUD用DAO层的接口类来实现。三个会议的热词动图分成三个页面,页面的实现代码一样,点击选项之后,提交表单后ChartServlet处理数据,执行sql语句,返回数据给JSP,再展示成一个时间轴柱状图。
关键词图谱目前只是使用按钮来实现跳转,点击一个关键词之后,提交表单后KWCServlet处理数据,执行sql语句,传递数据的KeyWordList.jsp显示相关的论文列表。

  • 数据库表设计

功能结构图

关键代码

  • 数据库连接接口
public class DBUtil {
	static String ip = "127.0.0.1";
	static int port = 3306;
	static String database = "paper";
	static String encoding = "UTF-8";
	static String loginName = "root";
	static String password = "lj3990353";

	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection() throws SQLException {
		String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s&useSSL=false", ip, port, database, encoding);
		return DriverManager.getConnection(url, loginName, password);
	}

	/* 关闭连接的方法 */
	public static void close(ResultSet rs, Statement stmt, Connection conn) {
		try {
			if (rs != null)
				rs.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		try {
			if (stmt != null)
				stmt.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		try {
			if (conn != null)
				conn.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public static void main(String[] args) throws SQLException {
		System.out.println(getConnection());
	}
}
  • 数据库按论文标题模糊搜索

    用sql语句的like可以筛选出包含搜索词的数据项,就可以实现模糊搜索了

public List<Paper> listGetByTitle(String str) {
        String sql = "select * from post where title " + "like" +"'%" + str + "%'";
        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)){
            ResultSet rs = ps.executeQuery(sql);
            List<Paper> list = new ArrayList<>();
            while (rs.next()) {
                Paper p = new Paper();
                p.setTitle(rs.getString(1));
                p.setSummary(rs.getString(2));
                p.setLink(rs.getString(3));
                p.setKeyword(rs.getString(4));
                p.setYear(rs.getString(5));
                p.setType(rs.getString(6));
                list.add(p);
            }
            return list;
        } catch (SQLException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        return null;
    }
  • 获取论文列表

    实例化一个PaperDAO对象并调用PaperDAOImpl这个接口的listGetByTitle()方法,获取按标题搜索的论文列表,再传给jsp来显示

public class ListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PaperDAO paperDAO = new PaperDAOImpl();
        String option = request.getParameter("option");
        String text = request.getParameter("search");
        List<Paper> list = new ArrayList<>();

        if ("title".equals(option)) {
            list = paperDAO.listGetByTitle(text);
        }

        if ("keyword".equals(option)) {
            list = paperDAO.listGetByKeyword(text);
        }

        if ("type".equals(option)) {
            list = paperDAO.listGetByType(text);
        }

        request.setAttribute("list", list);
        request.getRequestDispatcher("PaperList.jsp").forward(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  • 显示论文列表

    用HTML的table来显示Servlet处理后传来的论文列表数据

<%!
    List<Paper> list = new ArrayList<>();
%>

<%
    list = (List<Paper>) request.getAttribute("list");
    if(list != null) {
%>

    <table border="1" width="400" data-pagination="true"
           data-side-pagination="client"
           data-page-size="3">
        <tr>
            <th width="200px">论文标题</th>
            <th width="600px">摘要</th>
            <th>原文链接</th>
            <th width="200px">关键词</th>
            <th>年份</th>
            <th>类别</th>
            <th>操作</th>
        </tr>

        <%
                for (Paper paper : list) {
        %>

        <tr>
                <td width="200px"><%=paper.getTitle() %></td>
                <td width="600px"><%=paper.getSummary() %></td>
                <td><a href=<%=paper.getLink() %>> <%=paper.getLink() %></a></td>
                <td width="200px"><%=paper.getKeyword() %></td>
                <td><%=paper.getYear() %></td>
                <td><%=paper.getType() %></td>
                <td>
                    <form method="post" id="form1" action="<%=path%>/DeleteServlet">
                        <input type="submit" name="deleteButton" value="删除">
                        <input type="hidden" id="title" name="title" value="<%=paper.getTitle() %>">
                    </form>
                </td>
        </tr>

        <%
                }
            }
        %>

    </table>
  • 获取热词

    用listGetByYearCVPR()获得每年的前十个热词,再传给jsp展示

List<HotWord> total = new ArrayList<>();
        int cnt = 0;
        List<HotWord> CVPRHotWordList = new ArrayList<>();
        for (int year = 2000;year < 2021;year++) {
            WordDAO wordDAO = new WordDAOImpl();
            List<KeyWord> keyWordList = new ArrayList<>();
            keyWordList = wordDAO.listGetByYearCVPR(Integer.toString(year));//关键词列表
            //if (keyWordList == null) System.out.println("空");
            if (keyWordList != null) {
                Map<String,Integer> map = new HashMap<String,Integer>();//创建map,key保存字符串,value保存出现的次数
                for (KeyWord word : keyWordList) {
                    String s = word.getWord();
                    String[] temp = strCut(s);
                    int size = temp.length;
                    for (int i = 0; i < size; i++) {//遍历temp数组
                        if (map.containsKey(temp[i])) {
                            map.put(temp[i], map.get(temp[i]) + 1);
                        }
                        else
                            map.put(temp[i],1);
                    }
                }
                map = sortByValueDescending(map);

                List<HotWord> HotWordList = new ArrayList<>();
                for (Map.Entry<String,Integer> vo : map.entrySet()) {
                    HotWord hotWord = new HotWord();
                    hotWord.setWord(vo.getKey());
                    hotWord.setNum(vo.getValue());
                    hotWord.setYear(Integer.toString(year));
                    hotWord.setType("CVPR");
                    HotWordList.add(hotWord);
                } 

                HotWord[] hotWord = new HotWord[10];
                for (int i = 0;i < 10;i++) {
                    hotWord[i] = HotWordList.get(i);
                }

                for (int i = 0;i < 10;i++) {
                    CVPRHotWordList.add(hotWord[i]);//CVPR每年的热词
                }                            
            }

            for (int i = 0;i < 10;i++) {
                total.add(CVPRHotWordList.get(i));
            }
        }
  • 用echart展示热词动图

    用echart的时间轴实现每年的热词展示,展示形式为柱状图

<div id="main" style="width: 1280px;height:600px;"></div>
<script type="text/javascript">
    // 基于准备好的dom,初始化echarts实例
    var myChart = echarts.init(document.getElementById('main'));

    // 指定图表的配置项和数据
    var year = ['2016','2018','2020'];
    var word = ['Learning','Image','Neural','Convolut','Network','Deep','Object'];
    var option = {
        timeline:{
            axisType: 'category',
            autoPlay: true,
            playInterval: 1500,
            data: year,
            label:{
                fontSize: 18
            }
        },

        baseOption:{
            dataset:{
                source:[
                    ['year','Learning','Image','Neural','Convolut','Network','Deep','Object'],
                    ['2016',81,73,63,55,55,50,42],
                    ['2018',313,160,145,94,138,174,106],
                    ['2020',449,250,141,53,118,150,151]
                ]
            },

            title: {
                text: 'ECCV热词热度走势图',
                left: 'center',
                textStyle:{
                    fontSize:15
                }
            },
            tooltip: {
                trigger: 'axis'
            },
            toolbox: {
                feature: {
                    saveAsImage: {}
                }
            },
            legend: {
            },
            grid: {
                left: '10%',
                bottom: '15%',
                containLabel: true
            },
            xAxis: [
                {
                    type:'category',
                    data: word,
                    axisPointer: {
                        type: 'shadow'
                    },
                },
            ],
            yAxis:[
                {
                    name:'热度',
                    type:'value',
                    nameTextStyle:{
                        fontSize:18
                    },
                    axisLabel:{
                        fontSize:18
                    }
                },
            ],
            series: [
                {
                    //name: 'GDP',
                    type: 'bar',
                    seriesLayoutBy: 'row',
                    encode:{
                        x:'year',
                        y:'2016'
                    }
                },
            ]
        },
        options:[]
    };

    for (var n = 0; n < year.length; n++){
        option.options.push({
            title:{
                show:true,
                left: 'center',
                textStyle:{
                    fontSize:24
                }
            },
            series:[
                {
                    type: 'bar',
                    seriesLayoutBy: 'row',
                    encode:{
                        x:'year',
                        y:year[n]
                    }
                },
            ]
        });
    }

    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);
</script>

结对开发项目的心路历程与收获

心路历程与收获

K:写完代码的时候,心里五味杂陈的,心里想终于把项目的要求功能实现了,写完了,终于写完了。。。每天晚上一两点上床,白天没上课的时候要用5-6个小时来写代码(主要还是我太菜了),写完了想想这些好像也没什么。这次的项目基于Web来开发,我也是刚刚开始学JSP、Servlet,spring都还没接触,JSP、Servlet从模糊了解,到熟悉使用,都是磕磕碰碰。网上看视频,找教程,学习新技术真的占了开发的一大半时间。还有echart的使用,在同学的帮助下,也才会使用一点。Github工具现在基本上会使用了,也达到了熟练的程度,对协同开发也可以轻车熟路。在编码的过程中,我感到了深深的痛苦,每次写完一个功能测试的时候,总是有问题(头都大了),找到bug再修复的过程真的是让我处于崩溃的边缘,每次修复完之后的心情真的是心里的石头终于落下了(QAQ)。

L:刚开始看到题目的时候,我觉得有点头大,因为这次的作业不仅有很多我不熟悉的技术,而且分工的问题也很麻烦。本来想我做前端、K做后端。但是我们使用的JSP和Servlet前后端并没有很好的分离。难免遇到分工不均的问题,我也觉得这次K比我更多的时间在写代码上,所以我也更积极做一些其他的工作,比如部署服务器、撰写博客等。在做这次作业的这几天,我们每天花了几个小时在学习新技术,早上利用上完课挤出的零碎时间学习,晚上经常写代码到半夜,遇到不懂的问题也通过互相讨论、上网学习、询问其他的同学解决,虽然很累,但是觉得非常充实。经过这次的作业,我觉得自己的JavaWeb水平有了一定的提升、github和idea等工具的使用也更加熟练,也更加懂得如何去团队协作了。

评价结对队友

K->L:这次结对开发过程中有些工作我是需要让L来做的,他完成的不错,让我觉得这次结对作业轻松了不少。我的伙伴对这次结对作业很有热情、态度也十分认真,经常写代码到深夜,结对开发麻烦就麻烦在需要沟通与理解,所以我希望我的伙伴可以对结对开发过程的讨论更积极一些,也可以在开发过程中向我积极反馈问题,及时解决。

L->K:这次结对作业,K负责了工作量比较大的后端,包括数据库和数据分析等部分,但他也没有怨言,态度十分认真,积极完成了他负责的部分,我也觉得他做的很好。但是因为前几天K在忙比赛的事情,这次作业开始的时间比较晚,所以这次作业做的有些匆忙,有些细节没有很好地完善。我希望下次作业K能尽快安排时间开始做,让时间更充裕一些。

posted @ 2021-03-31 20:19  一只离离离  阅读(95)  评论(5编辑  收藏  举报