软件工程第二次结对作业
ProjectPartner
这个作业属于哪个课程 | fzu-se2024 |
---|---|
这个作业要求在哪里 | 要求 |
这个作业的目标 | 熟悉使用GitHub版本控制进行多人开发,学习前后端技术,了解一个软件开发的流程 |
学号 | 102201331 |
结对同学的博客链接
本作业博客的链接
GitHub项目地址
具体分工
在本项目中,我们采用了前后端分离的开发模式,团队成员根据各自的专长和技能进行了明确的分工。以下是团队成员的具体分工情况:
后端开发
负责人:黄宇舟
- 框架搭建:使用 Flask 框架搭建后端服务,包括初始化项目结构、配置数据库连接等。
- API 设计:包括路由、请求方法、参数、响应格式等。
- 数据库操作:负责数据库模型的创建、数据迁移、以及数据的增删改查操作。
- 业务逻辑实现:编写业务逻辑代码,包括用户认证、项目管理、消息处理等。
- 测试:编写后端单元测试,确保代码质量和功能正确性。
前端开发
负责人:施靖杰
- 页面设计:负责前端页面的设计,包括布局、样式、交互等。
- 页面实现:使用 HTML、CSS 和 JavaScript 等技术实现前端页面。
- API 调用:负责调用后端 API,处理数据的获取、提交等。
- 用户体验优化:关注用户体验,优化页面加载速度、交互反馈等。
- 测试:进行前端单元测试和集成测试,确保页面功能正确性。
- 部署:负责将前端代码部署到静态文件服务器或 CDN。
通过这种分工,我们确保了项目的高效推进。后端开发者专注于服务器、数据库和 API 的实现,而前端开发者则专注于用户界面和用户体验的优化。这种分工模式不仅提高了开发效率,还有助于提高代码的质量和可维护性。
PSP表格
工作描述 | 预期完成时间(h) | 实际完成时间(h) |
---|---|---|
需求分析 | 5 | 5 |
生成设计文档 | 3 | 2 |
页面设计 | 4 | 5 |
接口设计 | 3 | 3 |
路由设计 | 2 | 2 |
代码编写 | 15 | 18 |
前后端联调 | 4 | 5 |
测试 | 5 | 6 |
代码修改 | 3 | 4 |
目录整理 | 1 | 1 |
事后总结 | 2 | 2 |
总计 | 42 | 48 |
解题思路描述与设计实现说明
- 代码实现思路及重要代码与解释
1. 项目结构与初始化
首先,我们创建了一个 Flask 蓝图 main
,用于组织和注册项目的路由。这有助于将应用的不同部分分离开来,提高代码的可维护性。
main = Blueprint('main', __name__)
2. 用户会话管理
我们使用 Flask 的 session
对象来管理用户的登录状态。在 load_user_avatar
函数中,我们根据用户的 username
从数据库中获取用户信息,并将其 ID 和头像 URL 存储在 g
对象中,以便在请求处理过程中使用。
@main.before_request
def load_user_avatar():
if 'username' in session:
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute("SELECT * FROM users WHERE username = %s", (session['username'],))
user = cursor.fetchone()
g.userid = user['id']
g.avatar_url = user['img'] or url_for('static', filename='images/avatar.png')
3. 登录与注册
我们提供了注册和登录的路由。在注册路由中,我们检查用户名是否已存在,如果不存在,则将新用户信息插入数据库。在登录路由中,我们验证用户名和密码,如果验证成功,则在 session
中记录用户的登录状态。
@main.route('/register', methods=['GET', 'POST'])
def register():
# 注册逻辑
@main.route('/login', methods=['GET', 'POST'])
def login():
# 登录逻辑
4. 主页与项目展示
在主页路由中,我们展示了所有项目的信息。如果用户未登录,则重定向到登录页面。对于每个项目,我们使用 GROUP_CONCAT
函数来获取项目成员的名单。
@main.route('/')
def home():
# 获取项目列表并渲染主页
5. 个人项目页面
在个人项目页面中,我们展示了用户作为负责人的所有项目。这通过在查询中添加 WHERE
子句来实现,以过滤出用户负责的项目。
@main.route('/myprojects')
def myprojects():
# 获取用户负责的项目列表
6. 退出登录
退出登录路由中,我们从 session
中移除用户名,以注销用户的登录状态,并重定向到登录页面。
@main.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('main.login'))
7. 用户个人主页
在用户个人主页中,我们展示了用户的详细信息,包括邮件地址和日程安排。日程安排以逗号分隔的字符串形式存储在数据库中,在这里我们将其分割成列表。
@main.route('/myhome')
def myhome():
# 获取用户信息并渲染个人主页
8. 更新用户信息
用户可以通过一个表单提交新的邮件地址和日程安排。我们在后端接收这些数据,并更新数据库中的用户信息。
@main.route('/update_profile', methods=['POST'])
def update_profile():
# 更新用户信息
9. 创建项目
用户可以创建新项目,填写项目名称、类型、描述等信息。创建项目后,项目负责人自动成为项目成员。
@main.route('/createproject', methods=['GET', 'POST'])
def createproject():
# 创建新项目
10. 查看项目详情
我们提供了一个路由来查看项目的详细信息,包括项目成员列表。
@main.route('/project/<int:project_id>')
def project(project_id):
# 获取项目详情
11. 加入项目
用户可以申请加入项目。我们通过一个 AJAX 请求将用户的申请信息发送到服务器,并在数据库中记录这些申请。
@main.route('/joinproject', methods=['POST'])
def joinproject():
# 用户申请加入项目
12. 编辑和更新项目
项目负责人可以编辑项目信息。我们在后端接收这些数据,并更新数据库中的项目信息。
@main.route('/editproject/<int:project_id>', methods=['GET', 'POST'])
def editproject(project_id):
# 编辑项目信息
@main.route('/updateproject/<int:project_id>', methods=['POST'])
def updateproject(project_id):
# 更新项目信息
13. 管理项目成员
项目负责人可以查看项目的申请列表,并决定是否接受新的项目成员。我们提供了一个路由来处理这些操作。
@main.route('/newpartner/<int:project_id>')
def newpartner(project_id):
# 项目负责人查看项目申请列表
@main.route('/accept_application', methods=['POST'])
def acceptapplicant():
# 接受项目申请
14. 删除项目
项目负责人可以删除项目。我们在后端接收项目 ID,并从数据库中删除相应的项目和成员信息。
@main.route('/deleteproject/<int:project_id>')
def deleteproject(project_id):
# 删除项目
这些路由和逻辑共同构成了一个完整的项目管理系统,包括用户认证、项目创建、项目成员管理等功能。
- 流程图
附加特点设计与展示
1.个人主页的个人偏好
- 设计的意义:这个设计使用户的个人偏好能够清晰展示给负责人,帮助他们更好地了解申请人的兴趣领域,匹配合适的项目或比赛任务。
- 实现思路:用户的偏好(如喜欢的比赛类型或科研项目种类)以标签形式动态展示,标签可以使用不同的颜色来区分类型。通过 JavaScript 动态生成偏好标签,可以根据用户的实际偏好展示不同的标签内容。
- 代码片段:
<!-- 个人偏好部分 -->
<h2>个人偏好</h2>
<div id="preferences">
<!-- 偏好标签将在此处生成 -->
</div>
// 动态生成个人偏好标签
const preferencesContainer = document.getElementById('preferences');
applicantData.preferences.forEach(function(preference) {
const preferenceTag = document.createElement('span');
preferenceTag.textContent = preference;
preferenceTag.classList.add('preference-tag');
preferencesContainer.appendChild(preferenceTag);
});
- 实现成果展示
2.项目进度追踪
- 设计的意义:项目进度追踪可以帮助用户直观地了解各个项目的完成情况和进展,方便项目负责人或团队成员及时了解项目的当前状态、完成率及剩余任务,提升管理效率。
- 实现思路:每个项目的展示部分将包含一个进度条,显示项目的整体进度百分比。可以为每个项目的关键任务列出任务列表,并标记任务的完成状态。进度条和任务状态将根据任务的完成情况自动更新。
- 代码片段
<!-- 项目进度条 -->
<div class="progress-bar">
<div class="progress" id="progress1"></div>
</div>
<p>进度:<span id="progressText1">50%</span></p>
<!-- 任务列表 -->
<h3>任务进度</h3>
<ul class="task-list">
<li>
<input type="checkbox" id="task1" checked disabled>
<label for="task1">完成文献综述</label>
</li>
<li>
<input type="checkbox" id="task2">
<label for="task2">设计实验方案</label>
</li>
<li>
<input type="checkbox" id="task3">
<label for="task3">编写代码实现</label>
</li>
<li>
<input type="checkbox" id="task4">
<label for="task4">撰写研究报告</label>
</li>
</ul>
<script>
// 模拟项目数据
const projectData = {
tasksCompleted: 1,
totalTasks: 4,
progress: function() {
return (this.tasksCompleted / this.totalTasks) * 100;
}
};
// 更新进度条和文本
const progressElement = document.getElementById('progress1');
const progressText = document.getElementById('progressText1');
// 设置进度条宽度
const progressPercentage = projectData.progress();
progressElement.style.width = progressPercentage + '%';
progressText.textContent = progressPercentage + '%';
</script>
目录说明和使用说明
- 目录说明
目录栏有项目大厅、项目管理、我的、注销。
项目大厅可以浏览所有创建的项目,并点击查看项目详情及申请加入项目。
项目管理可以查看自己创建的项目,对自己创建的项目进行管理。
我的里面可以更改个人信息等。
注销即退出当前账号。 - 使用说明
README.md
单元测试
单元测试是软件开发中的一种重要实践,它有助于确保代码的每个部分按预期工作。在本项目中,我们使用 Python 的 unittest
框架来进行单元测试。
测试工具选择与学习方法
测试工具:
- 我们选择了 Python 标准库中的
unittest
框架作为我们的测试工具,因为它是 Python 内置的,不需要额外安装,且功能强大,足以满足我们的需求。
学习方法:
- 通过 GPT(如我这样的人工智能助手)和网络博客,我们学习了如何编写和运行单元测试。
- 我们阅读了官方文档和社区提供的教程,这些资源为我们提供了关于如何使用
unittest
框架的详细指导。
单元测试代码与说明
class ProjectTestCase(unittest.TestCase):
def setUp(self):
# 设置测试环境,创建测试客户端和数据库
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
self.app = app.test_client()
self.app.testing = True
with app.app_context():
db.create_all()
def test_create_project(self):
# 测试创建项目
with self.app as c:
# 登录测试用户
c.post('/login', data={'username': 'testuser', 'password': 'password123'})
# 创建项目
response = c.post('/createproject', data={
'manager': 'testuser',
'project-name': 'Test Project',
'category': 'competition',
'description': 'Test project description',
'participants': '2',
'participants-number': '5',
'image': ''
})
self.assertEqual(response.status_code, 302) # 检查是否重定向到主页
在这个测试用例中,我们首先在 setUp
方法中设置了测试环境,包括创建测试客户端和数据库。然后,我们编写了 test_create_project
方法来测试创建项目的路由。在这个方法中,我们首先模拟用户登录,然后提交创建项目的请求,并检查响应状态码是否为 302(重定向)。最后,在 tearDown
方法中,我们清理了测试环境,删除了测试数据。
构造思路
- 为每一个路由单独设计一个单元测试:这样做可以确保每个路由的功能都被独立地测试,这有助于在代码更改时快速定位问题。
- 结构清晰:每个测试用例都遵循相同的结构,这使得测试代码易于理解和维护。
- 容易实现且容易定位代码错误的地方:通过模拟不同的请求和检查预期的响应,我们可以轻松地验证代码的行为是否正确,并且在测试失败时,可以快速定位到问题所在。
通过这种方法,我们可以确保我们的应用在开发过程中的每个阶段都保持高质量和稳定性。单元测试为我们提供了一个安全网,使我们能够自信地进行代码重构和功能添加。
GitHub签入截图
遇到的困难和解决方法
问题描述
在项目开发初期,我面临了几个主要困难:
- 缺乏后端开发基础,对如何搭建和维护后端服务一无所知。
- 对网页开发流程不熟悉,不清楚如何将设计转化为实际的网页。
- 不了解前后端分离的开发模式,以及如何在这种模式下进行有效的协作。
尝试
为了解决这些问题,我采取了以下措施:
- 自学后端开发:我在 B 站上搜索并观看了相关的视频教程,这些教程涵盖了从基础的 Python 和 Flask 框架使用,到数据库操作和 API 设计的各个方面。
- 咨询有经验的人:我向有后端开发经验的学长和同学咨询,了解他们的开发流程和最佳实践,从他们的经验中学习。
- 研究现有文档:我查看了一些简单网页的 HTML 文档,以了解前端是如何组织的,以及如何通过 CSS 和 JavaScript 来增强页面的交互性。
- 利用 AI 生成框架:我借助 AI 工具生成了一个基本的后端框架,这个框架为我提供了一个起点,我在此基础上加入了个性化的设置,并进行了拓展。
是否解决
通过上述努力,我成功地克服了最初的困难,不仅建立了一个基本的后端服务,还学会了如何在前后端分离的模式下进行开发。这不仅解决了我的问题,还为我未来的项目打下了坚实的基础。
收获
通过这个过程,我获得了以下收获:
- 后端开发技能:我学会了如何使用 Flask 框架来创建后端服务,以及如何设计和实现 RESTful API。
- 网页开发流程:我了解了从设计到实现的整个网页开发流程,包括 HTML、CSS 和 JavaScript 的使用。
- 前后端分离的理解:我深入理解了前后端分离的开发模式,以及如何在这种模式下有效地进行前后端的协作。
- 自学能力的提升:我提高了自己的自学能力,学会了如何快速地学习新技术和解决问题。
- 项目经验:我积累了实际的项目经验,这将对我的未来职业发展大有裨益。
评价队友
施靖杰:前端开发
值得学习的地方:
- 创新思维:施靖杰在前端设计上总是能够提出创新的想法,使界面更加直观和友好。
- 用户体验:他对用户体验有着深刻的理解,注重细节,不断优化交互设计,提升用户满意度。
- 自我驱动:他有很强的自我驱动力,总是能够主动学习新技术,并将其应用到项目中。
需要改进的地方:
- 代码复用:在开发过程中,有时会重复编写相似的代码,可以通过提高代码复用率来提升开发效率。
- 压力管理:在项目压力大时,有时会显得有些焦虑,建议他学习一些放松的技巧,不要过度焦虑,以保持良好的工作状态。