☰
基于鸿蒙ArkTS的类小红书App毕设实战指南
2026/10/30 12:15:09 网站建设 项目流程

毕业设计如果继续做“XX管理系统”,大概率会在开题答辩时和七八个同学撞车。相比之下,以鸿蒙系统为平台、用 ArkTS 做原生开发的类小红书 App,从技术栈到产品形态都有足够区分度,而且它不是只做一个 demo 界面,而是把社交笔记、电商商城和 Web 后台串成一条完整业务链路。这类课题既能体现对新型平台的掌握,也能覆盖状态管理、网络请求、权限申请、数据持久化、接口设计和后台管理等常见工程能力,非常适合作为毕设选题,也可以作为简历上的完整项目。

这篇文章按一个可落地的毕设项目来拆解:先讲为什么选这个题、整体架构和技术栈怎么定,再给数据模型和接口约定,然后分别说明笔记信息流、商城模块、Web 后台的实现思路,最后补充真机调试排错路径、答辩演示路径和常见坑。文中代码用于说明工程思路,实际开发时要以你本地的 DevEco Studio 版本和 API 版本为准,不要照抄后不做版本验证。

1. 为什么这个选题值得做:从撞车选题里找区分度

1.1 毕设选题撞车的原因与破局思路

毕业设计撞车最多的通常是“图书管理系统”“学生选课系统”“企业员工管理”这类题目。撞车的原因很简单:技术栈固定、参考案例多、实现路径成熟。大家用同一个框架、同一套 CRUD,最后交上去的验收点高度相似,甚至答辩时被问的问题都一样。

破局思路不是把界面做得更花哨,而是换一个有平台属性的方向。鸿蒙系统是一个仍在快速迭代的操作系统,ArkTS 作为其应用开发的推荐语言,还没有被大量毕设项目覆盖。当别人还在写 Web 管理系统时,你手里是一个运行在真机或模拟器上的原生 App,带双列瀑布流、点赞收藏、购物车、下单流程和后台管理,这种完整度更容易在开题、中期和答辩时讲出东西。

这里要区分一个概念:鸿蒙系统并不只是“手机上的系统”。从通俗角度看,它面向手机、平板、车机、智慧屏等多设备协同场景;从技术角度看,应用层通过 ArkUI 声明式框架和 ArkTS 语言开发,底层系统负责调度、安全和分布式能力。毕设层面不需要讲得很底层,但理解这一点能帮助你在答辩时解释“为什么不用 WebView 套壳,而要选原生开发”。

1.2 ArkTS 原生开发在毕设中的优势

ArkTS 是在 TypeScript 基础上扩展出的声明式 UI 开发语言。它和传统命令式写界面的方式不同,开发者描述“界面应该长什么样”,框架负责在状态变化时更新界面。这个思路与 React、Vue 有相似之处,但 ArkTS 直接跑在鸿蒙应用框架上,能调用相机、相册、网络、权限管理等系统能力。

用 ArkTS 做原生开发,毕设里有三个实际收益:

  1. 权限申请、相机调用、相册选择这些能力可以作为独立功能点,答辩时容易展示系统级集成能力。
  2. 声明式 UI 的代码量相对少,页面结构和状态变化更直观,适合在有限时间内完成。
  3. 技术资料正在快速积累,但还远没有 JavaWeb 那么泛滥,写出来的项目有稀缺性。

需要注意,ArkTS 对类型约束比普通 JavaScript 严格,组件状态管理也有自己的规则。不要直接用写“自由脚本”的习惯去写 ArkTS,否则运行起来会遇到类型报错和状态不刷新问题。

1.3 课题拆解:社交笔记、电商商城、Web 后台三个模块的边界

这个题目可以拆成三个边界清晰的模块:

  • 用户端 App:包含登录注册、首页双列笔记流、笔记详情、发布笔记、点赞收藏、商品列表、商品详情、购物车、订单提交、个人中心。
  • 服务端接口:为 App 和 Web 后台提供 RESTful API,处理用户、笔记、商品、订单、评论、点赞等数据。
  • Web 后台:管理员登录后,可以查看数据看板、管理用户、审核笔记、上下架商品、处理订单。

