EE308FZ_First Assignment_Front-end and Back-end Separation Contacts Programming

部署运行你感兴趣的模型镜像

目录

PSP表格

访问链接

Github仓库地址

1. 功能展示

1.1  登录通讯录系统

1.2 增加联系人

1.3 删除联系人

1.4 修改联系人

1.5 查询联系人

1.6 联系人分组

2. 开发过程

Functional structure diagram:

2.1 后端开发

2.1.1 数据库搭建

2.1.2 创建contact表

2.1.3 python连接数据库+实现路由

增加联系人

查询联系人

编辑联系人

删除联系人

2.2 前端开发

2.2.1 前端简介

HTML

 CSS

JavaScript

2.1.4 Vue3框架

2.2.2 项目前端开发

登录注册页面

主界面

响应式布局

3. 拓展功能

3.1 登录功能

3.1.1 前端实现

3.1.2 后端实现

3.1.3 技术要点

3.2 联系人分组功能

3.2.1 前端实现

3.2.2 后端数据库列表

3.2.3 技术要点

4. 个人学习收获


Assignment 1Front-end and Back-end Separation Contacts Programming
Course for This AssignmentEE308FZ
Assignment RequirementsFront-end and Back-end Separation Contacts Programming
NameCheng Wang
Student ID

MU: 23126167

FZU: 832302103

Objectives of This AssignmentUsing web frameworks or other platforms to implement a front-end and back-end separated contacts management system with basic functionalities like adding, modifying, and deleting contacts.
 
Other ReferenceFlask Vue

PSP表格

任务子任务描述计划时间(h)实际时间(h)
规划需求分析模块划分分析,技术选型(Vue3 + Flask + MySQL)2.01.5
开发前端分析分模块开发(登录页、首页、通讯录)3.03.0
登录接口登录相关开发,集成前后端,权限管理3.53.5
功能接口接口开发(id, username, password, name, phone, email)集成2.01.0
前端路由集成 Vue3 + Router 路由开发,组件开发与交互3.53.5
前端功能前端开发,视图交互,组件开发,集成,响应式适配3.04.5
后端功能集成 Flask 开发路由、模型、服务层集成5.56.5
测试接口接口单元测试,集成测试,单元测试,集成测试3.03.0
测试单元测试单元测试开发,后端功能测试2.01.5
集成测试集成测试开发,前后端联调测试2.52.5
手动测试手动测试开发,SQL 语句编写与测试2.52.5
部署发布部署集成 Flask 项目打包部署,前端 Vue 打包,环境配置3.03.0
数据库部署在云服务器部署 MySQL,数据导入与备份2.01.5
运维测试运维测试开发,性能监控1.51.5
评估文档撰写文档撰写与用户手册2.52.5
合计-总计35.536.5

访问链接

http://120.48.22.150/

Github仓库地址

前端代码:832302103_contacts_frontend

后端代码:832302103_contacts_backend


1. 功能展示

1.1  登录通讯录系统

1.2 增加联系人

1.3 删除联系人

1.4 修改联系人

1.5 查询联系人

1.6 联系人分组

2. 开发过程

Functional structure diagram

2.1 后端开发

2.1.1 数据库搭建

在这次作业中,我使用了MySQL数据库。我使用的是MAC OS操作系统,首先我需要使用homebrew安装数据库:

brew install mysql

安装之后启动服务:

brew services start mysql

然后配置账号密码即可,此处不再展示。至此,MySQL数据库已经搭建完成。

2.1.2 创建contact表

搭建数据库之后,使用命令行进入数据库进行联系人列表的创建:

mysql -u root -p

输入密码即可进入数据库。然后使用命令行创建联系人列表:

CREATE DATABASE contacts_db

检查是否创建成功:

SHOW DATABASES

终端显示:

+--------------------+
| Database           |
+--------------------+
| contacts_db        |
| information_schema |
| mysql              |
| performance_schema |
| py_test_db         |
| sys                |
+--------------------+

可以发现,数据库中已经成功创建了联系人表格。

2.1.3 python连接数据库+实现路由

本次作业,我使用python连接数据库,并使用Flask框架实现API路由。Flask是一个轻量级的Web框架,提供基本的路由与请求处理,适合本次作业的开发。

首先,导入必要的包:

import pymysql
from flask import Flask, request, jsonify
from flask_cors import CORS

