310
社区成员




这个作业属于哪个课程 | 软件工程实践-2023学年-W班 |
---|---|
这个作业要求在哪里 | 结对第二次作业——编程实现 |
结对学号 | 222100418张星航 && 222100306洪朗晨 |
这个作业的目标 | 原型设计的编码实现、Gitcode的合作使用、撰写博客 |
其他参考文献 | CSDN网站 ;bilibili; |
目录
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 |
根据导航栏,网页有以下页面组成:首页、运动员排名、日程展示、国家奖牌榜、详细赛况。分别用英文表示为Overview、Athlete Rank、Schedule、Medal、Detail.
首页界面内如下:展示关于世界游泳锦标赛的举办背景,通过丰富的图文使平台更具吸引力,引起人们对世界游泳锦标赛的兴趣。
选手排名界面 :用下拉框展示了66th International Divers’ Day Rostock的排名,包含Overall Rank,Country,Athlete,Age,Points。
每日赛况和比赛详情:展示比赛日期和比赛项目、类型等 鼠标可以进行日期的选择,放置在某个比赛上显示高亮,点击比赛显示比赛的详情:
奖牌榜:显示各个国家的获奖情况。
从官网上找到选手排名、每日赛况、详细赛况、奖牌榜等相应页面,利用浏览器的开发者工具,在network中爬取到了本次作业所需的数据。
说明:本次爬取行为和爬取数据仅用于学习!
表名 | 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.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 云服务器服务中情况
购买后,记得开放80端口、服务器运行端口等,才能够正常访问。
由于洪朗晨同学有接触过后端的相关知识,因此我们经过讨论初步决定她写后端,我写前端(刚开始是学习使用vue框架的,后面感觉出了很多问题转用纯前端了)。
创建gitcode的dev分支,但是某条指令有问题,导致一直我无法创建dev分支,最后还是朗晨同学远程控制我的电脑,帮我解决了这个麻烦。
实现过程中的一些讨论
后端给我数据的时候我无法接收到数据,不太清楚是什么原因导致的。最后只能辛苦朗晨同学把数据传到我的前端界面,并进行一些代码修改。
此处定义了获取数据路由为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
响应结果如下:
if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0", port=8001)
前端除了css外,最关键的是用fetch抓取url的数据,后续进行处理。
// 获取后端日期列表
fetch('http://8.138.122.120:8001/date_list')
.then(response => response.json())
.then(data => {
而这里有待优化的地方是 云服务器ip 最好能够输入,或更改,而不要编码进代码。否则更换服务器后必须手动更改此处代码。
这里灵活的地方在于,schedule是根据数据库内容自动创建容器数量的,这很灵活(但也很负杂)。
这里没有页面的跳转,而是容器的变化。
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" onclick="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);
});
}
}
张星航 To 洪朗晨:队友非常优秀,很早就接手过后端的相关项目。在前后端对接遇到问题时,她也能够非常积极帮我去解决。有想法也会跟我及时的沟通交流,询问我的意见。队友的帮助让我感受到团队的温暖。
洪朗晨 To 张星航 :队友是个全力以赴不言弃的人,在合作过程中我感觉到了巨大的鼓励和支持,不论任何问题我们都能共同分担,但希望可以多学习软件工程知识,对于基础工具的使用还不熟练,对于对接的具体实现没有机会了解,这是一个中肯的建议,希望在日后能够渐渐习得这样的知识。
跨域问题,加上了cors(app)就可以了
【原因】后端需要设置代理,因为
在Web开发中,浏览器会限制从一个源加载的资源与来自另一个源的资源进行交互。源是由协议(例如http或https),主机(例如worldaquatics.free.idcfengye.com),和端口号(如果有的话)组成的。如果两个页面的源不同,浏览器就会阻止它们之间的通信。这可能是由于浏览器的安全策略所致,称为"同源策略"。
在这种情况下,前端页面部署在一个源(例如localhost或127.0.0.1)上,而后端数据通过'http://worldaquatics.freeidcfengye.com/event_results' 这个URL提供,这两个源是不同的。因此,浏览器会阻止前端页面尝试从不同源的URL获取数据。
【解决】
使用代理:在你的后端服务器上设置代理,使前端页面可以通过与相同源的URL来获取数据。例如,你可以在后端设置一个路由,该路由将从'http://worldaquatics.free.idcfengye.com/event_results'获取数据并将其转发给前端页面。
【原因】
如果页面是通过本地文件系统直接打开的(即没有通过 HTTP 或 HTTPS 协议加载页面),浏览器可能会将来源设置为
'null'
,从而导致 CORS 请求失败。
【解决】一种方法是:确保页面是通过 HTTP 或 HTTPS 协议加载的,而不是直接通过文件系统打开的。
因为我其他的y页面需要其他的参数,问题是:这两个页面都调用同一个函数,而可能产生抓取的数据里面参数冗余;编写两个函数,但这样查询数据库就要两编后端冗余。如何取舍?
在设计API时,需要权衡两个方面:端点的简洁性和数据冗余。下面是两种可能的方法:
共用一个函数:
优点: 代码简洁,维护成本低,不需要重复编写相似的代码。
缺点: 数据可能存在冗余,如果多个页面只需要部分数据,那么获取整个对象可能会浪费资源。
编写两个函数:
优点: 每个页面只获取所需数据,减少了数据冗余,节省了资源。
缺点: 代码重复,维护成本较高。
如果数据冗余不是太大的问题,而且更看重代码的简洁性和维护成本,那么共用一个函数可能是更好的选择(吧)。