團隊做業第六次—團隊Github實戰訓練

團隊做業第六次—團隊Github實戰訓練

團隊名稱: 雲打印
做業要求: 團隊做業第六次—團隊Github實戰訓練
做業目標:搭建一個相對公平公正的抽獎系統,根據QQ聊天記錄,完成從統計參與抽獎人員頒佈抽獎結果的基本流程。
Github地址:Github地址css

團隊隊員

隊員學號 隊員姓名 我的博客地址 備註
221600412 陳宇 http://www.cnblogs.com/chenyuu/ 隊長
221600411 陳迎仁 https://www.cnblogs.com/yinen/
221600409 蔡森林 https://www.cnblogs.com/csl8013/
221600401 陳詩嫺 https://www.cnblogs.com/orangepoem/
221600408 蔡鴻鍵 https://www.cnblogs.com/jichiwoyaochi/

組員分工及組員貢獻

隊員學號 隊員姓名 這次做業任務 貢獻比例
221600412 陳宇 項目管理、後端代碼的編寫,服務器的部署 23%
221600411 陳迎仁 後端邏輯模塊的編寫,聊天記錄過濾的處理,博客文檔的編寫 21%
221600401 陳詩嫺 編寫博客文檔結構,前端美工設計 15%
221600409 蔡森林 附加功能的實現,數據處理與挖掘、編寫附加功能部分的博客文檔 21%
221600408 蔡鴻鍵 前端代碼的編寫與設計 20%

github 的提交日誌截圖






程序運行截圖





程序運行環境

  • 本項目爲web項目,搭載在阿里雲服務器上,web訪問連接爲: 項目運行地址html

  • 前端:前端

    開發工具爲PhpStorm,開發語言爲Ajax、js、css、HTML,框架爲boostrap;運行環境爲各種瀏覽器(谷歌瀏覽器、火狐瀏覽器、IE6以上的IE瀏覽器等)java

  • 後端python

    開發工具爲IntelliJ IDEA Ultimate,開發語言爲java,框架爲boostrap;運行環境爲java環境git


GUI界面







***github

基礎功能實現

基本功能實現的核心代碼

  • 抽獎
@RequestMapping("/draw")
    public ResponseData draw(String email,String name, String document, Integer winnerNum,
                             String startTime, String endTime, String resultTime,
                             String keyWord, Integer filterType, String award,
                             HttpServletRequest request) throws ClientException, IOException, MessagingException {
        ResponseData responseData = new ResponseData();
       LotteryDrawRule lotteryDrawRule=new LotteryDrawRule(LotteryDrawFilter.getFilterTypeString(filterType),keyWord,startTime,
               endTime,resultTime, winnerNum);
        //LotteryDrawFilter lotteryDrawFilter=new LotteryDrawFilter(lotteryDrawRule,"/home/QQrecord-2022.txt");
       LotteryDrawFilter lotteryDrawFilter=new LotteryDrawFilter(lotteryDrawRule,"G:\\MyJavaWeb\\Luckydraw\\src\\main\\resources\\QQrecord-2022.txt");
       Map<String, Integer> users = lotteryDrawFilter.doFilter();
       List<User> awardUsers = LcgRandom.getResult(users,winnerNum);
       String str[] = award.split("\\,");
       int j = 0;
       for(String s : str){
           String awardName = s.split(":")[0];
           Integer awardNum = Integer.valueOf(s.split(":")[1]);
           for (int i = 0; i<awardNum;i++){
               if(j<awardUsers.size()){
                   awardUsers.get(j).setAward(awardName);
                   j++;
               }
           }
       }
       StringBuilder awardString = new StringBuilder();
       for (User u: awardUsers) {
           awardString.append(u.toString()+"\r\n");
       }
       awardString.append(" ");
       DrawLuckResult dr = new DrawLuckResult(name,document,keyWord,startTime,endTime,resultTime,winnerNum,award,
               LotteryDrawFilter.getFilterTypeString(filterType),awardString.toString());
       drawLuckResultDao.insert(dr);
       responseData.setData(dr);
       Thread t = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   StringBuilder sb = new StringBuilder();
                   for (User u: awardUsers) {
                       sb.append(u.toString()+"</br>");
                   }
                   sb.append(" ");
                   EmailUtil.send465("中獎結果","<h1>中獎結果通知</h1></br>" + sb.toString(),email);
               } catch (MessagingException e) {
                   e.printStackTrace();
               }
               for (User u: awardUsers) {
                   try {
                       String name = u.getName();
                       String email = null;
                       if(name.contains("(")){
                           email = name.substring(name.indexOf("(") +1 ,name.lastIndexOf(")"));
                           if (!email.contains("@qq.com")){
                               email += "@qq.com";
                           }
                       }else if(name.contains("<")){
                           email = name.substring(name.indexOf("<") +1 ,name.lastIndexOf(">"));
                       }
                       // System.out.println(email);
                       // 爲了避免打擾其餘人只通知本身
                       if (email.contains("947205926")){
                           EmailUtil.send465("中獎通知","恭喜" + u.getName() + "得到" + u.getAward(),"947205926@qq.com");
                       }
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
               }
           }
       });
       t.start();
        return responseData;
    }
  • Lgc隨機數