简要介绍一下这几个包:os用于文件管理,pymsql用于使用python连接MySQL数据库。flask_cors用于允许跨域访问(因为这次作业需要前端与后端分离,因此两者的域名不同,当前端调用后端API时,需要用到该扩展)。

在代码一开始,先声明使用pymysql作为MySQL的驱动,避免SQLAlchemy的兼容问题:

pymysql.install_as_MySQLdb()

接下来,创建数据库连接函数,每次连接数据库时进行调用:

def get_db_connection():
    connection = pymysql.connect(
        host=DB_HOST,
        port=DB_PORT,
        user=DB_USER,
        password=DB_PASSWORD,
        database=DB_NAME,
        charset='utf8mb4',  # 支持中文和表情符号
        cursorclass=pymysql.cursors.DictCursor  # 返回字典格式的结果
    )
    return connection
  • 增加联系人

我使用python的Flask框架创建RESTful API接口。首先,我实现了添加联系人的功能:

@app.route('/api/contacts', methods=['POST'])
def add_contact():
    name = data['name']
    phone = data['phone']
    position = data.get('position', '')
    group_name = data.get('group_name', '未分组')
    
    cursor.execute("INSERT INTO contact (name, phone, position, group_name) VALUES (%s, %s, %s, %s)",
                  (name, phone, position, group_name))
    conn.commit()
    
    return jsonify({
        'message': '联系人添加成功',
        'contact': {'id': cursor.lastrowid, 'name': name, 'phone': phone, 
                   'position': position, 'group_name': group_name}
    }), 201

这个函数实现了:接收前端发送的数据、连接数据库并插入到SQL表,使用try-except-finally进行异常处理。

  • 查询联系人

支持在姓名、电话、职务三个字段中进行模糊搜索:

@app.route('/api/contacts/search', methods=['GET'])
def search_contacts():
    keyword = request.args.get('keyword', '').strip()
    group_name = request.args.get('group_name')
    
    if not keyword:
        return jsonify({'error': '搜索关键词不能为空'}), 400
    
    pattern = f"%{keyword}%"
    
    if group_name:
        cursor.execute("""SELECT * FROM contact 
                        WHERE (name LIKE %s OR phone LIKE %s OR position LIKE %s) 
                        AND group_name = %s ORDER BY id DESC""",
                     (pattern, pattern, pattern, group_name))
    else:
        cursor.execute("""SELECT * FROM contact 
                        WHERE name LIKE %s OR phone LIKE %s OR position LIKE %s 
                        ORDER BY id DESC""",
                     (pattern, pattern, pattern))
    
    contacts = cursor.fetchall()
    return jsonify({'contacts': contacts, 'count': len(contacts)}), 200

这个函数实现了接收前端的查询要求,编写查询语句,执行并返回结果,同时处理了异常情况。

  • 编辑联系人

我的系统可以行内编辑,点击"编辑"按钮后,该行变为可编辑状态:

@app.route('/api/contacts/<int:contact_id>', methods=['PUT'])
def update_contact(contact_id):
    # 检查联系人是否存在
    cursor.execute("SELECT * FROM contact WHERE id = %s", (contact_id,))
    contact = cursor.fetchone()
    if not contact:
        return jsonify({'error': '联系人不存在'}), 404
    
    # 更新数据
    name = data.get('name', contact['name'])
    phone = data.get('phone', contact['phone'])
    position = data.get('position', contact.get('position', ''))
    group_name = data.get('group_name', contact.get('group_name', '未分组'))
    
    cursor.execute("UPDATE contact SET name=%s, phone=%s, position=%s, group_name=%s WHERE id=%s",
                  (name, phone, position, group_name, contact_id))
    conn.commit()
    
    return jsonify({'message': '联系人更新成功', 'contact': {...}}), 200

这个函数实现了接收前端的修改信息,编写修改语句,执行并返回结果,同时处理了异常情况。

  • 删除联系人

删除联系人的实现方式与增添联系人类似,这里仅展示不同代码

