结对第二次作业——编程实现
这个作业属于哪个课程 | 软件工程实践-2023学年-W班 |
---|---|
这个作业要求在哪里 | 结对第二次作业——编程实现 |
结对学号 | 222100418张星航 && 222100306洪朗晨 |
这个作业的目标 | 原型设计的编码实现、Gitcode的合作使用、撰写博客 |
其他参考文献 | CSDN网站 ;bilibili; |
目录:
1. Gitcode仓库链接
2. 代码规范链接
3. PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
• Discuss | • 讨论如何实现 | 60 | 60 |
• Assign tasks | • 分配任务 | 15 | 15 |
• Understanding technology | • 了解技术 | 60 | 90 |
• Front end coding | • 前端编码 | 300 | 360 |
•Backend encoding | • 后端编码 | 300 | 320 |
• Parsing data | • 解析数据 | 60 | 40 |
• Front and rear docking | • 前后端对接 | 180 | 200 |
• Fix bug | • 解决bug | 100 | 150 |
• Review testing | • 复审测试 | 60 | 60 |
deployment server | • 部署服务器 | 60 | 80 |
• Write a blog | • 撰写博客 | 60 | 80 |
合计 | 1255 | 1455 |
4. 项目访问链接
5. 项目成品展示
根据导航栏,网页有以下页面组成:首页、运动员排名、日程展示、国家奖牌榜、详细赛况。分别用英文表示为Overview、Athlete Rank、Schedule、Medal、Detail.
成果展示
Overview-首页
首页界面内如下:展示关于世界游泳锦标赛的举办背景,通过丰富的图文使平台更具吸引力,引起人们对世界游泳锦标赛的兴趣。
Athlete Rank-运动员排名
选手排名界面 :用下拉框展示了66th International Divers’ Day Rostock的排名,包含Overall Rank,Country,Athlete,Age,Points。
Schedule-日程展示
每日赛况和比赛详情:展示比赛日期和比赛项目、类型等 鼠标可以进行日期的选择,放置在某个比赛上显示高亮,点击比赛显示比赛的详情:
Detal-详细赛况
Medel-国家奖牌榜
奖牌榜:显示各个国家的获奖情况。
6. 设计实现过程
6.1功能结构图
6.2 爬取数据
从官网上找到选手排名、每日赛况、详细赛况、奖牌榜等相应页面,利用浏览器的开发者工具,在network中爬取到了本次作业所需的数据。
说明:本次爬取行为和爬取数据仅用于学习!
6.3 前端实现过程
- 技术和框架:(本来想用vue来完成本次作业,在经过短暂学习和使用后发现过于复杂,不好上手。最后选择纯前端HTML、CSS、JS)
- 界面设计:根据原型设计以及作业要求,在原型界面的基础上进行了适当的修改。分为首页、选手排名、每日赛况、详细赛况、奖牌榜五个界面。
- 数据的获取:通过fetch函数(js),从后端传回的接口抓取数据。
6.4 后端实现过程
-
编程语言:Python
-
Web框架:Flask框架。因为本次内容专注于少量数据的读取和展示,没有过多的复杂功能,因此使用轻量级的Web框架进行开发。
-
数据来源:首先利用网页抓包爬取(具体参考文件夹中的代码:其他信息\后端处理数据等其他代码\Python_fetch_20240303_task2)网页数据
-
数据存储:因为将数据库部署到云数据库需要多余的费用,所以弃用了原来的orm映射Mysql(代码在“其他信息\后端处理数据等其他代码“中),改把爬取的数据存在csv文件中,读取文件来实现数据提取。
- 文件夹swim_cmpt对应原数据库
- 每一个csv文件对应一个表
- 每个csv文件夹的列名对应原来的字段
-
数据解析:将需要的EventName, DisciplineName, EventResultDate, HeatName, OverallRank, Country, Athlete, Age, Points, PtsBehind抓取,存在event_result(mysql表/csv)中读取json 解析json 向前端传数据等
-
数据反馈:使用 JSON 格式返回数据,支持跨域请求。
-
跨域:调试过程中出现了跨域的Cors问题,根据学习的过程在代码中增加了代理、cors允许等代码,但其实可能失败了,但原代码不敢删除,因为怕引发更大的错误。
-
主要思路:
- 后端的实现思路很简单:主要就是把数据库中的内容返回就可以。本来只需要一个函数。
- 但是为了避免重复多次查询,重新设计了表。(具体见[数据库设计](# 6.5 数据库展示))建立了多个表,表之间有多层外键的联系(但在这里没有用外键,为了方便debug,这也是一个缺点)
6.5 数据库展示
表名 | athlete_info |
---|---|
字段 | 类型 |
id | int(11) |
Country | varchar(255) |
Athlete | varchar(255) |
Gender | varchar(10) |
DOB | date |
Discipline | varchar(255) |
表名 | date_list |
---|---|
字段 | 类型 |
id | int(11) |
EventResultDate | date |
表名 | event_items |
---|---|
字段 | 类型 |
id | int(11) |
DisciplineName | varchar(255) |
EventResultDate | date |
HeatName | varchar(255) |
表名 | event_results2 |
---|---|
字段 | 类型 |
id | int(11) |
EventName | varchar(255) |
DisciplineName | varchar(255) |
EventResultDate | date |
HeatName | varchar(255) |
OverallRank | int(11) |
Country | varchar(255) |
Athlete | varchar(255) |
Age | int(11) |
Points | float |
PtsBehind | float |
表名 | medals |
---|---|
字段 | 类型 |
id | int(11) |
EventName | varchar(255) |
EventTypeName | varchar(255) |
SportCode | varchar(10) |
DisciplineCode | varchar(10) |
CountryName | varchar(255) |
Rank | int(11) |
Gold | int(11) |
Silver | int(11) |
Bronze | int(11) |
Total | int(11) |
6.6 代码部署
利用阿里云平台,将平台部署在云服务器上。
6.6.1 环境设置
// 更新
apt update
// 安装nginx 80端口,更新,安装
apt install nginx
python3
// 查看python是否正常
pip3 install –upgrade pip
pip list
//更改安装源,可跳过
// 配置虚拟环境
// 安装虚拟环境包
pip install virtualenvwrapper
ls -al
vi .bashrc
// .bashrc中插入这段
export WORKON_HOME=$HOME/.virtualenvs
VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source/usr/local/bin/virtualenvwrapper.sh
// 可能是查看一下
source ~/.bashrc
// 下面是虚拟环境中运行
cd .virtualenvs
mkdir .....//在这里建了个文件夹
【 .virtualenvs】 如果突然断线……如何快速建立虚拟环境
// 虚拟环境创建
mkvirtualenv --python=/usr/bin/python3 test_env
cd .virtualenvs
// .virtualenvs文件下是test_dev虚拟环境
workon test_dev
【srv】 找到跑代码的地方
// 退出返回到srv
cd /srv
cd test
//进入我的文件夹test
然后连接 【git】
git init
......
pull origin dev
6.6.2 云服务器服务中情况
6.6.3 开放端口
购买后,记得开放80端口、服务器运行端口等,才能够正常访问。
7. 结对讨论过程描述
由于洪朗晨同学有接触过后端的相关知识,因此我们经过讨论初步决定她写后端,我写前端(刚开始是学习使用vue框架的,后面感觉出了很多问题转用纯前端了)。
创建gitcode的dev分支,但是某条指令有问题,导致一直我无法创建dev分支,最后还是朗晨同学远程控制我的电脑,帮我解决了这个麻烦。
实现过程中的一些讨论
后端给我数据的时候我无法接收到数据,不太清楚是什么原因导致的。最后只能辛苦朗晨同学把数据传到我的前端界面,并进行一些代码修改。
8. 代码说明
8.1返回数据-Python
此处定义了获取数据路由为event_results,前端只要访问 ip/event_results,就可以从这里抓取json数据。
@app.route('/event_results', methods=['GET'])
def get_event_results():
auth_header = request.headers.get('Authorization')
date_index = int(request.args.get('date', -1)) # 获取日期索引,默认为-1
if auth_header and auth_header.startswith('Basic '):
pass
filename = 'event_results2.csv' # 默认使用事件结果文件
event_results = read_csv_file(filename)
result = []
# 如果提供了日期索引,则根据日期查询事件结果
......
# 否则全部返回
for event_result in event_results:
result.append({
'id': event_result['id'],
'EventName': event_result['EventName'],
'DisciplineName': event_result['DisciplineName'],
'EventResultDate': event_result['EventResultDate'],
'OverallRank': event_result['OverallRank'],
'Country': event_result['Country'],
'Athlete': event_result['Athlete'],
'Age': event_result['Age'],
'Points': event_result['Points'],
'PtsBehind': event_result['PtsBehind'],
'HeatName': event_result['HeatName']
})
return jsonify(result), 200
响应结果如下:
8.2 设置端口、监听
if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0", port=8001)
- 这里对 port=8001 端口进行监听
- 0.0.0.0的设置是 使得 所有主机都能访问我的服务器。这不太安全,但为了作业能被访问。更安全的做法是设置具体要访问我的电脑的ip,监听多个固定主机。
8.3 前端抓取数据-js
前端除了css外,最关键的是用fetch抓取url的数据,后续进行处理。
// 获取后端日期列表
fetch('http://8.138.122.120:8001/date_list')
.then(response => response.json())
.then(data => {
而这里有待优化的地方是 云服务器ip 最好能够输入,或更改,而不要编码进代码。否则更换服务器后必须手动更改此处代码。
8.4 容器动态创建布局-js
这里灵活的地方在于,schedule是根据数据库内容自动创建容器数量的,这很灵活(但也很负杂)。
- 首先通过date_list:获取到一共表格中有哪些日期dates
- 再从event_intems中:根据日期date查询相关的记录
- 再根据event_intems:的个数创建当日的项目个数
- 遍历所有dates如上。
这里没有页面的跳转,而是容器的变化。
function changeDate(index) {
const dateBoxes = document.querySelectorAll('.date-box');
if (index >= 0 && index < dateBoxes.length) {
dateBoxes[currentDateIndex].classList.remove('selected');
currentDateIndex = index;
dateBoxes[currentDateIndex].classList.add('selected');
// 清空结果容器内容
const resultDiv = document.getElementById('result');
resultDiv.innerHTML = '';
// 获取当前选中日期的比赛信息
const selectedDate = dateBoxes[currentDateIndex].textContent;
// 请求后端获取比赛信息
fetch('http://8.138.122.120:8001/event_items?date=' + encodeURIComponent(selectedDate))
.then(response => response.json())
.then(data => {
// 遍历比赛信息,创建信息框并填充内容
data.forEach((event, index) => {
resultDiv.innerHTML += `
<div class="info-box" οnclick="redirectToDetail('${event.DisciplineName}')">
<div class="title">${event.DisciplineName}</div>
<div class="type">${event.HeatName}</div>
<div class="time">${event.EventResultDate}</div>
</div>`;
});
})
.catch(error => {
console.error('Error fetching event items:', error);
});
}
}
9. 心路历程和收获
- 张星航的心路历程和收获:这次的作业让我感觉有点质壁分离。刚开始本来想用vue来写前端,配置好环境后学习了一下vue的使用手册,但是在实现过程发现用vue有点难,最后放弃了选择去用纯前端技术写前端界面。界面写好后跟队友的数据对接又存在问题(她的后端数据我根本获取不了),俩个人解决了好久。但是回过头想想,这次的作业也让我受益匪浅。对前端技术的认识更进一步,学会了一些环境的配置。个人作业与结对作业完全不一样,与队友的配合至关重要,遇到问题需要俩个人积极配合一起解决才能取得最后的胜利。这次的作业也让我能够在以后的团队作业中更加得心应手。
- 洪朗晨的心路历程和收获:
- 【结对编程】:在团队合作中,更能暴露自己的强弱,这种密切的连接让我们更加清楚自己技术上的不足与强项。而更重要的是,我发现在团队开发中,未必两个人技术都强大,就能做好编程,这里软件的**“软”实力**就体现。
- 【合作】我和队友优势互补,各司其职,相辅相成。在完成任务的过程中,我们都感受到了对方的不放弃和支持,这是这次作业最激动人心的地方所在。
- 【差距/分工】我和队友技术水平上有一些差距。总体来说,我们就像老师课上说的**“学-带”**模式。
- 【经验只有一点点】因为我了解过前后端交互时后端的工作,一开始分工的时候我做后端,队友做前端。
- 【不了解对接】很快,我就把需要的数据,用后端返回,并编写好了代码。
- 【前端对接】后来发现队友对前端的对接难以了解,我变便承担起了对接的工作。
- 【对接思路】我了解过思路是前端抓取后端返回的数据,并进行显示,项目便解决了。但没有实现过。
- 【前端编程】因为不了解前端编程,不得不进行一定的学习,并借助AI工具解析代码以便理解。
- 【对接调试】对接调试的阶段,既改前端,也改后端,有时候出了bug不知道是前端还是后端……但和前后端打架不同,因为自己一个人对接,让我感觉出问题的时候,沟通的压力和负担减少了,提高了效率,让我感受到了全栈工程师的好处和坏处……
- 【情绪】
- 我对数据的关注和对数据显示平台的制作充满追求,热情而兴奋。
- 或许在设计这个数据显示平台的过程中,我遇到了一些挑战,但我和队友的毅力和决心让我克服了这些困难。
- 在难以坚持下去的时候,我会想到当我最终完成了这个有用的数据显示平台,并且它能够灵活地利用数据,我会感觉一切曾经以为的灾难都是值得的。
10. 评价结对队友
张星航 To 洪朗晨:队友非常优秀,很早就接手过后端的相关项目。在前后端对接遇到问题时,她也能够非常积极帮我去解决。有想法也会跟我及时的沟通交流,询问我的意见。队友的帮助让我感受到团队的温暖。
洪朗晨 To 张星航 :队友是个全力以赴不言弃的人,在合作过程中我感觉到了巨大的鼓励和支持,不论任何问题我们都能共同分担,但希望可以多学习软件工程知识,对于基础工具的使用还不熟练,对于对接的具体实现没有机会了解,这是一个中肯的建议,希望在日后能够渐渐习得这样的知识。