public static List<User> getResult(Map<String, Integer> users, Integer awardNum) {
        Iterator it = users.entrySet().iterator();
        List<User> listUser = new ArrayList<>();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String name = (String) entry.getKey();
            Integer weight = (Integer) entry.getValue();
            // System.out.println(name + "  " + weight);
            listUser.add(new User(name, weight));
        }
        Random random = new Random();
        // 對全部參與的用戶進行隨機排序
        Collections.sort(listUser, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return random.nextInt(2) - 1;
            }
        });
        int i = 0;
        int size = listUser.size();
        LcgRandom lcg = new LcgRandom();
        List<User> awardList = new ArrayList<>();
        if (size > 0) {
            while (i < awardNum) {
                int ran = lcg.nextInt(size);
                // 對水羣的用戶下降獲獎權重
                if (listUser.get(ran).getWeight() > 0) {
                    listUser.get(ran).setWeight(listUser.get(ran).getWeight() - 1);
                } else {
                    awardList.add(listUser.get(ran));
                    listUser.remove(ran);
                    size = listUser.size();
                    i++;
                }
            }
        }
        return awardList;
    }

LCG算法

LCG(linear congruential generator)線性同餘算法,是一個古老的產生隨機數的算法。由如下參數組成:
| 參數 | m|a | c|X|
|:---- |:---|:----- |----- |----- |
|性質 |模數 |乘數 |加數 |隨機數 |
|做用 |取模 |移位 |偏移 |做爲結果 |
LCG算法是以下的一個遞推公式,每下一個隨機數是當前隨機數向左移動 log2 a 位,加上一個 c,最後對 m 取餘,使隨機數限制在 0 ~ m-1 內web

  • 從該式能夠看出,該算法因爲構成簡單,具備如下優勢
    • 計算速度快
    • 易於實現
    • 易於寫入硬件

2、僞隨機數算法正則表達式

  僞隨機數產生的方法有個逼格挺高的名字---僞隨機數發生器。僞隨機數產生器中最最最基礎的思想是均勻分佈(固然這不是惟一的思路)。通常來講,只敢說"通常來講",由於我也不敢百分百確定,現在主流的編程語言中使用的隨機數函數基本採用這種均勻分佈思想,而其中最經常使用的算法就是"線性同餘法"。算法

  1. 什麼是線性同餘法?

  線性同餘法基於以下線性同餘方程組

  用於產生均勻型僞隨機數的線性同餘產生器(與上面的方程符號沒有對應關係)

   

  其中,a爲"乘數",b爲"增量",m爲"模數",x0爲"種子數"。

  若是產生的是區間實在(0,1)之間的,則只須要每一個數都除以m便可,即取

  

  2. 線性同餘法產生均勻型僞隨機數須要注意什麼?

   2.1)種子數是在計算時隨機給出的。好比C語言中用srand(time(NULL))函數進行隨機數種子初始化。

   2.2)決定僞隨機數質量的是其他的三個參數,即a,b,m決定生成僞隨機數的質量(質量指的是僞隨機數序列的週期性)

   2.3)通常b不爲0。若是b爲零,線性同餘法變成了乘同餘法,也是最經常使用的均勻型僞隨機數發生器。

  3. 高性能線性同餘法參數取值要求?

   3.1)通常選取方法:乘數a知足a=4p+1;增量b知足b=2q+1。其中p,q爲正整數。 PS:不要問我爲何,我只是搬運工,沒有深刻研究過這個問題。

   3.2)m值得話最好是選擇大的,由於m值直接影響僞隨機數序列的週期長短。記得Java中是取得32位2進制數吧。

   3.3)a和b的值越大,產生的僞隨機數越均勻

   3.4)a和m若是互質,產生隨機數效果比不互質好。