# 2. 先查询联系人是否存在
        check_sql = "SELECT * FROM contact WHERE id = %s"
        cursor.execute(check_sql, (contact_id,))
        contact = cursor.fetchone()
        
        if not contact:
            return jsonify({'error': '联系人不存在'}), 404
        
        # 3. 编写 SQL 删除语句
        delete_sql = "DELETE FROM contact WHERE id = %s"
        
        # 4. 执行删除
        cursor.execute(delete_sql, (contact_id,))
        
        # 5. 提交事务
        connection.commit()
        
        # 6. 返回成功响应
        return jsonify({
            'message': '联系人删除成功'
        }), 200

这个函数实现了接收前端的删除请求,编写删除语句,执行并返回结果,同时处理异常情况。

2.2 前端开发

2.2.1 前端简介

前端三大元素:HTML, JavaScript, CSS

HTML提供网页骨架结构,CSS进行美化,JavaScript实现交互逻辑

  • HTML

HTML通过一系列的标签,来定义文本、图像、链接等。HTML标签是由尖括号包围的关键字。

标签通常成对出现,包括开始标签与结束标签,内容位于这两个标签之间。

除了双标签,也存在单标签。双标签用于有内容的元素,单标签用于没有内容的元素。

HTML的标签包括:六级标签、段落标签、无序列表、有序列表

属性用于定义元素的行为和外观,以及与其他元素的关系

块元素:通常会从新的一行开始,并占据整行的宽度,呈现为一块独立的内容块(<div>, <p>, <h1>...<h6><ul><ol><li><table><form>)

行内元素:在同一行呈现<span><a><strong><em><img><br><input>

div标签:块级标签。创建一个容器块,没有语义,仅用于组织结构。

  •  CSS

CSS用于定义网页演示和布局,实现更精准的页面设计

CSS通常由选择器、属性和属性值组成,多个规则可以组合在一起,以便同时应用多个样式

CSS在HTML中有三种导入方式:内联样式、内部样式表(head 中定义)、外部样式表(定义在其它文件中,并在head中导入,允许多个网页使用相同样式)

优先级:内联 > 外部 > 内部

选择器:允许针对特定元素或一组元素定义样式

  • JavaScript

JS被设计用于在网页上实现动态效果,增加用户与网页的交互性

JS在前端中的作用:

客户端脚本:在浏览器中执行,实现动态效果和用户交互

网页开发:与HTML和CSS协同工作,加强动态性与交互性

后端开发:使用Node.js,JS也可以在服务器端运行,实现服务器端应用的开发

2.1.4 Vue3框架

前置:安装Node.js

使用官方脚手架创建Vue工程

进入空文件夹:npm create vue@latest

会自动提供一些配置信息

然后一个框架就被自动创建了:

此时,命令行输入:npm install

会自动下载依赖到node_modules文件夹

public用来放页面图标

src用来放代码文件

index.html是访问入口,一个vue项目都是在这一个单页面中进行各种交互,这也被称为SPA(Single Page Application)

Vue3的核心是通过createApp函数创建一个应用实例(绑定在index.html中),在这个实例中构建各种应用

每个Vue文件就是一个页面上的组件,组件可以嵌套使用

每个vue文件包括三个部分:模版templte 脚本script 样式style

此时命令行输入npm run dev即可运行了,初始页面是这样的:

2.2.2 项目前端开发

  • 登录注册页面

我使用了蓝色主题,界面干净简洁

.auth-container {
  background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 50%, #90caf9 100%);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.auth-card {
  background: white;
  border-radius: 16px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
  animation: slideUp 0.5s ease;
}
  • 主界面

我使用了侧边栏+右侧内容区的布局

.auth-container {
  background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 50%, #90caf9 100%);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.auth-card {
  background: white;
  border-radius: 16px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
  animation: slideUp 0.5s ease;
}
  • 响应式布局

我使用媒体查询适配了不同屏幕尺寸

@media (max-width: 768px) {
  .app-body {
    flex-direction: column;
  }

  .sidebar {
    width: 100%;
    border-right: none;
    border-bottom: 1px solid #e4e7ed;
  }

  .contact-form {
    grid-template-columns: 1fr;
  }
}

3. 拓展功能

3.1 登录功能

3.1.1 前端实现

const handleLogin = async () => {
  if (!loginForm.value.username || !loginForm.value.password) {
    showToast('请填写完整信息', 'error')
    return
  }

  try {
    const data = await api.login(loginForm.value)
    isAuthenticated.value = true
    currentUser.value = data.username
    showToast('登录成功!欢迎回来!')
    fetchGroups()
    fetchContacts()
  } catch (err) {
    showToast(err.message, 'error')
  }
}