毕设的工作量主要落在 App 端。如果时间有限,可以砍掉评论、搜索、支付对接等非核心功能,用一个“模拟支付成功”来代替真实支付。后端接口数量控制在 20 个左右就能支撑整个演示流程,不要一开始就把表设计得过于复杂。

2. 项目整体架构与技术选型:先画清楚模块边界

2.1 客户端、服务端、Web 后台三层结构

项目建议采用前后端分离结构,分三部分:

  • HarmonyOS App 客户端:负责用户交互,通过 HTTP 请求访问服务端接口。
  • 服务端:负责业务逻辑、鉴权、数据校验和数据库读写,同时给 Web 后台提供接口。
  • Web 后台:一个单独的管理端项目,只允许管理员登录,提供内容审核和运营管理功能。

数据流链路大致是:App 发起登录请求,服务端校验后返回 token;App 携带 token 获取笔记或商品列表;用户发布笔记,服务端写入待审核状态;管理员在后台审核通过,用户端才能看到笔记上线。

这种三层结构的好处是职责分离。App 端可以不关心 SQL 和业务规则,后台管理可以随时补充业务功能而不需要重新发版 App。答辩时也能清楚说明,这是一个“完整的前后端协作项目”,而不是单页面 Demo。

2.2 服务端与数据库选型

服务端技术栈可以根据你熟悉的方向选择。最常用的两组方案:

技术栈优点适合场景
Java + Spring Boot + MySQL资料多,企业微服务常用,代码结构规范熟悉 Java 或后续想找 Java 后端岗位
Node.js + Express/Nest + MySQL语言与前端一致,开发迭代快熟悉 TypeScript 或希望整体一套语言
Python + Flask/FastAPI + MySQL代码轻量,适合快速原型想快速跑通但需要后期补齐工程化能力

数据库层建议统一用 MySQL。毕设环境下表结构可控,MySQL 的 SQL 资料也多,排错成本低。如果你的电脑没有安装 MySQL,也可以先用 SQLite 或 H2 数据库开发,最后再迁移到 MySQL,但要注意 SQL 方言差异。

2.3 核心业务链路需要提前梳理

在写代码之前,先用文字把核心链路理清楚,后面就不会乱:

  1. 用户注册登录:注册时保存用户名和密码哈希,登录成功后服务端返回 token,App 后续请求在 Header 中携带。
  2. 笔记发布与审核:用户填写标题、内容、分类并选择图片,发布后状态为待审核;后台审核通过后,笔记在用户端可见。
  3. 商品与订单:用户浏览商品并加入购物车,确认后提交订单;服务端生成订单号,状态为待支付;模拟支付成功后状态变为已支付,后台可以进行发货操作。
  4. 后台管理:管理员登录后看到统计数字,对用户、笔记、商品、订单进行管理操作。

这些链路是后面设计数据库表结构的基础。先想清楚链路,再建表,不要一边写界面一边临时改表。

3. 环境准备与工程创建:先跑起来,再写业务

3.1 DevEco Studio、SDK 和 API 版本要对齐

HarmonyOS 应用开发的主力 IDE 是 DevEco Studio,安装后需要下载 HarmonyOS SDK。SDK 版本会直接影响 ArkTS 语法、组件能力和权限 API,所以开始项目前先确认三件事:

  • DevEco Studio 安装完成且登录账号环境正常。
  • SDK 已下载,且与工程目标 API 版本一致。
  • 有可用的模拟器或真机。如果使用真机,要在设备上开启开发者模式,并允许 USB 调试。

API 版本是一个容易踩坑的地方。不同 API 版本中,权限申请接口、路由跳转方式、WaterFlow 等新组件的支持程度不同。教程中经常看到的一些写法可能来自不同版本,遇到 API 不存在或编译报错时,优先在官方 API 文档中确认当前版本签名。

如果实在没有真机,可以用模拟器完成大部分功能演示,但相机、相册、定位等系统能力在模拟器上的体验会受限。毕设演示时,能准备一台鸿蒙真机效果更好。

3.2 创建 ArkTS 工程并理解目录结构

在 DevEco Studio 中选择“Empty Ability”模板创建工程。一个典型工程的目录结构大致如下:

HarmonyNotesDemo/ ├── AppScope/ │ ├── app.json5 │ └── resources/ ├── entry/ │ ├── src/main/ │ │ ├── ets/ │ │ │ ├── entryability/ │ │ │ ├── pages/ │ │ │ │ ├── Index.ets │ │ │ │ ├── NoteDetailPage.ets │ │ │ │ ├── PublishNotePage.ets │ │ │ │ ├── ProductListPage.ets │ │ │ │ ├── CartPage.ets │ │ │ │ └── MinePage.ets │ │ │ ├── model/ │ │ │ └── service/ │ │ ├── resources/ │ │ └── module.json5 │ └── build-profile.json5 └── build-profile.json5

module.json5是模块配置文件,里面注册 Ability、声明权限、配置页面入口。pages目录存放页面组件。model目录建议放数据模型和接口返回类型定义,service目录放网络请求封装和工具方法。不要在页面文件里写大量逻辑,否则后期维护会很痛苦。

创建完工程后,先运行一次默认 Hello World,确认开发环境可以编译、安装、启动。这一步能提前暴露 SDK、签名、模拟器连接等问题,不要在还没跑通基础工程时就开始写业务代码。

3.3 权限申请:从热门问题“arkts 权限申请”说起

权限申请是鸿蒙开发中很容易忽略的环节。应用访问网络、相机、相册等能力,需要先在module.json5中声明权限,然后在代码中请求动态权限。

基础网络权限配置如下:

{ "module": { "name": "entry", "requestPermissions": [ { "name": "ohos.permission.INTERNET" }, { "name": "ohos.permission.CAMERA" }, { "name": "ohos.permission.READ_IMAGEVIDEO" }, { "name": "ohos.permission.WRITE_IMAGEVIDEO" } ] } }

查询用户相册、访问网络、调用相机都属于需要“解释用途”的敏感权限。即使声明了权限,部分系统能力仍需要在运行时弹窗申请。常用的动态权限申请代码思路如下:

import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit'; async function requestPermission(permission: Permissions) { const atManager = abilityAccessCtrl.createAtManager(); try { const result = await atManager.requestPermissionsFromUser(permission); if (result.authResults.length > 0 && result.authResults[0] === 0) { console.info('permission granted'); } else { console.error('permission denied'); } } catch (err) { console.error('request permission error: ' + JSON.stringify(err)); } }

这里要特别提醒:不同 API 版本中requestPermissionsFromUser入参类型不一样,有的版本接受数组,有的版本接受单个权限对象,还有的版本要求传入context。写代码前必须以当前工程依赖的 API 版本为准,不能直接复制网上任意一段代码。

权限申请常见的坑是只做了声明、没有动态请求,或者声明了权限但用户拒绝后没有处理。正确做法是:在进入需要权限的功能前检查授权状态,未授权时弹窗说明用途并请求;用户拒绝后,界面要给出引导或降级处理,不能直接崩溃。

4. 数据库模型设计:先定义业务的数据基础

4.1 用户、笔记、商品、订单四张核心表

数据库表设计不用太多,但要能支撑完整业务链路。核心表先建四张:用户表、笔记表、商品表、订单表。

CREATE TABLE `user` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(50) NOT NULL UNIQUE, `password_hash` VARCHAR(255) NOT NULL, `nickname` VARCHAR(50), `avatar_url` VARCHAR(255), `role` TINYINT DEFAULT 0 COMMENT '0普通用户 1管理员', `status` TINYINT DEFAULT 1 COMMENT '1正常 0禁用', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE `note` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `user_id` BIGINT NOT NULL, `title` VARCHAR(100), `content` TEXT, `cover_url` VARCHAR(255), `category` VARCHAR(30), `like_count` INT DEFAULT 0, `status` TINYINT DEFAULT 0 COMMENT '0待审核 1已上线 2已下线', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE `product` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `price` DECIMAL(10, 2) NOT NULL, `stock` INT DEFAULT 0, `cover_url` VARCHAR(255), `status` TINYINT DEFAULT 1 COMMENT '1上架 0下架', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE `order` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `order_no` VARCHAR(64) NOT NULL UNIQUE, `user_id` BIGINT NOT NULL, `total_amount` DECIMAL(10, 2) NOT NULL, `status` TINYINT DEFAULT 0 COMMENT '0待支付 1已支付 2已发货 3已完成 4已取消', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP );

可以看到,用户表加了role字段区分普通用户和管理员,笔记表加了status字段支撑后台审核,商品表用status控制上下架。这些字段并不复杂,但它们是 Web 后台能独立管理内容的基础。如果省掉状态字段,后面后台审核功能会无从下手。

4.2 点赞、收藏、评论、购物车等关联表

核心表确定后,再补充关联表,保存用户与内容之间的交互关系。

CREATE TABLE `favorite` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `user_id` BIGINT NOT NULL, `note_id` BIGINT NOT NULL, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY `uk_user_note` (`user_id`, `note_id`) ); CREATE TABLE `comment` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `user_id` BIGINT NOT NULL, `note_id` BIGINT NOT NULL, `content` VARCHAR(500) NOT NULL, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE `cart` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `user_id` BIGINT NOT NULL, `product_id` BIGINT NOT NULL, `quantity` INT DEFAULT 1, `selected` TINYINT DEFAULT 1, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY `uk_user_product` (`user_id`, `product_id`) );

关联表看起来简单,但有几处容易错:favorite表要加唯一键防止重复点赞;cart表要按用户和商品维度唯一,这样重复加入购物车时执行的是数量累加而不是插入新记录。这些细节在接口开发时都能遇到。

4.3 接口返回格式与分页约定

App 端、Web 后台和服务端之间统一约定接口返回格式,可以大幅减少联调成本。

{ "code": 0, "message": "ok", "data": { "list": [], "total": 100, "page": 1, "size": 10 } }

分页接口统一约定page和size参数,返回结果带total。这样 App 端做下拉加载时,可以用page + 1请求下一页,直到列表长度等于total时停止。图片、头像、封面地址在数据库中建议存相对路径或完整 URL,服务端统一拼接域名,避免前端到处改 baseUrl。

5. 笔记信息流模块的 ArkTS 实现:双列瀑布流与交互状态

5.1 首页结构:搜索栏、Tab 栏与内容列表

首页是类小红书 App 的门面,结构上可以分为三块:顶部搜索栏、Tab 切换栏、笔记内容列表。Tab 可以切换“推荐”“穿搭”“美食”“美妆”等分类,按分类请求后端接口即可。

ArkTS 页面骨架如下:

@Entry @Component struct HomePage { @State noteList: NoteItem[] = []; @State currentCategory: string = '推荐'; build() { Column() { Row() { TextInput({ placeholder: '搜索笔记和商品' }) .layoutWeight(1) Button('搜索') .onClick(() => this.search()) } .padding(10) TabBar({ categories: ['推荐', '穿搭', '美食', '美妆'], current: this.currentCategory, onSelect: (category: string) => this.loadNotes(category) }) NoteList({ notes: this.noteList }) .layoutWeight(1) } } search() { // 跳转到搜索结果页 } loadNotes(category: string) { // 请求后端接口并刷新 noteList } }

这里把搜索、Tab、列表拆成多个组件或 Builder,可以让页面结构更清晰。@State装饰的变量是状态源,ArkUI 会在状态变化时重新渲染界面。要特别注意的是,修改数组时直接this.noteList.push(item)不会触发刷新,正确做法是生成新数组重新赋值,例如this.noteList = [...this.noteList, ...newData]。

5.2 双列瀑布流的两种实现方案

瀑布流是类小红书 App 最核心的界面特征。实现上主要有两种思路。

第一种是使用 ArkUI 的WaterFlow组件。如果你的目标 API 版本支持,代码会简洁很多:

WaterFlow() { LazyForEach(this.noteList, (item: NoteItem) => { FlowItem() { NoteCard({ note: item }) } }, (item: NoteItem) => item.id) }

LazyForEach会根据列表项在屏幕内的可见性按需创建组件,适合大量图片笔记的列表。如果目标版本中WaterFlow不可用,可以使用第二种方案:用Scroll包裹Row,左侧一个Column,右侧一个Column,把偶数项放进左列,奇数项放进右列。

Scroll(this.scroller) { Row() { this.leftColumn() this.rightColumn() } .alignItems(VerticalAlign.Top) } .scrollable(ScrollDirection.Vertical) .onReachEnd(() => this.loadMore())

双列手动布局的原理是:左列负责偶数下标数据,右列负责奇数下标数据,两列各自垂直排列,实现类似瀑布流的效果。这个方案的缺点是左右两列高度可能不平衡,但通过不断加载新数据、保持两列数量接近,可以得到比较自然的展示效果。

5.3 笔记卡片、点赞收藏与详情页跳转

笔记卡片组件需要展示封面图、标题、作者头像、作者昵称和点赞数。用@Component定义卡片,接收NoteItem对象,然后点击卡片时跳转到详情页。

@Component export struct NoteCard { @Prop note: NoteItem; build() { Column({ space: 4 }) { Image(this.note.coverUrl) .width('100%') .aspectRatio(0.85) .objectFit(ImageFit.Cover) .borderRadius(8) Text(this.note.title) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) Row({ space: 4 }) { Text(this.note.authorName) .fontSize(12) Text(this.note.likeCount + ' 赞') .fontSize(12) } .width('100%') } .padding(6) .onClick(() => { router.pushUrl({ url: 'pages/NoteDetailPage', params: { id: this.note.id } }); }) } }

@Prop表示单向数据传入,适合卡片展示场景。点赞按钮的状态变化通常要传递到父组件,可以用@Link双向绑定,或者通过回调函数通知父组件更新数据。点击卡片跳转详情页时,通过路由params传递笔记 id,详情页再根据 id 请求完整内容。

5.4 网络请求封装与图片加载兜底

App 端不直接在每个页面里写http请求,建议统一封装一个ApiClient服务。基本写法如下:

import { http } from '@kit.NetworkKit'; export class ApiClient { static baseUrl: string = 'http://192.168.1.100:8080/api'; static get<T>(path: string): Promise<T> { const request = http.createHttp(); return request.request(this.baseUrl + path, { method: http.RequestMethod.GET, connectTimeout: 10000, readTimeout: 10000, header: { 'Content-Type': 'application/json' } }).then((resp) => { if (resp.responseCode === 200) { return JSON.parse(resp.result as string) as T; } throw new Error('request failed: ' + resp.responseCode); }).finally(() => { request.destroy(); }); } }

网络请求成功不等于业务成功。服务端通常会在 HTTP 200 下返回code字段,前端要先判断code === 0,再处理data。如果code非 0,要弹出错误提示。

图片加载方面,Image组件的src可以设置网络 URL,但是要确认三件事:图片域名是否在系统网络安全配置允许的范围内;URL 是http还是https,明文请求可能被拦截;图片加载失败时有没有兜底图。兜底写法如下:

Image(this.note.coverUrl) .alt($r('app.media.default_cover')) .objectFit(ImageFit.Cover)

.alt()参数会在图片加载失败或尚未加载完成时展示本地兜底图。生产环境中图片链接触发大量流量,要考虑服务端开启 CDN 或图片压缩;毕设阶段只要保证图片能正常加载、失败有兜底即可。

6. 商城模块的 ArkTS 实现:购物车数量逻辑和模拟下单

6.1 商品列表、商品详情与加入购物车

商城模块的商品列表结构和笔记列表类似,只是卡片信息不同,需要展示商品名称、价格和库存。商品卡片点击后进入商品详情页,详情页包含大图、价格、库存、数量选择和加入购物车按钮。

商品数据模型可以设计为:

export class ProductItem { id: string = ''; name: string = ''; price: number = 0; stock: number = 0; coverUrl: string = ''; status: number = 1; }

加入购物车时调用后端接口,把userId、productId、quantity传给服务端。服务端做原子操作:库存足够时更新购物车记录并扣减临时数量,库存不足时返回错误码。不要在 App 端自行计算库存,因为客户端数据不可信,最终校验必须在服务端完成。

6.2 购物车数量管理、选中逻辑与总价计算

购物车页面是状态管理比较集中的地方,需要处理数量增加、数量减少、单选、全选、删除、总价计算等操作。ArkTS 中数组元素内部的字段变化通常不会自动触发界面刷新,因此更新数量后最好重新赋值整个数组。

核心逻辑示例:

@Component struct CartPage { @State cartItems: CartItem[] = []; updateQuantity(index: number, delta: number) { const item = this.cartItems[index]; item.quantity = Math.max(1, item.quantity + delta); this.cartItems = [...this.cartItems]; } toggleSelect(index: number) { this.cartItems[index].selected = !this.cartItems[index].selected; this.cartItems = [...this.cartItems]; } get totalPrice(): number { return this.cartItems .filter(item => item.selected) .reduce((sum, item) => sum + item.price * item.quantity, 0); } }

这里的totalPrice是计算属性,每次界面渲染时会根据cartItems重新计算。数量最小值要限制为 1,最大值不能超过商品库存。全选逻辑判断当前选中数量是否等于列表长度,注意空购物车时要禁用“提交订单”按钮。

6.3 下单流程与模拟支付

从购物车提交订单时,只把选中的商品提交给服务端。订单创建接口返回订单号,前端生成一个支付确认页,用户点击“确认支付”后调用模拟支付接口,服务端把订单状态从待支付改为已支付。

async submitOrder() { const selectedItems = this.cartItems.filter(item => item.selected); if (selectedItems.length === 0) { return; } const order = await ApiClient.post<OrderResult>('/order/create', { items: selectedItems.map(item => ({ productId: item.productId, quantity: item.quantity })) }); // 跳转到支付确认页 router.pushUrl({ url: 'pages/PayPage', params: { orderNo: order.orderNo, amount: order.totalAmount } }); }

模拟支付的代码量不大,但演示效果很重要。支付完成后,订单状态更新为已支付,购物车要清空已下单商品。后台管理员看到已支付订单后,可以执行发货操作,订单状态变为已发货。这样一条从 App 到后台再到 App 的完整业务闭环就成立了。

7. Web 后台快速搭建:内容审核和订单管理是关键

7.1 后台功能清单与页面拆分

Web 后台是区分“一个 App Demo”和“一个完整项目”的重要加分项。后台功能不需要做得非常华丽,但必须覆盖核心运营动作。

后台模块核心功能依赖数据表对 App 的影响
登录管理员账号登录user无
数据看板今日新增用户、笔记数、订单数、销售额user/note/order无
用户管理用户列表、禁用启用user被禁用用户无法登录
笔记管理笔记列表、审核、下架note审核通过后用户端可见
商品管理商品列表、上架、下架product下架商品用户端不可见
订单管理订单列表、发货order发货后订单状态变化

从这张表可以看出,后台管理的每个操作几乎都会影响用户端数据。毕设答辩时,最有效的演示路径是:在后台把一条笔记从待审核改为通过,然后在 App 端刷新看到这条笔记上线。这比单纯展示一堆静态页面更有说服力。

7.2 后台技术选型:前后端分离还是服务端模板

Web 后台有两种常见做法。

第一种是前后端分离:后端提供接口,前端使用 Vue3 + Element Plus 或 React + Ant Design 开发。这种方式结构清晰,页面美观,适合有前端基础的同学,但需要同时维护两个工程的开发环境。

第二种是服务端模板渲染:后端直接提供 HTML 页面,管理界面用 Bootstrap 或原生 HTML 实现。这种方式工程简单,适合时间紧张、只想快速跑通后台功能的场景。

对比表如下:

方案开发成本展示效果适合场景
Vue3 + Element Plus 前后端分离中等较好有前端基础,希望提升项目含金量
服务端模板渲染低一般时间紧,只求后台可用
React + Ant Design中等偏高较好熟悉 React 生态

7.3 后台列表页、审核操作和管理员登录

后台列表页的核心是“列表 + 条件筛选 + 操作按钮”。比如笔记管理页,需要展示用户昵称、笔记标题、分类、状态、创建时间,并提供“通过”“下架”按钮。状态字段在数据库中是数字,后台要转换成中文展示,例如0转成“待审核”、1转成“已上线”。

管理员登录需要单独设计,不能在后台使用普通用户的注册登录接口。简单做法是初始化一条role=1的管理员记录,后台登录时校验角色。生产环境还要加入验证码、单点登录、操作日志等机制,但毕设阶段可以先不做。

如果后台使用 Vue3 开发,基础登录流程是:输入账号密码,后端校验成功后返回 token,前端把 token 存到localStorage或pinia中,后续请求在Authorization头携带。这个流程和 App 端高度相似,可以在答辩时作为“多端接口复用”的例子来说明整个项目设计的一致性。

8. 真机调试与接口联调:从日志到链路的排查顺序

8.1 联调环境先确认,避免在错误前提下找问题

App 端和服务端联调时,最常遇到的就是环境问题。这里按优先级列出检查清单:

  1. 真机和电脑是否处于同一局域网。
  2. 服务端接口是否能从电脑浏览器直接访问。
  3. App 中配置的baseUrl是否是电脑的局域网 IP,而不是localhost或127.0.0.1。
  4. 真机是否能 ping 通电脑 IP,电脑防火墙是否拦截了服务端端口。
  5. 网络权限是否已在module.json5中声明。

localhost是一个高频错误。模拟器虽然运行在电脑上,但模拟器内部的网络环境和宿主机不同,写死localhost经常导致无法访问本机服务;真机上访问电脑服务也必须使用电脑的局域网 IP。建议把baseUrl单独放到配置文件中,方便调试时切换。

8.2 常见错误现象与排查路径

问题现象可能原因检查方式处理建议
请求后台接口一直超时真机和电脑不在同一网络,或端口被防火墙拦截查看两台设备 IP,做 ping 测试改用同一 WiFi,开放服务端端口或临时关闭防火墙
接口返回 404后端路径和前端请求路径不一致查看后端控制台日志,浏览器直接访问接口统一接口路径拼接规则
接口返回 JSON 解析失败返回格式不符合前端类型定义查看返回原始字符串和model中字段前后端共同维护接口文档
图片加载空白图片 URL 使用 http,或域名未配置浏览器打开图片地址,检查网络策略使用 https,配置网络安全白名单,准备本地兜底
权限弹窗不出现,功能不可用只在配置中声明,未动态申请检查requestPermissionsFromUser调用按系统要求完成动态申请流程
页面状态不刷新直接修改数组内部字段检查是否重新赋值@State数组使用新数组替换旧数组触发渲染

排查顺序建议:先看服务端有没有收到请求,再看服务端返回了什么,最后看前端解析结果。把问题定位到“网络不通”“服务端异常”“前端解析异常”三个分段,比从界面开始盲目改代码要高效得多。

8.3 日志和真机调试的关键节点

鸿蒙开发中,日志通过 HiLog 输出,可以从 DevEco Studio 的 Log 窗口查看。页面里可以使用console.info输出关键变量。排查网络请求时,重点看三个时间点:

  1. 请求发出前:baseUrl是否正确,参数是否完整。
  2. 服务端收到请求时:路径、Method、请求体是否与接口定义一致。
  3. 响应返回后:HTTP 状态码、code字段、data内容是否能被解析。

如果真机连接不上 DevEco Studio,先检查 USB 调试是否打开、驱动是否安装、设备是否已在开发者选项中授权电脑。部分型号的设备在首次连接时需要确认“允许 USB 调试”弹窗,这是很容易忽略的一步。

9. 毕设验收与答辩准备:功能完整度要能自圆其说

9.1 按模块整理验收清单

答辩演示之前,建议按模块整理一份验收清单,逐项自测。

模块必测功能验收标准
用户端登录注册、退出使用数据库中的账号可登录,错误密码有提示
笔记首页瀑布流、详情、点赞、收藏、发布发布后后台可见,后台审核通过后用户端可查看
搜索关键词搜索笔记或商品输入关键词返回正确结果
商城商品列表、详情、购物车、下单购物车选中项正确,订单状态正确流转
个人中心我的发布、我的收藏、订单列表数据与用户关联正确
后台登录、看板、管理操作审核、上下架、发货状态能同步到用户端

清单里最容易漏的是“发布笔记后走后台审核再上线”这条链路。很多毕设只做了页面展示,没有把内容状态管理起来,答辩时被问“谁审核内容”就答不上来。这一条链路完整跑通,整个项目的业务价值会明显提升。

9.2 演示路径:先主链路,再功能点

演示不要从“登录”开始慢慢点,要先给评委一条清晰的主链路。

推荐演示顺序:

  1. 打开 App,展示首页双列瀑布流,截图展示界面效果。
  2. 登录账号,进入笔记详情,演示点赞和收藏。
  3. 点击发布按钮,上传一张图片并填写内容,提交笔记。
  4. 切换到 Web 后台,演示管理员登录,找到待审核笔记并审核通过。
  5. 回到 App,刷新首页,看到刚发布的笔记已经上线。
  6. 进入商城模块,把商品加入购物车,确认下单并模拟支付。
  7. 回到 Web 后台,找到新订单并执行发货。
  8. 回到 App,查看订单状态变为已发货。

这条路径把 App、服务端、Web 后台三个端都串了起来,每一步都有明确的因果验证。相比“这里能点赞、那里能加购”的碎片化演示,这条链路更能体现项目完整性。

9.3 答辩高频问题与准备方向

答辩时经常被问到四类问题:

  1. 为什么选择鸿蒙系统和 ArkTS,而不是 Android 或 Flutter。可以从“新平台、原生能力、声明式 UI、与 TypeScript 语法相近”几个角度回答,不要贬低其他技术,只讲选题差异。
  2. 状态管理是怎么做的。要能说出@State、@Prop、@Link的区别,以及数组更新为什么需要重新赋值。
  3. 服务端接口如何保证安全。至少要说密码加密存储、登录 token、后台接口的角色校验。没有做 token 校验的项目在答辩时容易失分。
  4. 如果数据量变大,项目怎么优化。可以从分页、懒加载、图片缓存、服务端索引、Redis 缓存几个方向回答。前面代码里已经用了LazyForEach和分页,这一点就能直接关联上。

提前把这些问题的答案写成文字稿,比临场组织语言要稳得多。

10. 最佳实践与扩展方向:从毕设项目升级成简历项目

10.1 工程化上最值得做的几个改进

如果时间和精力允许,建议在完成基础功能后加入以下工程化改进:

  • 接口统一封装:所有请求都走一个ApiClient,统一处理错误码、加载态和 token。
  • 配置文件外置:baseUrl、图片域名放到配置文件中,不要在页面里散落写死。
  • 日志规范:App、服务端、Web 后台都保留运行日志,至少能查清请求失败发生在哪个环节。
  • 异常分支处理:用户拒绝权限、网络超时、库存不足、订单重复提交,这些场景要有明确提示。
  • 密码安全:用户密码在服务端使用bcrypt或PBKDF2哈希再存储,不能明文入库。

这些点不一定都写在答辩 PPT 里,但在代码审查和系统演示中会体现出来。尤其是“库存不足”和“重复提交订单”的异常处理,是很多毕设项目欠缺的地方。

10.2 可以继续扩展的方向

这个题目可以从两个方向继续拔高。

第一个方向是多端协同。鸿蒙系统强调分布式能力,可以尝试在平板、手机之间接力演示,或者用分布式数据把自己的笔记同步到另一个设备。这一块不需要做很大,有一个小型场景演示即可,但能体现对鸿蒙平台特性的理解。

第二个方向是内容推荐和数据可视化。用户端可以记录用户的浏览、点赞行为,服务端做一个简单的标签推荐策略;Web 后台的数据看板可以加入图表,展示签到趋势、订单金额趋势。这块可以参考开源图表库或服务端统计函数实现。推荐策略不要求做成复杂算法,能解释清楚“基于内容标签的简单推荐思路”就已经超过大多数选题。

10.3 对做

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询