832301320陶炯assignment1

832301320陶炯 2025-11-09 18:05:22

前后端分离通讯录开发

姓名:陶炯 FZU学号:832301320

发布时间:2025-11-09
所属课程:EE308FZ[A] — Software Engineering
作业要求:需采用前后端分离架构实现联系人添加、修改、删除核心功能(数据存储于后端数据库),支持多可视化技术选型,代码分仓托管至 Github 并遵循规范,需完成博客撰写与云服务器部署。
本次作业目标:掌握前后端分离开发与数据交互逻辑,熟练运用版本控制工具与云部署流程,培养标准化编码与文档撰写能力。

目录

目录

  • 前后端分离通讯录开发
  • 一、作业基础信息
  • 二、Git仓库链接 访问链接 代码规范
  • 三、PSP开发时间统计
  • 四、成品功能展示
  • 1. 项目初始界面
  • 2. 添加联系人功能
  • 3. 批量添加联系人演示
  • 4. 修改联系人功能
  • 5. 删除联系人功能
  • 6. 边界场景测试
  • 7. 云端访问演示
  • 五、设计与实现流程
  • 1. 系统架构设计
  • 2. 功能结构设计
  • 3. 数据库设计
  • 4. 核心实现流程
  • 六、核心代码解析
  • 1. 前端核心代码(Vue逻辑)
  • 2. 后端核心代码(API与数据库)
  • 七、部署流程(云端访问)
  • 八、个人开发心得与收获
  • 九、总结

一、作业基础信息

项目项内容
课程名称EE308FZ[A] — Software Engineering
作业名称前后端分离通讯录编程
作业目标掌握前后端分离架构开发流程,实现联系人增删改核心功能
技术栈前端:HTML+CSS+JavaScript+Vue.js;后端:Python+Flask;数据库:SQLite

二、Git仓库链接 访问链接 代码规范

三、PSP开发时间统计

开发前进行时间预估,开发后记录实际耗时,具体统计如下:

开发任务预计时间(小时)实际时间(小时)
需求分析与技术选型10.5
前端页面布局与样式开发34
前端Vue逻辑开发11.5
后端Flask框架搭建11
后端API与数据库开发33
前后端联调测试36
文档编写(README+博客)1.52
总计13.518

四、成品功能展示

本次开发的通讯录实现了添加、修改、删除核心功能,界面简洁直观,以下为功能演示截图(共10张,含完整操作流程):

1. 项目初始界面

启动后端后打开前端页面,默认显示空通讯录列表和添加表单,界面布局清晰

img


说明:页面上半部分为添加表单,下半部分为联系人列表区域,无数据时显示"No contacts yet. Add a new contact to get started."提示。

2. 添加联系人功能

步骤1:在表单中输入姓名和电话号码(示例:姓名"Freddy",电话"12345678")

img


说明:表单做了必填校验,未填写时点击添加会提示报错。

img


步骤2:点击"Add"按钮,前端调用后端API提交数据,成功后列表实时刷新

img


说明:联系人信息已显示在列表中,表单自动清空,便于继续添加。

3. 批量添加联系人演示

连续添加多个联系人数据,验证列表展示效果和数据存储稳定性。

img


说明:3位联系人数据均正常显示,每条数据包含编辑和删除按钮。

4. 修改联系人功能

步骤1:点击对应的"Edit"按钮,表单自动填充该联系人信息

img


说明:表单标题变为"Edit Contact",新增"Cancel"按钮可取消编辑。

步骤2:修改电话号码为"13900139000",点击"Update"按钮提交修改

img


说明:列表中的电话号码已更新,数据直接从数据库读取,无缓存。

5. 删除联系人功能

步骤1:点击"mark"对应的"Delete"按钮,弹出确认提示框

img


说明:添加确认步骤防止误删。
步骤2:点击"确认"后,联系人从列表中移除,数据库中对应数据删除

img


说明:列表仅剩2条数据,删除操作实时生效。

6. 边界场景测试

测试删除最后一条联系人后,界面显示空状态提示

img


说明:所有联系人删除后,列表区域显示"No contacts yet"提示,引导用户添加。

