結對作業二


結對作業二


這個作業屬於哪個課程 2021春軟件工程實踐|S班
這個作業要求在哪里 結對作業二
結對學號 221801214、221801225
這個作業的目標 fork git倉庫、原型設計實現
其他參考文獻 CSDN、百度、b站

一.Github倉庫地址

項目github地址:https://github.com/Leizhenkang/PairProject

代碼規范: https://github.com/Leizhenkang/PairProject/blob/dev/221801214_221801225/codestyle.md


二、PSP表格

1、PSP表格

PSP Personal Software Process Stages 預估耗時(分鍾) 實際耗時(分鍾)
Planning 計划 60 50
• Estimate • 估計這個任務需要多少時間 30 20
Development 開發 1000 1200
• Analysis • 需求分析 (包括學習新技術) 1800 2000
• Team Communication • 結對討論 360 420
• Design • 界面原型設計 10 20
Reporting 報告 60 60
• Test Repor • 測試報告 30 30
• Size Measurement • 計算工作量 30 30
• Postmortem & Process Improvement Plan • 事后總結, 並提出過程改進計 120 240
• Size Measurement 合計 3380 4070

三、項目訪問鏈接

項目訪問鏈接:


四、成品展示

1.論文列表的展示: 每頁包含五篇論文,可通過點擊上下頁查看不同論文,點擊查看可顯示文章具體信息

2.論文列表題目搜索:可通過標題搜索論文,當論文標題不完整時,則會使用模糊搜索來查詢結果,返回結果以論文編號來進行排序

3.論文列表摘要搜索:通過摘要對論文進行查找(也可實現模糊搜索)

4.論文列表關鍵詞搜索:通過關鍵詞來查找論文

5.關鍵詞圖譜:展示了論文列表中出現次數最多的關鍵詞,點擊關鍵詞可展開相關論文。

6.頂會論文-年份走勢圖:趨勢圖反應三大會議不同時間提交論文數量

五、結對討論過程描述

  • 結對作業二在返校之后,因為我們在同一個宿舍,所以本次作業的交流大部分都是面對面進行的

  • 第一次討論,主要分配了本次結對的任務,決定使用前后端分離的Vue+Springboot來完成項目

  • 在對各自負責部分有稍微的了解后,又討論了數據庫如何建立的初次方案,以下是曾在ipad做過的記錄(精簡).

  • 由於結對過程中兩個人都不太熟悉github的操作,所以很多時候都是互傳代碼或項目來實現交互的,有些后悔,應該在一開始之前,就先學習git使用的...以致后面的commit次數有些集中且不足.

  • 結對的過程遇到的困難和解決方法:

    • 項目不熟悉,知識欠缺 --------花了很多時間進行學習,看視頻(可見b站網頁歷史記錄一排下來的Springboot 和Vue.....)

    • 對爬蟲技術的不了解 ------- 用助教爬取的數據建立數據庫

    • 前端界面沒有使用組件,常常因為樣式是否美觀,合理而重新設計,最后在不斷地改變之后,與我們第一次的原型設計稍微有些偏差。

    • 后端在寫關鍵詞搜索的時候沒有找到合適的算法,效率低下。 ------自學以及請教大佬。


六.設計實現過程

項目技術:采用前后端分離Vue+SpringBoot

功能結構圖

設計思路:

  • 數據庫:數據庫表實現較為簡單,分為paper論文表,存儲論文列表所需相關信息;keyword表,當中存儲關鍵詞內容,以及關鍵詞id和論文paper_id,多對多關系;還有一張keyword_count記錄改關鍵詞出現次數,以供關鍵詞圖譜功能實現的便利。

  • .前端項目結構圖: Addpaper.vue 查看頁面的組件, Echartstest.vue 熱詞分析圖譜的組件 ,HdView.vue 導航欄組件 , Laa.vue Element-Ui引入的下拉選擇框組件 , PaperItem.vue顯示單篇文章的組件 ,ShowView顯示一頁文章的組件以及換頁等方法 , Trend.vue 趨勢圖組件,折線圖 , index,js 路由配置 , App.vue 渲染主頁面

  • 后端項目結構圖:按照接口要求設計, 1.建立實體類(entity),跟數據庫表字段保持一致 。 2. 2.建立mapper接口,定義要操作數據庫的動作 。 3.建立mapper的xml文件,寫具體的sql語句 。 4.建立service類,處理業務邏輯 5.在controller類展示處理的結果 。 不過由於對整個SpingBoot不是很理解,寫到后面對數據庫進行操作的時候就按原生方式寫了,熟悉之后會組件按照這個接口設計來寫接口的。