3.1.2 后端实现

@app.route('/api/login', methods=['POST'])
def login():
    username = data['username']
    password = data['password']
    
    cursor.execute("SELECT * FROM users WHERE username = %s", (username,))
    user = cursor.fetchone()
    
    # 验证密码
    if not user or not check_password_hash(user['password_hash'], password):
        return jsonify({'error': '用户名或密码错误'}), 401
    
    # 设置Session
    session['user_id'] = user['id']
    session['username'] = user['username']
    
    return jsonify({'message': '登录成功!', 'username': user['username']}), 200

3.1.3 技术要点

  • 使用 check_password_hash 验证密码
  • Flask Session机制保持登录状态
  • 前端使用 withCredentials: true 携带Cookie

3.2 联系人分组功能

3.2.1 前端实现

<div v-if="showAddGroupModal" class="modal-overlay">
  <div class="modal-content">
    <div class="modal-header">
      <h3>添加新分组</h3>
      <button @click="showAddGroupModal = false">×</button>
    </div>
    <div class="modal-body">
      <input v-model="newGroupName" placeholder="请输入分组名称" />
    </div>
    <div class="modal-footer">
      <button @click="showAddGroupModal = false" class="btn btn-cancel">取消</button>
      <button @click="addGroup" class="btn btn-primary">添加</button>
    </div>
  </div>
</div>

3.2.2 后端数据库列表

@app.route('/api/groups', methods=['GET'])
def get_all_groups():
    cursor.execute("""
        SELECT g.id, g.name, COUNT(c.id) as count
        FROM contact_group g
        LEFT JOIN contact c ON g.name = c.group_name
        GROUP BY g.id, g.name
        ORDER BY g.id ASC
    """)
    groups = cursor.fetchall()
    return jsonify({'groups': groups}), 200

3.2.3 技术要点

  • 使用 LEFT JOIN 连接分组表和联系人表
  • 使用 COUNT() 聚合函数统计数量
  • 使用 GROUP BY 分组统计

4. 个人学习收获

作为一名学生,在开发这个通讯录管理系统项目时,我一开始遇到了一些困难。之前仅接触过基础教程,现在需要构建一个完整的前后端应用,这让我认识到学习编程需要有条理的规划。因此,我选择循序渐进,先从后端开始,确保数据基础稳固后再转向界面开发。

首先,我决定进行后端Flask的开发。这一部分一开始比较困难,因为我缺乏后端经验。但我从简单API入手,先定义了登录和注册的端点,使用`@app.route`来路由请求,并通过`generate_password_hash`处理密码加密,这让我理解了数据安全的必要性。然后,我学习了MySQL数据库的操作。创建表结构(如users、contact和contact_group表)和执行查询语句时,最初遇到了一些语法错误,但通过反复测试PyMySQL连接,我成功插入了第一条联系人数据。分组功能的实现例如使用JOIN查询来计算分组计数进一步加深了我对表的理解。通过Postman测试API端点,我逐步验证了后端功能,确保后端功能完整。

接下来,我转向Vue.js的前端部分。理解模板语法和组件的交互比较困难,例如使用`v-if`来切换登录界面和主应用界面。但根据搭建的后端接口,我逐步编写代码。在实现登录和注册表单时,我学习了`v-model`来绑定用户输入,实现实时响应,这让我对界面的动态性有了直观认识。随后,我开发了添加联系人的表单和联系人列表,包括搜索、编辑和删除功能。过程中,CSS样式的调整让我学会了如何优化用户体验,每完成一个子模块,都能看到页面的逐步完善,这增强了我的信心。

最后,集成前后端是整个项目的关键,我也收获最多。我使用axios从前端发送HTTP请求到后端API,例如在添加联系人时传递数据并更新列表。过程中,遇到了CORS跨域和会话管理的问题,我通过网络搜索和逐步调试来解决,这培养了我问题排查的能力。项目最终运行顺利时,看到联系人能被搜索、编辑和分组管理,我感到很激动。

通过这个项目,我不仅掌握了Flask、MySQL和Vue.js的基本应用,还学会了项目开发的方法:从后端API起步,逐步集成前端。未来,我打算利用这次项目学到的知识,更好地完成学期项目。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值