7. 云端访问演示

项目已部署至云服务器,通过公网可访问
访问链接:http://8.148.231.135/

五、设计与实现流程

1. 系统架构设计

采用经典前后端分离架构,职责划分清晰:

  • 前端:负责用户界面展示和交互逻辑,调用后端API实现数据交互
  • 后端:提供RESTful API接口,处理业务逻辑,与数据库交互完成数据CRUD
  • 数据库:SQLite文件数据库,存储联系人基本信息(id、姓名、电话)

2. 功能结构设计

核心功能围绕联系人管理展开,结构如下:
通讯录系统
├── 前端功能
│ ├── 联系人表单(添加/编辑复用)
│ ├── 联系人列表展示
│ └── 联系人操作(编辑、删除、取消)
└── 后端功能
├── 数据库初始化(自动创建表)
├── API接口(5个核心接口)
│ ├── GET /contacts 获取所有联系人
│ ├── GET /contacts/{id} 获取单个联系人
│ ├── POST /contacts 添加联系人
│ ├── PUT /contacts/{id} 修改联系人
│ └── DELETE /contacts/{id} 删除联系人
└── 跨域支持(解决前后端端口不一致问题)

3. 数据库设计

采用SQLite数据库,设计单表contacts存储联系人信息,表结构如下:

字段名数据类型主键/约束说明
idINTEGER主键,自增联系人唯一标识
nameTEXTNOT NULL联系人姓名(必填)
phoneTEXTNOT NULL联系人电话(必填

数据库初始化由后端models.py中的init_db()函数自动完成,启动后端时会检查并创建表。

4. 核心实现流程

以"添加联系人"为例,完整流程如下:

  1. 用户在前端表单输入姓名和电话,点击"Add"按钮
  2. Vue监听点击事件,通过fetch发送POST请求到后端/contacts接口,携带表单数据
  3. 后端Flask路由接收请求,调用add_contact()函数
  4. 函数连接数据库,执行INSERT语句将数据存入contacts表
  5. 后端返回成功响应,前端收到后调用fetchContacts()重新获取所有联系人
  6. Vue数据更新,列表实时渲染新添加的联系人

六、核心代码解析

1. 前端核心代码(Vue逻辑)

前端核心逻辑在js/app.js中,实现数据绑定和API调用:

new Vue({
    el: '#app',
    data: {
        contacts: [],
        currentContact: {
            id: null,
            name: '',
            phone: ''
        },
        isEditing: false
    },
    mounted() {
        // Load contacts when the app starts
        this.fetchContacts();
    },
    methods: {
        // Fetch all contacts from the backend
        fetchContacts() {
        
            fetch('http://8.148.231.135:5000/contacts')
                .then(response => response.json())
                .then(data => {
                    this.contacts = data;
                })
                .catch(error => console.error('Error fetching contacts:', error));
        },
        
        // Save a new contact or update an existing one
        saveContact() {
            if (this.isEditing) {
                // Update existing contact
                
                fetch(`http://8.148.231.135:5000/contacts/${this.currentContact.id}`, {
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(this.currentContact)
                })
                .then(() => {
                    this.fetchContacts();
                    this.resetForm();
                })
                .catch(error => console.error('Error updating contact:', error));
            } else {
                // Add new contact
              
                fetch('http://8.148.231.135:5000/contacts', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        name: this.currentContact.name,
                        phone: this.currentContact.phone
                    })
                })
                .then(() => {
                    this.fetchContacts();
                    this.resetForm();
                })
                .catch(error => console.error('Error adding contact:', error));
            }
        },
        
        // Prepare form for editing a contact
        editContact(contact) {
            this.currentContact = { ...contact };
            this.isEditing = true;
        },
        
        // Delete a contact
        deleteContact(id) {
            if (confirm('Are you sure you want to delete this contact?')) {
               
                fetch(`http://8.148.231.135:5000/contacts/${id}`, {
                    method: 'DELETE'
                })
                .then(() => {
                    this.fetchContacts();
                })
                .catch(error => console.error('Error deleting contact:', error));
            }
        },
        
        // Reset the form
        resetForm() {
            this.currentContact = {
                id: null,
                name: '',
                phone: ''
            };
            this.isEditing = false;
        }
    }
});


