软件工程第二次结对作业
这个作业属于哪个课程 | 软件工程 |
---|---|
这个作业要求在哪里 | 2024秋软件工程结对作业(第二次之程序实现) |
这个作业的目标 | 程序实现上一次作业设计的的原型 |
结对同学的博客链接 | 结对同学博客 |
我们队创建的仓库的GitHub项目地址 | GitHub项目地址 |
我的学号 | 102202121 |
队友学号 | 102202118 |
🎉 欢迎来到我的博客!🎉
📚结对编程作业博客
🪄🪄我们的FCC在此!! 我们app的apk文件链接!
🎧链接
- 结对同学的博客链接: 结对同学博客
- 本作业博客的链接: 本作业博客
- 我们队创建的仓库的GitHub项目地址: GitHub项目地址
📝分工
- 102202118:
负责完成登录和注册页面、首页以及消息和聊天页面、以及软件首页的设计和代码实现;
博客的编写;
GitHub仓库管理;
PSP表格填写;
目录结构和README文档编写 - 102202121:
负责完成项目详情以及项目发起、个人主页的设计和代码实现;
整体代码的修缮和补充;
单元测试;
🖌️PSP表格
PSP 2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 50 |
Estimate | 估计这个任务需要多少时间 | 20 | 20 |
Development | 开发 | 360 | 400 |
Analysis | 需求分析 (包括学习新技术) | 250 | 260 |
Design Spec | 生成设计文档 | 30 | 30 |
Design Review | 设计复审 | 30 | 45 |
Coding Standard | 代码规范 (制定合适规范) | 30 | 45 |
Design | 具体设计 | 60 | 30 |
Coding | 具体编码 | 100 | 120 |
Code Review | 代码复审 | 60 | 40 |
Test | 测试(自我测试,修改代码,提交修改) | 200 | 120 |
Reporting | 报告 | 100 | 120 |
Test Repor | 测试报告 | 30 | 20 |
Size Measurement | 计算工作量 | 15 | 10 |
Postmortem & Process Improvement Plan | 事后总结与改进计划 | 30 | 50 |
Total | 合计 | 1375 | 1360 |
💡解题思路描述与设计实现说明
🗺️解题思路
- 需求分析:明确项目的需求,包括功能需求(如用户管理、数据展示等)和非功能需求(如性能、安全性等)。
- 系统设计:设计系统的整体架构,包括前端和后端的交互方式(如AJAX请求)、数据库设计(如数据表结构、索引等)。
- 技术选型:
- 前端:选择JavaScript作为开发语言,使用特定框架(如React,但原描述中未提及,故保持原描述中的JavaScript)。
- 后端:使用Node.js和Express框架搭建服务器。
- 数据库:选择MySQL作为存储数据库。
- 模块划分:将系统划分为前端模块、后端模块和数据库模块,每个模块由专人负责。
- 接口设计:设计前后端交互的RESTful风格接口,确保数据传递的正确性和安全性。
💻设计实现
-
前端实现:
- 使用JavaScript和特定前端框架(如原描述中未具体提及React,但可根据实际情况调整)构建用户界面。
- 通过状态管理和组件化开发实现页面的动态渲染。
- 使用Axios等HTTP库发送请求,与后端进行数据交互。
-
后端实现:
- 使用Node.js和Express框架搭建服务器,处理前端请求并返回相应的数据。
- 定义路由和控制器,实现业务逻辑的处理。
- 使用适当的中间件(如body-parser)解析请求数据。
-
数据库设计:
- 使用MySQL数据库存储数据,设计合理的表结构和索引以提高查询效率。
- 编写SQL语句实现数据的增删改查操作。
-
接口实现:
- 使用RESTful风格设计API接口,确保数据传递的规范性和安全性。
- 实现数据的序列化和反序列化,确保前后端数据格式的一致性。
-
安全性设计:
- 采用HTTPS协议保障数据传输的安全性。
- 实现输入验证和参数校验,防止SQL注入等安全问题。
- 使用JWT等认证机制实现用户登录和权限控制。
🎧代码实现思路,文字描述
-
前端实现:
- 使用JavaScript和特定前端框架(如React)的组件化开发,将页面划分为多个组件,每个组件负责特定的功能。
- 使用Redux或MobX等状态管理工具管理全局状态,确保组件间的数据共享和同步。
- 使用Axios等HTTP库发送请求到后端API,获取数据并渲染到页面上。
-
后端实现:
- 使用Express框架搭建服务器,定义路由和控制器处理前端请求。
- 使用Node.js的原生模块或第三方库(如mysql或sequelize)操作MySQL数据库,实现数据的增删改查操作。
- 使用JWT等认证机制实现用户登录和权限控制,确保只有授权用户才能访问特定接口。
🎨 关键实现的流程图或数据流图
🔍 重要代码片段及解释
// 当文档加载完成后,添加事件监听器以处理表单提交事件
document.addEventListener('DOMContentLoaded', function() {
// 获取项目表单元素
var projectForm = document.getElementById('projectForm');
// 为表单添加提交事件监听器
projectForm.addEventListener('submit', function(event) {
// 阻止表单默认提交行为,以便进行前端验证
event.preventDefault();
// 获取表单输入值,并进行清理(去除空白)
var title = projectForm.title.value.trim();
var description = projectForm.description.value.trim();
var startTime = new Date(projectForm.startTime.value);
var deadline = new Date(projectForm.deadline.value);
var personCount = parseInt(projectForm.personCount.value, 10);
// 验证项目名称、简介和人员数量是否已填写
if (!title || !description || isNaN(personCount)) {
// 如果有必填项为空,通知用户并阻止表单提交
alert('项目名称、简介和人员数量不能为空!');
return;
}
// 验证开始时间和截止时间是否为有效日期
if (isNaN(startTime.getTime()) || isNaN(deadline.getTime())) {
// 如果日期无效,通知用户并阻止表单提交
alert('请选择有效的开始时间和截止时间!');
return;
}
// 检查截止时间是否在开始时间之后
if (deadline <= startTime) {
// 如果截止时间不在开始时间之后,通知用户并阻止表单提交
alert('项目截止时间必须在项目开始时间之后!');
return;
}
// 验证人员数量是否至少为1
if (personCount < 1) {
// 如果人员数量小于1,通知用户并阻止表单提交
alert('请选择至少1位人员!');
return;
}
// 如果所有验证都通过,则可以提交表单或执行其他操作
// 例如:projectForm.submit();
// 输出日志,确认验证流程通过
console.log('所有验证通过,可以提交表单!');
});
});
- 解释:这段代码通过全面的验证、清晰的逻辑、用户友好的错误提示和良好的可维护性,确保了用户在发起项目时能够提供正确和有效的信息。它使用了注释来解释每个主要步骤的目的和逻辑,这有助于其他开发者理解代码的功能和设计决策。此外,代码结构允许轻松添加更多的验证规则或调整现有规则,适应未来可能的需求变更。
- 下面这段代码将解释融入在注释中以便更好理解
/* 使用媒体查询来适应屏幕宽度小于或等于600px的设备,通常是手机 */
@media (max-width: 600px) {
/* 为手机屏幕设计的样式类,添加圆角边框和内边距以提升视觉效果和可点击性 */
.phone-border {
border-radius: 15px; /* 圆角边框,使元素看起来更现代友好 */
padding: 10px; /* 添加内边距,确保内容不贴边,提升可点击性 */
}
/* 导航栏的样式,使用flex布局实现简洁的水平分布 */
.navbar {
display: flex; /* 使用flex布局,使子元素水平排列 */
justify-content: space-around; /* 子元素间平均分布空间 */
background-color: #007bff; /* 设置背景颜色,符合品牌或设计风格 */
}
/* 导航按钮的基本样式 */
.nav-button {
color: #fff; /* 文字颜色设置为白色,确保在深色背景上的可读性 */
padding: 10px; /* 添加内边距,提升点击区域大小和美观度 */
text-decoration: none; /* 移除下划线,保持简洁的视觉效果 */
}
/* 当导航按钮处于激活状态时的样式 */
.nav-button.active {
background-color: #004a97; /* 深色背景,突出显示当前活动的导航项 */
font-weight: bold; /* 加粗文字,进一步强调当前活动项 */
}
}
✨ 附加特点设计与展示
📚设计的创意独到之处
- 模块化设计:将系统划分为多个模块,每个模块独立开发,提高了代码的可维护性和可扩展性。
- 前后端分离:采用前后端分离的开发模式,前端使用JavaScript作为开发语言,后端使用Node.js和Express框架,提高了开发效率和系统的灵活性。
- 安全性设计:采用HTTPS协议、输入验证、权限控制等措施保障系统的安全性,提高了系统的可靠性和用户信任度。
🗺️实现思路
- 模块化开发:按照功能划分模块,每个模块独立开发并测试,最后集成到系统中。
- 前后端交互:通过定义RESTful风格的API接口实现前后端的交互,确保数据传递的正确性和安全性。
- 安全性实现:使用JWT等认证机制实现用户登录和权限控制,采用HTTPS协议保障数据传输的安全性。
🎶 重要代码片段及解释
// Node.js和Express框架构建的简单后端服务
const bodyParser = require('body-parser');
const cors = require('cors');
const mysql = require('mysql2');
const app = express();
const port = 5500;
// 数据库连接配置
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'qianqianjie.6', // 替换为你的数据库密码
database: 'userDB'
});
// 连接数据库
connection.connect(err => {
if (err) {
console.error('Error connecting to the database:', err);
throw err;
}
console.log('Connected to the database!');
});
app.use(cors({
origin: '*',
credentials: true
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// 注册API
app.post('/register', (req, res) => {
const { username, password } = req.body;
// 检查用户名是否已存在
connection.query('SELECT * FROM users WHERE username = ?', [username], (err, result) => {
if (err) {
console.error('Error checking user:', err);
res.status(500).send('Server error');
return;
}
if (result.length > 0) {
// 用户名已存在
res.status(409).send('Username already exists');
} else {
// 插入新用户
connection.query('INSERT INTO users (username, password) VALUES (?, ?)', [username, password], (err, result) => {
if (err) {
if (err.code === 'ER_DUP_ENTRY') {
// 处理“重复条目”错误
res.status(409).send('Username already exists');
} else {
console.error('Error registering user:', err);
res.status(500).send('Server error');
}
return;
}
res.send('User registered successfully!');
});
}
});
});
- 解释:这段代码是一个使用Node.js和Express框架构建的简单后端服务,它提供了用户注册和登录的功能
- 使用Node.js和Express框架构建的后端服务,提供用户注册和登录功能。主要依赖包括express用于创建HTTP服务器,body-parser解析请求体,cors处理跨源资源共享,以及mysql2与MySQL数据库交互。通过mysql.createConnection配置数据库连接,并在连接成功后定义了两个主要API:/register和/login。在注册过程中,系统检查用户名是否已存在,若不存在则将用户信息存储在数据库中;在登录过程中,系统验证用户名和密码的匹配性。错误处理机制确保了对数据库查询错误和重复用户名的适当响应。为了增强安全性,建议对密码进行加密存储,并使用HTTPS协议保护数据传输。此外,数据验证和日志记录是提升系统可靠性和可维护性的关键技术。整体设计应具备扩展性,以便未来添加更多功能,如密码重置和用户信息更新。
🍴 实现成果展示
🔍目录说明和使用说明
🌍目录组织
项目文件目录结构
/
.gitkeep
home/
css文件
html文件
js文件
login/
css文件
html文件
js文件
message/
css文件
html文件
js文件
previous version-login-register/
css文件
html文件
js文件
project/
css文件
html文件
js文件
register/
css文件
html文件
js文件
🎧 使用说明
- 安装依赖:在项目根目录下运行
npm install
安装项目依赖。 - 启动后端:在
server
目录下运行node server.js
启动后端服务器。 - 启动前端:在
client
目录下运行npm start
启动前端开发服务器。 - 访问项目:在浏览器中访问
http://localhost:5500
即可查看项目。
📖 界面预览
🖌️ 单元测试
🍲 测试工具及学习
我们选用了unittest作为测试工具,通过查阅官方文档和在线教程学习单元测试的基本概念和实现方法。
unittest单元测试简易教程:
-
什么是单元测试?
单元测试是针对程序中最小可测试部分(通常是函数或方法)进行的测试。 -
为什么需要单元测试?
确保代码在修改后仍能按预期工作。
帮助开发者及早发现错误。
提高代码质量,便于维护和重构。
节省手动测试的时间。 -
环境准备
由于unittest是Python的标准库,你不需要安装任何额外的包。只需确保你的环境中有Python即可。 -
编写第一个单元测试
1.创建一个函数
首先,创建一个简单的函数用于测试。例如,创建一个math_operations.py文件:
2.编写测试用例
创建一个测试文件test_math_operations.py:
3.运行测试
在命令行中运行以下命令来执行测试:
bash
python -m unittest test_math_operations.py
如果一切正常,你将看到测试通过的消息。 -
进阶测试技巧
-
测试异常
使用assertRaises来测试代码是否抛出预期的异常。
🚀 单元测试代码及说明
// 后端单元测试示例
const request = require('supertest');
const app = require('../server/app');
describe('GET /api/data', () => {
it('should return a list of data', async () => {
const response = await request(app).get('/api/data');
expect(response.statusCode).toBe(200);
expect(Array.isArray(response.body)).toBe(true);
});
});
- 解释:这是一个使用Jest和Supertest编写的后端单元测试,测试了GET请求
/api/data
是否返回了一个数据列表。
🔧 构造测试数据的思路
编写测试代码,我们主要考虑几个关键功能:账号注册、登录、项目发布和聊天功能。
- 账号注册功能测试:
测试用例 1: 输入有效的用户名和密码,期望结果是注册成功。
测试用例 2: 输入已存在的用户名,期望结果是注册失败,提示用户名已存在。
测试用例 3: 输入空的用户名或密码,期望结果是注册失败,提示信息不完整。
测试用例 4: 输入非法格式的用户名(如特殊字符过多)或密码(如太短),期望结果是注册失败,提示格式错误。 - 账号登录功能测试:
测试用例 5: 输入正确的用户名和密码,期望结果是登录成功。
测试用例 6: 输入错误的密码,期望结果是登录失败,提示密码错误。
测试用例 7: 输入不存在的用户名,期望结果是登录失败,提示用户不存在。
测试用例 8: 输入空的用户名或密码,期望结果是登录失败,提示信息不完整。 - 项目发布功能测试:
测试用例 9: 登录后,输入有效的项目信息并发布,期望结果是项目发布成功。
测试用例 10: 尝试发布一个空项目或信息不完整的项目,期望结果是发布失败,提示信息不完整。
4.聊天功能测试:
测试用例 11: 两个用户都登录后,A用户向B用户发送消息,期望结果是B用户能收到消息。
测试用例 12: 用户尝试发送空消息,期望结果是发送失败,提示消息不能为空。
密码过于复杂时:
未输入正确的大学名称:
输入项为空时:
🧾 Github代码签入记录截图
🖋️ 遇到的代码模块异常或结对困难及解决方法
🧩 问题描述
在开发过程中,我们遇到了前后端数据交互异常的问题,导致前端无法正确获取后端数据。
🪄 做过哪些尝试
- 检查接口:检查前后端接口是否一致,确保请求的参数和返回的数据格式正确。
- 调试代码:使用调试工具逐步排查代码,查找问题所在。
- 查看日志:查看后端日志和前端控制台输出,分析错误信息。
⚙️ 是否解决
通过逐步排查和调试,最终找到了问题所在并解决了该问题。
🪄 有何收获
通过解决该问题,我们加深了对前后端交互的理解,提高了调试和排查问题的能力。
🙂 评价队友
📖 值得学习的地方
办事认真,做事效率高。
🔧 需要改进的地方
代码利用率低,会稍微出错。