反正這圖我沒有發現明顯的規律。所以這種僞隨機數在必定條件下是能夠知足隨機性性質的。

聊天記錄過濾思路

  • 基本過濾:

    首先經過正則表達式進行聊天記錄的切割,分爲用戶信息和用戶聊天內容;經過用戶信息獲取用戶的ID(暱稱+帳號);根據用戶ID的開頭進行判斷是不是系統消息、助教、教師,對這三類的對象進行過濾,不參與後續的抽獎活動,實現基本過濾。

    if (Pattern.matches("系統消息\\([0-9]+\\)", userID) || Pattern.matches("教師_.*\\(.*\\)", userID)|| Pattern.matches("助教_.*\\(.*\\)", userID))
    {
         userID = null;
    }

三種過濾選擇:

  • 不過濾

    針對抽獎名單的過濾,只實現基本過濾,並不對名單進一步的進行篩選,即只去除系統消息、教師、助教這三類對象。

  • 普經過濾

    針對抽獎名單的過濾,首先實現基本過濾,去除系統消息、教師、助教這三類用戶;其次針對只發表抽獎關鍵字的對象,也進行過濾。主要經過去除聊天記錄中的關鍵字後,若是爲空,則這條消息對應的說話人則不加入待抽獎名單。

  • 深度過濾

    針對抽獎名單的過濾,首先實現基本過濾,去除系統消息、教師、助教這三類用戶;其次針對只發表抽獎關鍵字的對象,也進行過濾;而且對於聊天內容只有圖片和抽獎關鍵字的對象也進行必定抽獎機率的下降,但不進行過濾。

基本實現:

  • 讀取文件,基本過濾處理
BufferedReader bufferedReader = openFile();
        //讀取文件
        String talkContent = null;
        String temp = null;
        while ((temp = bufferedReader.readLine()) != null) {
            if (textType.equals("USER_TALK_CONTENT")) {
                if (!(isUserInfo(temp))) {
                    talkContent += temp;
                } else{
                    //判斷髮言是否有抽獎關鍵字
                    if (hasKeyWord(lotteryDrawRule.getKeyWord(), talkContent) && userID != null) {
                        talkContentFilter(talkContent);
                    }
                    talkContent = null;
                    userID = null;
                    textType = "USER_INFO";
                }
            }
            if (textType.equals("USER_INFO")) {
                userID = getUser(temp);
                if (userID != null) {
                    //去除系統消息、教師、助教
                    if (Pattern.matches("系統消息\\([0-9]+\\)", userID)
                            || Pattern.matches("教師_.*\\(.*\\)", userID)
                            || Pattern.matches("助教_.*\\(.*\\)", userID)) {
                        userID = null;
                    }
                }
                textType = "USER_TALK_CONTENT";
            }
        }
        //測試
        for (String key : users.keySet()) {
            System.out.println(key + ":" + users.get(key));
        }
        read.close();
        return users;
  • 三種過濾的處理