关键解析:通过isEditing状态区分添加和编辑,复用同一个表单和保存方法,减少冗余代码;使用fetch实现前后端数据交互,成功后刷新列表确保数据同步。

2. 后端核心代码(API与数据库)

(1)数据库操作(models.py)

import sqlite3
from config import Config

def get_db_connection():
    """Create and return a database connection"""
    conn = sqlite3.connect(Config.DATABASE_URI)
    conn.row_factory = sqlite3.Row
    return conn

def init_db():
    """Initialize the database with the contacts table"""
    conn = get_db_connection()
    conn.execute('''
    CREATE TABLE IF NOT EXISTS contacts (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        phone TEXT NOT NULL
    )
    ''')
    conn.commit()
    conn.close()

def get_all_contacts():
    """Get all contacts from the database"""
    conn = get_db_connection()
    contacts = conn.execute('SELECT * FROM contacts').fetchall()
    conn.close()
    return [dict(contact) for contact in contacts]

def get_contact_by_id(contact_id):
    """Get a single contact by ID"""
    conn = get_db_connection()
    contact = conn.execute('SELECT * FROM contacts WHERE id = ?', (contact_id,)).fetchone()
    conn.close()
    return dict(contact) if contact else None

def add_contact(name, phone):
    """Add a new contact to the database"""
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('INSERT INTO contacts (name, phone) VALUES (?, ?)', (name, phone))
    conn.commit()
    contact_id = cursor.lastrowid
    conn.close()
    return contact_id

def update_contact(contact_id, name, phone):
    """Update an existing contact"""
    conn = get_db_connection()
    conn.execute('UPDATE contacts SET name = ?, phone = ? WHERE id = ?', 
                 (name, phone, contact_id))
    conn.commit()
    conn.close()
    return True

def delete_contact(contact_id):
    """Delete a contact from the database"""
    conn = get_db_connection()
    conn.execute('DELETE FROM contacts WHERE id = ?', (contact_id,))
    conn.commit()
    conn.close()
    return True

关键解析:封装get_db_connection()方法复用数据库连接,避免重复代码;使用参数化查询,防止SQL注入,提升安全性;init_db()在后端启动时自动执行,无需手动建表。
(2)API接口(routes.py)

from flask import Blueprint, request, jsonify
import models

# Create a Blueprint for contact routes
contact_bp = Blueprint('contacts', __name__)

@contact_bp.route('/contacts', methods=['GET'])
def get_contacts():
    """Get all contacts"""
    contacts = models.get_all_contacts()
    return jsonify(contacts)

@contact_bp.route('/contacts/<int:contact_id>', methods=['GET'])
def get_contact(contact_id):
    """Get a single contact by ID"""
    contact = models.get_contact_by_id(contact_id)
    if contact:
        return jsonify(contact)
    return jsonify({'error': 'Contact not found'}), 404

@contact_bp.route('/contacts', methods=['POST'])
def add_contact():
    """Add a new contact"""
    data = request.get_json()
    
    if not data or 'name' not in data or 'phone' not in data:
        return jsonify({'error': 'Name and phone number are required'}), 400
    
    contact_id = models.add_contact(data['name'], data['phone'])
    return jsonify({'id': contact_id, 'message': 'Contact added successfully'}), 201

@contact_bp.route('/contacts/<int:contact_id>', methods=['PUT'])
def update_contact(contact_id):
    """Update an existing contact"""
    data = request.get_json()
    
    if not data or 'name' not in data or 'phone' not in data:
        return jsonify({'error': 'Name and phone number are required'}), 400
    
    # Check if contact exists
    contact = models.get_contact_by_id(contact_id)
    if not contact:
        return jsonify({'error': 'Contact not found'}), 404
    
    models.update_contact(contact_id, data['name'], data['phone'])
    return jsonify({'message': 'Contact updated successfully'})

