團隊作業第六次—團隊Github實戰訓練
團隊名稱: 雲打印
作業要求: 團隊作業第六次—團隊Github實戰訓練
作業目標:搭建一個相對公平公正的抽獎系統,根據QQ聊天記錄,完成從統計參與抽獎人員頒布抽獎結果的基本流程。
Github地址:Github地址
團隊隊員
隊員學號 | 隊員姓名 | 個人博客地址 | 備注 |
---|---|---|---|
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訪問鏈接為: 項目運行地址
-
前端:
開發工具為PhpStorm,開發語言為Ajax、js、css、HTML,框架為boostrap;運行環境為各類瀏覽器(谷歌瀏覽器、火狐瀏覽器、IE6以上的IE瀏覽器等)
- 后端
開發工具為IntelliJ IDEA Ultimate,開發語言為java,框架為boostrap;運行環境為java環境
GUI界面
基礎功能實現
基本功能實現的核心代碼
- 抽獎
@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 內
- 從該式可以看出,該算法由於構成簡單,具有以下優點
- 計算速度快
- 易於實現
- 易於寫入硬件
二、偽隨機數算法
偽隨機數產生的方法有個逼格挺高的名字---偽隨機數發生器。偽隨機數產生器中最最最基礎的思想是均勻分布(當然這不是唯一的思路)。一般來說,只敢說"一般來說",因為我也不敢百分百肯定,如今主流的編程語言中使用的隨機數函數基本采用這種均勻分布思想,而其中最常用的算法就是"線性同余法"。
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);
}
}
附加功能實現
附加需求功能
一、聊天記錄數據分析
用戶各時間段發言統計
整體分析用戶各時間段的發言情況,統計每個用戶各個時間段的發言次數,然后以柱形圖形式展現,通過柱狀圖我們很容易得出用戶在哪些時間段發言頻率較高。
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聊天記錄數據分析
二、繪畫獲獎名單海報
1、思路分析
通過接受服務器傳來的獲獎名單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')
2、實驗結果如下
增加功能
郵件提醒
增加了對中獎學生的郵件提醒,通過處理聊天記錄中的用戶信息,獲取用戶的郵箱信息比如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,使用搜索引擎查詢,多實踐
- 依靠隊友指導,大家一起測試尋找BUG,使用搜索引擎查詢,多實踐
- 遇到的困難:
馬后炮
-
陳宇
- 如果我能力能在強一點,那么隊友就能輕松一點
- 如果我能力能在強一點,那么隊友就能輕松一點
-
陳迎仁
- 如果我學java后端的進度能更快一點,那么這次我就能獨自實踐Java后端開發以及服務器的搭建了,實現我所渴望的技術。
- 如果我學java后端的進度能更快一點,那么這次我就能獨自實踐Java后端開發以及服務器的搭建了,實現我所渴望的技術。
-
陳詩嫻
- 如果我的代碼能力能強一點,那么就能為團隊做更多事。
- 如果我的代碼能力能強一點,那么就能為團隊做更多事。
-
蔡森林
- 如果我能提前好好學python,那么我將能為我的團隊做得更多
- 如果我能提前好好學python,那么我將能為我的團隊做得更多
-
蔡鴻鍵
- 如果好好學習,那么就沒什么BUG要解決了
- 如果好好學習,那么就沒什么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 |