結對第二次作業——頂會熱詞統計的實現
這個作業屬於哪個課程 | 2021春軟件工程實踐 | W班 (福州大學) |
---|---|
這個作業要求在哪里 | 結對第二次作業——頂會熱詞統計的實現 |
結對學號 | 221801304&221801331 |
這個作業的目標 | 實現頂會熱詞統計的相關功能 |
其他參考文獻 | 無 |
git倉庫鏈接和代碼規范鏈接
JS、CSS、HTML文件命名
js、css、html的命名均采用小寫命名方式(templates下的html除外)
正例:detail.css、echarts.js、table.html
反例:Echarts.js、Detail.cssHTML類型聲明
使用HTML5的文檔類型申明,不使用XHTML或HTML4
正例:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta charset="UTF-8" />
<title>Page title</title>
</head>
<body>
<img src="images/company-logo.png" alt="Company" />
</body>
</html>
- 縮進
嵌套的節點應該縮進,並且同層節點縮進需一致。
正例:<div> <p>111</p> <span>33</span> </div>
反例:
<div> <p>fa</p> <span>33</span> </div>
- CSS內部命名應該有意義
正例:.conceal{ border:none; }
- 每個選擇器及屬性獨占一行
正例:.btn{ width: 100px; height: 30px; }
- 多使用相對寬度,少用絕對寬度
這樣的目的主要是更容易適配不同瀏覽器及屏幕。
項目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
Planning | 計划 | ||
• Estimate | • 估計這個任務需要多少時間 | 7day | 8day |
Development | 開發 | ||
• Analysis | • 需求分析 | 30 | 30 |
• Dicussing & Design Spec | • 討論交流 & 設計文檔 | 30 | 40 |
• Design Review | • 設計復審 | 20 | 10 |
• Learning | • 學習新知識 | 60 | 80 |
• Coding Standard | • 代碼規范 | 30 | 30 |
• Coding | • 具體編碼 | 2500 | 3000 |
• Code Review | • 代碼復審 | 30 | 30 |
• Test | • 測試 | 30 | 20 |
Reporting | 報告 | ||
• Test Repor | • 測試報告 | 30 | 30 |
• Size Measurement | • 計算工作量 | 30 | 20 |
• Postmortem & Improvement Of The Prototype | • 事后總結, 並提出過程改進計划 | 30 | 20 |
合計 | 2820 | 3310 |
成品展示
- 主頁
由頭部和側邊導航欄和主體三部分,主題采用輪播圖進行網站的推銷介紹(笑)。
可以在頭部搜索框快速搜索,根據標題模糊查詢,得到查詢結果的列表。
每個條目顯示標題、摘要、關鍵詞、會議、時間的信息,點擊詳情后可以觀看更詳細的內容。
詳情頁內的關鍵詞里每個關鍵詞都可以點擊,點擊后可以跳轉到包含該關鍵詞的論文列表。
另外,在論文列表和詳情頁都可以刪除該論文。- 高級搜索頁
點擊側邊欄的高級搜索可以到高級搜索頁面,可以進行標題、摘要、關鍵詞的模糊或精確查詢,還可以選定時間區間和會議,默認是2000-2020和三大會議都查詢(如果把三個會議都取消掉再查詢,會彈出提示信息不讓你查詢)
順帶一提,這個分頁是可以用的,是真的分頁。
- 熱詞統計頁
點擊側邊欄的熱詞統計后,可以顯示熱詞top10,並且可以選擇查看某個會議、某個年份區間的熱詞top10。
熱詞top10下面還有對應上面top10的詞雲,點擊某個關鍵詞詞雲還可以跳轉到對應的論文列表。
點擊柱狀圖中某個柱形,還可以查看對應的這個熱詞的熱度走向圖,並且可以選擇查看不同會議的走向。
- 熱詞圖譜頁
點擊側邊欄的熱詞圖譜可以到這個頁面,展示的是所有會議的2000到2020期間的所有熱詞熱度還有詞雲,點擊這里的詞雲依然可以跳轉到對應搜索的論文列表。
結對討論過程描述
有了第一次結對作業的經驗,加上第二次結對作業開始時我們已經返校,面對面交流方便了許多,所以第二次結對作業的准備工作還是比較迅速的。
開始討論:由於在同一個宿舍,所以討論比較方便。第二次結對作業發布后,我們首先根據作業要求,把每一條需求映射到前端、后端,分別需要實現什么進行了分析,並且生成了下面的文檔。
雖然一個人寫前端一個人寫后端,但是經常寫着寫着就跑去對方的電腦面前,看看對方正在寫什么,並且提出自己的意見,通過不斷的交換意見,修改代碼,達成意見上的一致。
遇到問題:在編碼的過程中,遇到的最大的問題是數據庫CRUD的效率問題,把爬取下來的數據映射完轉換后,插入過程不盡如人意,跑了一晚上居然還沒插入完成(???),並且到后面越來越慢,從一開始的一秒n條到最后一分鍾一條。
解決問題:后來,通過不斷地測試和搜索引擎的資料查找與討論后,發現問題在於:插入關鍵詞信息之前使用了select(*)語句判斷關鍵詞是否存在,導致每插入一條論文數據,就需要執行十多次該語句,在論文數量逐漸增大之后,該語句效率也越來越低,導入論文導入時間迅速增加。於是我們重構了數據庫,將論文和關鍵詞的對應關系由多對多改為一對多,將三張表改為了兩張表,雖然會有一些數據冗余,但是大幅提升了性能,論文導入時間也縮短到了2分鍾。
遇到問題:在模糊查詢的過程中,由於需要連表,在本地進行一次查詢時間需要30s(當然也有電腦卡的原因),用戶體驗很差。
解決問題:將需要連表和模糊查詢的字段增加了索引,讓本地運行所需時間減少到了1s內
遇到問題:寫前端的時候,樣式問題困擾了許久,常常猶豫不決,有時寫完后發現不好看或者不合理,重寫樣式。加上第一次使用layui美化界面,不熟悉效果與用法,花了比較長的時間。
解決問題:不斷與隊友進行討論,探討頁面布局與樣式是否合理、美觀,設計好一個部分就commit一次,邀請隊友一起看效果,作出修改。研究layui官方文檔,通過不斷地測試樣式,調整樣式,把頁面做的更加美觀,同時也更加熟練的使用layui。
從需求分析開始到最后撰寫博客,我們兩個人都沒有停止過討論,我覺得這才是結對作業真正的意義所在,有交流才有改善,有交流才能解決問題。
下面附帶兩張討論時的照片,討論都是面對面交流。
設計實現過程
項目技術
本次項目前后端不分離,使用springboot開發。前端使用了thymeleaf模板引擎進行前后端的數據庫交互,並使用了Layui美化了樣式
設計思路
- 數據庫
本次作業的數據主要有三部分,論文信息、關鍵詞信息、關鍵詞與論文之間的對應關系
我們將論文與關鍵詞之間設計成1對多的關系進行建表
- 模塊設計
主要將功能模塊分為兩個部分:論文管理和關鍵詞統計
論文的搜索支持多條件模糊查詢;
關鍵詞統計模塊中包括了關鍵詞圖譜和top10排行;
實現過程
- 前端:使用thymeleaf做前后端數據傳遞,通過Layui美化樣式
前端項目結構圖
- 后端:使用java語言,通過SSM框架進行開發
后端項目結構圖
功能結構圖
代碼說明
論文高級檢索
<select id="selectPapersByMap" parameterType="map" resultMap="Paper">
SELECT p.pid,title,abst,p.conference,p.publicationYear,link,
keyword
FROM paper AS p
LEFT JOIN keyword AS k ON p.pid=k.pid
<where>
<!--精確查詢-->
<if test="etitle !=null and etitle !='' ">AND title=#{etitle}</if>
<if test="eabst !=NULL and eabst !='' ">AND abst=#{eabst}</if>
<if test="econference !=NULL and econference !=''">AND p.conference=#{econference}</if>
<if test="ekeyword !=NULL and ekeyword !=''">AND k.keyword=#{ekeyword}</if>
<!--模糊查詢-->
<if test="vtitle !=NULL and vtitle!=''">AND title LIKE '%${vtitle}%'</if>
<if test="vabst !=NULL and vabst !=''">AND abst LIKE '%${vabst}%'</if>
<if test="vkeyword !=NULL and vkeyword !=''">AND keyword LIKE '%${vkeyword}%'</if>
<!--年份查詢-->
<if test="publicationYear !=NULL and publicationYear !=''">AND p.publicationYear=#{publicationYear}</if>
<if test="beginYear !=NULL and beginYear !=''">AND p.publicationYear BETWEEN #{beginYear} AND #{endYear}</if>
<if test="link !=NULL and link !=''">AND link=#{link}</if>
<if test="conference !=NULL and conference !=''">
AND p.conference IN (1,
<if test="CVPR !=NULL and CVPR !=''">"CVPR",</if>
<if test="ECCV !=NULL and ECCV !=''">"ECCV",</if>
<if test="CVPR !=NULL and CVPR !=''">"CVPR",</if>
2)
</if>
</where>
</select>
使用mybatis實現dao層接口,通過將查詢參數傳入map進行查詢,可支持任意數量條件、模糊或精確查詢(不過使用map好像不太規范,下次封裝一個DO類來代替map)
論文展示(分頁)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageHelper
{
private List<String> pidList; //論文id列表
private int totalNum; //總條數
private int paperNum; //單頁面頁數
private int currentPage; //當前頁面
private int totalPage; //總頁數
/**
* 構造方法
* @param pidList
* @param paperNum
*/
public PageHelper(List<String> pidList, int paperNum)
{
this.pidList = pidList;
this.paperNum = paperNum;
this.totalNum=pidList.size();
this.currentPage=0;
this.totalPage=(totalNum%paperNum)==0?(totalNum/paperNum):(totalNum/paperNum+1);
}
/**
* 根據索引獲得列表
* @param start
* @param end
* @return
*/
public List<String> getListByIndex(int start,int end)
{
if(start>=totalNum || end<=0)
{
return new LinkedList<>();
}
if(end>=totalNum)
{
end=totalNum;
}
return pidList.subList(start,end);
}
/**
* 獲取指定頁號的內容
* @return
*/
public List<String> getPageByNum(int pageNum)
{
currentPage=pageNum;
return getListByIndex((pageNum-1)*paperNum,pageNum*paperNum);
}
/**
* 獲得上一頁的內容
* @return
*/
public List<String> getPrePage()
{
return getListByIndex((currentPage-1)*paperNum,currentPage--*paperNum);
}
/**
* 獲得下一頁的內容
* @return
*/
public List<String> getNextPage()
{
return getListByIndex((currentPage-1)*paperNum,currentPage++*paperNum);
}
封裝了一個PageHelper來幫助實現分頁,論文檢索時,將查詢結果的id列表存入List,進行分批讀取;
類里封裝了一些方法進行讀取和遍歷
關鍵詞圖譜
$(document).ready(function()
{
//根據條件請求數據
$.post('/getTop10Keywords/',{beginYear:2000,
endYear:2020,conference:''},function(data) {
data = JSON.parse(data);
//加載詞雲
CloudLoad(data);
});
})
function CloudLoad(data)
{
array.splice(0,array.length);
for(var i=0;i<data.x.length;i++)
{
var obj=new Object();
obj.text = data.x[i];
obj.weight = data.y[i]/100;
obj.link = "/getPapersByKeyword/"+data.x[i]; //為每個關鍵詞設置鏈接
array.push(obj);
}
//加載詞雲
$("#main").empty();
$("#main").jQCloud(array, { //設置參數
removeOverflowing: false,
shape: "elliptic",
width: 500,
height: 300
});
}
通過ajax異步請求后端數據,利用jQCloud組件進行關鍵詞圖譜的渲染
熱詞統計
function BarLoad(beginYear,endYear,conference)
{
bar.showLoading();
//根據篩選條件獲取后端數據
$.post('/getTop10Keywords/',{beginYear:beginYear,
endYear:endYear,conference:conference},function(data)
{
bar.hideLoading();
data=JSON.parse(data);
//加載詞雲
CloudLoad(data);
bar.setOption
({
title: {
text: beginYear==endYear?beginYear:(beginYear+'~'+endYear)+'年'+conference+'熱詞TOP10'
},
xAxis: {
data: data.x
},
series: [
{
type: 'bar',
data: data.y
}]
});
});
}
通過ajax異步請求后端數據,利用Echarts組件進行熱詞統計圖表的渲染
心路歷程和收獲
ZCX:這次作業是一次全新的體驗,我還是第一次對上十萬的數據進行處理。在導入論文以及進行查詢的過程中,經歷了一次次看着頁面轉圈圈的痛苦,第一次深切地體會到“性能”兩個字意味着什么。在不斷debug、不斷修改的過程中,慢慢試着去關注性能,試着去深入代碼底層,進行調優。當論文導入時間從40分鍾改進到2分鍾的時候,真的有一種某名的快感。希望自己在未來的開發和編碼過程中,能夠不僅僅滿足於解決問題,而是追求更快、更優的解決方案。
WKJ:這是第一次寫一個項目的前端,以往都只是手敲html、css、js,這次是比較規范的寫前端,各個方面都感覺挺新的,也是第一次接觸到layui和thymeleaf。雖然是第一次,但是通過不斷查看示例,查看官方文檔,再實踐應用,還是收獲頗豐的。一邊寫一邊看一邊修改,把一個空的界面變成有東西的界面,再變成美觀的界面,還是挺有成就感的。同時也體會到結對編程的快樂,通過跟隊友的討論與交流,自身實力也得到了提高。
評價結對隊友
ZCX:這是和KJ的第二次結對合作,這一次的合作從線上轉為了線下,雙方的交流更多,也更方便了。因為在同一個宿舍,有時在睡覺前突然想到一個好點子,便會直接轉過頭來和對方分享討論,大家都在這樣的交流討論過程中開闊了思維,試着從多種角度思考問題。
KJ是一個非常有耐心、非常負責的隊友,能夠把每一項任務都完成到最好,和他合作效率很高。
WKJ:第二次結對合作,跟第一次相比,還是有不同的收獲的,首先從線上變成了線下,兩個人的交流變得更多了,而且因為第二次結對合作量比較大,合作交流顯得更為重要。在宿舍里,常常代碼打着打着,就轉頭開始討論,交換想法,在這種模式下,可以及時發現分歧並且解決。
CX是一個效率高、樂於助人的隊友,時常能提出很好的點子,跟他合作結對編程又充實又得到了成長,吸取了經驗。