*
        過濾函數
        filterType=NO_FILTER:表示不過濾;全部人蔘與抽獎
        filterType=NORMAL_FILTER:表示普經過濾;過濾只有抽獎關鍵字的用戶
        filterType=DEEP_FILTER:表示深度過濾;過濾只有抽獎關鍵字的用戶或下降只有圖片+抽獎關鍵字的用戶的獲獎機率
         */
    public void talkContentFilter(String talkContent) {
        boolean flag = true;    //判斷其需不須要被過濾
        int deepNum = 0;        //知足深度過濾的次數
        //若是爲NO_FILTER;不執行任何過濾
        if ((lotteryDrawRule.getFilterType().equals("NO_FILTER"))) {
        }
        else if((lotteryDrawRule.getFilterType().equals("NORMAL_FILTER"))){
            //去除抽獎關鍵關鍵字
            talkContent = talkContent.substring(talkContent.lastIndexOf('#')+1);
            //符合NORMAL_FILTER
            if (talkContent == null || talkContent.equals("")) {
                flag = false;
            }
        }
        else{
             //去除抽獎關鍵關鍵字
            talkContent = talkContent.substring(talkContent.lastIndexOf('#')+1);
            //符合NORMAL_FILTER
            if (talkContent == null || talkContent.equals("")) {
                flag = false;
            }
            //符合DEEP_FILTER
            if (talkContent.equals("[圖片]") && lotteryDrawRule.getFilterType().equals("DEEP_FILTER")) {
                deepNum = 1;
            }
        }
        if (!users.containsKey(userID) && flag) { // 若是該用戶id未出現過且不須要過濾
            users.put(userID, deepNum); // 存入map
        }
        else if (deepNum > 0) {       //若是該用戶知足深度過濾的要求,就保存他的言論次數,用於計算機率時下降它的獲獎權值
            deepNum = (int) users.get(userID) + 1;
            users.put(userID, deepNum);
        }
    }

附加功能實現

附加需求功能

1、聊天記錄數據分析

用戶各時間段發言統計

總體分析用戶各時間段的發言狀況,統計每一個用戶各個時間段的發言次數,而後以柱形圖形式展示,經過柱狀圖咱們很容易得出用戶在哪些時間段發言頻率較高。

def get_time(self):
        times = re.findall(r'\d{2}:\d{2}:\d{2}', self.data)#提取用戶發言時間哪小時
        Xi = [time.split(":")[0] for time in times]
        sns.countplot(Xi, order=[str(i) for i in range(0, 24)])
        plt.plot()
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.title("各時間段發言統計")
        plt.xlabel("時間00:00—24:00")
        plt.ylabel("發言次數/次")
        plt.savefig(r"img\hour.png", format='png')
        plt.close()

活躍用戶的發言狀況

局部分析前五名活躍用戶的發言狀況,統計每一個用戶的發言次數,而後進行排序提取前五個活躍用戶的發言狀況,而後以折線圖的形式展示,經過折線圖咱們很容易發現這五個用戶在哪些時間段發言頻率較高。

def get_active(self):
        str_list = re.findall(r'\d{2}:\d{2}:\d{2} .*?\n', self.data)
        chat = {}
        i = 0
        for string in str_list:#提取用戶暱稱及其發言的時間段分佈
            size = len(string) - 1
            dict2 = {}
            if string[9:size] != "系統消息(10000)":
                if not chat.__contains__(string[9:size]):
                    i = i + 1
                    dict2[string[0:2]] = 1
                    chat[string[9:size]] = dict2
                else:
                    if not chat[string[9:size]].__contains__(string[0:2]):
                        chat[string[9:size]][string[0:2]] = 1
                    else:
                        chat[string[9:size]][string[0:2]] = chat[string[9:size]][string[0:2]] + 1
        dict3 = {}
        for key, dic in chat.items():#降序排序統計用戶活躍狀況
            count = 0
            for val in dic.values():
                count += val
            dict3[key] = count
        result = dict(sorted(dict3.items(), key=operator.itemgetter(1), reverse=True))
        colors = ['red', 'green', 'blue', 'orange', 'black']
        Xi = [str(k) for k in range(0, 24)]
        i = 0
        for key in result.keys():#遍歷前五名活躍用戶的發言狀況
            if i >= 5:
                break
            Yi = []
            for j in range(0, 24):
                Yi.append(0)
            for key2 in chat[key].keys():
                Yi[int(key2)] = chat[key][key2]
            plt.plot(Xi, Yi, color=colors[i], label=key)
            i = i + 1
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.xticks(range(len(Xi)))
        plt.legend()
        plt.title("活躍用戶統計")
        plt.xlabel("時間00:00—24:00")
        plt.ylabel("發言次數/次")
        plt.savefig(r"img\active.png", format='png')
        plt.close()

分析聊天記錄有效關鍵詞

對用戶聊天記錄進行有效關鍵詞提取與分析,而後對這些關鍵詞進行整合分析,繪出詞雲圖,經過詞雲圖咱們很容易得出,聊天記錄中哪些關鍵詞使用頻率較高。

def get_wordcloud(self):
        pattern = re.compile(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} .*?\(\d+\)\n(.*?)\n', re.DOTALL)
        contents = re.findall(pattern, self.data)
        word_list = []
        for sentence in contents:
            sentence = sentence.replace("[表情]", "").replace("[圖片]", "").replace("@全體成員", "")
            if sentence != "" and not sentence.__contains__("撤回了一條消息") and not sentence.__contains__("加入本羣。") and \
                not sentence.__contains__('長按複製此消息,打開最新版支付寶就能領取!') and not sentence.__contains__('請使用新版手機QQ查收紅.'):
                word_list.append(" ".join(jieba.cut(sentence.strip())))
        new_text = " ".join(word_list)
        wordcloud = WordCloud(background_color="white",
                              width=1200,
                              height=1000,
                              min_font_size=50,
                              font_path="simhei.ttf",
                              random_state=50,
                              )
        my_wordcloud = wordcloud.generate(new_text)
        plt.imshow(my_wordcloud)
        plt.axis("off")
        wordcloud.to_file(r'img\wordcloud.png')

實驗結果以下

  • PlusA.txt聊天記錄數據分析


  • PlusB.txt聊天記錄數據分析


2、繪畫獲獎名單海報

一、思路分析
經過接受服務器傳來的獲獎名單json數據,而後對json字符串進行相應的處理,提取出獲獎者的暱稱,QQ號或郵箱和獎品名稱,而後對相應的模塊進行繪畫,生成海報圖。

header = '[雲打印抽獎] QQ互動'
title = '2019年4月QQ互動獲獎名單'
chapter = ['暱稱', 'QQ號', '獎品']
string = '恭喜以上獲獎的同窗,咱們將在近期發出本次活動的獎勵,請有獲獎的同窗注意關注本平臺抽獎動態,感謝您的參與,謝謝!'
n = 19
foot = [string[i:i + n] for i in range(0, len(string), n)]

# 設置字體和顏色
font_type = r'font\my_font.ttc'
header_font = ImageFont.truetype(font_type, 40)
title_font = ImageFont.truetype(font_type, 23)
chapter_font = ImageFont.truetype(font_type, 25)
email_font = ImageFont.truetype(font_type, 18)
list_font = ImageFont.truetype(font_type, 24)
foot_font = ImageFont.truetype(font_type, 20)
header_color = '#FFFFFF'
title_color = '#EE0000'
chapter_color = '#CD3333'
list_color = '#EE2C2C'
foot_color = '#EE3B3B'

# 設置圖片
img = 'img/mode.png'
new_img = 'img/scholarship.png'  
image = Image.open(img)
draw = ImageDraw.Draw(image)
width, height = image.size

# header
header_x = 38
header_y = 880
draw.text((header_x, height - header_y), u'%s' % header, header_color, header_font)

# title
title_x = header_x + 30
title_y = header_y - 140
draw.text((title_x, height - title_y), u'%s' % title, title_color, title_font)

# chapter
chapter_x = title_x - 20
chapter_y = title_y - 40
draw.text((chapter_x, height - chapter_y), u'%s' % chapter[0], chapter_color, chapter_font)
draw.text((chapter_x + 140, height - chapter_y), u'%s' % chapter[1], chapter_color, chapter_font)
draw.text((chapter_x + 270, height - chapter_y), u'%s' % chapter[2], chapter_color, chapter_font)

# 獲取student_list
data = sys.argv[1]
contents = data.split('\\r\\n')
student_list = []
size = len(contents) - 1
for i in range(0, size):
    item = []
    if contents[i].__contains__('):'):
        nick_name = re.findall(r'(.*?)\(', contents[i])
    elif contents[i].__contains__('>:'):
        nick_name = re.findall(r'(.*?)<', contents[i])
    if contents[i].__contains__('):'):
        qq = re.findall(r'\((.*?)\)', contents[i])
    elif contents[i].__contains__('>:'):
        qq = re.findall(r'<(.*?)>', contents[i])
    reward = re.findall(r':(.*?),', contents[i])
    item.append(nick_name[0])
    item.append(qq[0])
    item.append(reward[0])
    student_list.append(item)
    
list_x = chapter_x - 20
list_y = chapter_y - 40
for student in student_list:
    for i in range(0, len(student)):
        if student[i].__contains__('@'):
            draw.text((list_x + i * 140, height - list_y), u'%s' % student[i], list_color, email_font)
        else:
            draw.text((list_x + i * 140, height - list_y), u'%s' % student[i], list_color, list_font)
    list_y = list_y - 40
    
#footer
foot_x = chapter_x - 30
foot_y = list_y - 40
for i in range(0, len(foot)):
    foot_y = foot_y - 40
    draw.text((foot_x, height - foot_y), u'%s' % foot[i], foot_color, foot_font)
draw.text((chapter_x + 30, height - (foot_y - 40)), u'%s(雲打印)' % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), foot_color, foot_font)

image.save(new_img, 'png')

二、實驗結果以下


增長功能

郵件提醒

增長了對中獎學生的郵件提醒,經過處理聊天記錄中的用戶信息,獲取用戶的郵箱信息好比qq郵箱,實現對中獎用戶的郵件提醒,提升用戶的體驗。

  • 基本實現
public class EmailUtil {
    // 發件人 帳號和密碼
    public static final String MY_EMAIL_ACCOUNT = "cy947205926@163.com";
    public static final String MY_EMAIL_PASSWORD = "**********";// 密碼,是你本身的設置的受權碼
    public static void send465(String subject,String content,String receiveEmail) throws AddressException, MessagingException {
        Properties p = new Properties();
        p.put("mail.smtp.ssl.enable", true);
        p.setProperty("mail.smtp.host", MEAIL_163_SMTP_HOST);
        p.setProperty("mail.smtp.port", "465");
        p.setProperty("mail.smtp.socketFactory.port", SMTP_163_PORT);
        p.setProperty("mail.smtp.auth", "true");
        p.setProperty("mail.smtp.socketFactory.class", "SSL_FACTORY");
        Session session = Session.getInstance(p, new Authenticator() {
            // 設置認證帳戶信息
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(MY_EMAIL_ACCOUNT, MY_EMAIL_PASSWORD);
            }
        });
        session.setDebug(true);
        MimeMessage message = new MimeMessage(session);
        // 發件人
        message.setFrom(new InternetAddress(MY_EMAIL_ACCOUNT));
        // 收件人和抄送人
        message.setRecipients(Message.RecipientType.TO, receiveEmail);
        // 內容(這個內容還不能亂寫,有可能會被SMTP拒絕掉;多試幾回吧)
        message.setSubject(subject);
        message.setContent("<h1>"+ content +"</h1>", "text/html;charset=UTF-8");
        message.setSentDate(new Date());
        message.saveChanges();
        Transport.send(message);
    }
}


遇到的困難及解決方法

  • 陳宇
    • 遇到的困難:java和python對接後端的時候出現了一些問題,部署服務器的時候遇到了一些浪費了比較多的時間。java調用shell命令出了點問題
    • 解決辦法:查詢相關資料。團隊成員一塊兒努力一塊兒解決了。

  • 陳迎仁
    • 遇到的困難:
      • 正則表達式應用不熟悉,在對於文檔的切割過程當中,常常遇到一些切割錯誤;花費了較多的時間在對聊天記錄的切割。
    • 解決辦法:
      • 經過查詢百度文檔,學習鄭重地表達式的基本語法,根據具體格式去尋找正則表達式的書寫;與團隊隊友進行商量。

  • 陳詩嫺
    • 遇到的困難:
      • 編程方面比較弱,算法單一,有不少不懂的
    • 解決辦法:
      • 作力所能及的部分

  • 蔡森林
    • 遇到的困難:對於數據分析,本身從未接觸過,不知道怎麼使用python繪製圖表;對先後端交互不是很懂;bug調試不是很熟練。
    • 解決辦法:經過網上搜索有關python繪圖知識,邊模仿邊踐行,一步一步實現聊天記錄的可視化圖表,如柱形圖,折線圖,詞雲圖和海報圖;對於先後端的交互,主要經過接口實現,以json數據格式進行數據處理;慢慢積累調bug經驗,培養獨立解決問題的能力。

  • 蔡鴻鍵
    • 遇到的困難:
      • git bash使用不便,先後端數據傳輸不順,JS參數傳輸遇到困難
    • 解決辦法:
      • 依靠隊友指導,你們一塊兒測試尋找BUG,使用搜索引擎查詢,多實踐