@contact_bp.route('/contacts/<int:contact_id>', methods=['DELETE'])
def delete_contact(contact_id):
    """Delete a contact"""
    # Check if contact exists
    contact = models.get_contact_by_id(contact_id)
    if not contact:
        return jsonify({'error': 'Contact not found'}), 404
    
    models.delete_contact(contact_id)
    return jsonify({'message': 'Contact deleted successfully'})

(3)应用入口(app.py)

from flask import Flask
from flask_cors import CORS
import models
from routes import contact_bp

# Create Flask app
app = Flask(__name__)

# Enable CORS to allow cross-origin requests
CORS(app)

# Register blueprints
app.register_blueprint(contact_bp)

# Initialize database
models.init_db()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)

关键解析:使用Flask-CORS解决前后端跨域问题(前端80端口,后端5000端口);通过蓝图(Blueprint)管理路由,使代码结构更清晰;启动时自动初始化数据库。

七、部署流程(云端访问)

本次采用阿里云轻量应用服务器部署,步骤如下:

  1. 服务器环境准备:
     安装Python3:yum install python3 -y(CentOS系统)
    
  2. 安装依赖:pip3 install flask flask-cors gunicorn(gunicorn为生产环境服务器)
  3. 上传代码:通过Xshell+Xftp将前后端代码上传至服务器(如/home/project/目录)
  4. 后端启动:
     进入后端src目录:cd /home/project/backend/src
    
  5. 用gunicorn启动:gunicorn -w 2 -b 0.0.0.0:5000 app:app(2个进程,监听5000端口)
  6. 前端部署:
     安装Nginx:yum install nginx -y
    
  7. 配置Nginx:修改/etc/nginx/nginx.conf,将root指向前端src目录
  8. 启动Nginx:systemctl start nginx
  9. 开放端口:在阿里云控制台开放80(Nginx)和5000(后端)端口
    部署完成后,通过服务器公网IP即可访问前端页面,实现云端访问功能。

八、个人开发心得与收获

  1. 技术层面收获
  • 前后端分离认知:彻底理解了前后端分离的核心——前端负责"展示和交互",后端负责"数据处理",通过API接口实现通信。
  • Vue实战能力:熟练掌握了Vue的基础语法(数据绑定、事件监听、计算属性),学会了通过状态管理复用组件(如添加/编辑表单),提升了前端代码复用性。
  • Flask与API设计:掌握了Flask框架的基本使用(路由、蓝图、请求处理),理解了RESTful API的设计规范(GET/POST/PUT/DELETE对应查增改删)。
  • 问题解决能力:解决了跨域访问(Flask-CORS)、数据库连接复用、前端数据同步等实际问题,学会了通过浏览器控制台和后端日志排查错误。
  1. 开发流程感悟
  • 前期设计很重要:刚开始直接写代码时出现了前端表单复用混乱的问题,后来重新梳理功能结构,明确状态管理逻辑后,开发效率大幅提升。
  • 增量开发+测试:采用"实现一个功能测试一个功能"的方式,比如先实现添加功能,确保前后端联调通后再开发修改功能,避免了后期大量bug堆积。
  • 规范编码的价值:遵循代码规范使代码可读性大幅提升,后期修改时能快速定位到关键逻辑,也便于他人查看代码。
  1. 待优化方向
  • 实现联系人搜索功能,支持按姓名模糊查询。
  • 添加用户登录功能,实现多用户数据隔离。
  • 增加用户反馈功能,便于用户反馈问题

    九、总结

    本次前后端分离通讯录开发作业,从需求分析到代码实现再到云端部署,完整经历了Web应用开发的全流程。通过实践,不仅掌握了Vue、Flask等技术的实际应用,更深入理解了前后端分离的架构思想和开发模式。虽然过程中遇到了跨域、数据同步等问题,但通过查阅资料和不断调试最终解决,极大提升了问题解决能力。
...全文
247 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

164

社区成员

发帖
与我相关
我的任务
社区描述
2501_MU_SE_FZU
软件工程 高校
社区管理员
  • FZU_SE_LQF
  • 助教_林日臻
  • 朱仕君
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