结对作业二
软工实践 第四次作业 结对作业二
这个作业属于哪个课程 | 2021春软件工程实践S班 |
---|---|
这个作业要求在哪里 | 作业要求 |
这个作业目标 | 深入学习web技术、学习根据原型构建网站 |
其他参考文献 | 百度、github、CSDN |
结对同学 | 黄隽芊 221801232 |
git仓库链接
代码规范链接
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 20 |
·Estimate | ·估计这个任务需要多少时 | 15 | 20 |
·Development | 开发 | 3580 | 4025 |
·Analysis | ·需求分析(包括学习新技术) | 360 | 400 |
·Design Spec | ·生成设计文档 | 40 | 30 |
·Design Review | ·设计复审 | 10 | 20 |
·Coding Standard | ·代码规范 | 20 | 25 |
·Design | ·具体设计 | 90 | 120 |
·Coding | ·具体编码 | 3000 | 3300 |
·Code Review | ·代码复审 | 60 | 50 |
·Test | ·测试(自我测试,修改代码,提交修改) | 60 | 80 |
Reporting | 报告 | 60 | 70 |
·Test Repor | ·测试报告 | 35 | 40 |
·Size Measurement | ·计算工作量 | 10 | 15 |
·Postmortem & Process Improvement Plan | ·事后总结, 并提出过程改进计划 | 15 | 15 |
合计 | 3575 | 4115 |
成品展示
- 可对论文列表进行查询
- 可对论文列表进行删除;
- 分析论文信息,提取top10个热门领域,形成关键词图谱,点击某个关键词可展现相关的论文
- 对多年间,ECCV顶会的热词呈现热度走势对比
结对讨论过程描述
1.刚开始分工
2.准备工作
3.后端进程
4.前端界面和问题讨论
5.收藏夹和删除功能的讨论
6.论文列表搜索页面的讨论
7.关键词图谱的讨论
8.热度走势图的讨论
9.宿舍讨论过程
描述设计实现
使用MVC开发流程实现项目架构,利用Servlet+JSP+Jdbc的功能开发流程。
项目架构:
以下功能结构图包括本次作业的流程(需求分析,实现方式,分工)
以下数据结构设计图以及项目结构是关于数据结构的一些设计。数据通过MYSQL数据库来管理,由ItemsDao封装所有对数据的查询,返回需要的对象,由前台实现数据的显示
代码说明
数据库设计
CREATE TABLE `paperslist` (
`id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`abstracts` varchar(8191) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`conference` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`keyword` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`link` varchar(8191) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
代码设计
从json文件夹取出数据
public void readECCVFileContent(String path) throws FileNotFoundException {
String key = "";
items item = new items();
JSONReader reader=new JSONReader(new FileReader(path));
//开始解析最外层的对象
reader.startObject();
//遍历最外层的对象
while (reader.hasNext()){
String longkeyword = "";
key = reader.readString(); //读取键的值
if(key.equals("摘要")){
String abstracts = reader.readObject().toString();
item.setAbstracts(abstracts);
}
else if(key.equals("会议和年份")){
String conference = reader.readObject().toString();
item.setConference(conference);
}
else if(key.equals("关键词")){
reader.startArray();//开始解析数组
while (reader.hasNext()){
String keyword = reader.readString();
longkeyword += keyword;
longkeyword += ",";
}
item.setKeyword(longkeyword);
reader.endArray();
}
else if(key.equals("发布时间")){
String time = reader.readObject().toString();
item.setTime(time);
}
else if(key.equals("论文名称")){
String title = reader.readObject().toString();
System.out.println("论文:" + title);
item.setTitle(title);
}
else if(key.equals("原文链接")){
String link = reader.readObject().toString();
item.setLink(link);
}
}
try {
Connection conn = DBHelper.getConnection();
saveDataToDb(conn,item);
} catch (Exception e) {
// 省略
}
reader.endObject();
}
解释思路:
其实刚开始拿到json数据还是有点头痛,怎么把数据取出来还是有点困难,于是上网搜索,觉得使用JSONReader来读数据在一层一层遍历解析。第一次拆Json数据,花费了很多时间调试。
获取所有论文信息
public ArrayList<items> getAllItems() {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
// 论文集合
ArrayList<items> list = new ArrayList<items>();
try {
conn = DBHelper.getConnection();
String sql = "select * from paperslist;";
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
while (rs.next()) {
items item = new items();
item.setId(rs.getString("id"));
item.setAbstracts(rs.getString("abstracts"));
item.setConference(rs.getString("conference"));
item.setKeyword(rs.getString("keyword"));
item.setTime(rs.getString("time"));
item.setTitle(rs.getString("title"));
item.setLink(rs.getString("link"));
// 把一个论文加入集合
list.add(item);
}
return list;
} catch (Exception ex) {
//省略
} finally {
// 省略
}
}
解释思路:
items是设计的关于论文的类,位于entity包里,那么从数据库取出数据就是执行sql语句,同样在相同类下也有根据论文标题,论文id搜索返回论文信息的方法,就是执行的sql语句不同。
获取top10热词
public List<Map.Entry<String, Integer>> getHotkw (String str){
int num = 0;
TreeMap<String, Integer> map = new TreeMap<>();
String lowerStr = str.toLowerCase();
String[] word = lowerStr.split(",");
int len = word.length;
String tw = null;
for (int i = 0; i < len; i++) {
tw = word[i];
if (!map.containsKey(tw)) {
map.put(tw, 1);
}
else {
num = map.get(tw);
map.put(tw, num + 1);
}
}
List<Map.Entry<String, Integer>> hotWords = WordCountMethod.highFreqWord(map);
return hotWords;
}
解释思路:
上次作业写了wordcount程序,这一次刚好获取的时候可以复用,就想到搬了上一次WordCountMethod.highFreqWord(map)
的函数,前期是获取所有论文关键词拼成字符串,再拆成一个个键值对存储在Map中,最后按需获取top的热词。
获取排名前几的热词近几年的数据
public int[] keyYearNum(int kw) {
//获取所有关键词
String allKw = getKeywordsFromDB();
//获取排好序的关键词数据
String[] topkw = words(getHotkw(allKw));
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
int year = 2016;
//存储三年该热词出现次数
int[] num = new int[3];
try {
conn = DBHelper.getConnection();
for(int i = 0;i < 3;i++) {
String sql = "select * from paperslist where conference like ? and keyword like ?;";
stmt = conn.prepareStatement(sql);
//模糊查询匹配语句
String y = "%" + year + "%";
String kw1 = "%"+ topkw[kw] + "%";
stmt.setString(1, y);
stmt.setString(2, kw1);
rs = stmt.executeQuery();
while (rs.next()) {
num[i]++;
}
year += 2;
}
return num;
} catch (Exception ex) {
//省略
} finally {
//省略
}
}
解释思路:
题目要求是多年间顶会的热词呈现热度走势,那么需要热词也要热词数据,其实上一个功能已经取出热词以及排名,那只要取出前几名的热词分别再多年的数据,正好数据中有提供论文发布年份,那就可以用sql条件查询语句,设置关键词和年份两个条件查询符合的论文返回论文数。
servlet处理前端传来请求转发数据
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
if(request.getParameter("action")!=null){
this.action = request.getParameter("action");
//如果是添加论文进收藏夹
if(action.equals("add")){
if(addToCollection(request,response)){
request.getRequestDispatcher("/success.jsp").forward(request, response);
}
else{
request.getRequestDispatcher("/failure.jsp").forward(request, response);
}
}
//如果是显示收藏夹
if(action.equals("show")){
request.getRequestDispatcher("/collection.jsp").forward(request, response);
}
//如果是执行删除收藏夹的论文
if(action.equals("delete")){
if(deleteFromCollection(request,response)){
request.getRequestDispatcher("/collection.jsp").forward(request, response);
}
else{
request.getRequestDispatcher("/collection.jsp").forward(request, response);
}
}
}
}
解释思路:
位于collectionServlet中,用于处理前端收藏,删除,展示收藏夹的请求,传输数据,再重定向到相应jsp页面。
添加论文进收藏夹
private boolean addToCollection(HttpServletRequest request, HttpServletResponse response){
String id = request.getParameter("id");
String number = request.getParameter("num");
items item = idao.getItemsById(Integer.parseInt(id));
//是否是第一次给收藏夹添加论文,需要给session中创建一个新的收藏夹对象
if(request.getSession().getAttribute("collection")==null){
collection collection = new collection();
request.getSession().setAttribute("collection",collection);
}
collection collection = (collection)request.getSession().getAttribute("collection");
if(collection.addPaperInCollection(item, Integer.parseInt(number))){
return true;
}
else{
return false;
}
}
//添加论文进收藏夹
public boolean addPaperInCollection(items item ,int number){
if(paperlist.containsKey(item)){
paperlist.put(item, paperlist.get(item)+number);
}
else{
paperlist.put(item, number);
}
return true;
}
解释思路:
获取前端传来的论文id和num,判断是否第一次给收藏夹添加论文,如果是,就新建一个收藏夹对象,如果不是就收藏文章。方法写在collection类中。
从收藏夹删除论文
private boolean deleteFromCollection(HttpServletRequest request, HttpServletResponse response){
String id = request.getParameter("id");
collection coll = (collection)request.getSession().getAttribute("collection");
items item = idao.getItemsById(Integer.parseInt(id));
if(coll.removePaperFromCollection(item)){
return true;
}
else{
return false;
}
}
//从收藏夹移除论文
public boolean removePaperFromCollection(items item){
paperlist.remove(item);
return true;
}
前端jsp实现论文信息显示
<table id="table" >
<tr>
<td>
<!-- 论文循环开始 -->
<%
ItemsDao itemsDao = new ItemsDao();
ArrayList<items> list = new ArrayList<items>();
//如果有获取到key说明是搜索后跳转的页面,就根据收到的key进行模糊搜索返回论文集合
if(request.getParameter("key")!=null){
list = itemsDao.getItemsByTitle(request.getParameter("key"));
}
//没有获得key,返回所有论文信息
else{
list = itemsDao.getAllItems();
}
if(list!=null&&list.size()>0){
for(int i=0;i<list.size();i++){
items item = list.get(i);
%>
<div>
<dl>
<dt clsaa="dt_title">
<a href="details.jsp?id=<%=item.getId()%>"><%=item.getTitle() %></a>
</dt>
<dd class="dd_abstract">abstract: <%=item.getAbstracts() %></dd>
<dd class="dd_conference">来源会议: <%=item.getConference() %></dd>
</dl>
</div>
<!-- 论文循环结束 -->
<%
}
}
%>
</td>
</tr>
</table>
论文模糊搜索
<form action="">
<input type="text" name="key" value="" placeholder="输入论文题目查找 支持模糊查询">
<a href="main.jsp?keyword=document.getElementById("key").value"><input type="submit" value="搜索"></a>
</form>
解释思路:
获取输入框的value,作为跳转回首页携带的数据,加载首页时判断是否有携带数据,有则执行函数搜索返回相应论文。
心路历程和收获
221801226肖寒:
之前一直接触的是静态网页的开发,在上学期web程序设计实践接触了php使用yii模板开发博客,但是还不是很熟练。在第一次寒假作业时候写的学习规划是前端,确实都有在一步步的学习,发现布置的作业也很贴合我学习路线。这一次学习了jsp+servlet+jdbc的MVC设计模式开发了小小小的论文查询系统,但是也有不足。
这一次我是和队友0基础的学做jsp+servlet,我是做后端和数据连接,刚开始的环境构建就遇到一些问题,但是我们都一起解决。这一次真的体会到结对编程,两个人并肩作战的感受。感谢小黄同学前端绿色简约的UI和无私的帮助,交流非常顺利,👍。
这一次对github的项目管理逐渐熟悉,学会了创建分支合并分支发布release版本,除了github有时候连接真的容易崩之外,其他都很好用。
221801232黄隽芊:
在上次做完原型之后,一直都很担心实践的问题,这次还是逃不过。一开始没有什么思路,真的毫无头绪,然后和队友商量着着先把数据弄出来,先把要做的能简化就简化,首先要先有个东西做出来。我花了好久先搭了jsp的环境,html和css因为以前有学过,所以并不难。主要就是细心和耐心,还是做得不够好看,希望下次有机会可以做得更好看。但是页面还需要和队友的数据连接,自己有很多不会的地方,多亏了队友的帮助,后期还要调试修改,一起努力。新学了echarts,这次只简单地做了折线图,其实可以用来制作各种图表。而且通过结对作业对github的使用也更加了解和熟练了。自己还有很多不会的地方,做得真的不够好,希望可以在一次次作业中进步,学会更多东西。
结对过程,队友评价
221801226肖寒:
话不多说就是nice!两个小白相互支持,主要是交流非常顺利,而且态度积极。对于前端UI小黄做了很多样式的调整,而且处理前后端数据的时候也是我们一起完成,对接很顺利。感觉这次作业完成的很顺利!
221801232黄隽芊:
队友真的非常好。我真的对实现这个作业一头雾水的时候,是队友一举担下处理数据的重任,才让我们的作业有了眉目。对于两个人都并不熟悉的后端,队友真的很努力,处理了数据的各项内容,让我做较为简单的前端页面,队友还教了我很多东西。非常感谢队友的帮助,让我们的作业得以实现。