七.關鍵代碼展示

  • 利用axios get方法調用后端接口,並且處理后端數據,利用循環將取出的最多十個關鍵字存儲到前端並且渲染
 mounted() {
    const _this = this;
    axios({
      url: "http://localhost:8080/keyword",
    }).then((res) => {
      for (let i = 0; i < 10; i++) {
        // console.log(res.data[i].count);
        // console.log(res)
        _this.data2[i] = res.data[i].count;
        _this.data1[i] = res.data[i].content;
      }
      console.log(_this.data1);
      console.log(_this.data2);
      this.drawLine();
    });
    // this.$nextTick(this.drawLine());
  },
  • 導航欄的html,利用了vue.js的路由鏈接

    <template>
      <div class="header">
        <div class="logo">
          <img
            src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=4090351118,2973307229&fm=26&gp=0.jpg"
            alt=""
          />
          <div class="text">論文系統</div>
        </div>
        <div class="nav">
          <router-link to="/show">論文列表</router-link>
          <router-link to="/echar">熱詞分析</router-link>
          <router-link to="/trend">趨勢圖</router-link>
        </div>
      </div>
    </template>
    
  • 用$router.relace跳轉頁面,點擊查看按鈕可以查看單獨一篇文章,傳遞當前循環的參數進去,以便渲染查看頁面

  methods: {
    deleted() {
      location.reload();
    },
    See(e) {
      window.location.href = e;
    },
    change: function () {
      this.$router.replace("/add");
      this.$nextTick(() => {
        eventVue.$emit("aa", this.itemObj);
      });
    },
    mounted() {
      eventVue.$on("ak", (message) => {
        this.itemObj = message;
        console.log(this.itemObj);
      });
    },
  },
  • 滾動事件的綁定,實現換頁自動滾動到頭部

      mounted() {
        //此處true 需要加上 不加滾動事件可能綁定不成功
        window.addEventListener("scroll", this.handleScroll, true);
        if (this.searchtext != null) {
          this.searchtext = this.$route.params.id;
        }
      },
      handleScroll() {
          let scrolltop =
            document.documentElement.scrolltop || document.body.scrollTop;
          scrolltop > 30 ? (this.gotop = true) : (this.gotop = false);
        },
    
  • 渲染列表頁面的參數接受和數據導入,判斷是否從熱詞分析點擊事件過來,接受熱詞點擊頁面的參數,可以用來實現熱詞分析中點擊關鍵詞直接跳轉到展示頁面並且搜索該關鍵詞的論文

      created() {
        axios({
          url: "http://localhost:8080/changepage",
        }).then((res) => {
          this.listArr2 = res.data;
          this.listArr1 = this.listArr2.slice(0, 5);
          if (this.searchtext != null) {
            this.value = "關鍵詞";
            this.selectwhat = 3;
            this.search1();
          } else {
            this.selectwhat = 1;
          }
        });
      }
    
  • 查找和搜索的功能實現,使用過濾器實現模糊搜索,直接使用前端實現.使用slice函數取出一頁的數據來實現換頁,首次加載頁面的時候取出所有的內容放在一個data里,每次分頁調取另外五條內容

        search1() {
          this.current = 1;
          console.log(this.value);
          if (this.value == "題目") {
            this.selectwhat = 2;
            this.listArr1 = this.listArr2
              .filter((item, index) => item.title.includes(this.searchtext))
              .slice(0, 5);
          } else if (this.value == "摘要") {
            this.selectwhat = 3;
            this.listArr1 = this.listArr2
              .filter((item, index) => item.abstracted.includes(this.searchtext))
              .slice(0, 5);
          } else if (this.value == "關鍵詞") {
            console.log(this.value);
            this.selectwhat = 4;
            this.listArr1 = this.listArr2
              .filter((item, index) => item.keyword.indexOf(this.searchtext) > -1)
              .slice(0, 5);
          }
        },
        nextpage() {
          let top = document.documentElement.scrollTop || document.body.scrollTop;
          //實現滾動效果
          const timeTop = setInterval(() => {
            document.body.scrollTop = document.documentElement.scrollTop = top -= 50;
            if (top <= 0) {
              clearInterval(timeTop);
            }
          }, 10);
          this.current++;
          if (this.selectwhat == 1) {
            this.listArr1 = this.listArr2.slice(
              this.current * 5 - 5,
              this.current * 5
            );
          } else if (this.selectwhat == 2) {
            this.listArr1 = this.listArr2
              .filter((item, index) => item.title.includes(this.searchtext))
              .slice(this.current * 5 - 5, this.current * 5);
          } else if (this.selectwhat == 3) {
            this.listArr1 = this.listArr2
              .filter((item, index) => item.abstracted.includes(this.searchtext))
              .slice(this.current * 5 - 5, this.current * 5);
          } else {
            this.listArr1 = this.listArr2
              .filter((item, index) => item.keyword.indexOf(this.searchtext) > -1)
              .slice(this.current * 5 - 5, this.current * 5);
          }
        },
    
  • 接收參數來構造年份趨勢圖的折線圖

      mounted() {
        const _this = this;
        axios({
          url: "http://localhost:8080/magazine",
        }).then((res) => {
          let j = 0;
          let m = 0;
          let l = 0;
          for (let i = 1; i < 36; i++) {
            if (res.data[i].magezine == "ICCV") {
              _this.data2[j] = res.data[i].publication_year - 0;
              _this.data1[j] = res.data[i].number;
              j++;
            } else if (res.data[i].magezine == "ECCV") {
              _this.data3[m] = res.data[i].number;
              _this.data4[m] = res.data[i].publication_year - 0;
              m++;
            } else if (res.data[i].magezine == "CVPR") {
              _this.data5[l] = res.data[i].number;
              _this.data6[l] = res.data[i].publication_year - 0;
              l++;
            }
            _this.datax = _this.data6;
            _this.datay = _this.data5;
          }
          console.log(_this.data5);
          console.log(_this.data6);
          this.$nextTick(function () {
            this.drawLine("main");
          });
        });
      },
    
  • 點擊切換不同會議的折線圖曲線

    clickEC() {
          this.datax = this.data4;
          this.datay = this.data3;
          this.msg="ECCV論文年份趨勢圖";
          this.$nextTick(function () {
            this.drawLine("main");
          });
        },
        clickIC() {
          this.datax = this.data2;
          this.datay = this.data1;
          this.msg="ICCV論文年份趨勢圖";
          this.$nextTick(function () {
            this.drawLine("main");
          });
        },
        clickPR() {
          this.datax = this.data6;
          this.datay = this.data5;
          this.msg="CVPR論文年份趨勢圖";
          this.$nextTick(function () {
            this.drawLine("main");
          });
        },
      },
    
  • 熱詞分析的接口,keyword_count表中存放了每個關鍵字的數量,利用sql語句進行排序,可以獲取前十個(也可以使用limit直接獲取)

        @CrossOrigin(origins = "*",maxAge = 3600)
        @RequestMapping("keyword")
        public List<Keyword> getKeyword(){
            return keywordService.findTopten();
          
         <select id="findTopten" resultType="jiekou.demo.entity.Keyword">
            SELECT keyword_count_id,keyword,count FROM keyword_count ORDER BY count DESC
        </select>
    
  • 趨勢圖接口, 返回三個參數的List列表,使用數據庫group by

    	@CrossOrigin(origins = "*",maxAge = 3600)
        @RequestMapping("/magazine")
        public List<Magazine> getMagezineAll(){
            return magazineService.findmagazine();
            @CrossOrigin(origins = "*",maxAge = 3600)
        @RequestMapping("/paperkey")
        public List<Paperkey> getPaperkey() {
            return paperkeyService.findAll();
        }
        <select id="findmagazine" resultType="jiekou.demo.entity.Magazine">
            select magazine,count(*) as number,publication_year from paper group by 			magazine,publication_year ORDER BY publication_year ASC
        <select>
    
  • 返回所有關鍵詞以及對應的論文id

        @CrossOrigin(origins = "*",maxAge = 3600)
        @RequestMapping("/paperkey")
        public List<Paperkey> getPaperkey() {
            return paperkeyService.findAll();
        }
    
  • 返回所有文章

        @RequestMapping("/paper")
        public List<Paper> getPaper(){
            return paperService.findAll();
        }
    
  • 返回所有文章內容接口

        @CrossOrigin(origins = "*",maxAge = 3600)
        @GetMapping("/changepage")
        public List<PaperKeyword> getPaging(){
            List<Paperkey> paperkeys=paperkeyService.findAll();
            List<Paper> papers=paperService.findAll();
            List<PaperKeyword> paperKeywords=new ArrayList<>();
            Paper paper=new Paper();
            int q=0;
            for(int i=0;i<papers.size(); i++){
                List<String> s=new ArrayList<>();
                paper=papers.get(i);
                while(paper.getPaper_id()==paperkeys.get(q).getPaper_id()){
                    s.add(paperkeys.get(q).getWord());
                    q++;
                }
                PaperKeyword paperKeyword=new PaperKeyword(paper.getPaper_id(),paper.getTitle(),paper.getLink(),paper.getPublication_year(),paper.getMagazine(),paper.getAbstracted(),s);
                paperKeywords.add(paperKeyword);
            }
            return paperKeywords;
        }
    

八.心路歷程與評價

1、心路歷程與收獲

雷振康的感受: 首先感受就是之前掌握的東西太少了,這次結對作業先是去學習了vue.js框架的應用,然后看着視頻學了幾天開始寫這次的前端,一開始只覺得vue.js框架只是對dom操作的一些簡化,並沒有感覺很好用,然后寫一半的時候發現了可以利用element ui來實現一些功能,會更加的方便,然后就是后端的學習,因為在團隊作業中我負責的是后端,所以也學習了一些后端的東西,就是感覺配置maven有點問題,會經常一直下載同一些jar包,導致項目導不進去,然后springboot的數據庫操作我不是特別熟練,不知道多表連接應該如何去創建一個實體類,這次時間不太夠,下次團隊作業應該就會學習好這些操作了。

李進明的感受:對這次結對作業最大的感受是無力,之前並沒有參與過前后端分離開發項目,在作業發布初期對整個項目束手無策。在項目開發過程中,得一邊學習新的知識,一邊運用知識,在這個部分體會到對一個知識點要做到依葫蘆畫瓢,必須要掌握基礎知識點,這又讓我覺得大一大二的時光過得太輕松,以至於許多比較基礎的知識都沒能運用起來。不過很感謝這次能有一個結對伙伴,在他進行自己任務比較順利的時候,能抽出空來幫助我,這讓我再次感受到結對作業的作用。整次的結對作業下來,我對后端開發有了比較初步的了解,同時明白了笨鳥還得先飛,在自己基礎比較差的情況下,就得更先一步去學習別人已經掌握的知識,這樣才能在整個團隊協作中不總是掉隊,拖后腿。


2.結對評價

雷振康對李進明的評價; 因為是舍友,所以這次結對編程比較方便,可以在凌晨兩三點還在一起打代碼,然后可以起到一些督促的作用,可以叫他起來學習,並且修改前后端的接口的時候也比較方便,隨時更改需求。

李進明對雷振康的評價:很感謝伙伴在這次結對作業對我的幫助,如果有一個詞說明在這次結對作業中振康的角色,那就是“全棧開發者”。在這次結對作業中,振康很勤奮,能比我早進行項目的開發,還有着比我更扎實的基礎,有些我這邊出現bug的時候都是振康幫忙調試出來的。一方面,如果可以的話,我希望振康能在這次結對作業中拿到更高的分數占比,感謝他在這次結對的辛苦付出。另一方面,振康有時也會說玩笑話刺激我,顯著起到了督促我的作用。在這里,我希望能有一天,我能做得更好,對着振康說“你求我,我就教你”(doge)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM