EE308FZ_First Assignment_832301117_Li Zongheng

Moneett 2025-11-10 22:10:56

目录

  • Github仓库链接
  • 1、项目介绍
  • 2、PSP表格
  • 3、成品展示
  • 4、设计流程
  • 4.1 技术选型
  • 4.2 关键设计
  • 4.2.1 架构设计
  • 4.2.2 目录结构设计
  • 5、代码说明
  • 5.1、项目概述
  • 5.2、 前端代码实现
  • 5.2.1 核心文件分析:index.html
  • 5.2.1.1 HTML结构设计
  • 5.2.1.2 Vue 3 应用初始化与状态管理
  • 5.2.1.3 本地存储功能实现
  • 5.2.1.4 联系人操作核心功能
  • 5.3、 后端代码实现
  • 5.3.1 服务器配置:server.js
  • 5.3.2 联系人控制器:contacts.js
  • 6、个人心得


学生姓名:李宗衡
FZUID:832301117
MUID:23126230


Github仓库链接

https://github.com/Moneett/832301117


1、项目介绍

本项目是基于前后端分离架构开发的多功能通讯录管理系统,核心目标是实现联系人信息的高效管理,同时适配多终端访问场景,帮助用户快速完成联系人的添加、修改、删除等基础操作,兼顾功能完整性与使用便捷性。


2、PSP表格

PSP阶段预估时间实际时间差异分析
需求分析21.5需求明确,效率较高
架构设计11.5技术选型调研比预期复杂
前端开发67难度较大,开发耗时多
后端开发89部署环境配置耗时较多
前后端调试34出现错误消耗时间
博客编写23精益求精,细致整理
合计2226消耗时间较多,追求高完成质量

3、成品展示

1、界面展示

img

2、添加联系人

img

img

3、删除联系人

img

img

4、编辑联系人

img

img


4、设计流程

4.1 技术选型

本通讯录管理系统采用现代化Web开发技术栈,实现了前后端分离的架构设计。下表列出了系统主要技术选型及其选型理由:

分类技术版本选型理由
前端框架Vue 33.x采用组合式API,性能卓越,响应式设计简化数据绑定,学习曲线平缓,社区活跃。
UI样式原生CSS-轻量级实现,无需额外依赖,便于自定义样式,适合小型应用快速开发。
构建方式CDN引入-无需复杂构建配置,直接在浏览器中运行,简化部署流程,适合教学演示。
本地存储localStorage-浏览器内置存储机制,无需后端即可实现数据持久化,使用简单,适合单机应用。
后端框架Express4.x轻量级Node.js Web框架,API简洁,中间件丰富,学习成本低,适合快速开发RESTful API。
运行环境Node.js14.x+JavaScript运行时,实现JavaScript全栈开发,生态丰富,跨平台支持良好。
跨域处理cors2.xExpress中间件,简单配置即可解决跨域问题,提高前后端协作效率。
数据存储(后端)内存数据库-开发阶段使用,简化数据库配置,便于快速原型开发和测试。

4.2 关键设计

4.2.1 架构设计

系统采用典型的前后端分离架构,具体架构设计如下图所示:

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   前端应用层    │     │   后端服务层    │     │   数据存储层    │
│   (Vue 3)       │◄───►│   (Express)     │◄───►│   (localStorage/│
│                 │     │                 │     │    内存存储)    │
└─────────────────┘     └─────────────────┘     └─────────────────┘

架构说明:

  1. 前端应用层:负责用户界面展示和交互逻辑,使用Vue 3框架实现组件化开发。采用组合式API管理应用状态,通过localStorage实现本地数据持久化,同时预留了与后端API交互的接口。

  2. 后端服务层:提供RESTful API接口,处理业务逻辑和数据操作。使用Express框架构建Web服务器,配置cors中间件处理跨域请求,实现了完整的联系人CRUD操作。

  3. 数据存储层:前端采用localStorage实现本地存储,后端采用内存数据库进行开发测试,支持后续平滑迁移到MongoDB或MySQL等持久化数据库。

4.2.2 目录结构设计

前端目录结构:

student123_contacts_frontend/
├── index.html           # 主页面
├── README.md            # 项目说明文档
├── codestyle.md         # 代码规范文档
└── src/                 # 源代码目录(可扩展)
    ├── assets/          # 静态资源
    ├── components/      # Vue组件
    └── utils/           # 工具函数

后端目录结构:

student123_contacts_backend/
├── server.js            # 应用入口文件
├── package.json         # 项目配置和依赖
├── README.md            # 项目说明文档
├── codestyle.md         # 代码规范文档
└── src/                 # 源代码目录
    └── controller/      # 控制器目录
        └── contacts.js  # 联系人控制器

目录设计说明:

  • 采用清晰的模块化结构,前后端代码完全分离
  • 前端使用扁平化结构,便于快速开发和部署
  • 后端采用MVC架构思想,将业务逻辑封装在控制器中
  • 预留了扩展目录,支持项目后续功能迭代和代码优化

5、代码说明

5.1、项目概述

通讯录管理系统是一个基于前后端分离架构的Web应用,支持联系人信息的添加、查询、修改和删除操作。系统采用现代化Web开发技术,前端使用Vue 3框架实现响应式界面,后端基于Express构建RESTful API服务,同时提供了纯前端localStorage存储方案,实现了无需后端服务也能独立运行的数据持久化功能。

5.2、 前端代码实现

5.2.1 核心文件分析:index.html

前端代码采用单文件设计,集成了HTML结构、CSS样式和JavaScript逻辑,使用Vue 3的组合式API构建响应式界面。

5.2.1.1 HTML结构设计

<div id="app" class="container">
    <h1>通讯录管理系统</h1>
    
    <div class="button-group">
        <button class="btn-primary" @click="showAddModal = true">添加联系人</button>
    </div>
    
    <table>
        <thead>
            <tr>
                <th>姓名</th>
                <th>电话</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="contact in contacts" :key="contact.id">
                <td>{{ contact.name }}</td>
                <td>{{ contact.phone }}</td>
                <td>
                    <button class="btn-default" @click="editContact(contact)">修改</button>
                    <button class="btn-danger" @click="deleteContact(contact.id)">删除</button>
                </td>
            </tr>
        </tbody>
    </table>
    
    <!-- 添加/编辑模态框 -->
    <div v-if="showAddModal || showEditModal" class="modal" @click.self="closeModal">
        <div class="modal-content">
            <h2>{{ showEditModal ? '编辑联系人' : '添加联系人' }}</h2>
            <div class="form-item">
                <label>姓名</label>
                <input v-model="formData.name" type="text" placeholder="请输入姓名">
            </div>
            <div class="form-item">
                <label>电话</label>
                <input v-model="formData.phone" type="tel" placeholder="请输入电话">
            </div>
            <div class="button-group">
                <button class="btn-primary" @click="submitForm">{{ showEditModal ? '更新' : '添加' }}</button>
                <button class="btn-default" @click="closeModal">取消</button>
            </div>
        </div>
    </div>
</div>

HTML结构采用了清晰的语义化设计:

  • 页面主体包含标题、操作按钮区和联系人表格
  • 使用Vue 3的指令系统(v-forv-ifv-model@click)实现数据绑定和事件处理
  • 模态框设计复用了一个组件,通过showAddModalshowEditModal两个状态变量控制显示逻辑和内容

5.2.1.2 Vue 3 应用初始化与状态管理

const { createApp, ref, reactive, onMounted } = Vue

createApp({
    setup() {
        const contacts = ref([])
        const showAddModal = ref(false)
        const showEditModal = ref(false)
        const editingId = ref(null)
        
        const formData = reactive({
            name: '',
            phone: ''
        })
        
        // 组件逻辑...
        
        return {
            contacts,
            showAddModal,
            showEditModal,
            formData,
            editContact,
            deleteContact,
            submitForm,
            closeModal
        }
    }
}).mount('#app')

Vue 3应用初始化采用了组合式API风格:

  • 使用ref()创建响应式基本类型数据(联系人列表、模态框状态等)
  • 使用reactive()创建响应式对象(表单数据)
  • setup()函数中定义所有逻辑和状态
  • 最后返回需要在模板中使用的状态和方法

5.2.1.3 本地存储功能实现

// 从localStorage获取联系人数据
const fetchContacts = () => {
    const storedContacts = localStorage.getItem('contacts')
    if (storedContacts) {
        contacts.value = JSON.parse(storedContacts)
    } else {
        // 设置默认模拟数据
        contacts.value = [
            { id: 1, name: '张三', phone: '13800138000' },
            { id: 2, name: '李四', phone: '13900139000' }
        ]
        // 保存默认数据到localStorage
        localStorage.setItem('contacts', JSON.stringify(contacts.value))
    }
}

// 保存联系人数据到localStorage
const saveContacts = () => {
    localStorage.setItem('contacts', JSON.stringify(contacts.value))
}

本地存储功能设计:

  • fetchContacts()函数在组件挂载时调用,从localStorage读取数据
  • 首次访问时,提供默认模拟数据并保存到localStorage
  • saveContacts()函数在任何数据变更后调用,确保数据持久化
  • 使用JSON.parse()JSON.stringify()进行数据格式转换

5.2.1.4 联系人操作核心功能

编辑联系人:

const editContact = (contact) => {
    editingId.value = contact.id
    formData.name = contact.name
    formData.phone = contact.phone
    showEditModal.value = true
}

删除联系人:

const deleteContact = (id) => {
    if (confirm('确定要删除这个联系人吗?')) {
        contacts.value = contacts.value.filter(c => c.id !== id)
        saveContacts()
    }
}

表单提交处理:

const submitForm = () => {
    if (!formData.name || !formData.phone) {
        alert('请填写完整信息')
        return
    }
    
    if (showEditModal.value) {
        // 更新现有联系人
        const index = contacts.value.findIndex(c => c.id === editingId.value)
        if (index !== -1) {
            contacts.value[index] = {
                ...contacts.value[index],
                name: formData.name,
                phone: formData.phone
            }
        }
    } else {
        // 添加新联系人
        const newContact = {
            id: Date.now(), // 使用时间戳作为唯一ID
            name: formData.name,
            phone: formData.phone
        }
        contacts.value.push(newContact)
    }
    
    // 保存到localStorage
    saveContacts()
    closeModal()
}

模态框管理:

const closeModal = () => {
    showAddModal.value = false
    showEditModal.value = false
    editingId.value = null
    formData.name = ''
    formData.phone = ''
}

生命周期管理:

// 初始化数据
onMounted(() => {
    fetchContacts()
})

核心功能实现亮点:

  • 使用条件判断区分添加和编辑操作,复用同一个表单组件
  • 表单验证确保数据完整性
  • 使用时间戳生成唯一ID,避免冲突
  • 组件卸载前调用fetchContacts()初始化数据
  • 操作后自动保存并关闭模态框,提升用户体验

5.3、 后端代码实现

5.3.1 服务器配置:server.js

const express = require('express');
const cors = require('cors');
const app = express();
const PORT = 3000;

// 导入控制器
const contactController = require('./src/controller/contacts');

// 中间件
app.use(cors());
app.use(express.json());

// API路由
app.get('/api/contacts', contactController.getAllContacts);
app.get('/api/contacts/:id', contactController.getContactById);
app.post('/api/contacts', contactController.createContact);
app.put('/api/contacts/:id', contactController.updateContact);
app.delete('/api/contacts/:id', contactController.deleteContact);

// 启动服务器
app.listen(PORT, () => {
    console.log(`后端服务启动在 http://localhost:${PORT}`);
});

// 添加一个简单的健康检查接口
app.get('/api/health', (req, res) => {
    res.json({ status: 'ok', message: '服务正常运行' });
});

后端服务器设计采用了典型的Express应用架构:

  • 导入必要的依赖(express、cors)
  • 配置中间件:cors(处理跨域请求)、express.json(解析JSON请求体)
  • 定义RESTful API路由,连接到对应的控制器方法
  • 添加健康检查接口,便于监控服务状态
  • 启动HTTP服务器监听指定端口

5.3.2 联系人控制器:contacts.js

// 模拟数据库
let contacts = [
    { id: 1, name: '张三', phone: '13800138000' },
    { id: 2, name: '李四', phone: '13900139000' }
];
let nextId = 3;

// 获取所有联系人
exports.getAllContacts = (req, res) => {
    res.json(contacts);
};

// 获取单个联系人
exports.getContactById = (req, res) => {
    const id = parseInt(req.params.id);
    const contact = contacts.find(c => c.id === id);
    if (contact) {
        res.json(contact);
    } else {
        res.status(404).json({ error: '联系人不存在' });
    }
};

// 添加联系人
exports.createContact = (req, res) => {
    const { name, phone } = req.body;
    if (!name || !phone) {
        return res.status(400).json({ error: '姓名和电话不能为空' });
    }
    
    const newContact = {
        id: nextId++,
        name,
        phone
    };
    
    contacts.push(newContact);
    res.status(201).json(newContact);
};

// 更新联系人
exports.updateContact = (req, res) => {
    const id = parseInt(req.params.id);
    const { name, phone } = req.body;
    
    if (!name || !phone) {
        return res.status(400).json({ error: '姓名和电话不能为空' });
    }
    
    const contactIndex = contacts.findIndex(c => c.id === id);
    if (contactIndex === -1) {
        return res.status(404).json({ error: '联系人不存在' });
    }
    
    contacts[contactIndex] = {
        ...contacts[contactIndex],
        name,
        phone
    };
    
    res.json(contacts[contactIndex]);
};

// 删除联系人
exports.deleteContact = (req, res) => {
    const id = parseInt(req.params.id);
    const contactIndex = contacts.findIndex(c => c.id === id);
    
    if (contactIndex === -1) {
        return res.status(404).json({ error: '联系人不存在' });
    }
    
    contacts.splice(contactIndex, 1);
    res.json({ message: '删除成功' });
};

联系人控制器实现了完整的CRUD操作:

  • 使用内存数组模拟数据库存储
  • 定义了全局变量nextId用于生成自增ID
  • 实现了五个主要API端点对应的处理函数:
    1. getAllContacts: 获取所有联系人列表
    2. getContactById: 根据ID获取单个联系人
    3. createContact: 创建新联系人
    4. updateContact: 更新现有联系人
    5. deleteContact: 删除指定联系人
  • 每个API都包含适当的请求验证和错误处理
  • 使用HTTP状态码区分不同的响应情况(200成功、201创建成功、400请求错误、404资源不存在)

6、个人心得

本次前后端分离通讯录编程作业,让我系统掌握了前后端分离开发的核心流程与关键技术。在问题解决方面,遇到了前后端跨域、接口联调数据格式不匹配、部署后访问超时等问题,通过查阅官方文档、调试工具排查与社区求助,最终逐一解决,提升了问题排查与解决能力。同时,严格按照作业要求进行代码规范整理与 Github 版本管理,养成了良好的开发习惯。通过本次作业,不仅提升了技术实操能力,更培养了从需求分析、设计、开发到部署的完整项目思维,为后续更复杂的项目开发奠定了基础。

...全文
104 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

164

社区成员

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

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