馬後炮

  • 陳宇

    • 若是我能力能在強一點,那麼隊友就能輕鬆一點

  • 陳迎仁

    • 若是我學java後端的進度能更快一點,那麼此次我就能獨自實踐Java後端開發以及服務器的搭建了,實現我所渴望的技術。

  • 陳詩嫺

    • 若是個人代碼能力能強一點,那麼就能爲團隊作更多事。

  • 蔡森林

    • 若是我能提早好好學python,那麼我將能爲個人團隊作得更多

  • 蔡鴻鍵

    • 若是好好學習,那麼就沒什麼BUG要解決了


PSP表格

陳宇

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 20 20
Estimate 估計這個任務須要多少時間 10 10
Development 開發 200 320
Analysis 需求分析 (包括學習新技術) 60 120
Design Spec 生成設計文檔 0 0
Design Review 設計複審 0 0
Coding Standard 代碼規範(爲目前的開發制定合適的規範) 20 30
Design 具體設計 0 0
Coding 具體編碼 160 210
Code Review 代碼複審 20 60
Test 測試(自我測試,修改代碼,提交修改) 30 120
Reporting 報告 30 40
Test Repor 測試報告 0 0
Size Measurement 計算工做量 10 10
Postmortem & Process Improvement Plan 過後總結, 並提出過程改進計劃 15 20
合計 575 960


陳迎仁

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 10 10
Estimate 估計這個任務須要多少時間 10 10
Development 開發 160 220
Analysis 需求分析 (包括學習新技術) 60 150
Design Spec 生成設計文檔 0 0
Design Review 設計複審 0 0
Coding Standard 代碼規範(爲目前的開發制定合適的規範) 5 5
Design 具體設計 0 0
Coding 具體編碼 120 160
Code Review 代碼複審 30 80
Test 測試(自我測試,修改代碼,提交修改) 40 140
Reporting 報告 40 120
Test Repor 測試報告 0 0
Size Measurement 計算工做量 10 10
Postmortem & Process Improvement Plan 過後總結, 並提出過程改進計劃 15 20
合計 500 925


陳詩嫺

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 5 10
Estimate 估計這個任務須要多少時間 0 0
Development 開發 60 60
Analysis 需求分析 (包括學習新技術) 20 40
Design Spec 生成設計文檔 0 0
Design Review 設計複審 0 0
Coding Standard 代碼規範(爲目前的開發制定合適的規範) 0 0
Design 具體設計 60 60
Coding 具體編碼 60 60
Code Review 代碼複審 10 10
Test 測試(自我測試,修改代碼,提交修改) 10 15
Reporting 報告 10 15
Test Repor 測試報告 0 0
Size Measurement 計算工做量 0 0
Postmortem & Process Improvement Plan 過後總結, 並提出過程改進計劃 10 10
合計 245 280


蔡森林

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 30 60
Estimate 估計這個任務須要多少時間 150 300
Development 開發 120 300
Analysis 需求分析 (包括學習新技術) 40 100
Design Spec 生成設計文檔 20 40
Design Review 設計複審 30 100
Coding Standard 代碼規範(爲目前的開發制定合適的規範) 10 20
Design 具體設計 40 80
Coding 具體編碼 120 300
Code Review 代碼複審 30 150
Test 測試(自我測試,修改代碼,提交修改) 30 90
Reporting 報告 20 20
Test Repor 測試報告 20 10
Size Measurement 計算工做量 15 30
Postmortem & Process Improvement Plan 過後總結, 並提出過程改進計 775 1640


蔡鴻鍵

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 30 30
Estimate 估計這個任務須要多少時間 120 300
Development 開發 120 300
Analysis 需求分析 (包括學習新技術) 40 80
Design Spec 生成設計文檔 20 20
Design Review 設計複審 20 120
Coding Standard 代碼規範(爲目前的開發制定合適的規範) 10 20
Design 具體設計 30 60
Coding 具體編碼 120 300
Code Review 代碼複審 30 120
Test 測試(自我測試,修改代碼,提交修改) 30 60
Reporting 報告 20 20
Test Repor 測試報告 20 10
Size Measurement 計算工做量 15 30
Postmortem & Process Improvement Plan 過後總結, 並提出過程改進計劃 20 40
合計 645 1510
相關文章
相關標籤/搜索