結對作業二
這個作業屬於哪個課程 | https://edu.cnblogs.com/campus/fzu/FZUSESPR21 |
---|---|
這個作業要求在哪里 | https://edu.cnblogs.com/campus/fzu/FZUSESPR21/homework/11891 |
結對學號 | 221801106 、221801127 |
這個作業的目標 | 對結對作業一的建模的項目進行編程實現,實現了論文查詢,熱詞可視化統計,熱詞排行,論文增刪收藏等功能,采取web端,用到的技術是mysql+jsp+servlet |
其他參考文獻 | ... |
項目部署地址 | http://120.77.182.55:8080/demo_war_exploded 賬號:admin密碼:123456,或者可以注冊一個賬號 |
1.git倉庫鏈接和代碼規范鏈接和項目部署地址
2.PSP表格
PSP | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
---|---|---|---|
Planning | 計划 | 20 | 20 |
•Estimate | 估計這個任務需要多少時間 | 20 | 20 |
Development | 開發 | 810 | 1055 |
•Analysis | 需求分析 (包括學習新技術) | 10 | 5 |
•Design Spec | 生成設計文檔 | 30 | 20 |
•Design Review | 設計復審 | 30 | 30 |
•Coding Standard | 代碼規范 (為目前的開發制定合適的規范) | 10 | 10 |
•Design | 具體設計 | 100 | 60 |
•Coding | 具體編碼 | 500 | 700 |
•Code Review | 代碼復審 | 100 | 200 |
•Test | 測試(自我測試,修改代碼,提交修改) | 30 | 30 |
Report | 報告 | 60 | 55 |
•Test Report | 測試報告 | 30 | 30 |
•Size Measurement | 計算工作量 | 10 | 15 |
•Postmortem & Process Improvement Plan | 事后總結, 並提出過程改進計划 | 20 | 10 |
合計 | 890 | 1030 |
3.成品展示
--三張動圖分別是關於平台登入注冊界面、論文查詢收藏及刪除功能(包括熱詞搜索和用戶收藏論文的熱詞爬取)、三大分會論文熱詞可視化統計及用戶管理中心。
4.結對討論過程描述
- 剛剛拿到題目的時候,感覺挺難的,要涉及爬取,去網上找論文等等七七八八的東西,這些都還不會,就是一點構思都沒有,都得通過網絡查詢。之前第一次結對作業整的功能稍微有點多,有的功能雖然較實用,但是感覺能力有限,設計的時候先砍掉了一些,日后有空有能力再去實現。開始討論的時候根據老師的要求和推薦就打算使用最近在學的javaEE的servlet+jsp,老師之前有布置過一次相關的作業,有了解這個東西的使用(后來學習了spring框架,但是之前已經有這個方式編碼了一些)
- 討論的時候覺得也挺好分工的,一個人后端,一個人前端。作業布置后的兩三天開始開動了。當時的時候根據能力,后端決定將老師給的論文json數據解析統計並導入數據庫,因為每次調用論文都從文件取太麻煩了。前端的話采取html+css的靜態代碼加一點java。當時討論決定先分開寫,后端任務主要是論文解析,數據庫建立,還有寫論文統計和數據交互的接口;前端主要寫登入注冊界面以及用戶功能界面,等寫的差不多了再整合(這點后來在前后端交接的時候比較麻煩,出了些問題,有一說一應該完成一個模塊就交接一次比較合理)
5.設計實現過程
設計的話,前端延續上一次結對作業的建模,設計為兩個主要界面,一個是登入注冊界面,一個是用戶功能界面。功能界面采取的時候左邊菜單欄超鏈接跳轉,右邊顯示具體功能。除了開始的登入注冊界面之外,具體要實現的功能界面分為五個模塊:
-
1實現對所有論文的模糊查詢和顯示已爬取所有論文得出的十大關鍵熱詞(所有論文指代助教提供的論文文件,里面㪰一萬多篇統計好的)
-
2顯示用戶收藏的所有論文,並爬取用戶收藏的論文,獲得用戶收藏論文的十大熱詞
-
3實現三大分會議熱詞研究方向的顯示,點擊會跳轉到相關論文搜索
-
4三大會議熱詞趨勢可視化
-
5個人中心,包括一些基本信息的修改
后端的話建立了用戶數據表,以爬取的論文表,以及爬取結果表。后端代碼結構上建立
dao包/servlet包/util包/pojo(baseClass)包,分別用來存儲和數據庫查詢有關接口/前后端對接接口/工具類/自定義對象類。
-
功能結構圖
6.代碼說明
public interface UserDAO {
List<Paper> findPaper(String input) throws SQLException; //模糊查詢從論文庫里面找論文
List<Paper> findUserPaper(String username) throws SQLException; //找用戶收藏的論文
User findUser(String name,String password)throws SQLException; //找是否存在這個用戶,是的話返回用戶類,不是的話返回null
boolean InsertUser(String name,String password)throws SQLException; //插入用戶
public void updateUserInfo(List<String> keys,List<String> values,String name) throws SQLException; //修改用戶單個信息(一次性多個字段修改,名字得放最后)
public boolean UserInsertPaper(String username,int paperNumber) throws SQLException; //添加用戶收藏論文
public void UserDeletePaper(String username,int paperNumber) throws SQLException; //刪除用戶類收藏論文
public List<String> returnUserTenHotwords(String username) throws SQLException; //用來統計返回用戶收藏論文里面的十大關鍵熱詞
public void writeTenhotwordsIntoDB(List<Map.Entry<String,Integer>> tenhotwords,String type) throws SQLException; //將總的和三大會議的十大熱詞存到數據庫里面
public List<Map.Entry<String,Integer>> getTenHotwords(String type) throws SQLException; //讀取十大熱詞
}
--1上述代碼是所有有關數據庫連接交互的接口
public List<Paper> findPaper(String input) throws SQLException {//模糊查詢(目前只針對作者 )
List<Paper> papers = new ArrayList<>();
Connection connection = DBUtil.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("select * from papers where title like ? or abstract like ? or keywords like ?");
preparedStatement.setString(1,"%"+input+"%");
preparedStatement.setString(2,"%"+input+"%");
preparedStatement.setString(3,"%"+input+"%");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Paper paper = new Paper();
paper.論文名稱 = resultSet.getString("title");
paper.ID = resultSet.getInt("number");
paper.摘要 = resultSet.getString("abstract");
paper.會議和年份 = resultSet.getString("meetingtype") + " " + resultSet.getString("meetingyear");
paper.發布時間 = resultSet.getString("releasetime");
paper.原文鏈接 = resultSet.getString("link");
String[] keywords = resultSet.getString("keywords").split(",");
paper.關鍵詞 = keywords;
papers.add(paper);
}
preparedStatement.close();
connection.close();
return papers;
}
--2上述代碼段是進行論文模糊查詢的函數,依據論文的關鍵詞,標題和摘要進行模糊查詢
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
switch (request.getParameter("type")){
case "crawl_paper":{
try {
List<Paper> list = userDAO.findPaper(request.getParameter("search_all_paper").trim());
if (list.size() == 0)
list = null;
request.setAttribute("right1Search",list);
if (request.getAttribute("login_error")!=null){
System.out.println(request.getAttribute("login_error"+"!!!!!!!!!!!!!!!!!!!!!!!!!!!!"));
}
request.getRequestDispatcher("/right1.jsp").forward(request, response);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
break;
} //case結束
case "findmy_paper":{
...
break;
} //case結束
case "collect":{
...
break;
} //case結束
case "delete":{
...
break;
} //case結束
case "changeMessage":{
...
break;
}
case "changePassword":{
...
break;
}
}
}
--3和用戶功能交互的Mainservlet的結構,采取在傳來的路徑后面添加?type=XXX 的方式
public class JsonParse {//將json文件寫入數據庫
Paper paper;
JSONObject jsonObject;
String url;
int number;
public JsonParse(int number,String url){
this.number = number;
this.url = url;
}
public void testPaper() throws IOException { //獲取paper類
paper = getBean(Paper.class);
// System.out.println(paper);
}
private <T> T getBean(Class<T> t) throws IOException {
File file = new File(url);
String jsonString = FileUtils.readFileToString(file);
jsonObject = JSON.parseObject(jsonString);
return JSON.parseObject(jsonString,t);
}
public void writeDB() throws SQLException { //將文件讀入的paper類寫入數據庫
String temp[] = paper.會議和年份.split(" ");
String temp1[] = paper.關鍵詞;
StringBuffer stringBuffer = new StringBuffer();
for (String keyword : temp1){
stringBuffer.append(keyword+",");
}
String keywords = stringBuffer.toString();
Connection connection = DBUtil.getConnection();
Statement statement = connection.createStatement();
String sql = String.format("insert into papers values (%d,'%s','%s','%s','%s','%s','%s','%s')",number,paper.摘要,temp[0],temp[1],keywords,paper.發布時間,paper.論文名稱,paper.原文鏈接);
statement.execute(sql);
statement.close();
connection.close();
}
}
--上述代碼為根據制定路徑解析改路徑文件夾下所有的json文件,這個類主要是解析ECCV會議的論文json數據,這些json數據比較工整,直接建一個類用fastjson里面的JSON.parseObject()方法進行解析
<div id="main" style="width: 800px;height: 500px; float: left; margin-left: 100px;">CVPR</div>
<div id="main2" style="width: 800px;height: 500px; float: left; margin-left: 100px;margin-top: 50px">ECCV</div>
<div id="main3" style="width: 800px;height: 500px; float: left; margin-left: 100px;margin-top: 50px">ICCV</div>
<script type="text/javascript">
// 基於准備好的dom,初始化echarts實例
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
option = {
title: {
text: 'CVPR熱詞'
},
tooltip: {},
legend: {
data:['熱詞']
},
xAxis: {
data: ["<%=s1.get(0).getKey()%>","<%=s1.get(1).getKey()%>","<%=s1.get(2).getKey()%>","<%=s1.get(3).getKey()%>","<%=s1.get(4).getKey()%>","<%=s1.get(5).getKey()%>","<%=s1.get(6).getKey()%>","<%=s1.get(7).getKey()%>","<%=s1.get(8).getKey()%>","<%=s1.get(9).getKey()%>"],
axisLabel: {
interval:0,
rotate:20
}
},
yAxis: {},
series: [{
name: '熱詞',
type: 'bar',
data: [<%=s1.get(0).getValue()%>, <%=s1.get(1).getValue()%>, <%=s1.get(2).getValue()%>, <%=s1.get(3).getValue()%>, <%=s1.get(4).getValue()%>, <%=s1.get(5).getValue()%>,<%=s1.get(6).getValue()%>,<%=s1.get(7).getValue()%>,<%=s1.get(8).getValue()%>,<%=s1.get(9).getValue()%>]
}]
};
myChart.setOption(option);
</script>
<script type="text/javascript">
// 基於准備好的dom,初始化echarts實例
var chartDom2 = document.getElementById('main2');
var myChart2 = echarts.init(chartDom2);
var option2;
option2 = {
title: {
text: 'ECCV熱詞'
},
tooltip: {},
legend: {
data:['熱詞']
},
xAxis: {
data: ["<%=s2.get(0).getKey()%>","<%=s2.get(1).getKey()%>","<%=s2.get(2).getKey()%>","<%=s2.get(3).getKey()%>","<%=s2.get(4).getKey()%>","<%=s2.get(5).getKey()%>","<%=s2.get(6).getKey()%>","<%=s2.get(7).getKey()%>","<%=s2.get(8).getKey()%>","<%=s2.get(9).getKey()%>"],
axisLabel: {
interval:0,
rotate:20
}
},
yAxis: {},
series: [{
name: '熱詞',
type: 'bar',
data: [<%=s2.get(0).getValue()%>, <%=s2.get(1).getValue()%>, <%=s2.get(2).getValue()%>, <%=s2.get(3).getValue()%>, <%=s2.get(4).getValue()%>, <%=s2.get(5).getValue()%>,<%=s2.get(6).getValue()%>,<%=s2.get(7).getValue()%>,<%=s2.get(8).getValue()%>,<%=s2.get(9).getValue()%>]
}],
};
myChart2.setOption(option2);
</script>
<script type="text/javascript">
// 基於准備好的dom,初始化echarts實例
var chartDom3 = document.getElementById('main3');
var myChart3 = echarts.init(chartDom3);
var option3;
option3 = {
title: {
text: 'ICCV熱詞'
},
tooltip: {},
legend: {
data:['熱詞']
},
xAxis: {
data: ["<%=s3.get(0).getKey()%>","<%=s3.get(1).getKey()%>","<%=s3.get(2).getKey()%>","<%=s3.get(3).getKey()%>","<%=s3.get(4).getKey()%>","<%=s3.get(5).getKey()%>","<%=s3.get(6).getKey()%>","<%=s3.get(7).getKey()%>","<%=s3.get(8).getKey()%>","<%=s3.get(9).getKey()%>"],
axisLabel: {
interval:0,
rotate:20
}
},
yAxis: {},
series: [{
name: '熱詞',
type: 'bar',
data: [<%=s3.get(0).getValue()%>, <%=s3.get(1).getValue()%>, <%=s3.get(2).getValue()%>, <%=s3.get(3).getValue()%>, <%=s3.get(4).getValue()%>, <%=s3.get(5).getValue()%>,<%=s3.get(6).getValue()%>,<%=s3.get(7).getValue()%>,<%=s3.get(8).getValue()%>,<%=s3.get(9).getValue()%>]
}],
grid: {
y2: 140
},
};
myChart3.setOption(option3);
</script>
--使用echarts表格來顯示熱詞
<%
if (request.getAttribute("right1Search") == null) {
out.println("<h3 style=\"margin-left:20%;\">無搜索結果<h3>");
}
// else{
// List<Paper> list = (List<Paper>) request.getAttribute("right1Search");
// out.println("<p>"+list.size()+"</p>");
// }
else {
List<Paper> list = (List<Paper>) request.getAttribute("right1Search");
out.println("<div id = \"contentbyshearch\">");
for (int i = 0; i < list.size()&&i<20; i++){
out.println("<p style=\"color: black\">"+list.get(i).論文名稱+"</p>");
out.println("<P>");
out.println("關鍵詞:");
for (String s : list.get(i).關鍵詞){
out.println("<label style=\"background-color: #B2D235;border-radius:5px 5px 5px 5px;border:1px solid #B2D235;\">"+s+"</label>");
}
out.println("</p>");
// out.println("<p style=\"color: #D71345\">");
// out.println("摘要:"+list.get(i).摘要);
// out.println("</p>");
out.println("<p>摘要:</p>");
out.println("<p style=\"overflow-y: scroll;height: 100px;color: #D71345;border:1px solid black\">");
out.println(list.get(i).摘要);
out.println("</p>");
out.println("<p>");
out.println("<span style=\"color: goldenrod\">編號:"+list.get(i).ID+"</span>");
out.println("<span>鏈接:</span>");
out.println("<a href=\"https://arxiv.org/pdf/2103.05494.pdf\" target=\"_blank\" style=\"display: inline;background-color: white;color: blue;\">"+list.get(i).原文鏈接+"</a>");
out.println("</p>");
%>
--使用for循環在jsp中輸出搜索到的文章
7.心路歷程和收獲
- 221801127的心路歷程:第一次寫前端,心里一點底都沒有,Axure構建出來的界面即使看起來很朴素,但具體寫起來,還是有很多意想不到在的驚喜(驚嚇),由於之前Axure的界面不是按模板來的,所以前端就只能手寫了,一開始不是很熟練,一些位置啊,陰影啊,大小的使用都不熟練,很多場景下某些位置或大小屬性會比較奇怪,出乎意料,往往達不到我想象的效果,甚至根本沒有效果,但越寫到后面,越明白套路了,也越來越會偷懶了,比如一開始CSS分開寫,后來干脆不寫外部CSS文件直接style屬性改多香啊,就是復用性可讀性可修改性比較那個一點。但純寫前端心態還好,到了對接后端接口,問題就來了,一會前端顯示不太對勁,一會servlet不太對勁,一會后端函數不太對勁,一會白屏,一會500錯誤,一會突然發現前端和后端交互需要的一些參數不全,或較難傳完整,於是對接這塊花了很多時間,並且有些本來寫好的功能因為一些原因給砍了,前端后端都寫了,但出於時間和技術就未能完美實現。
- 221801127的收獲:這次結對不僅幫我的鍛煉了前端的最基礎的html和css,並且學會使用echarts。而且還加深了,前端和后端通過交互時的表單屬性和內容使用,jsp動態加載頁面內容,jsp和servlet通過request,session進行通訊交互的方法,對了除了技術上,還體會了結對編程指指點點的樂趣。
- 221801106的心路歷程:之前在java的實踐時候寫過一次后端,這一次團隊作業和結對編程也都是寫后端。感覺自己對后端的結構和邏輯還是挺清楚的。個人編程的時間開始得比較晚一點,然后集中在幾天寫完了后端的代碼,不過有一點我沒有做得好,就是服務器連接那部分沒有怎么考慮,是最后前后端都寫好了對接編程的時候一起打的,感覺這部分應該算是我的工作,或者應該要結對編程。在寫后端的時候框架和javaEE課上老師作業建立的是一樣的。寫的過程中也遇到了挺多的問題,比如數據庫非string報錯,沒有考慮讀入的字符串可能含有''。在mysql那邊出了一些錯,特別是空指針的錯誤,自己設計的邏輯真的還不夠完善。在json解析那邊也出現過json文件某個字段沒有或者結構不同的錯誤,花了挺多時間在糾錯,終歸是自己項目經驗少的原因。
- 221801106的收獲:對數據庫建表還有增刪改查更熟悉了,和數據庫有關的報錯大部分都能很快找到了。對於hashmap和list的使用印象加深,java代碼容易出現的一些bug也記住了。然后是對於jsp和servlet這種方式的構建更清晰了。自己寫后端的時候bug挺好找的,但是在前后端交接的時候出現了一些沒有考慮的問題。
8.評價結對隊友
-
22180106對221801127評價:挺負責的,會經常催我打代碼。就是有時候有點凶,太專注了沒注意隊友的感覺。主要還是我個人不太行,太菜了。
-
22180127對221801106評價:
這次感覺寫后端bug出的數量並不多,畢竟我上我肯定是一堆bug,而前端沒有這些問題,並且對接時代碼出問題一般在servlet或后端函數,所以結對對接時我態度比較嘴臭,但后端同學還是十分溫順,認真合作,他說他不太行是謙虛之語,后端看着都頭暈我上肯定不行。