结对作业二
这个作业属于哪个课程 | 2021春软件工程实践W班(福州大学) |
---|---|
这个作业要求在哪里 | 结对作业二 |
结对学号 | 221801401 221801422 |
这个作业的目标 | 编程实现查看论文列表和分析爬取论文数据 |
其它参考文献 | 博客园 Element文档 CSDN Vue文档 |
目录
git仓库链接和代码规范链接
PSP表格
由于还未完成既定任务,实际耗时部分栏为不确数
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 60 |
·Estimate | ·估计这个任务需要多少时间 | 60 | 60 |
Development | 开发 | 2670 | 2990+ |
·Analysis | ·需求分析 | 100 | 150 |
·Design | ·具体设计 | 2500 | 2750+ |
·Design Review | ·设计复审 | 50 | 50 |
·Test | ·测试(测试原型的使用) | 20 | 40+ |
Reporting | 报告 | 50 | 60 |
·Test Repor | ·测试报告 | 10 | 10 |
·Size Measurement | ·计算工作量 | 10 | 20 |
·Postmortem&Process Improvement Plan | ·事后总结,并提出过程改进计划 | 30 | 30 |
合计 | 2780 | 3170+ |
成品展示
由于没有完成数据在前端的展示,所以只有登录界面的切换和页面的切换的动图
后端的数据输出,由于没有实现在前端的展示,故用postman
- 所有论文数据
- 按标题查询论文
- 按关键词查询论文
- 论文编号查询论文
- 查找top10关键词
- 根据年份和会议查找
结对讨论过程描述
因为之前做过类似的项目,不过是基于yii来实现,但是考虑到这样实现的话可能仅需要切换一下数据库再对前端的代码稍作修改就可以实现,那样的话可能就无法满足结对编程的初衷。所以最后商定前端使用vue框架,后端使用spring。
由于更多的讨论是在线下进行,所以只截取了一部分聊天截图
设计实现过程
- 数据库的结构就是论文的标题,论文的编号,论文的关键词,论文的摘要还有正文的链接。对于数据存入数据的过程,特地编写了代码来实现,通过将提供的json转换成对象的list来实现数据的存入,本来打算用jsonObject来实现,然后发现会难以处理有重复字段的情况,就改用对象类的list来实现。
- 后端采用的spring框架,主要运用了controller和dao之间的调用来实现,由于对其还不是特别的熟悉,所以难以处理service和dao之间的关系,故取消了service。另外,最初没有考虑到使用mybatis所以dao中对数据库的查询操作会比较冗长。
- 前端采用了vue框架,总的来说是修改创建的views中的vue文件来实现界面,由于vue中可以使用element ui组件,所以页面的构建上会相对比较美观一些,只需用css来调整相关组件的样式即可实现。
- 主要的界面分为论文列表界面,类似于收藏夹,论文爬取界面,图表界面以及个人中心界面。论文列表用element自带的el-table来实现数据的展示,图表界面考虑的是用element的走马灯来实现。而与后端的数据交互则考虑用qs以及axios来实现。
- 与后端的数据交互,论文列表的实现,查询以及图表的构建没有完成。
功能结构图
代码说明
- 数据存储到数据库
BufferedReader br = new BufferedReader(new FileReader(new File(base + file)));
int line = 1;
String context = null;
String json = "";
while((context = br.readLine()) != null) {
json += context;
line++;
}
if(json.charAt(json.length()-1) == ';') {
json = json.substring(0, json.length()-1);
}
Map<String, Object> result = JSONObject.fromObject(json);
String doiLink = (String)result.get("doiLink");
String formulaStrippedArticleTitle = (String)result.get("formulaStrippedArticleTitle");
String articleNumber = (String)result.get("articleNumber");
String abs = (String)result.get("abstract");
String authors = "";
String kwds = "无";
List<Map<String, Object>> list = (List<Map<String, Object>>)result.get("authors");
for(int i = 0; i < list.size(); i++) {
authors += (String)list.get(i).get("name") + ",";
}
List<Map<String, Object>> list2 = (List<Map<String, Object>>)result.get("keywords");
if(list2 != null) {
kwds = "";
for(int i = 0; i < list2.size(); i++) {
List<String> list3 = (List<String>)list2.get(i).get("kwd");
for(int j = 0; j < list3.size(); j++) {
kwds += (String)list3.get(j) + ",";
}
}
}
- 前端的dao(只取查询所有文章为例)
String sql = "select * from cvpr union select * from eccv union select * from iccv;";
List<Article> list = new ArrayList();
try {
Statement statement = conn.createStatement();
ResultSet result = statement.executeQuery(sql);
while(result.next()) {
String title = result.getString("formulastrippedarticletitle").toString();
String articleNumber = result.getString("articlenumber").toString();
String doiLink = result.getString("doilink").toString();
String abs = result.getString("abstract");
String kwds = result.getString("kwds").toString();
Article art = new Article();
art.setTitle(title);
art.setArticleNumber(articleNumber);
art.setDoiLink(doiLink);
art.setKwds(kwds);
art.setAbs(abs);
list.add(art);
}
result.close();
statement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
- 前端连接数据库
public static Connection connectToArticles() {
Connection conn = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
}catch(Exception e) {
System.out.println("Error loading Mysql Driver!");
e.printStackTrace();
}
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/articles?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC","root","zhl19991023");
}catch(Exception e) {
System.out.print("get data error!");;
e.printStackTrace();
}
return conn;
}
- 前端的controller
@RequestMapping("/articles")
@CrossOrigin
@ResponseBody
public List<Article> queryAll() {
ArticleDao dao = new ArticleDao();
dao.setConnection(DatabaseUtils.connectToArticles());
List<Article> a = dao.queryAll();
return a;
}
- 前端的top关键词排序,用到了wordcount,只不过将分割符改成了逗号
public static List<String> sortHashmap(String str) {
Map<String, Integer> wordsMap = new HashMap<String, Integer>();
String[] strs = str.split(",");
for(int i = 0; i < strs.length; i++) {
String temp = strs[i].toLowerCase();
if(wordsMap.containsKey(temp)) {
int num = wordsMap.get(temp);
wordsMap.put(temp, 1 + num);
}
else {
wordsMap.put(temp, 1);
}
}
//将words.entrySet()转换为list
List<Map.Entry<String, Integer>> list;
list = new ArrayList<Map.Entry<String, Integer>>(wordsMap.entrySet());
//通过比较器实现排序
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>(){
public int compare(Entry<String, Integer> m1, Entry<String, Integer> m2) {
//按照字典序以及value的值排序
if(m1.getValue().equals(m2.getValue())) {
return m1.getKey().compareTo(m2.getKey());
}else return m2.getValue()-m1.getValue();
}
});
int i = 0;
List<String> kwdsList = new ArrayList();
for(Map.Entry<String, Integer> map : list) {
if(i < 10) {
kwdsList.add(map.getKey());
i++;
}else break;
}
return kwdsList;
- 后端的界面实现(部分)
<ul>
<li @click="tab=0" :class="{tab_active:tab==0}">
<span> <i class="el-icon-document"></i> 论文列表</span>
</li>
<li @click="tab=1" :class="{tab_active:tab==1}">
<span> <i class="el-icon-search"></i> 论文爬取</span>
</li>
<li @click="tab=2" :class="{tab_active:tab==2}">
<span> <i class="el-icon-data-analysis"></i> 热点分析</span>
</li>
<li @click="tab=3" :class="{tab_active:tab==3}">
<span> <i class="el-icon-guide"></i> 个人中心</span>
</li>
</ul>
</div>
.......
<el-table
:data="tableData2"
style="width: 100%;height: 70%;margin-top:100px;width:90%;margin-left:40px;">
<el-table-column
prop="title"
label="标题"
width="130"
>
</el-table-column>
<el-table-column
prop="articlenumber"
label="论文编号"
width="80">
</el-table-column>
<el-table-column
prop="doilink"
label="正文链接"
width="100">
</el-table-column>
<el-table-column
prop="kwds"
label="关键词"
width="120">
</el-table-column>
<el-table-column
prop="abstract"
label="摘要"
width="280">
</el-table-column>
<el-table-column>
<template slot-scope="scope">
<el-button
size="mini"
@click="handleSave(scope.$index, scope.row)">收藏</el-button>
</template>
</el-table-column>
</el-table>
心路历程和收获
[zhl]这次的结对作业可能不是特别顺心。其实最初想结对的对象是另一个同学,就是实力相当然后都肯花时间去学习,可能结对过程会稍微轻松一些。后面的想法是要去照顾一下实力较差的同学,没有考虑到实际情况,所以就无法按时完成既定的任务。再加上自己对spring以及前端的vue框架都还不太熟悉,虽然花时间去学习了但过程依然磕磕碰碰,做完了后端又去做前端可能在结对过程后面的心态会有些炸裂。这次结对作业比较初步地学习了spring和vue,最大的收获还是认清了自身的不足,与一些身边的朋友的差距有点大,还需谦虚学习不断进步。
[zsy]对Github的操作更加了解,学习了vue框架和element ui的使用,对结对编程更加了解,因为对于框架的掌握了解程度不高,在实现过程中,需要一直查找资料,导致编程效率较低。
评价结对队友
[zhl]不是很满意吧,建议就是不要把事情都堆到一个点去做,多学习,多请教,继续加油。
[zsy]结对伙伴十分认真负责,对于功能实现的想法十分具体全面,代码实现中,遇到问题,向他求助都能得到解决,是个非常可靠的结对伙伴。